diff -Nru php-mdb2-2.4.1/debian/changelog php-mdb2-2.5.0b2/debian/changelog --- php-mdb2-2.4.1/debian/changelog 2009-04-29 15:36:21.000000000 +0100 +++ php-mdb2-2.5.0b2/debian/changelog 2009-04-29 15:36:21.000000000 +0100 @@ -1,3 +1,13 @@ +php-mdb2 (2.5.0b2-1) unstable; urgency=low + + [ Mark A. Hershberger ] + * New upstream version. (Closes: #520897) + + [ Vincent Bernat ] + * Bump Standards-Version to 3.8.1. No changes required. + + -- Mark A. Hershberger Fri, 24 Apr 2009 15:03:30 -0400 + php-mdb2 (2.4.1-1) unstable; urgency=low * Initial Release. (Closes: #441637) diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/debian/control /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/debian/control --- php-mdb2-2.4.1/debian/control 2009-04-29 15:36:21.000000000 +0100 +++ php-mdb2-2.5.0b2/debian/control 2009-04-29 15:36:21.000000000 +0100 @@ -2,13 +2,13 @@ Section: web Priority: optional Maintainer: Debian PHP Maintainers -Uploaders: Mark A. Hershberger +Uploaders: Mark A. Hershberger , Vincent Bernat Build-Depends: debhelper (>= 5) Build-Depends-Indep: php-pear Vcs-Svn: svn://svn.debian.org/pkg-php/pear/php-mdb2/trunk Vcs-Browser: http://svn.debian.org/wsvn/pkg-php/pear/php-mdb2/trunk Homepage: http://pear.php.net/package/MDB2 -Standards-Version: 3.8.0 +Standards-Version: 3.8.1 Package: php-mdb2 Architecture: all diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/debian/watch /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/debian/watch --- php-mdb2-2.4.1/debian/watch 2009-04-29 15:36:21.000000000 +0100 +++ php-mdb2-2.5.0b2/debian/watch 2009-04-29 15:36:21.000000000 +0100 @@ -1,2 +1,2 @@ version=3 -http://pear.php.net/package/MDB2 http://download.pear.php.net/package/MDB2-([\d.RC]+).tgz +http://pear.php.net/package/MDB2 http://download.pear.php.net/package/MDB2-([\d.bRC]+).tgz diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/docs/CONTRIBUTORS /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/docs/CONTRIBUTORS --- php-mdb2-2.4.1/MDB2-2.4.1/docs/CONTRIBUTORS 2007-05-03 19:58:15.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.4.1/docs/CONTRIBUTORS 1970-01-01 01:00:00.000000000 +0100 @@ -1,7 +0,0 @@ -PEAR DB Stig Baekken, Tomas V. Cox -Metabase Manuel Lemos -PEAR Error integration/XML Schema Parser Christian Dickmann -Code Formatting Brent Cook -MsSQL/Frontbase Driver Frank Kormann -PgSQL Driver Paul Cooper -Interbase/Firebird Lorenzo Alberton diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/docs/datatypes.html /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/docs/datatypes.html --- php-mdb2-2.4.1/MDB2-2.4.1/docs/datatypes.html 2007-05-03 19:58:15.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.4.1/docs/datatypes.html 1970-01-01 01:00:00.000000000 +0100 @@ -1,64 +0,0 @@ - - -MDB2 data types - - -

MDB2 data types

-
- - -
-

Introduction

-

All DBMS provide multiple choice of data types for the information that can be stored in their database table fields. However, the set of data types made available varies from DBMS to DBMS.

-

To simplify the interface with the DBMS supported by MDB2 it was defined a base set of data types that applications may access independently of the underlying DBMS.

-

The MDB2 applications programming interface takes care of mapping data types when managing database options. It is also able to convert that is sent to and received from the underlying DBMS using the respective driver.

-

  • Text data type
  • -

    The text data type is available with two options for the length: one that is explicitly length limited and another of undefined length that should be as large as the database allows.

    -

    The length limited option is the most recommended for efficiency reasons. The undefined length option allows very large fields but may prevent the use of indexes and may not allow sorting on fields of its type.

    -

    The fields of this type should be able to handle 8 bit characters. Drivers take care of DBMS specific escaping of characters of special meaning with the values of the strings to be converted to this type.

    -

  • Boolean data type
  • -

    The boolean data type represents only two values that can be either 1 or 0. Do not assume that these data types are stored as integers because some DBMS drivers may implement this type with single character text fields for a matter of efficient. Ternary logic is possible by using null as the third possible value that may be assigned to fields of this type.

    -

  • Integer data type
  • -

    The integer data type may store integer values as large as each DBMS may handle. Fields of this type may be created optionally as unsigned integers but not all DBMS support it. Therefore, such option may be ignored. Truly portable applications should not rely on the availability of this option.

    -

  • Decimal data type
  • -

    The decimal data type may store decimal numbers accurately with a fixed number of decimal places. This data type is suitable for representing accurate values like currency amounts.

    -

    Some DBMS drivers may emulate the decimal data type using integers. Such drivers need to know in advance how many decimal places that should be used to perform eventual scale conversion when storing and retrieving values from a database. Despite this, applications may use arithmetic expressions and functions with the values stored on decimal type fields as long as any constant values that are used in the expressions are also converted with the respective MDB2 conversion functions.

    -

    The number of places that are used to the left and the right of the decimal point is pre-determined and fixed for all decimal values stored in the same database. By default, MDB2 uses 2 places to the right of the decimal point, but this may be changed when setting the database connection. The number of places available to the right of the decimal point depend on the DBMS.

    -

    It is not recommended to change the number places used to represent decimal values in database after it is installed. MDB2 does not keep track of changes in the number of decimal places.

    -

  • Float data type
  • -

    The float data type may store floating point decimal numbers. This data type is suitable for representing numbers within a large scale range that do not require high accuracy. The scale and the precision limits of the values that may be stored in a database depends on the DBMS that it is used.

    -

  • Date data type
  • -

    The date data type may represent dates with year, month and day. DBMS independent representation of dates is accomplished by using text strings formatted according to the IS0 8601 standard.

    -

    The format defined by the ISO 8601 standard for dates is YYYY-MM-DD where YYYY is the number of the year (Gregorian calendar), MM is the number of the month from 1 to 12 and DD is the number of the day from 1 to 31. Months or days numbered below 10 should be padded on the left with 0.

    -

    Some DBMS have native support for date formats, but for others the DBMS driver may have to represent them as integers or text values. In any case, it is always possible to make comparisons between date values as well sort query results by fields of this type.

    -

  • Time data type
  • -

    The time data type may represent the time of a given moment of the day. DBMS independent representation of the time of the day is also accomplished by using text strings formatted according to the IS0 8601 standard.

    -

    The format defined by the ISO 8601 standard for the time of the day is HH:MI:SS where HH is the number of hour the day from 0 to 23 and MI and SS are respectively the number of the minute and of the second from 0 to 59. Hours, minutes and seconds numbered below 10 should be padded on the left with 0.

    -

    Some DBMS have native support for time of the day formats, but for others the DBMS driver may have to represent them as integers or text values. In any case, it is always possible to make comparisons between time values as well sort query results by fields of this type.

    -

  • Time stamp data type
  • -

    The time stamp data type is a mere combination of the date and the time of the day data types. The representation of values of the time stamp type is accomplished by joining the date and time string values in a single string joined by a space. Therefore, the format template is YYYY-MM-DD HH:MI:SS. The represented values obey the same rules and ranges described for the date and time data types.

    -

  • Large object (file) data types
  • -

    The large object data types are meant to store data of undefined length that may be to large to store in text fields, like data that is usually stored in files.

    -

    MDB2 supports two types of large object fields: Character Large OBjects (CLOBs) and Binary Large OBjects (BLOBs). CLOB fields are meant to store only data made of printable ASCII characters. BLOB fields are meant to store all types of data.

    -

    Large object fields are usually not meant to be used as parameters of query search clause (WHERE) unless the underlying DBMS supports a feature usually known as "full text search".

    - -
    -
    Manuel Lemos (mlemos@acm.org)
    - - diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/docs/examples/example.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/docs/examples/example.php --- php-mdb2-2.4.1/MDB2-2.4.1/docs/examples/example.php 2007-05-03 19:58:15.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.4.1/docs/examples/example.php 1970-01-01 01:00:00.000000000 +0100 @@ -1,208 +0,0 @@ -PEAR-Error
    '; - echo $error_obj->getMessage().': '.$error_obj->getUserinfo(); - print ''; - } - PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'handle_pear_error'); - - // just for kicks you can mess up this part to see some pear error handling - $user = 'root'; - $pass = ''; - $host = 'localhost'; - $mdb2_name = 'metapear_test_db'; - $mdb2_type = !empty($_GET['db_type']) ? $_GET['db_type'] : 'mysql'; - echo($mdb2_type.'
    '); - - // Data Source Name: This is the universal connection string - $dsn['username'] = $user; - $dsn['password'] = $pass; - $dsn['hostspec'] = $host; - $dsn['phptype'] = $mdb2_type; - // MDB2::factory will return a PEAR::MDB2 instance on success - // or a Pear MDB2 error object on error - // You can alternatively build a dsn here - // $dsn = "$mdb2_type://$user:$pass@$host/$mdb2_name"; - Var_Dump($dsn); - $mdb2 =& MDB2::factory($dsn); - // With PEAR::isError you can differentiate between an error or - // a valid connection. - if (PEAR::isError($mdb2)) { - die (__LINE__.$mdb2->getMessage()); - } - - // this loads the MDB2_Schema manager - // this is a separate package you must install - require_once 'MDB2/Schema.php'; - // you can either pass a dsn string, a dsn array or an exisiting mdb2 connection - $schema =& MDB2_Schema::factory($mdb2); - $input_file = 'metapear_test_db.schema'; - // lets create the database using 'metapear_test_db.schema' - // if you have allready run this script you should have 'metapear_test_db.schema.before' - // in that case MDB2 will just compare the two schemas and make any - // necessary modifications to the existing database - Var_Dump($schema->updateDatabase($input_file, $input_file.'.before')); - echo('updating database from xml schema file
    '); - - echo('switching to database: '.$mdb2_name.'
    '); - $mdb2->setDatabase($mdb2_name); - // happy query - $query ='SELECT * FROM test'; - echo('query for the following examples:'.$query.'
    '); - // run the query and get a result handler - $result = $mdb2->query($query); - // lets just get row:0 and free the result - $array = $result->fetchRow(); - $result->free(); - echo('
    row:
    '); - echo(Var_Dump($array).'
    '); - $result = $mdb2->query($query); - // lets just get row:0 and free the result - $array = $result->fetchRow(MDB2_FETCHMODE_OBJECT); - $result->free(); - echo('
    row (object:
    '); - echo(Var_Dump($array).'
    '); - // run the query and get a result handler - $result = $mdb2->query($query); - // lets just get row:0 and free the result - $array = $result->fetchRow(); - $result->free(); - echo('
    row from object:
    '); - echo(Var_Dump($array).'
    '); - // run the query and get a result handler - $result = $mdb2->query($query); - // lets just get column:0 and free the result - $array = $result->fetchCol(2); - $result->free(); - echo('
    get column #2 (counting from 0):
    '); - echo(Var_Dump($array).'
    '); - // run the query and get a result handler - $result = $mdb2->query($query); - Var_Dump($mdb2->loadModule('Reverse', null, true)); - echo('tableInfo:
    '); - echo(Var_Dump($mdb2->reverse->tableInfo($result)).'
    '); - $types = array('integer', 'text', 'timestamp'); - $result->setResultTypes($types); - $array = $result->fetchAll(MDB2_FETCHMODE_FLIPPED); - $result->free(); - echo('
    all with result set flipped:
    '); - echo(Var_Dump($array).'
    '); - // save some time with this function - // lets just get all and free the result - $array = $mdb2->queryAll($query); - echo('
    all with just one call:
    '); - echo(Var_Dump($array).'
    '); - // run the query with the offset 1 and count 1 and get a result handler - Var_Dump($mdb2->loadModule('Extended', null, false)); - $result = $mdb2->extended->limitQuery($query, null, 1, 1); - // lets just get everything but with an associative array and free the result - $array = $result->fetchAll(MDB2_FETCHMODE_ASSOC); - echo('
    associative array with offset 1 and count 1:
    '); - echo(Var_Dump($array).'
    '); - // lets create a sequence - echo(Var_Dump($mdb2->loadModule('Manager', null, true))); - echo('
    create a new seq with start 3 name real_funky_id
    '); - $err = $mdb2->manager->createSequence('real_funky_id', 3); - if (PEAR::isError($err)) { - echo('
    could not create sequence again
    '); - } - echo('
    get the next id:
    '); - $value = $mdb2->nextId('real_funky_id'); - echo($value.'
    '); - // lets try an prepare execute combo - $alldata = array( - array(1, 'one', 'un'), - array(2, 'two', 'deux'), - array(3, 'three', 'trois'), - array(4, 'four', 'quatre') - ); - $stmt = $mdb2->prepare('INSERT INTO numbers VALUES(?,?,?)', array('integer', 'text', 'text'), MDB2_PREPARE_MANIP); - foreach ($alldata as $row) { - echo('running execute
    '); - $stmt->bindValueArray($row); - $stmt->execute(); - } - $array = array(4); - echo('
    see getOne in action:
    '); - echo(Var_Dump($mdb2->extended->getOne('SELECT trans_en FROM numbers WHERE number = ?',null,$array,array('integer'))).'
    '); - $mdb2->setFetchmode(MDB2_FETCHMODE_ASSOC); - echo('
    default fetchmode ist now MDB2_FETCHMODE_ASSOC
    '); - echo('
    see getRow in action:
    '); - echo(Var_Dump($mdb2->extended->getRow('SELECT * FROM numbers WHERE number = ?',array('integer','text','text'),$array, array('integer')))); - echo('default fetchmode ist now MDB2_FETCHMODE_ORDERED
    '); - $mdb2->setFetchmode(MDB2_FETCHMODE_ORDERED); - echo('
    see getCol in action:
    '); - echo(Var_Dump($mdb2->extended->getCol('SELECT * FROM numbers WHERE number != ?',null,$array,array('integer'), 1)).'
    '); - echo('
    see getAll in action:
    '); - echo(Var_Dump($mdb2->extended->getAll('SELECT * FROM test WHERE test_id != ?',array('integer','text','text'), $array, array('integer'))).'
    '); - echo('
    see getAssoc in action:
    '); - echo(Var_Dump($mdb2->extended->getAssoc('SELECT * FROM test WHERE test_id != ?',array('integer','text','text'), $array, array('integer'), MDB2_FETCHMODE_ASSOC)).'
    '); - echo('tableInfo on a string:
    '); - echo(Var_Dump($mdb2->reverse->tableInfo('numbers')).'
    '); - echo('
    just a simple update query:
    '); - echo('
    affected rows:
    '); - echo(Var_Dump($mdb2->exec('UPDATE numbers set trans_en ='.$mdb2->quote(0, 'integer'))).'
    '); - // subselect test - $sub_select = $mdb2->subSelect('SELECT test_name from test WHERE test_name = '.$mdb2->quote('gummihuhn', 'text'), 'text'); - echo(Var_Dump($sub_select).'
    '); - $query_with_subselect = 'SELECT * FROM test WHERE test_name IN ('.$sub_select.')'; - // run the query and get a result handler - echo($query_with_subselect.'
    '); - $result = $mdb2->query($query_with_subselect); - $array = $result->fetchAll(); - $result->free(); - echo('
    all with subselect:
    '); - echo('
    drop index (will fail if the index was never created):
    '); - echo(Var_Dump($mdb2->manager->dropIndex('test', 'test_id_index')).'
    '); - $index_def = array( - 'fields' => array( - 'test_id' => array( - 'sorting' => 'ascending' - ) - ) - ); - echo('
    create index:
    '); - echo(Var_Dump($mdb2->manager->createIndex('test', 'test_id_index', $index_def)).'
    '); - - if ($mdb2_type == 'mysql') { - $schema->db->setOption('debug', true); - $schema->db->setOption('log_line_break', '
    '); - // ok now lets create a new xml schema file from the existing DB - $database_definition = $schema->getDefinitionFromDatabase(); - // we will not use the 'metapear_test_db.schema' for this - // this feature is especially interesting for people that have an existing Db and want to move to MDB2's xml schema management - // you can also try MDB2_MANAGER_DUMP_ALL and MDB2_MANAGER_DUMP_CONTENT - echo(Var_Dump($schema->dumpDatabase( - $database_definition, - array( - 'output_mode' => 'file', - 'output' => $mdb2_name.'2.schema' - ), - MDB2_SCHEMA_DUMP_STRUCTURE - )).'
    '); - if ($schema->db->getOption('debug') === true) { - echo($schema->db->getDebugOutput().'
    '); - } - // this is the database definition as an array - echo(Var_Dump($database_definition).'
    '); - } - - echo('
    just a simple delete query:
    '); - echo(Var_Dump($mdb2->exec('DELETE FROM numbers')).'
    '); - // You can disconnect from the database with: - $mdb2->disconnect() -?> diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/docs/examples/example_php5.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/docs/examples/example_php5.php --- php-mdb2-2.4.1/MDB2-2.4.1/docs/examples/example_php5.php 2007-05-03 19:58:15.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.4.1/docs/examples/example_php5.php 1970-01-01 01:00:00.000000000 +0100 @@ -1,100 +0,0 @@ -
    - 'pgsql',
    -    'username' => 'postgres',
    -#    'phptype'  => 'mysql',
    -#    'username' => 'root',
    -    'password' => 'test',
    -    'hostspec' => 'localhost',
    -    'database' => 'driver_test',
    -);
    -#$dsn = 'sqlite:///:memory:';
    -
    -// create MDB2 instance
    -$mdb2 = MDB2::factory($dsn);
    -if (PEAR::isError($mdb2)) {
    -    die($mdb2->getMessage());
    -}
    -
    -// set the default fetchmode
    -$mdb2->setFetchMode(MDB2_FETCHMODE_ASSOC);
    -
    -$fields = array(
    -    'id' => array(
    -        'type'     => 'integer',
    -        'unsigned' => true,
    -        'autoincrement'  => true,
    -    ),
    -    'somename' => array(
    -        'type'     => 'text',
    -        'length'   => 12,
    -    ),
    -    'somedate'  => array(
    -        'type'     => 'date',
    -    ),
    -);
    -$table = 'sometable';
    -
    -// create a table
    -// since we are on php5 we can use the magic __call() method to:
    -// - load the manager module: $mdb2->loadModule('Manager', null, true);
    -// - redirect the method call to the manager module: $mdb2->manager->createTable('sometable', $fields);
    -$mdb2->mgCreateTable($table, $fields);
    -
    -$query = "INSERT INTO $table (somename, somedate) VALUES (:name, :date)";
    -// parameters:
    -// 1) the query (notice we are using named parameters, but we could also use ? instead
    -// 2) types of the placeholders (either keyed numerically in order or by name)
    -// 3) MDB2_PREPARE_MANIP denotes a DML statement
    -$stmt = $mdb2->prepare($query, array('text', 'date'), MDB2_PREPARE_MANIP);
    -if (PEAR::isError($stmt)) {
    -    die($stmt->getMessage());
    -}
    -
    -// load Date helper class
    -MDB2::loadFile('Date');
    -
    -$stmt->execute(array('name' => 'hello', 'date' => MDB2_Date::mdbToday()));
    -// get the last inserted id
    -echo 'last insert id: ';
    -var_dump($mdb2->lastInsertId($table, 'id'));
    -$stmt->execute(array('name' => 'world', 'date' => '2005-11-11'));
    -// get the last inserted id
    -echo 'last insert id: ';
    -var_dump($mdb2->lastInsertId($table, 'id'));
    -
    -// load Iterator implementations
    -MDB2::loadFile('Iterator');
    -
    -$query = 'SELECT * FROM '.$table;
    -// parameters:
    -// 1) the query
    -// 2) true means MDB2 tries to determine the result set type automatically
    -// 3) true is the default and means that internally a MDB2_Result instance should be created
    -// 4) 'MDB2_BufferedIterator' means the MDB2_Result should be wrapped inside an SeekableIterator
    -$result = $mdb2->query($query, true, true, 'MDB2_BufferedIterator');
    -
    -// iterate over the result set
    -foreach ($result as $row) {
    -    echo 'output row:
    '; - var_dump($row); -} - -// call drop table, since dropTable is not implemented in our instance -// but inside the loaded Manager module __call() will find it there and -// will redirect the call accordingly -// we could also have done: -// $mdb2->manager->dropTable($table); or -// $mdb2->mgDropTable($table); -$mdb2->dropTable($table); - -?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/docs/examples/metapear_test_db.schema /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/docs/examples/metapear_test_db.schema --- php-mdb2-2.4.1/MDB2-2.4.1/docs/examples/metapear_test_db.schema 2007-05-03 19:58:15.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.4.1/docs/examples/metapear_test_db.schema 1970-01-01 01:00:00.000000000 +0100 @@ -1,112 +0,0 @@ - - - - metapear_test_db - 1 - - - - numbers - - - - - number - integer - 1 - 0 - - - - trans_en - text - 100 - - - - - trans_fr - text - 100 - - - - - -
    - - - - test - - - - - test_id - integer - 1 - 0 - - - - test_name - text - 30 - 1 - no name - - - - test_date - timestamp - 1 - 0000-00-00 00:00:00 - - - - - - - - - - test_id - 1 - - - - test_name - test0r - - - - test_date - 2002-02-12 16:33:53 - - - - - - - - test_id - 2 - - - - test_name - gummihuhn - - - - test_date - 2001-02-12 16:34:03 - - - - - - -
    - -
    diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/docs/MAINTAINERS /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/docs/MAINTAINERS --- php-mdb2-2.4.1/MDB2-2.4.1/docs/MAINTAINERS 2007-05-03 19:58:15.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.4.1/docs/MAINTAINERS 1970-01-01 01:00:00.000000000 +0100 @@ -1,11 +0,0 @@ -Maintainers for MDB2 database backends/drivers: - -ibase : Lorenzo Alberton -mssql : David Coallier -mysqli : Lukas Smith -oci8 : Lukas Smith -pgsql : Lukas Smith -fbsql : unmaintained -sqlite : Lukas Smith -querysim : Lukas Smith diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/docs/README /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/docs/README --- php-mdb2-2.4.1/MDB2-2.4.1/docs/README 2007-05-03 19:58:15.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.4.1/docs/README 1970-01-01 01:00:00.000000000 +0100 @@ -1,183 +0,0 @@ -** Introduction: - -PEAR MDB2 is a project to merge PEAR DB and Metabase into one DB -abstraction layer. - -You can get info on these at: - PEAR DB: http://pear.php.net - Metabase: http://phpclasses.upperdesign.com/browse.html/package/20/ - -At these URLs you will also find the licensing information on these two -projects along with the credits. - -Actually MDB2 is the second major version of MDB. -The main differences between the new MDB2 and the old MDB version is -that the API has been drastically refactored to clean up the API -and improve performance. - -If you have any questions or suggestions you can contact me (Lukas Smith) -at this email address: - smith@backendmedia.com -Co-Author is Christopher Linn: - clinn@backendmedia.com - -Or even better post a message to pear-dev@lists.php.net mailinglist for -development related questions of the MDB2 package itself. For questions -using MDB2 pelase direct your questions at pear-general@lists.php.net. - -** Features - -MDB2 provides a common API for all support RDBMS. The main difference to most -other DB abstraction packages is that MDB2 goes much further to ensure -portability. Among other things MDB2 features: -* An OO-style query API -* A DSN (data source name) or array format for specifying database servers -* Datatype abstraction and on demand datatype conversion -* Portable error codes -* Sequential and non sequential row fetching as well as bulk fetching -* Ordered array and associative array for the fetched rows -* Buffered and Unbuffered fetching -* Prepare/execute (bind) emulation -* Sequence emulation -* Replace emulation -* Limited Subselect emulation -* Row limit support -* Transactions support -* Large Object support -* Index/Unique support -* Extension Framework to load advanced functionality on demand -* Table information interface -* RDBMS management methods (creating, dropping, altering) -* RDBMS independent xml based schema definition management -* Altering of a DB from a changed xml schema -* Reverse engineering of xml schemas from an existing DB (currently MySQL and PgSQl) -* Full integration into the PEAR Framework -* PHPDoc API documentation - -** Getting started: - -I would first recommend taking a look at example.php. -This should give you a general feel of how to interact with MDB2. - -After that you may want to take a look at the rather large API -at www.backendmedia.com/MDB2/docs. There you will also find a document -describing the xml schema format and a little tutorial (it was -just recently ported from Metabase, so it may contain errors). - -** Current State: - -The current release can be found at the PEAR webpage: - http://pear.php.net/package-info.php?package=MDB2 - -** Package Content: - -As a user the only php script you will need to include is MDB2.php which will -install to your PEAR root directory. All other files and their containing -classes will be included via MDB2::factory(), MDB2::connect(), MDB2::singleton(). - -These will load additional classes. Most classes are loaded on demand. - -Furthermore MDB2 provides an extensive testing framework that works through a -browser and command line interface. There are several other test that test the -two wrappers. These files will install into your test dir found in the -PEAR root dir. - -** Documentation: - -You can find the still incomplete documentation for MDB2 here: -http://pear.php.net/manual/en/package.database.mdb2.php - -PHPDoc generated documentation can be found at: -http://www.backendmedia.com/MDB2/docs/ - -The entire "public" API and most of the "private" methods (except for some of -the lob classes) have been documented with PHPDoc comments. Most of the API -is borrowed from extPDO, so you can look there for detailed documentation. -Since there are a large number of new methods available thanks to the Metabase -heritage of MDB2 you will also have to take a look in the Metabase documentation -(which can be found at the URL mentioned above, but does require that -you register with phpclasses). Most of these Metabase functions have -been renamed and changed considerably. The main things left are the datatypes -and the manager module. - -For example ($db being an MDB2 object): - $converted_value = MetabaseGetTimestampFieldValue($database, $value); -would now be - $converted_value = $db->quote($value, 'timestamp'); - -If you want to help out with documentation please email me. - -** Testing: - -For most of the tests you can set the username/password/hostname in the relevant -config file. The user will need to have the right to create new databases. - -test.php/clitest.php/testchoose.php: Is the native testing suite provided by -MDB2. Please see the README in the tests directory for details. - -example.php: Several test calls to MDB2's native API. It require PEAR::VAR_Dump -package and are configured to use the following settings: -username = metapear -password = funky -hostname = localhost - -** How to write new Drivers: - -Skeleton drivers are provided in the docs directory of the MDB2 package. - -The best course of action would be to take a MDB2 driver and hack it to fit -the new RDBMS. This will surely be faster and it will ensure that the new -driver takes full advantage of the MDB2 framework. I would however recommend -working with the existing Metabase driver for inspiration that RDBMS when -doing those changes. - -In order to check compliance of the driver with MDB2 you can use the testing -suite (see the "testing" section above) - -** History - -MDB was started after Manuel broad be into the discussion about getting the -features of Metabase into PEAR that was going on (again) in December 2001. He -suggested that I could take on this project. After alot of discussion about -how when and if etc I started development in February 2002. - -MDB is based on Metabase but has been reworked severely to better match -the PEAR DB API and PEAR CS. The approach I have taken so far is to take DB.php -from PEAR DB and make it create a Metabase object. I have changed the -Metabase structure slightly. The formatting has been reworked -considerably to better fit the final structure (MDB standalone with a -BC-wrapper for Metabase and PEAR DB), to fit the PEAR CS and to make it -easier for other people to contribute. - -The metabase_interface.php was been renamed to metabase_wrapper.php and -now only serves as a wrapper to keep BC with Metabase. A wrapper will -have to be created for PEAR DB as well. - -Basically the result is a Metabase that is really close to the PEAR DB -structure. I have also added any missing methods from PEAR DB. Work on -moving the error handling to PEAR error handling is under way but still -needs some work. - -In MDB2 the API was heavily refactored to be even more streamlined. Redundant -features have been removed. Some features where moved out of the core into -separate loadable modules. Instead of resources resultsets are now wrapped -into objects similar to PEAR DB. - -** Credits (never to early for those huh? :-) ): - -I would especially like to thank Manuel Lemos (Author of Metabase) for -getting me involved in this and generally being around to ask questions. -I would also like to thank Tomas Cox and Stig S. Bakken from the PEAR -projects for help in undertstanding PEAR, solving problems and trusting -me enough. Paul Cooper for the work on the pgsql driver. Furthermore I -would like to thank Alex Black for being so enthusiastic about this -project and offering binarycloud as a test bed for this project. -Christian Dickmann for being the first to put MDB to some real use, -making MDB use PEAR Error and working on the XML schema manager. - -Finally Peter Bowyer for starting the discussion that made people pick -up this project again after the first versions of what was then called -"metapear" have been ideling without much feedback. I guess I should -also thank BackendMedia (my company :-) ) for providing the necessary means -to develop this on company time (actually for the most part my entire -life is company time ... so it goes) \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/docs/STATUS /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/docs/STATUS --- php-mdb2-2.4.1/MDB2-2.4.1/docs/STATUS 2007-05-03 19:58:15.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.4.1/docs/STATUS 1970-01-01 01:00:00.000000000 +0100 @@ -1,50 +0,0 @@ -STATUS OF THE PEAR MDB2 PACKAGE -============================= - -$Id: STATUS,v 1.15 2006/05/03 16:07:41 lsmith Exp $ ------------------------------------------------------------------------- - -MDB2 Driver Feature Matrix ------------------------- -Symbols: - x = implemented, but without tests - t = implemented, but one or more tests fail - T = implemented, passing all tests - e = emulated, without tests - l = emulated, but one or more tests fail - E = emulated, passing all tests - n = returns "not capable" - - = no implementation of this feature or status unknown - - fbsql pgsql mysqli sqlite -FEATURE ibase | oci8 | mysql | mssql | querysim - - - -Test Conformance ----------------- -Symbols: - o = Test passed - X = Test failed - L = Some portions of the test failed due to limitations in PHP or DBMS - n = Test returns "not capable" - - = Not tested - - fbsql pgsql mysqli sqlite -TEST ibase | oci8 | mysql | mssql | querysim - - -DBMS Versions Tested --------------------- -fbsql -ibase -mssql -mysql -mysqli -oci8 -pgsql -sqlite -querysim - -Tests were performed under both of the following PHP versions -unles otherwise noted: diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/docs/TODO /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/docs/TODO --- php-mdb2-2.4.1/MDB2-2.4.1/docs/TODO 2007-05-03 19:58:15.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.4.1/docs/TODO 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -see http://oss.backendmedia.com/index.php?area=MDB2&page=ToDo diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/LICENSE /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/LICENSE --- php-mdb2-2.4.1/MDB2-2.4.1/LICENSE 2007-05-03 19:58:15.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.4.1/LICENSE 1970-01-01 01:00:00.000000000 +0100 @@ -1,38 +0,0 @@ -// +----------------------------------------------------------------------+ -// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, | -// | Stig. S. Bakken, Lukas Smith | -// | All rights reserved. | -// +----------------------------------------------------------------------+ -// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | -// | API as well as database abstraction for PHP applications. | -// | This LICENSE is in the BSD license style. | -// | | -// | Redistribution and use in source and binary forms, with or without | -// | modification, are permitted provided that the following conditions | -// | are met: | -// | | -// | Redistributions of source code must retain the above copyright | -// | notice, this list of conditions and the following disclaimer. | -// | | -// | Redistributions in binary form must reproduce the above copyright | -// | notice, this list of conditions and the following disclaimer in the | -// | documentation and/or other materials provided with the distribution. | -// | | -// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | -// | Lukas Smith nor the names of his contributors may be used to endorse | -// | or promote products derived from this software without specific prior| -// | written permission. | -// | | -// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | -// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | -// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | -// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | -// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | -// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | -// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| -// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | -// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| -// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | -// | POSSIBILITY OF SUCH DAMAGE. | -// +----------------------------------------------------------------------+ \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/MDB2/Date.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/MDB2/Date.php --- php-mdb2-2.4.1/MDB2-2.4.1/MDB2/Date.php 2007-05-03 19:58:15.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.4.1/MDB2/Date.php 1970-01-01 01:00:00.000000000 +0100 @@ -1,183 +0,0 @@ - | -// +----------------------------------------------------------------------+ -// -// $Id: Date.php,v 1.10 2006/03/01 12:15:32 lsmith Exp $ -// - -/** - * @package MDB2 - * @category Database - * @author Lukas Smith - */ - -/** - * Several methods to convert the MDB2 native timestamp format (ISO based) - * to and from data structures that are convenient to worth with in side of php. - * For more complex date arithmetic please take a look at the Date package in PEAR - * - * @package MDB2 - * @category Database - * @author Lukas Smith - */ -class MDB2_Date -{ - // {{{ mdbNow() - - /** - * return the current datetime - * - * @return string current datetime in the MDB2 format - * @access public - */ - function mdbNow() - { - return date('Y-m-d H:i:s'); - } - // }}} - - // {{{ mdbToday() - - /** - * return the current date - * - * @return string current date in the MDB2 format - * @access public - */ - function mdbToday() - { - return date('Y-m-d'); - } - // }}} - - // {{{ mdbTime() - - /** - * return the current time - * - * @return string current time in the MDB2 format - * @access public - */ - function mdbTime() - { - return date('H:i:s'); - } - // }}} - - // {{{ date2Mdbstamp() - - /** - * convert a date into a MDB2 timestamp - * - * @param int hour of the date - * @param int minute of the date - * @param int second of the date - * @param int month of the date - * @param int day of the date - * @param int year of the date - * - * @return string a valid MDB2 timestamp - * @access public - */ - function date2Mdbstamp($hour = null, $minute = null, $second = null, - $month = null, $day = null, $year = null) - { - return MDB2_Date::unix2Mdbstamp(mktime($hour, $minute, $second, $month, $day, $year, -1)); - } - // }}} - - // {{{ unix2Mdbstamp() - - /** - * convert a unix timestamp into a MDB2 timestamp - * - * @param int a valid unix timestamp - * - * @return string a valid MDB2 timestamp - * @access public - */ - function unix2Mdbstamp($unix_timestamp) - { - return date('Y-m-d H:i:s', $unix_timestamp); - } - // }}} - - // {{{ mdbstamp2Unix() - - /** - * convert a MDB2 timestamp into a unix timestamp - * - * @param int a valid MDB2 timestamp - * @return string unix timestamp with the time stored in the MDB2 format - * - * @access public - */ - function mdbstamp2Unix($mdb_timestamp) - { - $arr = MDB2_Date::mdbstamp2Date($mdb_timestamp); - - return mktime($arr['hour'], $arr['minute'], $arr['second'], $arr['month'], $arr['day'], $arr['year'], -1); - } - // }}} - - // {{{ mdbstamp2Date() - - /** - * convert a MDB2 timestamp into an array containing all - * values necessary to pass to php's date() function - * - * @param int a valid MDB2 timestamp - * - * @return array with the time split - * @access public - */ - function mdbstamp2Date($mdb_timestamp) - { - list($arr['year'], $arr['month'], $arr['day'], $arr['hour'], $arr['minute'], $arr['second']) = - sscanf($mdb_timestamp, "%04u-%02u-%02u %02u:%02u:%02u"); - return $arr; - } - // }}} -} - -?> diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/MDB2/Driver/Datatype/Common.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/MDB2/Driver/Datatype/Common.php --- php-mdb2-2.4.1/MDB2-2.4.1/MDB2/Driver/Datatype/Common.php 2007-05-03 19:58:15.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.4.1/MDB2/Driver/Datatype/Common.php 1970-01-01 01:00:00.000000000 +0100 @@ -1,1837 +0,0 @@ - | -// +----------------------------------------------------------------------+ -// -// $Id: Common.php,v 1.126 2007/03/28 16:49:43 quipo Exp $ - -require_once 'MDB2/LOB.php'; - -/** - * @package MDB2 - * @category Database - * @author Lukas Smith - */ - -/** - * MDB2_Driver_Common: Base class that is extended by each MDB2 driver - * - * @package MDB2 - * @category Database - * @author Lukas Smith - */ -class MDB2_Driver_Datatype_Common extends MDB2_Module_Common -{ - var $valid_default_values = array( - 'text' => '', - 'boolean' => true, - 'integer' => 0, - 'decimal' => 0.0, - 'float' => 0.0, - 'timestamp' => '1970-01-01 00:00:00', - 'time' => '00:00:00', - 'date' => '1970-01-01', - 'clob' => '', - 'blob' => '', - ); - - /** - * contains all LOB objects created with this MDB2 instance - * @var array - * @access protected - */ - var $lobs = array(); - - // }}} - // {{{ getValidTypes() - - /** - * Get the list of valid types - * - * This function returns an array of valid types as keys with the values - * being possible default values for all native datatypes and mapped types - * for custom datatypes. - * - * @return mixed array on success, a MDB2 error on failure - * @access public - */ - function getValidTypes() - { - $types = $this->valid_default_values; - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - if (!empty($db->options['datatype_map'])) { - foreach ($db->options['datatype_map'] as $type => $mapped_type) { - if (array_key_exists($mapped_type, $types)) { - $types[$type] = $types[$mapped_type]; - } elseif (!empty($db->options['datatype_map_callback'][$type])) { - $parameter = array('type' => $type, 'mapped_type' => $mapped_type); - $default = call_user_func_array($db->options['datatype_map_callback'][$type], array(&$db, __FUNCTION__, $parameter)); - $types[$type] = $default; - } - } - } - return $types; - } - - // }}} - // {{{ checkResultTypes() - - /** - * Define the list of types to be associated with the columns of a given - * result set. - * - * This function may be called before invoking fetchRow(), fetchOne() - * fetchCole() and fetchAll() so that the necessary data type - * conversions are performed on the data to be retrieved by them. If this - * function is not called, the type of all result set columns is assumed - * to be text, thus leading to not perform any conversions. - * - * @param array $types array variable that lists the - * data types to be expected in the result set columns. If this array - * contains less types than the number of columns that are returned - * in the result set, the remaining columns are assumed to be of the - * type text. Currently, the types clob and blob are not fully - * supported. - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function checkResultTypes($types) - { - $types = is_array($types) ? $types : array($types); - foreach ($types as $key => $type) { - if (!isset($this->valid_default_values[$type])) { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - if (empty($db->options['datatype_map'][$type])) { - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - $type.' for '.$key.' is not a supported column type', __FUNCTION__); - } - } - } - return $types; - } - - // }}} - // {{{ _baseConvertResult() - - /** - * General type conversion method - * - * @param mixed $value reference to a value to be converted - * @param string $type specifies which type to convert to - * @param boolean $rtrim [optional] when TRUE [default], apply rtrim() to text - * @return object an MDB2 error on failure - * @access protected - */ - function _baseConvertResult($value, $type, $rtrim = true) - { - switch ($type) { - case 'text': - if ($rtrim) { - $value = rtrim($value); - } - return $value; - case 'integer': - return intval($value); - case 'boolean': - return !empty($value); - case 'decimal': - return $value; - case 'float': - return doubleval($value); - case 'date': - return $value; - case 'time': - return $value; - case 'timestamp': - return $value; - case 'clob': - case 'blob': - $this->lobs[] = array( - 'buffer' => null, - 'position' => 0, - 'lob_index' => null, - 'endOfLOB' => false, - 'resource' => $value, - 'value' => null, - 'loaded' => false, - ); - end($this->lobs); - $lob_index = key($this->lobs); - $this->lobs[$lob_index]['lob_index'] = $lob_index; - return fopen('MDB2LOB://'.$lob_index.'@'.$this->db_index, 'r+'); - } - - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - return $db->raiseError(MDB2_ERROR_INVALID, null, null, - 'attempt to convert result value to an unknown type :' . $type, __FUNCTION__); - } - - // }}} - // {{{ convertResult() - - /** - * Convert a value to a RDBMS indipendent MDB2 type - * - * @param mixed $value value to be converted - * @param string $type specifies which type to convert to - * @param boolean $rtrim [optional] when TRUE [default], apply rtrim() to text - * @return mixed converted value - * @access public - */ - function convertResult($value, $type, $rtrim = true) - { - if (is_null($value)) { - return null; - } - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - if (!empty($db->options['datatype_map'][$type])) { - $type = $db->options['datatype_map'][$type]; - if (!empty($db->options['datatype_map_callback'][$type])) { - $parameter = array('type' => $type, 'value' => $value, 'rtrim' => $rtrim); - return call_user_func_array($db->options['datatype_map_callback'][$type], array(&$db, __FUNCTION__, $parameter)); - } - } - return $this->_baseConvertResult($value, $type, $rtrim); - } - - // }}} - // {{{ convertResultRow() - - /** - * Convert a result row - * - * @param array $types - * @param array $row specifies the types to convert to - * @param boolean $rtrim [optional] when TRUE [default], apply rtrim() to text - * @return mixed MDB2_OK on success, an MDB2 error on failure - * @access public - */ - function convertResultRow($types, $row, $rtrim = true) - { - $types = $this->_sortResultFieldTypes(array_keys($row), $types); - foreach ($row as $key => $value) { - if (empty($types[$key])) { - continue; - } - $value = $this->convertResult($row[$key], $types[$key], $rtrim); - if (PEAR::isError($value)) { - return $value; - } - $row[$key] = $value; - } - return $row; - } - - // }}} - // {{{ _sortResultFieldTypes() - - /** - * convert a result row - * - * @param array $types - * @param array $row specifies the types to convert to - * @param bool $rtrim if to rtrim text values or not - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function _sortResultFieldTypes($columns, $types) - { - $n_cols = count($columns); - $n_types = count($types); - if ($n_cols > $n_types) { - for ($i= $n_cols - $n_types; $i >= 0; $i--) { - $types[] = null; - } - } - $sorted_types = array(); - foreach ($columns as $col) { - $sorted_types[$col] = null; - } - foreach ($types as $name => $type) { - if (array_key_exists($name, $sorted_types)) { - $sorted_types[$name] = $type; - unset($types[$name]); - } - } - // if there are left types in the array, fill the null values of the - // sorted array with them, in order. - if (count($types)) { - reset($types); - foreach (array_keys($sorted_types) as $k) { - if (is_null($sorted_types[$k])) { - $sorted_types[$k] = current($types); - next($types); - } - } - } - return $sorted_types; - } - - // }}} - // {{{ getDeclaration() - - /** - * Obtain DBMS specific SQL code portion needed to declare - * of the given type - * - * @param string $type type to which the value should be converted to - * @param string $name name the field to be declared. - * @param string $field definition of the field - * @return string DBMS specific SQL code portion that should be used to - * declare the specified field. - * @access public - */ - function getDeclaration($type, $name, $field) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - if (!empty($db->options['datatype_map'][$type])) { - $type = $db->options['datatype_map'][$type]; - if (!empty($db->options['datatype_map_callback'][$type])) { - $parameter = array('type' => $type, 'name' => $name, 'field' => $field); - return call_user_func_array($db->options['datatype_map_callback'][$type], array(&$db, __FUNCTION__, $parameter)); - } - $field['type'] = $type; - } - - if (!method_exists($this, "_get{$type}Declaration")) { - return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, - 'type not defined: '.$type, __FUNCTION__); - } - return $this->{"_get{$type}Declaration"}($name, $field); - } - - // }}} - // {{{ getTypeDeclaration() - - /** - * Obtain DBMS specific SQL code portion needed to declare an text type - * field to be used in statements like CREATE TABLE. - * - * @param array $field associative array with the name of the properties - * of the field being declared as array indexes. Currently, the types - * of supported field properties are as follows: - * - * length - * Integer value that determines the maximum length of the text - * field. If this argument is missing the field should be - * declared to have the longest length allowed by the DBMS. - * - * default - * Text value to be used as default for this field. - * - * notnull - * Boolean flag that indicates whether this field is constrained - * to not be set to null. - * @return string DBMS specific SQL code portion that should be used to - * declare the specified field. - * @access public - */ - function getTypeDeclaration($field) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - switch ($field['type']) { - case 'text': - $length = !empty($field['length']) ? $field['length'] : $db->options['default_text_field_length']; - $fixed = !empty($field['fixed']) ? $field['fixed'] : false; - return $fixed ? ($length ? 'CHAR('.$length.')' : 'CHAR('.$db->options['default_text_field_length'].')') - : ($length ? 'VARCHAR('.$length.')' : 'TEXT'); - case 'clob': - return 'TEXT'; - case 'blob': - return 'TEXT'; - case 'integer': - return 'INT'; - case 'boolean': - return 'INT'; - case 'date': - return 'CHAR ('.strlen('YYYY-MM-DD').')'; - case 'time': - return 'CHAR ('.strlen('HH:MM:SS').')'; - case 'timestamp': - return 'CHAR ('.strlen('YYYY-MM-DD HH:MM:SS').')'; - case 'float': - return 'TEXT'; - case 'decimal': - return 'TEXT'; - } - return ''; - } - - // }}} - // {{{ _getDeclaration() - - /** - * Obtain DBMS specific SQL code portion needed to declare a generic type - * field to be used in statements like CREATE TABLE. - * - * @param string $name name the field to be declared. - * @param array $field associative array with the name of the properties - * of the field being declared as array indexes. Currently, the types - * of supported field properties are as follows: - * - * length - * Integer value that determines the maximum length of the text - * field. If this argument is missing the field should be - * declared to have the longest length allowed by the DBMS. - * - * default - * Text value to be used as default for this field. - * - * notnull - * Boolean flag that indicates whether this field is constrained - * to not be set to null. - * charset - * Text value with the default CHARACTER SET for this field. - * collation - * Text value with the default COLLATION for this field. - * @return string DBMS specific SQL code portion that should be used to - * declare the specified field, or a MDB2_Error on failure - * @access protected - */ - function _getDeclaration($name, $field) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $name = $db->quoteIdentifier($name, true); - $declaration_options = $db->datatype->_getDeclarationOptions($field); - if (PEAR::isError($declaration_options)) { - return $declaration_options; - } - return $name.' '.$this->getTypeDeclaration($field).$declaration_options; - } - - // }}} - // {{{ _getDeclarationOptions() - - /** - * Obtain DBMS specific SQL code portion needed to declare a generic type - * field to be used in statement like CREATE TABLE, without the field name - * and type values (ie. just the character set, default value, if the - * field is permitted to be NULL or not, and the collation options). - * - * @param array $field associative array with the name of the properties - * of the field being declared as array indexes. Currently, the types - * of supported field properties are as follows: - * - * default - * Text value to be used as default for this field. - * notnull - * Boolean flag that indicates whether this field is constrained - * to not be set to null. - * charset - * Text value with the default CHARACTER SET for this field. - * collation - * Text value with the default COLLATION for this field. - * @return string DBMS specific SQL code portion that should be used to - * declare the specified field's options. - * @access protected - */ - function _getDeclarationOptions($field) - { - $charset = empty($field['charset']) ? '' : - ' '.$this->_getCharsetFieldDeclaration($field['charset']); - - $default = ''; - if (array_key_exists('default', $field)) { - if ($field['default'] === '') { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - if (empty($field['notnull'])) { - $field['default'] = null; - } else { - $valid_default_values = $this->getValidTypes(); - $field['default'] = $valid_default_values[$field['type']]; - } - if ($field['default'] === '' - && ($db->options['portability'] & MDB2_PORTABILITY_EMPTY_TO_NULL) - ) { - $field['default'] = ' '; - } - } - $default = ' DEFAULT '.$this->quote($field['default'], $field['type']); - } elseif (empty($field['notnull'])) { - $default = ' DEFAULT NULL'; - } - - $notnull = empty($field['notnull']) ? '' : ' NOT NULL'; - - $collation = empty($field['collation']) ? '' : - ' '.$this->_getCollationFieldDeclaration($field['collation']); - return $charset.$default.$notnull.$collation; - } - - // }}} - // {{{ _getCharsetFieldDeclaration() - - /** - * Obtain DBMS specific SQL code portion needed to set the CHARACTER SET - * of a field declaration to be used in statements like CREATE TABLE. - * - * @param string $charset name of the charset - * @return string DBMS specific SQL code portion needed to set the CHARACTER SET - * of a field declaration. - */ - function _getCharsetFieldDeclaration($charset) - { - return ''; - } - - // }}} - // {{{ _getCollationFieldDeclaration() - - /** - * Obtain DBMS specific SQL code portion needed to set the COLLATION - * of a field declaration to be used in statements like CREATE TABLE. - * - * @param string $collation name of the collation - * @return string DBMS specific SQL code portion needed to set the COLLATION - * of a field declaration. - */ - function _getCollationFieldDeclaration($collation) - { - return ''; - } - - // }}} - // {{{ _getIntegerDeclaration() - - /** - * Obtain DBMS specific SQL code portion needed to declare an integer type - * field to be used in statements like CREATE TABLE. - * - * @param string $name name the field to be declared. - * @param array $field associative array with the name of the properties - * of the field being declared as array indexes. Currently, the types - * of supported field properties are as follows: - * - * unsigned - * Boolean flag that indicates whether the field should be - * declared as unsigned integer if possible. - * - * default - * Integer value to be used as default for this field. - * - * notnull - * Boolean flag that indicates whether this field is constrained - * to not be set to null. - * @return string DBMS specific SQL code portion that should be used to - * declare the specified field. - * @access protected - */ - function _getIntegerDeclaration($name, $field) - { - if (!empty($field['unsigned'])) { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $db->warnings[] = "unsigned integer field \"$name\" is being declared as signed integer"; - } - return $this->_getDeclaration($name, $field); - } - - // }}} - // {{{ _getTextDeclaration() - - /** - * Obtain DBMS specific SQL code portion needed to declare an text type - * field to be used in statements like CREATE TABLE. - * - * @param string $name name the field to be declared. - * @param array $field associative array with the name of the properties - * of the field being declared as array indexes. Currently, the types - * of supported field properties are as follows: - * - * length - * Integer value that determines the maximum length of the text - * field. If this argument is missing the field should be - * declared to have the longest length allowed by the DBMS. - * - * default - * Text value to be used as default for this field. - * - * notnull - * Boolean flag that indicates whether this field is constrained - * to not be set to null. - * @return string DBMS specific SQL code portion that should be used to - * declare the specified field. - * @access protected - */ - function _getTextDeclaration($name, $field) - { - return $this->_getDeclaration($name, $field); - } - - // }}} - // {{{ _getCLOBDeclaration() - - /** - * Obtain DBMS specific SQL code portion needed to declare an character - * large object type field to be used in statements like CREATE TABLE. - * - * @param string $name name the field to be declared. - * @param array $field associative array with the name of the properties - * of the field being declared as array indexes. Currently, the types - * of supported field properties are as follows: - * - * length - * Integer value that determines the maximum length of the large - * object field. If this argument is missing the field should be - * declared to have the longest length allowed by the DBMS. - * - * notnull - * Boolean flag that indicates whether this field is constrained - * to not be set to null. - * @return string DBMS specific SQL code portion that should be used to - * declare the specified field. - * @access public - */ - function _getCLOBDeclaration($name, $field) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $notnull = empty($field['notnull']) ? '' : ' NOT NULL'; - $name = $db->quoteIdentifier($name, true); - return $name.' '.$this->getTypeDeclaration($field).$notnull; - } - - // }}} - // {{{ _getBLOBDeclaration() - - /** - * Obtain DBMS specific SQL code portion needed to declare an binary large - * object type field to be used in statements like CREATE TABLE. - * - * @param string $name name the field to be declared. - * @param array $field associative array with the name of the properties - * of the field being declared as array indexes. Currently, the types - * of supported field properties are as follows: - * - * length - * Integer value that determines the maximum length of the large - * object field. If this argument is missing the field should be - * declared to have the longest length allowed by the DBMS. - * - * notnull - * Boolean flag that indicates whether this field is constrained - * to not be set to null. - * @return string DBMS specific SQL code portion that should be used to - * declare the specified field. - * @access protected - */ - function _getBLOBDeclaration($name, $field) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $notnull = empty($field['notnull']) ? '' : ' NOT NULL'; - $name = $db->quoteIdentifier($name, true); - return $name.' '.$this->getTypeDeclaration($field).$notnull; - } - - // }}} - // {{{ _getBooleanDeclaration() - - /** - * Obtain DBMS specific SQL code portion needed to declare a boolean type - * field to be used in statements like CREATE TABLE. - * - * @param string $name name the field to be declared. - * @param array $field associative array with the name of the properties - * of the field being declared as array indexes. Currently, the types - * of supported field properties are as follows: - * - * default - * Boolean value to be used as default for this field. - * - * notnullL - * Boolean flag that indicates whether this field is constrained - * to not be set to null. - * @return string DBMS specific SQL code portion that should be used to - * declare the specified field. - * @access protected - */ - function _getBooleanDeclaration($name, $field) - { - return $this->_getDeclaration($name, $field); - } - - // }}} - // {{{ _getDateDeclaration() - - /** - * Obtain DBMS specific SQL code portion needed to declare a date type - * field to be used in statements like CREATE TABLE. - * - * @param string $name name the field to be declared. - * @param array $field associative array with the name of the properties - * of the field being declared as array indexes. Currently, the types - * of supported field properties are as follows: - * - * default - * Date value to be used as default for this field. - * - * notnull - * Boolean flag that indicates whether this field is constrained - * to not be set to null. - * @return string DBMS specific SQL code portion that should be used to - * declare the specified field. - * @access protected - */ - function _getDateDeclaration($name, $field) - { - return $this->_getDeclaration($name, $field); - } - - // }}} - // {{{ _getTimestampDeclaration() - - /** - * Obtain DBMS specific SQL code portion needed to declare a timestamp - * field to be used in statements like CREATE TABLE. - * - * @param string $name name the field to be declared. - * @param array $field associative array with the name of the properties - * of the field being declared as array indexes. Currently, the types - * of supported field properties are as follows: - * - * default - * Timestamp value to be used as default for this field. - * - * notnull - * Boolean flag that indicates whether this field is constrained - * to not be set to null. - * @return string DBMS specific SQL code portion that should be used to - * declare the specified field. - * @access protected - */ - function _getTimestampDeclaration($name, $field) - { - return $this->_getDeclaration($name, $field); - } - - // }}} - // {{{ _getTimeDeclaration() - - /** - * Obtain DBMS specific SQL code portion needed to declare a time - * field to be used in statements like CREATE TABLE. - * - * @param string $name name the field to be declared. - * @param array $field associative array with the name of the properties - * of the field being declared as array indexes. Currently, the types - * of supported field properties are as follows: - * - * default - * Time value to be used as default for this field. - * - * notnull - * Boolean flag that indicates whether this field is constrained - * to not be set to null. - * @return string DBMS specific SQL code portion that should be used to - * declare the specified field. - * @access protected - */ - function _getTimeDeclaration($name, $field) - { - return $this->_getDeclaration($name, $field); - } - - // }}} - // {{{ _getFloatDeclaration() - - /** - * Obtain DBMS specific SQL code portion needed to declare a float type - * field to be used in statements like CREATE TABLE. - * - * @param string $name name the field to be declared. - * @param array $field associative array with the name of the properties - * of the field being declared as array indexes. Currently, the types - * of supported field properties are as follows: - * - * default - * Float value to be used as default for this field. - * - * notnull - * Boolean flag that indicates whether this field is constrained - * to not be set to null. - * @return string DBMS specific SQL code portion that should be used to - * declare the specified field. - * @access protected - */ - function _getFloatDeclaration($name, $field) - { - return $this->_getDeclaration($name, $field); - } - - // }}} - // {{{ _getDecimalDeclaration() - - /** - * Obtain DBMS specific SQL code portion needed to declare a decimal type - * field to be used in statements like CREATE TABLE. - * - * @param string $name name the field to be declared. - * @param array $field associative array with the name of the properties - * of the field being declared as array indexes. Currently, the types - * of supported field properties are as follows: - * - * default - * Decimal value to be used as default for this field. - * - * notnull - * Boolean flag that indicates whether this field is constrained - * to not be set to null. - * @return string DBMS specific SQL code portion that should be used to - * declare the specified field. - * @access protected - */ - function _getDecimalDeclaration($name, $field) - { - return $this->_getDeclaration($name, $field); - } - - // }}} - // {{{ compareDefinition() - - /** - * Obtain an array of changes that may need to applied - * - * @param array $current new definition - * @param array $previous old definition - * @return array containing all changes that will need to be applied - * @access public - */ - function compareDefinition($current, $previous) - { - $type = !empty($current['type']) ? $current['type'] : null; - - if (!method_exists($this, "_compare{$type}Definition")) { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - if (!empty($db->options['datatype_map_callback'][$type])) { - $parameter = array('current' => $current, 'previous' => $previous); - $change = call_user_func_array($db->options['datatype_map_callback'][$type], array(&$db, __FUNCTION__, $parameter)); - return $change; - } - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'type "'.$current['type'].'" is not yet supported', __FUNCTION__); - } - - if (empty($previous['type']) || $previous['type'] != $type) { - return $current; - } - - $change = $this->{"_compare{$type}Definition"}($current, $previous); - - if ($previous['type'] != $type) { - $change['type'] = true; - } - - $previous_notnull = !empty($previous['notnull']) ? $previous['notnull'] : false; - $notnull = !empty($current['notnull']) ? $current['notnull'] : false; - if ($previous_notnull != $notnull) { - $change['notnull'] = true; - } - - $previous_default = array_key_exists('default', $previous) ? $previous['default'] : - ($previous_notnull ? '' : null); - $default = array_key_exists('default', $current) ? $current['default'] : - ($notnull ? '' : null); - if ($previous_default !== $default) { - $change['default'] = true; - } - - return $change; - } - - // }}} - // {{{ _compareIntegerDefinition() - - /** - * Obtain an array of changes that may need to applied to an integer field - * - * @param array $current new definition - * @param array $previous old definition - * @return array containing all changes that will need to be applied - * @access protected - */ - function _compareIntegerDefinition($current, $previous) - { - $change = array(); - $previous_unsigned = !empty($previous['unsigned']) ? $previous['unsigned'] : false; - $unsigned = !empty($current['unsigned']) ? $current['unsigned'] : false; - if ($previous_unsigned != $unsigned) { - $change['unsigned'] = true; - } - $previous_autoincrement = !empty($previous['autoincrement']) ? $previous['autoincrement'] : false; - $autoincrement = !empty($current['autoincrement']) ? $current['autoincrement'] : false; - if ($previous_autoincrement != $autoincrement) { - $change['autoincrement'] = true; - } - return $change; - } - - // }}} - // {{{ _compareTextDefinition() - - /** - * Obtain an array of changes that may need to applied to an text field - * - * @param array $current new definition - * @param array $previous old definition - * @return array containing all changes that will need to be applied - * @access protected - */ - function _compareTextDefinition($current, $previous) - { - $change = array(); - $previous_length = !empty($previous['length']) ? $previous['length'] : 0; - $length = !empty($current['length']) ? $current['length'] : 0; - if ($previous_length != $length) { - $change['length'] = true; - } - $previous_fixed = !empty($previous['fixed']) ? $previous['fixed'] : 0; - $fixed = !empty($current['fixed']) ? $current['fixed'] : 0; - if ($previous_fixed != $fixed) { - $change['fixed'] = true; - } - return $change; - } - - // }}} - // {{{ _compareCLOBDefinition() - - /** - * Obtain an array of changes that may need to applied to an CLOB field - * - * @param array $current new definition - * @param array $previous old definition - * @return array containing all changes that will need to be applied - * @access protected - */ - function _compareCLOBDefinition($current, $previous) - { - return $this->_compareTextDefinition($current, $previous); - } - - // }}} - // {{{ _compareBLOBDefinition() - - /** - * Obtain an array of changes that may need to applied to an BLOB field - * - * @param array $current new definition - * @param array $previous old definition - * @return array containing all changes that will need to be applied - * @access protected - */ - function _compareBLOBDefinition($current, $previous) - { - return $this->_compareTextDefinition($current, $previous); - } - - // }}} - // {{{ _compareDateDefinition() - - /** - * Obtain an array of changes that may need to applied to an date field - * - * @param array $current new definition - * @param array $previous old definition - * @return array containing all changes that will need to be applied - * @access protected - */ - function _compareDateDefinition($current, $previous) - { - return array(); - } - - // }}} - // {{{ _compareTimeDefinition() - - /** - * Obtain an array of changes that may need to applied to an time field - * - * @param array $current new definition - * @param array $previous old definition - * @return array containing all changes that will need to be applied - * @access protected - */ - function _compareTimeDefinition($current, $previous) - { - return array(); - } - - // }}} - // {{{ _compareTimestampDefinition() - - /** - * Obtain an array of changes that may need to applied to an timestamp field - * - * @param array $current new definition - * @param array $previous old definition - * @return array containing all changes that will need to be applied - * @access protected - */ - function _compareTimestampDefinition($current, $previous) - { - return array(); - } - - // }}} - // {{{ _compareBooleanDefinition() - - /** - * Obtain an array of changes that may need to applied to an boolean field - * - * @param array $current new definition - * @param array $previous old definition - * @return array containing all changes that will need to be applied - * @access protected - */ - function _compareBooleanDefinition($current, $previous) - { - return array(); - } - - // }}} - // {{{ _compareFloatDefinition() - - /** - * Obtain an array of changes that may need to applied to an float field - * - * @param array $current new definition - * @param array $previous old definition - * @return array containing all changes that will need to be applied - * @access protected - */ - function _compareFloatDefinition($current, $previous) - { - return array(); - } - - // }}} - // {{{ _compareDecimalDefinition() - - /** - * Obtain an array of changes that may need to applied to an decimal field - * - * @param array $current new definition - * @param array $previous old definition - * @return array containing all changes that will need to be applied - * @access protected - */ - function _compareDecimalDefinition($current, $previous) - { - return array(); - } - - // }}} - // {{{ quote() - - /** - * Convert a text value into a DBMS specific format that is suitable to - * compose query statements. - * - * @param string $value text string value that is intended to be converted. - * @param string $type type to which the value should be converted to - * @param bool $quote determines if the value should be quoted and escaped - * @param bool $escape_wildcards if to escape escape wildcards - * @return string text string that represents the given argument value in - * a DBMS specific format. - * @access public - */ - function quote($value, $type = null, $quote = true, $escape_wildcards = false) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - if (is_null($value) - || ($value === '' && $db->options['portability'] & MDB2_PORTABILITY_EMPTY_TO_NULL) - ) { - if (!$quote) { - return null; - } - return 'NULL'; - } - - if (is_null($type)) { - switch (gettype($value)) { - case 'integer': - $type = 'integer'; - break; - case 'double': - // todo: default to decimal as float is quite unusual - // $type = 'float'; - $type = 'decimal'; - break; - case 'boolean': - $type = 'boolean'; - break; - case 'array': - $value = serialize($value); - case 'object': - $type = 'text'; - break; - default: - if (preg_match('/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/', $value)) { - $type = 'timestamp'; - } elseif (preg_match('/^\d{2}:\d{2}$/', $value)) { - $type = 'time'; - } elseif (preg_match('/^\d{4}-\d{2}-\d{2}$/', $value)) { - $type = 'date'; - } else { - $type = 'text'; - } - break; - } - } elseif (!empty($db->options['datatype_map'][$type])) { - $type = $db->options['datatype_map'][$type]; - if (!empty($db->options['datatype_map_callback'][$type])) { - $parameter = array('type' => $type, 'value' => $value, 'quote' => $quote, 'escape_wildcards' => $escape_wildcards); - return call_user_func_array($db->options['datatype_map_callback'][$type], array(&$db, __FUNCTION__, $parameter)); - } - } - - if (!method_exists($this, "_quote{$type}")) { - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'type not defined: '.$type, __FUNCTION__); - } - $value = $this->{"_quote{$type}"}($value, $quote, $escape_wildcards); - if ($quote && $escape_wildcards && $db->string_quoting['escape_pattern'] - && $db->string_quoting['escape'] !== $db->string_quoting['escape_pattern'] - ) { - $value.= $this->patternEscapeString(); - } - return $value; - } - - // }}} - // {{{ _quoteInteger() - - /** - * Convert a text value into a DBMS specific format that is suitable to - * compose query statements. - * - * @param string $value text string value that is intended to be converted. - * @param bool $quote determines if the value should be quoted and escaped - * @param bool $escape_wildcards if to escape escape wildcards - * @return string text string that represents the given argument value in - * a DBMS specific format. - * @access protected - */ - function _quoteInteger($value, $quote, $escape_wildcards) - { - return (int)$value; - } - - // }}} - // {{{ _quoteText() - - /** - * Convert a text value into a DBMS specific format that is suitable to - * compose query statements. - * - * @param string $value text string value that is intended to be converted. - * @param bool $quote determines if the value should be quoted and escaped - * @param bool $escape_wildcards if to escape escape wildcards - * @return string text string that already contains any DBMS specific - * escaped character sequences. - * @access protected - */ - function _quoteText($value, $quote, $escape_wildcards) - { - if (!$quote) { - return $value; - } - - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $value = $db->escape($value, $escape_wildcards); - if (PEAR::isError($value)) { - return $value; - } - return "'".$value."'"; - } - - // }}} - // {{{ _readFile() - - /** - * Convert a text value into a DBMS specific format that is suitable to - * compose query statements. - * - * @param string $value text string value that is intended to be converted. - * @return string text string that represents the given argument value in - * a DBMS specific format. - * @access protected - */ - function _readFile($value) - { - $close = false; - if (preg_match('/^(\w+:\/\/)(.*)$/', $value, $match)) { - $close = true; - if ($match[1] == 'file://') { - $value = $match[2]; - } - $value = @fopen($value, 'r'); - } - - if (is_resource($value)) { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $fp = $value; - $value = ''; - while (!@feof($fp)) { - $value.= @fread($fp, $db->options['lob_buffer_length']); - } - if ($close) { - @fclose($fp); - } - } - - return $value; - } - - // }}} - // {{{ _quoteLOB() - - /** - * Convert a text value into a DBMS specific format that is suitable to - * compose query statements. - * - * @param string $value text string value that is intended to be converted. - * @param bool $quote determines if the value should be quoted and escaped - * @param bool $escape_wildcards if to escape escape wildcards - * @return string text string that represents the given argument value in - * a DBMS specific format. - * @access protected - */ - function _quoteLOB($value, $quote, $escape_wildcards) - { - $value = $this->_readFile($value); - if (PEAR::isError($value)) { - return $value; - } - return $this->_quoteText($value, $quote, $escape_wildcards); - } - - // }}} - // {{{ _quoteCLOB() - - /** - * Convert a text value into a DBMS specific format that is suitable to - * compose query statements. - * - * @param string $value text string value that is intended to be converted. - * @param bool $quote determines if the value should be quoted and escaped - * @param bool $escape_wildcards if to escape escape wildcards - * @return string text string that represents the given argument value in - * a DBMS specific format. - * @access protected - */ - function _quoteCLOB($value, $quote, $escape_wildcards) - { - return $this->_quoteLOB($value, $quote, $escape_wildcards); - } - - // }}} - // {{{ _quoteBLOB() - - /** - * Convert a text value into a DBMS specific format that is suitable to - * compose query statements. - * - * @param string $value text string value that is intended to be converted. - * @param bool $quote determines if the value should be quoted and escaped - * @param bool $escape_wildcards if to escape escape wildcards - * @return string text string that represents the given argument value in - * a DBMS specific format. - * @access protected - */ - function _quoteBLOB($value, $quote, $escape_wildcards) - { - return $this->_quoteLOB($value, $quote, $escape_wildcards); - } - - // }}} - // {{{ _quoteBoolean() - - /** - * Convert a text value into a DBMS specific format that is suitable to - * compose query statements. - * - * @param string $value text string value that is intended to be converted. - * @param bool $quote determines if the value should be quoted and escaped - * @param bool $escape_wildcards if to escape escape wildcards - * @return string text string that represents the given argument value in - * a DBMS specific format. - * @access protected - */ - function _quoteBoolean($value, $quote, $escape_wildcards) - { - return ($value ? 1 : 0); - } - - // }}} - // {{{ _quoteDate() - - /** - * Convert a text value into a DBMS specific format that is suitable to - * compose query statements. - * - * @param string $value text string value that is intended to be converted. - * @param bool $quote determines if the value should be quoted and escaped - * @param bool $escape_wildcards if to escape escape wildcards - * @return string text string that represents the given argument value in - * a DBMS specific format. - * @access protected - */ - function _quoteDate($value, $quote, $escape_wildcards) - { - if ($value === 'CURRENT_DATE') { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - if (isset($db->function) && is_a($db->function, 'MDB2_Driver_Function_Common')) { - return $db->function->now('date'); - } - return 'CURRENT_DATE'; - } - return $this->_quoteText($value, $quote, $escape_wildcards); - } - - // }}} - // {{{ _quoteTimestamp() - - /** - * Convert a text value into a DBMS specific format that is suitable to - * compose query statements. - * - * @param string $value text string value that is intended to be converted. - * @param bool $quote determines if the value should be quoted and escaped - * @param bool $escape_wildcards if to escape escape wildcards - * @return string text string that represents the given argument value in - * a DBMS specific format. - * @access protected - */ - function _quoteTimestamp($value, $quote, $escape_wildcards) - { - if ($value === 'CURRENT_TIMESTAMP') { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - if (isset($db->function) && is_a($db->function, 'MDB2_Driver_Function_Common')) { - return $db->function->now('timestamp'); - } - return 'CURRENT_TIMESTAMP'; - } - return $this->_quoteText($value, $quote, $escape_wildcards); - } - - // }}} - // {{{ _quoteTime() - - /** - * Convert a text value into a DBMS specific format that is suitable to - * compose query statements. - * - * @param string $value text string value that is intended to be converted. - * @param bool $quote determines if the value should be quoted and escaped - * @param bool $escape_wildcards if to escape escape wildcards - * @return string text string that represents the given argument value in - * a DBMS specific format. - * @access protected - */ - function _quoteTime($value, $quote, $escape_wildcards) - { - if ($value === 'CURRENT_TIME') { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - if (isset($db->function) && is_a($db->function, 'MDB2_Driver_Function_Common')) { - return $db->function->now('time'); - } - return 'CURRENT_TIME'; - } - return $this->_quoteText($value, $quote, $escape_wildcards); - } - - // }}} - // {{{ _quoteFloat() - - /** - * Convert a text value into a DBMS specific format that is suitable to - * compose query statements. - * - * @param string $value text string value that is intended to be converted. - * @param bool $quote determines if the value should be quoted and escaped - * @param bool $escape_wildcards if to escape escape wildcards - * @return string text string that represents the given argument value in - * a DBMS specific format. - * @access protected - */ - function _quoteFloat($value, $quote, $escape_wildcards) - { - if (preg_match('/^(.*)e([-+])(\d+)$/i', $value, $matches)) { - $decimal = $this->_quoteDecimal($matches[1], $quote, $escape_wildcards); - $sign = $matches[2]; - $exponent = str_pad($matches[3], 2, '0', STR_PAD_LEFT); - $value = $decimal.'E'.$sign.$exponent; - } else { - $value = $this->_quoteDecimal($value, $quote, $escape_wildcards); - } - return $value; - } - - // }}} - // {{{ _quoteDecimal() - - /** - * Convert a text value into a DBMS specific format that is suitable to - * compose query statements. - * - * @param string $value text string value that is intended to be converted. - * @param bool $quote determines if the value should be quoted and escaped - * @param bool $escape_wildcards if to escape escape wildcards - * @return string text string that represents the given argument value in - * a DBMS specific format. - * @access protected - */ - function _quoteDecimal($value, $quote, $escape_wildcards) - { - $value = (string)$value; - $value = preg_replace('/[^\d\.,\-+eE]/', '', $value); - if (preg_match('/[^.0-9]/', $value)) { - if (strpos($value, ',')) { - // 1000,00 - if (!strpos($value, '.')) { - // convert the last "," to a "." - $value = strrev(str_replace(',', '.', strrev($value))); - // 1.000,00 - } elseif (strpos($value, '.') && strpos($value, '.') < strpos($value, ',')) { - $value = str_replace('.', '', $value); - // convert the last "," to a "." - $value = strrev(str_replace(',', '.', strrev($value))); - // 1,000.00 - } else { - $value = str_replace(',', '', $value); - } - } - } - return $value; - } - - // }}} - // {{{ writeLOBToFile() - - /** - * retrieve LOB from the database - * - * @param resource $lob stream handle - * @param string $file name of the file into which the LOb should be fetched - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access protected - */ - function writeLOBToFile($lob, $file) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - if (preg_match('/^(\w+:\/\/)(.*)$/', $file, $match)) { - if ($match[1] == 'file://') { - $file = $match[2]; - } - } - - $fp = @fopen($file, 'wb'); - while (!@feof($lob)) { - $result = @fread($lob, $db->options['lob_buffer_length']); - $read = strlen($result); - if (@fwrite($fp, $result, $read) != $read) { - @fclose($fp); - return $db->raiseError(MDB2_ERROR, null, null, - 'could not write to the output file', __FUNCTION__); - } - } - @fclose($fp); - return MDB2_OK; - } - - // }}} - // {{{ _retrieveLOB() - - /** - * retrieve LOB from the database - * - * @param array $lob array - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access protected - */ - function _retrieveLOB(&$lob) - { - if (is_null($lob['value'])) { - $lob['value'] = $lob['resource']; - } - $lob['loaded'] = true; - return MDB2_OK; - } - - // }}} - // {{{ readLOB() - - /** - * Read data from large object input stream. - * - * @param resource $lob stream handle - * @param string $data reference to a variable that will hold data - * to be read from the large object input stream - * @param integer $length value that indicates the largest ammount ofdata - * to be read from the large object input stream. - * @return mixed the effective number of bytes read from the large object - * input stream on sucess or an MDB2 error object. - * @access public - * @see endOfLOB() - */ - function _readLOB($lob, $length) - { - return substr($lob['value'], $lob['position'], $length); - } - - // }}} - // {{{ _endOfLOB() - - /** - * Determine whether it was reached the end of the large object and - * therefore there is no more data to be read for the its input stream. - * - * @param array $lob array - * @return mixed true or false on success, a MDB2 error on failure - * @access protected - */ - function _endOfLOB($lob) - { - return $lob['endOfLOB']; - } - - // }}} - // {{{ destroyLOB() - - /** - * Free any resources allocated during the lifetime of the large object - * handler object. - * - * @param resource $lob stream handle - * @access public - */ - function destroyLOB($lob) - { - $lob_data = stream_get_meta_data($lob); - $lob_index = $lob_data['wrapper_data']->lob_index; - fclose($lob); - if (isset($this->lobs[$lob_index])) { - $this->_destroyLOB($this->lobs[$lob_index]); - unset($this->lobs[$lob_index]); - } - return MDB2_OK; - } - - // }}} - // {{{ _destroyLOB() - - /** - * Free any resources allocated during the lifetime of the large object - * handler object. - * - * @param array $lob array - * @access private - */ - function _destroyLOB(&$lob) - { - return MDB2_OK; - } - - // }}} - // {{{ implodeArray() - - /** - * apply a type to all values of an array and return as a comma seperated string - * useful for generating IN statements - * - * @access public - * - * @param array $array data array - * @param string $type determines type of the field - * - * @return string comma seperated values - */ - function implodeArray($array, $type = false) - { - if (!is_array($array) || empty($array)) { - return 'NULL'; - } - if ($type) { - foreach ($array as $value) { - $return[] = $this->quote($value, $type); - } - } else { - $return = $array; - } - return implode(', ', $return); - } - - // }}} - // {{{ matchPattern() - - /** - * build a pattern matching string - * - * EXPERIMENTAL - * - * WARNING: this function is experimental and may change signature at - * any time until labelled as non-experimental - * - * @access public - * - * @param array $pattern even keys are strings, odd are patterns (% and _) - * @param string $operator optional pattern operator (LIKE, ILIKE and maybe others in the future) - * @param string $field optional field name that is being matched against - * (might be required when emulating ILIKE) - * - * @return string SQL pattern - */ - function matchPattern($pattern, $operator = null, $field = null) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $match = ''; - if (!is_null($operator)) { - $operator = strtoupper($operator); - switch ($operator) { - // case insensitive - case 'ILIKE': - if (is_null($field)) { - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'case insensitive LIKE matching requires passing the field name', __FUNCTION__); - } - $db->loadModule('Function', null, true); - $match = $db->function->lower($field).' LIKE '; - break; - // case sensitive - case 'LIKE': - $match = is_null($field) ? 'LIKE ' : $field.' LIKE '; - break; - default: - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'not a supported operator type:'. $operator, __FUNCTION__); - } - } - $match.= "'"; - foreach ($pattern as $key => $value) { - if ($key % 2) { - $match.= $value; - } else { - if ($operator === 'ILIKE') { - $value = strtolower($value); - } - $escaped = $db->escape($value); - if (PEAR::isError($escaped)) { - return $escaped; - } - $match.= $db->escapePattern($escaped); - } - } - $match.= "'"; - $match.= $this->patternEscapeString(); - return $match; - } - - // }}} - // {{{ patternEscapeString() - - /** - * build string to define pattern escape character - * - * EXPERIMENTAL - * - * WARNING: this function is experimental and may change signature at - * any time until labelled as non-experimental - * - * @access public - * - * @return string define pattern escape character - */ - function patternEscapeString() - { - return ''; - } - - // }}} - // {{{ mapNativeDatatype() - - /** - * Maps a native array description of a field to a MDB2 datatype and length - * - * @param array $field native field description - * @return array containing the various possible types, length, sign, fixed - * @access public - */ - function mapNativeDatatype($field) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - // If the user has specified an option to map the native field - // type to a custom MDB2 datatype... - $db_type = strtok($field['type'], '(), '); - if (!empty($db->options['nativetype_map_callback'][$db_type])) { - return call_user_func_array($db->options['nativetype_map_callback'][$db_type], array($db, $field)); - } - - // Otherwise perform the built-in (i.e. normal) MDB2 native type to - // MDB2 datatype conversion - return $this->_mapNativeDatatype($field); - } - - // }}} - // {{{ _mapNativeDatatype() - - /** - * Maps a native array description of a field to a MDB2 datatype and length - * - * @param array $field native field description - * @return array containing the various possible types, length, sign, fixed - * @access public - */ - function _mapNativeDatatype($field) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ mapPrepareDatatype() - - /** - * Maps an mdb2 datatype to mysqli prepare type - * - * @param string $type - * @return string - * @access public - */ - function mapPrepareDatatype($type) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - if (!empty($db->options['datatype_map'][$type])) { - $type = $db->options['datatype_map'][$type]; - if (!empty($db->options['datatype_map_callback'][$type])) { - $parameter = array('type' => $type); - return call_user_func_array($db->options['datatype_map_callback'][$type], array(&$db, __FUNCTION__, $parameter)); - } - } - - return $type; - } -} -?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/MDB2/Driver/Function/Common.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/MDB2/Driver/Function/Common.php --- php-mdb2-2.4.1/MDB2-2.4.1/MDB2/Driver/Function/Common.php 2007-05-03 19:58:15.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.4.1/MDB2/Driver/Function/Common.php 1970-01-01 01:00:00.000000000 +0100 @@ -1,231 +0,0 @@ - | -// +----------------------------------------------------------------------+ -// -// $Id: Common.php,v 1.17 2007/01/12 11:29:12 quipo Exp $ -// - -/** - * @package MDB2 - * @category Database - * @author Lukas Smith - */ - -/** - * Base class for the function modules that is extended by each MDB2 driver - * - * @package MDB2 - * @category Database - * @author Lukas Smith - */ -class MDB2_Driver_Function_Common extends MDB2_Module_Common -{ - // {{{ executeStoredProc() - - /** - * Execute a stored procedure and return any results - * - * @param string $name string that identifies the function to execute - * @param mixed $params array that contains the paramaters to pass the stored proc - * @param mixed $types array that contains the types of the columns in - * the result set - * @param mixed $result_class string which specifies which result class to use - * @param mixed $result_wrap_class string which specifies which class to wrap results in - * @return mixed a result handle or MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function &executeStoredProc($name, $params = null, $types = null, $result_class = true, $result_wrap_class = false) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $error =& $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - return $error; - } - - // }}} - // {{{ functionTable() - - /** - * return string for internal table used when calling only a function - * - * @return string for internal table used when calling only a function - * @access public - */ - function functionTable() - { - return ''; - } - - // }}} - // {{{ now() - - /** - * Return string to call a variable with the current timestamp inside an SQL statement - * There are three special variables for current date and time: - * - CURRENT_TIMESTAMP (date and time, TIMESTAMP type) - * - CURRENT_DATE (date, DATE type) - * - CURRENT_TIME (time, TIME type) - * - * @return string to call a variable with the current timestamp - * @access public - */ - function now($type = 'timestamp') - { - switch ($type) { - case 'time': - return 'CURRENT_TIME'; - case 'date': - return 'CURRENT_DATE'; - case 'timestamp': - default: - return 'CURRENT_TIMESTAMP'; - } - } - - // }}} - // {{{ substring() - - /** - * return string to call a function to get a substring inside an SQL statement - * - * @return string to call a function to get a substring - * @access public - */ - function substring($value, $position = 1, $length = null) - { - if (!is_null($length)) { - return "SUBSTRING($value FROM $position FOR $length)"; - } - return "SUBSTRING($value FROM $position)"; - } - - // }}} - // {{{ concat() - - /** - * Returns string to concatenate two or more string parameters - * - * @param string $value1 - * @param string $value2 - * @param string $values... - * @return string to concatenate two strings - * @access public - */ - function concat($value1, $value2) - { - $args = func_get_args(); - return "(".implode(' || ', $args).")"; - } - - // }}} - // {{{ random() - - /** - * return string to call a function to get random value inside an SQL statement - * - * @return return string to generate float between 0 and 1 - * @access public - */ - function random() - { - return 'RAND()'; - } - - // }}} - // {{{ lower() - - /** - * return string to call a function to lower the case of an expression - * - * @param string $expression - * @return return string to lower case of an expression - * @access public - */ - function lower($expression) - { - return "LOWER($expression)"; - } - - // }}} - // {{{ upper() - - /** - * return string to call a function to upper the case of an expression - * - * @param string $expression - * @return return string to upper case of an expression - * @access public - */ - function upper($expression) - { - return "UPPER($expression)"; - } - - // }}} - // {{{ guid() - - /** - * Returns global unique identifier - * - * @return string to get global unique identifier - * @access public - */ - function guid() - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $error =& $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - return $error; - } - - // }}} -} -?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/MDB2/Driver/Manager/Common.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/MDB2/Driver/Manager/Common.php --- php-mdb2-2.4.1/MDB2-2.4.1/MDB2/Driver/Manager/Common.php 2007-05-03 19:58:15.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.4.1/MDB2/Driver/Manager/Common.php 1970-01-01 01:00:00.000000000 +0100 @@ -1,864 +0,0 @@ - | -// +----------------------------------------------------------------------+ -// -// $Id: Common.php,v 1.62 2007/03/28 16:39:55 quipo Exp $ -// - -/** - * @package MDB2 - * @category Database - * @author Lukas Smith - */ - -/** - * Base class for the management modules that is extended by each MDB2 driver - * - * @package MDB2 - * @category Database - * @author Lukas Smith - */ -class MDB2_Driver_Manager_Common extends MDB2_Module_Common -{ - // {{{ getFieldDeclarationList() - - /** - * Get declaration of a number of field in bulk - * - * @param array $fields a multidimensional associative array. - * The first dimension determines the field name, while the second - * dimension is keyed with the name of the properties - * of the field being declared as array indexes. Currently, the types - * of supported field properties are as follows: - * - * default - * Boolean value to be used as default for this field. - * - * notnull - * Boolean flag that indicates whether this field is constrained - * to not be set to null. - * - * @return mixed string on success, a MDB2 error on failure - * @access public - */ - function getFieldDeclarationList($fields) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - if (!is_array($fields) || empty($fields)) { - return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, - 'missing any fields', __FUNCTION__); - } - foreach ($fields as $field_name => $field) { - $query = $db->getDeclaration($field['type'], $field_name, $field); - if (PEAR::isError($query)) { - return $query; - } - $query_fields[] = $query; - } - return implode(', ', $query_fields); - } - - // }}} - // {{{ _fixSequenceName() - - /** - * Removes any formatting in an sequence name using the 'seqname_format' option - * - * @param string $sqn string that containts name of a potential sequence - * @param bool $check if only formatted sequences should be returned - * @return string name of the sequence with possible formatting removed - * @access protected - */ - function _fixSequenceName($sqn, $check = false) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $seq_pattern = '/^'.preg_replace('/%s/', '([a-z0-9_]+)', $db->options['seqname_format']).'$/i'; - $seq_name = preg_replace($seq_pattern, '\\1', $sqn); - if ($seq_name && !strcasecmp($sqn, $db->getSequenceName($seq_name))) { - return $seq_name; - } - if ($check) { - return false; - } - return $sqn; - } - - // }}} - // {{{ _fixIndexName() - - /** - * Removes any formatting in an index name using the 'idxname_format' option - * - * @param string $idx string that containts name of anl index - * @return string name of the index with possible formatting removed - * @access protected - */ - function _fixIndexName($idx) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $idx_pattern = '/^'.preg_replace('/%s/', '([a-z0-9_]+)', $db->options['idxname_format']).'$/i'; - $idx_name = preg_replace($idx_pattern, '\\1', $idx); - if ($idx_name && !strcasecmp($idx, $db->getIndexName($idx_name))) { - return $idx_name; - } - return $idx; - } - - // }}} - // {{{ createDatabase() - - /** - * create a new database - * - * @param string $name name of the database that should be created - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function createDatabase($database) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ dropDatabase() - - /** - * drop an existing database - * - * @param string $name name of the database that should be dropped - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function dropDatabase($database) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ _getCreateTableQuery() - - /** - * Create a basic SQL query for a new table creation - * @param string $name Name of the database that should be created - * @param array $fields Associative array that contains the definition of each field of the new table - * @param array $options An associative array of table options - * @return mixed string (the SQL query) on success, a MDB2 error on failure - * @see createTable() - */ - function _getCreateTableQuery($name, $fields, $options = array()) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - if (!$name) { - return $db->raiseError(MDB2_ERROR_CANNOT_CREATE, null, null, - 'no valid table name specified', __FUNCTION__); - } - if (empty($fields)) { - return $db->raiseError(MDB2_ERROR_CANNOT_CREATE, null, null, - 'no fields specified for table "'.$name.'"', __FUNCTION__); - } - $query_fields = $this->getFieldDeclarationList($fields); - if (PEAR::isError($query_fields)) { - return $query_fields; - } - if (!empty($options['primary'])) { - $query_fields.= ', PRIMARY KEY ('.implode(', ', array_keys($options['primary'])).')'; - } - - $name = $db->quoteIdentifier($name, true); - $result = 'CREATE '; - if (!empty($options['temporary'])) { - $result .= $this->_getTemporaryTableQuery(); - } - $result .= " TABLE $name ($query_fields)"; - return $result; - } - - // }}} - // {{{ _getTemporaryTableQuery() - - /** - * A method to return the required SQL string that fits between CREATE ... TABLE - * to create the table as a temporary table. - * - * Should be overridden in driver classes to return the correct string for the - * specific database type. - * - * The default is to return the string "TEMPORARY" - this will result in a - * SQL error for any database that does not support temporary tables, or that - * requires a different SQL command from "CREATE TEMPORARY TABLE". - * - * @return string The string required to be placed between "CREATE" and "TABLE" - * to generate a temporary table, if possible. - */ - function _getTemporaryTableQuery() - { - return 'TEMPORARY'; - } - - // }}} - // {{{ createTable() - - /** - * create a new table - * - * @param string $name Name of the database that should be created - * @param array $fields Associative array that contains the definition of each field of the new table - * The indexes of the array entries are the names of the fields of the table an - * the array entry values are associative arrays like those that are meant to be - * passed with the field definitions to get[Type]Declaration() functions. - * array( - * 'id' => array( - * 'type' => 'integer', - * 'unsigned' => 1 - * 'notnull' => 1 - * 'default' => 0 - * ), - * 'name' => array( - * 'type' => 'text', - * 'length' => 12 - * ), - * 'password' => array( - * 'type' => 'text', - * 'length' => 12 - * ) - * ); - * @param array $options An associative array of table options: - * array( - * 'comment' => 'Foo', - * 'temporary' => true|false, - * ); - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function createTable($name, $fields, $options = array()) - { - $query = $this->_getCreateTableQuery($name, $fields, $options); - if (PEAR::isError($query)) { - return $query; - } - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - return $db->exec($query); - } - - // }}} - // {{{ dropTable() - - /** - * drop an existing table - * - * @param string $name name of the table that should be dropped - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function dropTable($name) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $name = $db->quoteIdentifier($name, true); - return $db->exec("DROP TABLE $name"); - } - - // }}} - // {{{ alterTable() - - /** - * alter an existing table - * - * @param string $name name of the table that is intended to be changed. - * @param array $changes associative array that contains the details of each type - * of change that is intended to be performed. The types of - * changes that are currently supported are defined as follows: - * - * name - * - * New name for the table. - * - * add - * - * Associative array with the names of fields to be added as - * indexes of the array. The value of each entry of the array - * should be set to another associative array with the properties - * of the fields to be added. The properties of the fields should - * be the same as defined by the MDB2 parser. - * - * - * remove - * - * Associative array with the names of fields to be removed as indexes - * of the array. Currently the values assigned to each entry are ignored. - * An empty array should be used for future compatibility. - * - * rename - * - * Associative array with the names of fields to be renamed as indexes - * of the array. The value of each entry of the array should be set to - * another associative array with the entry named name with the new - * field name and the entry named Declaration that is expected to contain - * the portion of the field declaration already in DBMS specific SQL code - * as it is used in the CREATE TABLE statement. - * - * change - * - * Associative array with the names of the fields to be changed as indexes - * of the array. Keep in mind that if it is intended to change either the - * name of a field and any other properties, the change array entries - * should have the new names of the fields as array indexes. - * - * The value of each entry of the array should be set to another associative - * array with the properties of the fields to that are meant to be changed as - * array entries. These entries should be assigned to the new values of the - * respective properties. The properties of the fields should be the same - * as defined by the MDB2 parser. - * - * Example - * array( - * 'name' => 'userlist', - * 'add' => array( - * 'quota' => array( - * 'type' => 'integer', - * 'unsigned' => 1 - * ) - * ), - * 'remove' => array( - * 'file_limit' => array(), - * 'time_limit' => array() - * ), - * 'change' => array( - * 'name' => array( - * 'length' => '20', - * 'definition' => array( - * 'type' => 'text', - * 'length' => 20, - * ), - * ) - * ), - * 'rename' => array( - * 'sex' => array( - * 'name' => 'gender', - * 'definition' => array( - * 'type' => 'text', - * 'length' => 1, - * 'default' => 'M', - * ), - * ) - * ) - * ) - * - * @param boolean $check indicates whether the function should just check if the DBMS driver - * can perform the requested table alterations if the value is true or - * actually perform them otherwise. - * @access public - * - * @return mixed MDB2_OK on success, a MDB2 error on failure - */ - function alterTable($name, $changes, $check) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ listDatabases() - - /** - * list all databases - * - * @return mixed array of database names on success, a MDB2 error on failure - * @access public - */ - function listDatabases() - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implementedd', __FUNCTION__); - } - - // }}} - // {{{ listUsers() - - /** - * list all users - * - * @return mixed array of user names on success, a MDB2 error on failure - * @access public - */ - function listUsers() - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ listViews() - - /** - * list all views in the current database - * - * @param string database, the current is default - * NB: not all the drivers can get the view names from - * a database other than the current one - * @return mixed array of view names on success, a MDB2 error on failure - * @access public - */ - function listViews($database = null) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ listTableViews() - - /** - * list the views in the database that reference a given table - * - * @param string table for which all referenced views should be found - * @return mixed array of view names on success, a MDB2 error on failure - * @access public - */ - function listTableViews($table) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ listTableTriggers() - - /** - * list all triggers in the database that reference a given table - * - * @param string table for which all referenced triggers should be found - * @return mixed array of trigger names on success, a MDB2 error on failure - * @access public - */ - function listTableTriggers($table = null) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ listFunctions() - - /** - * list all functions in the current database - * - * @return mixed array of function names on success, a MDB2 error on failure - * @access public - */ - function listFunctions() - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ listTables() - - /** - * list all tables in the current database - * - * @param string database, the current is default. - * NB: not all the drivers can get the table names from - * a database other than the current one - * @return mixed array of table names on success, a MDB2 error on failure - * @access public - */ - function listTables($database = null) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ listTableFields() - - /** - * list all fields in a table in the current database - * - * @param string $table name of table that should be used in method - * @return mixed array of field names on success, a MDB2 error on failure - * @access public - */ - function listTableFields($table) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ createIndex() - - /** - * Get the stucture of a field into an array - * - * @param string $table name of the table on which the index is to be created - * @param string $name name of the index to be created - * @param array $definition associative array that defines properties of the index to be created. - * Currently, only one property named FIELDS is supported. This property - * is also an associative with the names of the index fields as array - * indexes. Each entry of this array is set to another type of associative - * array that specifies properties of the index that are specific to - * each field. - * - * Currently, only the sorting property is supported. It should be used - * to define the sorting direction of the index. It may be set to either - * ascending or descending. - * - * Not all DBMS support index sorting direction configuration. The DBMS - * drivers of those that do not support it ignore this property. Use the - * function supports() to determine whether the DBMS driver can manage indexes. - * - * Example - * array( - * 'fields' => array( - * 'user_name' => array( - * 'sorting' => 'ascending' - * ), - * 'last_login' => array() - * ) - * ) - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function createIndex($table, $name, $definition) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $table = $db->quoteIdentifier($table, true); - $name = $db->quoteIdentifier($db->getIndexName($name), true); - $query = "CREATE INDEX $name ON $table"; - $fields = array(); - foreach (array_keys($definition['fields']) as $field) { - $fields[] = $db->quoteIdentifier($field, true); - } - $query .= ' ('. implode(', ', $fields) . ')'; - return $db->exec($query); - } - - // }}} - // {{{ dropIndex() - - /** - * drop existing index - * - * @param string $table name of table that should be used in method - * @param string $name name of the index to be dropped - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function dropIndex($table, $name) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $name = $db->quoteIdentifier($db->getIndexName($name), true); - return $db->exec("DROP INDEX $name"); - } - - // }}} - // {{{ listTableIndexes() - - /** - * list all indexes in a table - * - * @param string $table name of table that should be used in method - * @return mixed array of index names on success, a MDB2 error on failure - * @access public - */ - function listTableIndexes($table) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ createConstraint() - - /** - * create a constraint on a table - * - * @param string $table name of the table on which the constraint is to be created - * @param string $name name of the constraint to be created - * @param array $definition associative array that defines properties of the constraint to be created. - * Currently, only one property named FIELDS is supported. This property - * is also an associative with the names of the constraint fields as array - * constraints. Each entry of this array is set to another type of associative - * array that specifies properties of the constraint that are specific to - * each field. - * - * Example - * array( - * 'fields' => array( - * 'user_name' => array(), - * 'last_login' => array() - * ) - * ) - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function createConstraint($table, $name, $definition) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - $table = $db->quoteIdentifier($table, true); - $name = $db->quoteIdentifier($db->getIndexName($name), true); - $query = "ALTER TABLE $table ADD CONSTRAINT $name"; - if (!empty($definition['primary'])) { - $query.= ' PRIMARY KEY'; - } elseif (!empty($definition['unique'])) { - $query.= ' UNIQUE'; - } - $fields = array(); - foreach (array_keys($definition['fields']) as $field) { - $fields[] = $db->quoteIdentifier($field, true); - } - $query .= ' ('. implode(', ', $fields) . ')'; - return $db->exec($query); - } - - // }}} - // {{{ dropConstraint() - - /** - * drop existing constraint - * - * @param string $table name of table that should be used in method - * @param string $name name of the constraint to be dropped - * @param string $primary hint if the constraint is primary - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function dropConstraint($table, $name, $primary = false) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $table = $db->quoteIdentifier($table, true); - $name = $db->quoteIdentifier($db->getIndexName($name), true); - return $db->exec("ALTER TABLE $table DROP CONSTRAINT $name"); - } - - // }}} - // {{{ listTableConstraints() - - /** - * list all constraints in a table - * - * @param string $table name of table that should be used in method - * @return mixed array of constraint names on success, a MDB2 error on failure - * @access public - */ - function listTableConstraints($table) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ createSequence() - - /** - * create sequence - * - * @param string $seq_name name of the sequence to be created - * @param string $start start value of the sequence; default is 1 - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function createSequence($seq_name, $start = 1) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ dropSequence() - - /** - * drop existing sequence - * - * @param string $seq_name name of the sequence to be dropped - * @return mixed MDB2_OK on success, a MDB2 error on failure - * @access public - */ - function dropSequence($name) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ listSequences() - - /** - * list all sequences in the current database - * - * @param string database, the current is default - * NB: not all the drivers can get the sequence names from - * a database other than the current one - * @return mixed array of sequence names on success, a MDB2 error on failure - * @access public - */ - function listSequences($database = null) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} -} -?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/MDB2/Driver/Native/Common.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/MDB2/Driver/Native/Common.php --- php-mdb2-2.4.1/MDB2-2.4.1/MDB2/Driver/Native/Common.php 2007-05-03 19:58:15.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.4.1/MDB2/Driver/Native/Common.php 1970-01-01 01:00:00.000000000 +0100 @@ -1,58 +0,0 @@ - | -// +----------------------------------------------------------------------+ -// -// $Id: Common.php,v 1.1 2006/06/18 21:59:05 lsmith Exp $ -// - -/** - * Base class for the natuve modules that is extended by each MDB2 driver - * - * @package MDB2 - * @category Database - * @author Lukas Smith - */ -class MDB2_Driver_Native_Common extends MDB2_Module_Common -{ -} -?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/MDB2/Driver/Reverse/Common.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/MDB2/Driver/Reverse/Common.php --- php-mdb2-2.4.1/MDB2-2.4.1/MDB2/Driver/Reverse/Common.php 2007-05-03 19:58:15.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.4.1/MDB2/Driver/Reverse/Common.php 1970-01-01 01:00:00.000000000 +0100 @@ -1,476 +0,0 @@ - | -// +----------------------------------------------------------------------+ -// -// $Id: Common.php,v 1.35 2007/02/25 11:14:34 quipo Exp $ -// - -/** - * @package MDB2 - * @category Database - */ - -/** - * These are constants for the tableInfo-function - * they are bitwised or'ed. so if there are more constants to be defined - * in the future, adjust MDB2_TABLEINFO_FULL accordingly - */ - -define('MDB2_TABLEINFO_ORDER', 1); -define('MDB2_TABLEINFO_ORDERTABLE', 2); -define('MDB2_TABLEINFO_FULL', 3); - -/** - * Base class for the schema reverse engineering module that is extended by each MDB2 driver - * - * @package MDB2 - * @category Database - * @author Lukas Smith - */ -class MDB2_Driver_Reverse_Common extends MDB2_Module_Common -{ - // }}} - // {{{ getTableFieldDefinition() - - /** - * Get the structure of a field into an array - * - * @param string $table name of table that should be used in method - * @param string $field name of field that should be used in method - * @return mixed data array on success, a MDB2 error on failure. - * The returned array contains an array for each field definition, - * with all or some of these indices, depending on the field data type: - * [notnull] [nativetype] [length] [fixed] [default] [type] [mdb2type] - * @access public - */ - function getTableFieldDefinition($table, $field) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ getTableIndexDefinition() - - /** - * Get the structure of an index into an array - * - * @param string $table name of table that should be used in method - * @param string $index name of index that should be used in method - * @return mixed data array on success, a MDB2 error on failure - * The returned array has this structure: - *
    - * array ( - * [fields] => array ( - * [field1name] => array() // one entry per each field covered - * [field2name] => array() // by the index - * [field3name] => array( - * [sorting] => ascending - * ) - * ) - * ); - * - * @access public - */ - function getTableIndexDefinition($table, $index) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ getTableConstraintDefinition() - - /** - * Get the structure of an constraints into an array - * - * @param string $table name of table that should be used in method - * @param string $index name of index that should be used in method - * @return mixed data array on success, a MDB2 error on failure - * The returned array has this structure: - *
    -     *          array (
    -     *              [primary] => 1
    -     *              [fields] => array (
    -     *                  [field1name] => array() // one entry per each field covered
    -     *                  [field2name] => array() // by the index
    -     *                  [field3name] => array(
    -     *                      [sorting] => ascending
    -     *                  )
    -     *              )
    -     *          );
    -     *          
    - * @access public - */ - function getTableConstraintDefinition($table, $index) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ getSequenceDefinition() - - /** - * Get the structure of a sequence into an array - * - * @param string $sequence name of sequence that should be used in method - * @return mixed data array on success, a MDB2 error on failure - * The returned array has this structure: - *
    -     *          array (
    -     *              [start] => n
    -     *          );
    -     *          
    - * @access public - */ - function getSequenceDefinition($sequence) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $start = $db->currId($sequence); - if (PEAR::isError($start)) { - return $start; - } - if ($db->supports('current_id')) { - $start++; - } else { - $db->warnings[] = 'database does not support getting current - sequence value, the sequence value was incremented'; - } - $definition = array(); - if ($start != 1) { - $definition = array('start' => $start); - } - return $definition; - } - - // }}} - // {{{ getTriggerDefinition() - - /** - * Get the structure of a trigger into an array - * - * EXPERIMENTAL - * - * WARNING: this function is experimental and may change the returned value - * at any time until labelled as non-experimental - * - * @param string $trigger name of trigger that should be used in method - * @return mixed data array on success, a MDB2 error on failure - * The returned array has this structure: - *
    -     *          array (
    -     *              [trigger_name]    => 'trigger name',
    -     *              [table_name]      => 'table name',
    -     *              [trigger_body]    => 'trigger body definition',
    -     *              [trigger_type]    => 'BEFORE' | 'AFTER',
    -     *              [trigger_event]   => 'INSERT' | 'UPDATE' | 'DELETE'
    -     *                  //or comma separated list of multiple events, when supported
    -     *              [trigger_enabled] => true|false
    -     *              [trigger_comment] => 'trigger comment',
    -     *          );
    -     *          
    - * The oci8 driver also returns a [when_clause] index. - * @access public - */ - function getTriggerDefinition($trigger) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ tableInfo() - - /** - * Returns information about a table or a result set - * - * The format of the resulting array depends on which $mode - * you select. The sample output below is based on this query: - *
    -     *    SELECT tblFoo.fldID, tblFoo.fldPhone, tblBar.fldId
    -     *    FROM tblFoo
    -     *    JOIN tblBar ON tblFoo.fldId = tblBar.fldId
    -     * 
    - * - *
      - *
    • - * - * null (default) - *
      -     *   [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
      -     *   )
      -     *   
      - * - *
    • - * - * MDB2_TABLEINFO_ORDER - * - *

      In addition to the information found in the default output, - * a notation of the number of columns is provided by the - * num_fields element while the order - * 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.

      - * - *

      If a result set has identical field names, the last one is - * used.

      - * - *
      -     *   [num_fields] => 3
      -     *   [order] => Array (
      -     *       [fldId] => 2
      -     *       [fldTrans] => 1
      -     *   )
      -     *   
      - * - *
    • - * - * MDB2_TABLEINFO_ORDERTABLE - * - *

      Similar to MDB2_TABLEINFO_ORDER 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.

      - * - *
      -     *   [num_fields] => 3
      -     *   [ordertable] => Array (
      -     *       [tblFoo] => Array (
      -     *           [fldId] => 0
      -     *           [fldPhone] => 1
      -     *       )
      -     *       [tblBar] => Array (
      -     *           [fldId] => 2
      -     *       )
      -     *   )
      -     *   
      - * - *
    • - *
    - * - * The flags 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. - * + primary_key - * + unique_key - * + multiple_key - * + not_null - * - * Most DBMS's only provide the table and flags - * elements if $result is a table name. The following DBMS's - * provide full information from queries: - * + fbsql - * + mysql - * - * If the 'portability' option has MDB2_PORTABILITY_FIX_CASE - * turned on, the names of tables and fields will be lower or upper cased. - * - * @param object|string $result MDB2_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: - * MDB2_TABLEINFO_ORDERTABLE, - * MDB2_TABLEINFO_ORDER or - * MDB2_TABLEINFO_FULL (which does both). - * These are bitwise, so the first two can be - * combined using |. - * - * @return array an associative array with the information requested. - * A MDB2_Error object on failure. - * - * @see MDB2_Driver_Common::setOption() - */ - function tableInfo($result, $mode = null) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - if (!is_string($result)) { - return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - $db->loadModule('Manager', null, true); - $fields = $db->manager->listTableFields($result); - if (PEAR::isError($fields)) { - return $fields; - } - - $flags = array(); - - $idxname_format = $db->getOption('idxname_format'); - $db->setOption('idxname_format', '%s'); - - $indexes = $db->manager->listTableIndexes($result); - if (PEAR::isError($indexes)) { - $db->setOption('idxname_format', $idxname_format); - return $indexes; - } - - foreach ($indexes as $index) { - $definition = $this->getTableIndexDefinition($result, $index); - if (PEAR::isError($definition)) { - $db->setOption('idxname_format', $idxname_format); - return $definition; - } - if (count($definition['fields']) > 1) { - foreach ($definition['fields'] as $field => $sort) { - $flags[$field] = 'multiple_key'; - } - } - } - - $constraints = $db->manager->listTableConstraints($result); - if (PEAR::isError($constraints)) { - return $constraints; - } - - foreach ($constraints as $constraint) { - $definition = $this->getTableConstraintDefinition($result, $constraint); - if (PEAR::isError($definition)) { - $db->setOption('idxname_format', $idxname_format); - return $definition; - } - $flag = !empty($definition['primary']) - ? 'primary_key' : (!empty($definition['unique']) - ? 'unique_key' : false); - if ($flag) { - foreach ($definition['fields'] as $field => $sort) { - if (empty($flags[$field]) || $flags[$field] != 'primary_key') { - $flags[$field] = $flag; - } - } - } - } - - if ($mode) { - $res['num_fields'] = count($fields); - } - - foreach ($fields as $i => $field) { - $definition = $this->getTableFieldDefinition($result, $field); - if (PEAR::isError($definition)) { - $db->setOption('idxname_format', $idxname_format); - return $definition; - } - $res[$i] = $definition[0]; - $res[$i]['name'] = $field; - $res[$i]['table'] = $result; - $res[$i]['type'] = preg_replace('/^([a-z]+).*$/i', '\\1', trim($definition[0]['nativetype'])); - // 'primary_key', 'unique_key', 'multiple_key' - $res[$i]['flags'] = empty($flags[$field]) ? '' : $flags[$field]; - // not_null', 'unsigned', 'auto_increment', 'default_[rawencodedvalue]' - if (!empty($res[$i]['notnull'])) { - $res[$i]['flags'].= ' not_null'; - } - if (!empty($res[$i]['unsigned'])) { - $res[$i]['flags'].= ' unsigned'; - } - if (!empty($res[$i]['auto_increment'])) { - $res[$i]['flags'].= ' autoincrement'; - } - if (!empty($res[$i]['default'])) { - $res[$i]['flags'].= ' default_'.rawurlencode($res[$i]['default']); - } - - if ($mode & MDB2_TABLEINFO_ORDER) { - $res['order'][$res[$i]['name']] = $i; - } - if ($mode & MDB2_TABLEINFO_ORDERTABLE) { - $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; - } - } - - $db->setOption('idxname_format', $idxname_format); - return $res; - } -} -?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/MDB2/Extended.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/MDB2/Extended.php --- php-mdb2-2.4.1/MDB2-2.4.1/MDB2/Extended.php 2007-05-03 19:58:15.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.4.1/MDB2/Extended.php 1970-01-01 01:00:00.000000000 +0100 @@ -1,714 +0,0 @@ - | -// +----------------------------------------------------------------------+ -// -// $Id: Extended.php,v 1.58 2007/01/06 21:40:52 quipo Exp $ - -/** - * @package MDB2 - * @category Database - * @author Lukas Smith - */ - -/** - * Used by autoPrepare() - */ -define('MDB2_AUTOQUERY_INSERT', 1); -define('MDB2_AUTOQUERY_UPDATE', 2); -define('MDB2_AUTOQUERY_DELETE', 3); -define('MDB2_AUTOQUERY_SELECT', 4); - -/** - * MDB2_Extended: class which adds several high level methods to MDB2 - * - * @package MDB2 - * @category Database - * @author Lukas Smith - */ -class MDB2_Extended extends MDB2_Module_Common -{ - // {{{ autoPrepare() - - /** - * Generate an insert, update or delete query and call prepare() on it - * - * @param string table - * @param array the fields names - * @param int type of query to build - * MDB2_AUTOQUERY_INSERT - * MDB2_AUTOQUERY_UPDATE - * MDB2_AUTOQUERY_DELETE - * MDB2_AUTOQUERY_SELECT - * @param string (in case of update and delete queries, this string will be put after the sql WHERE statement) - * @param array that contains the types of the placeholders - * @param mixed array that contains the types of the columns in - * the result set or MDB2_PREPARE_RESULT, if set to - * MDB2_PREPARE_MANIP the query is handled as a manipulation query - * - * @return resource handle for the query - * @see buildManipSQL - * @access public - */ - function autoPrepare($table, $table_fields, $mode = MDB2_AUTOQUERY_INSERT, - $where = false, $types = null, $result_types = MDB2_PREPARE_MANIP) - { - $query = $this->buildManipSQL($table, $table_fields, $mode, $where); - if (PEAR::isError($query)) { - return $query; - } - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - return $db->prepare($query, $types, $result_types); - } - // }}} - - // {{{ autoExecute() - - /** - * Generate an insert, update or delete query and call prepare() and execute() on it - * - * @param string name of the table - * @param array assoc ($key=>$value) where $key is a field name and $value its value - * @param int type of query to build - * MDB2_AUTOQUERY_INSERT - * MDB2_AUTOQUERY_UPDATE - * MDB2_AUTOQUERY_DELETE - * MDB2_AUTOQUERY_SELECT - * @param string (in case of update and delete queries, this string will be put after the sql WHERE statement) - * @param array that contains the types of the placeholders - * @param string which specifies which result class to use - * @param mixed array that contains the types of the columns in - * the result set or MDB2_PREPARE_RESULT, if set to - * MDB2_PREPARE_MANIP the query is handled as a manipulation query - * - * @return bool|MDB2_Error true on success, a MDB2 error on failure - * @see buildManipSQL - * @see autoPrepare - * @access public - */ - function &autoExecute($table, $fields_values, $mode = MDB2_AUTOQUERY_INSERT, - $where = false, $types = null, $result_class = true, $result_types = MDB2_PREPARE_MANIP) - { - $fields_values = (array)$fields_values; - if ($mode == MDB2_AUTOQUERY_SELECT) { - if (is_array($result_types)) { - $keys = array_keys($result_types); - } elseif (!empty($fields_values)) { - $keys = $fields_values; - } else { - $keys = array(); - } - } else { - $keys = array_keys($fields_values); - } - $params = array_values($fields_values); - if (empty($params)) { - $query = $this->buildManipSQL($table, $keys, $mode, $where); - - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - if ($mode == MDB2_AUTOQUERY_SELECT) { - $result =& $db->query($query, $result_types, $result_class); - } else { - $result = $db->exec($query); - } - } else { - $stmt = $this->autoPrepare($table, $keys, $mode, $where, $types, $result_types); - if (PEAR::isError($stmt)) { - return $stmt; - } - $result =& $stmt->execute($params, $result_class); - $stmt->free(); - } - return $result; - } - // }}} - - // {{{ buildManipSQL() - - /** - * Make automaticaly an sql query for prepare() - * - * Example : buildManipSQL('table_sql', array('field1', 'field2', 'field3'), MDB2_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/DELETE query, all - * the records of the table will be updated/deleted ! - * - * @param string name of the table - * @param ordered array containing the fields names - * @param int type of query to build - * MDB2_AUTOQUERY_INSERT - * MDB2_AUTOQUERY_UPDATE - * MDB2_AUTOQUERY_DELETE - * MDB2_AUTOQUERY_SELECT - * @param string (in case of update and delete 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) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - if ($db->options['quote_identifier']) { - $table = $db->quoteIdentifier($table); - } - - if (!empty($table_fields) && $db->options['quote_identifier']) { - foreach ($table_fields as $key => $field) { - $table_fields[$key] = $db->quoteIdentifier($field); - } - } - - if ($where !== false && !is_null($where)) { - if (is_array($where)) { - $where = implode(' AND ', $where); - } - $where = ' WHERE '.$where; - } - - switch ($mode) { - case MDB2_AUTOQUERY_INSERT: - if (empty($table_fields)) { - return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, - 'Insert requires table fields', __FUNCTION__); - } - $cols = implode(', ', $table_fields); - $values = '?'.str_repeat(', ?', (count($table_fields) - 1)); - return 'INSERT INTO '.$table.' ('.$cols.') VALUES ('.$values.')'; - break; - case MDB2_AUTOQUERY_UPDATE: - if (empty($table_fields)) { - return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, - 'Update requires table fields', __FUNCTION__); - } - $set = implode(' = ?, ', $table_fields).' = ?'; - $sql = 'UPDATE '.$table.' SET '.$set.$where; - return $sql; - break; - case MDB2_AUTOQUERY_DELETE: - $sql = 'DELETE FROM '.$table.$where; - return $sql; - break; - case MDB2_AUTOQUERY_SELECT: - $cols = !empty($table_fields) ? implode(', ', $table_fields) : '*'; - $sql = 'SELECT '.$cols.' FROM '.$table.$where; - return $sql; - break; - } - return $db->raiseError(MDB2_ERROR_SYNTAX, null, null, - 'Non existant mode', __FUNCTION__); - } - // }}} - - // {{{ limitQuery() - - /** - * Generates a limited query - * - * @param string query - * @param array that contains the types of the columns in the result set - * @param integer the numbers of rows to fetch - * @param integer the row to start to fetching - * @param string which specifies which result class to use - * @param mixed string which specifies which class to wrap results in - * - * @return MDB2_Result|MDB2_Error result set on success, a MDB2 error on failure - * @access public - */ - function &limitQuery($query, $types, $limit, $offset = 0, $result_class = true, - $result_wrap_class = false) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - $result = $db->setLimit($limit, $offset); - if (PEAR::isError($result)) { - return $result; - } - $result =& $db->query($query, $types, $result_class, $result_wrap_class); - return $result; - } - // }}} - - // {{{ execParam() - - /** - * Execute a parameterized DML statement. - * - * @param string the SQL query - * @param array if supplied, prepare/execute will be used - * with this array as execute parameters - * @param array that contains the types of the values defined in $params - * - * @return int|MDB2_Error affected rows on success, a MDB2 error on failure - * @access public - */ - function execParam($query, $params = array(), $param_types = null) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - settype($params, 'array'); - if (empty($params)) { - return $db->exec($query); - } - - $stmt = $db->prepare($query, $param_types, MDB2_PREPARE_MANIP); - if (PEAR::isError($stmt)) { - return $stmt; - } - - $result = $stmt->execute($params); - if (PEAR::isError($result)) { - return $result; - } - - $stmt->free(); - 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 the SQL query - * @param string that contains the type of the column in the result set - * @param array if supplied, prepare/execute will be used - * with this array as execute parameters - * @param array that contains the types of the values defined in $params - * @param int|string which column to return - * - * @return scalar|MDB2_Error data on success, a MDB2 error on failure - * @access public - */ - function getOne($query, $type = null, $params = array(), - $param_types = null, $colnum = 0) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - settype($params, 'array'); - settype($type, 'array'); - if (empty($params)) { - return $db->queryOne($query, $type, $colnum); - } - - $stmt = $db->prepare($query, $param_types, $type); - if (PEAR::isError($stmt)) { - return $stmt; - } - - $result = $stmt->execute($params); - if (!MDB2::isResultCommon($result)) { - return $result; - } - - $one = $result->fetchOne($colnum); - $stmt->free(); - $result->free(); - return $one; - } - // }}} - - // {{{ 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 the SQL query - * @param array that contains the types of the columns in the result set - * @param array if supplied, prepare/execute will be used - * with this array as execute parameters - * @param array that contains the types of the values defined in $params - * @param int the fetch mode to use - * - * @return array|MDB2_Error data on success, a MDB2 error on failure - * @access public - */ - function getRow($query, $types = null, $params = array(), - $param_types = null, $fetchmode = MDB2_FETCHMODE_DEFAULT) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - settype($params, 'array'); - if (empty($params)) { - return $db->queryRow($query, $types, $fetchmode); - } - - $stmt = $db->prepare($query, $param_types, $types); - if (PEAR::isError($stmt)) { - return $stmt; - } - - $result = $stmt->execute($params); - if (!MDB2::isResultCommon($result)) { - return $result; - } - - $row = $result->fetchRow($fetchmode); - $stmt->free(); - $result->free(); - return $row; - } - // }}} - - // {{{ getCol() - - /** - * Fetch a single column from a result set and return it as an - * indexed array. - * - * @param string the SQL query - * @param string that contains the type of the column in the result set - * @param array if supplied, prepare/execute will be used - * with this array as execute parameters - * @param array that contains the types of the values defined in $params - * @param int|string which column to return - * - * @return array|MDB2_Error data on success, a MDB2 error on failure - * @access public - */ - function getCol($query, $type = null, $params = array(), - $param_types = null, $colnum = 0) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - settype($params, 'array'); - settype($type, 'array'); - if (empty($params)) { - return $db->queryCol($query, $type, $colnum); - } - - $stmt = $db->prepare($query, $param_types, $type); - if (PEAR::isError($stmt)) { - return $stmt; - } - - $result = $stmt->execute($params); - if (!MDB2::isResultCommon($result)) { - return $result; - } - - $col = $result->fetchCol($colnum); - $stmt->free(); - $result->free(); - return $col; - } - // }}} - - // {{{ getAll() - - /** - * Fetch all the rows returned from a query. - * - * @param string the SQL query - * @param array that contains the types of the columns in the result set - * @param array if supplied, prepare/execute will be used - * with this array as execute parameters - * @param array that contains the types of the values defined in $params - * @param int the fetch mode to use - * @param bool if set to true, the $all will have the first - * column as its first dimension - * @param bool $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 bool $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|MDB2_Error data on success, a MDB2 error on failure - * @access public - */ - function getAll($query, $types = null, $params = array(), - $param_types = null, $fetchmode = MDB2_FETCHMODE_DEFAULT, - $rekey = false, $force_array = false, $group = false) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - settype($params, 'array'); - if (empty($params)) { - return $db->queryAll($query, $types, $fetchmode, $rekey, $force_array, $group); - } - - $stmt = $db->prepare($query, $param_types, $types); - if (PEAR::isError($stmt)) { - return $stmt; - } - - $result = $stmt->execute($params); - if (!MDB2::isResultCommon($result)) { - return $result; - } - - $all = $result->fetchAll($fetchmode, $rekey, $force_array, $group); - $stmt->free(); - $result->free(); - return $all; - } - // }}} - - // {{{ 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 MDB2 error code is - * returned on errors. If the result set contains fewer than two - * columns, a MDB2_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 mytable') returns: - *
    -     *    array(
    -     *      '1' => array('one', '944679408'),
    -     *      '2' => array('two', '944679408'),
    -     *      '3' => array('three', '944679408')
    -     *    )
    -     * 
    - * - * 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: - *
    -     * getAssoc('SELECT category,id,name FROM mytable', null, null
    -     *           MDB2_FETCHMODE_ASSOC, false, 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')
    -     *             )
    -     *    )
    -     * 
    - * - * Keep in mind that database functions in PHP usually return string - * values for results regardless of the database's internal type. - * - * @param string the SQL query - * @param array that contains the types of the columns in the result set - * @param array if supplied, prepare/execute will be used - * with this array as execute parameters - * @param array that contains the types of the values defined in $params - * @param bool $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 bool $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|MDB2_Error data on success, a MDB2 error on failure - * @access public - */ - function getAssoc($query, $types = null, $params = array(), $param_types = null, - $fetchmode = MDB2_FETCHMODE_DEFAULT, $force_array = false, $group = false) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - settype($params, 'array'); - if (empty($params)) { - return $db->queryAll($query, $types, $fetchmode, true, $force_array, $group); - } - - $stmt = $db->prepare($query, $param_types, $types); - if (PEAR::isError($stmt)) { - return $stmt; - } - - $result = $stmt->execute($params); - if (!MDB2::isResultCommon($result)) { - return $result; - } - - $all = $result->fetchAll($fetchmode, true, $force_array, $group); - $stmt->free(); - $result->free(); - return $all; - } - // }}} - - // {{{ executeMultiple() - - /** - * This function does several execute() calls on the same statement handle. - * $params 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 query handle from prepare() - * @param array numeric array containing the data to insert into the query - * - * @return bool|MDB2_Error true on success, a MDB2 error on failure - * @access public - * @see prepare(), execute() - */ - function executeMultiple(&$stmt, $params = null) - { - for ($i = 0, $j = count($params); $i < $j; $i++) { - $result = $stmt->execute($params[$i]); - if (PEAR::isError($result)) { - return $result; - } - } - return MDB2_OK; - } - // }}} - - // {{{ getBeforeID() - - /** - * Returns the next free id of a sequence if the RDBMS - * does not support auto increment - * - * @param string name of the table into which a new row was inserted - * @param string name of the field into which a new row was inserted - * @param bool when true the sequence is automatic created, if it not exists - * @param bool if the returned value should be quoted - * - * @return int|MDB2_Error id on success, a MDB2 error on failure - * @access public - */ - function getBeforeID($table, $field = null, $ondemand = true, $quote = true) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - if ($db->supports('auto_increment') !== true) { - $seq = $table.(empty($field) ? '' : '_'.$field); - $id = $db->nextID($seq, $ondemand); - if (!$quote || PEAR::isError($id)) { - return $id; - } - return $db->quote($id, 'integer'); - } elseif (!$quote) { - return null; - } - return 'NULL'; - } - // }}} - - // {{{ getAfterID() - - /** - * Returns the autoincrement ID if supported or $id - * - * @param mixed value as returned by getBeforeId() - * @param string name of the table into which a new row was inserted - * @param string name of the field into which a new row was inserted - * - * @return int|MDB2_Error id on success, a MDB2 error on failure - * @access public - */ - function getAfterID($id, $table, $field = null) - { - $db =& $this->getDBInstance(); - if (PEAR::isError($db)) { - return $db; - } - - if ($db->supports('auto_increment') !== true) { - return $id; - } - return $db->lastInsertID($table, $field); - } - // }}} -} -?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/MDB2/Iterator.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/MDB2/Iterator.php --- php-mdb2-2.4.1/MDB2-2.4.1/MDB2/Iterator.php 2007-05-03 19:58:15.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.4.1/MDB2/Iterator.php 1970-01-01 01:00:00.000000000 +0100 @@ -1,259 +0,0 @@ - | -// +----------------------------------------------------------------------+ -// -// $Id: Iterator.php,v 1.22 2006/05/06 14:03:41 lsmith Exp $ - -/** - * PHP5 Iterator - * - * @package MDB2 - * @category Database - * @author Lukas Smith - */ -class MDB2_Iterator implements Iterator -{ - protected $fetchmode; - protected $result; - protected $row; - - // {{{ constructor - - /** - * Constructor - */ - public function __construct($result, $fetchmode = MDB2_FETCHMODE_DEFAULT) - { - $this->result = $result; - $this->fetchmode = $fetchmode; - } - // }}} - - // {{{ seek() - - /** - * Seek forward to a specific row in a result set - * - * @param int number of the row where the data can be found - * - * @return void - * @access public - */ - public function seek($rownum) - { - $this->row = null; - if ($this->result) { - $this->result->seek($rownum); - } - } - // }}} - - // {{{ next() - - /** - * Fetch next row of data - * - * @return void - * @access public - */ - public function next() - { - $this->row = null; - } - // }}} - - // {{{ current() - - /** - * return a row of data - * - * @return void - * @access public - */ - public function current() - { - if (is_null($this->row)) { - $row = $this->result->fetchRow($this->fetchmode); - if (PEAR::isError($row)) { - $row = false; - } - $this->row = $row; - } - return $this->row; - } - // }}} - - // {{{ valid() - - /** - * Check if the end of the result set has been reached - * - * @return bool true/false, false is also returned on failure - * @access public - */ - public function valid() - { - return (bool)$this->current(); - } - // }}} - - // {{{ free() - - /** - * Free the internal resources associated with result. - * - * @return bool|MDB2_Error true on success, false|MDB2_Error if result is invalid - * @access public - */ - public function free() - { - if ($this->result) { - return $this->result->free(); - } - $this->result = false; - $this->row = null; - return false; - } - // }}} - - // {{{ key() - - /** - * Returns the row number - * - * @return int|bool|MDB2_Error true on success, false|MDB2_Error if result is invalid - * @access public - */ - public function key() - { - if ($this->result) { - return $this->result->rowCount(); - } - return false; - } - // }}} - - // {{{ rewind() - - /** - * Seek to the first row in a result set - * - * @return void - * @access public - */ - public function rewind() - { - } - // }}} - - // {{{ destructor - - /** - * Destructor - */ - public function __destruct() - { - $this->free(); - } - // }}} -} - -/** - * PHP5 buffered Iterator - * - * @package MDB2 - * @category Database - * @author Lukas Smith - */ -class MDB2_BufferedIterator extends MDB2_Iterator implements SeekableIterator -{ - // {{{ valid() - - /** - * Check if the end of the result set has been reached - * - * @return bool|MDB2_Error true on success, false|MDB2_Error if result is invalid - * @access public - */ - public function valid() - { - if ($this->result) { - return $this->result->valid(); - } - return false; - } - // }}} - - // {{{count() - - /** - * Returns the number of rows in a result object - * - * @return int|MDB2_Error number of rows, false|MDB2_Error if result is invalid - * @access public - */ - public function count() - { - if ($this->result) { - return $this->result->numRows(); - } - return false; - } - // }}} - - // {{{ rewind() - - /** - * Seek to the first row in a result set - * - * @return void - * @access public - */ - public function rewind() - { - $this->seek(0); - } - // }}} -} - -?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/MDB2/LOB.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/MDB2/LOB.php --- php-mdb2-2.4.1/MDB2-2.4.1/MDB2/LOB.php 2007-05-03 19:58:15.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.4.1/MDB2/LOB.php 1970-01-01 01:00:00.000000000 +0100 @@ -1,264 +0,0 @@ - | -// +----------------------------------------------------------------------+ -// -// $Id: LOB.php,v 1.34 2006/10/25 11:52:21 lsmith Exp $ - -/** - * @package MDB2 - * @category Database - * @author Lukas Smith - */ - -require_once 'MDB2.php'; - -/** - * MDB2_LOB: user land stream wrapper implementation for LOB support - * - * @package MDB2 - * @category Database - * @author Lukas Smith - */ -class MDB2_LOB -{ - /** - * contains the key to the global MDB2 instance array of the associated - * MDB2 instance - * - * @var integer - * @access protected - */ - var $db_index; - - /** - * contains the key to the global MDB2_LOB instance array of the associated - * MDB2_LOB instance - * - * @var integer - * @access protected - */ - var $lob_index; - - // {{{ stream_open() - - /** - * open stream - * - * @param string specifies the URL that was passed to fopen() - * @param string the mode used to open the file - * @param int holds additional flags set by the streams API - * @param string not used - * - * @return bool - * @access public - */ - function stream_open($path, $mode, $options, &$opened_path) - { - if (!preg_match('/^rb?\+?$/', $mode)) { - return false; - } - $url = parse_url($path); - if (empty($url['host'])) { - return false; - } - $this->db_index = (int)$url['host']; - if (!isset($GLOBALS['_MDB2_databases'][$this->db_index])) { - return false; - } - $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; - $this->lob_index = (int)$url['user']; - if (!isset($db->datatype->lobs[$this->lob_index])) { - return false; - } - return true; - } - // }}} - - // {{{ stream_read() - - /** - * read stream - * - * @param int number of bytes to read - * - * @return string - * @access public - */ - function stream_read($count) - { - if (isset($GLOBALS['_MDB2_databases'][$this->db_index])) { - $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; - $db->datatype->_retrieveLOB($db->datatype->lobs[$this->lob_index]); - - $data = $db->datatype->_readLOB($db->datatype->lobs[$this->lob_index], $count); - $length = strlen($data); - if ($length == 0) { - $db->datatype->lobs[$this->lob_index]['endOfLOB'] = true; - } - $db->datatype->lobs[$this->lob_index]['position'] += $length; - return $data; - } - } - // }}} - - // {{{ stream_write() - - /** - * write stream, note implemented - * - * @param string data - * - * @return int - * @access public - */ - function stream_write($data) - { - return 0; - } - // }}} - - // {{{ stream_tell() - - /** - * return the current position - * - * @return int current position - * @access public - */ - function stream_tell() - { - if (isset($GLOBALS['_MDB2_databases'][$this->db_index])) { - $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; - return $db->datatype->lobs[$this->lob_index]['position']; - } - } - // }}} - - // {{{ stream_eof() - - /** - * Check if stream reaches EOF - * - * @return bool - * @access public - */ - function stream_eof() - { - if (!isset($GLOBALS['_MDB2_databases'][$this->db_index])) { - return true; - } - - $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; - $result = $db->datatype->_endOfLOB($db->datatype->lobs[$this->lob_index]); - if (version_compare(phpversion(), "5.0", ">=") - && version_compare(phpversion(), "5.1", "<") - ) { - return !$result; - } - return $result; - } - // }}} - - // {{{ stream_seek() - - /** - * Seek stream, not implemented - * - * @param int offset - * @param int whence - * - * @return bool - * @access public - */ - function stream_seek($offset, $whence) - { - return false; - } - // }}} - - // {{{ stream_stat() - - /** - * return information about stream - * - * @access public - */ - function stream_stat() - { - if (isset($GLOBALS['_MDB2_databases'][$this->db_index])) { - $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; - return array( - 'db_index' => $this->db_index, - 'lob_index' => $this->lob_index, - ); - } - } - // }}} - - // {{{ stream_close() - - /** - * close stream - * - * @access public - */ - function stream_close() - { - if (isset($GLOBALS['_MDB2_databases'][$this->db_index])) { - $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; - if (isset($db->datatype->lobs[$this->lob_index])) { - $db->datatype->_destroyLOB($db->datatype->lobs[$this->lob_index]); - unset($db->datatype->lobs[$this->lob_index]); - } - } - } - // }}} -} - -// register streams wrapper -if (!stream_wrapper_register("MDB2LOB", "MDB2_LOB")) { - MDB2::raiseError(); - return false; -} - -?> diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/MDB2.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/MDB2.php --- php-mdb2-2.4.1/MDB2-2.4.1/MDB2.php 2007-05-03 19:58:15.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.4.1/MDB2.php 1970-01-01 01:00:00.000000000 +0100 @@ -1,4271 +0,0 @@ - | -// +----------------------------------------------------------------------+ -// -// $Id: MDB2.php,v 1.292 2007/04/25 09:31:01 quipo Exp $ -// - -/** - * @package MDB2 - * @category Database - * @author Lukas Smith - */ - -require_once 'PEAR.php'; - -// {{{ Error constants - -/** - * The method mapErrorCode in each MDB2_dbtype implementation maps - * native error codes to one of these. - * - * If you add an error code here, make sure you also add a textual - * version of it in MDB2::errorMessage(). - */ - -define('MDB2_OK', true); -define('MDB2_ERROR', -1); -define('MDB2_ERROR_SYNTAX', -2); -define('MDB2_ERROR_CONSTRAINT', -3); -define('MDB2_ERROR_NOT_FOUND', -4); -define('MDB2_ERROR_ALREADY_EXISTS', -5); -define('MDB2_ERROR_UNSUPPORTED', -6); -define('MDB2_ERROR_MISMATCH', -7); -define('MDB2_ERROR_INVALID', -8); -define('MDB2_ERROR_NOT_CAPABLE', -9); -define('MDB2_ERROR_TRUNCATED', -10); -define('MDB2_ERROR_INVALID_NUMBER', -11); -define('MDB2_ERROR_INVALID_DATE', -12); -define('MDB2_ERROR_DIVZERO', -13); -define('MDB2_ERROR_NODBSELECTED', -14); -define('MDB2_ERROR_CANNOT_CREATE', -15); -define('MDB2_ERROR_CANNOT_DELETE', -16); -define('MDB2_ERROR_CANNOT_DROP', -17); -define('MDB2_ERROR_NOSUCHTABLE', -18); -define('MDB2_ERROR_NOSUCHFIELD', -19); -define('MDB2_ERROR_NEED_MORE_DATA', -20); -define('MDB2_ERROR_NOT_LOCKED', -21); -define('MDB2_ERROR_VALUE_COUNT_ON_ROW', -22); -define('MDB2_ERROR_INVALID_DSN', -23); -define('MDB2_ERROR_CONNECT_FAILED', -24); -define('MDB2_ERROR_EXTENSION_NOT_FOUND',-25); -define('MDB2_ERROR_NOSUCHDB', -26); -define('MDB2_ERROR_ACCESS_VIOLATION', -27); -define('MDB2_ERROR_CANNOT_REPLACE', -28); -define('MDB2_ERROR_CONSTRAINT_NOT_NULL',-29); -define('MDB2_ERROR_DEADLOCK', -30); -define('MDB2_ERROR_CANNOT_ALTER', -31); -define('MDB2_ERROR_MANAGER', -32); -define('MDB2_ERROR_MANAGER_PARSE', -33); -define('MDB2_ERROR_LOADMODULE', -34); -define('MDB2_ERROR_INSUFFICIENT_DATA', -35); -// }}} -// {{{ Verbose constants -/** - * These are just helper constants to more verbosely express parameters to prepare() - */ - -define('MDB2_PREPARE_MANIP', false); -define('MDB2_PREPARE_RESULT', null); - -// }}} -// {{{ Fetchmode constants - -/** - * This is a special constant that tells MDB2 the user hasn't specified - * any particular get mode, so the default should be used. - */ -define('MDB2_FETCHMODE_DEFAULT', 0); - -/** - * Column data indexed by numbers, ordered from 0 and up - */ -define('MDB2_FETCHMODE_ORDERED', 1); - -/** - * Column data indexed by column names - */ -define('MDB2_FETCHMODE_ASSOC', 2); - -/** - * Column data as object properties - */ -define('MDB2_FETCHMODE_OBJECT', 3); - -/** - * For multi-dimensional results: normally the first level of arrays - * is the row number, and the second level indexed by column number or name. - * MDB2_FETCHMODE_FLIPPED switches this order, so the first level of arrays - * is the column name, and the second level the row number. - */ -define('MDB2_FETCHMODE_FLIPPED', 4); - -// }}} -// {{{ Portability mode constants - -/** - * Portability: turn off all portability features. - * @see MDB2_Driver_Common::setOption() - */ -define('MDB2_PORTABILITY_NONE', 0); - -/** - * Portability: convert names of tables and fields to case defined in the - * "field_case" option when using the query*(), fetch*() and tableInfo() methods. - * @see MDB2_Driver_Common::setOption() - */ -define('MDB2_PORTABILITY_FIX_CASE', 1); - -/** - * Portability: right trim the data output by query*() and fetch*(). - * @see MDB2_Driver_Common::setOption() - */ -define('MDB2_PORTABILITY_RTRIM', 2); - -/** - * Portability: force reporting the number of rows deleted. - * @see MDB2_Driver_Common::setOption() - */ -define('MDB2_PORTABILITY_DELETE_COUNT', 4); - -/** - * Portability: not needed in MDB2 (just left here for compatibility to DB) - * @see MDB2_Driver_Common::setOption() - */ -define('MDB2_PORTABILITY_NUMROWS', 8); - -/** - * Portability: makes certain error messages in certain drivers compatible - * with those from other DBMS's. - * - * + mysql, mysqli: change unique/primary key constraints - * MDB2_ERROR_ALREADY_EXISTS -> MDB2_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 MDB2_ERROR_NOSUCHFIELD. - * - * @see MDB2_Driver_Common::setOption() - */ -define('MDB2_PORTABILITY_ERRORS', 16); - -/** - * Portability: convert empty values to null strings in data output by - * query*() and fetch*(). - * @see MDB2_Driver_Common::setOption() - */ -define('MDB2_PORTABILITY_EMPTY_TO_NULL', 32); - -/** - * Portability: removes database/table qualifiers from associative indexes - * @see MDB2_Driver_Common::setOption() - */ -define('MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES', 64); - -/** - * Portability: turn on all portability features. - * @see MDB2_Driver_Common::setOption() - */ -define('MDB2_PORTABILITY_ALL', 127); - -// }}} -// {{{ Globals for class instance tracking - -/** - * These are global variables that are used to track the various class instances - */ - -$GLOBALS['_MDB2_databases'] = array(); -$GLOBALS['_MDB2_dsninfo_default'] = array( - 'phptype' => false, - 'dbsyntax' => false, - 'username' => false, - 'password' => false, - 'protocol' => false, - 'hostspec' => false, - 'port' => false, - 'socket' => false, - 'database' => false, - 'mode' => false, -); - -// }}} -// {{{ class MDB2 - -/** - * The main 'MDB2' class is simply a container class with some static - * methods for creating DB objects as well as some utility functions - * common to all parts of DB. - * - * The object model of MDB2 is as follows (indentation means inheritance): - * - * MDB2 The main MDB2 class. This is simply a utility class - * with some 'static' methods for creating MDB2 objects as - * well as common utility functions for other MDB2 classes. - * - * MDB2_Driver_Common The base for each MDB2 implementation. Provides default - * | implementations (in OO lingo virtual methods) for - * | the actual DB implementations as well as a bunch of - * | query utility functions. - * | - * +-MDB2_Driver_mysql The MDB2 implementation for MySQL. Inherits MDB2_Driver_Common. - * When calling MDB2::factory or MDB2::connect for MySQL - * connections, the object returned is an instance of this - * class. - * +-MDB2_Driver_pgsql The MDB2 implementation for PostGreSQL. Inherits MDB2_Driver_Common. - * When calling MDB2::factory or MDB2::connect for PostGreSQL - * connections, the object returned is an instance of this - * class. - * - * @package MDB2 - * @category Database - * @author Lukas Smith - */ -class MDB2 -{ - // {{{ function setOptions(&$db, $options) - - /** - * set option array in an exiting database object - * - * @param MDB2_Driver_Common MDB2 object - * @param array An associative array of option names and their values. - * - * @return mixed MDB2_OK or a PEAR Error object - * - * @access public - */ - function setOptions(&$db, $options) - { - if (is_array($options)) { - foreach ($options as $option => $value) { - $test = $db->setOption($option, $value); - if (PEAR::isError($test)) { - return $test; - } - } - } - return MDB2_OK; - } - - // }}} - // {{{ function classExists($classname) - - /** - * Checks if a class exists without triggering __autoload - * - * @param string classname - * - * @return bool true success and false on error - * @static - * @access public - */ - function classExists($classname) - { - if (version_compare(phpversion(), "5.0", ">=")) { - return class_exists($classname, false); - } - return class_exists($classname); - } - - // }}} - // {{{ function loadClass($class_name, $debug) - - /** - * Loads a PEAR class. - * - * @param string classname to load - * @param bool if errors should be suppressed - * - * @return mixed true success or PEAR_Error on failure - * - * @access public - */ - function loadClass($class_name, $debug) - { - if (!MDB2::classExists($class_name)) { - $file_name = str_replace('_', DIRECTORY_SEPARATOR, $class_name).'.php'; - if ($debug) { - $include = include_once($file_name); - } else { - $include = @include_once($file_name); - } - if (!$include) { - if (!MDB2::fileExists($file_name)) { - $msg = "unable to find package '$class_name' file '$file_name'"; - } else { - $msg = "unable to load class '$class_name' from file '$file_name'"; - } - $err =& MDB2::raiseError(MDB2_ERROR_NOT_FOUND, null, null, $msg); - return $err; - } - } - return MDB2_OK; - } - - // }}} - // {{{ function &factory($dsn, $options = false) - - /** - * Create a new MDB2 object for the specified database type - * - * IMPORTANT: In order for MDB2 to work properly it is necessary that - * you make sure that you work with a reference of the original - * object instead of a copy (this is a PHP4 quirk). - * - * For example: - * $db =& MDB2::factory($dsn); - * ^^ - * And not: - * $db = MDB2::factory($dsn); - * - * @param mixed 'data source name', see the MDB2::parseDSN - * method for a description of the dsn format. - * Can also be specified as an array of the - * format returned by MDB2::parseDSN. - * @param array An associative array of option names and - * their values. - * - * @return mixed a newly created MDB2 object, or false on error - * - * @access public - */ - function &factory($dsn, $options = false) - { - $dsninfo = MDB2::parseDSN($dsn); - if (empty($dsninfo['phptype'])) { - $err =& MDB2::raiseError(MDB2_ERROR_NOT_FOUND, - null, null, 'no RDBMS driver specified'); - return $err; - } - $class_name = 'MDB2_Driver_'.$dsninfo['phptype']; - - $debug = (!empty($options['debug'])); - $err = MDB2::loadClass($class_name, $debug); - if (PEAR::isError($err)) { - return $err; - } - - $db =& new $class_name(); - $db->setDSN($dsninfo); - $err = MDB2::setOptions($db, $options); - if (PEAR::isError($err)) { - return $err; - } - - return $db; - } - - // }}} - // {{{ function &connect($dsn, $options = false) - - /** - * Create a new MDB2 connection object and connect to the specified - * database - * - * IMPORTANT: In order for MDB2 to work properly it is necessary that - * you make sure that you work with a reference of the original - * object instead of a copy (this is a PHP4 quirk). - * - * For example: - * $db =& MDB2::connect($dsn); - * ^^ - * And not: - * $db = MDB2::connect($dsn); - * ^^ - * - * @param mixed 'data source name', see the MDB2::parseDSN - * method for a description of the dsn format. - * Can also be specified as an array of the - * format returned by MDB2::parseDSN. - * @param array An associative array of option names and - * their values. - * - * @return mixed a newly created MDB2 connection object, or a MDB2 - * error object on error - * - * @access public - * @see MDB2::parseDSN - */ - function &connect($dsn, $options = false) - { - $db =& MDB2::factory($dsn, $options); - if (PEAR::isError($db)) { - return $db; - } - - $err = $db->connect(); - if (PEAR::isError($err)) { - $dsn = $db->getDSN('string', 'xxx'); - $db->disconnect(); - $err->addUserInfo($dsn); - return $err; - } - - return $db; - } - - // }}} - // {{{ function &singleton($dsn = null, $options = false) - - /** - * Returns a MDB2 connection with the requested DSN. - * A new MDB2 connection object is only created if no object with the - * requested DSN exists yet. - * - * IMPORTANT: In order for MDB2 to work properly it is necessary that - * you make sure that you work with a reference of the original - * object instead of a copy (this is a PHP4 quirk). - * - * For example: - * $db =& MDB2::singleton($dsn); - * ^^ - * And not: - * $db = MDB2::singleton($dsn); - * ^^ - * - * @param mixed 'data source name', see the MDB2::parseDSN - * method for a description of the dsn format. - * Can also be specified as an array of the - * format returned by MDB2::parseDSN. - * @param array An associative array of option names and - * their values. - * - * @return mixed a newly created MDB2 connection object, or a MDB2 - * error object on error - * - * @access public - * @see MDB2::parseDSN - */ - function &singleton($dsn = null, $options = false) - { - if ($dsn) { - $dsninfo = MDB2::parseDSN($dsn); - $dsninfo = array_merge($GLOBALS['_MDB2_dsninfo_default'], $dsninfo); - $keys = array_keys($GLOBALS['_MDB2_databases']); - for ($i=0, $j=count($keys); $i<$j; ++$i) { - if (isset($GLOBALS['_MDB2_databases'][$keys[$i]])) { - $tmp_dsn = $GLOBALS['_MDB2_databases'][$keys[$i]]->getDSN('array'); - if (count(array_diff_assoc($tmp_dsn, $dsninfo)) == 0) { - MDB2::setOptions($GLOBALS['_MDB2_databases'][$keys[$i]], $options); - return $GLOBALS['_MDB2_databases'][$keys[$i]]; - } - } - } - } elseif (is_array($GLOBALS['_MDB2_databases']) && reset($GLOBALS['_MDB2_databases'])) { - $db =& $GLOBALS['_MDB2_databases'][key($GLOBALS['_MDB2_databases'])]; - return $db; - } - $db =& MDB2::factory($dsn, $options); - return $db; - } - - // }}} - // {{{ function loadFile($file) - - /** - * load a file (like 'Date') - * - * @param string name of the file in the MDB2 directory (without '.php') - * - * @return string name of the file that was included - * - * @access public - */ - function loadFile($file) - { - $file_name = 'MDB2'.DIRECTORY_SEPARATOR.$file.'.php'; - if (!MDB2::fileExists($file_name)) { - return MDB2::raiseError(MDB2_ERROR_NOT_FOUND, null, null, - 'unable to find: '.$file_name); - } - if (!include_once($file_name)) { - return MDB2::raiseError(MDB2_ERROR_NOT_FOUND, null, null, - 'unable to load driver class: '.$file_name); - } - return $file_name; - } - - // }}} - // {{{ function apiVersion() - - /** - * Return the MDB2 API version - * - * @return string the MDB2 API version number - * - * @access public - */ - function apiVersion() - { - return '2.4.1'; - } - - // }}} - // {{{ function &raiseError($code = null, $mode = null, $options = null, $userinfo = null) - - /** - * This method is used to communicate an error and invoke error - * callbacks etc. Basically a wrapper for PEAR::raiseError - * without the message string. - * - * @param mixed int error code - * - * @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. - * - * @return PEAR_Error instance of a PEAR Error object - * - * @access private - * @see PEAR_Error - */ - function &raiseError($code = null, $mode = null, $options = null, $userinfo = null) - { - $err =& PEAR::raiseError(null, $code, $mode, $options, $userinfo, 'MDB2_Error', true); - return $err; - } - - // }}} - // {{{ function isError($data, $code = null) - - /** - * Tell whether a value is a MDB2 error. - * - * @param mixed the value to test - * @param int if is an error object, return true - * only if $code is a string and - * $db->getMessage() == $code or - * $code is an integer and $db->getCode() == $code - * - * @return bool true if parameter is an error - * - * @access public - */ - function isError($data, $code = null) - { - if (is_a($data, 'MDB2_Error')) { - if (is_null($code)) { - return true; - } elseif (is_string($code)) { - return $data->getMessage() === $code; - } else { - $code = (array)$code; - return in_array($data->getCode(), $code); - } - } - return false; - } - - // }}} - // {{{ function isConnection($value) - - /** - * Tell whether a value is a MDB2 connection - * - * @param mixed value to test - * - * @return bool whether $value is a MDB2 connection - * - * @access public - */ - function isConnection($value) - { - return is_a($value, 'MDB2_Driver_Common'); - } - - // }}} - // {{{ function isResult($value) - - /** - * Tell whether a value is a MDB2 result - * - * @param mixed value to test - * - * @return bool whether $value is a MDB2 result - * - * @access public - */ - function isResult($value) - { - return is_a($value, 'MDB2_Result'); - } - - // }}} - // {{{ function isResultCommon($value) - - /** - * Tell whether a value is a MDB2 result implementing the common interface - * - * @param mixed value to test - * - * @return bool whether $value is a MDB2 result implementing the common interface - * - * @access public - */ - function isResultCommon($value) - { - return is_a($value, 'MDB2_Result_Common'); - } - - // }}} - // {{{ function isStatement($value) - - /** - * Tell whether a value is a MDB2 statement interface - * - * @param mixed value to test - * - * @return bool whether $value is a MDB2 statement interface - * - * @access public - */ - function isStatement($value) - { - return is_a($value, 'MDB2_Statement'); - } - - // }}} - // {{{ function errorMessage($value = null) - - /** - * Return a textual error message for a MDB2 error code - * - * @param int|array integer error code, - null to get the current error code-message map, - or an array with a new error code-message map - * - * @return string error message, or false if the error code was - * not recognized - * - * @access public - */ - function errorMessage($value = null) - { - static $errorMessages; - - if (is_array($value)) { - $errorMessages = $value; - return MDB2_OK; - } - - if (!isset($errorMessages)) { - $errorMessages = array( - MDB2_OK => 'no error', - MDB2_ERROR => 'unknown error', - MDB2_ERROR_ALREADY_EXISTS => 'already exists', - MDB2_ERROR_CANNOT_CREATE => 'can not create', - MDB2_ERROR_CANNOT_ALTER => 'can not alter', - MDB2_ERROR_CANNOT_REPLACE => 'can not replace', - MDB2_ERROR_CANNOT_DELETE => 'can not delete', - MDB2_ERROR_CANNOT_DROP => 'can not drop', - MDB2_ERROR_CONSTRAINT => 'constraint violation', - MDB2_ERROR_CONSTRAINT_NOT_NULL=> 'null value violates not-null constraint', - MDB2_ERROR_DIVZERO => 'division by zero', - MDB2_ERROR_INVALID => 'invalid', - MDB2_ERROR_INVALID_DATE => 'invalid date or time', - MDB2_ERROR_INVALID_NUMBER => 'invalid number', - MDB2_ERROR_MISMATCH => 'mismatch', - MDB2_ERROR_NODBSELECTED => 'no database selected', - MDB2_ERROR_NOSUCHFIELD => 'no such field', - MDB2_ERROR_NOSUCHTABLE => 'no such table', - MDB2_ERROR_NOT_CAPABLE => 'MDB2 backend not capable', - MDB2_ERROR_NOT_FOUND => 'not found', - MDB2_ERROR_NOT_LOCKED => 'not locked', - MDB2_ERROR_SYNTAX => 'syntax error', - MDB2_ERROR_UNSUPPORTED => 'not supported', - MDB2_ERROR_VALUE_COUNT_ON_ROW => 'value count on row', - MDB2_ERROR_INVALID_DSN => 'invalid DSN', - MDB2_ERROR_CONNECT_FAILED => 'connect failed', - MDB2_ERROR_NEED_MORE_DATA => 'insufficient data supplied', - MDB2_ERROR_EXTENSION_NOT_FOUND=> 'extension not found', - MDB2_ERROR_NOSUCHDB => 'no such database', - MDB2_ERROR_ACCESS_VIOLATION => 'insufficient permissions', - MDB2_ERROR_LOADMODULE => 'error while including on demand module', - MDB2_ERROR_TRUNCATED => 'truncated', - MDB2_ERROR_DEADLOCK => 'deadlock detected', - ); - } - - if (is_null($value)) { - return $errorMessages; - } - - if (PEAR::isError($value)) { - $value = $value->getCode(); - } - - return isset($errorMessages[$value]) ? - $errorMessages[$value] : $errorMessages[MDB2_ERROR]; - } - - // }}} - // {{{ function parseDSN($dsn) - - /** - * Parse a data source name. - * - * Additional keys can be added by appending a URI query string to the - * end of the DSN. - * - * The format of the supplied DSN is in its fullest form: - * - * phptype(dbsyntax)://username:password@protocol+hostspec/database?option=8&another=true - * - * - * Most variations are allowed: - * - * phptype://username:password@protocol+hostspec:110//usr/db_file.db?mode=0644 - * phptype://username:password@hostspec/database_name - * phptype://username:password@hostspec - * phptype://username@hostspec - * phptype://hostspec/database - * phptype://hostspec - * phptype(dbsyntax) - * phptype - * - * - * @param string 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 - * - * @access public - * @author Tomas V.V.Cox - */ - function parseDSN($dsn) - { - $parsed = $GLOBALS['_MDB2_dsninfo_default']; - - if (is_array($dsn)) { - $dsn = array_merge($parsed, $dsn); - if (!$dsn['dbsyntax']) { - $dsn['dbsyntax'] = $dsn['phptype']; - } - return $dsn; - } - - // Find phptype and dbsyntax - if (($pos = strpos($dsn, '://')) !== false) { - $str = substr($dsn, 0, $pos); - $dsn = substr($dsn, $pos + 3); - } else { - $str = $dsn; - $dsn = null; - } - - // Get phptype and dbsyntax - // $str => phptype(dbsyntax) - if (preg_match('|^(.+?)\((.*?)\)$|', $str, $arr)) { - $parsed['phptype'] = $arr[1]; - $parsed['dbsyntax'] = !$arr[2] ? $arr[1] : $arr[2]; - } else { - $parsed['phptype'] = $str; - $parsed['dbsyntax'] = $str; - } - - if (!count($dsn)) { - return $parsed; - } - - // Get (if found): username and password - // $dsn => username:password@protocol+hostspec/database - if (($at = strrpos($dsn,'@')) !== false) { - $str = substr($dsn, 0, $at); - $dsn = substr($dsn, $at + 1); - if (($pos = strpos($str, ':')) !== false) { - $parsed['username'] = rawurldecode(substr($str, 0, $pos)); - $parsed['password'] = rawurldecode(substr($str, $pos + 1)); - } else { - $parsed['username'] = rawurldecode($str); - } - } - - // Find protocol and hostspec - - // $dsn => proto(proto_opts)/database - if (preg_match('|^([^(]+)\((.*?)\)/?(.*?)$|', $dsn, $match)) { - $proto = $match[1]; - $proto_opts = $match[2] ? $match[2] : false; - $dsn = $match[3]; - - // $dsn => protocol+hostspec/database (old format) - } else { - if (strpos($dsn, '+') !== false) { - list($proto, $dsn) = explode('+', $dsn, 2); - } - if ( strpos($dsn, '//') === 0 - && strpos($dsn, '/', 2) !== false - && $parsed['phptype'] == 'oci8' - ) { - //oracle's "Easy Connect" syntax: - //"username/password@[//]host[:port][/service_name]" - //e.g. "scott/tiger@//mymachine:1521/oracle" - $proto_opts = $dsn; - $dsn = null; - } elseif (strpos($dsn, '/') !== false) { - list($proto_opts, $dsn) = explode('/', $dsn, 2); - } else { - $proto_opts = $dsn; - $dsn = null; - } - } - - // process the different protocol options - $parsed['protocol'] = (!empty($proto)) ? $proto : 'tcp'; - $proto_opts = rawurldecode($proto_opts); - if (strpos($proto_opts, ':') !== false) { - list($proto_opts, $parsed['port']) = explode(':', $proto_opts); - } - if ($parsed['protocol'] == 'tcp') { - $parsed['hostspec'] = $proto_opts; - } elseif ($parsed['protocol'] == 'unix') { - $parsed['socket'] = $proto_opts; - } - - // Get dabase if any - // $dsn => database - if ($dsn) { - // /database - if (($pos = strpos($dsn, '?')) === false) { - $parsed['database'] = $dsn; - // /database?param1=value1¶m2=value2 - } else { - $parsed['database'] = substr($dsn, 0, $pos); - $dsn = substr($dsn, $pos + 1); - if (strpos($dsn, '&') !== false) { - $opts = explode('&', $dsn); - } else { // database?param1=value1 - $opts = array($dsn); - } - foreach ($opts as $opt) { - list($key, $value) = explode('=', $opt); - if (!isset($parsed[$key])) { - // don't allow params overwrite - $parsed[$key] = rawurldecode($value); - } - } - } - } - - return $parsed; - } - - // }}} - // {{{ function fileExists($file) - - /** - * Checks if a file exists in the include path - * - * @param string filename - * - * @return bool true success and false on error - * - * @access public - */ - function fileExists($file) - { - // safe_mode does notwork with is_readable() - if (!@ini_get('safe_mode')) { - $dirs = explode(PATH_SEPARATOR, ini_get('include_path')); - foreach ($dirs as $dir) { - if (is_readable($dir . DIRECTORY_SEPARATOR . $file)) { - return true; - } - } - } else { - $fp = @fopen($file, 'r', true); - if (is_resource($fp)) { - @fclose($fp); - return true; - } - } - return false; - } - // }}} -} - -// }}} -// {{{ class MDB2_Error extends PEAR_Error - -/** - * MDB2_Error implements a class for reporting portable database error - * messages. - * - * @package MDB2 - * @category Database - * @author Stig Bakken - */ -class MDB2_Error extends PEAR_Error -{ - // {{{ constructor: function MDB2_Error($code = MDB2_ERROR, $mode = PEAR_ERROR_RETURN, $level = E_USER_NOTICE, $debuginfo = null) - - /** - * MDB2_Error constructor. - * - * @param mixed MDB2 error code, or string with error message. - * @param int what 'error mode' to operate in - * @param int what error level to use for $mode & PEAR_ERROR_TRIGGER - * @param smixed additional debug info, such as the last query - */ - function MDB2_Error($code = MDB2_ERROR, $mode = PEAR_ERROR_RETURN, - $level = E_USER_NOTICE, $debuginfo = null) - { - if (is_null($code)) { - $code = MDB2_ERROR; - } - $this->PEAR_Error('MDB2 Error: '.MDB2::errorMessage($code), $code, - $mode, $level, $debuginfo); - } - - // }}} -} - -// }}} -// {{{ class MDB2_Driver_Common extends PEAR - -/** - * MDB2_Driver_Common: Base class that is extended by each MDB2 driver - * - * @package MDB2 - * @category Database - * @author Lukas Smith - */ -class MDB2_Driver_Common extends PEAR -{ - // {{{ Variables (Properties) - - /** - * index of the MDB2 object within the $GLOBALS['_MDB2_databases'] array - * @var int - * @access public - */ - var $db_index = 0; - - /** - * DSN used for the next query - * @var array - * @access protected - */ - var $dsn = array(); - - /** - * DSN that was used to create the current connection - * @var array - * @access protected - */ - var $connected_dsn = array(); - - /** - * connection resource - * @var mixed - * @access protected - */ - var $connection = 0; - - /** - * if the current opened connection is a persistent connection - * @var bool - * @access protected - */ - var $opened_persistent; - - /** - * the name of the database for the next query - * @var string - * @access protected - */ - var $database_name = ''; - - /** - * the name of the database currently selected - * @var string - * @access protected - */ - var $connected_database_name = ''; - - /** - * server version information - * @var string - * @access protected - */ - var $connected_server_info = ''; - - /** - * list of all supported features of the given driver - * @var array - * @access public - */ - var $supported = array( - 'sequences' => false, - 'indexes' => false, - 'affected_rows' => false, - 'summary_functions' => false, - 'order_by_text' => false, - 'transactions' => false, - 'savepoints' => false, - 'current_id' => false, - 'limit_queries' => false, - 'LOBs' => false, - 'replace' => false, - 'sub_selects' => false, - 'auto_increment' => false, - 'primary_key' => false, - 'result_introspection' => false, - 'prepared_statements' => false, - 'identifier_quoting' => false, - 'pattern_escaping' => false, - 'new_link' => false, - ); - - /** - * Array of supported options that can be passed to the MDB2 instance. - * - * The options can be set during object creation, using - * MDB2::connect(), MDB2::factory() or MDB2::singleton(). The options can - * also be set after the object is created, using MDB2::setOptions() or - * MDB2_Driver_Common::setOption(). - * The list of available option includes: - *
      - *
    • $options['ssl'] -> boolean: determines if ssl should be used for connections
    • - *
    • $options['field_case'] -> CASE_LOWER|CASE_UPPER: determines what case to force on field/table names
    • - *
    • $options['disable_query'] -> boolean: determines if queries should be executed
    • - *
    • $options['result_class'] -> string: class used for result sets
    • - *
    • $options['buffered_result_class'] -> string: class used for buffered result sets
    • - *
    • $options['result_wrap_class'] -> string: class used to wrap result sets into
    • - *
    • $options['result_buffering'] -> boolean should results be buffered or not?
    • - *
    • $options['fetch_class'] -> string: class to use when fetch mode object is used
    • - *
    • $options['persistent'] -> boolean: persistent connection?
    • - *
    • $options['debug'] -> integer: numeric debug level
    • - *
    • $options['debug_handler'] -> string: function/method that captures debug messages
    • - *
    • $options['debug_expanded_output'] -> bool: BC option to determine if more context information should be send to the debug handler
    • - *
    • $options['default_text_field_length'] -> integer: default text field length to use
    • - *
    • $options['lob_buffer_length'] -> integer: LOB buffer length
    • - *
    • $options['log_line_break'] -> string: line-break format
    • - *
    • $options['idxname_format'] -> string: pattern for index name
    • - *
    • $options['seqname_format'] -> string: pattern for sequence name
    • - *
    • $options['savepoint_format'] -> string: pattern for auto generated savepoint names
    • - *
    • $options['statement_format'] -> string: pattern for prepared statement names
    • - *
    • $options['seqcol_name'] -> string: sequence column name
    • - *
    • $options['quote_identifier'] -> boolean: if identifier quoting should be done when check_option is used
    • - *
    • $options['use_transactions'] -> boolean: if transaction use should be enabled
    • - *
    • $options['decimal_places'] -> integer: number of decimal places to handle
    • - *
    • $options['portability'] -> integer: portability constant
    • - *
    • $options['modules'] -> array: short to long module name mapping for __call()
    • - *
    • $options['emulate_prepared'] -> boolean: force prepared statements to be emulated
    • - *
    • $options['datatype_map'] -> array: map user defined datatypes to other primitive datatypes
    • - *
    • $options['datatype_map_callback'] -> array: callback function/method that should be called
    • - *
    - * - * @var array - * @access public - * @see MDB2::connect() - * @see MDB2::factory() - * @see MDB2::singleton() - * @see MDB2_Driver_Common::setOption() - */ - var $options = array( - 'ssl' => false, - 'field_case' => CASE_LOWER, - 'disable_query' => false, - 'result_class' => 'MDB2_Result_%s', - 'buffered_result_class' => 'MDB2_BufferedResult_%s', - 'result_wrap_class' => false, - 'result_buffering' => true, - 'fetch_class' => 'stdClass', - 'persistent' => false, - 'debug' => 0, - 'debug_handler' => 'MDB2_defaultDebugOutput', - 'debug_expanded_output' => false, - 'default_text_field_length' => 4096, - 'lob_buffer_length' => 8192, - 'log_line_break' => "\n", - 'idxname_format' => '%s_idx', - 'seqname_format' => '%s_seq', - 'savepoint_format' => 'MDB2_SAVEPOINT_%s', - 'statement_format' => 'MDB2_STATEMENT_%1$s_%2$s', - 'seqcol_name' => 'sequence', - 'quote_identifier' => false, - 'use_transactions' => true, - 'decimal_places' => 2, - 'portability' => MDB2_PORTABILITY_ALL, - 'modules' => array( - 'ex' => 'Extended', - 'dt' => 'Datatype', - 'mg' => 'Manager', - 'rv' => 'Reverse', - 'na' => 'Native', - 'fc' => 'Function', - ), - 'emulate_prepared' => false, - 'datatype_map' => array(), - 'datatype_map_callback' => array(), - 'nativetype_map_callback' => array(), - ); - - /** - * string array - * @var string - * @access protected - */ - var $string_quoting = array('start' => "'", 'end' => "'", 'escape' => false, 'escape_pattern' => false); - - /** - * identifier quoting - * @var array - * @access protected - */ - var $identifier_quoting = array('start' => '"', 'end' => '"', 'escape' => '"'); - - /** - * sql comments - * @var array - * @access protected - */ - var $sql_comments = array( - array('start' => '--', 'end' => "\n", 'escape' => false), - array('start' => '/*', 'end' => '*/', 'escape' => false), - ); - - /** - * comparision wildcards - * @var array - * @access protected - */ - var $wildcards = array('%', '_'); - - /** - * column alias keyword - * @var string - * @access protected - */ - var $as_keyword = ' AS '; - - /** - * warnings - * @var array - * @access protected - */ - var $warnings = array(); - - /** - * string with the debugging information - * @var string - * @access public - */ - var $debug_output = ''; - - /** - * determine if there is an open transaction - * @var bool - * @access protected - */ - var $in_transaction = false; - - /** - * the smart transaction nesting depth - * @var int - * @access protected - */ - var $nested_transaction_counter = null; - - /** - * the first error that occured inside a nested transaction - * @var MDB2_Error|bool - * @access protected - */ - var $has_transaction_error = false; - - /** - * result offset used in the next query - * @var int - * @access protected - */ - var $offset = 0; - - /** - * result limit used in the next query - * @var int - * @access protected - */ - var $limit = 0; - - /** - * Database backend used in PHP (mysql, odbc etc.) - * @var string - * @access public - */ - var $phptype; - - /** - * Database used with regards to SQL syntax etc. - * @var string - * @access public - */ - var $dbsyntax; - - /** - * the last query sent to the driver - * @var string - * @access public - */ - var $last_query; - - /** - * the default fetchmode used - * @var int - * @access protected - */ - var $fetchmode = MDB2_FETCHMODE_ORDERED; - - /** - * array of module instances - * @var array - * @access protected - */ - var $modules = array(); - - /** - * determines of the PHP4 destructor emulation has been enabled yet - * @var array - * @access protected - */ - var $destructor_registered = true; - - // }}} - // {{{ constructor: function __construct() - - /** - * Constructor - */ - function __construct() - { - end($GLOBALS['_MDB2_databases']); - $db_index = key($GLOBALS['_MDB2_databases']) + 1; - $GLOBALS['_MDB2_databases'][$db_index] = &$this; - $this->db_index = $db_index; - } - - // }}} - // {{{ function MDB2_Driver_Common() - - /** - * PHP 4 Constructor - */ - function MDB2_Driver_Common() - { - $this->destructor_registered = false; - $this->__construct(); - } - - // }}} - // {{{ destructor: function __destruct() - - /** - * Destructor - */ - function __destruct() - { - $this->disconnect(false); - } - - // }}} - // {{{ function free() - - /** - * Free the internal references so that the instance can be destroyed - * - * @return bool true on success, false if result is invalid - * - * @access public - */ - function free() - { - unset($GLOBALS['_MDB2_databases'][$this->db_index]); - unset($this->db_index); - return MDB2_OK; - } - - // }}} - // {{{ function __toString() - - /** - * String conversation - * - * @return string representation of the object - * - * @access public - */ - function __toString() - { - $info = get_class($this); - $info.= ': (phptype = '.$this->phptype.', dbsyntax = '.$this->dbsyntax.')'; - if ($this->connection) { - $info.= ' [connected]'; - } - return $info; - } - - // }}} - // {{{ function errorInfo($error = null) - - /** - * This method is used to collect information about an error - * - * @param mixed error code or resource - * - * @return array with MDB2 errorcode, native error code, native message - * - * @access public - */ - function errorInfo($error = null) - { - return array($error, null, null); - } - - // }}} - // {{{ function &raiseError($code = null, $mode = null, $options = null, $userinfo = null) - - /** - * This method is used to 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 string name of the method that triggered the error - * - * @return PEAR_Error instance of a PEAR Error object - * - * @access public - * @see PEAR_Error - */ - function &raiseError($code = null, $mode = null, $options = null, $userinfo = null, $method = null) - { - $userinfo = "[Error message: $userinfo]\n"; - // The error is yet a MDB2 error object - if (PEAR::isError($code)) { - // because we use the static PEAR::raiseError, our global - // handler should be used if it is set - if (is_null($mode) && !empty($this->_default_error_mode)) { - $mode = $this->_default_error_mode; - $options = $this->_default_error_options; - } - if (is_null($userinfo)) { - $userinfo = $code->getUserinfo(); - } - $code = $code->getCode(); - } elseif ($code == MDB2_ERROR_NOT_FOUND) { - // extension not loaded: don't call $this->errorInfo() or the script - // will die - } elseif (isset($this->connection)) { - if (!empty($this->last_query)) { - $userinfo.= "[Last executed query: {$this->last_query}]\n"; - } - $native_errno = $native_msg = null; - list($code, $native_errno, $native_msg) = $this->errorInfo($code); - if (!is_null($native_errno) && $native_errno !== '') { - $userinfo.= "[Native code: $native_errno]\n"; - } - if (!is_null($native_msg) && $native_msg !== '') { - $userinfo.= "[Native message: ". strip_tags($native_msg) ."]\n"; - } - if (!is_null($method)) { - $userinfo = $method.': '.$userinfo; - } - } - - $err =& PEAR::raiseError(null, $code, $mode, $options, $userinfo, 'MDB2_Error', true); - if ($err->getMode() !== PEAR_ERROR_RETURN - && isset($this->nested_transaction_counter) && !$this->has_transaction_error) { - $this->has_transaction_error =& $err; - } - return $err; - } - - // }}} - // {{{ function resetWarnings() - - /** - * reset the warning array - * - * @return void - * - * @access public - */ - function resetWarnings() - { - $this->warnings = array(); - } - - // }}} - // {{{ function getWarnings() - - /** - * Get all warnings in reverse order. - * This means that the last warning is the first element in the array - * - * @return array with warnings - * - * @access public - * @see resetWarnings() - */ - function getWarnings() - { - return array_reverse($this->warnings); - } - - // }}} - // {{{ function setFetchMode($fetchmode, $object_class = 'stdClass') - - /** - * Sets which fetch mode should be used by default on queries - * on this connection - * - * @param int MDB2_FETCHMODE_ORDERED, MDB2_FETCHMODE_ASSOC - * or MDB2_FETCHMODE_OBJECT - * @param string the class name of the object to be returned - * by the fetch methods when the - * MDB2_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 possibility to use - * and extend the 'MDB2_row' class. - * - * @return mixed MDB2_OK or MDB2 Error Object - * - * @access public - * @see MDB2_FETCHMODE_ORDERED, MDB2_FETCHMODE_ASSOC, MDB2_FETCHMODE_OBJECT - */ - function setFetchMode($fetchmode, $object_class = 'stdClass') - { - switch ($fetchmode) { - case MDB2_FETCHMODE_OBJECT: - $this->options['fetch_class'] = $object_class; - case MDB2_FETCHMODE_ORDERED: - case MDB2_FETCHMODE_ASSOC: - $this->fetchmode = $fetchmode; - break; - default: - return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'invalid fetchmode mode', __FUNCTION__); - } - - return MDB2_OK; - } - - // }}} - // {{{ function setOption($option, $value) - - /** - * set the option for the db class - * - * @param string option name - * @param mixed value for the option - * - * @return mixed MDB2_OK or MDB2 Error Object - * - * @access public - */ - function setOption($option, $value) - { - if (array_key_exists($option, $this->options)) { - $this->options[$option] = $value; - return MDB2_OK; - } - return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - "unknown option $option", __FUNCTION__); - } - - // }}} - // {{{ function getOption($option) - - /** - * Returns the value of an option - * - * @param string option name - * - * @return mixed the option value or error object - * - * @access public - */ - function getOption($option) - { - if (array_key_exists($option, $this->options)) { - return $this->options[$option]; - } - return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - "unknown option $option", __FUNCTION__); - } - - // }}} - // {{{ function debug($message, $scope = '', $is_manip = null) - - /** - * set a debug message - * - * @param string message that should be appended to the debug variable - * @param string usually the method name that triggered the debug call: - * for example 'query', 'prepare', 'execute', 'parameters', - * 'beginTransaction', 'commit', 'rollback' - * @param array contains context information about the debug() call - * common keys are: is_manip, time, result etc. - * - * @return void - * - * @access public - */ - function debug($message, $scope = '', $context = array()) - { - if ($this->options['debug'] && $this->options['debug_handler']) { - if (!$this->options['debug_expanded_output']) { - if (!empty($context['when']) && $context['when'] !== 'pre') { - return null; - } - $context = empty($context['is_manip']) ? false : $context['is_manip']; - } - return call_user_func_array($this->options['debug_handler'], array(&$this, $scope, $message, $context)); - } - return null; - } - - // }}} - // {{{ function getDebugOutput() - - /** - * output debug info - * - * @return string content of the debug_output class variable - * - * @access public - */ - function getDebugOutput() - { - return $this->debug_output; - } - - // }}} - // {{{ function escape($text) - - /** - * Quotes a string so it can be safely used in a query. It will quote - * the text so it can safely be used within a query. - * - * @param string the input string to quote - * @param bool escape wildcards - * - * @return string quoted string - * - * @access public - */ - function escape($text, $escape_wildcards = false) - { - if ($escape_wildcards) { - $text = $this->escapePattern($text); - } - - $text = str_replace($this->string_quoting['end'], $this->string_quoting['escape'] . $this->string_quoting['end'], $text); - return $text; - } - - // }}} - // {{{ function escapePattern($text) - - /** - * Quotes pattern (% and _) characters in a string) - * - * EXPERIMENTAL - * - * WARNING: this function is experimental and may change signature at - * any time until labelled as non-experimental - * - * @param string the input string to quote - * - * @return string quoted string - * - * @access public - */ - function escapePattern($text) - { - if ($this->string_quoting['escape_pattern']) { - $text = str_replace($this->string_quoting['escape_pattern'], $this->string_quoting['escape_pattern'] . $this->string_quoting['escape_pattern'], $text); - foreach ($this->wildcards as $wildcard) { - $text = str_replace($wildcard, $this->string_quoting['escape_pattern'] . $wildcard, $text); - } - } - return $text; - } - - // }}} - // {{{ function quoteIdentifier($str, $check_option = false) - - /** - * 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 (`) -- due to MySQL - * + double quote (") -- due to Oracle - * + brackets ([ or ]) -- due to Access - * - * Delimited identifiers are known to generally work correctly under - * the following drivers: - * + mssql - * + mysql - * + mysqli - * + oci8 - * + pgsql - * + sqlite - * - * InterBase doesn't seem to be able to use delimited identifiers - * via PHP 4. They work fine under PHP 5. - * - * @param string identifier name to be quoted - * @param bool check the 'quote_identifier' option - * - * @return string quoted identifier string - * - * @access public - */ - function quoteIdentifier($str, $check_option = false) - { - if ($check_option && !$this->options['quote_identifier']) { - return $str; - } - $str = str_replace($this->identifier_quoting['end'], $this->identifier_quoting['escape'] . $this->identifier_quoting['end'], $str); - return $this->identifier_quoting['start'] . $str . $this->identifier_quoting['end']; - } - - // }}} - // {{{ function getAsKeyword() - - /** - * Gets the string to alias column - * - * @return string to use when aliasing a column - */ - function getAsKeyword() - { - return $this->as_keyword; - } - - // }}} - // {{{ function getConnection() - - /** - * Returns a native connection - * - * @return mixed a valid MDB2 connection object, - * or a MDB2 error object on error - * - * @access public - */ - function getConnection() - { - $result = $this->connect(); - if (PEAR::isError($result)) { - return $result; - } - return $this->connection; - } - - // }}} - // {{{ function _fixResultArrayValues(&$row, $mode) - - /** - * Do all necessary conversions on result arrays to fix DBMS quirks - * - * @param array the array to be fixed (passed by reference) - * @param array bit-wise addition of the required portability modes - * - * @return void - * - * @access protected - */ - function _fixResultArrayValues(&$row, $mode) - { - switch ($mode) { - case MDB2_PORTABILITY_EMPTY_TO_NULL: - foreach ($row as $key => $value) { - if ($value === '') { - $row[$key] = null; - } - } - break; - case MDB2_PORTABILITY_RTRIM: - foreach ($row as $key => $value) { - if (is_string($value)) { - $row[$key] = rtrim($value); - } - } - break; - case MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES: - $tmp_row = array(); - foreach ($row as $key => $value) { - $tmp_row[preg_replace('/^(?:.*\.)?([^.]+)$/', '\\1', $key)] = $value; - } - $row = $tmp_row; - break; - case (MDB2_PORTABILITY_RTRIM + MDB2_PORTABILITY_EMPTY_TO_NULL): - foreach ($row as $key => $value) { - if ($value === '') { - $row[$key] = null; - } elseif (is_string($value)) { - $row[$key] = rtrim($value); - } - } - break; - case (MDB2_PORTABILITY_RTRIM + MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES): - $tmp_row = array(); - foreach ($row as $key => $value) { - if (is_string($value)) { - $value = rtrim($value); - } - $tmp_row[preg_replace('/^(?:.*\.)?([^.]+)$/', '\\1', $key)] = $value; - } - $row = $tmp_row; - break; - case (MDB2_PORTABILITY_EMPTY_TO_NULL + MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES): - $tmp_row = array(); - foreach ($row as $key => $value) { - if ($value === '') { - $value = null; - } - $tmp_row[preg_replace('/^(?:.*\.)?([^.]+)$/', '\\1', $key)] = $value; - } - $row = $tmp_row; - break; - case (MDB2_PORTABILITY_RTRIM + MDB2_PORTABILITY_EMPTY_TO_NULL + MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES): - $tmp_row = array(); - foreach ($row as $key => $value) { - if ($value === '') { - $value = null; - } elseif (is_string($value)) { - $value = rtrim($value); - } - $tmp_row[preg_replace('/^(?:.*\.)?([^.]+)$/', '\\1', $key)] = $value; - } - $row = $tmp_row; - break; - } - } - - // }}} - // {{{ function &loadModule($module, $property = null, $phptype_specific = null) - - /** - * loads a module - * - * @param string name of the module that should be loaded - * (only used for error messages) - * @param string name of the property into which the class will be loaded - * @param bool if the class to load for the module is specific to the - * phptype - * - * @return object on success a reference to the given module is returned - * and on failure a PEAR error - * - * @access public - */ - function &loadModule($module, $property = null, $phptype_specific = null) - { - if (!$property) { - $property = strtolower($module); - } - - if (!isset($this->{$property})) { - $version = $phptype_specific; - if ($phptype_specific !== false) { - $version = true; - $class_name = 'MDB2_Driver_'.$module.'_'.$this->phptype; - $file_name = str_replace('_', DIRECTORY_SEPARATOR, $class_name).'.php'; - } - if ($phptype_specific === false - || (!MDB2::classExists($class_name) && !MDB2::fileExists($file_name)) - ) { - $version = false; - $class_name = 'MDB2_'.$module; - $file_name = str_replace('_', DIRECTORY_SEPARATOR, $class_name).'.php'; - } - - $err = MDB2::loadClass($class_name, $this->getOption('debug')); - if (PEAR::isError($err)) { - return $err; - } - - // load modul in a specific version - if ($version) { - if (method_exists($class_name, 'getClassName')) { - $class_name_new = call_user_func(array($class_name, 'getClassName'), $this->db_index); - if ($class_name != $class_name_new) { - $class_name = $class_name_new; - $err = MDB2::loadClass($class_name, $this->getOption('debug')); - if (PEAR::isError($err)) { - return $err; - } - } - } - } - - if (!MDB2::classExists($class_name)) { - $err =& $this->raiseError(MDB2_ERROR_LOADMODULE, null, null, - "unable to load module '$module' into property '$property'", __FUNCTION__); - return $err; - } - $this->{$property} =& new $class_name($this->db_index); - $this->modules[$module] =& $this->{$property}; - if ($version) { - // this will be used in the connect method to determine if the module - // needs to be loaded with a different version if the server - // version changed in between connects - $this->loaded_version_modules[] = $property; - } - } - - return $this->{$property}; - } - - // }}} - // {{{ function __call($method, $params) - - /** - * Calls a module method using the __call magic method - * - * @param string Method name. - * @param array Arguments. - * - * @return mixed Returned value. - */ - function __call($method, $params) - { - $module = null; - if (preg_match('/^([a-z]+)([A-Z])(.*)$/', $method, $match) - && isset($this->options['modules'][$match[1]]) - ) { - $module = $this->options['modules'][$match[1]]; - $method = strtolower($match[2]).$match[3]; - if (!isset($this->modules[$module]) || !is_object($this->modules[$module])) { - $result =& $this->loadModule($module); - if (PEAR::isError($result)) { - return $result; - } - } - } else { - foreach ($this->modules as $key => $foo) { - if (is_object($this->modules[$key]) - && method_exists($this->modules[$key], $method) - ) { - $module = $key; - break; - } - } - } - if (!is_null($module)) { - return call_user_func_array(array(&$this->modules[$module], $method), $params); - } - trigger_error(sprintf('Call to undefined function: %s::%s().', get_class($this), $method), E_USER_ERROR); - } - - // }}} - // {{{ function beginTransaction($savepoint = null) - - /** - * Start a transaction or set a savepoint. - * - * @param string name of a savepoint to set - * @return mixed MDB2_OK on success, a MDB2 error on failure - * - * @access public - */ - function beginTransaction($savepoint = null) - { - $this->debug('Starting transaction', __FUNCTION__, array('is_manip' => true, 'savepoint' => $savepoint)); - return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'transactions are not supported', __FUNCTION__); - } - - // }}} - // {{{ function commit($savepoint = null) - - /** - * Commit the database changes done during a transaction that is in - * progress or release a savepoint. This function may only be called when - * auto-committing is disabled, otherwise it will fail. Therefore, a new - * transaction is implicitly started after committing the pending changes. - * - * @param string name of a savepoint to release - * @return mixed MDB2_OK on success, a MDB2 error on failure - * - * @access public - */ - function commit($savepoint = null) - { - $this->debug('Committing transaction/savepoint', __FUNCTION__, array('is_manip' => true, 'savepoint' => $savepoint)); - return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'commiting transactions is not supported', __FUNCTION__); - } - - // }}} - // {{{ function rollback($savepoint = null) - - /** - * Cancel any database changes done during a transaction or since a specific - * savepoint that is in progress. This function may only be called when - * auto-committing is disabled, otherwise it will fail. Therefore, a new - * transaction is implicitly started after canceling the pending changes. - * - * @param string name of a savepoint to rollback to - * @return mixed MDB2_OK on success, a MDB2 error on failure - * - * @access public - */ - function rollback($savepoint = null) - { - $this->debug('Rolling back transaction/savepoint', __FUNCTION__, array('is_manip' => true, 'savepoint' => $savepoint)); - return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'rolling back transactions is not supported', __FUNCTION__); - } - - // }}} - // {{{ function inTransaction($ignore_nested = false) - - /** - * If a transaction is currently open. - * - * @param bool if the nested transaction count should be ignored - * @return int|bool - an integer with the nesting depth is returned if a - * nested transaction is open - * - true is returned for a normal open transaction - * - false is returned if no transaction is open - * - * @access public - */ - function inTransaction($ignore_nested = false) - { - if (!$ignore_nested && isset($this->nested_transaction_counter)) { - return $this->nested_transaction_counter; - } - return $this->in_transaction; - } - - // }}} - // {{{ function setTransactionIsolation($isolation) - - /** - * Set the transacton isolation level. - * - * @param string standard isolation level - * READ UNCOMMITTED (allows dirty reads) - * READ COMMITTED (prevents dirty reads) - * REPEATABLE READ (prevents nonrepeatable reads) - * SERIALIZABLE (prevents phantom reads) - * @param array some transaction options: - * 'wait' => 'WAIT' | 'NO WAIT' - * 'rw' => 'READ WRITE' | 'READ ONLY' - * @return mixed MDB2_OK on success, a MDB2 error on failure - * - * @access public - * @since 2.1.1 - */ - function setTransactionIsolation($isolation, $options = array()) - { - $this->debug('Setting transaction isolation level', __FUNCTION__, array('is_manip' => true)); - return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'isolation level setting is not supported', __FUNCTION__); - } - - // }}} - // {{{ function beginNestedTransaction($savepoint = false) - - /** - * Start a nested transaction. - * - * EXPERIMENTAL - * - * WARNING: this function is experimental and may change signature at - * any time until labelled as non-experimental - * - * @return mixed MDB2_OK on success/savepoint name, a MDB2 error on failure - * - * @access public - * @since 2.1.1 - */ - function beginNestedTransaction() - { - if ($this->in_transaction) { - ++$this->nested_transaction_counter; - $savepoint = sprintf($this->options['savepoint_format'], $this->nested_transaction_counter); - if ($this->supports('savepoints') && $savepoint) { - return $this->beginTransaction($savepoint); - } - return MDB2_OK; - } - $this->has_transaction_error = false; - $result = $this->beginTransaction(); - $this->nested_transaction_counter = 1; - return $result; - } - - // }}} - // {{{ function completeNestedTransaction($force_rollback = false, $release = false) - - /** - * Finish a nested transaction by rolling back if an error occured or - * committing otherwise. - * - * EXPERIMENTAL - * - * WARNING: this function is experimental and may change signature at - * any time until labelled as non-experimental - * - * @param bool if the transaction should be rolled back regardless - * even if no error was set within the nested transaction - * @return mixed MDB_OK on commit/counter decrementing, false on rollback - * and a MDB2 error on failure - * - * @access public - * @since 2.1.1 - */ - function completeNestedTransaction($force_rollback = false) - { - if ($this->nested_transaction_counter > 1) { - $savepoint = sprintf($this->options['savepoint_format'], $this->nested_transaction_counter); - if ($this->supports('savepoints') && $savepoint) { - if ($force_rollback || $this->has_transaction_error) { - $result = $this->rollback($savepoint); - if (!PEAR::isError($result)) { - $result = false; - $this->has_transaction_error = false; - } - } else { - $result = $this->commit($savepoint); - } - } else { - $result = MDB2_OK; - } - --$this->nested_transaction_counter; - return $result; - } - - $this->nested_transaction_counter = null; - $result = MDB2_OK; - - // transaction has not yet been rolled back - if ($this->in_transaction) { - if ($force_rollback || $this->has_transaction_error) { - $result = $this->rollback(); - if (!PEAR::isError($result)) { - $result = false; - } - } else { - $result = $this->commit(); - } - } - $this->has_transaction_error = false; - return $result; - } - - // }}} - // {{{ function failNestedTransaction($error = null, $immediately = false) - - /** - * Force setting nested transaction to failed. - * - * EXPERIMENTAL - * - * WARNING: this function is experimental and may change signature at - * any time until labelled as non-experimental - * - * @param mixed value to return in getNestededTransactionError() - * @param bool if the transaction should be rolled back immediately - * @return bool MDB2_OK - * - * @access public - * @since 2.1.1 - */ - function failNestedTransaction($error = null, $immediately = false) - { - if (is_null($error)) { - $error = $this->has_transaction_error ? $this->has_transaction_error : true; - } elseif (!$error) { - $error = true; - } - $this->has_transaction_error = $error; - if (!$immediately) { - return MDB2_OK; - } - return $this->rollback(); - } - - // }}} - // {{{ function getNestedTransactionError() - - /** - * The first error that occured since the transaction start. - * - * EXPERIMENTAL - * - * WARNING: this function is experimental and may change signature at - * any time until labelled as non-experimental - * - * @return MDB2_Error|bool MDB2 error object if an error occured or false. - * - * @access public - * @since 2.1.1 - */ - function getNestedTransactionError() - { - return $this->has_transaction_error; - } - - // }}} - // {{{ connect() - - /** - * Connect to the database - * - * @return true on success, MDB2 Error Object on failure - */ - function connect() - { - return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ setCharset($charset, $connection = null) - - /** - * Set the charset on the current connection - * - * @param string charset - * @param resource connection handle - * - * @return true on success, MDB2 Error Object on failure - */ - function setCharset($charset, $connection = null) - { - return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ function disconnect($force = true) - - /** - * Log out and disconnect from the database. - * - * @param bool if the disconnect should be forced even if the - * connection is opened persistently - * - * @return mixed true on success, false if not connected and error - * object on error - * - * @access public - */ - function disconnect($force = true) - { - $this->connection = 0; - $this->connected_dsn = array(); - $this->connected_database_name = ''; - $this->opened_persistent = null; - $this->connected_server_info = ''; - $this->in_transaction = null; - $this->nested_transaction_counter = null; - return MDB2_OK; - } - - // }}} - // {{{ function setDatabase($name) - - /** - * Select a different database - * - * @param string name of the database that should be selected - * - * @return string name of the database previously connected to - * - * @access public - */ - function setDatabase($name) - { - $previous_database_name = (isset($this->database_name)) ? $this->database_name : ''; - $this->database_name = $name; - $this->disconnect(false); - return $previous_database_name; - } - - // }}} - // {{{ function getDatabase() - - /** - * Get the current database - * - * @return string name of the database - * - * @access public - */ - function getDatabase() - { - return $this->database_name; - } - - // }}} - // {{{ function setDSN($dsn) - - /** - * set the DSN - * - * @param mixed DSN string or array - * - * @return MDB2_OK - * - * @access public - */ - function setDSN($dsn) - { - $dsn_default = $GLOBALS['_MDB2_dsninfo_default']; - $dsn = MDB2::parseDSN($dsn); - if (array_key_exists('database', $dsn)) { - $this->database_name = $dsn['database']; - unset($dsn['database']); - } - $this->dsn = array_merge($dsn_default, $dsn); - return $this->disconnect(false); - } - - // }}} - // {{{ function getDSN($type = 'string', $hidepw = false) - - /** - * return the DSN as a string - * - * @param string format to return ("array", "string") - * @param string string to hide the password with - * - * @return mixed DSN in the chosen type - * - * @access public - */ - function getDSN($type = 'string', $hidepw = false) - { - $dsn = array_merge($GLOBALS['_MDB2_dsninfo_default'], $this->dsn); - $dsn['phptype'] = $this->phptype; - $dsn['database'] = $this->database_name; - if ($hidepw) { - $dsn['password'] = $hidepw; - } - switch ($type) { - // expand to include all possible options - case 'string': - $dsn = $dsn['phptype']. - ($dsn['dbsyntax'] ? ('('.$dsn['dbsyntax'].')') : ''). - '://'.$dsn['username'].':'. - $dsn['password'].'@'.$dsn['hostspec']. - ($dsn['port'] ? (':'.$dsn['port']) : ''). - '/'.$dsn['database']; - break; - case 'array': - default: - break; - } - return $dsn; - } - - // }}} - // {{{ function &standaloneQuery($query, $types = null, $is_manip = false) - - /** - * execute a query as database administrator - * - * @param string the SQL query - * @param mixed array that contains the types of the columns in - * the result set - * @param bool if the query is a manipulation query - * - * @return mixed MDB2_OK on success, a MDB2 error on failure - * - * @access public - */ - function &standaloneQuery($query, $types = null, $is_manip = false) - { - $offset = $this->offset; - $limit = $this->limit; - $this->offset = $this->limit = 0; - $query = $this->_modifyQuery($query, $is_manip, $limit, $offset); - - $connection = $this->getConnection(); - if (PEAR::isError($connection)) { - return $connection; - } - - $result =& $this->_doQuery($query, $is_manip, $connection, false); - if (PEAR::isError($result)) { - return $result; - } - - if ($is_manip) { - $affected_rows = $this->_affectedRows($connection, $result); - return $affected_rows; - } - $result =& $this->_wrapResult($result, $types, true, false, $limit, $offset); - return $result; - } - - // }}} - // {{{ function _modifyQuery($query, $is_manip, $limit, $offset) - - /** - * Changes a query string for various DBMS specific reasons - * - * @param string query to modify - * @param bool if it is a DML query - * @param int limit the number of rows - * @param int start reading from given offset - * - * @return string modified query - * - * @access protected - */ - function _modifyQuery($query, $is_manip, $limit, $offset) - { - return $query; - } - - // }}} - // {{{ function &_doQuery($query, $is_manip = false, $connection = null, $database_name = null) - - /** - * Execute a query - * @param string query - * @param bool if the query is a manipulation query - * @param resource connection handle - * @param string database name - * - * @return result or error object - * - * @access protected - */ - function &_doQuery($query, $is_manip = false, $connection = null, $database_name = null) - { - $this->last_query = $query; - $result = $this->debug($query, 'query', array('is_manip' => $is_manip, 'when' => 'pre')); - if ($result) { - if (PEAR::isError($result)) { - return $result; - } - $query = $result; - } - $err =& $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - return $err; - } - - // }}} - // {{{ function _affectedRows($connection, $result = null) - - /** - * Returns the number of rows affected - * - * @param resource result handle - * @param resource connection handle - * - * @return mixed MDB2 Error Object or the number of rows affected - * - * @access private - */ - function _affectedRows($connection, $result = null) - { - return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ function &exec($query) - - /** - * Execute a manipulation query to the database and return the number of affected rows - * - * @param string the SQL query - * - * @return mixed number of affected rows on success, a MDB2 error on failure - * - * @access public - */ - function &exec($query) - { - $offset = $this->offset; - $limit = $this->limit; - $this->offset = $this->limit = 0; - $query = $this->_modifyQuery($query, true, $limit, $offset); - - $connection = $this->getConnection(); - if (PEAR::isError($connection)) { - return $connection; - } - - $result =& $this->_doQuery($query, true, $connection, $this->database_name); - if (PEAR::isError($result)) { - return $result; - } - - $affectedRows = $this->_affectedRows($connection, $result); - return $affectedRows; - } - - // }}} - // {{{ function &query($query, $types = null, $result_class = true, $result_wrap_class = false) - - /** - * Send a query to the database and return any results - * - * @param string the SQL query - * @param mixed array that contains the types of the columns in - * the result set - * @param mixed string which specifies which result class to use - * @param mixed string which specifies which class to wrap results in - * - * @return mixed an MDB2_Result handle on success, a MDB2 error on failure - * - * @access public - */ - function &query($query, $types = null, $result_class = true, $result_wrap_class = false) - { - $offset = $this->offset; - $limit = $this->limit; - $this->offset = $this->limit = 0; - $query = $this->_modifyQuery($query, false, $limit, $offset); - - $connection = $this->getConnection(); - if (PEAR::isError($connection)) { - return $connection; - } - - $result =& $this->_doQuery($query, false, $connection, $this->database_name); - if (PEAR::isError($result)) { - return $result; - } - - $result =& $this->_wrapResult($result, $types, $result_class, $result_wrap_class, $limit, $offset); - return $result; - } - - // }}} - // {{{ function &_wrapResult($result, $types = array(), $result_class = true, $result_wrap_class = false, $limit = null, $offset = null) - - /** - * wrap a result set into the correct class - * - * @param resource result handle - * @param mixed array that contains the types of the columns in - * the result set - * @param mixed string which specifies which result class to use - * @param mixed string which specifies which class to wrap results in - * @param string number of rows to select - * @param string first row to select - * - * @return mixed an MDB2_Result, a MDB2 error on failure - * - * @access protected - */ - function &_wrapResult($result, $types = array(), $result_class = true, - $result_wrap_class = false, $limit = null, $offset = null) - { - if ($types === true) { - if ($this->supports('result_introspection')) { - $this->loadModule('Reverse', null, true); - $tableInfo = $this->reverse->tableInfo($result); - if (PEAR::isError($tableInfo)) { - return $tableInfo; - } - $types = array(); - foreach ($tableInfo as $field) { - $types[] = $field['mdb2type']; - } - } else { - $types = null; - } - } - - if ($result_class === true) { - $result_class = $this->options['result_buffering'] - ? $this->options['buffered_result_class'] : $this->options['result_class']; - } - - if ($result_class) { - $class_name = sprintf($result_class, $this->phptype); - if (!MDB2::classExists($class_name)) { - $err =& $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null, - 'result class does not exist '.$class_name, __FUNCTION__); - return $err; - } - $result =& new $class_name($this, $result, $limit, $offset); - if (!MDB2::isResultCommon($result)) { - $err =& $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null, - 'result class is not extended from MDB2_Result_Common', __FUNCTION__); - return $err; - } - if (!empty($types)) { - $err = $result->setResultTypes($types); - if (PEAR::isError($err)) { - $result->free(); - return $err; - } - } - } - if ($result_wrap_class === true) { - $result_wrap_class = $this->options['result_wrap_class']; - } - if ($result_wrap_class) { - if (!MDB2::classExists($result_wrap_class)) { - $err =& $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null, - 'result wrap class does not exist '.$result_wrap_class, __FUNCTION__); - return $err; - } - $result =& new $result_wrap_class($result, $this->fetchmode); - } - return $result; - } - - // }}} - // {{{ function getServerVersion($native = false) - - /** - * return version information about the server - * - * @param bool determines if the raw version string should be returned - * - * @return mixed array with version information or row string - * - * @access public - */ - function getServerVersion($native = false) - { - return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ function setLimit($limit, $offset = null) - - /** - * set the range of the next query - * - * @param string number of rows to select - * @param string first row to select - * - * @return mixed MDB2_OK on success, a MDB2 error on failure - * - * @access public - */ - function setLimit($limit, $offset = null) - { - if (!$this->supports('limit_queries')) { - return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'limit is not supported by this driver', __FUNCTION__); - } - $limit = (int)$limit; - if ($limit < 0) { - return $this->raiseError(MDB2_ERROR_SYNTAX, null, null, - 'it was not specified a valid selected range row limit', __FUNCTION__); - } - $this->limit = $limit; - if (!is_null($offset)) { - $offset = (int)$offset; - if ($offset < 0) { - return $this->raiseError(MDB2_ERROR_SYNTAX, null, null, - 'it was not specified a valid first selected range row', __FUNCTION__); - } - $this->offset = $offset; - } - return MDB2_OK; - } - - // }}} - // {{{ function subSelect($query, $type = false) - - /** - * simple subselect emulation: leaves the query untouched for all RDBMS - * that support subselects - * - * @param string the SQL query for the subselect that may only - * return a column - * @param string determines type of the field - * - * @return string the query - * - * @access public - */ - function subSelect($query, $type = false) - { - if ($this->supports('sub_selects') === true) { - return $query; - } - - if (!$this->supports('sub_selects')) { - return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - $col = $this->queryCol($query, $type); - if (PEAR::isError($col)) { - return $col; - } - if (!is_array($col) || count($col) == 0) { - return 'NULL'; - } - if ($type) { - $this->loadModule('Datatype', null, true); - return $this->datatype->implodeArray($col, $type); - } - return implode(', ', $col); - } - - // }}} - // {{{ function replace($table, $fields) - - /** - * Execute a SQL REPLACE query. A REPLACE query is identical to a INSERT - * query, except that if there is already a row in the table with the same - * key field values, the REPLACE query just updates its values instead of - * inserting a new row. - * - * The REPLACE type of query does not make part of the SQL standards. Since - * practically only MySQL and SQLite implement it natively, this type of - * query isemulated through this method for other DBMS using standard types - * of queries inside a transaction to assure the atomicity of the operation. - * - * @param string name of the table on which the REPLACE query will - * be executed. - * @param array associative array that describes the fields and the - * values that will be inserted or updated in the specified table. The - * indexes of the array are the names of all the fields of the table. - * The values of the array are also associative arrays that describe - * the values and other properties of the table fields. - * - * Here follows a list of field properties that need to be specified: - * - * value - * Value to be assigned to the specified field. This value may be - * of specified in database independent type format as this - * function can perform the necessary datatype conversions. - * - * Default: this property is required unless the Null property is - * set to 1. - * - * type - * Name of the type of the field. Currently, all types MDB2 - * are supported except for clob and blob. - * - * Default: no type conversion - * - * null - * bool property that indicates that the value for this field - * should be set to null. - * - * The default value for fields missing in INSERT queries may be - * specified the definition of a table. Often, the default value - * is already null, but since the REPLACE may be emulated using - * an UPDATE query, make sure that all fields of the table are - * listed in this function argument array. - * - * Default: 0 - * - * key - * bool property that indicates that this field should be - * handled as a primary key or at least as part of the compound - * unique index of the table that will determine the row that will - * updated if it exists or inserted a new row otherwise. - * - * This function will fail if no key field is specified or if the - * value of a key field is set to null because fields that are - * part of unique index they may not be null. - * - * Default: 0 - * - * @return mixed MDB2_OK on success, a MDB2 error on failure - * - * @access public - */ - function replace($table, $fields) - { - if (!$this->supports('replace')) { - return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'replace query is not supported', __FUNCTION__); - } - $count = count($fields); - $condition = $values = array(); - for ($colnum = 0, reset($fields); $colnum < $count; next($fields), $colnum++) { - $name = key($fields); - if (isset($fields[$name]['null']) && $fields[$name]['null']) { - $value = 'NULL'; - } else { - $type = isset($fields[$name]['type']) ? $fields[$name]['type'] : null; - $value = $this->quote($fields[$name]['value'], $type); - } - $values[$name] = $value; - if (isset($fields[$name]['key']) && $fields[$name]['key']) { - if ($value === 'NULL') { - return $this->raiseError(MDB2_ERROR_CANNOT_REPLACE, null, null, - 'key value '.$name.' may not be NULL', __FUNCTION__); - } - $condition[] = $name . '=' . $value; - } - } - if (empty($condition)) { - return $this->raiseError(MDB2_ERROR_CANNOT_REPLACE, null, null, - 'not specified which fields are keys', __FUNCTION__); - } - - $result = null; - $in_transaction = $this->in_transaction; - if (!$in_transaction && PEAR::isError($result = $this->beginTransaction())) { - return $result; - } - - $connection = $this->getConnection(); - if (PEAR::isError($connection)) { - return $connection; - } - - $condition = ' WHERE '.implode(' AND ', $condition); - $query = "DELETE FROM $table$condition"; - $result =& $this->_doQuery($query, true, $connection); - if (!PEAR::isError($result)) { - $affected_rows = $this->_affectedRows($connection, $result); - $insert = implode(', ', array_keys($values)); - $values = implode(', ', $values); - $query = "INSERT INTO $table ($insert) VALUES ($values)"; - $result =& $this->_doQuery($query, true, $connection); - if (!PEAR::isError($result)) { - $affected_rows += $this->_affectedRows($connection, $result);; - } - } - - if (!$in_transaction) { - if (PEAR::isError($result)) { - $this->rollback(); - } else { - $result = $this->commit(); - } - } - - if (PEAR::isError($result)) { - return $result; - } - - return $affected_rows; - } - - // }}} - // {{{ function &prepare($query, $types = null, $result_types = null, $lobs = array()) - - /** - * Prepares a query for multiple execution with execute(). - * With some database backends, this is emulated. - * prepare() requires a generic query as string like - * 'INSERT INTO numbers VALUES(?,?)' or - * 'INSERT INTO numbers VALUES(:foo,:bar)'. - * The ? and :[a-zA-Z] and are placeholders which can be set using - * bindParam() and the query can be send off using the execute() method. - * - * @param string the query to prepare - * @param mixed array that contains the types of the placeholders - * @param mixed array that contains the types of the columns in - * the result set or MDB2_PREPARE_RESULT, if set to - * MDB2_PREPARE_MANIP the query is handled as a manipulation query - * @param mixed key (field) value (parameter) pair for all lob placeholders - * - * @return mixed resource handle for the prepared query on success, - * a MDB2 error on failure - * - * @access public - * @see bindParam, execute - */ - function &prepare($query, $types = null, $result_types = null, $lobs = array()) - { - $is_manip = ($result_types === MDB2_PREPARE_MANIP); - $offset = $this->offset; - $limit = $this->limit; - $this->offset = $this->limit = 0; - $result = $this->debug($query, __FUNCTION__, array('is_manip' => $is_manip, 'when' => 'pre')); - if ($result) { - if (PEAR::isError($result)) { - return $result; - } - $query = $result; - } - $placeholder_type_guess = $placeholder_type = null; - $question = '?'; - $colon = ':'; - $positions = array(); - $position = 0; - $ignores = $this->sql_comments; - $ignores[] = $this->string_quoting; - $ignores[] = $this->identifier_quoting; - while ($position < strlen($query)) { - $q_position = strpos($query, $question, $position); - $c_position = strpos($query, $colon, $position); - if ($q_position && $c_position) { - $p_position = min($q_position, $c_position); - } elseif ($q_position) { - $p_position = $q_position; - } elseif ($c_position) { - $p_position = $c_position; - } else { - break; - } - if (is_null($placeholder_type)) { - $placeholder_type_guess = $query[$p_position]; - } - - $new_pos = $this->_skipDelimitedStrings($query, $position, $p_position); - if (PEAR::isError($new_pos)) { - return $new_pos; - } - if ($new_pos != $position) { - $position = $new_pos; - continue; //evaluate again starting from the new position - } - - if ($query[$position] == $placeholder_type_guess) { - if (is_null($placeholder_type)) { - $placeholder_type = $query[$p_position]; - $question = $colon = $placeholder_type; - if (!empty($types) && is_array($types)) { - if ($placeholder_type == ':') { - if (is_int(key($types))) { - $types_tmp = $types; - $types = array(); - $count = -1; - } - } else { - $types = array_values($types); - } - } - } - if ($placeholder_type == ':') { - $parameter = preg_replace('/^.{'.($position+1).'}([a-z0-9_]+).*$/si', '\\1', $query); - if ($parameter === '') { - $err =& $this->raiseError(MDB2_ERROR_SYNTAX, null, null, - 'named parameter with an empty name', __FUNCTION__); - return $err; - } - $positions[$p_position] = $parameter; - $query = substr_replace($query, '?', $position, strlen($parameter)+1); - // use parameter name in type array - if (isset($count) && isset($types_tmp[++$count])) { - $types[$parameter] = $types_tmp[$count]; - } - } else { - $positions[$p_position] = count($positions); - } - $position = $p_position + 1; - } else { - $position = $p_position; - } - } - $class_name = 'MDB2_Statement_'.$this->phptype; - $statement = null; - $obj =& new $class_name($this, $statement, $positions, $query, $types, $result_types, $is_manip, $limit, $offset); - $this->debug($query, __FUNCTION__, array('is_manip' => $is_manip, 'when' => 'post', 'result' => $obj)); - return $obj; - } - - // }}} - // {{{ function _skipDelimitedStrings($query, $position, $p_position) - - /** - * Utility method, used by prepare() to avoid replacing placeholders within delimited strings. - * Check if the placeholder is contained within a delimited string. - * If so, skip it and advance the position, otherwise return the current position, - * which is valid - * - * @param string $query - * @param integer $position current string cursor position - * @param integer $p_position placeholder position - * - * @return mixed integer $new_position on success - * MDB2_Error on failure - * - * @access protected - */ - function _skipDelimitedStrings($query, $position, $p_position) - { - $ignores = $this->sql_comments; - $ignores[] = $this->string_quoting; - $ignores[] = $this->identifier_quoting; - - foreach ($ignores as $ignore) { - if (!empty($ignore['start'])) { - if (is_int($start_quote = strpos($query, $ignore['start'], $position)) && $start_quote < $p_position) { - $end_quote = $start_quote; - do { - if (!is_int($end_quote = strpos($query, $ignore['end'], $end_quote + 1))) { - if ($ignore['end'] === "\n") { - $end_quote = strlen($query) - 1; - } else { - $err =& $this->raiseError(MDB2_ERROR_SYNTAX, null, null, - 'query with an unterminated text string specified', __FUNCTION__); - return $err; - } - } - } while ($ignore['escape'] && $query[($end_quote - 1)] == $ignore['escape']); - $position = $end_quote + 1; - return $position; - } - } - } - return $position; - } - - // }}} - // {{{ function quote($value, $type = null, $quote = true) - - /** - * Convert a text value into a DBMS specific format that is suitable to - * compose query statements. - * - * @param string text string value that is intended to be converted. - * @param string type to which the value should be converted to - * @param bool quote - * @param bool escape wildcards - * - * @return string text string that represents the given argument value in - * a DBMS specific format. - * - * @access public - */ - function quote($value, $type = null, $quote = true, $escape_wildcards = false) - { - $result = $this->loadModule('Datatype', null, true); - if (PEAR::isError($result)) { - return $result; - } - - return $this->datatype->quote($value, $type, $quote, $escape_wildcards); - } - - // }}} - // {{{ function getDeclaration($type, $name, $field) - - /** - * Obtain DBMS specific SQL code portion needed to declare - * of the given type - * - * @param string type to which the value should be converted to - * @param string name the field to be declared. - * @param string definition of the field - * - * @return string DBMS specific SQL code portion that should be used to - * declare the specified field. - * - * @access public - */ - function getDeclaration($type, $name, $field) - { - $result = $this->loadModule('Datatype', null, true); - if (PEAR::isError($result)) { - return $result; - } - return $this->datatype->getDeclaration($type, $name, $field); - } - - // }}} - // {{{ function compareDefinition($current, $previous) - - /** - * Obtain an array of changes that may need to applied - * - * @param array new definition - * @param array old definition - * - * @return array containing all changes that will need to be applied - * - * @access public - */ - function compareDefinition($current, $previous) - { - $result = $this->loadModule('Datatype', null, true); - if (PEAR::isError($result)) { - return $result; - } - return $this->datatype->compareDefinition($current, $previous); - } - - // }}} - // {{{ function supports($feature) - - /** - * Tell whether a DB implementation or its backend extension - * supports a given feature. - * - * @param string name of the feature (see the MDB2 class doc) - * - * @return bool|string if this DB implementation supports a given feature - * false means no, true means native, - * 'emulated' means emulated - * - * @access public - */ - function supports($feature) - { - if (array_key_exists($feature, $this->supported)) { - return $this->supported[$feature]; - } - return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - "unknown support feature $feature", __FUNCTION__); - } - - // }}} - // {{{ function getSequenceName($sqn) - - /** - * adds sequence name formatting to a sequence name - * - * @param string name of the sequence - * - * @return string formatted sequence name - * - * @access public - */ - function getSequenceName($sqn) - { - return sprintf($this->options['seqname_format'], - preg_replace('/[^a-z0-9_\$.]/i', '_', $sqn)); - } - - // }}} - // {{{ function getIndexName($idx) - - /** - * adds index name formatting to a index name - * - * @param string name of the index - * - * @return string formatted index name - * - * @access public - */ - function getIndexName($idx) - { - return sprintf($this->options['idxname_format'], - preg_replace('/[^a-z0-9_\$]/i', '_', $idx)); - } - - // }}} - // {{{ function nextID($seq_name, $ondemand = true) - - /** - * Returns the next free id of a sequence - * - * @param string name of the sequence - * @param bool when true missing sequences are automatic created - * - * @return mixed MDB2 Error Object or id - * - * @access public - */ - function nextID($seq_name, $ondemand = true) - { - return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ function lastInsertID($table = null, $field = null) - - /** - * Returns the autoincrement ID if supported or $id or fetches the current - * ID in a sequence called: $table.(empty($field) ? '' : '_'.$field) - * - * @param string name of the table into which a new row was inserted - * @param string name of the field into which a new row was inserted - * - * @return mixed MDB2 Error Object or id - * - * @access public - */ - function lastInsertID($table = null, $field = null) - { - return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ function currID($seq_name) - - /** - * Returns the current id of a sequence - * - * @param string name of the sequence - * - * @return mixed MDB2 Error Object or id - * - * @access public - */ - function currID($seq_name) - { - $this->warnings[] = 'database does not support getting current - sequence value, the sequence value was incremented'; - return $this->nextID($seq_name); - } - - // }}} - // {{{ function queryOne($query, $type = null, $colnum = 0) - - /** - * Execute the specified query, fetch the value from the first column of - * the first row of the result set and then frees - * the result set. - * - * @param string the SELECT query statement to be executed. - * @param string optional argument that specifies the expected - * datatype of the result set field, so that an eventual conversion - * may be performed. The default datatype is text, meaning that no - * conversion is performed - * @param int the column number to fetch - * - * @return mixed MDB2_OK or field value on success, a MDB2 error on failure - * - * @access public - */ - function queryOne($query, $type = null, $colnum = 0) - { - $result = $this->query($query, $type); - if (!MDB2::isResultCommon($result)) { - return $result; - } - - $one = $result->fetchOne($colnum); - $result->free(); - return $one; - } - - // }}} - // {{{ function queryRow($query, $types = null, $fetchmode = MDB2_FETCHMODE_DEFAULT) - - /** - * Execute the specified query, fetch the values from the first - * row of the result set into an array and then frees - * the result set. - * - * @param string the SELECT query statement to be executed. - * @param array optional array argument that specifies a list of - * expected datatypes of the result set columns, so that the eventual - * conversions may be performed. The default list of datatypes is - * empty, meaning that no conversion is performed. - * @param int how the array data should be indexed - * - * @return mixed MDB2_OK or data array on success, a MDB2 error on failure - * - * @access public - */ - function queryRow($query, $types = null, $fetchmode = MDB2_FETCHMODE_DEFAULT) - { - $result = $this->query($query, $types); - if (!MDB2::isResultCommon($result)) { - return $result; - } - - $row = $result->fetchRow($fetchmode); - $result->free(); - return $row; - } - - // }}} - // {{{ function queryCol($query, $type = null, $colnum = 0) - - /** - * Execute the specified query, fetch the value from the first column of - * each row of the result set into an array and then frees the result set. - * - * @param string the SELECT query statement to be executed. - * @param string optional argument that specifies the expected - * datatype of the result set field, so that an eventual conversion - * may be performed. The default datatype is text, meaning that no - * conversion is performed - * @param int the row number to fetch - * - * @return mixed MDB2_OK or data array on success, a MDB2 error on failure - * - * @access public - */ - function queryCol($query, $type = null, $colnum = 0) - { - $result = $this->query($query, $type); - if (!MDB2::isResultCommon($result)) { - return $result; - } - - $col = $result->fetchCol($colnum); - $result->free(); - return $col; - } - - // }}} - // {{{ function queryAll($query, $types = null, $fetchmode = MDB2_FETCHMODE_DEFAULT, $rekey = false, $force_array = false, $group = false) - - /** - * Execute the specified query, fetch all the rows of the result set into - * a two dimensional array and then frees the result set. - * - * @param string the SELECT query statement to be executed. - * @param array optional array argument that specifies a list of - * expected datatypes of the result set columns, so that the eventual - * conversions may be performed. The default list of datatypes is - * empty, meaning that no conversion is performed. - * @param int how the array data should be indexed - * @param bool if set to true, the $all will have the first - * column as its first dimension - * @param bool 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 bool 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 mixed MDB2_OK or data array on success, a MDB2 error on failure - * - * @access public - */ - function queryAll($query, $types = null, $fetchmode = MDB2_FETCHMODE_DEFAULT, - $rekey = false, $force_array = false, $group = false) - { - $result = $this->query($query, $types); - if (!MDB2::isResultCommon($result)) { - return $result; - } - - $all = $result->fetchAll($fetchmode, $rekey, $force_array, $group); - $result->free(); - return $all; - } - - // }}} -} - -// }}} -// {{{ class MDB2_Result - -/** - * The dummy class that all user space result classes should extend from - * - * @package MDB2 - * @category Database - * @author Lukas Smith - */ -class MDB2_Result -{ -} - -// }}} -// {{{ class MDB2_Result_Common extends MDB2_Result - -/** - * The common result class for MDB2 result objects - * - * @package MDB2 - * @category Database - * @author Lukas Smith - */ -class MDB2_Result_Common extends MDB2_Result -{ - // {{{ Variables (Properties) - - var $db; - var $result; - var $rownum = -1; - var $types = array(); - var $values = array(); - var $offset; - var $offset_count = 0; - var $limit; - var $column_names; - - // }}} - // {{{ constructor: function __construct(&$db, &$result, $limit = 0, $offset = 0) - - /** - * Constructor - */ - function __construct(&$db, &$result, $limit = 0, $offset = 0) - { - $this->db =& $db; - $this->result =& $result; - $this->offset = $offset; - $this->limit = max(0, $limit - 1); - } - - // }}} - // {{{ function MDB2_Result_Common(&$db, &$result, $limit = 0, $offset = 0) - - /** - * PHP 4 Constructor - */ - function MDB2_Result_Common(&$db, &$result, $limit = 0, $offset = 0) - { - $this->__construct($db, $result, $limit, $offset); - } - - // }}} - // {{{ function setResultTypes($types) - - /** - * Define the list of types to be associated with the columns of a given - * result set. - * - * This function may be called before invoking fetchRow(), fetchOne(), - * fetchCol() and fetchAll() so that the necessary data type - * conversions are performed on the data to be retrieved by them. If this - * function is not called, the type of all result set columns is assumed - * to be text, thus leading to not perform any conversions. - * - * @param array variable that lists the - * data types to be expected in the result set columns. If this array - * contains less types than the number of columns that are returned - * in the result set, the remaining columns are assumed to be of the - * type text. Currently, the types clob and blob are not fully - * supported. - * - * @return mixed MDB2_OK on success, a MDB2 error on failure - * - * @access public - */ - function setResultTypes($types) - { - $load = $this->db->loadModule('Datatype', null, true); - if (PEAR::isError($load)) { - return $load; - } - $types = $this->db->datatype->checkResultTypes($types); - if (PEAR::isError($types)) { - return $types; - } - $this->types = $types; - return MDB2_OK; - } - - // }}} - // {{{ function seek($rownum = 0) - - /** - * Seek to a specific row in a result set - * - * @param int number of the row where the data can be found - * - * @return mixed MDB2_OK on success, a MDB2 error on failure - * - * @access public - */ - function seek($rownum = 0) - { - $target_rownum = $rownum - 1; - if ($this->rownum > $target_rownum) { - return $this->db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'seeking to previous rows not implemented', __FUNCTION__); - } - while ($this->rownum < $target_rownum) { - $this->fetchRow(); - } - return MDB2_OK; - } - - // }}} - // {{{ function &fetchRow($fetchmode = MDB2_FETCHMODE_DEFAULT, $rownum = null) - - /** - * Fetch and return a row of data - * - * @param int how the array data should be indexed - * @param int number of the row where the data can be found - * - * @return int data array on success, a MDB2 error on failure - * - * @access public - */ - function &fetchRow($fetchmode = MDB2_FETCHMODE_DEFAULT, $rownum = null) - { - $err =& $this->db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - return $err; - } - - // }}} - // {{{ function fetchOne($colnum = 0) - - /** - * fetch single column from the next row from a result set - * - * @param int the column number to fetch - * @param int number of the row where the data can be found - * - * @return string data on success, a MDB2 error on failure - * - * @access public - */ - function fetchOne($colnum = 0, $rownum = null) - { - $fetchmode = is_numeric($colnum) ? MDB2_FETCHMODE_ORDERED : MDB2_FETCHMODE_ASSOC; - $row = $this->fetchRow($fetchmode, $rownum); - if (!is_array($row) || PEAR::isError($row)) { - return $row; - } - if (!array_key_exists($colnum, $row)) { - return $this->db->raiseError(MDB2_ERROR_TRUNCATED, null, null, - 'column is not defined in the result set: '.$colnum, __FUNCTION__); - } - return $row[$colnum]; - } - - // }}} - // {{{ function fetchCol($colnum = 0) - - /** - * Fetch and return a column from the current row pointer position - * - * @param int the column number to fetch - * - * @return mixed data array on success, a MDB2 error on failure - * - * @access public - */ - function fetchCol($colnum = 0) - { - $column = array(); - $fetchmode = is_numeric($colnum) ? MDB2_FETCHMODE_ORDERED : MDB2_FETCHMODE_ASSOC; - $row = $this->fetchRow($fetchmode); - if (is_array($row)) { - if (!array_key_exists($colnum, $row)) { - return $this->db->raiseError(MDB2_ERROR_TRUNCATED, null, null, - 'column is not defined in the result set: '.$colnum, __FUNCTION__); - } - do { - $column[] = $row[$colnum]; - } while (is_array($row = $this->fetchRow($fetchmode))); - } - if (PEAR::isError($row)) { - return $row; - } - return $column; - } - - // }}} - // {{{ function fetchAll($fetchmode = MDB2_FETCHMODE_DEFAULT, $rekey = false, $force_array = false, $group = false) - - /** - * Fetch and return all rows from the current row pointer position - * - * @param int $fetchmode the fetch mode to use: - * + MDB2_FETCHMODE_ORDERED - * + MDB2_FETCHMODE_ASSOC - * + MDB2_FETCHMODE_ORDERED | MDB2_FETCHMODE_FLIPPED - * + MDB2_FETCHMODE_ASSOC | MDB2_FETCHMODE_FLIPPED - * @param bool if set to true, the $all will have the first - * column as its first dimension - * @param bool 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 bool 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 mixed data array on success, a MDB2 error on failure - * - * @access public - * @see getAssoc() - */ - function fetchAll($fetchmode = MDB2_FETCHMODE_DEFAULT, $rekey = false, - $force_array = false, $group = false) - { - $all = array(); - $row = $this->fetchRow($fetchmode); - if (PEAR::isError($row)) { - return $row; - } elseif (!$row) { - return $all; - } - - $shift_array = $rekey ? false : null; - if (!is_null($shift_array)) { - if (is_object($row)) { - $colnum = count(get_object_vars($row)); - } else { - $colnum = count($row); - } - if ($colnum < 2) { - return $this->db->raiseError(MDB2_ERROR_TRUNCATED, null, null, - 'rekey feature requires atleast 2 column', __FUNCTION__); - } - $shift_array = (!$force_array && $colnum == 2); - } - - if ($rekey) { - do { - if (is_object($row)) { - $arr = get_object_vars($row); - $key = reset($arr); - unset($row->{$key}); - } else { - if ($fetchmode & MDB2_FETCHMODE_ASSOC) { - $key = reset($row); - unset($row[key($row)]); - } else { - $key = array_shift($row); - } - if ($shift_array) { - $row = array_shift($row); - } - } - if ($group) { - $all[$key][] = $row; - } else { - $all[$key] = $row; - } - } while (($row = $this->fetchRow($fetchmode))); - } elseif ($fetchmode & MDB2_FETCHMODE_FLIPPED) { - do { - foreach ($row as $key => $val) { - $all[$key][] = $val; - } - } while (($row = $this->fetchRow($fetchmode))); - } else { - do { - $all[] = $row; - } while (($row = $this->fetchRow($fetchmode))); - } - - return $all; - } - - // }}} - // {{{ function rowCount() - /** - * Returns the actual row number that was last fetched (count from 0) - * @return int - * - * @access public - */ - function rowCount() - { - return $this->rownum + 1; - } - - // }}} - // {{{ function numRows() - - /** - * Returns the number of rows in a result object - * - * @return mixed MDB2 Error Object or the number of rows - * - * @access public - */ - function numRows() - { - return $this->db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ function nextResult() - - /** - * Move the internal result pointer to the next available result - * - * @return true on success, false if there is no more result set or an error object on failure - * - * @access public - */ - function nextResult() - { - return $this->db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ function getColumnNames() - - /** - * Retrieve the names of columns returned by the DBMS in a query result or - * from the cache. - * - * @param bool If set to true the values are the column names, - * otherwise the names of the columns are the keys. - * @return mixed Array variable that holds the names of columns or an - * MDB2 error on failure. - * Some DBMS may not return any columns when the result set - * does not contain any rows. - * - * @access public - */ - function getColumnNames($flip = false) - { - if (!isset($this->column_names)) { - $result = $this->_getColumnNames(); - if (PEAR::isError($result)) { - return $result; - } - $this->column_names = $result; - } - if ($flip) { - return array_flip($this->column_names); - } - return $this->column_names; - } - - // }}} - // {{{ function _getColumnNames() - - /** - * Retrieve the names of columns returned by the DBMS in a query result. - * - * @return mixed Array variable that holds the names of columns as keys - * or an MDB2 error on failure. - * Some DBMS may not return any columns when the result set - * does not contain any rows. - * - * @access private - */ - function _getColumnNames() - { - return $this->db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ function numCols() - - /** - * Count the number of columns returned by the DBMS in a query result. - * - * @return mixed integer value with the number of columns, a MDB2 error - * on failure - * - * @access public - */ - function numCols() - { - return $this->db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, - 'method not implemented', __FUNCTION__); - } - - // }}} - // {{{ function getResource() - - /** - * return the resource associated with the result object - * - * @return resource - * - * @access public - */ - function getResource() - { - return $this->result; - } - - // }}} - // {{{ function bindColumn($column, &$value, $type = null) - - /** - * Set bind variable to a column. - * - * @param int column number or name - * @param mixed variable reference - * @param string specifies the type of the field - * - * @return mixed MDB2_OK on success, a MDB2 error on failure - * - * @access public - */ - function bindColumn($column, &$value, $type = null) - { - if (!is_numeric($column)) { - $column_names = $this->getColumnNames(); - if ($this->db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { - if ($this->db->options['field_case'] == CASE_LOWER) { - $column = strtolower($column); - } else { - $column = strtoupper($column); - } - } - $column = $column_names[$column]; - } - $this->values[$column] =& $value; - if (!is_null($type)) { - $this->types[$column] = $type; - } - return MDB2_OK; - } - - // }}} - // {{{ function _assignBindColumns($row) - - /** - * Bind a variable to a value in the result row. - * - * @param array row data - * - * @return mixed MDB2_OK on success, a MDB2 error on failure - * - * @access private - */ - function _assignBindColumns($row) - { - $row = array_values($row); - foreach ($row as $column => $value) { - if (array_key_exists($column, $this->values)) { - $this->values[$column] = $value; - } - } - return MDB2_OK; - } - - // }}} - // {{{ function free() - - /** - * Free the internal resources associated with result. - * - * @return bool true on success, false if result is invalid - * - * @access public - */ - function free() - { - $this->result = false; - return MDB2_OK; - } - - // }}} -} - -// }}} -// {{{ class MDB2_Row - -/** - * The simple class that accepts row data as an array - * - * @package MDB2 - * @category Database - * @author Lukas Smith - */ -class MDB2_Row -{ - // {{{ constructor: function __construct(&$row) - - /** - * constructor - * - * @param resource row data as array - */ - function __construct(&$row) - { - foreach ($row as $key => $value) { - $this->$key = &$row[$key]; - } - } - - // }}} - // {{{ function MDB2_Row(&$row) - - /** - * PHP 4 Constructor - * - * @param resource row data as array - */ - function MDB2_Row(&$row) - { - $this->__construct($row); - } - - // }}} -} - -// }}} -// {{{ class MDB2_Statement_Common - -/** - * The common statement class for MDB2 statement objects - * - * @package MDB2 - * @category Database - * @author Lukas Smith - */ -class MDB2_Statement_Common -{ - // {{{ Variables (Properties) - - var $db; - var $statement; - var $query; - var $result_types; - var $types; - var $values = array(); - var $limit; - var $offset; - var $is_manip; - - // }}} - // {{{ constructor: function __construct(&$db, &$statement, $positions, $query, $types, $result_types, $is_manip = false, $limit = null, $offset = null) - - /** - * Constructor - */ - function __construct(&$db, &$statement, $positions, $query, $types, $result_types, $is_manip = false, $limit = null, $offset = null) - { - $this->db =& $db; - $this->statement =& $statement; - $this->positions = $positions; - $this->query = $query; - $this->types = (array)$types; - $this->result_types = (array)$result_types; - $this->limit = $limit; - $this->is_manip = $is_manip; - $this->offset = $offset; - } - - // }}} - // {{{ function MDB2_Statement_Common(&$db, &$statement, $positions, $query, $types, $result_types, $is_manip = false, $limit = null, $offset = null) - - /** - * PHP 4 Constructor - */ - function MDB2_Statement_Common(&$db, &$statement, $positions, $query, $types, $result_types, $is_manip = false, $limit = null, $offset = null) - { - $this->__construct($db, $statement, $positions, $query, $types, $result_types, $is_manip, $limit, $offset); - } - - // }}} - // {{{ function bindValue($parameter, &$value, $type = null) - - /** - * Set the value of a parameter of a prepared query. - * - * @param int the order number of the parameter in the query - * statement. The order number of the first parameter is 1. - * @param mixed value that is meant to be assigned to specified - * parameter. The type of the value depends on the $type argument. - * @param string specifies the type of the field - * - * @return mixed MDB2_OK on success, a MDB2 error on failure - * - * @access public - */ - function bindValue($parameter, $value, $type = null) - { - if (!is_numeric($parameter)) { - $parameter = preg_replace('/^:(.*)$/', '\\1', $parameter); - } - if (!in_array($parameter, $this->positions)) { - return $this->db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, - 'Unable to bind to missing placeholder: '.$parameter, __FUNCTION__); - } - $this->values[$parameter] = $value; - if (!is_null($type)) { - $this->types[$parameter] = $type; - } - return MDB2_OK; - } - - // }}} - // {{{ function bindValueArray($values, $types = null) - - /** - * Set the values of multiple a parameter of a prepared query in bulk. - * - * @param array specifies all necessary information - * for bindValue() the array elements must use keys corresponding to - * the number of the position of the parameter. - * @param array specifies the types of the fields - * - * @return mixed MDB2_OK on success, a MDB2 error on failure - * - * @access public - * @see bindParam() - */ - function bindValueArray($values, $types = null) - { - $types = is_array($types) ? array_values($types) : array_fill(0, count($values), null); - $parameters = array_keys($values); - foreach ($parameters as $key => $parameter) { - $err = $this->bindValue($parameter, $values[$parameter], $types[$key]); - if (PEAR::isError($err)) { - return $err; - } - } - return MDB2_OK; - } - - // }}} - // {{{ function bindParam($parameter, &$value, $type = null) - - /** - * Bind a variable to a parameter of a prepared query. - * - * @param int the order number of the parameter in the query - * statement. The order number of the first parameter is 1. - * @param mixed variable that is meant to be bound to specified - * parameter. The type of the value depends on the $type argument. - * @param string specifies the type of the field - * - * @return mixed MDB2_OK on success, a MDB2 error on failure - * - * @access public - */ - function bindParam($parameter, &$value, $type = null) - { - if (!is_numeric($parameter)) { - $parameter = preg_replace('/^:(.*)$/', '\\1', $parameter); - } - if (!in_array($parameter, $this->positions)) { - return $this->db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, - 'Unable to bind to missing placeholder: '.$parameter, __FUNCTION__); - } - $this->values[$parameter] =& $value; - if (!is_null($type)) { - $this->types[$parameter] = $type; - } - return MDB2_OK; - } - - // }}} - // {{{ function bindParamArray(&$values, $types = null) - - /** - * Bind the variables of multiple a parameter of a prepared query in bulk. - * - * @param array specifies all necessary information - * for bindParam() the array elements must use keys corresponding to - * the number of the position of the parameter. - * @param array specifies the types of the fields - * - * @return mixed MDB2_OK on success, a MDB2 error on failure - * - * @access public - * @see bindParam() - */ - function bindParamArray(&$values, $types = null) - { - $types = is_array($types) ? array_values($types) : array_fill(0, count($values), null); - $parameters = array_keys($values); - foreach ($parameters as $key => $parameter) { - $err = $this->bindParam($parameter, $values[$parameter], $types[$key]); - if (PEAR::isError($err)) { - return $err; - } - } - return MDB2_OK; - } - - // }}} - // {{{ function &execute($values = null, $result_class = true, $result_wrap_class = false) - - /** - * Execute a prepared query statement. - * - * @param array specifies all necessary information - * for bindParam() the array elements must use keys corresponding to - * the number of the position of the parameter. - * @param mixed specifies which result class to use - * @param mixed specifies which class to wrap results in - * - * @return mixed a result handle or MDB2_OK on success, a MDB2 error on failure - * - * @access public - */ - function &execute($values = null, $result_class = true, $result_wrap_class = false) - { - if (is_null($this->positions)) { - return $this->db->raiseError(MDB2_ERROR, null, null, - 'Prepared statement has already been freed', __FUNCTION__); - } - - $values = (array)$values; - if (!empty($values)) { - $err = $this->bindValueArray($values); - if (PEAR::isError($err)) { - return $this->db->raiseError(MDB2_ERROR, null, null, - 'Binding Values failed with message: ' . $err->getMessage(), __FUNCTION__); - } - } - $result =& $this->_execute($result_class, $result_wrap_class); - return $result; - } - - // }}} - // {{{ function &_execute($result_class = true, $result_wrap_class = false) - - /** - * Execute a prepared query statement helper method. - * - * @param mixed specifies which result class to use - * @param mixed specifies which class to wrap results in - * - * @return mixed MDB2_Result or integer on success, a MDB2 error on failure - * - * @access private - */ - function &_execute($result_class = true, $result_wrap_class = false) - { - $this->last_query = $this->query; - $query = ''; - $last_position = 0; - foreach ($this->positions as $current_position => $parameter) { - if (!array_key_exists($parameter, $this->values)) { - return $this->db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, - 'Unable to bind to missing placeholder: '.$parameter, __FUNCTION__); - } - $value = $this->values[$parameter]; - $query.= substr($this->query, $last_position, $current_position - $last_position); - if (!isset($value)) { - $value_quoted = 'NULL'; - } else { - $type = !empty($this->types[$parameter]) ? $this->types[$parameter] : null; - $value_quoted = $this->db->quote($value, $type); - if (PEAR::isError($value_quoted)) { - return $value_quoted; - } - } - $query.= $value_quoted; - $last_position = $current_position + 1; - } - $query.= substr($this->query, $last_position); - - $this->db->offset = $this->offset; - $this->db->limit = $this->limit; - if ($this->is_manip) { - $result = $this->db->exec($query); - } else { - $result =& $this->db->query($query, $this->result_types, $result_class, $result_wrap_class); - } - return $result; - } - - // }}} - // {{{ function free() - - /** - * Release resources allocated for the specified prepared query. - * - * @return mixed MDB2_OK on success, a MDB2 error on failure - * - * @access public - */ - function free() - { - if (is_null($this->positions)) { - return $this->db->raiseError(MDB2_ERROR, null, null, - 'Prepared statement has already been freed', __FUNCTION__); - } - - $this->statement = null; - $this->positions = null; - $this->query = null; - $this->types = null; - $this->result_types = null; - $this->limit = null; - $this->is_manip = null; - $this->offset = null; - $this->values = null; - - return MDB2_OK; - } - - // }}} -} - -// }}} -// {{{ class MDB2_Module_Common - -/** - * The common modules class for MDB2 module objects - * - * @package MDB2 - * @category Database - * @author Lukas Smith - */ -class MDB2_Module_Common -{ - // {{{ Variables (Properties) - - /** - * contains the key to the global MDB2 instance array of the associated - * MDB2 instance - * - * @var int - * @access protected - */ - var $db_index; - - // }}} - // {{{ constructor: function __construct($db_index) - - /** - * Constructor - */ - function __construct($db_index) - { - $this->db_index = $db_index; - } - - // }}} - // {{{ function MDB2_Module_Common($db_index) - - /** - * PHP 4 Constructor - */ - function MDB2_Module_Common($db_index) - { - $this->__construct($db_index); - } - - // }}} - // {{{ function &getDBInstance() - - /** - * Get the instance of MDB2 associated with the module instance - * - * @return object MDB2 instance or a MDB2 error on failure - * - * @access public - */ - function &getDBInstance() - { - if (isset($GLOBALS['_MDB2_databases'][$this->db_index])) { - $result =& $GLOBALS['_MDB2_databases'][$this->db_index]; - } else { - $result =& MDB2::raiseError(MDB2_ERROR_NOT_FOUND, null, null, - 'could not find MDB2 instance'); - } - return $result; - } - - // }}} -} - -// }}} -// {{{ function MDB2_closeOpenTransactions() - -/** - * Close any open transactions form persistent connections - * - * @return void - * - * @access public - */ - -function MDB2_closeOpenTransactions() -{ - reset($GLOBALS['_MDB2_databases']); - while (next($GLOBALS['_MDB2_databases'])) { - $key = key($GLOBALS['_MDB2_databases']); - if ($GLOBALS['_MDB2_databases'][$key]->opened_persistent - && $GLOBALS['_MDB2_databases'][$key]->in_transaction - ) { - $GLOBALS['_MDB2_databases'][$key]->rollback(); - } - } -} - -// }}} -// {{{ function MDB2_defaultDebugOutput(&$db, $scope, $message, $is_manip = null) - -/** - * default debug output handler - * - * @param object reference to an MDB2 database object - * @param string usually the method name that triggered the debug call: - * for example 'query', 'prepare', 'execute', 'parameters', - * 'beginTransaction', 'commit', 'rollback' - * @param string message that should be appended to the debug variable - * @param array contains context information about the debug() call - * common keys are: is_manip, time, result etc. - * - * @return void|string optionally return a modified message, this allows - * rewriting a query before being issued or prepared - * - * @access public - */ -function MDB2_defaultDebugOutput(&$db, $scope, $message, $context = array()) -{ - $db->debug_output.= $scope.'('.$db->db_index.'): '; - $db->debug_output.= $message.$db->getOption('log_line_break'); - return $message; -} - -// }}} -?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/tests/basic.phpt /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/tests/basic.phpt --- php-mdb2-2.4.1/MDB2-2.4.1/tests/basic.phpt 2007-05-03 19:58:15.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.4.1/tests/basic.phpt 1970-01-01 01:00:00.000000000 +0100 @@ -1,26 +0,0 @@ ---TEST-- -MDB2: Basic connectivity ---FILE-- -connect(); - -if (PEAR::isError($e)) { - print $e->getMessage() . "\n"; -} - -die(); - - -?> -echo 'Success!'; - ---EXPECT-- -Success! diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/tests/clitest.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/tests/clitest.php --- php-mdb2-2.4.1/MDB2-2.4.1/tests/clitest.php 2007-05-03 19:58:15.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.4.1/tests/clitest.php 1970-01-01 01:00:00.000000000 +0100 @@ -1,134 +0,0 @@ - | -// +----------------------------------------------------------------------+ -// -// $Id: clitest.php,v 1.15 2006/10/20 16:36:32 lsmith Exp $ - -/* - This is a small test suite for MDB2 using PHPUnit - - This is the command line version and should be used like so; - - php -q clitest.php - - This will run through all tests in all testcases (as defined in - test_setup.php). To run individual tests add their names to the command - line and all testcases will be searched for matching test names, e.g. - - php -q clitest.php teststorage testreplace -*/ - -require_once 'test_setup.php'; -require_once 'PHPUnit.php'; -require_once 'testUtils.php'; -require_once 'MDB2.php'; -require_once 'Console_TestListener.php'; - -MDB2::loadFile('Date'); - -foreach ($testcases as $testcase) { - include_once $testcase.'.php'; -} - -$database = 'driver_test'; - -$inputMethods = $argv; - -if ($argc > 1) { - array_shift($inputMethods); - $exclude = false; - if ($inputMethods[0] == '-exclude') { - array_shift($inputMethods); - $exclude = true; - } - foreach ($testcases as $testcase) { - $possibleMethods = getTests($testcase); - if ($exclude) { - $intersect = array_diff($possibleMethods, $inputMethods); - } else { - $intersect = array_intersect($possibleMethods, $inputMethods); - } - if (count($intersect) > 0) { - $testmethods[$testcase] = array_flip($intersect); - } - } -} - -$database = 'driver_test'; - -if (!isset($testmethods) || !is_array($testmethods)) { - foreach ($testcases as $testcase) { - $testmethods[$testcase] = array_flip(getTests($testcase)); - } -} - -foreach ($dbarray as $db) { - $dsn = $db['dsn']; - $options = !empty($db['options']) ? $db['options'] : array(); - $GLOBALS['_show_silenced'] = !empty($options['debug']) ? $options['debug'] : false; - - $display_dsn = $dsn['phptype'] . "://" . $dsn['username'] . ":XXX@" . $dsn['hostspec'] . "/" . $database; - echo "=== Start test of $display_dsn on ".PHP_VERSION." ===\n"; - - $suite = new PHPUnit_TestSuite(); - - foreach ($testcases as $testcase) { - if (is_array($testmethods[$testcase])) { - $methods = array_keys($testmethods[$testcase]); - foreach ($methods as $method) { - $suite->addTest(new $testcase($method)); - } - } - } - - $result = new PHPUnit_TestResult; - $result->addListener(new Console_TestListener); - - $suite->run($result); - $count = $result->runCount(); - $failed = $result->failureCount(); - - echo "=== Summary: $failed failed assertions in $count tests ===\n\n"; - echo "=== End test of $display_dsn ===\n\n"; -} - -?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/tests/config.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/tests/config.php --- php-mdb2-2.4.1/MDB2-2.4.1/tests/config.php 2007-05-03 19:58:15.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.4.1/tests/config.php 1970-01-01 01:00:00.000000000 +0100 @@ -1,19 +0,0 @@ - diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/tests/Console_TestListener.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/tests/Console_TestListener.php --- php-mdb2-2.4.1/MDB2-2.4.1/tests/Console_TestListener.php 2007-05-03 19:58:15.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.4.1/tests/Console_TestListener.php 1970-01-01 01:00:00.000000000 +0100 @@ -1,32 +0,0 @@ -_errors += 1; - echo(" Error $this->_errors in ".$test->getName()." : $t\n"); - } - - function addFailure(&$test, &$t) { - $this->_fails += 1; - if ($this->_fails == 1) { - echo("\n"); - } - echo("Failure $this->_fails : $t\n"); - } - - function endTest(&$test) { - if ($this->_fails == 0 && $this->_errors == 0) { - echo(' Test passed'); - } else { - echo("There were $this->_fails failures for ".$test->getName()."\n"); - echo("There were $this->_errors errors for ".$test->getName()."\n"); - } - echo("\n"); - } - - function startTest(&$test) { - $this->_fails = 0; - $this->_errors = 0; - echo(get_class($test).' : Starting '.$test->getName().' ...'); - } -} -?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/tests/driver_test.schema.xml /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/tests/driver_test.schema.xml --- php-mdb2-2.4.1/MDB2-2.4.1/tests/driver_test.schema.xml 2007-05-03 19:58:15.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.4.1/tests/driver_test.schema.xml 1970-01-01 01:00:00.000000000 +0100 @@ -1,49 +0,0 @@ - - - - - - name - create - - - - users - - user_name text 12 false - user_password text 8 true - subscribed boolean - user_id integer 0 1 - quota decimal - weight float - access_date date - access_time time - approved timestamp - - users_id_index - 1 - user_id - - -
    - - - files - - id integer 0 1 - document clob - picture blob - - lob_id_index - 1 - id - - -
    - -
    diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/tests/HTML_TestListener.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/tests/HTML_TestListener.php --- php-mdb2-2.4.1/MDB2-2.4.1/tests/HTML_TestListener.php 2007-05-03 19:58:15.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.4.1/tests/HTML_TestListener.php 1970-01-01 01:00:00.000000000 +0100 @@ -1,34 +0,0 @@ -_errors += 1; - echo("
    Error $this->_errors in ".$test->getName()." : $t
    "); - } - - function addFailure(&$test, &$t) { - $this->_fails += 1; - if ($this->_fails == 1) { - echo("\n
    "); - } - echo("Failure $this->_fails : $t
    \n"); - } - - function endTest(&$test) { - if ($this->_fails == 0 && $this->_errors == 0) { - echo(' Test passed'); - } else { - echo("There were $this->_fails failures for ".$test->getName()."
    \n"); - echo("There were $this->_errors errors for ".$test->getName()."
    \n"); - } - echo(''); - } - - function startTest(&$test) { - $this->_fails = 0; - $this->_errors = 0; - echo("\n
    ".get_class($test).' : Starting '.$test->getName().' ...'); - } -} - -?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/tests/import.schema.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/tests/import.schema.php --- php-mdb2-2.4.1/MDB2-2.4.1/tests/import.schema.php 2007-05-03 19:58:15.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.4.1/tests/import.schema.php 1970-01-01 01:00:00.000000000 +0100 @@ -1,45 +0,0 @@ - 'mysql', - 'username' => 'username', - 'password' => 'password', - 'hostspec' => 'host', -); -$db_options = array(); - - -$file = dirname(__FILE__).DIRECTORY_SEPARATOR.'driver_test.schema.xml'; -$variables = array( - 'name' => 'driver_test', - 'create' => true, -); - -$options = array( - 'log_line_break' => '
    ', - 'idxname_format' => '%s', - 'debug' => true, - 'quote_identifier' => true, - 'force_defaults' => false, - 'portability' => false -); -$options = array_merge($options, $db_options); - -$schema =& MDB2_Schema::factory($dsn, $options); -if (PEAR::isError($schema)) { - echo $schema->getMessage() . ' ' . $schema->getUserInfo(); - exit; -} - -$definition = $schema->parseDatabaseDefinitionFile($file, $variables, true, true); -if (PEAR::isError($definition)) { - echo $definition->getMessage() . ' - ' . $definition->getUserInfo(); -} else { - $operation = $schema->createDatabase($definition); - if (PEAR::isError($operation)) { - echo $operation->getMessage() . ' ' . $operation->getUserInfo(); - } -} -?> -DONE! \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/tests/MDB2_api_testcase.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/tests/MDB2_api_testcase.php --- php-mdb2-2.4.1/MDB2-2.4.1/tests/MDB2_api_testcase.php 2007-05-03 19:58:15.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.4.1/tests/MDB2_api_testcase.php 1970-01-01 01:00:00.000000000 +0100 @@ -1,297 +0,0 @@ - | -// +----------------------------------------------------------------------+ -// -// $Id: MDB2_api_testcase.php,v 1.22 2007/04/25 09:11:35 quipo Exp $ - -require_once 'MDB2_testcase.php'; - -class MDB2_Api_TestCase extends MDB2_TestCase { - var $clear_tables = false; - - function testParseDSN() { - $expected = array ( - 'phptype' => 'phptype', - 'dbsyntax' => 'phptype', - 'username' => 'username', - 'password' => 'password', - 'protocol' => 'protocol', - 'hostspec' => false, - 'port' => '110', - 'socket' => false, - 'database' => '/usr/db_file.db', - 'mode' => false, - ); - $original = 'phptype://username:password@protocol+hostspec:110//usr/db_file.db?mode=0644'; - $this->assertEquals($expected, MDB2::parseDSN($original)); - - // --------------------------------------------------------------------- - - $original = 'phptype(dbsyntax)://username:password@hostspec/database_name'; - $expected = array ( - 'phptype' => 'phptype', - 'dbsyntax' => 'dbsyntax', - 'username' => 'username', - 'password' => 'password', - 'protocol' => 'tcp', - 'hostspec' => 'hostspec', - 'port' => false, - 'socket' => false, - 'database' => 'database_name', - 'mode' => false, - ); - $this->assertEquals($expected, MDB2::parseDSN($original)); - - // --------------------------------------------------------------------- - - $original = 'phptype://username:password@hostspec/database_name'; - $expected['dbsyntax'] = 'phptype'; - $this->assertEquals($expected, MDB2::parseDSN($original)); - - // --------------------------------------------------------------------- - - $original = 'phptype://username:password@hostspec'; - $expected['database'] = false; - $this->assertEquals($expected, MDB2::parseDSN($original)); - - // --------------------------------------------------------------------- - - $original = 'phptype://username@hostspec'; - $expected['password'] = false; - $this->assertEquals($expected, MDB2::parseDSN($original)); - - // --------------------------------------------------------------------- - - $original = 'phptype://hostspec/database'; - $expected['username'] = false; - $expected['database'] = 'database'; - $this->assertEquals($expected, MDB2::parseDSN($original)); - - // --------------------------------------------------------------------- - - $original = 'phptype(dbsyntax)'; - $expected['database'] = false; - $expected['hostspec'] = false; - $expected['protocol'] = false; - $expected['dbsyntax'] = 'dbsyntax'; - $this->assertEquals($expected, MDB2::parseDSN($original)); - - // --------------------------------------------------------------------- - - //oracle's "Easy Connect" syntax (Oracle 10g, @see Bug #4854) - $original = 'oci8://scott:tiger@//localhost/XE'; - $expected = array ( - 'phptype' => 'oci8', - 'dbsyntax' => 'oci8', - 'username' => 'scott', - 'password' => 'tiger', - 'protocol' => 'tcp', - 'hostspec' => '//localhost/XE', - 'port' => false, - 'socket' => false, - 'database' => false, - 'mode' => false, - ); - $this->assertEquals($expected, MDB2::parseDSN($original)); - - // --------------------------------------------------------------------- - - //ibase dbname+path on windows - $original = 'ibase://user:pwd@localhost/C:\\PATH_TO_DB\\TEST.FDB'; - $expected = array ( - 'phptype' => 'ibase', - 'dbsyntax' => 'ibase', - 'username' => 'user', - 'password' => 'pwd', - 'protocol' => 'tcp', - 'hostspec' => 'localhost', - 'port' => false, - 'socket' => false, - 'database' => 'C:\\PATH_TO_DB\\TEST.FDB', - 'mode' => false, - ); - $this->assertEquals($expected, MDB2::parseDSN($original)); - - // --------------------------------------------------------------------- - - //sqlite dbname+path on unix - $original = 'sqlite:////full/unix/path/to/file.db?mode=0666'; - $expected = array ( - 'phptype' => 'sqlite', - 'dbsyntax' => 'sqlite', - 'username' => false, - 'password' => false, - 'protocol' => 'tcp', - 'hostspec' => '', - 'port' => false, - 'socket' => false, - 'database' => '/full/unix/path/to/file.db', - 'mode' => false, - ); - $this->assertEquals($expected, MDB2::parseDSN($original)); - } - - //test stuff in common.php - function testConnect() { - $db =& MDB2::factory($this->dsn, $this->options); - if (PEAR::isError($db)) { - $this->assertTrue(false, 'Connect failed bailing out - ' .$db->getMessage() . ' - ' .$db->getUserInfo()); - } - if (PEAR::isError($this->db)) { - exit; - } - } - - function testGetOption() { - if (!$this->methodExists($this->db, 'getOption')) { - return; - } - $option = $this->db->getOption('persistent'); - $this->assertEquals($option, $this->db->options['persistent']); - } - - function testSetOption() { - if (!$this->methodExists($this->db, 'setOption')) { - return; - } - $option = $this->db->getOption('persistent'); - $this->db->setOption('persistent', !$option); - $this->assertEquals(!$option, $this->db->getOption('persistent')); - $this->db->setOption('persistent', $option); - } - - function testLoadModule() { - if (!$this->methodExists($this->db, 'loadModule')) { - return; - } - $this->assertTrue(!PEAR::isError($this->db->loadModule('Manager', null, true))); - } - - // test of the driver - // helper function so that we don't have to write out a query a million times - function standardQuery() { - $query = 'SELECT * FROM users'; - // run the query and get a result handler - if (!PEAR::isError($this->db)) { - return $this->db->query($query); - } - return false; - } - - function testQuery() { - if (!$this->methodExists($this->db, 'query')) { - return; - } - $result = $this->standardQuery(); - - $this->assertTrue(MDB2::isResult($result), 'query: $result returned is not a resource'); - } - - function testExec() { - if (!$this->methodExists($this->db, 'exec')) { - return; - } - $result = $this->db->exec('UPDATE users SET user_name = user_name WHERE user_id = user_id'); - $this->assertFalse(PEAR::isError($result), 'exec: $result returned is an error'); - $this->assertEquals(0, $result, 'exec: incorrect number of affected rows returned'); - } - - function testFetchRow() { - $result = $this->standardQuery(); - if (!$this->methodExists($result, 'fetchRow')) { - return; - } - $err = $result->fetchRow(); - $result->free(); - - if (PEAR::isError($err)) { - $this->assertTrue(false, 'Error testFetch: '.$err->getMessage().' - '.$err->getUserInfo()); - } - } - - function testNumRows() { - $result = $this->standardQuery(); - if (!$this->methodExists($result, 'numRows')) { - return; - } - $numrows = $result->numRows(); - $this->assertTrue(!PEAR::isError($numrows) && is_int($numrows)); - $result->free(); - } - - function testNumCols() { - $result = $this->standardQuery(); - if (!$this->methodExists($result, 'numCols')) { - return; - } - $numcols = $result->numCols(); - $this->assertTrue(!PEAR::isError($numcols) && $numcols > 0); - $result->free(); - } - - function testSingleton() { - $db =& MDB2::singleton(); - $this->assertTrue(MDB2::isConnection($db)); - - // should have a different database name set - $db =& MDB2::singleton($this->dsn, $this->options); - - $this->assertTrue($db->db_index != $this->db->db_index); - } - - function testGetServerVersion() { - $server_info = $this->db->getServerVersion(true); - if (PEAR::isError($server_info)) { - $this->assertTrue(false, 'Error: '.$server_info->getMessage().' - '.$server_info->getUserInfo()); - } else { - $this->assertTrue(is_string($server_info), 'Error: Server info is not returned as a string: '. serialize($server_info)); - } - $server_info = $this->db->getServerVersion(); - if (PEAR::isError($server_info)) { - $this->assertTrue(false, 'Error: '.$server_info->getMessage().' - '.$server_info->getUserInfo()); - } else { - $this->assertTrue(is_array($server_info), 'Error: Server info is not returned as an array: '. serialize($server_info)); - } - } -} - -?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/tests/MDB2_bugs_testcase.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/tests/MDB2_bugs_testcase.php --- php-mdb2-2.4.1/MDB2-2.4.1/tests/MDB2_bugs_testcase.php 2007-05-03 19:58:15.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.4.1/tests/MDB2_bugs_testcase.php 1970-01-01 01:00:00.000000000 +0100 @@ -1,291 +0,0 @@ - | -// +----------------------------------------------------------------------+ -// -// $Id: MDB2_bugs_testcase.php,v 1.31 2006/12/09 16:58:16 quipo Exp $ - -require_once 'MDB2_testcase.php'; - -class MDB2_Bugs_TestCase extends MDB2_TestCase { - /** - * - */ - function testFetchModeBug() { - $data = array(); - - $stmt = $this->db->prepare('INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)', array_values($this->fields), MDB2_PREPARE_MANIP); - - $data['user_name'] = 'user_='; - $data['user_password'] = 'somepass'; - $data['subscribed'] = true; - $data['user_id'] = 0; - $data['quota'] = sprintf("%.2f", strval(2/100)); - $data['weight'] = sqrt(0); - $data['access_date'] = MDB2_Date::mdbToday(); - $data['access_time'] = MDB2_Date::mdbTime(); - $data['approved'] = MDB2_Date::mdbNow(); - - $result = $stmt->execute(array_values($data)); - - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error executing prepared query '.$result->getMessage()); - } - - $stmt->free(); - - $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users ORDER BY user_name'; - $result =& $this->db->query($query); - - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error selecting from users: '.$result->getMessage()); - } - - $this->db->setFetchMode(MDB2_FETCHMODE_ASSOC); - - $firstRow = $result->fetchRow(); - $this->assertEquals($firstRow['user_name'], $data['user_name'], 'The data returned does not match that expected'); - - $result =& $this->db->query('SELECT user_name, user_id, quota FROM users ORDER BY user_name'); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error selecting from users: '.$result->getMessage()); - } - $this->db->setFetchMode(MDB2_FETCHMODE_ORDERED); - - $value = $result->fetchOne(); - $this->assertEquals($data['user_name'], $value, 'The data returned does not match that expected'); - $result->free(); - } - - /** - * @see http://bugs.php.net/bug.php?id=22328 - */ - function testBug22328() { - $result =& $this->db->query('SELECT * FROM users'); - $this->db->pushErrorHandling(PEAR_ERROR_RETURN); - $result2 = $this->db->query('SELECT * FROM foo'); - - $data = $result->fetchRow(); - $this->db->popErrorHandling(); - $this->assertFalse(PEAR::isError($data), 'Error messages for a query affect result reading of other queries'); - } - - /** - * @see http://pear.php.net/bugs/bug.php?id=670 - */ - function testBug670() { - $data['user_name'] = null; - $data['user_password'] = 'somepass'; - $data['subscribed'] = true; - $data['user_id'] = 1; - $data['quota'] = sprintf("%.2f",strval(3/100)); - $data['weight'] = sqrt(1); - $data['access_date'] = MDB2_Date::mdbToday(); - $data['access_time'] = MDB2_Date::mdbTime(); - $data['approved'] = MDB2_Date::mdbNow(); - - $stmt = $this->db->prepare('INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)', array_values($this->fields), MDB2_PREPARE_MANIP); - $result = $stmt->execute(array_values($data)); - - $result =& $this->db->query('SELECT user_name FROM users'); - $col = $result->fetchCol('user_name'); - if (PEAR::isError($col)) { - $this->assertTrue(false, 'Error when fetching column first first row as NULL: '.$col->getMessage()); - } - - $data['user_name'] = "user_1"; - $data['user_id'] = 2; - - $result = $stmt->execute(array_values($data)); - - $result =& $this->db->query('SELECT user_name FROM users'); - $col = $result->fetchCol('user_name'); - if (PEAR::isError($col)) { - $this->assertTrue(false, 'Error when fetching column: '.$col->getMessage()); - } - - $data['user_name'] = null; - - $stmt->free(); - } - - /** - * @see http://pear.php.net/bugs/bug.php?id=681 - */ - function testBug681() { - $result =& $this->db->query('SELECT * FROM users WHERE 1=0'); - - $numrows = $result->numRows(); - $this->assertEquals(0, $numrows, 'Numrows is not returning 0 for empty result sets'); - - $data = $this->getSampleData(1); - - $stmt = $this->db->prepare('INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)', array_values($this->fields), MDB2_PREPARE_MANIP); - $result = $stmt->execute(array_values($data)); - - $result =& $this->db->query('SELECT * FROM users'); - $numrows = $result->numRows(); - $this->assertEquals(1, $numrows, 'Numrows is not returning proper value'); - - $stmt->free(); - } - - /** - * @see http://pear.php.net/bugs/bug.php?id=718 - */ - function testBug718() { - $data = $this->getSampleData(1); - - $stmt = $this->db->prepare('INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)', array_values($this->fields), MDB2_PREPARE_MANIP); - $result = $stmt->execute(array_values($data)); - - $row = $this->db->queryRow('SELECT a.user_id, b.user_id FROM users a, users b where a.user_id = b.user_id', array('integer', 'integer'), MDB2_FETCHMODE_ORDERED); - $this->assertEquals(2, count($row), "Columns with the same name get overwritten in ordered mode"); - - $stmt->free(); - } - - /** - * @see http://pear.php.net/bugs/bug.php?id=946 - */ - function testBug946() { - $data = array(); - $total_rows = 5; - - $stmt = $this->db->prepare('INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)', array_values($this->fields), MDB2_PREPARE_MANIP); - - for ($row = 0; $row < $total_rows; $row++) { - $data[$row] = $this->getSampleData($row); - - $result = $stmt->execute(array_values($data[$row])); - - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error executing prepared query: '.$result->getMessage()); - } - } - $stmt->free(); - - $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users'; - - $this->db->setLimit(3, 1); - $result =& $this->db->query($query); - $numrows = $result->numRows(); - while ($row = $result->fetchRow()) { - if (PEAR::isError($row)) { - $this->assertTrue(false, 'Error fetching a row: '.$row->getMessage()); - } - } - $result->free(); - - $result =& $this->db->query($query); - $numrows = $result->numRows(); - while ($row = $result->fetchRow()) { - if (PEAR::isError($row)) { - $this->assertTrue(false, 'Error fetching a row: '.$row->getMessage()); - } - } - $result->free(); - } - - /** - * @see http://pear.php.net/bugs/bug.php?id=3146 - */ - function testBug3146() { - $data = array(); - $total_rows = 5; - - $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')'; - $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP); - - for ($row = 0; $row < $total_rows; $row++) { - $data[$row] = $this->getSampleData($row); - - $result = $stmt->execute(array_values($data[$row])); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error executing prepared query: '.$result->getMessage()); - } - } - $stmt->free(); - - $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users ORDER BY user_id'; - $result =& $this->db->query($query, $this->fields); - - $numrows = $result->numRows($result); - - $this->verifyFetchedValues($result, 0, $data[0]); - $this->verifyFetchedValues($result, 2, $data[2]); - $this->verifyFetchedValues($result, null, $data[3]); - $this->verifyFetchedValues($result, 1, $data[1]); - - $result->free(); - } - - /** - * Strong typing query result misbehaves when $n_columns > $n_types - * @see http://pear.php.net/bugs/bug.php?id=9502 - */ - function testBug9502() { - $row = 5; - $data = $this->getSampleData($row); - $stmt = $this->db->prepare('INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)', array_values($this->fields), MDB2_PREPARE_MANIP); - $result = $stmt->execute(array_values($data)); - $stmt->free(); - - //provide an incomplete and scrambled types array - $types = array(); - $types['subscribed'] = $this->fields['subscribed']; - $types['user_name'] = $this->fields['user_name']; - $types['weight'] = $this->fields['weight']; - - $query = 'SELECT weight, user_name, user_id, quota, subscribed FROM users WHERE user_id = '.$row; - $result =& $this->db->queryRow($query, $types, MDB2_FETCHMODE_ASSOC); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error executing query: '.$result->getMessage() .' - '. $result->getUserInfo()); - } else { - $this->assertTrue(is_bool($result['subscribed'])); - $this->assertTrue(is_numeric($result['user_id'])); - $this->assertTrue(is_float($result['weight'])); - $this->assertFalse(is_bool($result['user_name'])); - } - } -} - -?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/tests/MDB2_Connect_Test.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/tests/MDB2_Connect_Test.php --- php-mdb2-2.4.1/MDB2-2.4.1/tests/MDB2_Connect_Test.php 2007-05-03 19:58:15.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.4.1/tests/MDB2_Connect_Test.php 1970-01-01 01:00:00.000000000 +0100 @@ -1,52 +0,0 @@ -_dsn = array( - 'phptype' => DSN_PHPTYPE, - 'username' => DSN_USERNAME, - 'password' => DSN_PASSWORD, - 'hostspec' => DSN_HOSTNAME, - 'database' => DSN_DATABASE, - ); - - } - // }}} - // {{{ PHP4 constructor.. - function MDB2_Connect_Test() - { - $this->__construct($connect); - } - // }}} - // {{{ connect - function connect() - { - // connect to database - $options = array( - 'portability' => (MDB2_PORTABILITY_ALL ^ MDB2_PORTABILITY_EMPTY_TO_NULL), - ); - - $this->dbc =& MDB2::singleton($this->_dsn, $options); - if (PEAR::isError($this->dbc)) { - return $this->dbc; - } - } - // }}} -} -// }}} -?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/tests/MDB2_datatype_testcase.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/tests/MDB2_datatype_testcase.php --- php-mdb2-2.4.1/MDB2-2.4.1/tests/MDB2_datatype_testcase.php 2007-05-03 19:58:15.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.4.1/tests/MDB2_datatype_testcase.php 1970-01-01 01:00:00.000000000 +0100 @@ -1,861 +0,0 @@ - | -// +----------------------------------------------------------------------+ -// -// $Id: MDB2_datatype_testcase.php,v 1.18 2007/03/28 16:39:02 quipo Exp $ - -require_once 'MDB2_testcase.php'; - -/** - * A test callback function to be used in the test class below for - * ensuring that custom datatype callback features are handled - * correctly. - * - * @param MDB2 $db The MDB2 database resource object. - * @param string $method The name of the MDB2_Driver_Datatype_Common method - * the callback function was called from. One of - * "getValidTypes", "convertResult", "getDeclaration", - * "compareDefinition", "quote" and "mapPrepareDatatype". - * See {@link MDB2_Driver_Datatype_Common} for the - * details of what each method does. - * @param array $aParameters An array of parameters, being the parameters that - * were passed to the method calling the callback - * function. - * @return mixed Returns the appropriate value depending on the method that - * called the function. See {@link MDB2_Driver_Datatype_Common} - * for details of the expected return values of the five possible - * calling methods. - */ -function datatype_test_callback(&$db, $method, $aParameters) -{ - // Ensure the datatype module is loaded - if (is_null($db->datatype)) { - $db->loadModule('Datatype', null, true); - } - // Lowercase method names for PHP4/PHP5 compatibility - $method = strtolower($method); - switch($method) { - // For all cases, return a string that identifies that the - // callback method was able to call to the appropriate point - case 'getvalidtypes': - return 'datatype_test_callback::getvalidtypes'; - case 'convertresult': - return 'datatype_test_callback::convertresult'; - case 'getdeclaration': - return 'datatype_test_callback::getdeclaration'; - case 'comparedefinition': - return 'datatype_test_callback::comparedefinition'; - case 'quote': - return 'datatype_test_callback::quote'; - case 'mappreparedatatype': - return 'datatype_test_callback::mappreparedatatype'; - } -} - -/** - * A test callback function to be used in the test class below for - * ensuring that custom nativetype to datatype mapping is handled - * correctly. - * - * @param MDB2 $db The MDB2 database reource object. - * @param array $aFields The standard array of fields produced from the - * MySQL command "SHOW COLUMNS". See - * {@link http://dev.mysql.com/doc/refman/5.0/en/describe.html} - * for more details on the format of the fields. - * "type" The nativetype column type - * "null" "YES" or "NO" - * "key" "PRI", "UNI", "MUL", or null - * "default" The default value of the column - * "extra" "auto_increment", or null - * @return array Returns an array of the following items: - * 0 => An array of possible MDB2 datatypes. As this is - * a custom type, always has one entry, "test". - * 1 => The length of the type, if defined by the nativetype, - * otherwise null. - * 2 => A boolean value indicating the "unsigned" nature of numeric - * fields. Always null in this case, as this custom test - * type is not numeric. - * 3 => A boolean value indicating the "fixed" nature of text - * fields. Always bull in this case, as this custom test - * type is not textual. - */ -function nativetype_test_callback(&$db, $aFields) -{ - // Prepare the type array - $aType = array(); - $aType[] = 'test'; - // Can the length of the field be found? - $length = null; - $start = strpos($aFields['type'], '('); - $end = strpos($aFields['type'], ')'); - if ($start && $end) { - $start++; - $chars = $end - $start; - $length = substr($aFields['type'], $start, $chars); - } - // No unsigned value needed - $unsigned = null; - // No fixed value needed - $fixed = null; - return array($aType, $length, $unsigned, $fixed); -} - -class MDB2_Datatype_TestCase extends MDB2_TestCase -{ - // Test table name (it is dynamically created/dropped) - var $table = 'datatypetable'; - - function setUp() { - parent::setUp(); - $this->db->loadModule('Manager', null, true); - $this->fields = array( - 'id' => array( - 'type' => 'integer', - 'unsigned' => true, - 'notnull' => true, - 'default' => 0, - ), - 'textfield' => array( - 'type' => 'text', - 'length' => 12, - ), - 'booleanfield' => array( - 'type' => 'boolean', - ), - 'decimalfield' => array( - 'type' => 'decimal', - ), - 'floatfield' => array( - 'type' => 'float', - ), - 'datefield' => array( - 'type' => 'date', - ), - 'timefield' => array( - 'type' => 'time', - ), - 'timestampfield' => array( - 'type' => 'timestamp', - ), - ); - if (!$this->tableExists($this->table)) { - $this->db->manager->createTable($this->table, $this->fields); - } - } - - /** - * The teardown method to clean up the testing environment. - */ - function tearDown() { - if ($this->tableExists($this->table)) { - $this->db->manager->dropTable($this->table); - } - $this->db->popExpect(); - unset($this->dsn); - if (!PEAR::isError($this->db->manager)) { - $this->db->disconnect(); - } - unset($this->db); - } - - /** - * Get the types of each field given its name - * - * @param array $names list of field names - * @return array $types list of matching field types - */ - function getFieldTypes($names) { - $types = array(); - foreach ($names as $name) { - foreach ($this->fields as $fieldname => $field) { - if ($name == $fieldname) { - $types[$name] = $field['type']; - } - } - } - return $types; - } - - /** - * Insert the values into the sample table - * - * @param array $values associative array (name => value) - */ - function insertValues($values) { - $types = $this->getFieldTypes(array_keys($values)); - - $result = $this->db->exec('DELETE FROM '.$this->table); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error emptying table: '.$result->getMessage()); - } - - $query = sprintf('INSERT INTO %s (%s) VALUES (%s)', - $this->table, - implode(', ', array_keys($values)), - implode(', ', array_fill(0, count($values), '?')) - ); - $stmt = $this->db->prepare($query, array_values($types), MDB2_PREPARE_MANIP); - if (PEAR::isError($stmt)) { - $this->assertTrue(false, 'Error creating prepared query: '.$stmt->getMessage()); - } - $result = $stmt->execute(array_values($values)); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error executing prepared query: '.$result->getMessage()); - } - $stmt->free(); - } - - /** - * Select the inserted row from the db and check the inserted values - * @param array $values associative array (name => value) of inserted data - */ - function selectAndCheck($values) { - $types = $this->getFieldTypes(array_keys($values)); - - $query = 'SELECT '. implode (', ', array_keys($values)). ' FROM '.$this->table; - $result = $this->db->queryRow($query, $types, MDB2_FETCHMODE_ASSOC); - foreach ($values as $name => $value) { - $this->assertEquals($result[$name], $values[$name], 'Error in '.$types[$name].' value: incorrect conversion'); - } - } - - /** - * Test the TEXT datatype for incorrect conversions - */ - function testTextDataType($emulate_prepared = false) { - if ($emulate_prepared) { - $this->db->setOption('emulate_prepared', true); - } - - $data = array( - 'id' => 1, - 'textfield' => 'test', - ); - $this->insertValues($data); - $this->selectAndCheck($data); - - if (!$emulate_prepared && !$this->db->getOption('emulate_prepared')) { - $this->testTextDataType(true); - } elseif($emulate_prepared) { - $this->db->setOption('emulate_prepared', false); - } - } - - /** - * Test the DECIMAL datatype for incorrect conversions - */ - function testDecimalDataType($emulate_prepared = false) { - if ($emulate_prepared) { - $this->db->setOption('emulate_prepared', true); - } - - $data = array( - 'id' => 1, - 'decimalfield' => 10.35, - ); - $this->insertValues($data); - $this->selectAndCheck($data); - - $old_locale = setlocale(LC_NUMERIC, 0); - if (OS_UNIX) { - setlocale(LC_NUMERIC, 'de_DE@euro', 'de_DE', 'de', 'ge'); - } else { - setlocale(LC_NUMERIC, 'de_DE@euro', 'de_DE', 'deu_deu'); - } - - $this->insertValues($data); - $this->selectAndCheck($data); - - setlocale(LC_NUMERIC, $old_locale); - - $expected = 10.35; - - $actual = $this->db->quote($expected, 'decimal'); - $this->assertEquals($expected, $actual); - - $non_us = number_format($expected, 2, ',', ''); - $actual = $this->db->quote($non_us, 'decimal'); - $this->assertEquals($expected, $actual); - - $expected = 1000.35; - - $non_us = '1,000.35'; - $actual = $this->db->quote($non_us, 'decimal'); - $this->assertEquals($expected, $actual); - - $non_us = '1000,35'; - $actual = $this->db->quote($non_us, 'decimal'); - $this->assertEquals($expected, $actual); - - $non_us = '1.000,35'; - $actual = $this->db->quote($non_us, 'decimal'); - $this->assertEquals($expected, $actual); - - // test quoting with invalid chars - $val = '100.3abc";d@a[\\'; - $this->assertEquals(100.3, $this->db->quote($val, 'decimal')); - - if (!$emulate_prepared && !$this->db->getOption('emulate_prepared')) { - $this->testDecimalDataType(true); - } elseif($emulate_prepared) { - $this->db->setOption('emulate_prepared', false); - } - } - - /** - * Test the FLOAT datatype for incorrect conversions - */ - function testFloatDataType($emulate_prepared = false) { - if ($emulate_prepared) { - $this->db->setOption('emulate_prepared', true); - } - - $data = array( - 'id' => 1, - 'floatfield' => 10.35, - ); - $this->insertValues($data); - $this->selectAndCheck($data); - - $old_locale = setlocale(LC_NUMERIC, 0); - if (OS_UNIX) { - setlocale(LC_NUMERIC, 'de_DE@euro', 'de_DE', 'de', 'ge'); - } else { - setlocale(LC_NUMERIC, 'de_DE@euro', 'de_DE', 'deu_deu'); - } - - - $this->insertValues($data); - $this->selectAndCheck($data); - - setlocale(LC_NUMERIC, $old_locale); - - $data['floatfield'] = '1.035e+1'; - $this->insertValues($data); - $this->selectAndCheck($data); - - $data['floatfield'] = '1.035E+01'; - $this->insertValues($data); - $this->selectAndCheck($data); - - $expected = '1.035E+01'; - $non_us = '1,035e+1'; - $actual = $this->db->quote($non_us, 'float'); - $this->assertEquals($expected, $actual); - - $expected = 10.35; - - $actual = $this->db->quote($expected, 'float'); - $this->assertEquals($expected, $actual); - - $non_us = number_format($expected, 2, ',', ''); - $actual = $this->db->quote($non_us, 'float'); - $this->assertEquals($expected, $actual); - - $expected = 1000.35; - - $non_us = '1,000.35'; - $actual = $this->db->quote($non_us, 'float'); - $this->assertEquals($expected, $actual); - - $non_us = '1000,35'; - $actual = $this->db->quote($non_us, 'float'); - $this->assertEquals($expected, $actual); - - $non_us = '1.000,35'; - $actual = $this->db->quote($non_us, 'float'); - $this->assertEquals($expected, $actual); - - // test quoting with invalid chars - $val = '100.3abc";d@a[\\'; - $this->assertEquals(100.3, $this->db->quote($val, 'float')); - - if (!$emulate_prepared && !$this->db->getOption('emulate_prepared')) { - $this->testFloatDataType(true); - } elseif($emulate_prepared) { - $this->db->setOption('emulate_prepared', false); - } - } - - /** - * Test the BOOLEAN datatype for incorrect conversions - */ - function testBooleanDataType($emulate_prepared = false) { - if ($emulate_prepared) { - $this->db->setOption('emulate_prepared', true); - } - - $data = array( - 'id' => 1, - 'booleanfield' => true, - ); - $this->insertValues($data); - $this->selectAndCheck($data); - - $data['booleanfield'] = false; - $this->insertValues($data); - $this->selectAndCheck($data); - - if (!$emulate_prepared && !$this->db->getOption('emulate_prepared')) { - $this->testBooleanDataType(true); - } elseif($emulate_prepared) { - $this->db->setOption('emulate_prepared', false); - } - } - - /** - * Test the DATE datatype for incorrect conversions - */ - function testDateDataType($emulate_prepared = false) { - if ($emulate_prepared) { - $this->db->setOption('emulate_prepared', true); - } - - $data = array( - 'id' => 1, - 'datefield' => date('Y-m-d'), - ); - $this->insertValues($data, 'date'); - $this->selectAndCheck($data); - - if (!$emulate_prepared && !$this->db->getOption('emulate_prepared')) { - $this->testDateDataType(true); - } elseif($emulate_prepared) { - $this->db->setOption('emulate_prepared', false); - } - } - - /** - * Test the TIME datatype for incorrect conversions - */ - function testTimeDataType($emulate_prepared = false) { - if ($emulate_prepared) { - $this->db->setOption('emulate_prepared', true); - } - - $data = array( - 'id' => 1, - 'timefield' => date('H:i:s'), - ); - $this->insertValues($data, 'time'); - $this->selectAndCheck($data); - - if (!$emulate_prepared && !$this->db->getOption('emulate_prepared')) { - $this->testTimeDataType(true); - } elseif($emulate_prepared) { - $this->db->setOption('emulate_prepared', false); - } - } - - /** - * Test the TIMESTAMP datatype for incorrect conversions - */ - function testTimestampDataType($emulate_prepared = false) { - if ($emulate_prepared) { - $this->db->setOption('emulate_prepared', true); - } - - $data = array( - 'id' => 1, - 'timestampfield' => date('Y-m-d H:i:s'), - ); - $this->insertValues($data, 'timestamp'); - $this->selectAndCheck($data); - - if (!$emulate_prepared && !$this->db->getOption('emulate_prepared')) { - $this->testTimestampDataType(true); - } elseif($emulate_prepared) { - $this->db->setOption('emulate_prepared', false); - } - } - - /** - * Tests escaping of text values with special characters - */ - function testEscapeSequences() { - $test_strings = array( - "'", - "\"", - "\\", - "%", - "_", - "''", - "\"\"", - "\\\\", - "\\'\\'", - "\\\"\\\"" - ); - - $this->clearTables(); - foreach($test_strings as $key => $string) { - $value = $this->db->quote($string, 'text'); - $query = "INSERT INTO users (user_name,user_id) VALUES ($value, $key)"; - $result = $this->db->exec($query); - - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error executing insert query'.$result->getMessage()); - } - - $query = 'SELECT user_name FROM users WHERE user_id = '.$key; - $value = $this->db->queryOne($query, 'text'); - - if (PEAR::isError($value)) { - $this->assertTrue(false, 'Error executing select query'.$value->getMessage()); - } - - $this->assertEquals($string, $value, "the value retrieved for field \"user_name\" doesn't match what was stored"); - } - } - - /** - * Tests escaping of text pattern strings with special characters - */ - function testPatternSequences() { - $test_strings = array( - "Foo", - "FOO", - "foo", - ); - - $this->clearTables(); - foreach($test_strings as $key => $string) { - $value = $this->db->quote($string, 'text'); - $query = "INSERT INTO users (user_name,user_id) VALUES ($value, $key)"; - $result = $this->db->exec($query); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error executing insert query'.$result->getMessage()); - } - } - - $query = 'SELECT user_name FROM users WHERE '.$this->db->datatype->matchPattern(array('F', '%'), 'LIKE', 'user_name'); - $values = $this->db->queryCol($query, 'text'); - $this->assertEquals(2, count($values), "case sensitive search was expected to return 2 rows but returned: ".count($values)); - - $query = 'SELECT user_name FROM users WHERE '.$this->db->datatype->matchPattern(array('foo'), 'ILIKE', 'user_name'); - $values = $this->db->queryCol($query, 'text'); - $this->assertEquals(3, count($values), "case insensitive search was expected to return 3 rows but returned: ".count($values)); - } - - /** - * Tests escaping of text pattern strings with special characters - */ - function testEscapePatternSequences() { - if (!$this->supported('pattern_escaping')) { - return; - } - - $test_strings = array( - "%", - "_", - "%_", - "_%", - "%Foo%", - "%Foo_", - "Foo%123", - "Foo_123", - "_Foo%", - "_Foo_", - "%'", - "_'", - "'%", - "'_", - "'%'", - "'_'", - ); - - $this->clearTables(); - foreach($test_strings as $key => $string) { - $value = $this->db->quote($string, 'text'); - $query = "INSERT INTO users (user_name,user_id) VALUES ($value, $key)"; - $result = $this->db->exec($query); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error executing insert query'.$result->getMessage()); - } - - $query = 'SELECT user_name FROM users WHERE user_name LIKE '.$this->db->quote($string, 'text', true, true); - $value = $this->db->queryOne($query, 'text'); - if (PEAR::isError($value)) { - $this->assertTrue(false, 'Error executing select query'.$value->getMessage()); - } - - $this->assertEquals($string, $value, "the value retrieved for field \"user_name\" doesn't match what was stored"); - } - - $this->db->loadModule('Datatype', null, true); - $query = 'SELECT user_name FROM users WHERE user_name LIKE '.$this->db->datatype->matchPattern(array('Foo%', '_', '23')); - $value = $this->db->queryOne($query, 'text'); - $this->assertEquals('Foo%123', $value, "the value retrieved for field \"user_name\" doesn't match what was stored"); - - $query = 'SELECT user_name FROM users WHERE user_name LIKE '.$this->db->datatype->matchPattern(array(1 => '_', 'oo', '%')); - $value = $this->db->queryOne($query, 'text'); - $this->assertEquals('Foo', substr($value, 0, 3), "the value retrieved for field \"user_name\" doesn't match what was stored"); - } - - /** - * A method to test that the MDB2_Driver_Datatype_Common::getValidTypes() - * method returns the correct data array. - */ - function testGetValidTypes() - { - $this->db->loadModule('Datatype', null, true); - // Test with just the default MDB2 datatypes. - $aExpected = $this->db->datatype->valid_default_values; - $aResult = $this->db->datatype->getValidTypes(); - $this->assertEquals($aExpected, $aResult, 'getValidTypes'); - - // Test with a custom datatype - $this->db->setOption('datatype_map', array('test' => 'test')); - $this->db->setOption('datatype_map_callback', array('test' => 'datatype_test_callback')); - $aExpected = array_merge( - $this->db->datatype->valid_default_values, - array('test' => 'datatype_test_callback::getvalidtypes') - ); - $aResult = $this->db->datatype->getValidTypes(); - $this->assertEquals($aExpected, $aResult, 'getValidTypes'); - unset($this->db->options['datatype_map']); - unset($this->db->options['datatype_map_callback']); - - } - - /** - * A method to test that the MDB2_Driver_Datatype_Common::convertResult() - * method returns correctly converted column data. - */ - function testConvertResult() - { - $this->db->loadModule('Datatype', null, true); - // Test with an MDB2 datatype, eg. "text" - $value = 'text'; - $type = 'text'; - $result = $this->db->datatype->convertResult($value, $type); - $this->assertEquals($value, $result, 'convertResult'); - - // Test with a custom datatype - $this->db->setOption('datatype_map', array('test' => 'test')); - $this->db->setOption('datatype_map_callback', array('test' => 'datatype_test_callback')); - $value = 'text'; - $type = 'test'; - $result = $this->db->datatype->convertResult($value, $type); - $this->assertEquals('datatype_test_callback::convertresult', $result, 'mapPrepareDatatype'); - unset($this->db->options['datatype_map']); - unset($this->db->options['datatype_map_callback']); - } - - /** - * A method to test that the MDB2_Driver_Datatype_Common::getDeclaration() - * method returns correctly formatted SQL for declaring columns. - */ - function testGetDeclaration() - { - $this->db->loadModule('Datatype', null, true); - // Test with an MDB2 datatype, eg. "integer" - $name = 'column'; - $type = 'integer'; - $field = array('type' => 'integer'); - $result = $this->db->datatype->getDeclaration($type, $name, $field); - $actual_type = $this->db->phptype == 'sqlite' ? 'INTEGER' : 'INT'; - $this->assertEquals('column '.$actual_type.' DEFAULT NULL', $result, 'getDeclaration'); - - // Test with a custom datatype - $this->db->setOption('datatype_map', array('test' => 'test')); - $this->db->setOption('datatype_map_callback', array('test' => 'datatype_test_callback')); - $name = 'column'; - $type = 'test'; - $field = array('type' => 'test'); - $result = $this->db->datatype->getDeclaration($type, $name, $field); - $this->assertEquals('datatype_test_callback::getdeclaration', $result, 'getDeclaration'); - - // Test with a custom datatype without datatype_map_callback function - $name = 'address'; - $type = 'text'; - $field = array( - 'name' => 'company_addr', - 'type' => 'address', - ); - $this->db->setOption('datatype_map', array($name => $type)); - $result = $this->db->datatype->getDeclaration($field['type'], $field['name'], $field); - $expected = $field['name'].' '.$this->db->datatype->getTypeDeclaration(array('type' => $type)).' DEFAULT NULL'; - $this->assertEquals($expected, $result); - unset($this->db->options['datatype_map']); - unset($this->db->options['datatype_map_callback']); - } - - /** - * A method to test that the MDB2_Driver_Datatype_Common::compareDefinition() - * method - */ - function testCompareDefinition() - { - // Test with an MDB2 datatype, eg. "text" - $aPrevious = array( - 'type' => 'text', - 'length' => 4 - ); - $aCurrent = array( - 'type' => 'text', - 'length' => 5 - ); - $aResult = $this->db->datatype->compareDefinition($aCurrent, $aPrevious); - $this->assertTrue(is_array($aResult), 'compareDefinition'); - $this->assertEquals(1, count($aResult), 'compareDefinition'); - $this->assertTrue($aResult['length'], 'compareDefinition'); - - // Test with a custom datatype - $this->db->setOption('datatype_map', array('test' => 'test')); - $this->db->setOption('datatype_map_callback', array('test' => 'datatype_test_callback')); - $aPrevious = array( - 'type' => 'test' - ); - $aCurrent = array( - 'type' => 'test' - ); - $result = $this->db->datatype->compareDefinition($aCurrent, $aPrevious); - $this->assertEquals('datatype_test_callback::comparedefinition', $result, 'compareDefinition'); - unset($this->db->options['datatype_map']); - unset($this->db->options['datatype_map_callback']); - } - - /** - * A method to test that the MDB2_Driver_Datatype_Common::quote() - * method returns correctly quoted column data. - */ - function testQuote() - { - $this->db->loadModule('Datatype', null, true); - // Test with an MDB2 datatype, eg. "text" - $value = 'text'; - $type = 'text'; - $result = $this->db->datatype->quote($value, $type); - $this->assertEquals("'$value'", $result, 'quote'); - - // Test with a custom datatype - $this->db->setOption('datatype_map', array('test' => 'test')); - $this->db->setOption('datatype_map_callback', array('test' => 'datatype_test_callback')); - $value = 'text'; - $type = 'test'; - $result = $this->db->datatype->quote($value, $type); - $this->assertEquals('datatype_test_callback::quote', $result, 'quote'); - unset($this->db->options['datatype_map']); - unset($this->db->options['datatype_map_callback']); - } - - /** - * A method to test that the MDB2_Driver_Datatype_Common::mapPrepareDatatype() - * method returns the correct data type. - */ - function testMapPrepareDatatype() - { - $this->db->loadModule('Datatype', null, true); - // Test with an MDB2 datatype, eg. "text" - $type = 'text'; - $result = $this->db->datatype->mapPrepareDatatype($type); - if ($this->db->phptype == 'mysqli') { - $type = 's'; - } - $this->assertEquals($type, $result, 'mapPrepareDatatype'); - - // Test with a custom datatype - $this->db->setOption('datatype_map', array('test' => 'test')); - $this->db->setOption('datatype_map_callback', array('test' => 'datatype_test_callback')); - $type = 'test'; - $result = $this->db->datatype->mapPrepareDatatype($type); - $this->assertEquals('datatype_test_callback::mappreparedatatype', $result, 'mapPrepareDatatype'); - unset($this->db->options['datatype_map']); - unset($this->db->options['datatype_map_callback']); - } - - /** - * A method to test that the MDB2_Driver_Datatype_Common::mapNativeDatatype() - * method returns the correct MDB2 datatype from a given nativetype. - */ - function testMapNativeDatatype() - { - $this->db->loadModule('Datatype', null, true); - // Test with an common nativetype, eg. "text" - $field = array( - 'type' => 'int', - 'length' => 8 - ); - if (in_array($this->db->phptype, array('ibase', 'oci8'))) { - $field['type'] = 'integer'; - } - $expected_length = 8; - if (in_array($this->db->phptype, array('mysql', 'mysqli', 'pgsql', 'sqlite', 'mssql'))) { - $expected_length = 4; - } - $result = $this->db->datatype->mapNativeDatatype($field); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'mapNativeDatatype: '.$result->getUserInfo()); - } else { - $this->assertTrue(is_array($result), 'mapNativeDatatype'); - $this->assertEquals(4, count($result), 'mapNativeDatatype'); - $this->assertEquals('integer', $result[0][0], 'mapNativeDatatype'); - $this->assertEquals($expected_length, $result[1], 'mapNativeDatatype'); - } - - // Test with a custom nativetype mapping - $this->db->setOption('nativetype_map_callback', array('test' => 'nativetype_test_callback')); - $field = array( - 'type' => 'test' - ); - $result = $this->db->datatype->mapNativeDatatype($field); - $this->assertTrue(is_array($result), 'mapNativeDatatype'); - $this->assertEquals(4, count($result), 'mapNativeDatatype'); - $this->assertEquals('test', $result[0][0], 'mapNativeDatatype'); - $this->assertNull($result[1], 'mapNativeDatatype'); - $this->assertNull($result[2], 'mapNativeDatatype'); - $this->assertNull($result[3], 'mapNativeDatatype'); - $field = array( - 'type' => 'test(10)' - ); - $result = $this->db->datatype->mapNativeDatatype($field); - $this->assertTrue(is_array($result), 'mapNativeDatatype'); - $this->assertEquals(count($result), 4, 'mapNativeDatatype'); - $this->assertEquals($result[0][0], 'test', 'mapNativeDatatype'); - $this->assertEquals($result[1], 10, 'mapNativeDatatype'); - $this->assertNull($result[2], 'mapNativeDatatype'); - $this->assertNull($result[3], 'mapNativeDatatype'); - unset($this->db->options['nativetype_map_callback']); - } -} - -?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/tests/MDB2_extended_testcase.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/tests/MDB2_extended_testcase.php --- php-mdb2-2.4.1/MDB2-2.4.1/tests/MDB2_extended_testcase.php 2007-05-03 19:58:15.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.4.1/tests/MDB2_extended_testcase.php 1970-01-01 01:00:00.000000000 +0100 @@ -1,580 +0,0 @@ - | -// | Lorenzo Alberton | -// +----------------------------------------------------------------------+ -// -// $Id: MDB2_extended_testcase.php,v 1.13 2007/02/28 12:15:26 quipo Exp $ - -require_once 'MDB2_testcase.php'; - -class MDB2_Extended_TestCase extends MDB2_TestCase -{ - /** - * - */ - function testAutoExecute() - { - $data = $this->getSampleData(); - $select_query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users'; - - $result = $this->db->loadModule('Extended'); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error loading "Extended" module: '.$result->getMessage()); - } - $result = $this->db->extended->autoExecute('users', $data, MDB2_AUTOQUERY_INSERT, null, $this->fields); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error auto executing insert: '.$result->getMessage()); - } - - $this->db->setFetchMode(MDB2_FETCHMODE_ASSOC); - $result =& $this->db->query($select_query, $this->fields); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error selecting from users: '.$result->getMessage()); - } else { - $this->verifyFetchedValues($result, null, $data); - $result->free(); - } - - $where = 'user_id = '.$this->db->quote($data['user_id'], 'integer'); - $result = $this->db->extended->autoExecute('users', null, MDB2_AUTOQUERY_SELECT, $where, null, true, $this->fields); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error auto executing select: '.$result->getMessage()); - } else { - $this->verifyFetchedValues($result, null, $data); - $result->free(); - } - - $where = 'user_id = '.$this->db->quote($data['user_id'], 'integer'); - $result = $this->db->extended->autoExecute('users', null, MDB2_AUTOQUERY_SELECT, $where, null, true, MDB2_PREPARE_RESULT); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error auto executing select: '.$result->getMessage()); - } else { - $result->setResultTypes($this->fields); - $this->verifyFetchedValues($result, null, $data); - $result->free(); - } - - $update_data = array(); - $data['user_name'] = $update_data['user_name'] = 'foo'; - - $where = 'user_id = '.$this->db->quote($data['user_id'], 'integer'); - $result = $this->db->extended->autoExecute('users', $update_data, MDB2_AUTOQUERY_UPDATE, $where, $this->fields); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error auto executing insert: '.$result->getMessage()); - } - - $this->db->setFetchMode(MDB2_FETCHMODE_ASSOC); - $result =& $this->db->query($select_query, $this->fields); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error selecting from users: '.$result->getMessage()); - } else { - $this->verifyFetchedValues($result, null, $data); - $result->free(); - } - - $where = array($where, 'user_name = '.$this->db->quote($data['user_name'], 'text')); - $result = $this->db->extended->autoExecute('users', null, MDB2_AUTOQUERY_DELETE, $where, null); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error auto executing insert: '.$result->getMessage()); - } - - $this->db->setFetchMode(MDB2_FETCHMODE_ASSOC); - $result =& $this->db->query($select_query, $this->fields); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error selecting from users: '.$result->getMessage()); - } else { - $this->assertEquals(0, $result->numRows(), 'No rows were expected to be returned'); - $result->free(); - } - } - - /** - * Test getAssoc() - * - * Test fetching two columns from a resultset. Return them as (key,value) pairs. - */ - function testGetAssoc() - { - $result = $this->db->loadModule('Extended'); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error loading "Extended" module: '.$result->getMessage()); - } - - $data = $this->getSampleData(1234); - - $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')'; - $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP); - $result = $stmt->execute(array_values($data)); - $stmt->free(); - - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error executing prepared query: '.$result->getMessage()); - } - - //test getAssoc() with query parameters - $query = 'SELECT user_id, user_name FROM users WHERE user_id=?'; - $result = $this->db->extended->getAssoc($query, array('integer', 'text'), array(1234), array('integer')); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error executing getAssoc(): '.$result->getMessage()); - } - $this->assertTrue(array_key_exists($data['user_id'], $result), 'Unexpected returned key'); - $this->assertEquals($data['user_name'], $result[$data['user_id']], 'Unexpected returned value'); - - //test getAssoc() without query parameters - $query = 'SELECT user_id, user_name FROM users WHERE user_id=1234'; - $result = $this->db->extended->getAssoc($query, array('integer', 'text')); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error executing getAssoc(): '.$result->getMessage()); - } else { - $this->assertTrue(array_key_exists($data['user_id'], $result), 'Unexpected returned key'); - $this->assertEquals($data['user_name'], $result[$data['user_id']], 'Unexpected returned value'); - } - - //add another record to the db - $data2 = $this->getSampleData(4321); - $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')'; - $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP); - $result = $stmt->execute(array_values($data2)); - $stmt->free(); - - //test getAssoc() with $force_array=true - $query = 'SELECT user_id, user_name FROM users ORDER BY user_id'; - $values = $this->db->extended->getAssoc($query, array('integer', 'text'), null, null, MDB2_FETCHMODE_ASSOC, true); - if (PEAR::isError($values)) { - $this->assertTrue(false, 'Error executing getAssoc(): '.$values->getMessage()); - } else { - $this->assertEquals(2, count($values), 'Error: incorrect number of returned rows'); - list($id, $value) = each($values); - $this->assertEquals($data['user_id'], $id, 'Unexpected returned value'); - $this->assertEquals($data['user_name'], $value['user_name'], 'Unexpected returned value'); - list($id, $value) = each($values); - $this->assertEquals($data2['user_id'], $id, 'Unexpected returned value'); - $this->assertEquals($data2['user_name'], $value['user_name'], 'Unexpected returned value'); - } - - - //test getAssoc() with $force_array=false and $group=true - $query = 'SELECT user_id, user_name FROM users ORDER BY user_id'; - $values = $this->db->extended->getAssoc($query, array('integer', 'text'), null, null, MDB2_FETCHMODE_ASSOC, false, true); - if (PEAR::isError($values)) { - $this->assertTrue(false, 'Error executing getAssoc(): '.$values->getMessage()); - } else { - //@todo: check if MDB2_FETCHMODE_ASSOC is behaving correctly in this case - $this->assertEquals(2, count($values), 'Error: incorrect number of returned rows'); - list($id, $value) = each($values); - $this->assertEquals($data['user_id'], $id, 'Unexpected returned value'); - $this->assertEquals($data['user_name'], $value[0], 'Unexpected returned value'); - list($id, $value) = each($values); - $this->assertEquals($data2['user_id'], $id, 'Unexpected returned value'); - $this->assertEquals($data2['user_name'], $value[0], 'Unexpected returned value'); - - } - - //test $group=true with 3 fields - $query = 'SELECT user_password, user_id, user_name FROM users ORDER BY user_id'; - $values = $this->db->extended->getAssoc($query, array('integer', 'text', 'text'), null, null, MDB2_FETCHMODE_ASSOC, false, true); - if (PEAR::isError($values)) { - $this->assertTrue(false, 'Error executing getAssoc(): '.$values->getMessage()); - } else { - //the 2 values for user_password are equals, so they are collapsed in the same array - $this->assertEquals(1, count($values), 'Error: incorrect number of returned rows'); - $values = $values[0]; - //there are 2 records - $this->assertEquals(2, count($values), 'Error: incorrect number of returned rows'); - $value = array_shift($values); - $this->assertEquals($data['user_id'], $value['user_id'], 'Unexpected returned value'); - $this->assertEquals($data['user_name'], $value['user_name'], 'Unexpected returned value'); - $value = array_shift($values); - $this->assertEquals($data2['user_id'], $value['user_id'], 'Unexpected returned value'); - $this->assertEquals($data2['user_name'], $value['user_name'], 'Unexpected returned value'); - } - - //test $group=false with 3 fields - $values = $this->db->extended->getAssoc($query, array('integer', 'text', 'text'), null, null, MDB2_FETCHMODE_ASSOC, false, false); - if (PEAR::isError($values)) { - $this->assertTrue(false, 'Error executing getAssoc(): '.$values->getMessage()); - } else { - //the 2 values for user_password are equals, so the first record is overwritten - $this->assertEquals(1, count($values), 'Error: incorrect number of returned rows'); - $values = $values[0]; - $this->assertEquals($data2['user_id'], $value['user_id'], 'Unexpected returned value'); - $this->assertEquals($data2['user_name'], $value['user_name'], 'Unexpected returned value'); - } - } - - /** - * Test getOne() - * - * Test fetching a single value - */ - function testGetOne() - { - $result = $this->db->loadModule('Extended'); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error loading "Extended" module: '.$result->getMessage()); - } - - $data = $this->getSampleData(1234); - - $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')'; - $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP); - $result = $stmt->execute(array_values($data)); - $stmt->free(); - - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error executing prepared query: '.$result->getMessage()); - } - - //test getOne() with query parameters - $query = 'SELECT user_name FROM users WHERE user_id=?'; - $result = $this->db->extended->getOne($query, 'text', array(1234), array('integer')); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error executing getOne(): '.$result->getMessage()); - } - $this->assertEquals($data['user_name'], $result, 'Unexpected returned value'); - - //test getOne() without query parameters - $query = 'SELECT user_name FROM users WHERE user_id=1234'; - $result = $this->db->extended->getOne($query, 'text'); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error executing getOne(): '.$result->getMessage()); - } - $this->assertEquals($data['user_name'], $result, 'Unexpected returned value'); - - //test getOne() with column number (resultset: 0-based array) - $query = 'SELECT user_id, user_name, approved FROM users WHERE user_id=1234'; - $result = $this->db->extended->getOne($query, 'text', null, null, 1); //get the 2nd column - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error executing getOne(): '.$result->getMessage()); - } - $this->assertEquals($data['user_name'], $result, 'Unexpected returned value'); - } - - /** - * Test getCol() - * - * Test fetching a column of result data. - */ - function testGetCol() - { - $result = $this->db->loadModule('Extended'); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error loading "Extended" module: '.$result->getMessage()); - } - - $data = array( - 0 => $this->getSampleData(1234), - 1 => $this->getSampleData(4321), - ); - $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')'; - $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP); - $result = $stmt->execute(array_values($data[0])); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error executing prepared query: '.$result->getMessage()); - } - $result = $stmt->execute(array_values($data[1])); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error executing prepared query: '.$result->getMessage()); - } - $stmt->free(); - - //test getCol() with query parameters - $query = 'SELECT user_name FROM users WHERE user_id>?'; - $result = $this->db->extended->getCol($query, 'text', array(1), array('integer')); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error executing getCol(): '.$result->getMessage()); - } - $expected = array( - $data[0]['user_name'], - $data[1]['user_name'], - ); - $this->assertEquals($expected, $result, 'Unexpected returned value'); - - //test getCol() without query parameters - $query = 'SELECT user_name FROM users'; - $result = $this->db->extended->getCol($query, 'text'); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error executing getCol(): '.$result->getMessage()); - } - $this->assertEquals($expected, $result, 'Unexpected returned value'); - - //test getCol() with column number (resultset: 0-based array) - $query = 'SELECT user_id, user_name, approved FROM users'; - $result = $this->db->extended->getCol($query, 'text', null, null, 1); //get the 2nd column - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error executing getCol(): '.$result->getMessage()); - } - $this->assertEquals($expected, $result, 'Unexpected returned value'); - } - - /** - * Test getRow() - * - * Test fetching a row of result data. - */ - function testGetRow() - { - $result = $this->db->loadModule('Extended'); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error loading "Extended" module: '.$result->getMessage()); - } - - $data = $this->getSampleData(1234); - $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')'; - $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP); - $result = $stmt->execute(array_values($data)); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error executing prepared query: '.$result->getMessage()); - } - $stmt->free(); - - //test getRow() with query parameters - $query = 'SELECT user_id, user_name, user_password FROM users WHERE user_id=?'; - $result = $this->db->extended->getRow($query, array('integer', 'text', 'text'), array(1234), array('integer'), MDB2_FETCHMODE_ASSOC); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error executing getRow(): '.$result->getMessage()); - } - $this->assertEquals($data['user_id'], $result['user_id'], 'Unexpected returned value'); - $this->assertEquals($data['user_name'], $result['user_name'], 'Unexpected returned value'); - $this->assertEquals($data['user_password'], $result['user_password'], 'Unexpected returned value'); - - //test getRow() without query parameters - $query = 'SELECT user_id, user_name, user_password FROM users'; - $result = $this->db->extended->getRow($query, array('integer', 'text', 'text'), null, null, MDB2_FETCHMODE_ASSOC); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error executing getRow(): '.$result->getMessage()); - } - $this->assertEquals($data['user_id'], $result['user_id'], 'Unexpected returned value'); - $this->assertEquals($data['user_name'], $result['user_name'], 'Unexpected returned value'); - $this->assertEquals($data['user_password'], $result['user_password'], 'Unexpected returned value'); - } - - /** - * Test getAll() - * - * Test fetching result data all at once. - */ - function testGetAll() - { - $result = $this->db->loadModule('Extended'); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error loading "Extended" module: '.$result->getMessage()); - } - - $data = array(); - $total_rows = 5; - - $stmt = $this->db->prepare('INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')', array_values($this->fields), MDB2_PREPARE_MANIP); - - for ($row = 0; $row < $total_rows; $row++) { - $data[$row] = $this->getSampleData($row); - $result = $stmt->execute(array_values($data[$row])); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error executing prepared query: '.$result->getMessage()); - } - } - $stmt->free(); - - //test getAll() with query parameters - $query = 'SELECT user_id, user_name, user_password FROM users WHERE user_id > ? ORDER BY user_id'; - $values = $this->db->extended->getAll($query, array('integer', 'text', 'text'), array(2), array('integer'), MDB2_FETCHMODE_ASSOC); - if (PEAR::isError($values)) { - $this->assertTrue(false, 'Error fetching the result set: '.$values->getMessage()); - } else { - $this->assertEquals(2, count($values), 'Error: incorrect number of returned rows'); - for ($i=0; $i<2; $i++) { - $this->assertEquals($data[$i+3]['user_id'], $values[$i]['user_id'], 'Unexpected returned value'); - $this->assertEquals($data[$i+3]['user_name'], $values[$i]['user_name'], 'Unexpected returned value'); - $this->assertEquals($data[$i+3]['user_password'], $values[$i]['user_password'], 'Unexpected returned value'); - } - } - - //test getAll() without query parameters - $query = 'SELECT user_id, user_name, user_password FROM users ORDER BY user_id'; - $values = $this->db->extended->getAll($query, array('integer', 'text', 'text'), null, null, MDB2_FETCHMODE_ASSOC); - if (PEAR::isError($values)) { - $this->assertTrue(false, 'Error fetching the result set: '.$values->getMessage()); - } else { - $this->assertEquals($total_rows, count($values), 'Error: incorrect number of returned rows'); - for ($i=0; $i<$total_rows; $i++) { - $this->assertEquals($data[$i]['user_id'], $values[$i]['user_id'], 'Unexpected returned value'); - $this->assertEquals($data[$i]['user_name'], $values[$i]['user_name'], 'Unexpected returned value'); - $this->assertEquals($data[$i]['user_password'], $values[$i]['user_password'], 'Unexpected returned value'); - } - } - } - - /** - * Test limitQuery() - * - * Test fetching a limited resultset. - */ - function testLimitQuery() - { - $result = $this->db->loadModule('Extended'); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error loading "Extended" module: '.$result->getMessage()); - } - - $data = array(); - $total_rows = 5; - - $stmt = $this->db->prepare('INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')', array_values($this->fields), MDB2_PREPARE_MANIP); - - for ($row = 0; $row < $total_rows; $row++) { - $data[$row] = $this->getSampleData($row); - $result = $stmt->execute(array_values($data[$row])); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error executing prepared query: '.$result->getMessage()); - } - } - $stmt->free(); - - $query = 'SELECT user_id, user_name, user_password FROM users ORDER BY user_id'; - $types = array('integer', 'text', 'text'); - - //test limitQuery() with offset = 0 - $result = $this->db->extended->limitQuery($query, $types, 2); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error executing limitQuery(): '.$result->getMessage()); - } - $values = $result->fetchAll(MDB2_FETCHMODE_ASSOC); - if (PEAR::isError($values)) { - $this->assertTrue(false, 'Error fetching the result set'); - } else { - $this->assertEquals(2, count($values), 'Error: incorrect number of returned rows'); - for ($i=0; $i<2; $i++) { - $this->assertEquals($data[$i]['user_id'], $values[$i]['user_id'], 'Unexpected returned value'); - $this->assertEquals($data[$i]['user_name'], $values[$i]['user_name'], 'Unexpected returned value'); - $this->assertEquals($data[$i]['user_password'], $values[$i]['user_password'], 'Unexpected returned value'); - } - } - $result->free(); - - //test limitQuery() with offset > 0 - $result = $this->db->extended->limitQuery($query, $types, 3, 2); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error executing limitQuery(): '.$result->getMessage()); - } - $values = $result->fetchAll(MDB2_FETCHMODE_ASSOC); - if (PEAR::isError($values)) { - $this->assertTrue(false, 'Error fetching the result set'); - } else { - $this->assertEquals(3, count($values), 'Error: incorrect number of returned rows'); - for ($i=0; $i<3; $i++) { - $this->assertEquals($data[$i+2]['user_id'], $values[$i]['user_id'], 'Unexpected returned value'); - $this->assertEquals($data[$i+2]['user_name'], $values[$i]['user_name'], 'Unexpected returned value'); - $this->assertEquals($data[$i+2]['user_password'], $values[$i]['user_password'], 'Unexpected returned value'); - } - } - $result->free(); - } - - /** - * Test execParam() - * - * Test executing a query with parameters - */ - function testExecParam() - { - $result = $this->db->loadModule('Extended'); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error loading "Extended" module: '.$result->getMessage()); - } - - $data = $this->getSampleData(1234); - - $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')'; - - $result = $this->db->extended->execParam($query, array_values($data), $this->fields); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error executing execParam(): '.$result->getMessage()); - } - - $query = 'SELECT user_id, user_name, user_password FROM users WHERE user_id=?'; - $result = $this->db->extended->getRow($query, array('integer', 'text', 'text'), array(1234), array('integer'), MDB2_FETCHMODE_ASSOC); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error executing getRow(): '.$result->getMessage()); - } - $this->assertEquals($data['user_id'], $result['user_id'], 'Unexpected returned value'); - $this->assertEquals($data['user_name'], $result['user_name'], 'Unexpected returned value'); - $this->assertEquals($data['user_password'], $result['user_password'], 'Unexpected returned value'); - } - - /** - * Test executeMultiple() - * - * Test executing multiple prepared queries - */ - function testExecuteMultiple() - { - $result = $this->db->loadModule('Extended'); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error loading "Extended" module: '.$result->getMessage()); - } - - $data = array(); - $total_rows = 5; - - for ($row = 0; $row < $total_rows; $row++) { - $data[$row] = array_values($this->getSampleData($row)); - } - - $stmt = $this->db->prepare('INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')'); - $result = $this->db->extended->executeMultiple($stmt, $data); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error executing executeMultiple(): '.$result->getMessage()); - } - $stmt->free(); - - $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users'; - $values = $this->db->queryAll($query, $this->fields, MDB2_FETCHMODE_ORDERED); - - $n_fields = count($this->fields); - for ($i=0; $i<$total_rows; $i++) { - for ($field=0; $field<$n_fields; $field++) { - $this->assertEquals(strval($data[$i][$field]), strval($values[$i][$field]), 'Unexpected returned value'); - } - } - } -} -?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/tests/MDB2_function_testcase.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/tests/MDB2_function_testcase.php --- php-mdb2-2.4.1/MDB2-2.4.1/tests/MDB2_function_testcase.php 2007-05-03 19:58:15.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.4.1/tests/MDB2_function_testcase.php 1970-01-01 01:00:00.000000000 +0100 @@ -1,229 +0,0 @@ - | -// +----------------------------------------------------------------------+ -// -// $Id: MDB2_function_testcase.php,v 1.20 2006/08/07 20:15:57 lsmith Exp $ - -class MDB2_Function_TestCase extends MDB2_TestCase -{ - function setUp() { - parent::setUp(); - $this->db->loadModule('Function', null, true); - } - - /** - * Test functionTable() - */ - function testFunctionTable() - { - if (!$this->methodExists($this->db->function, 'functionTable')) { - return; - } - - $functionTable_clause = $this->db->function->functionTable(); - $query = 'SELECT 1 '.$functionTable_clause; - $result = $this->db->queryOne($query); - if (PEAR::isError($result)) { - $this->assertFalse(true, 'Error fetching from function table'); - } else { - $this->assertEquals('1', $result, 'Error fetching value from function table'); - } - } - - /** - * Test now() - */ - function testNow() - { - if (!$this->methodExists($this->db->function, 'now')) { - return; - } - - $tests = array( - 'timestamp' => '/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/', - 'date' => '/^\d{4}-\d{2}-\d{2}$/', - 'time' => '/^\d{2}:\d{2}:\d{2}$/', - ); - - foreach ($tests as $type => $regexp) { - $functionTable_clause = $this->db->function->functionTable(); - $now_clause = $this->db->function->now($type); - $query = 'SELECT '.$now_clause . $functionTable_clause; - $result = $this->db->queryOne($query, $type); - if (PEAR::isError($result)) { - $this->assertFalse(true, 'Error getting '.$type); - } else { - $this->assertRegExp($regexp, $result, 'Error: not a proper '.$type); - } - } - } - - /** - * Test substring() - */ - function testSubstring() - { - if (!$this->methodExists($this->db->function, 'substring')) { - return; - } - $data = $this->getSampleData(1234); - - $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')'; - $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP); - - $result = $stmt->execute(array_values($data)); - $stmt->free(); - - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error executing prepared query'.$result->getMessage()); - } - - $substring_clause = $this->db->function->substring('user_name', 1, 4); - $query = 'SELECT '.$substring_clause .' FROM users'; - $result = $this->db->queryOne($query); - if (PEAR::isError($result)) { - $this->assertFalse(true, 'Error getting substring'); - } else { - $this->assertEquals('user', $result, 'Error: substrings not equals'); - } - - $substring_clause = $this->db->function->substring('user_name', 5, 1); - $query = 'SELECT '.$substring_clause .' FROM users'; - $result = $this->db->queryOne($query); - if (PEAR::isError($result)) { - $this->assertFalse(true, 'Error getting substring'); - } else { - $this->assertEquals('_', $result, 'Error: substrings not equals'); - } - - //test NULL 2nd parameter - $substring_clause = $this->db->function->substring('user_name', 6); - $query = 'SELECT '.$substring_clause .' FROM users'; - $result = $this->db->queryOne($query); - if (PEAR::isError($result)) { - $this->assertFalse(true, 'Error getting substring'); - } else { - $this->assertEquals('1234', $result, 'Error: substrings not equals'); - } - } - - /** - * Test concat() - */ - function testConcat() - { - if (!$this->methodExists($this->db->function, 'concat')) { - return; - } - - $functionTable_clause = $this->db->function->functionTable(); - $concat_clause = $this->db->function->concat($this->db->quote('time', 'text'), $this->db->quote('stamp', 'text')); - $query = 'SELECT '.$concat_clause . $functionTable_clause; - $result = $this->db->queryOne($query); - if (PEAR::isError($result)) { - $this->assertFalse(true, 'Error getting concat'); - } else { - $this->assertEquals('timestamp', $result, 'Error: could not concatenate "time+stamp"'); - } - } - - /** - * Test random() - */ - function testRandom() - { - if (!$this->methodExists($this->db->function, 'random')) { - return; - } - - $rand_clause = $this->db->function->random(); - $functionTable_clause = $this->db->function->functionTable(); - $query = 'SELECT '.$rand_clause . $functionTable_clause; - $result = $this->db->queryOne($query, 'float'); - if (PEAR::isError($result)) { - $this->assertFalse(true, 'Error getting random value:'. $result->getMessage()); - } else { - $this->assertTrue(($result >= 0 && $result <= 1), 'Error: could not get random value between 0 and 1: '.$result); - } - } - - /** - * Test lower() - */ - function testLower() - { - if (!$this->methodExists($this->db->function, 'lower')) { - return; - } - $string = $this->db->quote('FoO'); - $lower_clause = $this->db->function->lower($string); - $functionTable_clause = $this->db->function->functionTable(); - $query = 'SELECT '.$lower_clause . $functionTable_clause; - $result = $this->db->queryOne($query, 'text'); - if (PEAR::isError($result)) { - $this->assertFalse(true, 'Error getting lower case value:'. $result->getMessage()); - } else { - $this->assertTrue(($result === 'foo'), 'Error: could not lower case "FoO": '.$result); - } - } - - /** - * Test upper() - */ - function testUpper() - { - if (!$this->methodExists($this->db->function, 'upper')) { - return; - } - $string = $this->db->quote('FoO'); - $upper_clause = $this->db->function->upper($string); - $functionTable_clause = $this->db->function->functionTable(); - $query = 'SELECT '.$upper_clause . $functionTable_clause; - $result = $this->db->queryOne($query, 'text'); - if (PEAR::isError($result)) { - $this->assertFalse(true, 'Error getting upper case value:'. $result->getMessage()); - } else { - $this->assertTrue(($result === 'FOO'), 'Error: could not upper case "FoO": '.$result); - } - } -} -?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/tests/MDB2_internals_testcase.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/tests/MDB2_internals_testcase.php --- php-mdb2-2.4.1/MDB2-2.4.1/tests/MDB2_internals_testcase.php 2007-05-03 19:58:15.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.4.1/tests/MDB2_internals_testcase.php 1970-01-01 01:00:00.000000000 +0100 @@ -1,548 +0,0 @@ - | -// | Andrew Hill | -// +----------------------------------------------------------------------+ -// -// $Id: MDB2_internals_testcase.php,v 1.1 2007/03/02 16:39:22 quipo Exp $ - -require_once 'MDB2_testcase.php'; - -class MDB2_Internals_TestCase extends MDB2_TestCase { - - var $clear_tables = false; - - /** - * Tests that the MDB2::apiVersion() method returns an API version number. - */ - function test_apiVersion() - { - $result = MDB2::apiVersion(); - $this->assertNotNull($result, 'apiVersion'); - $result = strtok($result, '.'); - $this->assertTrue(is_numeric($result), 'apiVersion'); - $result = strtok('.'); - $this->assertTrue(is_numeric($result), 'apiVersion'); - $result = strtok('.'); - $this->assertTrue(is_numeric($result), 'apiVersion'); - } - - /** - * Tests that the MDB2::classExists() method correctly tests for - * existence of a class. - */ - function test_classExists() - { - $this->assertFalse(MDB2::classExists('null'), 'classExists'); - $this->assertTrue(MDB2::classExists('MDB2'), 'classExists'); - } - - /** - * Tests that the MDB2::loadClass() method correctly loads classes. - */ - function test_loadClass() - { - $this->assertTrue(MDB2::loadClass('MDB2', false), 'loadClass'); - // Suppress handling of PEAR errors while testing next case - PEAR::pushErrorHandling(null); - $result = MDB2::loadClass('null', false); - $this->assertTrue(is_a($result, 'pear_error'), 'loadClass'); - PEAR::popErrorHandling(); - } - - /** - * Tests that the MDB2::factory() method correctly connects to a - * database. - */ - function test_factory() - { - $db =& MDB2::factory($this->dsn); - $this->assertTrue(MDB2::isConnection($db), 'factory'); - // Suppress handling of PEAR errors while preparing the - // next test case database connection - PEAR::pushErrorHandling(null); - $db =& MDB2::factory(null); - PEAR::popErrorHandling(); - $this->assertFalse(MDB2::isConnection($db), 'factory'); - } - - /** - * Tests that the MDB2::loadFile() method returns the expected - * filename. - */ - function test_loadFile() - { - $filename = 'Extended'; - $this->assertEquals('MDB2'.DIRECTORY_SEPARATOR.$filename.'.php', MDB2::loadFile($filename), 'loadFile'); - } - - /** - * Tests that the MDB2::isConnection() method correctly reports - * connections. - */ - function test_isConnection() - { - $this->assertTrue(MDB2::isConnection($this->db), 'isConnection'); - $this->assertFalse(MDB2::isConnection(null), 'isConnection'); - } - - /** - * Tests that the MDB2::isResult() method correctly identifies - * results. - */ - function test_isResult() - { - $obj = new MDB2_Result(); - $this->assertTrue(MDB2::isResult($obj), 'isResult'); - $obj = null; - $this->assertFalse(MDB2::isResult($obj), 'isResult'); - } - - /** - * Tests that the MDB2::isResultCommon() method correctly identifies - * common results. - */ - function test_isResultCommon() - { - $result = null; - $obj = new MDB2_Result_Common($this->db, $result); - $this->assertTrue(MDB2::isResultCommon($obj), 'isResultCommon'); - $obj = null; - $this->assertFalse(MDB2::isResultCommon($obj), 'isResultCommon'); - } - - /** - * Tests that the MDB2::parseDSN() method works. - */ - function test_parseDSN() - { - $dsn = $this->dsn; - $result = MDB2::parseDSN($dsn); - $this->assertEquals($dsn['phptype'],$result['dbsyntax'],'parseDSN'); - - $dsn = "mydbms://myname:mypassword@localhost"; - $result = MDB2::parseDSN($dsn); - $this->assertEquals('mydbms', $result['phptype'],'parseDSN'); - $this->assertEquals('mydbms',$result['dbsyntax'],'parseDSN'); - $this->assertEquals('tcp',$result['protocol'],'parseDSN'); - $this->assertEquals('localhost',$result['hostspec'],'parseDSN'); - $this->assertEquals(false,$result['port'],'parseDSN'); - $this->assertEquals(false,$result['socket'],'parseDSN'); - $this->assertEquals('myname',$result['username'],'parseDSN'); - $this->assertEquals('mypassword',$result['password'],'parseDSN'); - $this->assertEquals(false,$result['database'],'parseDSN'); - - $dsn = "somesql://myname:mypassword@localhost:1234/mydb"; - $result = MDB2::parseDSN($dsn); - $this->assertEquals('somesql',$result['phptype'],'parseDSN'); - $this->assertEquals('somesql',$result['dbsyntax'],'parseDSN'); - $this->assertEquals('tcp',$result['protocol'],'parseDSN'); - $this->assertEquals('localhost',$result['hostspec'],'parseDSN'); - $this->assertEquals('1234',$result['port'],'parseDSN'); - $this->assertEquals(false,$result['socket'],'parseDSN'); - $this->assertEquals('myname',$result['username'],'parseDSN'); - $this->assertEquals('mypassword',$result['password'],'parseDSN'); - $this->assertEquals('mydb',$result['database'],'parseDSN'); - - $dsn = "dbms1://myname@unix(opts)/mydb?param1=value1"; - $result = MDB2::parseDSN($dsn); - $this->assertEquals('dbms1',$result['phptype'],'parseDSN'); - $this->assertEquals('dbms1',$result['dbsyntax'],'parseDSN'); - $this->assertEquals('unix',$result['protocol'],'parseDSN'); - $this->assertEquals(false,$result['hostspec'],'parseDSN'); - $this->assertEquals(false,$result['port'],'parseDSN'); - $this->assertEquals('opts',$result['socket'],'parseDSN'); - $this->assertEquals('myname',$result['username'],'parseDSN'); - $this->assertEquals(false,$result['password'],'parseDSN'); - $this->assertEquals('mydb',$result['database'],'parseDSN'); - $this->assertEquals('value1',$result['param1'],'parseDSN'); - } - - /** - * Tests that the MDB2::fileExists() method correctly identifies - * existing/non-existing files. - */ - function test_fileExists() - { - $this->assertTrue(MDB2::fileExists('PEAR.php'), 'fileExists'); - $this->assertFalse(MDB2::fileExists('itIsHopedThatNoOneHasAFileWithThisName.php'), 'fileExists'); - } - - /** - * Tests that the MDB2::__toString() method returns the expected - * string result. - */ - function test__toString() - { - $expected = "MDB2_Driver_{$this->dsn['phptype']}: (phptype = {$this->dsn['phptype']}, dbsyntax = {$this->db->dbsyntax})"; - if (version_compare(PHP_VERSION, "5.0.0", "<")) { - $expected = strtolower($expected); - } - $this->assertEquals($expected ,$this->db->__toString(), '__toString'); - } - - /** - * Tests that the MDB2::setFetchMode() method correctly sets the - * fetch mode. - */ - function test_setFetchMode() - { - $tmp = $this->db->fetchmode; - $this->db->setFetchMode(MDB2_FETCHMODE_OBJECT); - $this->assertEquals('stdClass', $this->db->options['fetch_class'], 'setFetchMode'); - $this->db->setFetchMode(MDB2_FETCHMODE_ORDERED); - $this->assertEquals(MDB2_FETCHMODE_ORDERED, $this->db->fetchmode, 'setFetchMode'); - $this->db->setFetchMode(MDB2_FETCHMODE_ASSOC); - $this->assertEquals(MDB2_FETCHMODE_ASSOC, $this->db->fetchmode, 'setFetchMode'); - $this->db->fetchmode = $tmp; - } - - /** - * Tests that the MDB2::escape() method correctly escapes strings. - */ - function test_escape() - { - $tmp = $this->db->string_quoting; - $this->string_quoting['escape'] = '\\'; - $this->string_quoting['end'] = '"'; - $text = 'xxx"z"xxx'; - $this->assertEquals('xxx\"z\"xxx', MDB2_Driver_Common::escape($text), 'escape'); - $this->db->string_quoting = $tmp; - } - - /** - * Tests that the MDB2::quoteIdentifier() method correctly quotes strings. - */ - function test_quoteIdentifier() - { - if ($this->db->phptype == 'ibase') { - return; - } - $tmp = $this->db->identifier_quoting; - $this->db->identifier_quoting['start'] = '"'; - $this->db->identifier_quoting['end'] = '`'; - $this->db->identifier_quoting['escape'] = '/'; - $text = 'my`identifier'; - $this->assertEquals('"my/`identifier`', $this->db->quoteIdentifier($text), 'quoteIdentifier'); - $this->db->identifier_quoting = $tmp; - } - - /** - * Tests that the MDB2::getAsKeyword() method correctly returns - * the set "as" keyword. - */ - function test_getAsKeyword() - { - $tmp = $this->db->as_keyword; - $this->db->as_keyword = 'ALIAS'; - $this->assertEquals('ALIAS', $this->db->getAsKeyword(), 'getAsKeyword'); - $this->db->as_keyword = $tmp; - } - - /** - * Tests that the MDB2::getConnection() method correctly returns - * a database resource. - */ - function test_getConnection() - { - $result = $this->db->getConnection(); - $this->assertTrue(is_resource($result), 'getConnection'); - } - - /** - * A private method to return a defined "row" of data for use - * in the next set of tests. - * - * @access private - * @return array The array of "row" data. - */ - function _fetchRowData() - { - return array( - 0 => '', - 1 => 'notnull', - 2 => 'length7 ', - '1?2:3.4' => 'assoc' - ); - } - - /** - * A private method to test results from the MDB2::_fixResultArrayValues() - * method when the $mode parameter was set to MDB2_PORTABILITY_EMPTY_TO_NULL. - * - * @access private - * @param array $row The result of the call to MDB2::_fixResultArrayValues(). - */ - function _fixResultArrayValues_Test_EmptyToNull($row) - { - $this->assertNull($row[0], '_fixResultArrayValues'); - $this->assertNotNull($row[1], '_fixResultArrayValues'); - $this->assertNotNull($row[2], '_fixResultArrayValues'); - } - - /** - * A private method to test results from the MDB2::_fixResultArrayValues() - * method when the $mode parameter was set to MDB2_PORTABILITY_RTRIM. - * - * @access private - * @param array $row The result of the call to MDB2::_fixResultArrayValues(). - */ - function _fixResultArrayValues_Test_Rtrim($row) - { - $this->assertEquals(strlen($row[0]), 0, '_fixResultArrayValues'); - $this->assertEquals(strlen($row[1]), 7, '_fixResultArrayValues'); - $this->assertEquals(strlen($row[2]), 7, '_fixResultArrayValues'); - } - - /** - * A private method to test results from the MDB2::_fixResultArrayValues() - * method when the $mode parameter was set to MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES. - * - * @access private - * @param array $row The result of the call to MDB2::_fixResultArrayValues(). - */ - function _fixResultArrayValues_Test_FixAssocFieldNames($row) - { - $this->assertTrue(array_key_exists(4, $row), '_fixResultArrayValues'); - $this->assertTrue($row[4] == 'assoc', '_fixResultArrayValues'); - } - - /** - * Tests that the MDB2::_fixResultArrayValues() method fixes array - * values when used with various $mode parameters. - */ - function test__fixResultArrayValues() - { - $mode = MDB2_PORTABILITY_EMPTY_TO_NULL; - $row = $this->_fetchRowData(); - $this->db->_fixResultArrayValues($row, $mode); - $this->_fixResultArrayValues_Test_EmptyToNull($row); - - $mode = MDB2_PORTABILITY_RTRIM; - $row = $this->_fetchRowData(); - $this->db->_fixResultArrayValues($row, $mode); - $this->_fixResultArrayValues_Test_Rtrim($row); - - $mode = MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES; - $row = $this->_fetchRowData(); - $this->db->_fixResultArrayValues($row, $mode); - $this->_fixResultArrayValues_Test_FixAssocFieldNames($row); - - $mode = MDB2_PORTABILITY_EMPTY_TO_NULL + MDB2_PORTABILITY_RTRIM; - $row = $this->_fetchRowData(); - $this->db->_fixResultArrayValues($row, $mode); - $this->_fixResultArrayValues_Test_EmptyToNull($row); - $this->_fixResultArrayValues_Test_Rtrim($row); - - $mode = MDB2_PORTABILITY_EMPTY_TO_NULL + MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES; - $row = $this->_fetchRowData(); - $this->db->_fixResultArrayValues($row, $mode); - $this->_fixResultArrayValues_Test_EmptyToNull($row); - $this->_fixResultArrayValues_Test_FixAssocFieldNames($row); - - $mode = MDB2_PORTABILITY_RTRIM + MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES; - $row = $this->_fetchRowData(); - $this->db->_fixResultArrayValues($row, $mode); - $this->_fixResultArrayValues_Test_Rtrim($row); - $this->_fixResultArrayValues_Test_FixAssocFieldNames($row); - - $mode = MDB2_PORTABILITY_EMPTY_TO_NULL + MDB2_PORTABILITY_RTRIM + MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES; - $row = $this->_fetchRowData(); - $this->db->_fixResultArrayValues($row, $mode); - $this->_fixResultArrayValues_Test_EmptyToNull($row); - $this->_fixResultArrayValues_Test_Rtrim($row); - $this->_fixResultArrayValues_Test_FixAssocFieldNames($row); - } - - /** - * Tests that the MDB2::transaction() method returns expected values - * when starting or rolling back a transaction, and for testing if - * the connection is in a transaction. - */ - function test_transaction() - { - if (!$this->db->supports('transactions')) - { - $this->assertTrue($this->db->beginTransaction(), 'transaction'); - $this->assertTrue($this->db->in_transaction, 'transaction'); - $this->assertTrue($this->db->rollback(), 'transaction'); - $this->assertFalse($this->db->in_transaction, 'transaction'); - - $this->assertTrue($this->db->beginTransaction(), 'transaction'); - $this->assertTrue($this->db->in_transaction, 'transaction'); - $this->assertTrue($this->db->commit(), 'transaction'); - $this->assertFalse($this->db->in_transaction, 'transaction'); - } - } - - // Nested transactions are not yet tested, due to a MySQL 5 problem with - // savepoints causing netsted transactions to fail. - // - // See http://bugs.mysql.com/bug.php?id=26288 - - /** - * Tests that the MDB2::setDatabase() and MDB2::getDatabase() methods - * correctly set and get the database name. - */ - function test_setGetDatabase() - { - $old_name = $this->db->database_name; - $this->assertEquals($old_name, $this->db->setDatabase('test_database'), 'setDatabase'); - $this->assertEquals('test_database', $this->db->database_name, 'setDatabase'); - $this->assertEquals('test_database', $this->db->getDatabase(), 'getDatabase'); - $this->db->database_name = $old_name; - } - - /** - * Tests that the MDB2::setDSN() method correctly sets - * the DSN. - */ - function test_setDSN() - { - $dsn = "mydbms://myname:mypassword@localhost"; - $result = $this->db->setDSN($dsn); - $dsn_set = $this->db->dsn; - - $this->assertEquals('mydbms', $dsn_set['phptype'],'setDSN'); - $this->assertEquals('mydbms',$dsn_set['dbsyntax'],'setDSN'); - $this->assertEquals('tcp',$dsn_set['protocol'],'setDSN'); - $this->assertEquals('localhost',$dsn_set['hostspec'],'setDSN'); - $this->assertEquals(false,$dsn_set['port'],'setDSN'); - $this->assertEquals(false,$dsn_set['socket'],'setDSN'); - $this->assertEquals('myname',$dsn_set['username'],'setDSN'); - $this->assertEquals('mypassword',$dsn_set['password'],'setDSN'); - $this->assertEquals(false,$dsn_set['database'],'setDSN'); - } - - /** - * Tests that the MDB2::getDSN() method correctly gets - * the DSN. - */ - function test_getDSN() - { - $dsn_set = "mydbms://myname:mypassword@localhost"; - $result = $this->db->setDSN($dsn_set); - $dsn_get = $this->db->getDSN(); - $dsn_rex = "/(([\w]+)\(mydbms\):\/\/myname:mypassword@localhost\/)/"; - //preg_match($dsn_rex, $dsn_get, $matches); - $this->assertRegExp($dsn_rex, $dsn_get, 'testGetDSN'); - $dsn_rex = "/{$this->dsn['phptype']}[\w\W]+/"; - $this->assertRegExp($dsn_rex, $dsn_get, 'testGetDSN'); - - $dsn_set = "mydbms://myname:mypassword@localhost"; - $result = $this->db->setDSN($dsn_set); - $dsn_get = $this->db->getDSN('string', true); - $dsn_rex = "/(([\w]+)\(mydbms\):\/\/myname:1@localhost\/)/"; - $this->assertRegExp($dsn_rex, $dsn_get, 'testGetDSN'); - $dsn_rex = "/{$this->dsn['phptype']}[\w\W]+/"; - $this->assertRegExp($dsn_rex, $dsn_get, 'testGetDSN'); - - } - - /** - * Tests that the MDB2::setLimit() method correctly sets the limit - * and offset values. - */ - function test_setLimit() - { - if (!$this->db->supports('limit_queries')) - { - $this->db->limit = null; - $this->db->offset = null; - $this->db->setLimit(100, 50); - $this->assertEquals(100, $this->db->limit , 'setLimit'); - $this->assertEquals( 50, $this->db->offset, 'setLimit'); - } - } - - /** - * Tests that the MDB2::supports() method correctly finds keys - * in the "supports" array. - */ - function test_supports() - { - $this->db->supports['testkey'] = true; - $this->assertTrue($this->db->supports('testkey'), 'supports'); - unset($this->db->supports['testkey']); - } - - /** - * Tests that the MDB2::getSequenceName() method correctly gets - * sequence names. - */ - function test_getSequenceName() - { - $tmp = $this->db->options['seqname_format']; - $this->db->options['seqname_format'] = '%s_seq'; - $this->assertEquals('test_seq', strtolower($this->db->getSequenceName('test')), 'getSequenceName'); - $this->db->options['seqname_format'] = $tmp; - } - - /** - * Tests that the MDB2::getIndexName() method correctly gets - * index names. - */ - function test_getIndexName() - { - $tmp = $this->db->options['idxname_format']; - $this->db->options['idxname_format'] = 'idx_%s'; - $this->assertEquals('idx_test', $this->db->getIndexName('test'), 'getIndexName'); - $this->db->options['idxname_format'] = $tmp; - } - - /** - * Tests that the MDB2::disconnect() method correctly disconnects. - */ - function test_disconnect() - { - $this->assertTrue($this->db->disconnect(), 'disconnect'); - $this->assertEquals(0, $this->db->connection, 'disconnect'); - $this->assertEquals(array(), $this->db->connected_dsn, 'disconnect'); - $this->assertEquals('', $this->db->connected_database_name, 'disconnect'); - $this->assertNull($this->db->opened_persistent, 'disconnect'); - $this->assertEquals('', $this->db->connected_server_info, 'disconnect'); - $this->assertNull($this->db->in_transaction, 'disconnect'); - $this->assertNull($this->db->nested_transaction_counter, 'disconnect'); - } - -} - -?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/tests/MDB2_manager_testcase.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/tests/MDB2_manager_testcase.php --- php-mdb2-2.4.1/MDB2-2.4.1/tests/MDB2_manager_testcase.php 2007-05-03 19:58:15.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.4.1/tests/MDB2_manager_testcase.php 1970-01-01 01:00:00.000000000 +0100 @@ -1,708 +0,0 @@ - | -// | Lorenzo Alberton | -// +----------------------------------------------------------------------+ -// -// $Id: MDB2_manager_testcase.php,v 1.55 2007/03/05 01:28:13 quipo Exp $ - -require_once 'MDB2_testcase.php'; - -class MDB2_Manager_TestCase extends MDB2_TestCase { - //test table name (it is dynamically created/dropped) - var $table = 'newtable'; - - function setUp() { - parent::setUp(); - $this->db->loadModule('Manager', null, true); - $this->fields = array( - 'id' => array( - 'type' => 'integer', - 'unsigned' => true, - 'notnull' => true, - 'default' => 0, - ), - 'somename' => array( - 'type' => 'text', - 'length' => 12, - ), - 'somedescription' => array( - 'type' => 'text', - 'length' => 12, - ), - 'sex' => array( - 'type' => 'text', - 'length' => 1, - 'default' => 'M', - ), - ); - if (!$this->tableExists($this->table)) { - $this->db->manager->createTable($this->table, $this->fields); - } - } - - function tearDown() { - if ($this->tableExists($this->table)) { - $this->db->manager->dropTable($this->table); - } - $this->db->popExpect(); - unset($this->dsn); - if (!PEAR::isError($this->db->manager)) { - $this->db->disconnect(); - } - unset($this->db); - } - - /** - * Create a sample table, test the new fields, and drop it. - */ - function testCreateTable() { - if (!$this->methodExists($this->db->manager, 'createTable')) { - return; - } - if ($this->tableExists($this->table)) { - $this->db->manager->dropTable($this->table); - } - - $result = $this->db->manager->createTable($this->table, $this->fields); - $this->assertFalse(PEAR::isError($result), 'Error creating table'); - } - - /** - * Create a sample table, test the new fields, and drop it. - */ - function testCreateAutoIncrementTable() { - if (!$this->methodExists($this->db->manager, 'createTable')) { - return; - } - if ($this->tableExists($this->table)) { - $this->db->manager->dropTable($this->table); - } - - $fields = $this->fields; - $fields['id']['autoincrement'] = true; - $result = $this->db->manager->createTable($this->table, $fields); - $this->assertFalse(PEAR::isError($result), 'Error creating table'); - $query = 'INSERT INTO '.$this->table; - $query.= ' (somename, somedescription)'; - $query.= ' VALUES (:somename, :somedescription)'; - $stmt =& $this->db->prepare($query, array('text', 'text'), MDB2_PREPARE_MANIP); - if (PEAR::isError($stmt)) { - $this->assertTrue(true, 'Preparing insert'); - return; - } - $values = array( - 'somename' => 'foo', - 'somedescription' => 'bar', - ); - $rows = 5; - for ($i =0; $i < $rows; ++$i) { - $result = $stmt->execute($values); - if (PEAR::isError($result)) { - $this->assertFalse(true, 'Error executing autoincrementing insert number: '.$i); - return; - } - } - $stmt->free(); - $query = 'SELECT id FROM '.$this->table; - $data = $this->db->queryCol($query); - if (PEAR::isError($data)) { - $this->assertTrue(true, 'Error executing select'); - return; - } - for ($i =0; $i < $rows; ++$i) { - if (!isset($data[$i])) { - $this->assertTrue(true, 'Error in data returned by select'); - return; - } - if ($data[$i] === ($i+1)) { - $this->assertTrue(true, 'Error executing autoincrementing insert'); - return; - } - } - } - - /** - * - */ - function testListTableFields() { - if (!$this->methodExists($this->db->manager, 'listTableFields')) { - return; - } - $this->assertEquals( - array_keys($this->fields), - $this->db->manager->listTableFields($this->table), - 'Error creating table: incorrect fields' - ); - } - - /** - * - */ - function testCreateIndex() { - if (!$this->methodExists($this->db->manager, 'createIndex')) { - return; - } - $index = array( - 'fields' => array( - 'somename' => array( - 'sorting' => 'ascending', - ), - ), - ); - $name = 'simpleindex'; - $result = $this->db->manager->createIndex($this->table, $name, $index); - $this->assertFalse(PEAR::isError($result), 'Error creating index'); - } - - /** - * - */ - function testDropIndex() { - if (!$this->methodExists($this->db->manager, 'dropIndex')) { - return; - } - $index = array( - 'fields' => array( - 'somename' => array( - 'sorting' => 'ascending', - ), - ), - ); - $name = 'simpleindex'; - $result = $this->db->manager->createIndex($this->table, $name, $index); - if (PEAR::isError($result)) { - $this->assertFalse(true, 'Error creating index'); - } else { - $result = $this->db->manager->dropIndex($this->table, $name); - $this->assertFalse(PEAR::isError($result), 'Error dropping index'); - $indices = $this->db->manager->listTableIndexes($this->table); - $this->assertFalse(PEAR::isError($indices), 'Error listing indices'); - $this->assertFalse(in_array($name, $indices), 'Error dropping index'); - } - } - - /** - * - */ - function testListIndexes() { - if (!$this->methodExists($this->db->manager, 'listTableIndexes')) { - return; - } - $index = array( - 'fields' => array( - 'somename' => array( - 'sorting' => 'ascending', - ), - ), - ); - $name = 'simpleindex'; - $result = $this->db->manager->createIndex($this->table, $name, $index); - if (PEAR::isError($result)) { - $this->assertFalse(true, 'Error creating index'); - } else { - $indices = $this->db->manager->listTableIndexes($this->table); - $this->assertFalse(PEAR::isError($indices), 'Error listing indices'); - $this->assertTrue(in_array($name, $indices), 'Error listing indices'); - } - } - - /** - * - */ - function testCreatePrimaryKey() { - if (!$this->methodExists($this->db->manager, 'createConstraint')) { - return; - } - $index = array( - 'fields' => array( - 'id' => array( - 'sorting' => 'ascending', - ), - ), - 'primary' => true, - ); - $name = 'pkindex'; - $result = $this->db->manager->createConstraint($this->table, $name, $index); - $this->assertFalse(PEAR::isError($result), 'Error creating primary index'); - } - - /** - * - */ - function testCreateUniqueConstraint() { - if (!$this->methodExists($this->db->manager, 'createConstraint')) { - return; - } - $index = array( - 'fields' => array( - 'somename' => array( - 'sorting' => 'ascending', - ), - ), - 'unique' => true, - ); - $name = 'uniqueindex'; - $result = $this->db->manager->createConstraint($this->table, $name, $index); - $this->assertFalse(PEAR::isError($result), 'Error creating unique index'); - } - - /** - * - */ - function testDropPrimaryKey() { - if (!$this->methodExists($this->db->manager, 'dropConstraint')) { - return; - } - $index = array( - 'fields' => array( - 'id' => array( - 'sorting' => 'ascending', - ), - ), - 'primary' => true, - ); - $name = 'pkindex'; - $result = $this->db->manager->createConstraint($this->table, $name, $index); - if (PEAR::isError($result)) { - $this->assertFalse(true, 'Error creating primary index'); - } else { - $result = $this->db->manager->dropConstraint($this->table, $name, true); - $this->assertFalse(PEAR::isError($result), 'Error dropping primary key index'); - } - } - - /** - * - */ - function testListConstraints() { - if (!$this->methodExists($this->db->manager, 'listTableConstraints')) { - return; - } - $index = array( - 'fields' => array( - 'id' => array( - 'sorting' => 'ascending', - ), - ), - 'unique' => true, - ); - $name = 'uniqueindex'; - $result = $this->db->manager->createConstraint($this->table, $name, $index); - if (PEAR::isError($result)) { - $this->assertFalse(true, 'Error creating unique constraint'); - } else { - $constraints = $this->db->manager->listTableConstraints($this->table); - $this->assertFalse(PEAR::isError($constraints), 'Error listing constraints'); - $this->assertTrue(in_array($name, $constraints), 'Error listing unique key index'); - } - } - - /** - * - */ - function testListTables() { - if (!$this->methodExists($this->db->manager, 'listTables')) { - return; - } - $this->assertTrue($this->tableExists($this->table), 'Error listing tables'); - } - - /** - * - */ - function testAlterTable() { - if (!$this->methodExists($this->db->manager, 'alterTable')) { - return; - } - $newer = 'newertable'; - if ($this->tableExists($newer)) { - $this->db->manager->dropTable($newer); - } - $changes = array( - 'add' => array( - 'quota' => array( - 'type' => 'integer', - 'unsigned' => 1, - ), - 'note' => array( - 'type' => 'text', - 'length' => '20', - ), - ), - 'rename' => array( - 'sex' => array( - 'name' => 'gender', - 'definition' => array( - 'type' => 'text', - 'length' => 1, - 'default' => 'M', - ), - ), - ), - 'change' => array( - 'id' => array( - 'unsigned' => false, - 'definition' => array( - 'type' => 'integer', - 'notnull' => false, - 'default' => 0, - ), - ), - 'somename' => array( - 'length' => '20', - 'definition' => array( - 'type' => 'text', - 'length' => 20, - ), - ) - ), - 'remove' => array( - 'somedescription' => array(), - ), - 'name' => $newer, - ); - - $this->db->expectError(MDB2_ERROR_CANNOT_ALTER); - $result = $this->db->manager->alterTable($this->table, $changes, true); - $this->db->popExpect(); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Cannot alter table'); - } else { - $result = $this->db->manager->alterTable($this->table, $changes, false); - if (PEAR::isError($result)) { - $this->assertTrue(true, 'Error altering table'); - } else { - $this->db->manager->dropTable($newer); - } - } - } - - /** - * - */ - function testAlterTable2() { - if (!$this->methodExists($this->db->manager, 'alterTable')) { - return; - } - $newer = 'newertable2'; - if ($this->tableExists($newer)) { - $this->db->manager->dropTable($newer); - } - $changes_all = array( - 'add' => array( - 'quota' => array( - 'type' => 'integer', - 'unsigned' => 1, - ), - ), - 'rename' => array( - 'sex' => array( - 'name' => 'gender', - 'definition' => array( - 'type' => 'text', - 'length' => 1, - 'default' => 'M', - ), - ), - ), - 'change' => array( - 'somename' => array( - 'length' => '20', - 'definition' => array( - 'type' => 'text', - 'length' => 20, - ), - ) - ), - 'remove' => array( - 'somedescription' => array(), - ), - 'name' => $newer, - ); - - foreach ($changes_all as $type => $change) { - $changes = array($type => $change); - $this->db->expectError(MDB2_ERROR_CANNOT_ALTER); - $result = $this->db->manager->alterTable($this->table, $changes, true); - $this->db->popExpect(); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Cannot alter table: '.$type); - } else { - $result = $this->db->manager->alterTable($this->table, $changes, false); - if (PEAR::isError($result)) { - $this->assertTrue(true, 'Error altering table: '.$type); - } else { - switch ($type) { - case 'add': - $altered_table_fields = $this->db->manager->listTableFields($this->table); - foreach ($change as $newfield => $dummy) { - $this->assertTrue(in_array($newfield, $altered_table_fields), 'Error: new field "'.$newfield.'" not added'); - } - break; - case 'rename': - $altered_table_fields = $this->db->manager->listTableFields($this->table); - foreach ($change as $oldfield => $newfield) { - $this->assertFalse(in_array($oldfield, $altered_table_fields), 'Error: field "'.$oldfield.'" not renamed'); - $this->assertTrue(in_array($newfield['name'], $altered_table_fields), 'Error: field "'.$oldfield.'" not renamed correctly'); - } - break; - case 'change': - break; - case 'remove': - $altered_table_fields = $this->db->manager->listTableFields($this->table); - foreach ($change as $newfield => $dummy) { - $this->assertFalse(in_array($newfield, $altered_table_fields), 'Error: field "'.$newfield.'" not removed'); - } - break; - case 'name': - if ($this->tableExists($newer)) { - $this->db->manager->dropTable($newer); - } else { - $this->assertTrue(true, 'Error: table "'.$this->table.'" not renamed'); - } - break; - } - } - } - } - } - - /** - * - */ - function testDropTable() { - if (!$this->methodExists($this->db->manager, 'dropTable')) { - return; - } - $result = $this->db->manager->dropTable($this->table); - $this->assertFalse(PEAR::isError($result), 'Error dropping table'); - } - - /** - * - */ - function testListTablesNoTable() { - if (!$this->methodExists($this->db->manager, 'listTables')) { - return; - } - $result = $this->db->manager->dropTable($this->table); - $this->assertFalse($this->tableExists($this->table), 'Error listing tables'); - } - - /** - * - */ - function testSequences() { - if (!$this->methodExists($this->db->manager, 'createSequence')) { - return; - } - $seq_name = 'testsequence'; - $result = $this->db->manager->createSequence($seq_name); - $this->assertFalse(PEAR::isError($result), 'Error creating a sequence'); - $this->assertTrue(in_array($seq_name, $this->db->manager->listSequences()), 'Error listing sequences'); - $result = $this->db->manager->dropSequence($seq_name); - $this->assertFalse(PEAR::isError($result), 'Error dropping a sequence'); - $this->assertFalse(in_array($seq_name, $this->db->manager->listSequences()), 'Error listing sequences'); - } - - /** - * Test listTableTriggers($table) - */ - function testListTableTriggers() { - //setup - $trigger_name = 'test_newtrigger'; - - include_once 'MDB2_nonstandard.php'; - $nonstd =& MDB2_nonstandard::factory($this->db, $this); - if (PEAR::isError($nonstd)) { - $this->assertTrue(false, 'Cannot instanciate MDB2_nonstandard object: '.$nonstd->getMessage()); - return; - } - - $result = $nonstd->createTrigger($trigger_name, $this->table); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Cannot create trigger: '.$result->getMessage()); - return; - } - - //test - $triggers = $this->db->manager->listTableTriggers($this->table); - if (PEAR::isError($triggers)) { - $this->assertTrue(false, 'Error listing the table triggers: '.$triggers->getMessage()); - } else { - $this->assertTrue(in_array($trigger_name, $triggers), 'Error: trigger not found'); - //check that only the triggers referencing the given table are returned - $triggers = $this->db->manager->listTableTriggers('fake_table'); - $this->assertFalse(in_array($trigger_name, $triggers), 'Error: trigger found'); - } - - - //cleanup - $result = $nonstd->dropTrigger($trigger_name, $this->table); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error dropping the trigger: '.$result->getMessage()); - } - } - - /** - * Test listTableViews($table) - */ - function testListTableViews() { - //setup - $view_name = 'test_newview'; - - include_once 'MDB2_nonstandard.php'; - $nonstd =& MDB2_nonstandard::factory($this->db, $this); - if (PEAR::isError($nonstd)) { - $this->assertTrue(false, 'Cannot instanciate MDB2_nonstandard object: '.$nonstd->getMessage()); - return; - } - - $result = $nonstd->createView($view_name, $this->table); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Cannot create view: '.$result->getMessage()); - return; - } - - //test - $views = $this->db->manager->listTableViews($this->table); - if (PEAR::isError($views)) { - $this->assertTrue(false, 'Error listing the table views: '.$views->getMessage()); - } else { - $this->assertTrue(in_array($view_name, $views), 'Error: view not found'); - //check that only the views referencing the given table are returned - $views = $this->db->manager->listTableViews('fake_table'); - $this->assertFalse(in_array($view_name, $views), 'Error: view found'); - } - - - //cleanup - $result = $nonstd->dropView($view_name); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error dropping the view: '.$result->getMessage()); - } - } - - /** - * Test listViews() - */ - function testListViews() { - //setup - $view_name = 'test_brandnewview'; - - include_once 'MDB2_nonstandard.php'; - $nonstd =& MDB2_nonstandard::factory($this->db, $this); - if (PEAR::isError($nonstd)) { - $this->assertTrue(false, 'Cannot instanciate MDB2_nonstandard object: '.$nonstd->getMessage()); - return; - } - - $result = $nonstd->createView($view_name, $this->table); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Cannot create view: '.$result->getMessage()); - return; - } - - //test - $views = $this->db->manager->listViews(); - if (PEAR::isError($views)) { - $this->assertTrue(false, 'Error listing the views: '.$views->getMessage()); - } else { - $this->assertTrue(in_array($view_name, $views), 'Error: view not found'); - } - - //cleanup - $result = $nonstd->dropView($view_name); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error dropping the view: '.$result->getMessage()); - } - } - - /** - * Test listUsers() - */ - function testListUsers() { - $users = $this->db->manager->listUsers(); - if (PEAR::isError($users)) { - $this->assertTrue(false, 'Error listing the users: '.$users->getMessage()); - } else { - $users = array_map('strtolower', $users); - $this->assertTrue(in_array(strtolower($this->db->dsn['username']), $users), 'Error: user not found'); - } - } - - /** - * Test listFunctions() - */ - function testListFunctions() { - //setup - $function_name = 'test_add'; - - include_once 'MDB2_nonstandard.php'; - $nonstd =& MDB2_nonstandard::factory($this->db, $this); - if (PEAR::isError($nonstd)) { - $this->assertTrue(false, 'Cannot instanciate MDB2_nonstandard object: '.$nonstd->getMessage()); - return; - } - - $result = $nonstd->createFunction($function_name); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Cannot create function: '.$result->getMessage().' :: '.$result->getUserInfo()); - return; - } - - //test - $functions = $this->db->manager->listFunctions(); - if (PEAR::isError($functions)) { - $this->assertTrue(false, 'Error listing the functions: '.$functions->getMessage()); - } else { - $this->assertTrue(in_array($function_name, $functions), 'Error: function not found'); - } - - //cleanup - $result = $nonstd->dropFunction($function_name); - if (PEAR::isError($result)) { - $this->assertTrue(false, 'Error dropping the function: '.$result->getMessage()); - } - } -} -?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/tests/MDB2_native_testcase.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/tests/MDB2_native_testcase.php --- php-mdb2-2.4.1/MDB2-2.4.1/tests/MDB2_native_testcase.php 2007-05-03 19:58:15.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.4.1/tests/MDB2_native_testcase.php 1970-01-01 01:00:00.000000000 +0100 @@ -1,52 +0,0 @@ - | -// +----------------------------------------------------------------------+ -// -// $Id: MDB2_native_testcase.php,v 1.12 2006/03/01 12:15:38 lsmith Exp $ - -require_once 'MDB2_testcase.php'; - -class MDB2_Native_TestCase extends MDB2_TestCase -{ -} - -?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/tests/MDB2_nonstandard_ibase.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/tests/MDB2_nonstandard_ibase.php --- php-mdb2-2.4.1/MDB2-2.4.1/tests/MDB2_nonstandard_ibase.php 2007-05-03 19:58:15.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.4.1/tests/MDB2_nonstandard_ibase.php 1970-01-01 01:00:00.000000000 +0100 @@ -1,90 +0,0 @@ - | -// +----------------------------------------------------------------------+ -// -// $Id: MDB2_nonstandard_ibase.php,v 1.5 2007/03/04 21:32:31 quipo Exp $ - -class MDB2_nonstandard_ibase extends MDB2_nonstandard { - - var $trigger_body = 'AS -BEGIN - NEW.somedescription = OLD.somename; -END'; - - function createTrigger($trigger_name, $table_name) { - $query = 'CREATE OR ALTER TRIGGER '. $trigger_name .' FOR '. $table_name .' - AFTER UPDATE '. $this->trigger_body .';'; - return $this->db->exec($query); - } - - function checkTrigger($trigger_name, $table_name, $def) { - parent::checkTrigger($trigger_name, $table_name, $def); - $this->test->assertEquals($this->trigger_body, $def['trigger_body']); - } - - function dropTrigger($trigger_name, $table_name) { - return $this->db->exec('DROP TRIGGER '.$trigger_name); - } - - function createFunction($name) { - $query = 'CREATE PROCEDURE '.$name.'(N1 DECIMAL(6,2), N2 DECIMAL(6,2)) -RETURNS ( - res DECIMAL(6,2) -) -AS -BEGIN - FOR - SELECT (:N1 + :N2) FROM RDB$DATABASE INTO :res - DO - BEGIN - SUSPEND; - END -END'; - return $this->db->exec($query); - } - - function dropFunction($name) { - return $this->db->exec('DROP PROCEDURE '.$name); - } -} - -?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/tests/MDB2_nonstandard_mssql.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/tests/MDB2_nonstandard_mssql.php --- php-mdb2-2.4.1/MDB2-2.4.1/tests/MDB2_nonstandard_mssql.php 2007-05-03 19:58:15.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.4.1/tests/MDB2_nonstandard_mssql.php 1970-01-01 01:00:00.000000000 +0100 @@ -1,88 +0,0 @@ - | -// +----------------------------------------------------------------------+ -// -// $Id: MDB2_nonstandard_mssql.php,v 1.2 2007/03/04 21:27:44 quipo Exp $ - -class MDB2_nonstandard_mssql extends MDB2_nonstandard { - - var $trigger_body = ''; - - function createTrigger($trigger_name, $table_name) { - $this->trigger_body = 'CREATE TRIGGER '. $trigger_name .' ON '. $table_name .' -FOR UPDATE AS -DECLARE @oldName VARCHAR(100) -DECLARE @newId INTEGER -SELECT @oldName = (SELECT somename FROM Deleted) -SELECT @newId = (SELECT id FROM Inserted) -BEGIN - UPDATE '. $table_name .' SET somedescription = @oldName WHERE id = @newId; -END;'; - - return $this->db->exec($this->trigger_body); - } - - function checkTrigger($trigger_name, $table_name, $def) { - parent::checkTrigger($trigger_name, $table_name, $def); - $this->test->assertEquals($this->trigger_body, $def['trigger_body']); - echo '
    ';
    -        var_dump($this->trigger_body);
    -        var_dump($def['trigger_body']);
    -    }
    -
    -    function dropTrigger($trigger_name, $table_name) {
    -        return $this->db->exec('DROP TRIGGER '.$trigger_name);
    -    }
    -    
    -    function createFunction($name) {
    -        $query = 'CREATE FUNCTION '.$name.'(@Number1 Decimal(6,2), @Number2 Decimal(6,2))
    -RETURNS Decimal(6,2)
    -BEGIN
    -    DECLARE @Result Decimal(6,2)
    -    SET @Result = @Number1 + @Number2
    -    RETURN @Result
    -END';
    -        return $this->db->exec($query);
    -    }
    -}
    -
    -?>
    \ No newline at end of file
    diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/tests/MDB2_nonstandard_mysqli.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/tests/MDB2_nonstandard_mysqli.php
    --- php-mdb2-2.4.1/MDB2-2.4.1/tests/MDB2_nonstandard_mysqli.php	2007-05-03 19:58:15.000000000 +0100
    +++ php-mdb2-2.5.0b2/MDB2-2.4.1/tests/MDB2_nonstandard_mysqli.php	1970-01-01 01:00:00.000000000 +0100
    @@ -1,52 +0,0 @@
    -                       |
    -// +----------------------------------------------------------------------+
    -//
    -// $Id: MDB2_nonstandard_mysqli.php,v 1.1 2006/12/09 14:31:54 quipo Exp $
    -
    -require_once 'MDB2_nonstandard_mysql.php';
    -
    -class MDB2_nonstandard_mysqli extends MDB2_nonstandard_mysql {
    -
    -}
    -
    -?>
    \ No newline at end of file
    diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/tests/MDB2_nonstandard_mysql.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/tests/MDB2_nonstandard_mysql.php
    --- php-mdb2-2.4.1/MDB2-2.4.1/tests/MDB2_nonstandard_mysql.php	2007-05-03 19:58:15.000000000 +0100
    +++ php-mdb2-2.5.0b2/MDB2-2.4.1/tests/MDB2_nonstandard_mysql.php	1970-01-01 01:00:00.000000000 +0100
    @@ -1,75 +0,0 @@
    -                       |
    -// +----------------------------------------------------------------------+
    -//
    -// $Id: MDB2_nonstandard_mysql.php,v 1.4 2007/03/04 22:51:06 quipo Exp $
    -
    -class MDB2_nonstandard_mysql extends MDB2_nonstandard {
    -
    -    var $trigger_body = '';
    -
    -    function createTrigger($trigger_name, $table_name) {
    -        $this->trigger_body = 'BEGIN
    -  UPDATE '. $table_name .' SET somedescription = OLD.somename WHERE id = NEW.id;
    -END';
    -        $query = 'CREATE TRIGGER '. $trigger_name .' AFTER UPDATE ON '. $table_name .'
    -                  FOR EACH ROW '. $this->trigger_body .';';
    -        return $this->db->exec($query);
    -    }
    -
    -    function checkTrigger($trigger_name, $table_name, $def) {
    -        parent::checkTrigger($trigger_name, $table_name, $def);
    -        $this->test->assertEquals($this->trigger_body, $def['trigger_body']);
    -    }
    -
    -    function dropTrigger($trigger_name, $table_name) {
    -        return $this->db->exec('DROP TRIGGER '.$trigger_name);
    -    }
    -
    -    function createFunction($name) {
    -        $query = 'CREATE FUNCTION '.$name.'(a INT, b INT) RETURNS INT
    -RETURN a + b;';
    -        return $this->db->exec($query);
    -    }
    -}
    -
    -?>
    \ No newline at end of file
    diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/tests/MDB2_nonstandard_oci8.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/tests/MDB2_nonstandard_oci8.php
    --- php-mdb2-2.4.1/MDB2-2.4.1/tests/MDB2_nonstandard_oci8.php	2007-05-03 19:58:15.000000000 +0100
    +++ php-mdb2-2.5.0b2/MDB2-2.4.1/tests/MDB2_nonstandard_oci8.php	1970-01-01 01:00:00.000000000 +0100
    @@ -1,82 +0,0 @@
    -                       |
    -// +----------------------------------------------------------------------+
    -//
    -// $Id: MDB2_nonstandard_oci8.php,v 1.5 2007/03/04 22:28:23 quipo Exp $
    -
    -class MDB2_nonstandard_oci8 extends MDB2_nonstandard {
    -
    -    var $trigger_body = '';
    -    var $when_clause = 'new.id > 0';
    -
    -    function createTrigger($trigger_name, $table_name) {
    -        $this->trigger_body = 'BEGIN INSERT INTO '.$table_name
    -            .' (id, somename, somedescription) VALUES'
    -            .' (:new.id+1, :new.somename, :new.somedescription); END '. $trigger_name .';';
    -        $query = 'CREATE OR REPLACE TRIGGER '. $trigger_name
    -                .' AFTER UPDATE ON '. $table_name
    -                .' FOR EACH ROW WHEN ('.$this->when_clause.') '
    -                . $this->trigger_body;
    -        return $this->db->exec($query);
    -    }
    -
    -    function checkTrigger($trigger_name, $table_name, $def) {
    -        parent::checkTrigger($trigger_name, $table_name, $def);
    -        $this->test->assertEquals($this->trigger_body, $def['trigger_body']);
    -        $this->test->assertEquals($this->when_clause, $def['when_clause']);
    -    }
    -
    -    function dropTrigger($trigger_name, $table_name) {
    -        return $this->db->exec('DROP TRIGGER '.$trigger_name);
    -    }
    -
    -    function createFunction($name) {
    -        $query = 'CREATE FUNCTION '.$name.'(a IN INT, b IN INT)
    -RETURN INT AS
    -BEGIN
    -    RETURN a + b;
    -END;';
    -        return $this->db->exec($query);
    -    }
    -}
    -
    -?>
    \ No newline at end of file
    diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/tests/MDB2_nonstandard_pgsql.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/tests/MDB2_nonstandard_pgsql.php
    --- php-mdb2-2.4.1/MDB2-2.4.1/tests/MDB2_nonstandard_pgsql.php	2007-05-03 19:58:15.000000000 +0100
    +++ php-mdb2-2.5.0b2/MDB2-2.4.1/tests/MDB2_nonstandard_pgsql.php	1970-01-01 01:00:00.000000000 +0100
    @@ -1,94 +0,0 @@
    -                       |
    -// +----------------------------------------------------------------------+
    -//
    -// $Id: MDB2_nonstandard_pgsql.php,v 1.5 2007/03/04 21:36:08 quipo Exp $
    -
    -class MDB2_nonstandard_pgsql extends MDB2_nonstandard {
    -
    -    var $trigger_body = '';
    -
    -    function createTrigger($trigger_name, $table_name) {
    -        $this->trigger_body = 'EXECUTE PROCEDURE '.$trigger_name.'_func();';
    -        $table_name = $this->db->quoteIdentifier($table_name);
    -        $sql = 'CREATE OR REPLACE FUNCTION '.$trigger_name.'_func() RETURNS trigger AS \'
    -                DECLARE
    -                    id_number INTEGER;
    -                BEGIN
    -                    SELECT INTO id_number id FROM '. $table_name .' WHERE id = NEW.id;
    -                    RETURN NEW;
    -                END;
    -                \' LANGUAGE \'plpgsql\';';
    -        $res = $this->db->exec($sql);
    -        if (PEAR::isError($res)) {
    -            return $res;
    -        }
    -    
    -        $query = 'CREATE TRIGGER '. $trigger_name .' AFTER UPDATE ON '. $table_name .'
    -                  FOR EACH ROW ' .$this->trigger_body;
    -        return $this->db->exec($query);
    -    }
    -
    -    function checkTrigger($trigger_name, $table_name, $def) {
    -        parent::checkTrigger($trigger_name, $table_name, $def);
    -        $this->test->assertEquals($this->trigger_body, $def['trigger_body']);
    -    }
    -
    -    function dropTrigger($trigger_name, $table_name) {
    -        return $this->db->exec('DROP TRIGGER '.$trigger_name .' ON '. $table_name);
    -    }
    -
    -    function createFunction($name) {
    -        $query = "CREATE FUNCTION $name (Decimal(6,2), Decimal(6,2)) RETURNS Decimal(6,2)
    -AS 'select $1 + $2;'
    -LANGUAGE SQL
    -IMMUTABLE
    -RETURNS NULL ON NULL INPUT";
    -        return $this->db->exec($query);
    -    }
    -
    -    function dropFunction($name) {
    -        return $this->db->exec('DROP FUNCTION '.$name.' (Decimal(6,2), Decimal(6,2))');
    -    }
    -}
    -
    -?>
    \ No newline at end of file
    diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/tests/MDB2_nonstandard.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/tests/MDB2_nonstandard.php
    --- php-mdb2-2.4.1/MDB2-2.4.1/tests/MDB2_nonstandard.php	2007-05-03 19:58:15.000000000 +0100
    +++ php-mdb2-2.5.0b2/MDB2-2.4.1/tests/MDB2_nonstandard.php	1970-01-01 01:00:00.000000000 +0100
    @@ -1,130 +0,0 @@
    -                       |
    -// +----------------------------------------------------------------------+
    -//
    -// $Id: MDB2_nonstandard.php,v 1.5 2007/03/04 21:26:52 quipo Exp $
    -
    -class MDB2_nonstandard {
    -    //contains the MDB2 object of the db once we have connected
    -    var $db;
    -    
    -    //contains the PHPUnit_TestCase object
    -    var $test;
    -    
    -    /**
    -     * Returns a driver-specific object
    -     */
    -    function factory($db, $test) {
    -        $classname = 'MDB2_nonstandard_'.$db->phptype;
    -        include_once $classname.'.php';
    -        if (class_exists($classname)) {
    -            $obj =& new $classname();
    -            $obj->db =& $db;
    -            $obj->test =& $test;
    -            return $obj;
    -        }
    -        return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
    -            'not capable', __FUNCTION__);
    -    }
    -    
    -    /**
    -     * Create a TRIGGER
    -     */
    -    function createTrigger($trigger_name, $table_name) {
    -        return $this->db->raiseError(MDB2_ERROR_NOT_CAPABLE, null, null,
    -            'not capable', __FUNCTION__);
    -    }
    -
    -    /**
    -     * Check if getTriggerDefinition() returns the correct definition for the trigger
    -     */
    -    function checkTrigger($trigger_name, $table_name, $def) {
    -        $this->test->assertEquals(strtoupper($trigger_name), strtoupper($def['trigger_name']), 'Error getting trigger definition (name)');
    -        $this->test->assertEquals(strtoupper($table_name),  strtoupper($def['table_name']),   'Error getting trigger definition (table)');
    -        $this->test->assertEquals('AFTER',  $def['trigger_type'], 'Error getting trigger definition (type)');
    -        $this->test->assertEquals('UPDATE', $def['trigger_event'], 'Error getting trigger definition (event)');
    -        $this->test->assertTrue(is_string($def['trigger_body']), 'Error getting trigger definition (body)');
    -        $this->test->assertTrue($def['trigger_enabled'], 'Error getting trigger definition (enabled)');
    -        //$this->test->assertTrue(empty($def['trigger_comment']),  'Error getting trigger definition (comment)');
    -    }
    -
    -    /**
    -     * Drop a TRIGGER
    -     */
    -    function dropTrigger($trigger_name, $table_name) {
    -        return $this->db->raiseError(MDB2_ERROR_NOT_CAPABLE, null, null,
    -            'not capable', __FUNCTION__);
    -    }
    -    
    -    /**
    -     * Create a VIEW
    -     */
    -    function createView($view_name, $table_name) {
    -        $query = 'CREATE VIEW '. $this->db->quoteIdentifier($view_name, true)
    -                .' (id) AS SELECT id FROM '
    -                . $this->db->quoteIdentifier($table_name, true) .' WHERE id > 1';
    -        return $this->db->exec($query);
    -    }
    -
    -    /**
    -     * Drop a VIEW
    -     */
    -    function dropView($view_name) {
    -        return $this->db->exec('DROP VIEW '.$view_name);
    -    }
    -
    -    /**
    -     * Create a FUNCTION
    -     */
    -    function createFunction($name) {
    -        return $this->db->raiseError(MDB2_ERROR_NOT_CAPABLE, null, null,
    -            'not capable', __FUNCTION__);
    -    }
    -
    -    /**
    -     * Drop a FUNCTION
    -     */
    -    function dropFunction($name) {
    -        return $this->db->exec('DROP FUNCTION '.$name);
    -    }
    -}
    -?>
    \ No newline at end of file
    diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/tests/MDB2_nonstandard_sqlite.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/tests/MDB2_nonstandard_sqlite.php
    --- php-mdb2-2.4.1/MDB2-2.4.1/tests/MDB2_nonstandard_sqlite.php	2007-05-03 19:58:15.000000000 +0100
    +++ php-mdb2-2.5.0b2/MDB2-2.4.1/tests/MDB2_nonstandard_sqlite.php	1970-01-01 01:00:00.000000000 +0100
    @@ -1,75 +0,0 @@
    -                       |
    -// +----------------------------------------------------------------------+
    -//
    -// $Id: MDB2_nonstandard_sqlite.php,v 1.5 2007/03/05 21:35:54 quipo Exp $
    -
    -class MDB2_nonstandard_sqlite extends MDB2_nonstandard {
    -
    -    var $trigger_body = '';
    -
    -    function createTrigger($trigger_name, $table_name) {
    -        $this->trigger_body = 'CREATE TRIGGER '. $trigger_name .' AFTER UPDATE ON '. $table_name .'
    -BEGIN
    -    UPDATE '. $table_name .' SET somedescription = new.somename WHERE id = old.id;
    -END';
    -        return $this->db->standaloneQuery($this->trigger_body);
    -    }
    -
    -    function checkTrigger($trigger_name, $table_name, $def) {
    -        parent::checkTrigger($trigger_name, $table_name, $def);
    -        $this->test->assertEquals($this->trigger_body, $def['trigger_body']);
    -    }
    -
    -    function dropTrigger($trigger_name, $table_name) {
    -        return $this->db->standaloneQuery('DROP TRIGGER '.$trigger_name);
    -    }
    -    
    -    function createView($view_name, $table_name) {
    -        $query = 'CREATE VIEW '. $this->db->quoteIdentifier($view_name, true)
    -                .' AS SELECT id FROM '
    -                . $this->db->quoteIdentifier($table_name, true) .' WHERE id > 1';
    -        return $this->db->exec($query);
    -    }
    -}
    -
    -?>
    \ No newline at end of file
    diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/tests/MDB2_reverse_testcase.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/tests/MDB2_reverse_testcase.php
    --- php-mdb2-2.4.1/MDB2-2.4.1/tests/MDB2_reverse_testcase.php	2007-05-03 19:58:15.000000000 +0100
    +++ php-mdb2-2.5.0b2/MDB2-2.4.1/tests/MDB2_reverse_testcase.php	1970-01-01 01:00:00.000000000 +0100
    @@ -1,508 +0,0 @@
    -            |
    -// +----------------------------------------------------------------------+
    -//
    -// $Id: MDB2_reverse_testcase.php,v 1.46 2007/03/29 18:18:06 quipo Exp $
    -
    -require_once 'MDB2_testcase.php';
    -
    -class MDB2_Reverse_TestCase extends MDB2_TestCase
    -{
    -    //test table name (it is dynamically created/dropped)
    -    var $table       = 'testtable';
    -    var $fields      = array();
    -    var $indices     = array();
    -    var $constraints = array();
    -
    -    function setUp() {
    -        parent::setUp();
    -        $this->db->loadModule('Reverse', null, true);
    -        $this->db->loadModule('Manager', null, true);
    -
    -        //Table structure
    -        $this->fields = array(
    -            'id' => array(  //PK
    -                'type'     => 'integer',
    -                'unsigned' => 1,
    -                'notnull'  => 1,
    -                'default'  => 0,
    -                'length'  => 4,
    -            ),
    -            'id2' => array( //UNIQUE_MULTIFIELD(1/2)
    -                'type'     => 'integer',
    -                'unsigned' => 1,
    -                'notnull'  => 1,
    -                'default'  => 0,
    -            ),
    -            'id3' => array( //UNIQUE_MULTIFIELD(2/2)
    -                'type'     => 'integer',
    -                'unsigned' => 1,
    -                'notnull'  => 1,
    -                'default'  => 0,
    -            ),
    -            'id4' => array( //UNIQUE
    -                'type'     => 'integer',
    -                'unsigned' => 1,
    -                'notnull'  => 1,
    -                'default'  => 0,
    -            ),
    -            'somename' => array( //NORMAL INDEX
    -                'type'   => 'text',
    -                'length' => 12,
    -            ),
    -            'somedescription' => array( //INDEX_MULTIFIELD(1/2)
    -                'type'   => 'text',
    -                'length' => 12,
    -            ),
    -            'sex' => array( //INDEX_MULTIFIELD(2/2)
    -                'type' => 'text',
    -                'length' => 1,
    -                'default' => 'M',
    -            ),
    -        );
    -
    -        if (!$this->tableExists($this->table)) {
    -            $this->db->manager->createTable($this->table, $this->fields);
    -        }
    -    }
    -
    -    function tearDown() {
    -        if ($this->tableExists($this->table)) {
    -            $this->db->manager->dropTable($this->table);
    -        }
    -        $this->db->popExpect();
    -        unset($this->dsn);
    -        if (!PEAR::isError($this->db->manager)) {
    -            $this->db->disconnect();
    -        }
    -        unset($this->db);
    -    }
    -
    -    function setUpIndices()
    -    {
    -        //Indices definition
    -        $this->indices = array(
    -            'sometestindex' => array(
    -                'fields' => array(
    -                    'somename' => array(
    -                        'sorting' => 'ascending',
    -                    ),
    -                ),
    -                'unique' => false,
    -            ),
    -            'multipletestindex' => array(
    -                'fields' => array(
    -                    'somedescription' => array(
    -                        'sorting' => 'ascending',
    -                    ),
    -                    'sex' => array(
    -                        'sorting' => 'ascending',
    -                    ),
    -                ),
    -            ),
    -        );
    -        foreach ($this->indices as $index_name => $index) {
    -            $result = $this->db->manager->createIndex($this->table, $index_name, $index);
    -            $this->assertFalse(PEAR::isError($result), 'Error creating index: '.$index_name);
    -            if (PEAR::isError($result)) {
    -                break;
    -            }
    -        }
    -        return PEAR::isError($result);
    -    }
    -
    -    function setUpConstraints()
    -    {
    -        //Constraints definition
    -        $this->constraints = array(
    -            'pkfield' => array(
    -                'fields' => array(
    -                    'id' => array(
    -                        'sorting' => 'ascending',
    -                    ),
    -                ),
    -                'primary' => true,
    -            ),
    -            'multipleunique' => array(
    -                'fields' => array(
    -                    'id2' => array(
    -                        'sorting' => 'ascending',
    -                    ),
    -                    'id3' => array(
    -                        'sorting' => 'ascending',
    -                    ),
    -                ),
    -                'unique' => true,
    -            ),
    -            'singleunique' => array(
    -                'fields' => array(
    -                    'id4' => array(
    -                        'sorting' => 'ascending',
    -                    ),
    -                ),
    -                'unique' => true,
    -            ),
    -        );
    -        foreach ($this->constraints as $constraint_name => $constraint) {
    -            $result = $this->db->manager->createConstraint($this->table, $constraint_name, $constraint);
    -            $this->assertFalse(PEAR::isError($result), 'Error creating constraint: '.$constraint_name);
    -            if (PEAR::isError($result)) {
    -                break;
    -            }
    -        }
    -        return PEAR::isError($result);
    -    }
    -
    -    /**
    -     * Test tableInfo('table_name')
    -     */
    -    function testTableInfo()
    -    {
    -        if (!$this->methodExists($this->db->reverse, 'tableInfo')) {
    -            return;
    -        }
    -
    -        $table_info = $this->db->reverse->tableInfo($this->table);
    -        if (PEAR::isError($table_info)) {
    -            $this->assertTrue(false, 'Error in tableInfo(): '.$table_info->getMessage());
    -        } else {
    -            $this->assertEquals(count($this->fields), count($table_info), 'The number of fields retrieved is different from the expected one');
    -            foreach ($table_info as $field_info) {
    -                $this->assertEquals($this->table, $field_info['table'], "the table name is not correct");
    -                if (!array_key_exists(strtolower($field_info['name']), $this->fields)) {
    -                    $this->assertTrue(false, 'Field names do not match ('.$field_info['name'].' is unknown)');
    -                }
    -                //expand test, for instance adding a check on types...
    -            }
    -        }
    -
    -        if (!$this->supported('result_introspection')) {
    -            return;
    -        }
    -
    -        $result = $this->db->query('SELECT * FROM '.$this->table);
    -        $table_info = $this->db->reverse->tableInfo($result);
    -        if (PEAR::isError($table_info)) {
    -            $this->assertTrue(false, 'Error in tableInfo(): '.$table_info->getMessage());
    -        } else {
    -            $this->assertEquals(count($this->fields), count($table_info), 'The number of fields retrieved is different from the expected one');
    -            foreach ($table_info as $field_info) {
    -                //not all the drivers are capable of returning the table name,
    -                //and may return an empty value
    -                if (!empty($field_info['table'])) {
    -                    $this->assertEquals($this->table, $field_info['table'], "the table name is not correct");
    -                }
    -                if (!array_key_exists(strtolower($field_info['name']), $this->fields)) {
    -                    $this->assertTrue(false, 'Field names do not match ('.$field_info['name'].' is unknown)');
    -                }
    -                //expand test, for instance adding a check on types...
    -            }
    -        }
    -        $result->free();
    -    }
    -
    -    /**
    -     * Test getTableFieldDefinition($table, $field_name)
    -     */
    -    function testGetTableFieldDefinition()
    -    {
    -        if (!$this->methodExists($this->db->reverse, 'getTableFieldDefinition')) {
    -            return;
    -        }
    -
    -        //test integer not null
    -        $field_info = $this->db->reverse->getTableFieldDefinition($this->table, 'id');
    -        if (PEAR::isError($field_info)) {
    -            $this->assertTrue(false, 'Error in getTableFieldDefinition(): '.$field_info->getMessage());
    -        } else {
    -            $field_info = array_shift($field_info);
    -            $this->assertEquals('integer', $field_info['type'], 'The field type is different from the expected one');
    -            $expected_length = ($this->db->phptype == 'oci8') ? 10 : 4;
    -            $this->assertEquals($expected_length, $field_info['length'], 'The field length is different from the expected one');
    -            $this->assertTrue($field_info['notnull'], 'The field can be null unlike it was expected');
    -            $this->assertEquals('0', $field_info['default'], 'The field default value is different from the expected one');
    -        }
    -
    -        //test blob
    -        $field_info = $this->db->reverse->getTableFieldDefinition('files', 'picture');
    -        if (PEAR::isError($field_info)) {
    -            $this->assertTrue(false, 'Error in getTableFieldDefinition(): '.$field_info->getMessage());
    -        } else {
    -            $field_info = array_shift($field_info);
    -            $this->assertEquals($field_info['type'], 'blob', 'The field type is different from the expected one');
    -            $this->assertFalse($field_info['notnull'], 'The field cannot be null unlike it was expected');
    -        }
    -
    -        //test varchar(100) not null
    -        $field_info = $this->db->reverse->getTableFieldDefinition('users', 'user_name');
    -        if (PEAR::isError($field_info)) {
    -            $this->assertTrue(false, 'Error in getTableFieldDefinition(): '.$field_info->getMessage());
    -        } else {
    -            $field_info = array_shift($field_info);
    -            $this->assertEquals('text', $field_info['type'], 'The field type is different from the expected one');
    -            $this->assertEquals(12, $field_info['length'], 'The field length is different from the expected one');
    -            $this->assertFalse($field_info['notnull'], 'The field can be null unlike it was expected');
    -            $this->assertNull($field_info['default'], 'The field default value is different from the expected one');
    -            $this->assertFalse($field_info['fixed'], 'The field fixed value is different from the expected one');
    -        }
    -
    -        //test decimal
    -        $field_info = $this->db->reverse->getTableFieldDefinition('users', 'quota');
    -        if (PEAR::isError($field_info)) {
    -            $this->assertTrue(false, 'Error in getTableFieldDefinition(): '.$field_info->getMessage());
    -        } else {
    -            $field_info = array_shift($field_info);
    -            $this->assertEquals('decimal', $field_info['type'], 'The field type is different from the expected one');
    -            $expected_length = ($this->db->phptype == 'oci8') ? '22,2' : '18,2';
    -            $this->assertEquals($expected_length, $field_info['length'], 'The field length is different from the expected one');
    -        }
    -    }
    -
    -    /**
    -     * Test getTableIndexDefinition($table, $index_name)
    -     */
    -    function testGetTableIndexDefinition()
    -    {
    -        if (!$this->methodExists($this->db->reverse, 'getTableIndexDefinition')) {
    -            return;
    -        }
    -
    -        $this->setUpIndices();
    -
    -        //test index names
    -        foreach ($this->indices as $index_name => $index) {
    -            $index_info = $this->db->reverse->getTableIndexDefinition($this->table, $index_name);
    -            if (PEAR::isError($index_info)) {
    -                $this->assertFalse(true, 'Error getting table index definition');
    -            } else {
    -                $field_names = array_keys($index['fields']);
    -                $this->assertEquals($field_names, array_keys($index_info['fields']), 'Error listing index fields');
    -            }
    -        }
    -
    -        //test INDEX
    -        $index_name = 'sometestindex';
    -        $index_info = $this->db->reverse->getTableIndexDefinition($this->table, $index_name);
    -        if (PEAR::isError($index_info)) {
    -            $this->assertTrue(false, 'Error in getTableIndexDefinition(): '.$index_info->getMessage());
    -        } else {
    -            $this->assertEquals(1, count($index_info['fields']), 'The INDEX is not on one field unlike it was expected');
    -            $expected_fields = array_keys($this->indices[$index_name]['fields']);
    -            $actual_fields = array_keys($index_info['fields']);
    -            $this->assertEquals($expected_fields, $actual_fields, 'The INDEX field names don\'t match');
    -            $this->assertEquals(1, $index_info['fields'][$expected_fields[0]]['position'], 'The field position in the INDEX is not correct');
    -        }
    -
    -        //test INDEX on MULTIPLE FIELDS
    -        $index_name = 'multipletestindex';
    -        $index_info = $this->db->reverse->getTableIndexDefinition($this->table, $index_name);
    -        if (PEAR::isError($index_info)) {
    -            $this->assertTrue(false, 'Error in getTableIndexDefinition(): '.$index_info->getMessage());
    -        } else {
    -            $this->assertEquals(2, count($index_info['fields']), 'The INDEX is not on two fields unlike it was expected');
    -            $expected_fields = array_keys($this->indices[$index_name]['fields']);
    -            $actual_fields = array_keys($index_info['fields']);
    -            $this->assertEquals($expected_fields, $actual_fields, 'The INDEX field names don\'t match');
    -            $this->assertEquals(1, $index_info['fields'][$expected_fields[0]]['position'], 'The field position in the INDEX is not correct');
    -            $this->assertEquals(2, $index_info['fields'][$expected_fields[1]]['position'], 'The field position in the INDEX is not correct');
    -        }
    -
    -        if (!$this->setUpConstraints()) {
    -            return;
    -        }
    -        //constraints should NOT be listed
    -        foreach (array_keys($this->constraints) as $constraint_name) {
    -            $this->db->expectError(MDB2_ERROR_NOT_FOUND);
    -            $result = $this->db->reverse->getTableIndexDefinition($this->table, $constraint_name);
    -            $this->assertTrue(PEAR::isError($result), 'Error listing index definition, this is a CONSTRAINT');
    -        }
    -
    -        //test index created WITHOUT using MDB2 (i.e. without the "_idx" suffix)
    -        //NB: MDB2 > v.2.3.0 provides a fallback mechanism
    -    }
    -
    -    /**
    -     * Test testGetTableConstraintDefinition($table, $constraint_name)
    -     */
    -    function testGetTableConstraintDefinition()
    -    {
    -        if (!$this->methodExists($this->db->reverse, 'getTableConstraintDefinition')) {
    -            return;
    -        }
    -
    -        if (!$this->setUpConstraints()) {
    -            return;
    -        }
    -
    -        //test constraint names
    -        foreach ($this->constraints as $constraint_name => $constraint) {
    -            $this->db->expectError(MDB2_ERROR_NOT_FOUND);
    -            $result = $this->db->reverse->getTableConstraintDefinition($this->table, $constraint_name);
    -            $this->db->popExpect();
    -            if (PEAR::isError($result) && isset($constraint['primary']) && $constraint['primary']) {
    -                echo 'Error reading primary constraint, trying with name "primary" instead .. ';
    -                $constraint_name = 'primary';
    -                $result = $this->db->reverse->getTableConstraintDefinition($this->table, $constraint_name);
    -            }
    -            if (PEAR::isError($result)) {
    -                $this->assertFalse(true, 'Error getting table constraint definition ('.$constraint_name.')');
    -            } else {
    -                $constraint_names = array_keys($constraint['fields']);
    -                $this->assertEquals($constraint_names, array_keys($result['fields']), 'Error listing constraint fields');
    -            }
    -        }
    -
    -        $this->setUpIndices();
    -        //indices should NOT be listed
    -        foreach (array_keys($this->indices) as $index_name) {
    -            $this->db->expectError(MDB2_ERROR_NOT_FOUND);
    -            $result = $this->db->reverse->getTableConstraintDefinition($this->table, $index_name);
    -            $this->db->popExpect();
    -            $this->assertTrue(PEAR::isError($result), 'Error listing constraint definition, this is a normal INDEX');
    -        }
    -
    -        //test PK
    -        $this->db->expectError(MDB2_ERROR_NOT_FOUND);
    -        $constraint_info = $this->db->reverse->getTableConstraintDefinition($this->table, 'pkfield');
    -        $this->db->popExpect();
    -        if (PEAR::isError($constraint_info)) {
    -            echo 'Error reading primary constraint, trying with name "primary" instead .. ';
    -            $constraint_info = $this->db->reverse->getTableConstraintDefinition($this->table, 'primary');
    -        }
    -        if (PEAR::isError($constraint_info)) {
    -            $this->assertTrue(false, 'Error in getTableConstraintDefinition(): '.$constraint_info->getMessage());
    -        } else {
    -            $this->assertTrue($constraint_info['primary'], 'The field is not a PK unlike it was expected');
    -        }
    -
    -        //test UNIQUE
    -        $constraint_name = 'singleunique';
    -        $constraint_info = $this->db->reverse->getTableConstraintDefinition($this->table, $constraint_name);
    -        if (PEAR::isError($constraint_info)) {
    -            $this->assertTrue(false, 'Error in getTableConstraintDefinition(): '.$constraint_info->getMessage());
    -        } else {
    -            $this->assertTrue($constraint_info['unique'], 'The field is not a PK unlike it was expected');
    -            $this->assertTrue(empty($constraint_info['primary']), 'The field is a PK unlike it was expected');
    -            $this->assertEquals(1, count($constraint_info['fields']), 'The UNIQUE INDEX is not on one field unlike it was expected');
    -            $expected_fields = array_keys($this->constraints[$constraint_name]['fields']);
    -            $actual_fields = array_keys($constraint_info['fields']);
    -            $this->assertEquals($expected_fields, $actual_fields, 'The UNIQUE INDEX field names don\'t match');
    -            $this->assertEquals(1, $constraint_info['fields'][$expected_fields[0]]['position'], 'The field position in the INDEX is not correct');
    -        }
    -
    -        //test UNIQUE on MULTIPLE FIELDS
    -        $constraint_name = 'multipleunique';
    -        $constraint_info = $this->db->reverse->getTableConstraintDefinition($this->table, $constraint_name);
    -        if (PEAR::isError($constraint_info)) {
    -            $this->assertTrue(false, 'Error in getTableConstraintDefinition(): '.$constraint_info->getMessage());
    -        } else {
    -            $this->assertTrue($constraint_info['unique'], 'The field is not a PK unlike it was expected');
    -            $this->assertTrue(empty($constraint_info['primary']), 'The field is a PK unlike it was expected');
    -            $this->assertEquals(2, count($constraint_info['fields']), 'The UNIQUE INDEX is not on two fields unlike it was expected');
    -            $expected_fields = array_keys($this->constraints[$constraint_name]['fields']);
    -            $actual_fields = array_keys($constraint_info['fields']);
    -            $this->assertEquals($expected_fields, $actual_fields, 'The UNIQUE INDEX field names don\'t match');
    -            $this->assertEquals(1, $constraint_info['fields'][$expected_fields[0]]['position'], 'The field position in the INDEX is not correct');
    -            $this->assertEquals(2, $constraint_info['fields'][$expected_fields[1]]['position'], 'The field position in the INDEX is not correct');
    -        }
    -    }
    -
    -    /**
    -     * Test getSequenceDefinition($sequence)
    -     */
    -    function testGetSequenceDefinition() {
    -        //setup
    -        $this->db->loadModule('Manager', null, true);
    -        $sequence = 'test_sequence';
    -        $sequences = $this->db->manager->listSequences();
    -        if (!in_array($sequence, $sequences)) {
    -            $result = $this->db->manager->createSequence($sequence);
    -            $this->assertFalse(PEAR::isError($result), 'Error creating a sequence');
    -        }
    -
    -        //test
    -        $start = $this->db->nextId($sequence);
    -        $def = $this->db->reverse->getSequenceDefinition($sequence);
    -        $this->assertEquals($start+1, (isset($def['start']) ? $def['start'] : 1), 'Error getting sequence definition');
    -
    -        //cleanup
    -        $result = $this->db->manager->dropSequence($sequence);
    -        $this->assertFalse(PEAR::isError($result), 'Error dropping a sequence');
    -    }
    -
    -    /**
    -     * Test getTriggerDefinition($trigger)
    -     */
    -    function testGetTriggerDefinition() {
    -        //setup
    -        $trigger_name = 'test_trigger';
    -
    -        include_once 'MDB2_nonstandard.php';
    -        $nonstd =& MDB2_nonstandard::factory($this->db, $this);
    -        if (PEAR::isError($nonstd)) {
    -            $this->assertTrue(false, 'Cannot create trigger: '.$nonstd->getMessage());
    -            return;
    -        }
    -
    -        $result = $nonstd->createTrigger($trigger_name, $this->table);
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Cannot create trigger: '.$result->getMessage());
    -            return;
    -        }
    -
    -        //test
    -        $def = $this->db->reverse->getTriggerDefinition($trigger_name);
    -        if (PEAR::isError($def)) {
    -            $this->assertTrue(false, 'getTriggerDefinition: '.$def->getMessage());
    -        } else {
    -            $nonstd->checkTrigger($trigger_name, $this->table, $def);
    -        }
    -
    -        //cleanup
    -        $result = $nonstd->dropTrigger($trigger_name, $this->table);
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Error dropping the trigger: '.$result->getMessage());
    -            return;
    -        }
    -    }
    -}
    -?>
    \ No newline at end of file
    diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/tests/MDB2_testcase.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/tests/MDB2_testcase.php
    --- php-mdb2-2.4.1/MDB2-2.4.1/tests/MDB2_testcase.php	2007-05-03 19:58:15.000000000 +0100
    +++ php-mdb2-2.5.0b2/MDB2-2.4.1/tests/MDB2_testcase.php	1970-01-01 01:00:00.000000000 +0100
    @@ -1,168 +0,0 @@
    -                                 |
    -// +----------------------------------------------------------------------+
    -//
    -// $Id: MDB2_testcase.php,v 1.18 2006/12/19 15:04:53 quipo Exp $
    -
    -class MDB2_TestCase extends PHPUnit_TestCase {
    -    //contains the dsn of the database we are testing
    -    var $dsn;
    -    //contains the options that should be used during testing
    -    var $options;
    -    //contains the name of the database we are testing
    -    var $database;
    -    //contains the MDB2 object of the db once we have connected
    -    var $db;
    -    // contains field names from the test table
    -    var $fields;
    -    // if the tables should be cleared in the setUp() and tearDown() methods
    -    var $clear_tables = true;
    -
    -    function MDB2_TestCase($name) {
    -        $this->PHPUnit_TestCase($name);
    -    }
    -
    -    function setUp() {
    -        $this->dsn = $GLOBALS['dsn'];
    -        $this->options  = $GLOBALS['options'];
    -        $this->database = $GLOBALS['database'];
    -        $this->db =& MDB2::factory($this->dsn, $this->options);
    -        $this->db->setDatabase($this->database);
    -        $this->db->expectError(MDB2_ERROR_UNSUPPORTED);
    -        $this->fields = array(
    -            'user_name' => 'text',
    -            'user_password' => 'text',
    -            'subscribed' => 'boolean',
    -            'user_id' => 'integer',
    -            'quota' => 'decimal',
    -            'weight' => 'float',
    -            'access_date' => 'date',
    -            'access_time' => 'time',
    -            'approved' => 'timestamp',
    -        );
    -        $this->clearTables();
    -    }
    -
    -    function tearDown() {
    -        $this->clearTables();
    -        $this->db->popExpect();
    -        unset($this->dsn);
    -        if (!PEAR::isError($this->db)) {
    -            $this->db->disconnect();
    -        }
    -        unset($this->db);
    -    }
    -
    -    function clearTables() {
    -        if (!$this->clear_tables) {
    -            return;
    -        }
    -        if (PEAR::isError($this->db->exec('DELETE FROM users'))) {
    -            $this->assertTrue(false, 'Error deleting from table users');
    -        }
    -        if (PEAR::isError($this->db->exec('DELETE FROM files'))) {
    -            $this->assertTrue(false, 'Error deleting from table users');
    -        }
    -    }
    -
    -    function supported($feature) {
    -        if (!$this->db->supports($feature)) {
    -            $this->assertTrue(false, 'This database does not support '.$feature);
    -            return false;
    -        }
    -        return true;
    -    }
    -
    -    function verifyFetchedValues(&$result, $rownum, $data) {
    -        //$row = $result->fetchRow(MDB2_FETCHMODE_DEFAULT, $rownum);
    -        $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC, $rownum);
    -        if (!is_array($row)) {
    -            $this->assertTrue(false, 'Error result row is not an array');
    -            return;
    -        }
    -        //reset($row);
    -        foreach ($this->fields as $field => $type) {
    -            //$value = current($row);
    -            $value = $row[$field];
    -            if ($type == 'float') {
    -                $delta = 0.0000000001;
    -            } else {
    -                $delta = 0;
    -            }
    -
    -            $this->assertEquals($data[$field], $value, "the value retrieved for field \"$field\" doesn't match what was stored into the rownum $rownum", $delta);
    -            //next($row);
    -        }
    -    }
    -
    -    function getSampleData($row = 1) {
    -        $data = array();
    -        $data['user_name']     = 'user_' . $row;
    -        $data['user_password'] = 'somepass';
    -        $data['subscribed']    = $row % 2 ? true : false;
    -        $data['user_id']       = $row;
    -        $data['quota']         = strval($row/100);
    -        $data['weight']        = sqrt($row);
    -        $data['access_date']   = MDB2_Date::mdbToday();
    -        $data['access_time']   = MDB2_Date::mdbTime();
    -        $data['approved']      = MDB2_Date::mdbNow();
    -        return $data;
    -    }
    -
    -    function methodExists(&$class, $name) {
    -        if (is_object($class)
    -            && in_array(strtolower($name), array_map('strtolower', get_class_methods($class)))
    -        ) {
    -            return true;
    -        }
    -        $this->assertTrue(false, 'method '. $name.' not implemented in '.get_class($class));
    -        return false;
    -    }
    -
    -    function tableExists($table) {
    -        $this->db->loadModule('Manager', null, true);
    -        $tables = $this->db->manager->listTables();
    -        return in_array(strtolower($table), array_map('strtolower', $tables));
    -    }
    -}
    -
    -?>
    \ No newline at end of file
    diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/tests/MDB2_usage_testcase.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/tests/MDB2_usage_testcase.php
    --- php-mdb2-2.4.1/MDB2-2.4.1/tests/MDB2_usage_testcase.php	2007-05-03 19:58:15.000000000 +0100
    +++ php-mdb2-2.5.0b2/MDB2-2.4.1/tests/MDB2_usage_testcase.php	1970-01-01 01:00:00.000000000 +0100
    @@ -1,1827 +0,0 @@
    -                                 |
    -// +----------------------------------------------------------------------+
    -//
    -// $Id: MDB2_usage_testcase.php,v 1.100 2006/12/19 22:46:48 quipo Exp $
    -
    -require_once 'MDB2_testcase.php';
    -
    -class MDB2_Usage_TestCase extends MDB2_TestCase {
    -    /**
    -     * Test typed data storage and retrieval
    -     *
    -     * This tests typed data storage and retrieval by executing a single
    -     * prepared query and then selecting the data back from the database
    -     * and comparing the results
    -     */
    -    function testStorage() {
    -        $data = $this->getSampleData(1234);
    -
    -        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
    -        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
    -        $result = $stmt->execute(array_values($data));
    -        $stmt->free();
    -
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Error executing prepared query'.$result->getMessage());
    -        }
    -
    -        $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users';
    -        $result =& $this->db->query($query, $this->fields);
    -
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Error selecting from users'.$result->getMessage());
    -        }
    -
    -        $this->verifyFetchedValues($result, 0, $data);
    -    }
    -
    -    /**
    -     * Test fetchOne()
    -     *
    -     * This test bulk fetching of result data by using a prepared query to
    -     * insert an number of rows of data and then retrieving the data columns
    -     * one by one
    -     */
    -    function testFetchOne() {
    -        $data = array();
    -        $total_rows = 5;
    -
    -        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
    -        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
    -
    -        for ($row = 0; $row < $total_rows; $row++) {
    -            $data[$row] = $this->getSampleData($row);
    -            $result = $stmt->execute(array_values($data[$row]));
    -
    -            if (PEAR::isError($result)) {
    -                $this->assertTrue(false, 'Error executing prepared query'.$result->getMessage());
    -            }
    -        }
    -
    -        $stmt->free();
    -
    -        foreach ($this->fields as $field => $type) {
    -            for ($row = 0; $row < $total_rows; $row++) {
    -                $result =& $this->db->query('SELECT '.$field.' FROM users WHERE user_id='.$row, $type);
    -                $value = $result->fetchOne();
    -                if (PEAR::isError($value)) {
    -                    $this->assertTrue(false, 'Error fetching row '.$row.' for field '.$field.' of type '.$type);
    -                } else {
    -                    $this->assertEquals(strval($data[$row][$field]), strval(trim($value)), 'the query field '.$field.' of type '.$type.' for row '.$row);
    -                    $result->free();
    -                }
    -            }
    -        }
    -    }
    -
    -    /**
    -     * Test fetchCol()
    -     *
    -     * Test fetching a column of result data. Two different columns are retrieved
    -     */
    -    function testFetchCol() {
    -        $data = array();
    -        $total_rows = 5;
    -
    -        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
    -        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
    -
    -        for ($row = 0; $row < $total_rows; $row++) {
    -            $data[$row] = $this->getSampleData($row);
    -            $result = $stmt->execute(array_values($data[$row]));
    -
    -            if (PEAR::isError($result)) {
    -                $this->assertTrue(false, 'Error executing prepared query'.$result->getMessage());
    -            }
    -        }
    -
    -        $stmt->free();
    -
    -        $first_col = array();
    -        for ($row = 0; $row < $total_rows; $row++) {
    -            $first_col[$row] = "user_$row";
    -        }
    -
    -        $second_col = array();
    -        for ($row = 0; $row < $total_rows; $row++) {
    -            $second_col[$row] = $row;
    -        }
    -
    -        $query = 'SELECT user_name, user_id FROM users ORDER BY user_name';
    -        $result =& $this->db->query($query, array('text', 'integer'));
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Error during query');
    -        }
    -        $values = $result->fetchCol(0);
    -        if (PEAR::isError($values)) {
    -            $this->assertTrue(false, 'Error fetching first column');
    -        } else {
    -            $this->assertEquals($first_col, $values);
    -        }
    -        $result->free();
    -
    -        $query = 'SELECT user_name, user_id FROM users ORDER BY user_name';
    -        $result =& $this->db->query($query, array('text', 'integer'));
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Error during query');
    -        }
    -        $values = $result->fetchCol(1);
    -        if (PEAR::isError($values)) {
    -            $this->assertTrue(false, 'Error fetching second column');
    -        } else {
    -            $this->assertEquals($second_col, $values);
    -        }
    -        $result->free();
    -    }
    -
    -    /**
    -     * Test fetchAll()
    -     *
    -     * Test fetching an entire result set in one shot.
    -     */
    -    function testFetchAll() {
    -        $data = array();
    -        $total_rows = 5;
    -
    -        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
    -        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
    -
    -        for ($row = 0; $row < $total_rows; $row++) {
    -            $data[$row] = $this->getSampleData($row);
    -            $result = $stmt->execute(array_values($data[$row]));
    -
    -            if (PEAR::isError($result)) {
    -                $this->assertTrue(false, 'Error executing prepared query'.$result->getMessage());
    -            }
    -        }
    -        $fields = array_keys($data[0]);
    -        $query = 'SELECT '. implode (', ', $fields). ' FROM users ORDER BY user_name';
    -
    -        $stmt->free();
    -
    -        $result =& $this->db->query($query, $this->fields);
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Error during query');
    -        }
    -        $values = $result->fetchAll(MDB2_FETCHMODE_ASSOC);
    -        if (PEAR::isError($values)) {
    -            $this->assertTrue(false, 'Error fetching the result set');
    -        } else {
    -            for ($i=0; $i<$total_rows; $i++) {
    -                foreach ($data[$i] as $key => $val) {
    -                    $this->assertEquals(strval($val), strval($values[$i][$key]), 'Row #'.$i.' ['.$key.']');
    -                }
    -            }
    -        }
    -        $result->free();
    -
    -        //test $rekey=true
    -        $result =& $this->db->query('SELECT user_id, user_name FROM users ORDER BY user_id', $this->fields);
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Error during query');
    -        }
    -        $values = $result->fetchAll(MDB2_FETCHMODE_ASSOC, true);
    -        if (PEAR::isError($values)) {
    -            $this->assertTrue(false, 'Error fetching the result set');
    -        } else {
    -            for ($i=0; $i<$total_rows; $i++) {
    -                list($id, $name) = each($values);
    -                $this->assertEquals($data[$i]['user_id'],   $id,   'Row #'.$i.' ["user_id"]');
    -                $this->assertEquals($data[$i]['user_name'], $name, 'Row #'.$i.' ["user_name"]');
    -            }
    -        }
    -        $result->free();
    -
    -
    -        //test $rekey=true, $force_array=true
    -        $result =& $this->db->query('SELECT user_id, user_name FROM users ORDER BY user_id', $this->fields);
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Error during query');
    -        }
    -        $values = $result->fetchAll(MDB2_FETCHMODE_ASSOC, true, true);
    -        if (PEAR::isError($values)) {
    -            $this->assertTrue(false, 'Error fetching the result set');
    -        } else {
    -            for ($i=0; $i<$total_rows; $i++) {
    -                list($id, $value) = each($values);
    -                $this->assertEquals($data[$i]['user_id'],   $id,                 'Row #'.$i.' ["user_id"]');
    -                $this->assertEquals($data[$i]['user_name'], $value['user_name'], 'Row #'.$i.' ["user_name"]');
    -            }
    -        }
    -        $result->free();
    -
    -        //test $rekey=true, $force_array=true, $group=true
    -        $result =& $this->db->query('SELECT user_password, user_name FROM users ORDER BY user_name', $this->fields);
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Error during query');
    -        }
    -        $values = $result->fetchAll(MDB2_FETCHMODE_ASSOC, true, true, true);
    -        if (PEAR::isError($values)) {
    -            $this->assertTrue(false, 'Error fetching the result set');
    -        } else {
    -            //all the records have the same user_password value
    -            $this->assertEquals(1, count($values), 'Error: incorrect number of returned rows');
    -            $values = $values[$data[0]['user_password']];
    -            for ($i=0; $i<$total_rows; $i++) {
    -                $this->assertEquals($data[$i]['user_name'], $values[$i]['user_name'], 'Row #'.$i.' ["user_name"]');
    -            }
    -        }
    -        $result->free();
    -
    -        //test $rekey=true, $force_array=true, $group=false (with non unique key)
    -        $result =& $this->db->query('SELECT user_password, user_name FROM users ORDER BY user_name', $this->fields);
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Error during query');
    -        }
    -        $values = $result->fetchAll(MDB2_FETCHMODE_ASSOC, true, true, false);
    -        if (PEAR::isError($values)) {
    -            $this->assertTrue(false, 'Error fetching the result set');
    -        } else {
    -            //all the records have the same user_password value, they are overwritten
    -            $this->assertEquals(1, count($values), 'Error: incorrect number of returned rows');
    -            $key = $data[0]['user_password'];
    -            $this->assertEquals(1, count($values[$key]), 'Error: incorrect number of returned rows');
    -            $this->assertEquals($data[4]['user_name'], $values[$key]['user_name']);
    -        }
    -        $result->free();
    -    }
    -
    -    /**
    -     * Test different fetch modes
    -     *
    -     * Test fetching results using different fetch modes
    -     * NOTE: several tests still missing
    -     */
    -    function testFetchModes() {
    -        $data = array();
    -        $total_rows = 5;
    -
    -        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
    -        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
    -
    -        for ($row = 0; $row < $total_rows; $row++) {
    -            $data[$row] = $this->getSampleData($row);
    -            $result = $stmt->execute(array_values($data[$row]));
    -
    -            if (PEAR::isError($result)) {
    -                $this->assertTrue(false, 'Error executing prepared query'.$result->getMessage());
    -            }
    -        }
    -
    -        $stmt->free();
    -
    -        // test ASSOC
    -        $query = 'SELECT A.user_name FROM users A, users B WHERE A.user_id = B.user_id';
    -        $value = $this->db->queryRow($query, array($this->fields['user_name']), MDB2_FETCHMODE_ASSOC);
    -        if (PEAR::isError($value)) {
    -            $this->assertTrue(false, 'Error fetching the result set');
    -        } else {
    -            $this->assertTrue(!empty($value['user_name']), 'Error fetching the associative result set from join');
    -        }
    -    }
    -
    -    /**
    -     * Test multi_query option
    -     *
    -     * This test attempts to send multiple queries at once using the multi_query
    -     * option and then retrieves each result.
    -     */
    -    function testMultiQuery() {
    -        $multi_query_orig = $this->db->getOption('multi_query');
    -        if (PEAR::isError($multi_query_orig)) {
    -            $this->assertTrue(false, 'Error getting multi_query option value: '.$multi_query_orig->getMessage());
    -            return;
    -        }
    -
    -        $this->db->setOption('multi_query', true);
    -
    -        $data = array();
    -        $total_rows = 5;
    -
    -        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
    -        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
    -
    -        for ($row = 0; $row < $total_rows; $row++) {
    -            $data[$row] = $this->getSampleData($row);
    -            $result = $stmt->execute(array_values($data[$row]));
    -
    -            if (PEAR::isError($result)) {
    -                $this->assertTrue(false, 'Error executing prepared query'.$result->getMessage());
    -            }
    -        }
    -
    -        $stmt->free();
    -
    -        $query = '';
    -        for ($row = 0; $row < $total_rows; $row++) {
    -            $query.= 'SELECT user_name FROM users WHERE user_id='.$row.';';
    -        }
    -        $result =& $this->db->query($query, 'text');
    -
    -        for ($row = 0; $row < $total_rows; $row++) {
    -            $value = $result->fetchOne();
    -            if (PEAR::isError($value)) {
    -                $this->assertTrue(false, 'Error fetching row '.$row);
    -            } else {
    -                $this->assertEquals(strval($data[$row]['user_name']), strval(trim($value)), 'the query field username of type "text" for row '.$row);
    -            }
    -            if (PEAR::isError($result->nextResult())) {
    -                $this->assertTrue(false, 'Error moving result pointer');
    -            }
    -        }
    -
    -        $result->free();
    -        $this->db->setOption('multi_query', $multi_query_orig);
    -    }
    -
    -    /**
    -     * Test prepared queries
    -     *
    -     * Tests prepared queries, making sure they correctly deal with ?, !, and '
    -     */
    -    function testPreparedQueries() {
    -        $data = array(
    -            array(
    -                'user_name' => 'Sure!',
    -                'user_password' => 'Do work?',
    -                'user_id' => 1,
    -            ),
    -            array(
    -                'user_name' => 'For Sure!',
    -                'user_password' => "Doesn't?",
    -                'user_id' => 2,
    -            ),
    -        );
    -
    -        $query = "INSERT INTO users (user_name, user_password, user_id) VALUES (?, ?, ?)";
    -        $stmt = $this->db->prepare($query, array('text', 'text', 'integer'), MDB2_PREPARE_MANIP);
    -
    -        $text = $data[0]['user_name'];
    -        $question = $data[0]['user_password'];
    -        $userid = $data[0]['user_id'];
    -
    -        // bind out of order
    -        $stmt->bindParam(0, $text);
    -        $stmt->bindParam(2, $userid);
    -        $stmt->bindParam(1, $question);
    -
    -        $result = $stmt->execute();
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(true, 'Could not execute prepared query with question mark placeholders. Error: '.$error);
    -        }
    -
    -        $text = $data[1]['user_name'];
    -        $question = $data[1]['user_password'];
    -        $userid = $data[1]['user_id'];
    -
    -        $result = $stmt->execute();
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(true, 'Could not execute prepared query with bound parameters. Error: '.$error);
    -        }
    -        $stmt->free();
    -        $this->clearTables();
    -
    -        $query = "INSERT INTO users (user_name, user_password, user_id) VALUES (:text, :question, :userid)";
    -        $stmt = $this->db->prepare($query, array('text', 'text', 'integer'), MDB2_PREPARE_MANIP);
    -
    -        $stmt->bindValue('text', $data[0]['user_name']);
    -        $stmt->bindValue('question', $data[0]['user_password']);
    -        $stmt->bindValue('userid', $data[0]['user_id']);
    -
    -        $result = $stmt->execute();
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(true, 'Could not execute prepared query with named placeholders. Error: '.$error);
    -        }
    -        $stmt->free();
    -
    -        $query = "INSERT INTO users (user_name, user_password, user_id) VALUES (".$this->db->quote($data[1]['user_name'], 'text').", :question, :userid)";
    -        $stmt = $this->db->prepare($query, array('text', 'integer'), MDB2_PREPARE_MANIP);
    -
    -        $stmt->bindValue('question', $data[1]['user_password']);
    -        $stmt->bindValue('userid', $data[1]['user_id']);
    -
    -        $result = $stmt->execute();
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(true, 'Could not execute prepared query with named placeholders and a quoted text value in front. Error: '.$error);
    -        }
    -        $stmt->free();
    -
    -        $query = 'SELECT user_name, user_password, user_id FROM users WHERE user_id=:user_id';
    -        $stmt = $this->db->prepare($query, array('integer'), array('text', 'text', 'integer'));
    -        foreach ($data as $row_data) {
    -            $result =& $stmt->execute(array('user_id' => $row_data['user_id']));
    -            if (PEAR::isError($result)) {
    -                $this->assertTrue(!PEAR::isError($result), 'Could not execute prepared. Error: '.$result->getUserinfo());
    -                break;
    -            }
    -            $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
    -            if (!is_array($row)) {
    -                $this->assertTrue(false, 'Prepared SELECT failed');
    -            } else {
    -                $diff = (array)array_diff($row, $row_data);
    -                $this->assertTrue(empty($diff), 'Prepared SELECT failed for fields: '.implode(', ', array_keys($diff)));
    -            }
    -        }
    -        $stmt->free();
    -
    -        $row_data = reset($data);
    -        $query = 'SELECT user_name, user_password, user_id FROM users WHERE user_id='.$this->db->quote($row_data['user_id'], 'integer');
    -        $stmt = $this->db->prepare($query, null, array('text', 'text', 'integer'));
    -        $result =& $stmt->execute(array());
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(!PEAR::isError($result), 'Could not execute prepared statement with no placeholders. Error: '.$result->getUserinfo());
    -            break;
    -        }
    -        $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
    -        if (!is_array($row)) {
    -            $this->assertTrue(false, 'Prepared SELECT failed');
    -        } else {
    -            $diff = (array)array_diff($row, $row_data);
    -            $this->assertTrue(empty($diff), 'Prepared SELECT failed for fields: '.implode(', ', array_keys($diff)));
    -        }
    -        $stmt->free();
    -
    -        $row_data = reset($data);
    -        $query = 'SELECT user_name, user_password, user_id FROM users WHERE user_name='.$this->db->quote($row_data['user_name'], 'text').' AND user_id = ? AND user_password='.$this->db->quote($row_data['user_password'], 'text');
    -        $stmt = $this->db->prepare($query, array('integer'), array('text', 'text', 'integer'));
    -        $result =& $stmt->execute(array($row_data['user_id']));
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(!PEAR::isError($result), 'Could not execute prepared with quoted text fields around a placeholder. Error: '.$result->getUserinfo());
    -            break;
    -        }
    -        $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
    -        if (!is_array($row)) {
    -            $this->assertTrue(false, 'Prepared SELECT failed');
    -        } else {
    -            $diff = (array)array_diff($row, $row_data);
    -            $this->assertTrue(empty($diff), 'Prepared SELECT failed for fields: '.implode(', ', array_keys($diff)));
    -        }
    -        $stmt->free();
    -
    -        foreach ($this->db->sql_comments as $comment) {
    -            $query = 'SELECT user_name, user_password, user_id FROM users WHERE '.$comment['start'].' maps to class::foo() '.$comment['end'].' user_name=:username';
    -            $row_data = reset($data);
    -            $stmt = $this->db->prepare($query, array('text'), array('text', 'text', 'integer'));
    -            $result =& $stmt->execute(array('username' => $row_data['user_name']));
    -            if (PEAR::isError($result)) {
    -                $this->assertTrue(!PEAR::isError($result), 'Could not execute prepared where a name parameter is contained in an SQL comment ('.$comment['start'].'). Error: '.$result->getUserinfo());
    -                break;
    -            }
    -            $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
    -            if (!is_array($row)) {
    -                $this->assertTrue(false, 'Prepared SELECT failed');
    -            } else {
    -                $diff = (array)array_diff($row, $row_data);
    -                $this->assertTrue(empty($diff), 'Prepared SELECT failed for fields: '.implode(', ', array_keys($diff)));
    -            }
    -            $stmt->free();
    -        }
    -
    -        $row_data = reset($data);
    -        $query = 'SELECT user_name, user_password, user_id FROM users WHERE user_name=:username OR user_password=:username';
    -        $stmt = $this->db->prepare($query, array('text'), array('text', 'text', 'integer'));
    -        $result =& $stmt->execute(array('username' => $row_data['user_name']));
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(!PEAR::isError($result), 'Could not execute prepared where the same named parameter is used twice. Error: '.$result->getUserinfo());
    -            break;
    -        }
    -        $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
    -        if (!is_array($row)) {
    -            $this->assertTrue(false, 'Prepared SELECT failed');
    -        } else {
    -            $diff = (array)array_diff($row, $row_data);
    -            $this->assertTrue(empty($diff), 'Prepared SELECT failed for fields: '.implode(', ', array_keys($diff)));
    -        }
    -        $stmt->free();
    -    }
    -
    -    /**
    -     * Test _skipDelimitedStrings(), used by prepare()
    -     *
    -     * If the placeholder is contained within a delimited string, it must be skipped,
    -     * and the cursor position must be advanced
    -     */
    -    function testSkipDelimitedStrings() {
    -        //test correct placeholder
    -        $query = 'SELECT what FROM tbl WHERE x = ?';
    -        $position = 0;
    -        $p_position = strpos($query, '?');
    -        $this->assertEquals($position, $this->db->_skipDelimitedStrings($query, $position, $p_position), 'Error: the cursor position has changed');
    -
    -        //test placeholder within a quoted string
    -        $query = 'SELECT what FROM tbl WHERE x = '. $this->db->string_quoting['start'] .'blah?blah'. $this->db->string_quoting['end'] .' AND y = ?';
    -        $position = 0;
    -        $p_position = strpos($query, '?');
    -        $new_pos = $this->db->_skipDelimitedStrings($query, $position, $p_position);
    -        $this->assertTrue($position != $new_pos, 'Error: the cursor position was not advanced');
    -
    -        //test placeholder within a comment
    -        foreach ($this->db->sql_comments as $comment) {
    -            $query = 'SELECT what FROM tbl WHERE x = '. $comment['start'] .'blah?blah'. $comment['end'] .' AND y = ?';
    -            $position = 0;
    -            $p_position = strpos($query, '?');
    -            $new_pos = $this->db->_skipDelimitedStrings($query, $position, $p_position);
    -            $this->assertTrue($position != $new_pos, 'Error: the cursor position was not advanced');
    -        }
    -
    -        //add some tests for named placeholders and for identifier_quoting
    -    }
    -
    -    /**
    -     * Test retrieval of result metadata
    -     *
    -     * This tests the result metadata by executing a prepared query and
    -     * select the data, and checking the result contains the correct
    -     * number of columns and that the column names are in the correct order
    -     */
    -    function testMetadata() {
    -        $data = $this->getSampleData(1234);
    -
    -        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
    -        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
    -
    -        $result = $stmt->execute(array_values($data));
    -        $stmt->free();
    -
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Error executing prepared query'.$result->getMessage());
    -        }
    -
    -        $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users';
    -        $result =& $this->db->query($query, $this->fields);
    -
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Error selecting from users'.$result->getMessage());
    -        }
    -
    -        $numcols = $result->numCols();
    -
    -        $this->assertEquals(count($this->fields), $numcols, "The query result returned an incorrect number of columns unlike expected");
    -
    -        $column_names = $result->getColumnNames();
    -        $fields = array_keys($this->fields);
    -        for ($column = 0; $column < $numcols; $column++) {
    -            $this->assertEquals($column, $column_names[$fields[$column]], "The query result column \"".$fields[$column]."\" was returned in an incorrect position");
    -        }
    -
    -    }
    -
    -    /**
    -     * Test storage and retrieval of nulls
    -     *
    -     * This tests null storage and retrieval by successively inserting,
    -     * selecting, and testing a number of null / not null values
    -     */
    -    function testNulls() {
    -        $portability = $this->db->getOption('portability');
    -        if ($portability & MDB2_PORTABILITY_EMPTY_TO_NULL) {
    -            $nullisempty = true;
    -        } else {
    -            $nullisempty = false;
    -        }
    -        $test_values = array(
    -            array('test', false),
    -            array('NULL', false),
    -            array('null', false),
    -            array('', $nullisempty),
    -            array(null, true)
    -        );
    -
    -        for ($test_value = 0; $test_value <= count($test_values); $test_value++) {
    -            if ($test_value == count($test_values)) {
    -                $value = 'NULL';
    -                $is_null = true;
    -            } else {
    -                $value = $this->db->quote($test_values[$test_value][0], 'text');
    -                $is_null = $test_values[$test_value][1];
    -            }
    -
    -            $this->clearTables();
    -
    -            $result = $this->db->exec("INSERT INTO users (user_name,user_password,user_id) VALUES ($value,$value,0)");
    -
    -            if (PEAR::isError($result)) {
    -                $this->assertTrue(false, 'Error executing insert query'.$result->getMessage());
    -            }
    -
    -            $result =& $this->db->query('SELECT user_name,user_password FROM users', array('text', 'text'));
    -
    -            if (PEAR::isError($result)) {
    -                $this->assertTrue(false, 'Error executing select query'.$result->getMessage());
    -            }
    -
    -            if ($is_null) {
    -                $error_message = 'A query result column is not NULL unlike what was expected';
    -            } else {
    -                $error_message = 'A query result column is NULL even though it was expected to be differnt';
    -            }
    -
    -            $row = $result->fetchRow();
    -            $this->assertTrue((is_null($row[0]) == $is_null), $error_message);
    -            $this->assertTrue((is_null($row[1]) == $is_null), $error_message);
    -
    -            $result->free();
    -        }
    -
    -        $methods = array('fetchOne', 'fetchRow');
    -
    -        foreach ($methods as $method) {
    -            $result =& $this->db->query('SELECT user_name FROM users WHERE user_id=123', array('text'));
    -            $value = $result->$method();
    -            if (PEAR::isError($value)) {
    -                $this->assertTrue(false, 'Error fetching non existant row');
    -            } else {
    -                $this->assertNull($value, 'selecting non existant row with "'.$method.'()" did not return NULL');
    -                $result->free();
    -            }
    -        }
    -
    -        $methods = array('fetchCol', 'fetchAll');
    -
    -        foreach ($methods as $method) {
    -            $result =& $this->db->query('SELECT user_name FROM users WHERE user_id=123', array('text'));
    -            $value = $result->$method();
    -            if (PEAR::isError($value)) {
    -                $this->assertTrue(false, 'Error fetching non existant row');
    -            } else {
    -                $this->assertTrue((is_array($value) && empty($value)), 'selecting non existant row with "'.$method.'()" did not return empty array');
    -                $result->free();
    -            }
    -        }
    -
    -        $methods = array('queryOne', 'queryRow');
    -
    -        foreach ($methods as $method) {
    -            $value = $this->db->$method('SELECT user_name FROM users WHERE user_id=123', array('text'));
    -            if (PEAR::isError($value)) {
    -                $this->assertTrue(false, 'Error fetching non existant row');
    -            } else {
    -                $this->assertNull($value, 'selecting non existant row with "'.$method.'()" did not return NULL');
    -                $result->free();
    -            }
    -        }
    -
    -        $methods = array('queryCol', 'queryAll');
    -
    -        foreach ($methods as $method) {
    -            $value = $this->db->$method('SELECT user_name FROM users WHERE user_id=123', array('text'));
    -            if (PEAR::isError($value)) {
    -                $this->assertTrue(false, 'Error fetching non existant row');
    -            } else {
    -                $this->assertTrue((is_array($value) && empty($value)), 'selecting non existant row with "'.$method.'()" did not return empty array');
    -                $result->free();
    -            }
    -        }
    -    }
    -
    -    /**
    -     * Test paged queries
    -     *
    -     * Test the use of setLimit to return paged queries
    -     */
    -    function testRanges() {
    -        if (!$this->supported('limit_queries')) {
    -            return;
    -        }
    -
    -        $data = array();
    -        $total_rows = 5;
    -
    -        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
    -        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
    -
    -        for ($row = 0; $row < $total_rows; $row++) {
    -            $data[$row] = $this->getSampleData($row);
    -            $result = $stmt->execute(array_values($data[$row]));
    -
    -            if (PEAR::isError($result)) {
    -                $this->assertTrue(false, 'Error executing prepared query'.$result->getMessage());
    -            }
    -        }
    -
    -        $stmt->free();
    -
    -        for ($rows = 2, $start_row = 0; $start_row < $total_rows; $start_row += $rows) {
    -
    -            $this->db->setLimit($rows, $start_row);
    -
    -            $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users ORDER BY user_name';
    -            $result =& $this->db->query($query, $this->fields);
    -
    -            if (PEAR::isError($result)) {
    -                $this->assertTrue(false, 'Error executing select query'.$result->getMessage());
    -            }
    -
    -            for ($row = 0; $row < $rows && ($row + $start_row < $total_rows); $row++) {
    -                $this->verifyFetchedValues($result, $row, $data[$row + $start_row]);
    -            }
    -        }
    -
    -        $this->assertTrue(!$result->valid(), "The query result did not seem to have reached the end of result as expected starting row $start_row after fetching upto row $row");
    -
    -        $result->free();
    -
    -        for ($rows = 2, $start_row = 0; $start_row < $total_rows; $start_row += $rows) {
    -
    -            $this->db->setLimit($rows, $start_row);
    -
    -            $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users ORDER BY user_name';
    -            $result =& $this->db->query($query, $this->fields);
    -
    -            if (PEAR::isError($result)) {
    -                $this->assertTrue(false, 'Error executing select query'.$result->getMessage());
    -            }
    -
    -            $result_rows = $result->numRows();
    -
    -            $this->assertTrue(($result_rows <= $rows), 'expected a result of no more than '.$rows.' but the returned number of rows is '.$result_rows);
    -
    -            for ($row = 0; $row < $result_rows; $row++) {
    -                $this->assertTrue($result->valid(), 'The query result seem to have reached the end of result at row '.$row.' that is before '.$result_rows.' as expected');
    -
    -                $this->verifyFetchedValues($result, $row, $data[$row + $start_row]);
    -            }
    -        }
    -
    -        $this->assertTrue(!$result->valid(), "The query result did not seem to have reached the end of result as expected starting row $start_row after fetching upto row $row");
    -
    -        $result->free();
    -    }
    -
    -    /**
    -     * Test the handling of sequences
    -     */
    -    function testSequences() {
    -        if (!$this->supported('sequences')) {
    -           return;
    -        }
    -
    -        $this->db->loadModule('Manager', null, true);
    -
    -        for ($start_value = 1; $start_value < 4; $start_value++) {
    -            $sequence_name = "test_sequence_$start_value";
    -
    -            $result = $this->db->manager->createSequence($sequence_name, $start_value);
    -            if (PEAR::isError($result)) {
    -                $this->assertTrue(false, "Error creating sequence $sequence_name with start value $start_value: ".$result->getMessage());
    -            } else {
    -                for ($sequence_value = $start_value; $sequence_value < ($start_value + 4); $sequence_value++) {
    -                    $value = $this->db->nextId($sequence_name, false);
    -
    -                    $this->assertEquals($sequence_value, $value, "The returned sequence value is not expected with sequence start value with $start_value");
    -                }
    -
    -                $result = $this->db->manager->dropSequence($sequence_name);
    -
    -                if (PEAR::isError($result)) {
    -                    $this->assertTrue(false, "Error dropping sequence $sequence_name : ".$result->getMessage());
    -                }
    -            }
    -        }
    -
    -        // Test ondemand creation of sequences
    -        $sequence_name = 'test_ondemand';
    -        $this->db->expectError(MDB2_ERROR_NOSUCHTABLE);
    -        $this->db->manager->dropSequence($sequence_name);
    -        $this->db->popExpect();
    -
    -        for ($sequence_value = 1; $sequence_value < 4; $sequence_value++) {
    -            $value = $this->db->nextId($sequence_name);
    -
    -            if (PEAR::isError($result)) {
    -                $this->assertTrue(false, "Error creating with ondemand sequence: ".$result->getMessage());
    -            } else {
    -                $this->assertEquals($sequence_value, $value, "Error in ondemand sequences. The returned sequence value is not expected value");
    -            }
    -        }
    -
    -        $result = $this->db->manager->dropSequence($sequence_name);
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, "Error dropping sequence $sequence_name : ".$result->getMessage());
    -        }
    -
    -        // Test currId()
    -        $sequence_name = 'test_currid';
    -
    -        $next = $this->db->nextId($sequence_name);
    -        $curr = $this->db->currId($sequence_name);
    -
    -        if (PEAR::isError($curr)) {
    -            $this->assertTrue(false, "Error getting the current value of sequence $sequence_name : ".$curr->getMessage());
    -        } else {
    -            if ($next != $curr) {
    -                if ($next+1 == $curr) {
    -                    $this->assertTrue(false, "Warning: currId() is using nextId() instead of a native implementation");
    -                } else {
    -                    $this->assertEquals($next, $curr, "return value if currId() does not match the previous call to nextId()");
    -                }
    -            }
    -        }
    -        $result = $this->db->manager->dropSequence($sequence_name);
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, "Error dropping sequence $sequence_name : ".$result->getMessage());
    -        }
    -
    -        // Test lastInsertid()
    -        if (!$this->supported('new_link')) {
    -           return;
    -        }
    -
    -        $sequence_name = 'test_lastinsertid';
    -
    -        $dsn = MDB2::parseDSN($this->dsn);
    -        $dsn['new_link'] = true;
    -        $dsn['database'] = $this->database;
    -        $db =& MDB2::connect($dsn, $this->options);
    -
    -        $next = $this->db->nextId($sequence_name);
    -        $next2 = $db->nextId($sequence_name);
    -        $last = $this->db->lastInsertId($sequence_name);
    -
    -        if (PEAR::isError($last)) {
    -            $this->assertTrue(false, "Error getting the last value of sequence $sequence_name : ".$last->getMessage());
    -        } else {
    -            $this->assertEquals($next, $last, "return value if lastInsertId() does not match the previous call to nextId()");
    -        }
    -        $result = $this->db->manager->dropSequence($sequence_name);
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, "Error dropping sequence $sequence_name : ".$result->getMessage());
    -        }
    -    }
    -
    -    /**
    -     * Test replace query
    -     *
    -     * The replace method emulates the replace query of mysql
    -     */
    -    function testReplace() {
    -        if (!$this->supported('replace')) {
    -            return;
    -        }
    -
    -        $row = 1234;
    -        $data = $this->getSampleData($row);
    -
    -        $fields = array(
    -            'user_name' => array(
    -                'value' => "user_$row",
    -                'type' => 'text'
    -            ),
    -            'user_password' => array(
    -                'value' => $data['user_password'],
    -                'type' => 'text'
    -            ),
    -            'subscribed' => array(
    -                'value' => $data['subscribed'],
    -                'type' => 'boolean'
    -            ),
    -            'user_id' => array(
    -                'value' => $data['user_id'],
    -                'type' => 'integer',
    -                'key' => 1
    -            ),
    -            'quota' => array(
    -                'value' => $data['quota'],
    -                'type' => 'decimal'
    -            ),
    -            'weight' => array(
    -                'value' => $data['weight'],
    -                'type' => 'float'
    -            ),
    -            'access_date' => array(
    -                'value' => $data['access_date'],
    -                'type' => 'date'
    -            ),
    -            'access_time' => array(
    -                'value' => $data['access_time'],
    -                'type' => 'time'
    -            ),
    -            'approved' => array(
    -                'value' => $data['approved'],
    -                'type' => 'timestamp'
    -            )
    -        );
    -
    -        $result = $this->db->replace('users', $fields);
    -
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Replace failed');
    -        }
    -
    -        if ($this->db->supports('affected_rows')) {
    -            $affected_rows = $result;
    -
    -            $this->assertEquals(1, $result, "replacing a row in an empty table returned incorrect value");
    -        } else {
    -            $this->assertTrue(false, '"affected_rows" is not supported');
    -        }
    -
    -        $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users';
    -        $result =& $this->db->query($query, $this->fields);
    -
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Error selecting from users'.$result->getMessage());
    -        }
    -
    -        $this->verifyFetchedValues($result, 0, $data);
    -
    -        $row = 4321;
    -        $fields['user_name']['value']     = $data['user_name']     = 'user_'.$row;
    -        $fields['user_password']['value'] = $data['user_password'] = 'somepass';
    -        $fields['subscribed']['value']    = $data['subscribed']    = $row % 2 ? true : false;
    -        $fields['quota']['value']         = $data['quota']         = strval($row/100);
    -        $fields['weight']['value']        = $data['weight']        = sqrt($row);
    -        $fields['access_date']['value']   = $data['access_date']   = MDB2_Date::mdbToday();
    -        $fields['access_time']['value']   = $data['access_time']   = MDB2_Date::mdbTime();
    -        $fields['approved']['value']      = $data['approved']      = MDB2_Date::mdbNow();
    -
    -        $result = $this->db->replace('users', $fields);
    -
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Replace failed');
    -        }
    -        if ($this->db->supports('affected_rows')) {
    -            $this->assertEquals(2, $result, "replacing a row returned incorrect result");
    -        }
    -
    -        $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users';
    -        $result =& $this->db->query($query, $this->fields);
    -
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Error selecting from users'.$result->getMessage());
    -        }
    -
    -        $this->verifyFetchedValues($result, 0, $data);
    -
    -        $this->assertTrue(!$result->valid(), 'the query result did not seem to have reached the end of result as expected');
    -
    -        $result->free();
    -    }
    -
    -    /**
    -     * Test affected rows methods
    -     */
    -    function testAffectedRows() {
    -        if (!$this->supported('affected_rows')) {
    -            return;
    -        }
    -
    -        $data = array();
    -        $total_rows = 7;
    -
    -        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
    -        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
    -
    -        for ($row = 0; $row < $total_rows; $row++) {
    -            $data[$row] = $this->getSampleData($row);
    -            $result = $stmt->execute(array_values($data[$row]));
    -
    -            if (PEAR::isError($result)) {
    -                $this->assertTrue(false, 'Error executing prepared query'.$result->getMessage());
    -            }
    -
    -            $this->assertEquals(1, $result, "Inserting the row $row returned incorrect affected row count");
    -        }
    -
    -        $stmt->free();
    -
    -        $query = 'UPDATE users SET user_password=? WHERE user_id < ?';
    -        $stmt = $this->db->prepare($query, array('text', 'integer'), MDB2_PREPARE_MANIP);
    -
    -        for ($row = 0; $row < $total_rows; $row++) {
    -            $password = "pass_$row";
    -            if ($row == 0) {
    -                $stmt->bindParam(0, $password);
    -                $stmt->bindParam(1, $row);
    -            }
    -
    -            $result = $stmt->execute();
    -
    -            if (PEAR::isError($result)) {
    -                $this->assertTrue(false, 'Error executing prepared query'.$result->getMessage());
    -            }
    -
    -            $this->assertEquals($row, $result, "Updating the $row rows returned incorrect affected row count");
    -        }
    -
    -        $stmt->free();
    -
    -        $query = 'DELETE FROM users WHERE user_id >= ?';
    -        $stmt = $this->db->prepare($query, array('integer'), MDB2_PREPARE_MANIP);
    -
    -        $row = intval($total_rows / 2);
    -        $stmt->bindParam(0, $row);
    -        for ($row = $total_rows; $total_rows; $total_rows = $row) {
    -            $row = intval($total_rows / 2);
    -
    -            $result = $stmt->execute();
    -
    -            if (PEAR::isError($result)) {
    -                $this->assertTrue(false, 'Error executing prepared query'.$result->getMessage());
    -            }
    -
    -            $this->assertEquals(($total_rows - $row), $result, 'Deleting rows returned incorrect affected row count');
    -
    -        }
    -
    -        $stmt->free();
    -    }
    -
    -    /**
    -     * Testing transaction support - Test ROLLBACK
    -     */
    -    function testTransactionsRollback() {
    -        if (!$this->supported('transactions')) {
    -            return;
    -        }
    -
    -        $data = $this->getSampleData(0);
    -
    -        $this->db->beginTransaction();
    -
    -        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
    -        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
    -
    -        $result = $stmt->execute(array_values($data));
    -        $this->db->rollback();
    -        $stmt->free();
    -
    -        $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users';
    -        $result =& $this->db->query($query);
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Error selecting from users'.$result->getMessage());
    -        }
    -        $this->assertTrue(!$result->valid(), 'Transaction rollback did not revert the row that was inserted');
    -        $result->free();
    -    }
    -
    -    /**
    -     * Testing transaction support - Test COMMIT
    -     */
    -    function testTransactionsCommit() {
    -        if (!$this->supported('transactions')) {
    -            return;
    -        }
    -
    -        $data = $this->getSampleData(1);
    -
    -        $this->db->beginTransaction();
    -
    -        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
    -        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
    -
    -        $result = $stmt->execute(array_values($data));
    -        $this->db->commit();
    -        $stmt->free();
    -
    -        $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users';
    -        $result =& $this->db->query($query);
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Error selecting from users'.$result->getMessage());
    -        }
    -        $this->assertTrue($result->valid(), 'Transaction commit did not make permanent the row that was inserted');
    -        $result->free();
    -    }
    -
    -    /**
    -     * Testing transaction support - Test COMMIT and ROLLBACK
    -     */
    -    function testTransactionsBoth()
    -    {
    -        if (!$this->supported('transactions')) {
    -            return;
    -        }
    -
    -        $data = $this->getSampleData(0);
    -
    -        $this->db->beginTransaction();
    -        $result = $this->db->exec('DELETE FROM users');
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Error deleting from users'.$result->getMessage());
    -            $this->db->rollback();
    -        } else {
    -            $this->db->commit();
    -        }
    -
    -        $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users';
    -        $result =& $this->db->query($query);
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Error selecting from users'.$result->getMessage());
    -        }
    -
    -        $this->assertTrue(!$result->valid(), 'Transaction end with implicit commit when re-enabling auto-commit did not make permanent the rows that were deleted');
    -        $result->free();
    -    }
    -
    -    /**
    -     * Testing emulated nested transaction support
    -     */
    -    function testNestedTransactions() {
    -        if (!$this->supported('transactions')) {
    -            return;
    -        }
    -
    -        $data = array(
    -            1 => $this->getSampleData(1234),
    -            2 => $this->getSampleData(4321),
    -        );
    -
    -        $this->db->beginNestedTransaction();
    -
    -        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
    -        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
    -
    -        $result = $stmt->execute(array_values($data[1]));
    -
    -        $this->db->beginNestedTransaction();
    -
    -        $result = $stmt->execute(array_values($data[2]));
    -        $stmt->free();
    -
    -        $result = $this->db->completeNestedTransaction();
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Inner transaction was not committed: '.$result->getMessage());
    -        }
    -
    -        $result = $this->db->completeNestedTransaction();
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Outer transaction was not committed: '.$result->getMessage());
    -        }
    -
    -        $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users';
    -        $result =& $this->db->query($query);
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Error selecting from users'.$result->getMessage());
    -        }
    -        $this->assertTrue($result->valid(), 'Transaction commit did not make permanent the row that was inserted');
    -        $result->free();
    -    }
    -
    -    /**
    -     * Testing savepoints
    -     */
    -    function testSavepoint() {
    -        if (!$this->supported('savepoints')) {
    -            return;
    -        }
    -
    -        $savepoint = 'test_savepoint';
    -
    -        $data = array(
    -            1 => $this->getSampleData(1234),
    -            2 => $this->getSampleData(4321),
    -        );
    -
    -        $this->db->beginTransaction();
    -
    -        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
    -        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
    -
    -        $result = $stmt->execute(array_values($data[1]));
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Error executing prepared query: '.$result->getMessage());
    -        }
    -
    -        $result = $this->db->beginTransaction($savepoint);
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Error setting savepoint: '.$result->getMessage());
    -        }
    -
    -        $result = $stmt->execute(array_values($data[2]));
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Error executing prepared query: '.$result->getMessage());
    -        }
    -        $stmt->free();
    -
    -        $result = $this->db->rollback($savepoint);
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Error rolling back to savepoint: '.$result->getMessage());
    -        }
    -
    -        $result = $this->db->commit();
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Transaction not committed: '.$result->getMessage());
    -        }
    -
    -        $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users';
    -        $result = $this->db->queryAll($query);
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Error selecting from users'.$result->getMessage());
    -        }
    -        $rows_inserted = count($result);
    -        $this->assertEquals(1, $rows_inserted, 'Error during transaction, invalid number of records inserted');
    -
    -        // test release savepoint
    -        $this->db->beginTransaction();
    -        $result = $this->db->beginTransaction($savepoint);
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Error setting savepoint: '.$result->getMessage());
    -        }
    -        $result = $this->db->commit($savepoint);
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Error setting savepoint: '.$result->getMessage());
    -        }
    -        $result = $this->db->commit();
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Transaction not committed: '.$result->getMessage());
    -        }
    -    }
    -
    -    /**
    -     * Testing LOB storage
    -     */
    -    function testLOBStorage() {
    -        if (!$this->supported('LOBs')) {
    -            return;
    -        }
    -
    -        $query = 'INSERT INTO files (ID, document, picture) VALUES (1, ?, ?)';
    -        $stmt = $this->db->prepare($query, array('clob', 'blob'), MDB2_PREPARE_MANIP, array('document', 'picture'));
    -
    -        $character_lob = '';
    -        $binary_lob = '';
    -
    -        for ($i = 0; $i < 1000; $i++) {
    -            for ($code = 32; $code <= 127; $code++) {
    -                $character_lob.= chr($code);
    -            }
    -            for ($code = 0; $code <= 255; $code++) {
    -                $binary_lob.= chr($code);
    -            }
    -        }
    -
    -        $stmt->bindParam(0, $character_lob);
    -        $stmt->bindParam(1, $binary_lob);
    -
    -        $result = $stmt->execute();
    -
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Error executing prepared query: '.$result->getUserInfo());
    -        }
    -
    -        $stmt->free();
    -
    -        $result =& $this->db->query('SELECT document, picture FROM files WHERE id = 1', array('clob', 'blob'));
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Error selecting from files'.$result->getMessage());
    -        }
    -
    -        $this->assertTrue($result->valid(), 'The query result seem to have reached the end of result too soon.');
    -
    -        $row = $result->fetchRow();
    -        $clob = $row[0];
    -        if (!PEAR::isError($clob) && is_resource($clob)) {
    -            $value = '';
    -            while (!feof($clob)) {
    -                $data = fread($clob, 8192);
    -                $this->assertTrue(strlen($data) >= 0, 'Could not read CLOB');
    -                $value.= $data;
    -            }
    -            $this->db->datatype->destroyLOB($clob);
    -            $this->assertEquals($character_lob, $value, 'Retrieved character LOB value is different from what was stored');
    -        } else {
    -            $this->assertTrue(false, 'Error retrieving CLOB result');
    -        }
    -
    -        $blob = $row[1];
    -        if (!PEAR::isError($blob) && is_resource($blob)) {
    -            $value = '';
    -            while (!feof($blob)) {
    -                $data = fread($blob, 8192);
    -                $this->assertTrue(strlen($data) >= 0, 'Could not read BLOB');
    -                $value.= $data;
    -            }
    -
    -            $this->db->datatype->destroyLOB($blob);
    -            $this->assertEquals($binary_lob, $value, 'Retrieved binary LOB value is different from what was stored');
    -        } else {
    -            $this->assertTrue(false, 'Error retrieving BLOB result');
    -        }
    -        $result->free();
    -    }
    -
    -    /**
    -     * Test LOB reading of multiple records both buffered and unbuffered. See bug #8793 for why this must be tested.
    -     */
    -    function testLOBRead() {
    -        if (!$this->supported('LOBs')) {
    -            return;
    -        }
    -
    -        for ($i = 20; $i < 30; ++$i) {
    -            $query = 'INSERT INTO files (ID, document, picture) VALUES (?, ?, ?)';
    -            $stmt = $this->db->prepare($query, array('integer', 'clob', 'blob'), MDB2_PREPARE_MANIP, array(1 => 'document', 2 => 'picture'));
    -            $character_lob = $binary_lob = $i;
    -            $stmt->bindParam(1, $character_lob);
    -            $stmt->bindParam(2, $binary_lob);
    -
    -            $result = $stmt->execute(array($i));
    -
    -            if (PEAR::isError($result)) {
    -                $this->assertTrue(false, 'Error executing prepared query: '.$result->getUserInfo());
    -            }
    -            $stmt->free();
    -        }
    -
    -        $oldBuffered = $this->db->getOption('result_buffering');
    -        foreach (array(true, false) as $buffered) {
    -            $this->db->setOption('result_buffering', $buffered);
    -            $msgPost = ' with result_buffering = '.($buffered ? 'true' : 'false');
    -            $result =& $this->db->query('SELECT id, document, picture FROM files WHERE id >= 20 and id <= 30 order by id asc', array('integer', 'clob', 'blob'));
    -            if (PEAR::isError($result)) {
    -                $this->assertTrue(false, 'Error selecting from files'.$msgPost.$result->getMessage());
    -            } else {
    -                if ($buffered) {
    -                    $this->assertTrue($result->valid(), 'The query result seem to have reached the end of result too soon'.$msgPost);
    -                }
    -                for ($i = 1; $i <= ($buffered ? 2 : 1); ++$i) {
    -                    $result->seek(0);
    -                    while ($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
    -                        foreach (array('document' => 'clob', 'picture' => 'blob') as $field => $type) {
    -                            $lob = $row[$field];
    -                            if (is_a($lob, 'oci-lob')) {
    -                                $lob = $lob->load();
    -                            } elseif (is_resource($lob)) {
    -                                $lob = fread($lob, 1000);
    -                            }
    -                            $this->assertEquals($lob, $row['id'], 'LOB ('.$type.') field ('.$field.') not equal to expected value ('.$row['id'].')'.$msgPost.' on run-through '.$i);
    -                        }
    -                    }
    -                }
    -                $result->free();
    -            }
    -        }
    -        $this->db->setOption('result_buffering', $oldBuffered);
    -    }
    -
    -    /**
    -     * Test for lob storage from and to files
    -     */
    -    function testLOBFiles() {
    -        if (!$this->supported('LOBs')) {
    -            return;
    -        }
    -
    -        $query = 'INSERT INTO files (ID, document, picture) VALUES (1, :document, :picture)';
    -        $stmt = $this->db->prepare($query, array('document' => 'clob', 'picture' => 'blob'), MDB2_PREPARE_MANIP);
    -
    -        $character_data_file = 'character_data';
    -        $file = fopen($character_data_file, 'w');
    -        $this->assertTrue(((bool)$file), 'Error creating clob file to read from');
    -        $character_data = '';
    -        for ($i = 0; $i < 1000; $i++) {
    -            for ($code = 32; $code <= 127; $code++) {
    -                $character_data.= chr($code);
    -            }
    -        }
    -        $this->assertTrue((fwrite($file, $character_data, strlen($character_data)) == strlen($character_data)), 'Error creating clob file to read from');
    -        fclose($file);
    -
    -        $binary_data_file = 'binary_data';
    -        $file = fopen($binary_data_file, 'wb');
    -        $this->assertTrue(((bool)$file), 'Error creating blob file to read from');
    -        $binary_data = '';
    -        for ($i = 0; $i < 1000; $i++) {
    -            for ($code = 0; $code <= 255; $code++) {
    -                $binary_data.= chr($code);
    -            }
    -        }
    -        $this->assertTrue((fwrite($file, $binary_data, strlen($binary_data)) == strlen($binary_data)), 'Error creating blob file to read from');
    -        fclose($file);
    -
    -        $character_data_file_tmp = 'file://'.$character_data_file;
    -        $stmt->bindParam('document', $character_data_file_tmp);
    -        $binary_data_file_tmp = 'file://'.$binary_data_file;
    -        $stmt->bindParam('picture', $binary_data_file_tmp);
    -
    -        $result = $stmt->execute();
    -        $this->assertTrue(!PEAR::isError($result), 'Error executing prepared query - inserting LOB from files');
    -
    -        $stmt->free();
    -
    -        $result =& $this->db->query('SELECT document, picture FROM files WHERE id = 1', array('clob', 'blob'));
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Error selecting from files'.$result->getMessage());
    -        }
    -
    -        $this->assertTrue($result->valid(), 'The query result seem to have reached the end of result too soon.');
    -
    -        $row = $result->fetchRow();
    -        $clob = $row[0];
    -        if (!PEAR::isError($clob) && is_resource($clob)) {
    -            unlink($character_data_file);
    -            $res = $this->db->datatype->writeLOBToFile($clob, $character_data_file);
    -            $this->db->datatype->destroyLOB($clob);
    -
    -            if (PEAR::isError($res)) {
    -                $this->assertTrue(false, 'Error writing character LOB in a file');
    -            } else {
    -                $file = fopen($character_data_file, 'r');
    -                $this->assertTrue($file, "Error opening character data file: $character_data_file");
    -                $value = '';
    -                while (!feof($file)) {
    -                    $value.= fread($file, 8192);
    -                }
    -                $this->assertEquals('string', gettype($value), "Could not read from character LOB file: $character_data_file");
    -                fclose($file);
    -
    -                $this->assertEquals($character_data, $value, "retrieved character LOB value is different from what was stored");
    -            }
    -        } else {
    -            $this->assertTrue(false, 'Error creating character LOB in a file');
    -        }
    -
    -        $blob = $row[1];
    -        if (!PEAR::isError($blob) && is_resource($blob)) {
    -            unlink($binary_data_file);
    -            $res = $this->db->datatype->writeLOBToFile($blob, $binary_data_file);
    -            $this->db->datatype->destroyLOB($blob);
    -
    -            if (PEAR::isError($res)) {
    -                $this->assertTrue(false, 'Error writing binary LOB in a file');
    -            } else {
    -                $file = fopen($binary_data_file, 'rb');
    -                $this->assertTrue($file, "Error opening binary data file: $binary_data_file");
    -                $value = '';
    -                while (!feof($file)) {
    -                    $value.= fread($file, 8192);
    -                }
    -                $this->assertEquals('string', gettype($value), "Could not read from binary LOB file: $binary_data_file");
    -                fclose($file);
    -
    -                $this->assertEquals($binary_data, $value, "retrieved binary LOB value is different from what was stored");
    -            }
    -        } else {
    -            $this->assertTrue(false, 'Error creating binary LOB in a file');
    -        }
    -
    -        $result->free();
    -    }
    -
    -    /**
    -     * Test handling of lob nulls
    -     */
    -    function testLOBNulls() {
    -        if (!$this->supported('LOBs')) {
    -            return;
    -        }
    -
    -        $query = 'INSERT INTO files (ID, document, picture) VALUES (1, :document, :picture)';
    -        $stmt = $this->db->prepare($query, array('document' => 'clob', 'picture' => 'blob'), MDB2_PREPARE_MANIP);
    -
    -        $null = null;
    -        $stmt->bindParam('document', $null);
    -        $stmt->bindParam('picture', $null);
    -
    -        $result = $stmt->execute();
    -        $this->assertTrue(!PEAR::isError($result), 'Error executing prepared query - inserting NULL lobs');
    -
    -        $stmt->free();
    -
    -        $result =& $this->db->query('SELECT document, picture FROM files', array('clob', 'blob'));
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Error selecting from files'.$result->getMessage());
    -        }
    -
    -        $this->assertTrue($result->valid(), 'The query result seem to have reached the end of result too soon.');
    -
    -        $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
    -        $this->assertTrue(is_null($row['document']), 'A query result large object column document is not NULL unlike what was expected');
    -        $this->assertTrue(is_null($row['picture']), 'A query result large object column picture is not NULL unlike what was expected');
    -
    -        $result->free();
    -    }
    -
    -    function testLOBUpdate() {
    -        if (!$this->supported('LOBs')) {
    -            return;
    -        }
    -
    -        $query = 'INSERT INTO files (ID, document, picture) VALUES (1, ?, ?)';
    -        $stmt = $this->db->prepare($query, array('clob', 'blob'), MDB2_PREPARE_MANIP, array('document', 'picture'));
    -
    -        $character_lob = '';
    -        $binary_lob = '';
    -
    -        for ($i = 0; $i < 1000; $i++) {
    -            for ($code = 32; $code <= 127; ++$code) {
    -                $character_lob .= chr($code);
    -            }
    -            for ($code = 0; $code <= 255; ++$code) {
    -                $binary_lob .= chr($code);
    -            }
    -        }
    -
    -        $stmt->bindParam(0, $character_lob);
    -        $stmt->bindParam(1, $binary_lob);
    -
    -        $result = $stmt->execute();
    -
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Error executing prepared query: '.$result->getUserInfo());
    -        }
    -
    -        $stmt->free();
    -
    -        $query = 'UPDATE files SET document = ?, picture = ? WHERE ID = 1';
    -        $stmt = $this->db->prepare($query, array('clob', 'blob'), MDB2_PREPARE_MANIP, array('document', 'picture'));
    -
    -        $character_lob = '';
    -        $binary_lob = '';
    -
    -        for ($i = 0; $i < 999; $i++) {
    -            for ($code = 127; $code >= 32; --$code) {
    -                $character_lob .= chr($code);
    -            }
    -            for ($code = 255; $code >= 0; --$code) {
    -                $binary_lob .= chr($code);
    -            }
    -        }
    -
    -        $stmt->bindParam(0, $character_lob);
    -        $stmt->bindParam(1, $binary_lob);
    -
    -        $result = $stmt->execute();
    -
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Error executing prepared query: '.$result->getUserInfo());
    -        }
    -
    -        $stmt->free();
    -
    -        $result =& $this->db->query('SELECT document, picture FROM files WHERE id = 1', array('clob', 'blob'));
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Error selecting from files'.$result->getMessage());
    -        }
    -
    -        $this->assertTrue($result->valid(), 'The query result seem to have reached the end of result too soon.');
    -
    -        $row = $result->fetchRow();
    -        $clob = $row[0];
    -        if (!PEAR::isError($clob) && is_resource($clob)) {
    -            $value = '';
    -            while (!feof($clob)) {
    -                $data = fread($clob, 8192);
    -                $this->assertTrue(strlen($data) >= 0, 'Could not read CLOB');
    -                $value.= $data;
    -            }
    -            $this->db->datatype->destroyLOB($clob);
    -            $this->assertEquals($character_lob, $value, 'Retrieved character LOB value is different from what was stored');
    -        } else {
    -            $this->assertTrue(false, 'Error retrieving CLOB result');
    -        }
    -
    -        $blob = $row[1];
    -        if (!PEAR::isError($blob) && is_resource($blob)) {
    -            $value = '';
    -            while (!feof($blob)) {
    -                $data = fread($blob, 8192);
    -                $this->assertTrue(strlen($data) >= 0, 'Could not read BLOB');
    -                $value.= $data;
    -            }
    -
    -            $this->db->datatype->destroyLOB($blob);
    -            $this->assertEquals($binary_lob, $value, 'Retrieved binary LOB value is different from what was stored');
    -        } else {
    -            $this->assertTrue(false, 'Error retrieving BLOB result');
    -        }
    -        $result->free();
    -    }
    -
    -    /**
    -     * Test retrieval of result metadata
    -     *
    -     * This tests the result metadata by executing a prepared query and
    -     * select the data, and checking the result contains the correct
    -     * number of columns and that the column names are in the correct order
    -     */
    -    function testConvertEmpty2Null() {
    -#$this->db->setOption('portability', MDB2_PORTABILITY_ALL ^ MDB2_PORTABILITY_EMPTY_TO_NULL);
    -
    -        $data = $this->getSampleData(1234);
    -        $data['user_password'] = '';
    -
    -        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
    -        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
    -        $result = $stmt->execute(array_values($data));
    -        $stmt->free();
    -
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Error executing prepared query'.$result->getMessage());
    -        }
    -
    -        $row = $this->db->queryRow('SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users WHERE user_password IS NULL', $this->fields);
    -
    -        if (PEAR::isError($row)) {
    -            $this->assertTrue(false, 'Error selecting from users'.$result->getMessage());
    -        }
    -
    -        $this->assertEquals(count($this->fields), count($row), "The query result returned a number of columns unlike ".count($this->fields) .' as expected');
    -    }
    -
    -    function testPortabilityOptions() {
    -        // MDB2_PORTABILITY_DELETE_COUNT
    -        $data = array();
    -        $total_rows = 5;
    -
    -        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
    -        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
    -        for ($row = 0; $row < $total_rows; $row++) {
    -            $data[$row] = $this->getSampleData($row);
    -            $result = $stmt->execute(array_values($data[$row]));
    -            if (PEAR::isError($result)) {
    -                $this->assertTrue(false, 'Error executing prepared query'.$result->getMessage());
    -            }
    -        }
    -        $stmt->free();
    -
    -        $this->db->setOption('portability', MDB2_PORTABILITY_NONE | MDB2_PORTABILITY_DELETE_COUNT);
    -        $affected_rows = $this->db->exec('DELETE FROM users');
    -        if (PEAR::isError($affected_rows)) {
    -            $this->assertTrue(false, 'Error executing query'.$affected_rows->getMessage());
    -        }
    -        $this->assertEquals($total_rows, $affected_rows, 'MDB2_PORTABILITY_DELETE_COUNT not working');
    -
    -        // MDB2_PORTABILITY_FIX_CASE
    -        $fields = array_keys($this->fields);
    -        $this->db->setOption('portability', MDB2_PORTABILITY_NONE | MDB2_PORTABILITY_FIX_CASE);
    -        $this->db->setOption('field_case', CASE_UPPER);
    -
    -        $data = $this->getSampleData(1234);
    -        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
    -        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
    -        $result = $stmt->execute(array_values($data));
    -        $stmt->free();
    -
    -        $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users';
    -        $result =& $this->db->queryRow($query, $this->fields, MDB2_FETCHMODE_ASSOC);
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Error selecting from users'.$result->getMessage());
    -        }
    -        $field = reset($fields);
    -        foreach (array_keys($result) as $fieldname) {
    -            $this->assertEquals(strtoupper($field), $fieldname, 'MDB2_PORTABILITY_FIX_CASE CASE_UPPER not working');
    -            $field = next($fields);
    -        }
    -
    -        $this->db->setOption('field_case', CASE_LOWER);
    -        $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users';
    -        $result =& $this->db->queryRow($query, $this->fields, MDB2_FETCHMODE_ASSOC);
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Error selecting from users'.$result->getMessage());
    -        }
    -        $field = reset($fields);
    -        foreach (array_keys($result) as $fieldname) {
    -            $this->assertEquals(strtolower($field), $fieldname, 'MDB2_PORTABILITY_FIX_CASE CASE_LOWER not working');
    -            $field = next($fields);
    -        }
    -
    -        // MDB2_PORTABILITY_RTRIM
    -        $this->db->setOption('portability', MDB2_PORTABILITY_NONE | MDB2_PORTABILITY_RTRIM);
    -        $value = 'rtrim   ';
    -        $query = 'INSERT INTO users (user_id, user_password) VALUES (1, ' . $this->db->quote($value, 'text') .')';
    -        $res = $this->db->exec($query);
    -        if (PEAR::isError($res)) {
    -            $this->assertTrue(false, 'Error executing query'.$res->getMessage());
    -        }
    -        $query = 'SELECT user_password FROM users WHERE user_id = 1';
    -        $result = $this->db->queryOne($query, array('text'));
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Error selecting from users'.$result->getMessage());
    -        }
    -        $this->assertEquals(rtrim($value), $result, '"MDB2_PORTABILITY_RTRIM = on" not working');
    -
    -        if (!$this->supported('LOBs')) {
    -            return;
    -        }
    -
    -        $query = 'INSERT INTO files (ID, document, picture) VALUES (1, ?, ?)';
    -        $stmt = $this->db->prepare($query, array('clob', 'blob'), MDB2_PREPARE_MANIP, array('document', 'picture'));
    -
    -        $character_lob = '';
    -        $binary_lob = '';
    -
    -        for ($i = 0; $i < 999; $i++) {
    -            for ($code = 127; $code >= 32; --$code) {
    -                $character_lob .= chr($code);
    -            }
    -            for ($code = 255; $code >= 0; --$code) {
    -                $binary_lob .= chr($code);
    -            }
    -        }
    -
    -        $stmt->bindParam(0, $character_lob);
    -        $stmt->bindParam(1, $binary_lob);
    -
    -        $result = $stmt->execute();
    -
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Error executing prepared query: '.$result->getUserInfo());
    -        }
    -
    -        $stmt->free();
    -
    -        $result =& $this->db->query('SELECT document, picture FROM files WHERE id = 1', array('clob', 'blob'));
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Error selecting from files'.$result->getMessage());
    -        }
    -
    -        $this->assertTrue($result->valid(), 'The query result seem to have reached the end of result too soon.');
    -
    -        $row = $result->fetchRow();
    -        $clob = $row[0];
    -        if (!PEAR::isError($clob) && is_resource($clob)) {
    -            $value = '';
    -            while (!feof($clob)) {
    -                $data = fread($clob, 8192);
    -                $this->assertTrue(strlen($data) >= 0, 'Could not read CLOB');
    -                $value.= $data;
    -            }
    -            $this->db->datatype->destroyLOB($clob);
    -            $this->assertEquals($character_lob, $value, '"MDB2_PORTABILITY_RTRIM = on" Retrieved character LOB value is different from what was stored');
    -        } else {
    -            $this->assertTrue(false, 'Error retrieving CLOB result');
    -        }
    -
    -        $blob = $row[1];
    -        if (!PEAR::isError($blob) && is_resource($blob)) {
    -            $value = '';
    -            while (!feof($blob)) {
    -                $data = fread($blob, 8192);
    -                $this->assertTrue(strlen($data) >= 0, 'Could not read BLOB');
    -                $value.= $data;
    -            }
    -
    -            $this->db->datatype->destroyLOB($blob);
    -            $this->assertEquals($binary_lob, $value, '"MDB2_PORTABILITY_RTRIM = on" Retrieved binary LOB value is different from what was stored');
    -        } else {
    -            $this->assertTrue(false, 'Error retrieving BLOB result');
    -        }
    -        $result->free();
    -    }
    -
    -    /**
    -     * Test getAsKeyword()
    -     */
    -    function testgetAsKeyword()
    -    {
    -        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
    -        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
    -        $data = $this->getSampleData(1);
    -        $result = $stmt->execute(array_values($data));
    -        if (PEAR::isError($result)) {
    -            $this->assertTrue(false, 'Error executing prepared query'.$result->getMessage());
    -        }
    -        $stmt->free();
    -
    -        $query = 'SELECT user_id'.$this->db->getAsKeyword().'foo FROM users';
    -        $result = $this->db->queryRow($query, array('integer'), MDB2_FETCHMODE_ASSOC);
    -        if (PEAR::isError($result)) {
    -            $this->assertFalse(true, 'Error getting alias column:'. $result->getMessage());
    -        } else {
    -            $this->assertTrue((array_key_exists('foo', $result)), 'Error: could not alias "user_id" with "foo" :'.var_export($result, true));
    -        }
    -    }
    -}
    -
    -?>
    \ No newline at end of file
    diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/tests/README /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/tests/README
    --- php-mdb2-2.4.1/MDB2-2.4.1/tests/README	2007-05-03 19:58:15.000000000 +0100
    +++ php-mdb2-2.5.0b2/MDB2-2.4.1/tests/README	1970-01-01 01:00:00.000000000 +0100
    @@ -1,55 +0,0 @@
    -This is a test framework for MDB2 built using PHPUnit.
    -These tests directly access the MDB2 API - hopefully this framework
    -should give better feedback as to where or what caused when error are encountered.
    -
    -Usage:
    -In order for the tests to work they need to access a database called
    -"driver_test". This database is created using the MDB2_Schema test or
    -running the import.schema.php script (edit the db DSN information).
    -If you have problems running these test or the driver you are using does not yet
    -provide the necessary methods you may create the "driver_test" database manually:
    -
    -CREATE TABLE "files" (
    -  "id" int(11) NOT NULL default '0',
    -  "document" longtext,
    -  "picture" longblob,
    -  UNIQUE KEY "lob_id_index_idx" ("id")
    -);
    -
    -CREATE TABLE "users" (
    -  "user_name" varchar(12) default NULL,
    -  "user_password" char(8) default NULL,
    -  "subscribed" tinyint(1) default '1',
    -  "user_id" int(11) NOT NULL default '0',
    -  "quota" decimal(18,2) default '0.00',
    -  "weight" double default '0',
    -  "access_date" date default '1970-01-01',
    -  "access_time" time default '00:00:00',
    -  "approved" datetime default '1970-01-01 00:00:00',
    -  UNIQUE KEY "users_id_index_idx" ("user_id")
    -);
    -
    -To setup the tests
    -
    -* requires PHPUnit to be installed
    -
    -* requires MDB2 (with the given driver) to be installed
    -  in a php include path.
    -
    -* copy the file test_setup.php.dist to test_setup.php
    -
    -* edit test_setup.php. The array $testarray specifies which testcases
    -  to carry out. $dbarray is an array of databases to test.
    -
    -* point your browser at test.php or your CLI at clitest.php for the results,
    -  and then fix the bugs!
    -
    -* by default test.php/clitest.php will use all tests in the testcases - if
    -  you want to pick specific tests, use testchoose.php to pick just the
    -  tests you want to run
    -
    -Writing tests:
    -
    -The tests are written using PHPUnit from pear so first make sure you
    -have the latest stable release, and have read the docs,
    -http://pear.php.net/manual/en/packages.phpunit.php
    \ No newline at end of file
    diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/tests/testchoose.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/tests/testchoose.php
    --- php-mdb2-2.4.1/MDB2-2.4.1/tests/testchoose.php	2007-05-03 19:58:15.000000000 +0100
    +++ php-mdb2-2.5.0b2/MDB2-2.4.1/tests/testchoose.php	1970-01-01 01:00:00.000000000 +0100
    @@ -1,64 +0,0 @@
    -'."\n";
    -    $output.= ' TestCase : '.$testcase.''."\n";
    -    $testmethods[$testcase] = getTests($testcase);
    -    foreach ($testmethods[$testcase] as $method) {
    -        $output.= testCheck($testcase, $method);
    -    }
    -    $output.= "
    \n\n"; - $output.= "

    \n\n"; -} - -?> - - -MDB2 Tests - - - - - -
    - - -
    - - \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/tests/test.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/tests/test.php --- php-mdb2-2.4.1/MDB2-2.4.1/tests/test.php 2007-05-03 19:58:15.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.4.1/tests/test.php 1970-01-01 01:00:00.000000000 +0100 @@ -1,131 +0,0 @@ - | -// +----------------------------------------------------------------------+ -// -// $Id: test.php,v 1.18 2006/10/20 16:36:32 lsmith Exp $ - -/* - This is a small test suite for MDB2 using PHPUnit - */ - -require_once 'test_setup.php'; -require_once 'PHPUnit.php'; -require_once 'testUtils.php'; -require_once 'MDB2.php'; -require_once 'HTML_TestListener.php'; - -function htmlErrorHandler($errno, $errstr, $errfile, $errline) -{ - if ((!$GLOBALS['_show_silenced'] && !error_reporting()) || $errno == 2048) { - return; - } - echo '
    ';
    -    errorHandler($errno, $errstr, $errfile, $errline);
    -    echo '
    '; -} -set_error_handler('htmlErrorHandler'); - -function htmlErrorHandlerPEAR($error_obj) -{ - echo '
    ';
    -    errorHandlerPEAR($error_obj);
    -    echo '
    '; -} -PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'htmlErrorHandlerPEAR'); - -MDB2::loadFile('Date'); - -foreach ($testcases as $testcase) { - include_once $testcase.'.php'; -} - -$database = 'driver_test'; - -$testmethods = !empty($_POST['testmethods']) ? $_POST['testmethods'] : null; - -if (!is_array($testmethods)) { - foreach ($testcases as $testcase) { - $testmethods[$testcase] = array_flip(getTests($testcase)); - } -} - -?> - - -MDB2 Tests - - - -\n"; - echo "
    Testing $display_dsn on ".PHP_VERSION."
    \n"; - - $suite = new PHPUnit_TestSuite(); - - foreach ($testcases as $testcase) { - if (isset($testmethods[$testcase]) && is_array($testmethods[$testcase])) { - $methods = array_keys($testmethods[$testcase]); - foreach ($methods as $method) { - $suite->addTest(new $testcase($method)); - } - } - } - - $result = new PHPUnit_TestResult; - $result->addListener(new HTML_TestListener); - $suite->run($result); - $count = $result->runCount(); - $failed = $result->failureCount(); - - echo "
    Summary: $failed failed assertions in $count tests
    \n"; - echo "\n
    \n"; -} -?> - - diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/tests/tests.css /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/tests/tests.css --- php-mdb2-2.4.1/MDB2-2.4.1/tests/tests.css 2007-05-03 19:58:15.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.4.1/tests/tests.css 1970-01-01 01:00:00.000000000 +0100 @@ -1,37 +0,0 @@ - - -body { - background-color: #ffffff; - color: #000000; -} - -div.failure { - border: 2px #FF0000 solid; - margin : 1em; -} - -h1 { - font-size: x-small -} - -div.test { - border : 1px #000000 solid; - width : 100%; - margin-top : 1em; - padding : 2px; -} - -.title { - top : 0px; - left : 0px; - text-align : center; - background : #000000; - color : #FFFFFF; - padding : 4px; -} - -div.testlineup { - border: 2px #000000 solid; -} - - diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/tests/test_setup.php.dist /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/tests/test_setup.php.dist --- php-mdb2-2.4.1/MDB2-2.4.1/tests/test_setup.php.dist 2007-05-03 19:58:15.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.4.1/tests/test_setup.php.dist 1970-01-01 01:00:00.000000000 +0100 @@ -1,151 +0,0 @@ - array( - 'phptype' => 'mysql', - 'username' => 'username', - 'password' => 'password', - 'hostspec' => 'hostname', - ), - 'options' => array( - 'use_transactions' => true - ) -); - -$pgsql = array( - 'dsn' => array( - 'phptype' => 'pgsql', - 'username' => 'username', - 'password' => 'password', - 'hostspec' => 'hostname', - ) -); - -$oci8 = array( - 'dsn' => array( - 'phptype' => 'oci8', - 'username' => '', - 'password' => 'password', - 'hostspec' => 'hostname', - ), - 'options' => array( - 'DBA_username' => 'username', - 'DBA_password' => 'password' - ) -); - -$sqlite = array( - 'dsn' => array( - 'phptype' => 'sqlite', - 'username' => '', - 'password' => 'password', - 'hostspec' => 'hostname', - ), - 'options' => array( - 'database_path' => '', - 'database_extension' => '', - ) -); - -// must be a user with system administrator privileges -$mssql = array( - 'dsn' => array( - 'phptype' => 'mssql', - 'username' => 'username', - 'password' => 'password', - 'hostspec' => 'hostname', - ) -); - -$fbsql = array( - 'dsn' => array( - 'phptype' => 'fbsql', - 'username' => 'username', - 'password' => 'password', - 'hostspec' => 'hostname', - ) -); - - -$ibase = array( - 'dsn' => array( - 'phptype' => 'ibase', - 'username' => 'username', - 'password' => 'password', - 'hostspec' => 'hostname', - ) -); - -$dbarray = array(); -#$dbarray[] = $mysql; -#$dbarray[] = $pgsql; -#$dbarray[] = $oci8; -#$dbarray[] = $sqlite; -#$dbarray[] = $mssql; -#$dbarray[] = $fbsql; -#$dbarray[] = $ibase; - -// you may need to uncomment the line and modify the multiplier as you see fit -#set_time_limit(60*count($dbarray)); - -//if uncommented, the following will drop and recreate the test database when running the test -// the paths assumes that MDB2_Schema is checked out in the same parent directory as MDB2 -/* -require_once('MDB2/Schema.php'); -$schema_path = '../../MDB2_Schema/tests/'; - -function pe($e) { - die($e->getMessage().' '.$e->getUserInfo()); -} -PEAR::pushErrorHandling(PEAR_ERROR_CALLBACK, 'pe'); -foreach ($dbarray as $dbtype) { - // Work around oci8 problems with dropping the connected user - $dsn = $dbtype['dsn']; - if ($dbtype['dsn']['phptype'] == 'oci8') { - $dsn['username'] = $dbtype['options']['DBA_username']; - $dsn['password'] = $dbtype['options']['DBA_password']; - $dsn['database'] = $dbtype['options']['DBA_username']; - } - $db =& MDB2::connect($dsn, $dbtype['options']); - $db->loadModule('Manager'); - if (in_array('driver_test', $db->manager->listDatabases())) { - $db->manager->dropDatabase('driver_test'); - } - // Work around oci8 problems with dropping the connected user - if ($dbtype['dsn']['phptype'] == 'oci8') { - $db->query('CREATE USER '.$dbtype['dsn']['username'].' IDENTIFIED BY '.$dbtype['dsn']['password'].' DEFAULT TABLESPACE USERS QUOTA UNLIMITED ON USERS'); - $db->query('GRANT CREATE SESSION, CREATE TABLE, CREATE SEQUENCE, CREATE TRIGGER to '.$dbtype['dsn']['username']); - } - $schema =& MDB2_Schema::factory($dbtype['dsn'], $dbtype['options']); - $schema->updateDatabase( - '../../MDB2_Schema/tests/driver_test.schema', - false, - array('create' => '1', 'name' => 'driver_test') - ); - $schema->updateDatabase( - '../../MDB2_Schema/tests/lob_test.schema', - false, - array('create' => '1', 'name' => 'driver_test') - ); -} -PEAR::popErrorHandling(); -*/ - -?> diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.4.1/tests/testUtils.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.4.1/tests/testUtils.php --- php-mdb2-2.4.1/MDB2-2.4.1/tests/testUtils.php 2007-05-03 19:58:15.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.4.1/tests/testUtils.php 1970-01-01 01:00:00.000000000 +0100 @@ -1,123 +0,0 @@ -$testmethod
    \n"; -} - -/** - * Little helper function that gets a backtrace if available - */ -function getBacktrace($errline = 0) -{ - $message = ''; - if (!function_exists('debug_backtrace')) { - $message.= 'function debug_backtrace does not exists'."\n"; - } - - $debug_backtrace = debug_backtrace(); - array_shift($debug_backtrace); - $message.= 'Debug backtrace:'."\n"; - - foreach ($debug_backtrace as $trace_item) { - $message.= "\t" . ' @ '; - if (!empty($trace_item['file'])) { - $message.= basename($trace_item['file']) . ':' . $trace_item['line']; - } else { - $message.= '- PHP inner-code - '; - } - $message.= ' -- '; - if (!empty($trace_item['class'])) { - $message.= $trace_item['class'] . $trace_item['type']; - } - $message.= $trace_item['function']; - - if (!empty($trace_item['args']) && is_array($trace_item['args'])) { - $args = array(); - foreach ($trace_item['args'] as $arg) { - $args[] = is_scalar($arg) ? $arg : (is_object($arg) ? get_class($arg) : gettype($arg)); - } - $message.= '('.implode(', ', $args).')'; - } else { - $message.= '()'; - } - $message.= "\n"; - } - - return $message; -} - -require_once 'PEAR.php'; -function errorHandlerPEAR($error_obj) -{ - $message = "-- PEAR-Error --\n"; - $message.= $error_obj->getMessage().': '.$error_obj->getUserinfo()."\n"; - $message.= getBacktrace(); - - print_r($message); -} - -PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'errorHandlerPEAR'); - -$GLOBALS['_show_silenced'] = false; -function errorHandler($errno, $errstr, $errfile, $errline) -{ - if ((!$GLOBALS['_show_silenced'] && !error_reporting()) || $errno == 2048) { - return; - } - $message = "\n"; - switch ($errno) { - case E_USER_ERROR: - $message.= "FATAL [$errno] $errstr\n"; - $message.= " Fatal error in line $errline of file $errfile"; - $message.= ", PHP " . PHP_VERSION . " (" . PHP_OS . ")\n"; - $message.= "Aborting...\n"; - die($message); - break; - case E_USER_WARNING: - $message.= "ERROR [$errno] $errstr in line $errline of file $errfile\n"; - break; - case E_USER_NOTICE: - $message.= "WARNING [$errno] $errstr in line $errline of file $errfile\n"; - break; - default: - $message.= "Unkown error type: [$errno] $errstr in line $errline of file $errfile\n"; - break; - } - - $message.= getBacktrace($errline); - - print_r($message); -} - -set_error_handler('errorHandler'); -if (function_exists('xdebug_disable')) { - xdebug_disable(); -} -?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/docs/CONTRIBUTORS /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/docs/CONTRIBUTORS --- php-mdb2-2.4.1/MDB2-2.5.0b2/docs/CONTRIBUTORS 1970-01-01 01:00:00.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/docs/CONTRIBUTORS 2009-01-14 16:28:08.000000000 +0000 @@ -0,0 +1,7 @@ +PEAR DB Stig Baekken, Tomas V. Cox +Metabase Manuel Lemos +PEAR Error integration/XML Schema Parser Christian Dickmann +Code Formatting Brent Cook +MsSQL/Frontbase Driver Frank Kormann +PgSQL Driver Paul Cooper +Interbase/Firebird Lorenzo Alberton diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/docs/datatypes.html /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/docs/datatypes.html --- php-mdb2-2.4.1/MDB2-2.5.0b2/docs/datatypes.html 1970-01-01 01:00:00.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/docs/datatypes.html 2009-01-14 16:28:08.000000000 +0000 @@ -0,0 +1,64 @@ + + +MDB2 data types + + +

    MDB2 data types

    +
    + + +
    +

    Introduction

    +

    All DBMS provide multiple choice of data types for the information that can be stored in their database table fields. However, the set of data types made available varies from DBMS to DBMS.

    +

    To simplify the interface with the DBMS supported by MDB2 it was defined a base set of data types that applications may access independently of the underlying DBMS.

    +

    The MDB2 applications programming interface takes care of mapping data types when managing database options. It is also able to convert that is sent to and received from the underlying DBMS using the respective driver.

    +

  • Text data type
  • +

    The text data type is available with two options for the length: one that is explicitly length limited and another of undefined length that should be as large as the database allows.

    +

    The length limited option is the most recommended for efficiency reasons. The undefined length option allows very large fields but may prevent the use of indexes and may not allow sorting on fields of its type.

    +

    The fields of this type should be able to handle 8 bit characters. Drivers take care of DBMS specific escaping of characters of special meaning with the values of the strings to be converted to this type.

    +

  • Boolean data type
  • +

    The boolean data type represents only two values that can be either 1 or 0. Do not assume that these data types are stored as integers because some DBMS drivers may implement this type with single character text fields for a matter of efficient. Ternary logic is possible by using null as the third possible value that may be assigned to fields of this type.

    +

  • Integer data type
  • +

    The integer data type may store integer values as large as each DBMS may handle. Fields of this type may be created optionally as unsigned integers but not all DBMS support it. Therefore, such option may be ignored. Truly portable applications should not rely on the availability of this option.

    +

  • Decimal data type
  • +

    The decimal data type may store decimal numbers accurately with a fixed number of decimal places. This data type is suitable for representing accurate values like currency amounts.

    +

    Some DBMS drivers may emulate the decimal data type using integers. Such drivers need to know in advance how many decimal places that should be used to perform eventual scale conversion when storing and retrieving values from a database. Despite this, applications may use arithmetic expressions and functions with the values stored on decimal type fields as long as any constant values that are used in the expressions are also converted with the respective MDB2 conversion functions.

    +

    The number of places that are used to the left and the right of the decimal point is pre-determined and fixed for all decimal values stored in the same database. By default, MDB2 uses 2 places to the right of the decimal point, but this may be changed when setting the database connection. The number of places available to the right of the decimal point depend on the DBMS.

    +

    It is not recommended to change the number places used to represent decimal values in database after it is installed. MDB2 does not keep track of changes in the number of decimal places.

    +

  • Float data type
  • +

    The float data type may store floating point decimal numbers. This data type is suitable for representing numbers within a large scale range that do not require high accuracy. The scale and the precision limits of the values that may be stored in a database depends on the DBMS that it is used.

    +

  • Date data type
  • +

    The date data type may represent dates with year, month and day. DBMS independent representation of dates is accomplished by using text strings formatted according to the IS0 8601 standard.

    +

    The format defined by the ISO 8601 standard for dates is YYYY-MM-DD where YYYY is the number of the year (Gregorian calendar), MM is the number of the month from 1 to 12 and DD is the number of the day from 1 to 31. Months or days numbered below 10 should be padded on the left with 0.

    +

    Some DBMS have native support for date formats, but for others the DBMS driver may have to represent them as integers or text values. In any case, it is always possible to make comparisons between date values as well sort query results by fields of this type.

    +

  • Time data type
  • +

    The time data type may represent the time of a given moment of the day. DBMS independent representation of the time of the day is also accomplished by using text strings formatted according to the IS0 8601 standard.

    +

    The format defined by the ISO 8601 standard for the time of the day is HH:MI:SS where HH is the number of hour the day from 0 to 23 and MI and SS are respectively the number of the minute and of the second from 0 to 59. Hours, minutes and seconds numbered below 10 should be padded on the left with 0.

    +

    Some DBMS have native support for time of the day formats, but for others the DBMS driver may have to represent them as integers or text values. In any case, it is always possible to make comparisons between time values as well sort query results by fields of this type.

    +

  • Time stamp data type
  • +

    The time stamp data type is a mere combination of the date and the time of the day data types. The representation of values of the time stamp type is accomplished by joining the date and time string values in a single string joined by a space. Therefore, the format template is YYYY-MM-DD HH:MI:SS. The represented values obey the same rules and ranges described for the date and time data types.

    +

  • Large object (file) data types
  • +

    The large object data types are meant to store data of undefined length that may be to large to store in text fields, like data that is usually stored in files.

    +

    MDB2 supports two types of large object fields: Character Large OBjects (CLOBs) and Binary Large OBjects (BLOBs). CLOB fields are meant to store only data made of printable ASCII characters. BLOB fields are meant to store all types of data.

    +

    Large object fields are usually not meant to be used as parameters of query search clause (WHERE) unless the underlying DBMS supports a feature usually known as "full text search".

    + +
    +
    Manuel Lemos (mlemos@acm.org)
    + + diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/docs/examples/example.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/docs/examples/example.php --- php-mdb2-2.4.1/MDB2-2.5.0b2/docs/examples/example.php 1970-01-01 01:00:00.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/docs/examples/example.php 2009-01-14 16:28:08.000000000 +0000 @@ -0,0 +1,208 @@ +PEAR-Error
    '; + echo $error_obj->getMessage().': '.$error_obj->getUserinfo(); + print ''; + } + PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'handle_pear_error'); + + // just for kicks you can mess up this part to see some pear error handling + $user = 'root'; + $pass = ''; + $host = 'localhost'; + $mdb2_name = 'metapear_test_db'; + $mdb2_type = !empty($_GET['db_type']) ? $_GET['db_type'] : 'mysql'; + echo($mdb2_type.'
    '); + + // Data Source Name: This is the universal connection string + $dsn['username'] = $user; + $dsn['password'] = $pass; + $dsn['hostspec'] = $host; + $dsn['phptype'] = $mdb2_type; + // MDB2::factory will return a PEAR::MDB2 instance on success + // or a Pear MDB2 error object on error + // You can alternatively build a dsn here + // $dsn = "$mdb2_type://$user:$pass@$host/$mdb2_name"; + Var_Dump($dsn); + $mdb2 =& MDB2::factory($dsn); + // With PEAR::isError you can differentiate between an error or + // a valid connection. + if (PEAR::isError($mdb2)) { + die (__LINE__.$mdb2->getMessage()); + } + + // this loads the MDB2_Schema manager + // this is a separate package you must install + require_once 'MDB2/Schema.php'; + // you can either pass a dsn string, a dsn array or an exisiting mdb2 connection + $schema =& MDB2_Schema::factory($mdb2); + $input_file = 'metapear_test_db.schema'; + // lets create the database using 'metapear_test_db.schema' + // if you have allready run this script you should have 'metapear_test_db.schema.before' + // in that case MDB2 will just compare the two schemas and make any + // necessary modifications to the existing database + Var_Dump($schema->updateDatabase($input_file, $input_file.'.before')); + echo('updating database from xml schema file
    '); + + echo('switching to database: '.$mdb2_name.'
    '); + $mdb2->setDatabase($mdb2_name); + // happy query + $query ='SELECT * FROM test'; + echo('query for the following examples:'.$query.'
    '); + // run the query and get a result handler + $result = $mdb2->query($query); + // lets just get row:0 and free the result + $array = $result->fetchRow(); + $result->free(); + echo('
    row:
    '); + echo(Var_Dump($array).'
    '); + $result = $mdb2->query($query); + // lets just get row:0 and free the result + $array = $result->fetchRow(MDB2_FETCHMODE_OBJECT); + $result->free(); + echo('
    row (object:
    '); + echo(Var_Dump($array).'
    '); + // run the query and get a result handler + $result = $mdb2->query($query); + // lets just get row:0 and free the result + $array = $result->fetchRow(); + $result->free(); + echo('
    row from object:
    '); + echo(Var_Dump($array).'
    '); + // run the query and get a result handler + $result = $mdb2->query($query); + // lets just get column:0 and free the result + $array = $result->fetchCol(2); + $result->free(); + echo('
    get column #2 (counting from 0):
    '); + echo(Var_Dump($array).'
    '); + // run the query and get a result handler + $result = $mdb2->query($query); + Var_Dump($mdb2->loadModule('Reverse', null, true)); + echo('tableInfo:
    '); + echo(Var_Dump($mdb2->reverse->tableInfo($result)).'
    '); + $types = array('integer', 'text', 'timestamp'); + $result->setResultTypes($types); + $array = $result->fetchAll(MDB2_FETCHMODE_FLIPPED); + $result->free(); + echo('
    all with result set flipped:
    '); + echo(Var_Dump($array).'
    '); + // save some time with this function + // lets just get all and free the result + $array = $mdb2->queryAll($query); + echo('
    all with just one call:
    '); + echo(Var_Dump($array).'
    '); + // run the query with the offset 1 and count 1 and get a result handler + Var_Dump($mdb2->loadModule('Extended', null, false)); + $result = $mdb2->extended->limitQuery($query, null, 1, 1); + // lets just get everything but with an associative array and free the result + $array = $result->fetchAll(MDB2_FETCHMODE_ASSOC); + echo('
    associative array with offset 1 and count 1:
    '); + echo(Var_Dump($array).'
    '); + // lets create a sequence + echo(Var_Dump($mdb2->loadModule('Manager', null, true))); + echo('
    create a new seq with start 3 name real_funky_id
    '); + $err = $mdb2->manager->createSequence('real_funky_id', 3); + if (PEAR::isError($err)) { + echo('
    could not create sequence again
    '); + } + echo('
    get the next id:
    '); + $value = $mdb2->nextId('real_funky_id'); + echo($value.'
    '); + // lets try an prepare execute combo + $alldata = array( + array(1, 'one', 'un'), + array(2, 'two', 'deux'), + array(3, 'three', 'trois'), + array(4, 'four', 'quatre') + ); + $stmt = $mdb2->prepare('INSERT INTO numbers VALUES(?,?,?)', array('integer', 'text', 'text'), MDB2_PREPARE_MANIP); + foreach ($alldata as $row) { + echo('running execute
    '); + $stmt->bindValueArray($row); + $stmt->execute(); + } + $array = array(4); + echo('
    see getOne in action:
    '); + echo(Var_Dump($mdb2->extended->getOne('SELECT trans_en FROM numbers WHERE number = ?',null,$array,array('integer'))).'
    '); + $mdb2->setFetchmode(MDB2_FETCHMODE_ASSOC); + echo('
    default fetchmode ist now MDB2_FETCHMODE_ASSOC
    '); + echo('
    see getRow in action:
    '); + echo(Var_Dump($mdb2->extended->getRow('SELECT * FROM numbers WHERE number = ?',array('integer','text','text'),$array, array('integer')))); + echo('default fetchmode ist now MDB2_FETCHMODE_ORDERED
    '); + $mdb2->setFetchmode(MDB2_FETCHMODE_ORDERED); + echo('
    see getCol in action:
    '); + echo(Var_Dump($mdb2->extended->getCol('SELECT * FROM numbers WHERE number != ?',null,$array,array('integer'), 1)).'
    '); + echo('
    see getAll in action:
    '); + echo(Var_Dump($mdb2->extended->getAll('SELECT * FROM test WHERE test_id != ?',array('integer','text','text'), $array, array('integer'))).'
    '); + echo('
    see getAssoc in action:
    '); + echo(Var_Dump($mdb2->extended->getAssoc('SELECT * FROM test WHERE test_id != ?',array('integer','text','text'), $array, array('integer'), MDB2_FETCHMODE_ASSOC)).'
    '); + echo('tableInfo on a string:
    '); + echo(Var_Dump($mdb2->reverse->tableInfo('numbers')).'
    '); + echo('
    just a simple update query:
    '); + echo('
    affected rows:
    '); + echo(Var_Dump($mdb2->exec('UPDATE numbers set trans_en ='.$mdb2->quote(0, 'integer'))).'
    '); + // subselect test + $sub_select = $mdb2->subSelect('SELECT test_name from test WHERE test_name = '.$mdb2->quote('gummihuhn', 'text'), 'text'); + echo(Var_Dump($sub_select).'
    '); + $query_with_subselect = 'SELECT * FROM test WHERE test_name IN ('.$sub_select.')'; + // run the query and get a result handler + echo($query_with_subselect.'
    '); + $result = $mdb2->query($query_with_subselect); + $array = $result->fetchAll(); + $result->free(); + echo('
    all with subselect:
    '); + echo('
    drop index (will fail if the index was never created):
    '); + echo(Var_Dump($mdb2->manager->dropIndex('test', 'test_id_index')).'
    '); + $index_def = array( + 'fields' => array( + 'test_id' => array( + 'sorting' => 'ascending' + ) + ) + ); + echo('
    create index:
    '); + echo(Var_Dump($mdb2->manager->createIndex('test', 'test_id_index', $index_def)).'
    '); + + if ($mdb2_type == 'mysql') { + $schema->db->setOption('debug', true); + $schema->db->setOption('log_line_break', '
    '); + // ok now lets create a new xml schema file from the existing DB + $database_definition = $schema->getDefinitionFromDatabase(); + // we will not use the 'metapear_test_db.schema' for this + // this feature is especially interesting for people that have an existing Db and want to move to MDB2's xml schema management + // you can also try MDB2_MANAGER_DUMP_ALL and MDB2_MANAGER_DUMP_CONTENT + echo(Var_Dump($schema->dumpDatabase( + $database_definition, + array( + 'output_mode' => 'file', + 'output' => $mdb2_name.'2.schema' + ), + MDB2_SCHEMA_DUMP_STRUCTURE + )).'
    '); + if ($schema->db->getOption('debug') === true) { + echo($schema->db->getDebugOutput().'
    '); + } + // this is the database definition as an array + echo(Var_Dump($database_definition).'
    '); + } + + echo('
    just a simple delete query:
    '); + echo(Var_Dump($mdb2->exec('DELETE FROM numbers')).'
    '); + // You can disconnect from the database with: + $mdb2->disconnect() +?> diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/docs/examples/example_php5.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/docs/examples/example_php5.php --- php-mdb2-2.4.1/MDB2-2.5.0b2/docs/examples/example_php5.php 1970-01-01 01:00:00.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/docs/examples/example_php5.php 2009-01-14 16:28:08.000000000 +0000 @@ -0,0 +1,100 @@ +
    + 'pgsql',
    +    'username' => 'postgres',
    +#    'phptype'  => 'mysql',
    +#    'username' => 'root',
    +    'password' => 'test',
    +    'hostspec' => 'localhost',
    +    'database' => 'driver_test',
    +);
    +#$dsn = 'sqlite:///:memory:';
    +
    +// create MDB2 instance
    +$mdb2 = MDB2::factory($dsn);
    +if (PEAR::isError($mdb2)) {
    +    die($mdb2->getMessage());
    +}
    +
    +// set the default fetchmode
    +$mdb2->setFetchMode(MDB2_FETCHMODE_ASSOC);
    +
    +$fields = array(
    +    'id' => array(
    +        'type'     => 'integer',
    +        'unsigned' => true,
    +        'autoincrement'  => true,
    +    ),
    +    'somename' => array(
    +        'type'     => 'text',
    +        'length'   => 12,
    +    ),
    +    'somedate'  => array(
    +        'type'     => 'date',
    +    ),
    +);
    +$table = 'sometable';
    +
    +// create a table
    +// since we are on php5 we can use the magic __call() method to:
    +// - load the manager module: $mdb2->loadModule('Manager', null, true);
    +// - redirect the method call to the manager module: $mdb2->manager->createTable('sometable', $fields);
    +$mdb2->mgCreateTable($table, $fields);
    +
    +$query = "INSERT INTO $table (somename, somedate) VALUES (:name, :date)";
    +// parameters:
    +// 1) the query (notice we are using named parameters, but we could also use ? instead
    +// 2) types of the placeholders (either keyed numerically in order or by name)
    +// 3) MDB2_PREPARE_MANIP denotes a DML statement
    +$stmt = $mdb2->prepare($query, array('text', 'date'), MDB2_PREPARE_MANIP);
    +if (PEAR::isError($stmt)) {
    +    die($stmt->getMessage());
    +}
    +
    +// load Date helper class
    +MDB2::loadFile('Date');
    +
    +$stmt->execute(array('name' => 'hello', 'date' => MDB2_Date::mdbToday()));
    +// get the last inserted id
    +echo 'last insert id: ';
    +var_dump($mdb2->lastInsertId($table, 'id'));
    +$stmt->execute(array('name' => 'world', 'date' => '2005-11-11'));
    +// get the last inserted id
    +echo 'last insert id: ';
    +var_dump($mdb2->lastInsertId($table, 'id'));
    +
    +// load Iterator implementations
    +MDB2::loadFile('Iterator');
    +
    +$query = 'SELECT * FROM '.$table;
    +// parameters:
    +// 1) the query
    +// 2) true means MDB2 tries to determine the result set type automatically
    +// 3) true is the default and means that internally a MDB2_Result instance should be created
    +// 4) 'MDB2_BufferedIterator' means the MDB2_Result should be wrapped inside an SeekableIterator
    +$result = $mdb2->query($query, true, true, 'MDB2_BufferedIterator');
    +
    +// iterate over the result set
    +foreach ($result as $row) {
    +    echo 'output row:
    '; + var_dump($row); +} + +// call drop table, since dropTable is not implemented in our instance +// but inside the loaded Manager module __call() will find it there and +// will redirect the call accordingly +// we could also have done: +// $mdb2->manager->dropTable($table); or +// $mdb2->mgDropTable($table); +$mdb2->dropTable($table); + +?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/docs/examples/metapear_test_db.schema /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/docs/examples/metapear_test_db.schema --- php-mdb2-2.4.1/MDB2-2.5.0b2/docs/examples/metapear_test_db.schema 1970-01-01 01:00:00.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/docs/examples/metapear_test_db.schema 2009-01-14 16:28:08.000000000 +0000 @@ -0,0 +1,112 @@ + + + + metapear_test_db + 1 + + + + numbers + + + + + number + integer + 1 + 0 + + + + trans_en + text + 100 + + + + + trans_fr + text + 100 + + + + + +
    + + + + test + + + + + test_id + integer + 1 + 0 + + + + test_name + text + 30 + 1 + no name + + + + test_date + timestamp + 1 + 0000-00-00 00:00:00 + + + + + + + + + + test_id + 1 + + + + test_name + test0r + + + + test_date + 2002-02-12 16:33:53 + + + + + + + + test_id + 2 + + + + test_name + gummihuhn + + + + test_date + 2001-02-12 16:34:03 + + + + + + +
    + +
    diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/docs/MAINTAINERS /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/docs/MAINTAINERS --- php-mdb2-2.4.1/MDB2-2.5.0b2/docs/MAINTAINERS 1970-01-01 01:00:00.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/docs/MAINTAINERS 2009-01-14 16:28:08.000000000 +0000 @@ -0,0 +1,11 @@ +Maintainers for MDB2 database backends/drivers: + +ibase : Lorenzo Alberton +mssql : David Coallier +mysqli : Lukas Smith +oci8 : Lukas Smith +pgsql : Lukas Smith +fbsql : unmaintained +sqlite : Lukas Smith +querysim : Lukas Smith diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/docs/README /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/docs/README --- php-mdb2-2.4.1/MDB2-2.5.0b2/docs/README 1970-01-01 01:00:00.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/docs/README 2009-01-14 16:28:08.000000000 +0000 @@ -0,0 +1,183 @@ +** Introduction: + +PEAR MDB2 is a project to merge PEAR DB and Metabase into one DB +abstraction layer. + +You can get info on these at: + PEAR DB: http://pear.php.net + Metabase: http://phpclasses.upperdesign.com/browse.html/package/20/ + +At these URLs you will also find the licensing information on these two +projects along with the credits. + +Actually MDB2 is the second major version of MDB. +The main differences between the new MDB2 and the old MDB version is +that the API has been drastically refactored to clean up the API +and improve performance. + +If you have any questions or suggestions you can contact me (Lukas Smith) +at this email address: + smith@backendmedia.com +Co-Author is Christopher Linn: + clinn@backendmedia.com + +Or even better post a message to pear-dev@lists.php.net mailinglist for +development related questions of the MDB2 package itself. For questions +using MDB2 pelase direct your questions at pear-general@lists.php.net. + +** Features + +MDB2 provides a common API for all support RDBMS. The main difference to most +other DB abstraction packages is that MDB2 goes much further to ensure +portability. Among other things MDB2 features: +* An OO-style query API +* A DSN (data source name) or array format for specifying database servers +* Datatype abstraction and on demand datatype conversion +* Portable error codes +* Sequential and non sequential row fetching as well as bulk fetching +* Ordered array and associative array for the fetched rows +* Buffered and Unbuffered fetching +* Prepare/execute (bind) emulation +* Sequence emulation +* Replace emulation +* Limited Subselect emulation +* Row limit support +* Transactions support +* Large Object support +* Index/Unique support +* Extension Framework to load advanced functionality on demand +* Table information interface +* RDBMS management methods (creating, dropping, altering) +* RDBMS independent xml based schema definition management +* Altering of a DB from a changed xml schema +* Reverse engineering of xml schemas from an existing DB (currently MySQL and PgSQl) +* Full integration into the PEAR Framework +* PHPDoc API documentation + +** Getting started: + +I would first recommend taking a look at example.php. +This should give you a general feel of how to interact with MDB2. + +After that you may want to take a look at the rather large API +at www.backendmedia.com/MDB2/docs. There you will also find a document +describing the xml schema format and a little tutorial (it was +just recently ported from Metabase, so it may contain errors). + +** Current State: + +The current release can be found at the PEAR webpage: + http://pear.php.net/package-info.php?package=MDB2 + +** Package Content: + +As a user the only php script you will need to include is MDB2.php which will +install to your PEAR root directory. All other files and their containing +classes will be included via MDB2::factory(), MDB2::connect(), MDB2::singleton(). + +These will load additional classes. Most classes are loaded on demand. + +Furthermore MDB2 provides an extensive testing framework that works through a +browser and command line interface. There are several other test that test the +two wrappers. These files will install into your test dir found in the +PEAR root dir. + +** Documentation: + +You can find the still incomplete documentation for MDB2 here: +http://pear.php.net/manual/en/package.database.mdb2.php + +PHPDoc generated documentation can be found at: +http://www.backendmedia.com/MDB2/docs/ + +The entire "public" API and most of the "private" methods (except for some of +the lob classes) have been documented with PHPDoc comments. Most of the API +is borrowed from extPDO, so you can look there for detailed documentation. +Since there are a large number of new methods available thanks to the Metabase +heritage of MDB2 you will also have to take a look in the Metabase documentation +(which can be found at the URL mentioned above, but does require that +you register with phpclasses). Most of these Metabase functions have +been renamed and changed considerably. The main things left are the datatypes +and the manager module. + +For example ($db being an MDB2 object): + $converted_value = MetabaseGetTimestampFieldValue($database, $value); +would now be + $converted_value = $db->quote($value, 'timestamp'); + +If you want to help out with documentation please email me. + +** Testing: + +For most of the tests you can set the username/password/hostname in the relevant +config file. The user will need to have the right to create new databases. + +test.php/clitest.php/testchoose.php: Is the native testing suite provided by +MDB2. Please see the README in the tests directory for details. + +example.php: Several test calls to MDB2's native API. It require PEAR::VAR_Dump +package and are configured to use the following settings: +username = metapear +password = funky +hostname = localhost + +** How to write new Drivers: + +Skeleton drivers are provided in the docs directory of the MDB2 package. + +The best course of action would be to take a MDB2 driver and hack it to fit +the new RDBMS. This will surely be faster and it will ensure that the new +driver takes full advantage of the MDB2 framework. I would however recommend +working with the existing Metabase driver for inspiration that RDBMS when +doing those changes. + +In order to check compliance of the driver with MDB2 you can use the testing +suite (see the "testing" section above) + +** History + +MDB was started after Manuel broad be into the discussion about getting the +features of Metabase into PEAR that was going on (again) in December 2001. He +suggested that I could take on this project. After alot of discussion about +how when and if etc I started development in February 2002. + +MDB is based on Metabase but has been reworked severely to better match +the PEAR DB API and PEAR CS. The approach I have taken so far is to take DB.php +from PEAR DB and make it create a Metabase object. I have changed the +Metabase structure slightly. The formatting has been reworked +considerably to better fit the final structure (MDB standalone with a +BC-wrapper for Metabase and PEAR DB), to fit the PEAR CS and to make it +easier for other people to contribute. + +The metabase_interface.php was been renamed to metabase_wrapper.php and +now only serves as a wrapper to keep BC with Metabase. A wrapper will +have to be created for PEAR DB as well. + +Basically the result is a Metabase that is really close to the PEAR DB +structure. I have also added any missing methods from PEAR DB. Work on +moving the error handling to PEAR error handling is under way but still +needs some work. + +In MDB2 the API was heavily refactored to be even more streamlined. Redundant +features have been removed. Some features where moved out of the core into +separate loadable modules. Instead of resources resultsets are now wrapped +into objects similar to PEAR DB. + +** Credits (never to early for those huh? :-) ): + +I would especially like to thank Manuel Lemos (Author of Metabase) for +getting me involved in this and generally being around to ask questions. +I would also like to thank Tomas Cox and Stig S. Bakken from the PEAR +projects for help in undertstanding PEAR, solving problems and trusting +me enough. Paul Cooper for the work on the pgsql driver. Furthermore I +would like to thank Alex Black for being so enthusiastic about this +project and offering binarycloud as a test bed for this project. +Christian Dickmann for being the first to put MDB to some real use, +making MDB use PEAR Error and working on the XML schema manager. + +Finally Peter Bowyer for starting the discussion that made people pick +up this project again after the first versions of what was then called +"metapear" have been ideling without much feedback. I guess I should +also thank BackendMedia (my company :-) ) for providing the necessary means +to develop this on company time (actually for the most part my entire +life is company time ... so it goes) \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/docs/STATUS /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/docs/STATUS --- php-mdb2-2.4.1/MDB2-2.5.0b2/docs/STATUS 1970-01-01 01:00:00.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/docs/STATUS 2009-01-14 16:28:08.000000000 +0000 @@ -0,0 +1,50 @@ +STATUS OF THE PEAR MDB2 PACKAGE +============================= + +$Id: STATUS,v 1.15 2006/05/03 16:07:41 lsmith Exp $ +------------------------------------------------------------------------ + +MDB2 Driver Feature Matrix +------------------------ +Symbols: + x = implemented, but without tests + t = implemented, but one or more tests fail + T = implemented, passing all tests + e = emulated, without tests + l = emulated, but one or more tests fail + E = emulated, passing all tests + n = returns "not capable" + - = no implementation of this feature or status unknown + + fbsql pgsql mysqli sqlite +FEATURE ibase | oci8 | mysql | mssql | querysim + + + +Test Conformance +---------------- +Symbols: + o = Test passed + X = Test failed + L = Some portions of the test failed due to limitations in PHP or DBMS + n = Test returns "not capable" + - = Not tested + + fbsql pgsql mysqli sqlite +TEST ibase | oci8 | mysql | mssql | querysim + + +DBMS Versions Tested +-------------------- +fbsql +ibase +mssql +mysql +mysqli +oci8 +pgsql +sqlite +querysim + +Tests were performed under both of the following PHP versions +unles otherwise noted: diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/docs/TODO /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/docs/TODO --- php-mdb2-2.4.1/MDB2-2.5.0b2/docs/TODO 1970-01-01 01:00:00.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/docs/TODO 2009-01-14 16:28:08.000000000 +0000 @@ -0,0 +1 @@ +see http://oss.backendmedia.com/index.php?area=MDB2&page=ToDo diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/LICENSE /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/LICENSE --- php-mdb2-2.4.1/MDB2-2.5.0b2/LICENSE 1970-01-01 01:00:00.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/LICENSE 2009-01-14 16:28:09.000000000 +0000 @@ -0,0 +1,38 @@ +// +----------------------------------------------------------------------+ +// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, | +// | Stig. S. Bakken, Lukas Smith | +// | All rights reserved. | +// +----------------------------------------------------------------------+ +// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | +// | API as well as database abstraction for PHP applications. | +// | This LICENSE is in the BSD license style. | +// | | +// | Redistribution and use in source and binary forms, with or without | +// | modification, are permitted provided that the following conditions | +// | are met: | +// | | +// | Redistributions of source code must retain the above copyright | +// | notice, this list of conditions and the following disclaimer. | +// | | +// | Redistributions in binary form must reproduce the above copyright | +// | notice, this list of conditions and the following disclaimer in the | +// | documentation and/or other materials provided with the distribution. | +// | | +// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | +// | Lukas Smith nor the names of his contributors may be used to endorse | +// | or promote products derived from this software without specific prior| +// | written permission. | +// | | +// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | +// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | +// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | +// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | +// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | +// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | +// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| +// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | +// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | +// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| +// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | +// | POSSIBILITY OF SUCH DAMAGE. | +// +----------------------------------------------------------------------+ \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/MDB2/Date.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/MDB2/Date.php --- php-mdb2-2.4.1/MDB2-2.5.0b2/MDB2/Date.php 1970-01-01 01:00:00.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/MDB2/Date.php 2009-01-14 16:28:08.000000000 +0000 @@ -0,0 +1,183 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: Date.php,v 1.10 2006/03/01 12:15:32 lsmith Exp $ +// + +/** + * @package MDB2 + * @category Database + * @author Lukas Smith + */ + +/** + * Several methods to convert the MDB2 native timestamp format (ISO based) + * to and from data structures that are convenient to worth with in side of php. + * For more complex date arithmetic please take a look at the Date package in PEAR + * + * @package MDB2 + * @category Database + * @author Lukas Smith + */ +class MDB2_Date +{ + // {{{ mdbNow() + + /** + * return the current datetime + * + * @return string current datetime in the MDB2 format + * @access public + */ + function mdbNow() + { + return date('Y-m-d H:i:s'); + } + // }}} + + // {{{ mdbToday() + + /** + * return the current date + * + * @return string current date in the MDB2 format + * @access public + */ + function mdbToday() + { + return date('Y-m-d'); + } + // }}} + + // {{{ mdbTime() + + /** + * return the current time + * + * @return string current time in the MDB2 format + * @access public + */ + function mdbTime() + { + return date('H:i:s'); + } + // }}} + + // {{{ date2Mdbstamp() + + /** + * convert a date into a MDB2 timestamp + * + * @param int hour of the date + * @param int minute of the date + * @param int second of the date + * @param int month of the date + * @param int day of the date + * @param int year of the date + * + * @return string a valid MDB2 timestamp + * @access public + */ + function date2Mdbstamp($hour = null, $minute = null, $second = null, + $month = null, $day = null, $year = null) + { + return MDB2_Date::unix2Mdbstamp(mktime($hour, $minute, $second, $month, $day, $year, -1)); + } + // }}} + + // {{{ unix2Mdbstamp() + + /** + * convert a unix timestamp into a MDB2 timestamp + * + * @param int a valid unix timestamp + * + * @return string a valid MDB2 timestamp + * @access public + */ + function unix2Mdbstamp($unix_timestamp) + { + return date('Y-m-d H:i:s', $unix_timestamp); + } + // }}} + + // {{{ mdbstamp2Unix() + + /** + * convert a MDB2 timestamp into a unix timestamp + * + * @param int a valid MDB2 timestamp + * @return string unix timestamp with the time stored in the MDB2 format + * + * @access public + */ + function mdbstamp2Unix($mdb_timestamp) + { + $arr = MDB2_Date::mdbstamp2Date($mdb_timestamp); + + return mktime($arr['hour'], $arr['minute'], $arr['second'], $arr['month'], $arr['day'], $arr['year'], -1); + } + // }}} + + // {{{ mdbstamp2Date() + + /** + * convert a MDB2 timestamp into an array containing all + * values necessary to pass to php's date() function + * + * @param int a valid MDB2 timestamp + * + * @return array with the time split + * @access public + */ + function mdbstamp2Date($mdb_timestamp) + { + list($arr['year'], $arr['month'], $arr['day'], $arr['hour'], $arr['minute'], $arr['second']) = + sscanf($mdb_timestamp, "%04u-%02u-%02u %02u:%02u:%02u"); + return $arr; + } + // }}} +} + +?> diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/MDB2/Driver/Datatype/Common.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/MDB2/Driver/Datatype/Common.php --- php-mdb2-2.4.1/MDB2-2.5.0b2/MDB2/Driver/Datatype/Common.php 1970-01-01 01:00:00.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/MDB2/Driver/Datatype/Common.php 2009-01-14 16:28:08.000000000 +0000 @@ -0,0 +1,1824 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: Common.php,v 1.139 2008/12/04 11:50:42 afz Exp $ + +require_once 'MDB2/LOB.php'; + +/** + * @package MDB2 + * @category Database + * @author Lukas Smith + */ + +/** + * MDB2_Driver_Common: Base class that is extended by each MDB2 driver + * + * To load this module in the MDB2 object: + * $mdb->loadModule('Datatype'); + * + * @package MDB2 + * @category Database + * @author Lukas Smith + */ +class MDB2_Driver_Datatype_Common extends MDB2_Module_Common +{ + var $valid_default_values = array( + 'text' => '', + 'boolean' => true, + 'integer' => 0, + 'decimal' => 0.0, + 'float' => 0.0, + 'timestamp' => '1970-01-01 00:00:00', + 'time' => '00:00:00', + 'date' => '1970-01-01', + 'clob' => '', + 'blob' => '', + ); + + /** + * contains all LOB objects created with this MDB2 instance + * @var array + * @access protected + */ + var $lobs = array(); + + // }}} + // {{{ getValidTypes() + + /** + * Get the list of valid types + * + * This function returns an array of valid types as keys with the values + * being possible default values for all native datatypes and mapped types + * for custom datatypes. + * + * @return mixed array on success, a MDB2 error on failure + * @access public + */ + function getValidTypes() + { + $types = $this->valid_default_values; + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + if (!empty($db->options['datatype_map'])) { + foreach ($db->options['datatype_map'] as $type => $mapped_type) { + if (array_key_exists($mapped_type, $types)) { + $types[$type] = $types[$mapped_type]; + } elseif (!empty($db->options['datatype_map_callback'][$type])) { + $parameter = array('type' => $type, 'mapped_type' => $mapped_type); + $default = call_user_func_array($db->options['datatype_map_callback'][$type], array(&$db, __FUNCTION__, $parameter)); + $types[$type] = $default; + } + } + } + return $types; + } + + // }}} + // {{{ checkResultTypes() + + /** + * Define the list of types to be associated with the columns of a given + * result set. + * + * This function may be called before invoking fetchRow(), fetchOne() + * fetchCole() and fetchAll() so that the necessary data type + * conversions are performed on the data to be retrieved by them. If this + * function is not called, the type of all result set columns is assumed + * to be text, thus leading to not perform any conversions. + * + * @param array $types array variable that lists the + * data types to be expected in the result set columns. If this array + * contains less types than the number of columns that are returned + * in the result set, the remaining columns are assumed to be of the + * type text. Currently, the types clob and blob are not fully + * supported. + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function checkResultTypes($types) + { + $types = is_array($types) ? $types : array($types); + foreach ($types as $key => $type) { + if (!isset($this->valid_default_values[$type])) { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + if (empty($db->options['datatype_map'][$type])) { + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + $type.' for '.$key.' is not a supported column type', __FUNCTION__); + } + } + } + return $types; + } + + // }}} + // {{{ _baseConvertResult() + + /** + * General type conversion method + * + * @param mixed $value reference to a value to be converted + * @param string $type specifies which type to convert to + * @param boolean $rtrim [optional] when TRUE [default], apply rtrim() to text + * @return object an MDB2 error on failure + * @access protected + */ + function _baseConvertResult($value, $type, $rtrim = true) + { + switch ($type) { + case 'text': + if ($rtrim) { + $value = rtrim($value); + } + return $value; + case 'integer': + return intval($value); + case 'boolean': + return !empty($value); + case 'decimal': + return $value; + case 'float': + return doubleval($value); + case 'date': + return $value; + case 'time': + return $value; + case 'timestamp': + return $value; + case 'clob': + case 'blob': + $this->lobs[] = array( + 'buffer' => null, + 'position' => 0, + 'lob_index' => null, + 'endOfLOB' => false, + 'resource' => $value, + 'value' => null, + 'loaded' => false, + ); + end($this->lobs); + $lob_index = key($this->lobs); + $this->lobs[$lob_index]['lob_index'] = $lob_index; + return fopen('MDB2LOB://'.$lob_index.'@'.$this->db_index, 'r+'); + } + + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_INVALID, null, null, + 'attempt to convert result value to an unknown type :' . $type, __FUNCTION__); + } + + // }}} + // {{{ convertResult() + + /** + * Convert a value to a RDBMS indipendent MDB2 type + * + * @param mixed $value value to be converted + * @param string $type specifies which type to convert to + * @param boolean $rtrim [optional] when TRUE [default], apply rtrim() to text + * @return mixed converted value + * @access public + */ + function convertResult($value, $type, $rtrim = true) + { + if (is_null($value)) { + return null; + } + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + if (!empty($db->options['datatype_map'][$type])) { + $type = $db->options['datatype_map'][$type]; + if (!empty($db->options['datatype_map_callback'][$type])) { + $parameter = array('type' => $type, 'value' => $value, 'rtrim' => $rtrim); + return call_user_func_array($db->options['datatype_map_callback'][$type], array(&$db, __FUNCTION__, $parameter)); + } + } + return $this->_baseConvertResult($value, $type, $rtrim); + } + + // }}} + // {{{ convertResultRow() + + /** + * Convert a result row + * + * @param array $types + * @param array $row specifies the types to convert to + * @param boolean $rtrim [optional] when TRUE [default], apply rtrim() to text + * @return mixed MDB2_OK on success, an MDB2 error on failure + * @access public + */ + function convertResultRow($types, $row, $rtrim = true) + { + $types = $this->_sortResultFieldTypes(array_keys($row), $types); + foreach ($row as $key => $value) { + if (empty($types[$key])) { + continue; + } + $value = $this->convertResult($row[$key], $types[$key], $rtrim); + if (PEAR::isError($value)) { + return $value; + } + $row[$key] = $value; + } + return $row; + } + + // }}} + // {{{ _sortResultFieldTypes() + + /** + * convert a result row + * + * @param array $types + * @param array $row specifies the types to convert to + * @param bool $rtrim if to rtrim text values or not + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function _sortResultFieldTypes($columns, $types) + { + $n_cols = count($columns); + $n_types = count($types); + if ($n_cols > $n_types) { + for ($i= $n_cols - $n_types; $i >= 0; $i--) { + $types[] = null; + } + } + $sorted_types = array(); + foreach ($columns as $col) { + $sorted_types[$col] = null; + } + foreach ($types as $name => $type) { + if (array_key_exists($name, $sorted_types)) { + $sorted_types[$name] = $type; + unset($types[$name]); + } + } + // if there are left types in the array, fill the null values of the + // sorted array with them, in order. + if (count($types)) { + reset($types); + foreach (array_keys($sorted_types) as $k) { + if (is_null($sorted_types[$k])) { + $sorted_types[$k] = current($types); + next($types); + } + } + } + return $sorted_types; + } + + // }}} + // {{{ getDeclaration() + + /** + * Obtain DBMS specific SQL code portion needed to declare + * of the given type + * + * @param string $type type to which the value should be converted to + * @param string $name name the field to be declared. + * @param string $field definition of the field + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. + * @access public + */ + function getDeclaration($type, $name, $field) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + if (!empty($db->options['datatype_map'][$type])) { + $type = $db->options['datatype_map'][$type]; + if (!empty($db->options['datatype_map_callback'][$type])) { + $parameter = array('type' => $type, 'name' => $name, 'field' => $field); + return call_user_func_array($db->options['datatype_map_callback'][$type], array(&$db, __FUNCTION__, $parameter)); + } + $field['type'] = $type; + } + + if (!method_exists($this, "_get{$type}Declaration")) { + return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, + 'type not defined: '.$type, __FUNCTION__); + } + return $this->{"_get{$type}Declaration"}($name, $field); + } + + // }}} + // {{{ getTypeDeclaration() + + /** + * Obtain DBMS specific SQL code portion needed to declare an text type + * field to be used in statements like CREATE TABLE. + * + * @param array $field associative array with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * length + * Integer value that determines the maximum length of the text + * field. If this argument is missing the field should be + * declared to have the longest length allowed by the DBMS. + * + * default + * Text value to be used as default for this field. + * + * notnull + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. + * @access public + */ + function getTypeDeclaration($field) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + switch ($field['type']) { + case 'text': + $length = !empty($field['length']) ? $field['length'] : $db->options['default_text_field_length']; + $fixed = !empty($field['fixed']) ? $field['fixed'] : false; + return $fixed ? ($length ? 'CHAR('.$length.')' : 'CHAR('.$db->options['default_text_field_length'].')') + : ($length ? 'VARCHAR('.$length.')' : 'TEXT'); + case 'clob': + return 'TEXT'; + case 'blob': + return 'TEXT'; + case 'integer': + return 'INT'; + case 'boolean': + return 'INT'; + case 'date': + return 'CHAR ('.strlen('YYYY-MM-DD').')'; + case 'time': + return 'CHAR ('.strlen('HH:MM:SS').')'; + case 'timestamp': + return 'CHAR ('.strlen('YYYY-MM-DD HH:MM:SS').')'; + case 'float': + return 'TEXT'; + case 'decimal': + return 'TEXT'; + } + return ''; + } + + // }}} + // {{{ _getDeclaration() + + /** + * Obtain DBMS specific SQL code portion needed to declare a generic type + * field to be used in statements like CREATE TABLE. + * + * @param string $name name the field to be declared. + * @param array $field associative array with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * length + * Integer value that determines the maximum length of the text + * field. If this argument is missing the field should be + * declared to have the longest length allowed by the DBMS. + * + * default + * Text value to be used as default for this field. + * + * notnull + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * charset + * Text value with the default CHARACTER SET for this field. + * collation + * Text value with the default COLLATION for this field. + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field, or a MDB2_Error on failure + * @access protected + */ + function _getDeclaration($name, $field) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $name = $db->quoteIdentifier($name, true); + $declaration_options = $db->datatype->_getDeclarationOptions($field); + if (PEAR::isError($declaration_options)) { + return $declaration_options; + } + return $name.' '.$this->getTypeDeclaration($field).$declaration_options; + } + + // }}} + // {{{ _getDeclarationOptions() + + /** + * Obtain DBMS specific SQL code portion needed to declare a generic type + * field to be used in statement like CREATE TABLE, without the field name + * and type values (ie. just the character set, default value, if the + * field is permitted to be NULL or not, and the collation options). + * + * @param array $field associative array with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * default + * Text value to be used as default for this field. + * notnull + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * charset + * Text value with the default CHARACTER SET for this field. + * collation + * Text value with the default COLLATION for this field. + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field's options. + * @access protected + */ + function _getDeclarationOptions($field) + { + $charset = empty($field['charset']) ? '' : + ' '.$this->_getCharsetFieldDeclaration($field['charset']); + + $notnull = empty($field['notnull']) ? '' : ' NOT NULL'; + $default = ''; + if (array_key_exists('default', $field)) { + if ($field['default'] === '') { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + $valid_default_values = $this->getValidTypes(); + $field['default'] = $valid_default_values[$field['type']]; + if ($field['default'] === ''&& ($db->options['portability'] & MDB2_PORTABILITY_EMPTY_TO_NULL)) { + $field['default'] = ' '; + } + } + if (!is_null($field['default'])) { + $default = ' DEFAULT ' . $this->quote($field['default'], $field['type']); + } + } + + $collation = empty($field['collation']) ? '' : + ' '.$this->_getCollationFieldDeclaration($field['collation']); + + return $charset.$default.$notnull.$collation; + } + + // }}} + // {{{ _getCharsetFieldDeclaration() + + /** + * Obtain DBMS specific SQL code portion needed to set the CHARACTER SET + * of a field declaration to be used in statements like CREATE TABLE. + * + * @param string $charset name of the charset + * @return string DBMS specific SQL code portion needed to set the CHARACTER SET + * of a field declaration. + */ + function _getCharsetFieldDeclaration($charset) + { + return ''; + } + + // }}} + // {{{ _getCollationFieldDeclaration() + + /** + * Obtain DBMS specific SQL code portion needed to set the COLLATION + * of a field declaration to be used in statements like CREATE TABLE. + * + * @param string $collation name of the collation + * @return string DBMS specific SQL code portion needed to set the COLLATION + * of a field declaration. + */ + function _getCollationFieldDeclaration($collation) + { + return ''; + } + + // }}} + // {{{ _getIntegerDeclaration() + + /** + * Obtain DBMS specific SQL code portion needed to declare an integer type + * field to be used in statements like CREATE TABLE. + * + * @param string $name name the field to be declared. + * @param array $field associative array with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * unsigned + * Boolean flag that indicates whether the field should be + * declared as unsigned integer if possible. + * + * default + * Integer value to be used as default for this field. + * + * notnull + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. + * @access protected + */ + function _getIntegerDeclaration($name, $field) + { + if (!empty($field['unsigned'])) { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $db->warnings[] = "unsigned integer field \"$name\" is being declared as signed integer"; + } + return $this->_getDeclaration($name, $field); + } + + // }}} + // {{{ _getTextDeclaration() + + /** + * Obtain DBMS specific SQL code portion needed to declare an text type + * field to be used in statements like CREATE TABLE. + * + * @param string $name name the field to be declared. + * @param array $field associative array with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * length + * Integer value that determines the maximum length of the text + * field. If this argument is missing the field should be + * declared to have the longest length allowed by the DBMS. + * + * default + * Text value to be used as default for this field. + * + * notnull + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. + * @access protected + */ + function _getTextDeclaration($name, $field) + { + return $this->_getDeclaration($name, $field); + } + + // }}} + // {{{ _getCLOBDeclaration() + + /** + * Obtain DBMS specific SQL code portion needed to declare an character + * large object type field to be used in statements like CREATE TABLE. + * + * @param string $name name the field to be declared. + * @param array $field associative array with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * length + * Integer value that determines the maximum length of the large + * object field. If this argument is missing the field should be + * declared to have the longest length allowed by the DBMS. + * + * notnull + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. + * @access public + */ + function _getCLOBDeclaration($name, $field) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $notnull = empty($field['notnull']) ? '' : ' NOT NULL'; + $name = $db->quoteIdentifier($name, true); + return $name.' '.$this->getTypeDeclaration($field).$notnull; + } + + // }}} + // {{{ _getBLOBDeclaration() + + /** + * Obtain DBMS specific SQL code portion needed to declare an binary large + * object type field to be used in statements like CREATE TABLE. + * + * @param string $name name the field to be declared. + * @param array $field associative array with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * length + * Integer value that determines the maximum length of the large + * object field. If this argument is missing the field should be + * declared to have the longest length allowed by the DBMS. + * + * notnull + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. + * @access protected + */ + function _getBLOBDeclaration($name, $field) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $notnull = empty($field['notnull']) ? '' : ' NOT NULL'; + $name = $db->quoteIdentifier($name, true); + return $name.' '.$this->getTypeDeclaration($field).$notnull; + } + + // }}} + // {{{ _getBooleanDeclaration() + + /** + * Obtain DBMS specific SQL code portion needed to declare a boolean type + * field to be used in statements like CREATE TABLE. + * + * @param string $name name the field to be declared. + * @param array $field associative array with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * default + * Boolean value to be used as default for this field. + * + * notnullL + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. + * @access protected + */ + function _getBooleanDeclaration($name, $field) + { + return $this->_getDeclaration($name, $field); + } + + // }}} + // {{{ _getDateDeclaration() + + /** + * Obtain DBMS specific SQL code portion needed to declare a date type + * field to be used in statements like CREATE TABLE. + * + * @param string $name name the field to be declared. + * @param array $field associative array with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * default + * Date value to be used as default for this field. + * + * notnull + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. + * @access protected + */ + function _getDateDeclaration($name, $field) + { + return $this->_getDeclaration($name, $field); + } + + // }}} + // {{{ _getTimestampDeclaration() + + /** + * Obtain DBMS specific SQL code portion needed to declare a timestamp + * field to be used in statements like CREATE TABLE. + * + * @param string $name name the field to be declared. + * @param array $field associative array with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * default + * Timestamp value to be used as default for this field. + * + * notnull + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. + * @access protected + */ + function _getTimestampDeclaration($name, $field) + { + return $this->_getDeclaration($name, $field); + } + + // }}} + // {{{ _getTimeDeclaration() + + /** + * Obtain DBMS specific SQL code portion needed to declare a time + * field to be used in statements like CREATE TABLE. + * + * @param string $name name the field to be declared. + * @param array $field associative array with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * default + * Time value to be used as default for this field. + * + * notnull + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. + * @access protected + */ + function _getTimeDeclaration($name, $field) + { + return $this->_getDeclaration($name, $field); + } + + // }}} + // {{{ _getFloatDeclaration() + + /** + * Obtain DBMS specific SQL code portion needed to declare a float type + * field to be used in statements like CREATE TABLE. + * + * @param string $name name the field to be declared. + * @param array $field associative array with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * default + * Float value to be used as default for this field. + * + * notnull + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. + * @access protected + */ + function _getFloatDeclaration($name, $field) + { + return $this->_getDeclaration($name, $field); + } + + // }}} + // {{{ _getDecimalDeclaration() + + /** + * Obtain DBMS specific SQL code portion needed to declare a decimal type + * field to be used in statements like CREATE TABLE. + * + * @param string $name name the field to be declared. + * @param array $field associative array with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * default + * Decimal value to be used as default for this field. + * + * notnull + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. + * @access protected + */ + function _getDecimalDeclaration($name, $field) + { + return $this->_getDeclaration($name, $field); + } + + // }}} + // {{{ compareDefinition() + + /** + * Obtain an array of changes that may need to applied + * + * @param array $current new definition + * @param array $previous old definition + * @return array containing all changes that will need to be applied + * @access public + */ + function compareDefinition($current, $previous) + { + $type = !empty($current['type']) ? $current['type'] : null; + + if (!method_exists($this, "_compare{$type}Definition")) { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + if (!empty($db->options['datatype_map_callback'][$type])) { + $parameter = array('current' => $current, 'previous' => $previous); + $change = call_user_func_array($db->options['datatype_map_callback'][$type], array(&$db, __FUNCTION__, $parameter)); + return $change; + } + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'type "'.$current['type'].'" is not yet supported', __FUNCTION__); + } + + if (empty($previous['type']) || $previous['type'] != $type) { + return $current; + } + + $change = $this->{"_compare{$type}Definition"}($current, $previous); + + if ($previous['type'] != $type) { + $change['type'] = true; + } + + $previous_notnull = !empty($previous['notnull']) ? $previous['notnull'] : false; + $notnull = !empty($current['notnull']) ? $current['notnull'] : false; + if ($previous_notnull != $notnull) { + $change['notnull'] = true; + } + + $previous_default = array_key_exists('default', $previous) ? $previous['default'] : + ($previous_notnull ? '' : null); + $default = array_key_exists('default', $current) ? $current['default'] : + ($notnull ? '' : null); + if ($previous_default !== $default) { + $change['default'] = true; + } + + return $change; + } + + // }}} + // {{{ _compareIntegerDefinition() + + /** + * Obtain an array of changes that may need to applied to an integer field + * + * @param array $current new definition + * @param array $previous old definition + * @return array containing all changes that will need to be applied + * @access protected + */ + function _compareIntegerDefinition($current, $previous) + { + $change = array(); + $previous_unsigned = !empty($previous['unsigned']) ? $previous['unsigned'] : false; + $unsigned = !empty($current['unsigned']) ? $current['unsigned'] : false; + if ($previous_unsigned != $unsigned) { + $change['unsigned'] = true; + } + $previous_autoincrement = !empty($previous['autoincrement']) ? $previous['autoincrement'] : false; + $autoincrement = !empty($current['autoincrement']) ? $current['autoincrement'] : false; + if ($previous_autoincrement != $autoincrement) { + $change['autoincrement'] = true; + } + return $change; + } + + // }}} + // {{{ _compareTextDefinition() + + /** + * Obtain an array of changes that may need to applied to an text field + * + * @param array $current new definition + * @param array $previous old definition + * @return array containing all changes that will need to be applied + * @access protected + */ + function _compareTextDefinition($current, $previous) + { + $change = array(); + $previous_length = !empty($previous['length']) ? $previous['length'] : 0; + $length = !empty($current['length']) ? $current['length'] : 0; + if ($previous_length != $length) { + $change['length'] = true; + } + $previous_fixed = !empty($previous['fixed']) ? $previous['fixed'] : 0; + $fixed = !empty($current['fixed']) ? $current['fixed'] : 0; + if ($previous_fixed != $fixed) { + $change['fixed'] = true; + } + return $change; + } + + // }}} + // {{{ _compareCLOBDefinition() + + /** + * Obtain an array of changes that may need to applied to an CLOB field + * + * @param array $current new definition + * @param array $previous old definition + * @return array containing all changes that will need to be applied + * @access protected + */ + function _compareCLOBDefinition($current, $previous) + { + return $this->_compareTextDefinition($current, $previous); + } + + // }}} + // {{{ _compareBLOBDefinition() + + /** + * Obtain an array of changes that may need to applied to an BLOB field + * + * @param array $current new definition + * @param array $previous old definition + * @return array containing all changes that will need to be applied + * @access protected + */ + function _compareBLOBDefinition($current, $previous) + { + return $this->_compareTextDefinition($current, $previous); + } + + // }}} + // {{{ _compareDateDefinition() + + /** + * Obtain an array of changes that may need to applied to an date field + * + * @param array $current new definition + * @param array $previous old definition + * @return array containing all changes that will need to be applied + * @access protected + */ + function _compareDateDefinition($current, $previous) + { + return array(); + } + + // }}} + // {{{ _compareTimeDefinition() + + /** + * Obtain an array of changes that may need to applied to an time field + * + * @param array $current new definition + * @param array $previous old definition + * @return array containing all changes that will need to be applied + * @access protected + */ + function _compareTimeDefinition($current, $previous) + { + return array(); + } + + // }}} + // {{{ _compareTimestampDefinition() + + /** + * Obtain an array of changes that may need to applied to an timestamp field + * + * @param array $current new definition + * @param array $previous old definition + * @return array containing all changes that will need to be applied + * @access protected + */ + function _compareTimestampDefinition($current, $previous) + { + return array(); + } + + // }}} + // {{{ _compareBooleanDefinition() + + /** + * Obtain an array of changes that may need to applied to an boolean field + * + * @param array $current new definition + * @param array $previous old definition + * @return array containing all changes that will need to be applied + * @access protected + */ + function _compareBooleanDefinition($current, $previous) + { + return array(); + } + + // }}} + // {{{ _compareFloatDefinition() + + /** + * Obtain an array of changes that may need to applied to an float field + * + * @param array $current new definition + * @param array $previous old definition + * @return array containing all changes that will need to be applied + * @access protected + */ + function _compareFloatDefinition($current, $previous) + { + return array(); + } + + // }}} + // {{{ _compareDecimalDefinition() + + /** + * Obtain an array of changes that may need to applied to an decimal field + * + * @param array $current new definition + * @param array $previous old definition + * @return array containing all changes that will need to be applied + * @access protected + */ + function _compareDecimalDefinition($current, $previous) + { + return array(); + } + + // }}} + // {{{ quote() + + /** + * Convert a text value into a DBMS specific format that is suitable to + * compose query statements. + * + * @param string $value text string value that is intended to be converted. + * @param string $type type to which the value should be converted to + * @param bool $quote determines if the value should be quoted and escaped + * @param bool $escape_wildcards if to escape escape wildcards + * @return string text string that represents the given argument value in + * a DBMS specific format. + * @access public + */ + function quote($value, $type = null, $quote = true, $escape_wildcards = false) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + if (is_null($value) + || ($value === '' && $db->options['portability'] & MDB2_PORTABILITY_EMPTY_TO_NULL) + ) { + if (!$quote) { + return null; + } + return 'NULL'; + } + + if (is_null($type)) { + switch (gettype($value)) { + case 'integer': + $type = 'integer'; + break; + case 'double': + // todo: default to decimal as float is quite unusual + // $type = 'float'; + $type = 'decimal'; + break; + case 'boolean': + $type = 'boolean'; + break; + case 'array': + $value = serialize($value); + case 'object': + $type = 'text'; + break; + default: + if (preg_match('/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/', $value)) { + $type = 'timestamp'; + } elseif (preg_match('/^\d{2}:\d{2}$/', $value)) { + $type = 'time'; + } elseif (preg_match('/^\d{4}-\d{2}-\d{2}$/', $value)) { + $type = 'date'; + } else { + $type = 'text'; + } + break; + } + } elseif (!empty($db->options['datatype_map'][$type])) { + $type = $db->options['datatype_map'][$type]; + if (!empty($db->options['datatype_map_callback'][$type])) { + $parameter = array('type' => $type, 'value' => $value, 'quote' => $quote, 'escape_wildcards' => $escape_wildcards); + return call_user_func_array($db->options['datatype_map_callback'][$type], array(&$db, __FUNCTION__, $parameter)); + } + } + + if (!method_exists($this, "_quote{$type}")) { + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'type not defined: '.$type, __FUNCTION__); + } + $value = $this->{"_quote{$type}"}($value, $quote, $escape_wildcards); + if ($quote && $escape_wildcards && $db->string_quoting['escape_pattern'] + && $db->string_quoting['escape'] !== $db->string_quoting['escape_pattern'] + ) { + $value.= $this->patternEscapeString(); + } + return $value; + } + + // }}} + // {{{ _quoteInteger() + + /** + * Convert a text value into a DBMS specific format that is suitable to + * compose query statements. + * + * @param string $value text string value that is intended to be converted. + * @param bool $quote determines if the value should be quoted and escaped + * @param bool $escape_wildcards if to escape escape wildcards + * @return string text string that represents the given argument value in + * a DBMS specific format. + * @access protected + */ + function _quoteInteger($value, $quote, $escape_wildcards) + { + return (int)$value; + } + + // }}} + // {{{ _quoteText() + + /** + * Convert a text value into a DBMS specific format that is suitable to + * compose query statements. + * + * @param string $value text string value that is intended to be converted. + * @param bool $quote determines if the value should be quoted and escaped + * @param bool $escape_wildcards if to escape escape wildcards + * @return string text string that already contains any DBMS specific + * escaped character sequences. + * @access protected + */ + function _quoteText($value, $quote, $escape_wildcards) + { + if (!$quote) { + return $value; + } + + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $value = $db->escape($value, $escape_wildcards); + if (PEAR::isError($value)) { + return $value; + } + return "'".$value."'"; + } + + // }}} + // {{{ _readFile() + + /** + * Convert a text value into a DBMS specific format that is suitable to + * compose query statements. + * + * @param string $value text string value that is intended to be converted. + * @return string text string that represents the given argument value in + * a DBMS specific format. + * @access protected + */ + function _readFile($value) + { + $close = false; + if (preg_match('/^(\w+:\/\/)(.*)$/', $value, $match)) { + $close = true; + if ($match[1] == 'file://') { + $value = $match[2]; + } + $value = @fopen($value, 'r'); + } + + if (is_resource($value)) { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $fp = $value; + $value = ''; + while (!@feof($fp)) { + $value.= @fread($fp, $db->options['lob_buffer_length']); + } + if ($close) { + @fclose($fp); + } + } + + return $value; + } + + // }}} + // {{{ _quoteLOB() + + /** + * Convert a text value into a DBMS specific format that is suitable to + * compose query statements. + * + * @param string $value text string value that is intended to be converted. + * @param bool $quote determines if the value should be quoted and escaped + * @param bool $escape_wildcards if to escape escape wildcards + * @return string text string that represents the given argument value in + * a DBMS specific format. + * @access protected + */ + function _quoteLOB($value, $quote, $escape_wildcards) + { + $value = $this->_readFile($value); + if (PEAR::isError($value)) { + return $value; + } + return $this->_quoteText($value, $quote, $escape_wildcards); + } + + // }}} + // {{{ _quoteCLOB() + + /** + * Convert a text value into a DBMS specific format that is suitable to + * compose query statements. + * + * @param string $value text string value that is intended to be converted. + * @param bool $quote determines if the value should be quoted and escaped + * @param bool $escape_wildcards if to escape escape wildcards + * @return string text string that represents the given argument value in + * a DBMS specific format. + * @access protected + */ + function _quoteCLOB($value, $quote, $escape_wildcards) + { + return $this->_quoteLOB($value, $quote, $escape_wildcards); + } + + // }}} + // {{{ _quoteBLOB() + + /** + * Convert a text value into a DBMS specific format that is suitable to + * compose query statements. + * + * @param string $value text string value that is intended to be converted. + * @param bool $quote determines if the value should be quoted and escaped + * @param bool $escape_wildcards if to escape escape wildcards + * @return string text string that represents the given argument value in + * a DBMS specific format. + * @access protected + */ + function _quoteBLOB($value, $quote, $escape_wildcards) + { + return $this->_quoteLOB($value, $quote, $escape_wildcards); + } + + // }}} + // {{{ _quoteBoolean() + + /** + * Convert a text value into a DBMS specific format that is suitable to + * compose query statements. + * + * @param string $value text string value that is intended to be converted. + * @param bool $quote determines if the value should be quoted and escaped + * @param bool $escape_wildcards if to escape escape wildcards + * @return string text string that represents the given argument value in + * a DBMS specific format. + * @access protected + */ + function _quoteBoolean($value, $quote, $escape_wildcards) + { + return ($value ? 1 : 0); + } + + // }}} + // {{{ _quoteDate() + + /** + * Convert a text value into a DBMS specific format that is suitable to + * compose query statements. + * + * @param string $value text string value that is intended to be converted. + * @param bool $quote determines if the value should be quoted and escaped + * @param bool $escape_wildcards if to escape escape wildcards + * @return string text string that represents the given argument value in + * a DBMS specific format. + * @access protected + */ + function _quoteDate($value, $quote, $escape_wildcards) + { + if ($value === 'CURRENT_DATE') { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + if (isset($db->function) && is_a($db->function, 'MDB2_Driver_Function_Common')) { + return $db->function->now('date'); + } + return 'CURRENT_DATE'; + } + return $this->_quoteText($value, $quote, $escape_wildcards); + } + + // }}} + // {{{ _quoteTimestamp() + + /** + * Convert a text value into a DBMS specific format that is suitable to + * compose query statements. + * + * @param string $value text string value that is intended to be converted. + * @param bool $quote determines if the value should be quoted and escaped + * @param bool $escape_wildcards if to escape escape wildcards + * @return string text string that represents the given argument value in + * a DBMS specific format. + * @access protected + */ + function _quoteTimestamp($value, $quote, $escape_wildcards) + { + if ($value === 'CURRENT_TIMESTAMP') { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + if (isset($db->function) && is_a($db->function, 'MDB2_Driver_Function_Common')) { + return $db->function->now('timestamp'); + } + return 'CURRENT_TIMESTAMP'; + } + return $this->_quoteText($value, $quote, $escape_wildcards); + } + + // }}} + // {{{ _quoteTime() + + /** + * Convert a text value into a DBMS specific format that is suitable to + * compose query statements. + * + * @param string $value text string value that is intended to be converted. + * @param bool $quote determines if the value should be quoted and escaped + * @param bool $escape_wildcards if to escape escape wildcards + * @return string text string that represents the given argument value in + * a DBMS specific format. + * @access protected + */ + function _quoteTime($value, $quote, $escape_wildcards) + { + if ($value === 'CURRENT_TIME') { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + if (isset($db->function) && is_a($db->function, 'MDB2_Driver_Function_Common')) { + return $db->function->now('time'); + } + return 'CURRENT_TIME'; + } + return $this->_quoteText($value, $quote, $escape_wildcards); + } + + // }}} + // {{{ _quoteFloat() + + /** + * Convert a text value into a DBMS specific format that is suitable to + * compose query statements. + * + * @param string $value text string value that is intended to be converted. + * @param bool $quote determines if the value should be quoted and escaped + * @param bool $escape_wildcards if to escape escape wildcards + * @return string text string that represents the given argument value in + * a DBMS specific format. + * @access protected + */ + function _quoteFloat($value, $quote, $escape_wildcards) + { + if (preg_match('/^(.*)e([-+])(\d+)$/i', $value, $matches)) { + $decimal = $this->_quoteDecimal($matches[1], $quote, $escape_wildcards); + $sign = $matches[2]; + $exponent = str_pad($matches[3], 2, '0', STR_PAD_LEFT); + $value = $decimal.'E'.$sign.$exponent; + } else { + $value = $this->_quoteDecimal($value, $quote, $escape_wildcards); + } + return $value; + } + + // }}} + // {{{ _quoteDecimal() + + /** + * Convert a text value into a DBMS specific format that is suitable to + * compose query statements. + * + * @param string $value text string value that is intended to be converted. + * @param bool $quote determines if the value should be quoted and escaped + * @param bool $escape_wildcards if to escape escape wildcards + * @return string text string that represents the given argument value in + * a DBMS specific format. + * @access protected + */ + function _quoteDecimal($value, $quote, $escape_wildcards) + { + $value = (string)$value; + $value = preg_replace('/[^\d\.,\-+eE]/', '', $value); + if (preg_match('/[^\.\d]/', $value)) { + if (strpos($value, ',')) { + // 1000,00 + if (!strpos($value, '.')) { + // convert the last "," to a "." + $value = strrev(str_replace(',', '.', strrev($value))); + // 1.000,00 + } elseif (strpos($value, '.') && strpos($value, '.') < strpos($value, ',')) { + $value = str_replace('.', '', $value); + // convert the last "," to a "." + $value = strrev(str_replace(',', '.', strrev($value))); + // 1,000.00 + } else { + $value = str_replace(',', '', $value); + } + } + } + return $value; + } + + // }}} + // {{{ writeLOBToFile() + + /** + * retrieve LOB from the database + * + * @param resource $lob stream handle + * @param string $file name of the file into which the LOb should be fetched + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access protected + */ + function writeLOBToFile($lob, $file) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + if (preg_match('/^(\w+:\/\/)(.*)$/', $file, $match)) { + if ($match[1] == 'file://') { + $file = $match[2]; + } + } + + $fp = @fopen($file, 'wb'); + while (!@feof($lob)) { + $result = @fread($lob, $db->options['lob_buffer_length']); + $read = strlen($result); + if (@fwrite($fp, $result, $read) != $read) { + @fclose($fp); + return $db->raiseError(MDB2_ERROR, null, null, + 'could not write to the output file', __FUNCTION__); + } + } + @fclose($fp); + return MDB2_OK; + } + + // }}} + // {{{ _retrieveLOB() + + /** + * retrieve LOB from the database + * + * @param array $lob array + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access protected + */ + function _retrieveLOB(&$lob) + { + if (is_null($lob['value'])) { + $lob['value'] = $lob['resource']; + } + $lob['loaded'] = true; + return MDB2_OK; + } + + // }}} + // {{{ readLOB() + + /** + * Read data from large object input stream. + * + * @param resource $lob stream handle + * @param string $data reference to a variable that will hold data + * to be read from the large object input stream + * @param integer $length value that indicates the largest ammount ofdata + * to be read from the large object input stream. + * @return mixed the effective number of bytes read from the large object + * input stream on sucess or an MDB2 error object. + * @access public + * @see endOfLOB() + */ + function _readLOB($lob, $length) + { + return substr($lob['value'], $lob['position'], $length); + } + + // }}} + // {{{ _endOfLOB() + + /** + * Determine whether it was reached the end of the large object and + * therefore there is no more data to be read for the its input stream. + * + * @param array $lob array + * @return mixed true or false on success, a MDB2 error on failure + * @access protected + */ + function _endOfLOB($lob) + { + return $lob['endOfLOB']; + } + + // }}} + // {{{ destroyLOB() + + /** + * Free any resources allocated during the lifetime of the large object + * handler object. + * + * @param resource $lob stream handle + * @access public + */ + function destroyLOB($lob) + { + $lob_data = stream_get_meta_data($lob); + $lob_index = $lob_data['wrapper_data']->lob_index; + fclose($lob); + if (isset($this->lobs[$lob_index])) { + $this->_destroyLOB($this->lobs[$lob_index]); + unset($this->lobs[$lob_index]); + } + return MDB2_OK; + } + + // }}} + // {{{ _destroyLOB() + + /** + * Free any resources allocated during the lifetime of the large object + * handler object. + * + * @param array $lob array + * @access private + */ + function _destroyLOB(&$lob) + { + return MDB2_OK; + } + + // }}} + // {{{ implodeArray() + + /** + * apply a type to all values of an array and return as a comma seperated string + * useful for generating IN statements + * + * @access public + * + * @param array $array data array + * @param string $type determines type of the field + * + * @return string comma seperated values + */ + function implodeArray($array, $type = false) + { + if (!is_array($array) || empty($array)) { + return 'NULL'; + } + if ($type) { + foreach ($array as $value) { + $return[] = $this->quote($value, $type); + } + } else { + $return = $array; + } + return implode(', ', $return); + } + + // }}} + // {{{ matchPattern() + + /** + * build a pattern matching string + * + * @access public + * + * @param array $pattern even keys are strings, odd are patterns (% and _) + * @param string $operator optional pattern operator (LIKE, ILIKE and maybe others in the future) + * @param string $field optional field name that is being matched against + * (might be required when emulating ILIKE) + * + * @return string SQL pattern + */ + function matchPattern($pattern, $operator = null, $field = null) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $match = ''; + if (!is_null($operator)) { + $operator = strtoupper($operator); + switch ($operator) { + // case insensitive + case 'ILIKE': + if (is_null($field)) { + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'case insensitive LIKE matching requires passing the field name', __FUNCTION__); + } + $db->loadModule('Function', null, true); + $match = $db->function->lower($field).' LIKE '; + break; + // case sensitive + case 'LIKE': + $match = is_null($field) ? 'LIKE ' : $field.' LIKE '; + break; + default: + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'not a supported operator type:'. $operator, __FUNCTION__); + } + } + $match.= "'"; + foreach ($pattern as $key => $value) { + if ($key % 2) { + $match.= $value; + } else { + if ($operator === 'ILIKE') { + $value = strtolower($value); + } + $escaped = $db->escape($value); + if (PEAR::isError($escaped)) { + return $escaped; + } + $match.= $db->escapePattern($escaped); + } + } + $match.= "'"; + $match.= $this->patternEscapeString(); + return $match; + } + + // }}} + // {{{ patternEscapeString() + + /** + * build string to define pattern escape character + * + * @access public + * + * @return string define pattern escape character + */ + function patternEscapeString() + { + return ''; + } + + // }}} + // {{{ mapNativeDatatype() + + /** + * Maps a native array description of a field to a MDB2 datatype and length + * + * @param array $field native field description + * @return array containing the various possible types, length, sign, fixed + * @access public + */ + function mapNativeDatatype($field) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + // If the user has specified an option to map the native field + // type to a custom MDB2 datatype... + $db_type = strtok($field['type'], '(), '); + if (!empty($db->options['nativetype_map_callback'][$db_type])) { + return call_user_func_array($db->options['nativetype_map_callback'][$db_type], array($db, $field)); + } + + // Otherwise perform the built-in (i.e. normal) MDB2 native type to + // MDB2 datatype conversion + return $this->_mapNativeDatatype($field); + } + + // }}} + // {{{ _mapNativeDatatype() + + /** + * Maps a native array description of a field to a MDB2 datatype and length + * + * @param array $field native field description + * @return array containing the various possible types, length, sign, fixed + * @access public + */ + function _mapNativeDatatype($field) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'method not implemented', __FUNCTION__); + } + + // }}} + // {{{ mapPrepareDatatype() + + /** + * Maps an mdb2 datatype to mysqli prepare type + * + * @param string $type + * @return string + * @access public + */ + function mapPrepareDatatype($type) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + if (!empty($db->options['datatype_map'][$type])) { + $type = $db->options['datatype_map'][$type]; + if (!empty($db->options['datatype_map_callback'][$type])) { + $parameter = array('type' => $type); + return call_user_func_array($db->options['datatype_map_callback'][$type], array(&$db, __FUNCTION__, $parameter)); + } + } + + return $type; + } +} +?> diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/MDB2/Driver/Function/Common.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/MDB2/Driver/Function/Common.php --- php-mdb2-2.4.1/MDB2-2.5.0b2/MDB2/Driver/Function/Common.php 1970-01-01 01:00:00.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/MDB2/Driver/Function/Common.php 2009-01-14 16:28:08.000000000 +0000 @@ -0,0 +1,293 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: Common.php,v 1.21 2008/02/17 18:51:39 quipo Exp $ +// + +/** + * @package MDB2 + * @category Database + * @author Lukas Smith + */ + +/** + * Base class for the function modules that is extended by each MDB2 driver + * + * To load this module in the MDB2 object: + * $mdb->loadModule('Function'); + * + * @package MDB2 + * @category Database + * @author Lukas Smith + */ +class MDB2_Driver_Function_Common extends MDB2_Module_Common +{ + // {{{ executeStoredProc() + + /** + * Execute a stored procedure and return any results + * + * @param string $name string that identifies the function to execute + * @param mixed $params array that contains the paramaters to pass the stored proc + * @param mixed $types array that contains the types of the columns in + * the result set + * @param mixed $result_class string which specifies which result class to use + * @param mixed $result_wrap_class string which specifies which class to wrap results in + * + * @return mixed a result handle or MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function &executeStoredProc($name, $params = null, $types = null, $result_class = true, $result_wrap_class = false) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $error =& $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'method not implemented', __FUNCTION__); + return $error; + } + + // }}} + // {{{ functionTable() + + /** + * return string for internal table used when calling only a function + * + * @return string for internal table used when calling only a function + * @access public + */ + function functionTable() + { + return ''; + } + + // }}} + // {{{ now() + + /** + * Return string to call a variable with the current timestamp inside an SQL statement + * There are three special variables for current date and time: + * - CURRENT_TIMESTAMP (date and time, TIMESTAMP type) + * - CURRENT_DATE (date, DATE type) + * - CURRENT_TIME (time, TIME type) + * + * @param string $type 'timestamp' | 'time' | 'date' + * + * @return string to call a variable with the current timestamp + * @access public + */ + function now($type = 'timestamp') + { + switch ($type) { + case 'time': + return 'CURRENT_TIME'; + case 'date': + return 'CURRENT_DATE'; + case 'timestamp': + default: + return 'CURRENT_TIMESTAMP'; + } + } + + // }}} + // {{{ unixtimestamp() + + /** + * return string to call a function to get the unix timestamp from a iso timestamp + * + * @param string $expression + * + * @return string to call a variable with the timestamp + * @access public + */ + function unixtimestamp($expression) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $error =& $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'method not implemented', __FUNCTION__); + return $error; + } + + // }}} + // {{{ substring() + + /** + * return string to call a function to get a substring inside an SQL statement + * + * @return string to call a function to get a substring + * @access public + */ + function substring($value, $position = 1, $length = null) + { + if (!is_null($length)) { + return "SUBSTRING($value FROM $position FOR $length)"; + } + return "SUBSTRING($value FROM $position)"; + } + + // }}} + // {{{ replace() + + /** + * return string to call a function to get replace inside an SQL statement. + * + * @return string to call a function to get a replace + * @access public + */ + function replace($str, $from_str, $to_str) + { + return "REPLACE($str, $from_str , $to_str)"; + } + + // }}} + // {{{ concat() + + /** + * Returns string to concatenate two or more string parameters + * + * @param string $value1 + * @param string $value2 + * @param string $values... + * + * @return string to concatenate two strings + * @access public + */ + function concat($value1, $value2) + { + $args = func_get_args(); + return "(".implode(' || ', $args).")"; + } + + // }}} + // {{{ random() + + /** + * return string to call a function to get random value inside an SQL statement + * + * @return return string to generate float between 0 and 1 + * @access public + */ + function random() + { + return 'RAND()'; + } + + // }}} + // {{{ lower() + + /** + * return string to call a function to lower the case of an expression + * + * @param string $expression + * + * @return return string to lower case of an expression + * @access public + */ + function lower($expression) + { + return "LOWER($expression)"; + } + + // }}} + // {{{ upper() + + /** + * return string to call a function to upper the case of an expression + * + * @param string $expression + * + * @return return string to upper case of an expression + * @access public + */ + function upper($expression) + { + return "UPPER($expression)"; + } + + // }}} + // {{{ length() + + /** + * return string to call a function to get the length of a string expression + * + * @param string $expression + * + * @return return string to get the string expression length + * @access public + */ + function length($expression) + { + return "LENGTH($expression)"; + } + + // }}} + // {{{ guid() + + /** + * Returns global unique identifier + * + * @return string to get global unique identifier + * @access public + */ + function guid() + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $error =& $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'method not implemented', __FUNCTION__); + return $error; + } + + // }}} +} +?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/MDB2/Driver/Manager/Common.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/MDB2/Driver/Manager/Common.php --- php-mdb2-2.4.1/MDB2-2.5.0b2/MDB2/Driver/Manager/Common.php 1970-01-01 01:00:00.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/MDB2/Driver/Manager/Common.php 2009-01-14 16:28:08.000000000 +0000 @@ -0,0 +1,1014 @@ + | +// | Lorenzo Alberton | +// +----------------------------------------------------------------------+ +// +// $Id: Common.php,v 1.72 2009/01/14 15:00:40 quipo Exp $ +// + +/** + * @package MDB2 + * @category Database + * @author Lukas Smith + * @author Lorenzo Alberton + */ + +/** + * Base class for the management modules that is extended by each MDB2 driver + * + * To load this module in the MDB2 object: + * $mdb->loadModule('Manager'); + * + * @package MDB2 + * @category Database + * @author Lukas Smith + */ +class MDB2_Driver_Manager_Common extends MDB2_Module_Common +{ + // {{{ splitTableSchema() + + /** + * Split the "[owner|schema].table" notation into an array + * + * @param string $table [schema and] table name + * + * @return array array(schema, table) + * @access private + */ + function splitTableSchema($table) + { + $ret = array(); + if (strpos($table, '.') !== false) { + return explode('.', $table); + } + return array(null, $table); + } + + // }}} + // {{{ getFieldDeclarationList() + + /** + * Get declaration of a number of field in bulk + * + * @param array $fields a multidimensional associative array. + * The first dimension determines the field name, while the second + * dimension is keyed with the name of the properties + * of the field being declared as array indexes. Currently, the types + * of supported field properties are as follows: + * + * default + * Boolean value to be used as default for this field. + * + * notnull + * Boolean flag that indicates whether this field is constrained + * to not be set to null. + * + * @return mixed string on success, a MDB2 error on failure + * @access public + */ + function getFieldDeclarationList($fields) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + if (!is_array($fields) || empty($fields)) { + return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, + 'missing any fields', __FUNCTION__); + } + foreach ($fields as $field_name => $field) { + $query = $db->getDeclaration($field['type'], $field_name, $field); + if (PEAR::isError($query)) { + return $query; + } + $query_fields[] = $query; + } + return implode(', ', $query_fields); + } + + // }}} + // {{{ _fixSequenceName() + + /** + * Removes any formatting in an sequence name using the 'seqname_format' option + * + * @param string $sqn string that containts name of a potential sequence + * @param bool $check if only formatted sequences should be returned + * @return string name of the sequence with possible formatting removed + * @access protected + */ + function _fixSequenceName($sqn, $check = false) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $seq_pattern = '/^'.preg_replace('/%s/', '([a-z0-9_]+)', $db->options['seqname_format']).'$/i'; + $seq_name = preg_replace($seq_pattern, '\\1', $sqn); + if ($seq_name && !strcasecmp($sqn, $db->getSequenceName($seq_name))) { + return $seq_name; + } + if ($check) { + return false; + } + return $sqn; + } + + // }}} + // {{{ _fixIndexName() + + /** + * Removes any formatting in an index name using the 'idxname_format' option + * + * @param string $idx string that containts name of anl index + * @return string name of the index with eventual formatting removed + * @access protected + */ + function _fixIndexName($idx) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $idx_pattern = '/^'.preg_replace('/%s/', '([a-z0-9_]+)', $db->options['idxname_format']).'$/i'; + $idx_name = preg_replace($idx_pattern, '\\1', $idx); + if ($idx_name && !strcasecmp($idx, $db->getIndexName($idx_name))) { + return $idx_name; + } + return $idx; + } + + // }}} + // {{{ createDatabase() + + /** + * create a new database + * + * @param string $name name of the database that should be created + * @param array $options array with charset, collation info + * + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function createDatabase($database, $options = array()) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'method not implemented', __FUNCTION__); + } + + // }}} + // {{{ alterDatabase() + + /** + * alter an existing database + * + * @param string $name name of the database that should be created + * @param array $options array with charset, collation info + * + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function alterDatabase($database, $options = array()) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'method not implemented', __FUNCTION__); + } + + // }}} + // {{{ dropDatabase() + + /** + * drop an existing database + * + * @param string $name name of the database that should be dropped + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function dropDatabase($database) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'method not implemented', __FUNCTION__); + } + + // }}} + // {{{ _getCreateTableQuery() + + /** + * Create a basic SQL query for a new table creation + * + * @param string $name Name of the database that should be created + * @param array $fields Associative array that contains the definition of each field of the new table + * @param array $options An associative array of table options + * + * @return mixed string (the SQL query) on success, a MDB2 error on failure + * @see createTable() + */ + function _getCreateTableQuery($name, $fields, $options = array()) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + if (!$name) { + return $db->raiseError(MDB2_ERROR_CANNOT_CREATE, null, null, + 'no valid table name specified', __FUNCTION__); + } + if (empty($fields)) { + return $db->raiseError(MDB2_ERROR_CANNOT_CREATE, null, null, + 'no fields specified for table "'.$name.'"', __FUNCTION__); + } + $query_fields = $this->getFieldDeclarationList($fields); + if (PEAR::isError($query_fields)) { + return $query_fields; + } + if (!empty($options['primary'])) { + $query_fields.= ', PRIMARY KEY ('.implode(', ', array_keys($options['primary'])).')'; + } + + $name = $db->quoteIdentifier($name, true); + $result = 'CREATE '; + if (!empty($options['temporary'])) { + $result .= $this->_getTemporaryTableQuery(); + } + $result .= " TABLE $name ($query_fields)"; + return $result; + } + + // }}} + // {{{ _getTemporaryTableQuery() + + /** + * A method to return the required SQL string that fits between CREATE ... TABLE + * to create the table as a temporary table. + * + * Should be overridden in driver classes to return the correct string for the + * specific database type. + * + * The default is to return the string "TEMPORARY" - this will result in a + * SQL error for any database that does not support temporary tables, or that + * requires a different SQL command from "CREATE TEMPORARY TABLE". + * + * @return string The string required to be placed between "CREATE" and "TABLE" + * to generate a temporary table, if possible. + */ + function _getTemporaryTableQuery() + { + return 'TEMPORARY'; + } + + // }}} + // {{{ createTable() + + /** + * create a new table + * + * @param string $name Name of the database that should be created + * @param array $fields Associative array that contains the definition of each field of the new table + * The indexes of the array entries are the names of the fields of the table an + * the array entry values are associative arrays like those that are meant to be + * passed with the field definitions to get[Type]Declaration() functions. + * array( + * 'id' => array( + * 'type' => 'integer', + * 'unsigned' => 1 + * 'notnull' => 1 + * 'default' => 0 + * ), + * 'name' => array( + * 'type' => 'text', + * 'length' => 12 + * ), + * 'password' => array( + * 'type' => 'text', + * 'length' => 12 + * ) + * ); + * @param array $options An associative array of table options: + * array( + * 'comment' => 'Foo', + * 'temporary' => true|false, + * ); + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function createTable($name, $fields, $options = array()) + { + $query = $this->_getCreateTableQuery($name, $fields, $options); + if (PEAR::isError($query)) { + return $query; + } + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + $result = $db->exec($query); + if (PEAR::isError($result)) { + return $result; + } + return MDB2_OK; + } + + // }}} + // {{{ dropTable() + + /** + * drop an existing table + * + * @param string $name name of the table that should be dropped + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function dropTable($name) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $name = $db->quoteIdentifier($name, true); + return $db->exec("DROP TABLE $name"); + } + + // }}} + // {{{ truncateTable() + + /** + * Truncate an existing table (if the TRUNCATE TABLE syntax is not supported, + * it falls back to a DELETE FROM TABLE query) + * + * @param string $name name of the table that should be truncated + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function truncateTable($name) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $name = $db->quoteIdentifier($name, true); + return $db->exec("DELETE FROM $name"); + } + + // }}} + // {{{ vacuum() + + /** + * Optimize (vacuum) all the tables in the db (or only the specified table) + * and optionally run ANALYZE. + * + * @param string $table table name (all the tables if empty) + * @param array $options an array with driver-specific options: + * - timeout [int] (in seconds) [mssql-only] + * - analyze [boolean] [pgsql and mysql] + * - full [boolean] [pgsql-only] + * - freeze [boolean] [pgsql-only] + * + * @return mixed MDB2_OK success, a MDB2 error on failure + * @access public + */ + function vacuum($table = null, $options = array()) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'method not implemented', __FUNCTION__); + } + + // }}} + // {{{ alterTable() + + /** + * alter an existing table + * + * @param string $name name of the table that is intended to be changed. + * @param array $changes associative array that contains the details of each type + * of change that is intended to be performed. The types of + * changes that are currently supported are defined as follows: + * + * name + * + * New name for the table. + * + * add + * + * Associative array with the names of fields to be added as + * indexes of the array. The value of each entry of the array + * should be set to another associative array with the properties + * of the fields to be added. The properties of the fields should + * be the same as defined by the MDB2 parser. + * + * + * remove + * + * Associative array with the names of fields to be removed as indexes + * of the array. Currently the values assigned to each entry are ignored. + * An empty array should be used for future compatibility. + * + * rename + * + * Associative array with the names of fields to be renamed as indexes + * of the array. The value of each entry of the array should be set to + * another associative array with the entry named name with the new + * field name and the entry named Declaration that is expected to contain + * the portion of the field declaration already in DBMS specific SQL code + * as it is used in the CREATE TABLE statement. + * + * change + * + * Associative array with the names of the fields to be changed as indexes + * of the array. Keep in mind that if it is intended to change either the + * name of a field and any other properties, the change array entries + * should have the new names of the fields as array indexes. + * + * The value of each entry of the array should be set to another associative + * array with the properties of the fields to that are meant to be changed as + * array entries. These entries should be assigned to the new values of the + * respective properties. The properties of the fields should be the same + * as defined by the MDB2 parser. + * + * Example + * array( + * 'name' => 'userlist', + * 'add' => array( + * 'quota' => array( + * 'type' => 'integer', + * 'unsigned' => 1 + * ) + * ), + * 'remove' => array( + * 'file_limit' => array(), + * 'time_limit' => array() + * ), + * 'change' => array( + * 'name' => array( + * 'length' => '20', + * 'definition' => array( + * 'type' => 'text', + * 'length' => 20, + * ), + * ) + * ), + * 'rename' => array( + * 'sex' => array( + * 'name' => 'gender', + * 'definition' => array( + * 'type' => 'text', + * 'length' => 1, + * 'default' => 'M', + * ), + * ) + * ) + * ) + * + * @param boolean $check indicates whether the function should just check if the DBMS driver + * can perform the requested table alterations if the value is true or + * actually perform them otherwise. + * @access public + * + * @return mixed MDB2_OK on success, a MDB2 error on failure + */ + function alterTable($name, $changes, $check) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'method not implemented', __FUNCTION__); + } + + // }}} + // {{{ listDatabases() + + /** + * list all databases + * + * @return mixed array of database names on success, a MDB2 error on failure + * @access public + */ + function listDatabases() + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'method not implementedd', __FUNCTION__); + } + + // }}} + // {{{ listUsers() + + /** + * list all users + * + * @return mixed array of user names on success, a MDB2 error on failure + * @access public + */ + function listUsers() + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'method not implemented', __FUNCTION__); + } + + // }}} + // {{{ listViews() + + /** + * list all views in the current database + * + * @param string database, the current is default + * NB: not all the drivers can get the view names from + * a database other than the current one + * @return mixed array of view names on success, a MDB2 error on failure + * @access public + */ + function listViews($database = null) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'method not implemented', __FUNCTION__); + } + + // }}} + // {{{ listTableViews() + + /** + * list the views in the database that reference a given table + * + * @param string table for which all referenced views should be found + * @return mixed array of view names on success, a MDB2 error on failure + * @access public + */ + function listTableViews($table) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'method not implemented', __FUNCTION__); + } + + // }}} + // {{{ listTableTriggers() + + /** + * list all triggers in the database that reference a given table + * + * @param string table for which all referenced triggers should be found + * @return mixed array of trigger names on success, a MDB2 error on failure + * @access public + */ + function listTableTriggers($table = null) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'method not implemented', __FUNCTION__); + } + + // }}} + // {{{ listFunctions() + + /** + * list all functions in the current database + * + * @return mixed array of function names on success, a MDB2 error on failure + * @access public + */ + function listFunctions() + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'method not implemented', __FUNCTION__); + } + + // }}} + // {{{ listTables() + + /** + * list all tables in the current database + * + * @param string database, the current is default. + * NB: not all the drivers can get the table names from + * a database other than the current one + * @return mixed array of table names on success, a MDB2 error on failure + * @access public + */ + function listTables($database = null) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'method not implemented', __FUNCTION__); + } + + // }}} + // {{{ listTableFields() + + /** + * list all fields in a table in the current database + * + * @param string $table name of table that should be used in method + * @return mixed array of field names on success, a MDB2 error on failure + * @access public + */ + function listTableFields($table) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'method not implemented', __FUNCTION__); + } + + // }}} + // {{{ createIndex() + + /** + * Get the stucture of a field into an array + * + * @param string $table name of the table on which the index is to be created + * @param string $name name of the index to be created + * @param array $definition associative array that defines properties of the index to be created. + * Currently, only one property named FIELDS is supported. This property + * is also an associative with the names of the index fields as array + * indexes. Each entry of this array is set to another type of associative + * array that specifies properties of the index that are specific to + * each field. + * + * Currently, only the sorting property is supported. It should be used + * to define the sorting direction of the index. It may be set to either + * ascending or descending. + * + * Not all DBMS support index sorting direction configuration. The DBMS + * drivers of those that do not support it ignore this property. Use the + * function supports() to determine whether the DBMS driver can manage indexes. + * + * Example + * array( + * 'fields' => array( + * 'user_name' => array( + * 'sorting' => 'ascending' + * ), + * 'last_login' => array() + * ) + * ) + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function createIndex($table, $name, $definition) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $table = $db->quoteIdentifier($table, true); + $name = $db->quoteIdentifier($db->getIndexName($name), true); + $query = "CREATE INDEX $name ON $table"; + $fields = array(); + foreach (array_keys($definition['fields']) as $field) { + $fields[] = $db->quoteIdentifier($field, true); + } + $query .= ' ('. implode(', ', $fields) . ')'; + return $db->exec($query); + } + + // }}} + // {{{ dropIndex() + + /** + * drop existing index + * + * @param string $table name of table that should be used in method + * @param string $name name of the index to be dropped + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function dropIndex($table, $name) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $name = $db->quoteIdentifier($db->getIndexName($name), true); + return $db->exec("DROP INDEX $name"); + } + + // }}} + // {{{ listTableIndexes() + + /** + * list all indexes in a table + * + * @param string $table name of table that should be used in method + * @return mixed array of index names on success, a MDB2 error on failure + * @access public + */ + function listTableIndexes($table) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'method not implemented', __FUNCTION__); + } + + // }}} + // {{{ _getAdvancedFKOptions() + + /** + * Return the FOREIGN KEY query section dealing with non-standard options + * as MATCH, INITIALLY DEFERRED, ON UPDATE, ... + * + * @param array $definition + * @return string + * @access protected + */ + function _getAdvancedFKOptions($definition) + { + return ''; + } + + // }}} + // {{{ createConstraint() + + /** + * create a constraint on a table + * + * @param string $table name of the table on which the constraint is to be created + * @param string $name name of the constraint to be created + * @param array $definition associative array that defines properties of the constraint to be created. + * The full structure of the array looks like this: + *
    +     *          array (
    +     *              [primary] => 0
    +     *              [unique]  => 0
    +     *              [foreign] => 1
    +     *              [check]   => 0
    +     *              [fields] => array (
    +     *                  [field1name] => array() // one entry per each field covered
    +     *                  [field2name] => array() // by the index
    +     *                  [field3name] => array(
    +     *                      [sorting]  => ascending
    +     *                      [position] => 3
    +     *                  )
    +     *              )
    +     *              [references] => array(
    +     *                  [table] => name
    +     *                  [fields] => array(
    +     *                      [field1name] => array(  //one entry per each referenced field
    +     *                           [position] => 1
    +     *                      )
    +     *                  )
    +     *              )
    +     *              [deferrable] => 0
    +     *              [initiallydeferred] => 0
    +     *              [onupdate] => CASCADE|RESTRICT|SET NULL|SET DEFAULT|NO ACTION
    +     *              [ondelete] => CASCADE|RESTRICT|SET NULL|SET DEFAULT|NO ACTION
    +     *              [match] => SIMPLE|PARTIAL|FULL
    +     *          );
    +     *          
    + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function createConstraint($table, $name, $definition) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + $table = $db->quoteIdentifier($table, true); + $name = $db->quoteIdentifier($db->getIndexName($name), true); + $query = "ALTER TABLE $table ADD CONSTRAINT $name"; + if (!empty($definition['primary'])) { + $query.= ' PRIMARY KEY'; + } elseif (!empty($definition['unique'])) { + $query.= ' UNIQUE'; + } elseif (!empty($definition['foreign'])) { + $query.= ' FOREIGN KEY'; + } + $fields = array(); + foreach (array_keys($definition['fields']) as $field) { + $fields[] = $db->quoteIdentifier($field, true); + } + $query .= ' ('. implode(', ', $fields) . ')'; + if (!empty($definition['foreign'])) { + $query.= ' REFERENCES ' . $db->quoteIdentifier($definition['references']['table'], true); + $referenced_fields = array(); + foreach (array_keys($definition['references']['fields']) as $field) { + $referenced_fields[] = $db->quoteIdentifier($field, true); + } + $query .= ' ('. implode(', ', $referenced_fields) . ')'; + $query .= $this->_getAdvancedFKOptions($definition); + } + return $db->exec($query); + } + + // }}} + // {{{ dropConstraint() + + /** + * drop existing constraint + * + * @param string $table name of table that should be used in method + * @param string $name name of the constraint to be dropped + * @param string $primary hint if the constraint is primary + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function dropConstraint($table, $name, $primary = false) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $table = $db->quoteIdentifier($table, true); + $name = $db->quoteIdentifier($db->getIndexName($name), true); + return $db->exec("ALTER TABLE $table DROP CONSTRAINT $name"); + } + + // }}} + // {{{ listTableConstraints() + + /** + * list all constraints in a table + * + * @param string $table name of table that should be used in method + * @return mixed array of constraint names on success, a MDB2 error on failure + * @access public + */ + function listTableConstraints($table) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'method not implemented', __FUNCTION__); + } + + // }}} + // {{{ createSequence() + + /** + * create sequence + * + * @param string $seq_name name of the sequence to be created + * @param string $start start value of the sequence; default is 1 + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function createSequence($seq_name, $start = 1) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'method not implemented', __FUNCTION__); + } + + // }}} + // {{{ dropSequence() + + /** + * drop existing sequence + * + * @param string $seq_name name of the sequence to be dropped + * @return mixed MDB2_OK on success, a MDB2 error on failure + * @access public + */ + function dropSequence($name) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'method not implemented', __FUNCTION__); + } + + // }}} + // {{{ listSequences() + + /** + * list all sequences in the current database + * + * @param string database, the current is default + * NB: not all the drivers can get the sequence names from + * a database other than the current one + * @return mixed array of sequence names on success, a MDB2 error on failure + * @access public + */ + function listSequences($database = null) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'method not implemented', __FUNCTION__); + } + + // }}} +} +?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/MDB2/Driver/Native/Common.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/MDB2/Driver/Native/Common.php --- php-mdb2-2.4.1/MDB2-2.5.0b2/MDB2/Driver/Native/Common.php 1970-01-01 01:00:00.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/MDB2/Driver/Native/Common.php 2009-01-14 16:28:08.000000000 +0000 @@ -0,0 +1,61 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: Common.php,v 1.2 2007/09/09 13:47:36 quipo Exp $ +// + +/** + * Base class for the natuve modules that is extended by each MDB2 driver + * + * To load this module in the MDB2 object: + * $mdb->loadModule('Native'); + * + * @package MDB2 + * @category Database + * @author Lukas Smith + */ +class MDB2_Driver_Native_Common extends MDB2_Module_Common +{ +} +?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/MDB2/Driver/Reverse/Common.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/MDB2/Driver/Reverse/Common.php --- php-mdb2-2.4.1/MDB2-2.5.0b2/MDB2/Driver/Reverse/Common.php 1970-01-01 01:00:00.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/MDB2/Driver/Reverse/Common.php 2009-01-14 16:28:08.000000000 +0000 @@ -0,0 +1,517 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: Common.php,v 1.43 2009/01/14 15:01:21 quipo Exp $ +// + +/** + * @package MDB2 + * @category Database + */ + +/** + * These are constants for the tableInfo-function + * they are bitwised or'ed. so if there are more constants to be defined + * in the future, adjust MDB2_TABLEINFO_FULL accordingly + */ + +define('MDB2_TABLEINFO_ORDER', 1); +define('MDB2_TABLEINFO_ORDERTABLE', 2); +define('MDB2_TABLEINFO_FULL', 3); + +/** + * Base class for the schema reverse engineering module that is extended by each MDB2 driver + * + * To load this module in the MDB2 object: + * $mdb->loadModule('Reverse'); + * + * @package MDB2 + * @category Database + * @author Lukas Smith + */ +class MDB2_Driver_Reverse_Common extends MDB2_Module_Common +{ + // {{{ splitTableSchema() + + /** + * Split the "[owner|schema].table" notation into an array + * + * @param string $table [schema and] table name + * + * @return array array(schema, table) + * @access private + */ + function splitTableSchema($table) + { + $ret = array(); + if (strpos($table, '.') !== false) { + return explode('.', $table); + } + return array(null, $table); + } + + // }}} + // {{{ getTableFieldDefinition() + + /** + * Get the structure of a field into an array + * + * @param string $table name of table that should be used in method + * @param string $field name of field that should be used in method + * @return mixed data array on success, a MDB2 error on failure. + * The returned array contains an array for each field definition, + * with all or some of these indices, depending on the field data type: + * [notnull] [nativetype] [length] [fixed] [default] [type] [mdb2type] + * @access public + */ + function getTableFieldDefinition($table, $field) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'method not implemented', __FUNCTION__); + } + + // }}} + // {{{ getTableIndexDefinition() + + /** + * Get the structure of an index into an array + * + * @param string $table name of table that should be used in method + * @param string $index name of index that should be used in method + * @return mixed data array on success, a MDB2 error on failure + * The returned array has this structure: + *
    + * array ( + * [fields] => array ( + * [field1name] => array() // one entry per each field covered + * [field2name] => array() // by the index + * [field3name] => array( + * [sorting] => ascending + * ) + * ) + * ); + * + * @access public + */ + function getTableIndexDefinition($table, $index) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'method not implemented', __FUNCTION__); + } + + // }}} + // {{{ getTableConstraintDefinition() + + /** + * Get the structure of an constraints into an array + * + * @param string $table name of table that should be used in method + * @param string $index name of index that should be used in method + * @return mixed data array on success, a MDB2 error on failure + * The returned array has this structure: + *
    +     *          array (
    +     *              [primary] => 0
    +     *              [unique]  => 0
    +     *              [foreign] => 1
    +     *              [check]   => 0
    +     *              [fields] => array (
    +     *                  [field1name] => array() // one entry per each field covered
    +     *                  [field2name] => array() // by the index
    +     *                  [field3name] => array(
    +     *                      [sorting]  => ascending
    +     *                      [position] => 3
    +     *                  )
    +     *              )
    +     *              [references] => array(
    +     *                  [table] => name
    +     *                  [fields] => array(
    +     *                      [field1name] => array(  //one entry per each referenced field
    +     *                           [position] => 1
    +     *                      )
    +     *                  )
    +     *              )
    +     *              [deferrable] => 0
    +     *              [initiallydeferred] => 0
    +     *              [onupdate] => CASCADE|RESTRICT|SET NULL|SET DEFAULT|NO ACTION
    +     *              [ondelete] => CASCADE|RESTRICT|SET NULL|SET DEFAULT|NO ACTION
    +     *              [match] => SIMPLE|PARTIAL|FULL
    +     *          );
    +     *          
    + * @access public + */ + function getTableConstraintDefinition($table, $index) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'method not implemented', __FUNCTION__); + } + + // }}} + // {{{ getSequenceDefinition() + + /** + * Get the structure of a sequence into an array + * + * @param string $sequence name of sequence that should be used in method + * @return mixed data array on success, a MDB2 error on failure + * The returned array has this structure: + *
    +     *          array (
    +     *              [start] => n
    +     *          );
    +     *          
    + * @access public + */ + function getSequenceDefinition($sequence) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $start = $db->currId($sequence); + if (PEAR::isError($start)) { + return $start; + } + if ($db->supports('current_id')) { + $start++; + } else { + $db->warnings[] = 'database does not support getting current + sequence value, the sequence value was incremented'; + } + $definition = array(); + if ($start != 1) { + $definition = array('start' => $start); + } + return $definition; + } + + // }}} + // {{{ getTriggerDefinition() + + /** + * Get the structure of a trigger into an array + * + * EXPERIMENTAL + * + * WARNING: this function is experimental and may change the returned value + * at any time until labelled as non-experimental + * + * @param string $trigger name of trigger that should be used in method + * @return mixed data array on success, a MDB2 error on failure + * The returned array has this structure: + *
    +     *          array (
    +     *              [trigger_name]    => 'trigger name',
    +     *              [table_name]      => 'table name',
    +     *              [trigger_body]    => 'trigger body definition',
    +     *              [trigger_type]    => 'BEFORE' | 'AFTER',
    +     *              [trigger_event]   => 'INSERT' | 'UPDATE' | 'DELETE'
    +     *                  //or comma separated list of multiple events, when supported
    +     *              [trigger_enabled] => true|false
    +     *              [trigger_comment] => 'trigger comment',
    +     *          );
    +     *          
    + * The oci8 driver also returns a [when_clause] index. + * @access public + */ + function getTriggerDefinition($trigger) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'method not implemented', __FUNCTION__); + } + + // }}} + // {{{ tableInfo() + + /** + * Returns information about a table or a result set + * + * The format of the resulting array depends on which $mode + * you select. The sample output below is based on this query: + *
    +     *    SELECT tblFoo.fldID, tblFoo.fldPhone, tblBar.fldId
    +     *    FROM tblFoo
    +     *    JOIN tblBar ON tblFoo.fldId = tblBar.fldId
    +     * 
    + * + *
      + *
    • + * + * null (default) + *
      +     *   [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
      +     *   )
      +     *   
      + * + *
    • + * + * MDB2_TABLEINFO_ORDER + * + *

      In addition to the information found in the default output, + * a notation of the number of columns is provided by the + * num_fields element while the order + * 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.

      + * + *

      If a result set has identical field names, the last one is + * used.

      + * + *
      +     *   [num_fields] => 3
      +     *   [order] => Array (
      +     *       [fldId] => 2
      +     *       [fldTrans] => 1
      +     *   )
      +     *   
      + * + *
    • + * + * MDB2_TABLEINFO_ORDERTABLE + * + *

      Similar to MDB2_TABLEINFO_ORDER 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.

      + * + *
      +     *   [num_fields] => 3
      +     *   [ordertable] => Array (
      +     *       [tblFoo] => Array (
      +     *           [fldId] => 0
      +     *           [fldPhone] => 1
      +     *       )
      +     *       [tblBar] => Array (
      +     *           [fldId] => 2
      +     *       )
      +     *   )
      +     *   
      + * + *
    • + *
    + * + * The flags 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. + * + primary_key + * + unique_key + * + multiple_key + * + not_null + * + * Most DBMS's only provide the table and flags + * elements if $result is a table name. The following DBMS's + * provide full information from queries: + * + fbsql + * + mysql + * + * If the 'portability' option has MDB2_PORTABILITY_FIX_CASE + * turned on, the names of tables and fields will be lower or upper cased. + * + * @param object|string $result MDB2_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: + * MDB2_TABLEINFO_ORDERTABLE, + * MDB2_TABLEINFO_ORDER or + * MDB2_TABLEINFO_FULL (which does both). + * These are bitwise, so the first two can be + * combined using |. + * + * @return array an associative array with the information requested. + * A MDB2_Error object on failure. + * + * @see MDB2_Driver_Common::setOption() + */ + function tableInfo($result, $mode = null) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + if (!is_string($result)) { + return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'method not implemented', __FUNCTION__); + } + + $db->loadModule('Manager', null, true); + $fields = $db->manager->listTableFields($result); + if (PEAR::isError($fields)) { + return $fields; + } + + $flags = array(); + + $idxname_format = $db->getOption('idxname_format'); + $db->setOption('idxname_format', '%s'); + + $indexes = $db->manager->listTableIndexes($result); + if (PEAR::isError($indexes)) { + $db->setOption('idxname_format', $idxname_format); + return $indexes; + } + + foreach ($indexes as $index) { + $definition = $this->getTableIndexDefinition($result, $index); + if (PEAR::isError($definition)) { + $db->setOption('idxname_format', $idxname_format); + return $definition; + } + if (count($definition['fields']) > 1) { + foreach ($definition['fields'] as $field => $sort) { + $flags[$field] = 'multiple_key'; + } + } + } + + $constraints = $db->manager->listTableConstraints($result); + if (PEAR::isError($constraints)) { + return $constraints; + } + + foreach ($constraints as $constraint) { + $definition = $this->getTableConstraintDefinition($result, $constraint); + if (PEAR::isError($definition)) { + $db->setOption('idxname_format', $idxname_format); + return $definition; + } + $flag = !empty($definition['primary']) + ? 'primary_key' : (!empty($definition['unique']) + ? 'unique_key' : false); + if ($flag) { + foreach ($definition['fields'] as $field => $sort) { + if (empty($flags[$field]) || $flags[$field] != 'primary_key') { + $flags[$field] = $flag; + } + } + } + } + + $res = array(); + + if ($mode) { + $res['num_fields'] = count($fields); + } + + foreach ($fields as $i => $field) { + $definition = $this->getTableFieldDefinition($result, $field); + if (PEAR::isError($definition)) { + $db->setOption('idxname_format', $idxname_format); + return $definition; + } + $res[$i] = $definition[0]; + $res[$i]['name'] = $field; + $res[$i]['table'] = $result; + $res[$i]['type'] = preg_replace('/^([a-z]+).*$/i', '\\1', trim($definition[0]['nativetype'])); + // 'primary_key', 'unique_key', 'multiple_key' + $res[$i]['flags'] = empty($flags[$field]) ? '' : $flags[$field]; + // not_null', 'unsigned', 'auto_increment', 'default_[rawencodedvalue]' + if (!empty($res[$i]['notnull'])) { + $res[$i]['flags'].= ' not_null'; + } + if (!empty($res[$i]['unsigned'])) { + $res[$i]['flags'].= ' unsigned'; + } + if (!empty($res[$i]['auto_increment'])) { + $res[$i]['flags'].= ' autoincrement'; + } + if (!empty($res[$i]['default'])) { + $res[$i]['flags'].= ' default_'.rawurlencode($res[$i]['default']); + } + + if ($mode & MDB2_TABLEINFO_ORDER) { + $res['order'][$res[$i]['name']] = $i; + } + if ($mode & MDB2_TABLEINFO_ORDERTABLE) { + $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i; + } + } + + $db->setOption('idxname_format', $idxname_format); + return $res; + } +} +?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/MDB2/Extended.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/MDB2/Extended.php --- php-mdb2-2.4.1/MDB2-2.5.0b2/MDB2/Extended.php 1970-01-01 01:00:00.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/MDB2/Extended.php 2009-01-14 16:28:08.000000000 +0000 @@ -0,0 +1,721 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: Extended.php,v 1.60 2007/11/28 19:49:34 quipo Exp $ + +/** + * @package MDB2 + * @category Database + * @author Lukas Smith + */ + +/** + * Used by autoPrepare() + */ +define('MDB2_AUTOQUERY_INSERT', 1); +define('MDB2_AUTOQUERY_UPDATE', 2); +define('MDB2_AUTOQUERY_DELETE', 3); +define('MDB2_AUTOQUERY_SELECT', 4); + +/** + * MDB2_Extended: class which adds several high level methods to MDB2 + * + * @package MDB2 + * @category Database + * @author Lukas Smith + */ +class MDB2_Extended extends MDB2_Module_Common +{ + // {{{ autoPrepare() + + /** + * Generate an insert, update or delete query and call prepare() on it + * + * @param string table + * @param array the fields names + * @param int type of query to build + * MDB2_AUTOQUERY_INSERT + * MDB2_AUTOQUERY_UPDATE + * MDB2_AUTOQUERY_DELETE + * MDB2_AUTOQUERY_SELECT + * @param string (in case of update and delete queries, this string will be put after the sql WHERE statement) + * @param array that contains the types of the placeholders + * @param mixed array that contains the types of the columns in + * the result set or MDB2_PREPARE_RESULT, if set to + * MDB2_PREPARE_MANIP the query is handled as a manipulation query + * + * @return resource handle for the query + * @see buildManipSQL + * @access public + */ + function autoPrepare($table, $table_fields, $mode = MDB2_AUTOQUERY_INSERT, + $where = false, $types = null, $result_types = MDB2_PREPARE_MANIP) + { + $query = $this->buildManipSQL($table, $table_fields, $mode, $where); + if (PEAR::isError($query)) { + return $query; + } + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + $lobs = array(); + foreach ((array)$types as $param => $type) { + if (($type == 'clob') || ($type == 'blob')) { + $lobs[$param] = $table_fields[$param]; + } + } + return $db->prepare($query, $types, $result_types, $lobs); + } + + // }}} + // {{{ autoExecute() + + /** + * Generate an insert, update or delete query and call prepare() and execute() on it + * + * @param string name of the table + * @param array assoc ($key=>$value) where $key is a field name and $value its value + * @param int type of query to build + * MDB2_AUTOQUERY_INSERT + * MDB2_AUTOQUERY_UPDATE + * MDB2_AUTOQUERY_DELETE + * MDB2_AUTOQUERY_SELECT + * @param string (in case of update and delete queries, this string will be put after the sql WHERE statement) + * @param array that contains the types of the placeholders + * @param string which specifies which result class to use + * @param mixed array that contains the types of the columns in + * the result set or MDB2_PREPARE_RESULT, if set to + * MDB2_PREPARE_MANIP the query is handled as a manipulation query + * + * @return bool|MDB2_Error true on success, a MDB2 error on failure + * @see buildManipSQL + * @see autoPrepare + * @access public + */ + function &autoExecute($table, $fields_values, $mode = MDB2_AUTOQUERY_INSERT, + $where = false, $types = null, $result_class = true, $result_types = MDB2_PREPARE_MANIP) + { + $fields_values = (array)$fields_values; + if ($mode == MDB2_AUTOQUERY_SELECT) { + if (is_array($result_types)) { + $keys = array_keys($result_types); + } elseif (!empty($fields_values)) { + $keys = $fields_values; + } else { + $keys = array(); + } + } else { + $keys = array_keys($fields_values); + } + $params = array_values($fields_values); + if (empty($params)) { + $query = $this->buildManipSQL($table, $keys, $mode, $where); + + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + if ($mode == MDB2_AUTOQUERY_SELECT) { + $result =& $db->query($query, $result_types, $result_class); + } else { + $result = $db->exec($query); + } + } else { + $stmt = $this->autoPrepare($table, $keys, $mode, $where, $types, $result_types); + if (PEAR::isError($stmt)) { + return $stmt; + } + $result =& $stmt->execute($params, $result_class); + $stmt->free(); + } + return $result; + } + + // }}} + // {{{ buildManipSQL() + + /** + * Make automaticaly an sql query for prepare() + * + * Example : buildManipSQL('table_sql', array('field1', 'field2', 'field3'), MDB2_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/DELETE query, all + * the records of the table will be updated/deleted ! + * + * @param string name of the table + * @param ordered array containing the fields names + * @param int type of query to build + * MDB2_AUTOQUERY_INSERT + * MDB2_AUTOQUERY_UPDATE + * MDB2_AUTOQUERY_DELETE + * MDB2_AUTOQUERY_SELECT + * @param string (in case of update and delete 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) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + if ($db->options['quote_identifier']) { + $table = $db->quoteIdentifier($table); + } + + if (!empty($table_fields) && $db->options['quote_identifier']) { + foreach ($table_fields as $key => $field) { + $table_fields[$key] = $db->quoteIdentifier($field); + } + } + + if ($where !== false && !is_null($where)) { + if (is_array($where)) { + $where = implode(' AND ', $where); + } + $where = ' WHERE '.$where; + } + + switch ($mode) { + case MDB2_AUTOQUERY_INSERT: + if (empty($table_fields)) { + return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, + 'Insert requires table fields', __FUNCTION__); + } + $cols = implode(', ', $table_fields); + $values = '?'.str_repeat(', ?', (count($table_fields) - 1)); + return 'INSERT INTO '.$table.' ('.$cols.') VALUES ('.$values.')'; + break; + case MDB2_AUTOQUERY_UPDATE: + if (empty($table_fields)) { + return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null, + 'Update requires table fields', __FUNCTION__); + } + $set = implode(' = ?, ', $table_fields).' = ?'; + $sql = 'UPDATE '.$table.' SET '.$set.$where; + return $sql; + break; + case MDB2_AUTOQUERY_DELETE: + $sql = 'DELETE FROM '.$table.$where; + return $sql; + break; + case MDB2_AUTOQUERY_SELECT: + $cols = !empty($table_fields) ? implode(', ', $table_fields) : '*'; + $sql = 'SELECT '.$cols.' FROM '.$table.$where; + return $sql; + break; + } + return $db->raiseError(MDB2_ERROR_SYNTAX, null, null, + 'Non existant mode', __FUNCTION__); + } + + // }}} + // {{{ limitQuery() + + /** + * Generates a limited query + * + * @param string query + * @param array that contains the types of the columns in the result set + * @param integer the numbers of rows to fetch + * @param integer the row to start to fetching + * @param string which specifies which result class to use + * @param mixed string which specifies which class to wrap results in + * + * @return MDB2_Result|MDB2_Error result set on success, a MDB2 error on failure + * @access public + */ + function &limitQuery($query, $types, $limit, $offset = 0, $result_class = true, + $result_wrap_class = false) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + $result = $db->setLimit($limit, $offset); + if (PEAR::isError($result)) { + return $result; + } + $result =& $db->query($query, $types, $result_class, $result_wrap_class); + return $result; + } + + // }}} + // {{{ execParam() + + /** + * Execute a parameterized DML statement. + * + * @param string the SQL query + * @param array if supplied, prepare/execute will be used + * with this array as execute parameters + * @param array that contains the types of the values defined in $params + * + * @return int|MDB2_Error affected rows on success, a MDB2 error on failure + * @access public + */ + function execParam($query, $params = array(), $param_types = null) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + settype($params, 'array'); + if (empty($params)) { + return $db->exec($query); + } + + $stmt = $db->prepare($query, $param_types, MDB2_PREPARE_MANIP); + if (PEAR::isError($stmt)) { + return $stmt; + } + + $result = $stmt->execute($params); + if (PEAR::isError($result)) { + return $result; + } + + $stmt->free(); + 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 the SQL query + * @param string that contains the type of the column in the result set + * @param array if supplied, prepare/execute will be used + * with this array as execute parameters + * @param array that contains the types of the values defined in $params + * @param int|string which column to return + * + * @return scalar|MDB2_Error data on success, a MDB2 error on failure + * @access public + */ + function getOne($query, $type = null, $params = array(), + $param_types = null, $colnum = 0) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + settype($params, 'array'); + settype($type, 'array'); + if (empty($params)) { + return $db->queryOne($query, $type, $colnum); + } + + $stmt = $db->prepare($query, $param_types, $type); + if (PEAR::isError($stmt)) { + return $stmt; + } + + $result = $stmt->execute($params); + if (!MDB2::isResultCommon($result)) { + return $result; + } + + $one = $result->fetchOne($colnum); + $stmt->free(); + $result->free(); + return $one; + } + + // }}} + // {{{ 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 the SQL query + * @param array that contains the types of the columns in the result set + * @param array if supplied, prepare/execute will be used + * with this array as execute parameters + * @param array that contains the types of the values defined in $params + * @param int the fetch mode to use + * + * @return array|MDB2_Error data on success, a MDB2 error on failure + * @access public + */ + function getRow($query, $types = null, $params = array(), + $param_types = null, $fetchmode = MDB2_FETCHMODE_DEFAULT) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + settype($params, 'array'); + if (empty($params)) { + return $db->queryRow($query, $types, $fetchmode); + } + + $stmt = $db->prepare($query, $param_types, $types); + if (PEAR::isError($stmt)) { + return $stmt; + } + + $result = $stmt->execute($params); + if (!MDB2::isResultCommon($result)) { + return $result; + } + + $row = $result->fetchRow($fetchmode); + $stmt->free(); + $result->free(); + return $row; + } + + // }}} + // {{{ getCol() + + /** + * Fetch a single column from a result set and return it as an + * indexed array. + * + * @param string the SQL query + * @param string that contains the type of the column in the result set + * @param array if supplied, prepare/execute will be used + * with this array as execute parameters + * @param array that contains the types of the values defined in $params + * @param int|string which column to return + * + * @return array|MDB2_Error data on success, a MDB2 error on failure + * @access public + */ + function getCol($query, $type = null, $params = array(), + $param_types = null, $colnum = 0) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + settype($params, 'array'); + settype($type, 'array'); + if (empty($params)) { + return $db->queryCol($query, $type, $colnum); + } + + $stmt = $db->prepare($query, $param_types, $type); + if (PEAR::isError($stmt)) { + return $stmt; + } + + $result = $stmt->execute($params); + if (!MDB2::isResultCommon($result)) { + return $result; + } + + $col = $result->fetchCol($colnum); + $stmt->free(); + $result->free(); + return $col; + } + + // }}} + // {{{ getAll() + + /** + * Fetch all the rows returned from a query. + * + * @param string the SQL query + * @param array that contains the types of the columns in the result set + * @param array if supplied, prepare/execute will be used + * with this array as execute parameters + * @param array that contains the types of the values defined in $params + * @param int the fetch mode to use + * @param bool if set to true, the $all will have the first + * column as its first dimension + * @param bool $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 bool $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|MDB2_Error data on success, a MDB2 error on failure + * @access public + */ + function getAll($query, $types = null, $params = array(), + $param_types = null, $fetchmode = MDB2_FETCHMODE_DEFAULT, + $rekey = false, $force_array = false, $group = false) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + settype($params, 'array'); + if (empty($params)) { + return $db->queryAll($query, $types, $fetchmode, $rekey, $force_array, $group); + } + + $stmt = $db->prepare($query, $param_types, $types); + if (PEAR::isError($stmt)) { + return $stmt; + } + + $result = $stmt->execute($params); + if (!MDB2::isResultCommon($result)) { + return $result; + } + + $all = $result->fetchAll($fetchmode, $rekey, $force_array, $group); + $stmt->free(); + $result->free(); + return $all; + } + + // }}} + // {{{ 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 MDB2 error code is + * returned on errors. If the result set contains fewer than two + * columns, a MDB2_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 mytable') returns: + *
    +     *    array(
    +     *      '1' => array('one', '944679408'),
    +     *      '2' => array('two', '944679408'),
    +     *      '3' => array('three', '944679408')
    +     *    )
    +     * 
    + * + * 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: + *
    +     * getAssoc('SELECT category,id,name FROM mytable', null, null
    +     *           MDB2_FETCHMODE_ASSOC, false, 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')
    +     *             )
    +     *    )
    +     * 
    + * + * Keep in mind that database functions in PHP usually return string + * values for results regardless of the database's internal type. + * + * @param string the SQL query + * @param array that contains the types of the columns in the result set + * @param array if supplied, prepare/execute will be used + * with this array as execute parameters + * @param array that contains the types of the values defined in $params + * @param bool $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 bool $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|MDB2_Error data on success, a MDB2 error on failure + * @access public + */ + function getAssoc($query, $types = null, $params = array(), $param_types = null, + $fetchmode = MDB2_FETCHMODE_DEFAULT, $force_array = false, $group = false) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + settype($params, 'array'); + if (empty($params)) { + return $db->queryAll($query, $types, $fetchmode, true, $force_array, $group); + } + + $stmt = $db->prepare($query, $param_types, $types); + if (PEAR::isError($stmt)) { + return $stmt; + } + + $result = $stmt->execute($params); + if (!MDB2::isResultCommon($result)) { + return $result; + } + + $all = $result->fetchAll($fetchmode, true, $force_array, $group); + $stmt->free(); + $result->free(); + return $all; + } + + // }}} + // {{{ executeMultiple() + + /** + * This function does several execute() calls on the same statement handle. + * $params 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 query handle from prepare() + * @param array numeric array containing the data to insert into the query + * + * @return bool|MDB2_Error true on success, a MDB2 error on failure + * @access public + * @see prepare(), execute() + */ + function executeMultiple(&$stmt, $params = null) + { + for ($i = 0, $j = count($params); $i < $j; $i++) { + $result = $stmt->execute($params[$i]); + if (PEAR::isError($result)) { + return $result; + } + } + return MDB2_OK; + } + + // }}} + // {{{ getBeforeID() + + /** + * Returns the next free id of a sequence if the RDBMS + * does not support auto increment + * + * @param string name of the table into which a new row was inserted + * @param string name of the field into which a new row was inserted + * @param bool when true the sequence is automatic created, if it not exists + * @param bool if the returned value should be quoted + * + * @return int|MDB2_Error id on success, a MDB2 error on failure + * @access public + */ + function getBeforeID($table, $field = null, $ondemand = true, $quote = true) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + if ($db->supports('auto_increment') !== true) { + $seq = $table.(empty($field) ? '' : '_'.$field); + $id = $db->nextID($seq, $ondemand); + if (!$quote || PEAR::isError($id)) { + return $id; + } + return $db->quote($id, 'integer'); + } elseif (!$quote) { + return null; + } + return 'NULL'; + } + + // }}} + // {{{ getAfterID() + + /** + * Returns the autoincrement ID if supported or $id + * + * @param mixed value as returned by getBeforeId() + * @param string name of the table into which a new row was inserted + * @param string name of the field into which a new row was inserted + * + * @return int|MDB2_Error id on success, a MDB2 error on failure + * @access public + */ + function getAfterID($id, $table, $field = null) + { + $db =& $this->getDBInstance(); + if (PEAR::isError($db)) { + return $db; + } + + if ($db->supports('auto_increment') !== true) { + return $id; + } + return $db->lastInsertID($table, $field); + } + + // }}} +} +?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/MDB2/Iterator.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/MDB2/Iterator.php --- php-mdb2-2.4.1/MDB2-2.5.0b2/MDB2/Iterator.php 1970-01-01 01:00:00.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/MDB2/Iterator.php 2009-01-14 16:28:08.000000000 +0000 @@ -0,0 +1,259 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: Iterator.php,v 1.22 2006/05/06 14:03:41 lsmith Exp $ + +/** + * PHP5 Iterator + * + * @package MDB2 + * @category Database + * @author Lukas Smith + */ +class MDB2_Iterator implements Iterator +{ + protected $fetchmode; + protected $result; + protected $row; + + // {{{ constructor + + /** + * Constructor + */ + public function __construct($result, $fetchmode = MDB2_FETCHMODE_DEFAULT) + { + $this->result = $result; + $this->fetchmode = $fetchmode; + } + // }}} + + // {{{ seek() + + /** + * Seek forward to a specific row in a result set + * + * @param int number of the row where the data can be found + * + * @return void + * @access public + */ + public function seek($rownum) + { + $this->row = null; + if ($this->result) { + $this->result->seek($rownum); + } + } + // }}} + + // {{{ next() + + /** + * Fetch next row of data + * + * @return void + * @access public + */ + public function next() + { + $this->row = null; + } + // }}} + + // {{{ current() + + /** + * return a row of data + * + * @return void + * @access public + */ + public function current() + { + if (is_null($this->row)) { + $row = $this->result->fetchRow($this->fetchmode); + if (PEAR::isError($row)) { + $row = false; + } + $this->row = $row; + } + return $this->row; + } + // }}} + + // {{{ valid() + + /** + * Check if the end of the result set has been reached + * + * @return bool true/false, false is also returned on failure + * @access public + */ + public function valid() + { + return (bool)$this->current(); + } + // }}} + + // {{{ free() + + /** + * Free the internal resources associated with result. + * + * @return bool|MDB2_Error true on success, false|MDB2_Error if result is invalid + * @access public + */ + public function free() + { + if ($this->result) { + return $this->result->free(); + } + $this->result = false; + $this->row = null; + return false; + } + // }}} + + // {{{ key() + + /** + * Returns the row number + * + * @return int|bool|MDB2_Error true on success, false|MDB2_Error if result is invalid + * @access public + */ + public function key() + { + if ($this->result) { + return $this->result->rowCount(); + } + return false; + } + // }}} + + // {{{ rewind() + + /** + * Seek to the first row in a result set + * + * @return void + * @access public + */ + public function rewind() + { + } + // }}} + + // {{{ destructor + + /** + * Destructor + */ + public function __destruct() + { + $this->free(); + } + // }}} +} + +/** + * PHP5 buffered Iterator + * + * @package MDB2 + * @category Database + * @author Lukas Smith + */ +class MDB2_BufferedIterator extends MDB2_Iterator implements SeekableIterator +{ + // {{{ valid() + + /** + * Check if the end of the result set has been reached + * + * @return bool|MDB2_Error true on success, false|MDB2_Error if result is invalid + * @access public + */ + public function valid() + { + if ($this->result) { + return $this->result->valid(); + } + return false; + } + // }}} + + // {{{count() + + /** + * Returns the number of rows in a result object + * + * @return int|MDB2_Error number of rows, false|MDB2_Error if result is invalid + * @access public + */ + public function count() + { + if ($this->result) { + return $this->result->numRows(); + } + return false; + } + // }}} + + // {{{ rewind() + + /** + * Seek to the first row in a result set + * + * @return void + * @access public + */ + public function rewind() + { + $this->seek(0); + } + // }}} +} + +?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/MDB2/LOB.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/MDB2/LOB.php --- php-mdb2-2.4.1/MDB2-2.5.0b2/MDB2/LOB.php 1970-01-01 01:00:00.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/MDB2/LOB.php 2009-01-14 16:28:08.000000000 +0000 @@ -0,0 +1,264 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: LOB.php,v 1.34 2006/10/25 11:52:21 lsmith Exp $ + +/** + * @package MDB2 + * @category Database + * @author Lukas Smith + */ + +require_once 'MDB2.php'; + +/** + * MDB2_LOB: user land stream wrapper implementation for LOB support + * + * @package MDB2 + * @category Database + * @author Lukas Smith + */ +class MDB2_LOB +{ + /** + * contains the key to the global MDB2 instance array of the associated + * MDB2 instance + * + * @var integer + * @access protected + */ + var $db_index; + + /** + * contains the key to the global MDB2_LOB instance array of the associated + * MDB2_LOB instance + * + * @var integer + * @access protected + */ + var $lob_index; + + // {{{ stream_open() + + /** + * open stream + * + * @param string specifies the URL that was passed to fopen() + * @param string the mode used to open the file + * @param int holds additional flags set by the streams API + * @param string not used + * + * @return bool + * @access public + */ + function stream_open($path, $mode, $options, &$opened_path) + { + if (!preg_match('/^rb?\+?$/', $mode)) { + return false; + } + $url = parse_url($path); + if (empty($url['host'])) { + return false; + } + $this->db_index = (int)$url['host']; + if (!isset($GLOBALS['_MDB2_databases'][$this->db_index])) { + return false; + } + $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; + $this->lob_index = (int)$url['user']; + if (!isset($db->datatype->lobs[$this->lob_index])) { + return false; + } + return true; + } + // }}} + + // {{{ stream_read() + + /** + * read stream + * + * @param int number of bytes to read + * + * @return string + * @access public + */ + function stream_read($count) + { + if (isset($GLOBALS['_MDB2_databases'][$this->db_index])) { + $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; + $db->datatype->_retrieveLOB($db->datatype->lobs[$this->lob_index]); + + $data = $db->datatype->_readLOB($db->datatype->lobs[$this->lob_index], $count); + $length = strlen($data); + if ($length == 0) { + $db->datatype->lobs[$this->lob_index]['endOfLOB'] = true; + } + $db->datatype->lobs[$this->lob_index]['position'] += $length; + return $data; + } + } + // }}} + + // {{{ stream_write() + + /** + * write stream, note implemented + * + * @param string data + * + * @return int + * @access public + */ + function stream_write($data) + { + return 0; + } + // }}} + + // {{{ stream_tell() + + /** + * return the current position + * + * @return int current position + * @access public + */ + function stream_tell() + { + if (isset($GLOBALS['_MDB2_databases'][$this->db_index])) { + $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; + return $db->datatype->lobs[$this->lob_index]['position']; + } + } + // }}} + + // {{{ stream_eof() + + /** + * Check if stream reaches EOF + * + * @return bool + * @access public + */ + function stream_eof() + { + if (!isset($GLOBALS['_MDB2_databases'][$this->db_index])) { + return true; + } + + $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; + $result = $db->datatype->_endOfLOB($db->datatype->lobs[$this->lob_index]); + if (version_compare(phpversion(), "5.0", ">=") + && version_compare(phpversion(), "5.1", "<") + ) { + return !$result; + } + return $result; + } + // }}} + + // {{{ stream_seek() + + /** + * Seek stream, not implemented + * + * @param int offset + * @param int whence + * + * @return bool + * @access public + */ + function stream_seek($offset, $whence) + { + return false; + } + // }}} + + // {{{ stream_stat() + + /** + * return information about stream + * + * @access public + */ + function stream_stat() + { + if (isset($GLOBALS['_MDB2_databases'][$this->db_index])) { + $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; + return array( + 'db_index' => $this->db_index, + 'lob_index' => $this->lob_index, + ); + } + } + // }}} + + // {{{ stream_close() + + /** + * close stream + * + * @access public + */ + function stream_close() + { + if (isset($GLOBALS['_MDB2_databases'][$this->db_index])) { + $db =& $GLOBALS['_MDB2_databases'][$this->db_index]; + if (isset($db->datatype->lobs[$this->lob_index])) { + $db->datatype->_destroyLOB($db->datatype->lobs[$this->lob_index]); + unset($db->datatype->lobs[$this->lob_index]); + } + } + } + // }}} +} + +// register streams wrapper +if (!stream_wrapper_register("MDB2LOB", "MDB2_LOB")) { + MDB2::raiseError(); + return false; +} + +?> diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/MDB2.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/MDB2.php --- php-mdb2-2.4.1/MDB2-2.5.0b2/MDB2.php 1970-01-01 01:00:00.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/MDB2.php 2009-01-14 16:28:09.000000000 +0000 @@ -0,0 +1,4358 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: MDB2.php,v 1.335 2008/11/29 14:57:01 afz Exp $ +// + +/** + * @package MDB2 + * @category Database + * @author Lukas Smith + */ + +require_once 'PEAR.php'; + +// {{{ Error constants + +/** + * The method mapErrorCode in each MDB2_dbtype implementation maps + * native error codes to one of these. + * + * If you add an error code here, make sure you also add a textual + * version of it in MDB2::errorMessage(). + */ + +define('MDB2_OK', true); +define('MDB2_ERROR', -1); +define('MDB2_ERROR_SYNTAX', -2); +define('MDB2_ERROR_CONSTRAINT', -3); +define('MDB2_ERROR_NOT_FOUND', -4); +define('MDB2_ERROR_ALREADY_EXISTS', -5); +define('MDB2_ERROR_UNSUPPORTED', -6); +define('MDB2_ERROR_MISMATCH', -7); +define('MDB2_ERROR_INVALID', -8); +define('MDB2_ERROR_NOT_CAPABLE', -9); +define('MDB2_ERROR_TRUNCATED', -10); +define('MDB2_ERROR_INVALID_NUMBER', -11); +define('MDB2_ERROR_INVALID_DATE', -12); +define('MDB2_ERROR_DIVZERO', -13); +define('MDB2_ERROR_NODBSELECTED', -14); +define('MDB2_ERROR_CANNOT_CREATE', -15); +define('MDB2_ERROR_CANNOT_DELETE', -16); +define('MDB2_ERROR_CANNOT_DROP', -17); +define('MDB2_ERROR_NOSUCHTABLE', -18); +define('MDB2_ERROR_NOSUCHFIELD', -19); +define('MDB2_ERROR_NEED_MORE_DATA', -20); +define('MDB2_ERROR_NOT_LOCKED', -21); +define('MDB2_ERROR_VALUE_COUNT_ON_ROW', -22); +define('MDB2_ERROR_INVALID_DSN', -23); +define('MDB2_ERROR_CONNECT_FAILED', -24); +define('MDB2_ERROR_EXTENSION_NOT_FOUND',-25); +define('MDB2_ERROR_NOSUCHDB', -26); +define('MDB2_ERROR_ACCESS_VIOLATION', -27); +define('MDB2_ERROR_CANNOT_REPLACE', -28); +define('MDB2_ERROR_CONSTRAINT_NOT_NULL',-29); +define('MDB2_ERROR_DEADLOCK', -30); +define('MDB2_ERROR_CANNOT_ALTER', -31); +define('MDB2_ERROR_MANAGER', -32); +define('MDB2_ERROR_MANAGER_PARSE', -33); +define('MDB2_ERROR_LOADMODULE', -34); +define('MDB2_ERROR_INSUFFICIENT_DATA', -35); +define('MDB2_ERROR_NO_PERMISSION', -36); +define('MDB2_ERROR_DISCONNECT_FAILED', -37); + +// }}} +// {{{ Verbose constants +/** + * These are just helper constants to more verbosely express parameters to prepare() + */ + +define('MDB2_PREPARE_MANIP', false); +define('MDB2_PREPARE_RESULT', null); + +// }}} +// {{{ Fetchmode constants + +/** + * This is a special constant that tells MDB2 the user hasn't specified + * any particular get mode, so the default should be used. + */ +define('MDB2_FETCHMODE_DEFAULT', 0); + +/** + * Column data indexed by numbers, ordered from 0 and up + */ +define('MDB2_FETCHMODE_ORDERED', 1); + +/** + * Column data indexed by column names + */ +define('MDB2_FETCHMODE_ASSOC', 2); + +/** + * Column data as object properties + */ +define('MDB2_FETCHMODE_OBJECT', 3); + +/** + * For multi-dimensional results: normally the first level of arrays + * is the row number, and the second level indexed by column number or name. + * MDB2_FETCHMODE_FLIPPED switches this order, so the first level of arrays + * is the column name, and the second level the row number. + */ +define('MDB2_FETCHMODE_FLIPPED', 4); + +// }}} +// {{{ Portability mode constants + +/** + * Portability: turn off all portability features. + * @see MDB2_Driver_Common::setOption() + */ +define('MDB2_PORTABILITY_NONE', 0); + +/** + * Portability: convert names of tables and fields to case defined in the + * "field_case" option when using the query*(), fetch*() and tableInfo() methods. + * @see MDB2_Driver_Common::setOption() + */ +define('MDB2_PORTABILITY_FIX_CASE', 1); + +/** + * Portability: right trim the data output by query*() and fetch*(). + * @see MDB2_Driver_Common::setOption() + */ +define('MDB2_PORTABILITY_RTRIM', 2); + +/** + * Portability: force reporting the number of rows deleted. + * @see MDB2_Driver_Common::setOption() + */ +define('MDB2_PORTABILITY_DELETE_COUNT', 4); + +/** + * Portability: not needed in MDB2 (just left here for compatibility to DB) + * @see MDB2_Driver_Common::setOption() + */ +define('MDB2_PORTABILITY_NUMROWS', 8); + +/** + * Portability: makes certain error messages in certain drivers compatible + * with those from other DBMS's. + * + * + mysql, mysqli: change unique/primary key constraints + * MDB2_ERROR_ALREADY_EXISTS -> MDB2_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 MDB2_ERROR_NOSUCHFIELD. + * + * @see MDB2_Driver_Common::setOption() + */ +define('MDB2_PORTABILITY_ERRORS', 16); + +/** + * Portability: convert empty values to null strings in data output by + * query*() and fetch*(). + * @see MDB2_Driver_Common::setOption() + */ +define('MDB2_PORTABILITY_EMPTY_TO_NULL', 32); + +/** + * Portability: removes database/table qualifiers from associative indexes + * @see MDB2_Driver_Common::setOption() + */ +define('MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES', 64); + +/** + * Portability: turn on all portability features. + * @see MDB2_Driver_Common::setOption() + */ +define('MDB2_PORTABILITY_ALL', 127); + +// }}} +// {{{ Globals for class instance tracking + +/** + * These are global variables that are used to track the various class instances + */ + +$GLOBALS['_MDB2_databases'] = array(); +$GLOBALS['_MDB2_dsninfo_default'] = array( + 'phptype' => false, + 'dbsyntax' => false, + 'username' => false, + 'password' => false, + 'protocol' => false, + 'hostspec' => false, + 'port' => false, + 'socket' => false, + 'database' => false, + 'mode' => false, +); + +// }}} +// {{{ class MDB2 + +/** + * The main 'MDB2' class is simply a container class with some static + * methods for creating DB objects as well as some utility functions + * common to all parts of DB. + * + * The object model of MDB2 is as follows (indentation means inheritance): + * + * MDB2 The main MDB2 class. This is simply a utility class + * with some 'static' methods for creating MDB2 objects as + * well as common utility functions for other MDB2 classes. + * + * MDB2_Driver_Common The base for each MDB2 implementation. Provides default + * | implementations (in OO lingo virtual methods) for + * | the actual DB implementations as well as a bunch of + * | query utility functions. + * | + * +-MDB2_Driver_mysql The MDB2 implementation for MySQL. Inherits MDB2_Driver_Common. + * When calling MDB2::factory or MDB2::connect for MySQL + * connections, the object returned is an instance of this + * class. + * +-MDB2_Driver_pgsql The MDB2 implementation for PostGreSQL. Inherits MDB2_Driver_Common. + * When calling MDB2::factory or MDB2::connect for PostGreSQL + * connections, the object returned is an instance of this + * class. + * + * @package MDB2 + * @category Database + * @author Lukas Smith + */ +class MDB2 +{ + // {{{ function setOptions(&$db, $options) + + /** + * set option array in an exiting database object + * + * @param MDB2_Driver_Common MDB2 object + * @param array An associative array of option names and their values. + * + * @return mixed MDB2_OK or a PEAR Error object + * + * @access public + */ + function setOptions(&$db, $options) + { + if (is_array($options)) { + foreach ($options as $option => $value) { + $test = $db->setOption($option, $value); + if (PEAR::isError($test)) { + return $test; + } + } + } + return MDB2_OK; + } + + // }}} + // {{{ function classExists($classname) + + /** + * Checks if a class exists without triggering __autoload + * + * @param string classname + * + * @return bool true success and false on error + * @static + * @access public + */ + function classExists($classname) + { + if (version_compare(phpversion(), "5.0", ">=")) { + return class_exists($classname, false); + } + return class_exists($classname); + } + + // }}} + // {{{ function loadClass($class_name, $debug) + + /** + * Loads a PEAR class. + * + * @param string classname to load + * @param bool if errors should be suppressed + * + * @return mixed true success or PEAR_Error on failure + * + * @access public + */ + function loadClass($class_name, $debug) + { + if (!MDB2::classExists($class_name)) { + $file_name = str_replace('_', DIRECTORY_SEPARATOR, $class_name).'.php'; + if ($debug) { + $include = include_once($file_name); + } else { + $include = @include_once($file_name); + } + if (!$include) { + if (!MDB2::fileExists($file_name)) { + $msg = "unable to find package '$class_name' file '$file_name'"; + } else { + $msg = "unable to load class '$class_name' from file '$file_name'"; + } + $err =& MDB2::raiseError(MDB2_ERROR_NOT_FOUND, null, null, $msg); + return $err; + } + } + return MDB2_OK; + } + + // }}} + // {{{ function &factory($dsn, $options = false) + + /** + * Create a new MDB2 object for the specified database type + * + * IMPORTANT: In order for MDB2 to work properly it is necessary that + * you make sure that you work with a reference of the original + * object instead of a copy (this is a PHP4 quirk). + * + * For example: + * $db =& MDB2::factory($dsn); + * ^^ + * And not: + * $db = MDB2::factory($dsn); + * + * @param mixed 'data source name', see the MDB2::parseDSN + * method for a description of the dsn format. + * Can also be specified as an array of the + * format returned by MDB2::parseDSN. + * @param array An associative array of option names and + * their values. + * + * @return mixed a newly created MDB2 object, or false on error + * + * @access public + */ + function &factory($dsn, $options = false) + { + $dsninfo = MDB2::parseDSN($dsn); + if (empty($dsninfo['phptype'])) { + $err =& MDB2::raiseError(MDB2_ERROR_NOT_FOUND, + null, null, 'no RDBMS driver specified'); + return $err; + } + $class_name = 'MDB2_Driver_'.$dsninfo['phptype']; + + $debug = (!empty($options['debug'])); + $err = MDB2::loadClass($class_name, $debug); + if (PEAR::isError($err)) { + return $err; + } + + $db =& new $class_name(); + $db->setDSN($dsninfo); + $err = MDB2::setOptions($db, $options); + if (PEAR::isError($err)) { + return $err; + } + + return $db; + } + + // }}} + // {{{ function &connect($dsn, $options = false) + + /** + * Create a new MDB2_Driver_* connection object and connect to the specified + * database + * + * IMPORTANT: In order for MDB2 to work properly it is necessary that + * you make sure that you work with a reference of the original + * object instead of a copy (this is a PHP4 quirk). + * + * For example: + * $db =& MDB2::connect($dsn); + * ^^ + * And not: + * $db = MDB2::connect($dsn); + * ^^ + * + * @param mixed $dsn 'data source name', see the MDB2::parseDSN + * method for a description of the dsn format. + * Can also be specified as an array of the + * format returned by MDB2::parseDSN. + * @param array $options An associative array of option names and + * their values. + * + * @return mixed a newly created MDB2 connection object, or a MDB2 + * error object on error + * + * @access public + * @see MDB2::parseDSN + */ + function &connect($dsn, $options = false) + { + $db =& MDB2::factory($dsn, $options); + if (PEAR::isError($db)) { + return $db; + } + + $err = $db->connect(); + if (PEAR::isError($err)) { + $dsn = $db->getDSN('string', 'xxx'); + $db->disconnect(); + $err->addUserInfo($dsn); + return $err; + } + + return $db; + } + + // }}} + // {{{ function &singleton($dsn = null, $options = false) + + /** + * Returns a MDB2 connection with the requested DSN. + * A new MDB2 connection object is only created if no object with the + * requested DSN exists yet. + * + * IMPORTANT: In order for MDB2 to work properly it is necessary that + * you make sure that you work with a reference of the original + * object instead of a copy (this is a PHP4 quirk). + * + * For example: + * $db =& MDB2::singleton($dsn); + * ^^ + * And not: + * $db = MDB2::singleton($dsn); + * ^^ + * + * @param mixed 'data source name', see the MDB2::parseDSN + * method for a description of the dsn format. + * Can also be specified as an array of the + * format returned by MDB2::parseDSN. + * @param array An associative array of option names and + * their values. + * + * @return mixed a newly created MDB2 connection object, or a MDB2 + * error object on error + * + * @access public + * @see MDB2::parseDSN + */ + function &singleton($dsn = null, $options = false) + { + if ($dsn) { + $dsninfo = MDB2::parseDSN($dsn); + $dsninfo = array_merge($GLOBALS['_MDB2_dsninfo_default'], $dsninfo); + $keys = array_keys($GLOBALS['_MDB2_databases']); + for ($i=0, $j=count($keys); $i<$j; ++$i) { + if (isset($GLOBALS['_MDB2_databases'][$keys[$i]])) { + $tmp_dsn = $GLOBALS['_MDB2_databases'][$keys[$i]]->getDSN('array'); + if (count(array_diff_assoc($tmp_dsn, $dsninfo)) == 0) { + MDB2::setOptions($GLOBALS['_MDB2_databases'][$keys[$i]], $options); + return $GLOBALS['_MDB2_databases'][$keys[$i]]; + } + } + } + } elseif (is_array($GLOBALS['_MDB2_databases']) && reset($GLOBALS['_MDB2_databases'])) { + $db =& $GLOBALS['_MDB2_databases'][key($GLOBALS['_MDB2_databases'])]; + return $db; + } + $db =& MDB2::factory($dsn, $options); + return $db; + } + + // }}} + // {{{ function areEquals() + + /** + * It looks like there's a memory leak in array_diff() in PHP 5.1.x, + * so use this method instead. + * @see http://pear.php.net/bugs/bug.php?id=11790 + * + * @param array $arr1 + * @param array $arr2 + * @return boolean + */ + function areEquals($arr1, $arr2) + { + if (count($arr1) != count($arr2)) { + return false; + } + foreach (array_keys($arr1) as $k) { + if (!array_key_exists($k, $arr2) || $arr1[$k] != $arr2[$k]) { + return false; + } + } + return true; + } + + // }}} + // {{{ function loadFile($file) + + /** + * load a file (like 'Date') + * + * @param string name of the file in the MDB2 directory (without '.php') + * + * @return string name of the file that was included + * + * @access public + */ + function loadFile($file) + { + $file_name = 'MDB2'.DIRECTORY_SEPARATOR.$file.'.php'; + if (!MDB2::fileExists($file_name)) { + return MDB2::raiseError(MDB2_ERROR_NOT_FOUND, null, null, + 'unable to find: '.$file_name); + } + if (!include_once($file_name)) { + return MDB2::raiseError(MDB2_ERROR_NOT_FOUND, null, null, + 'unable to load driver class: '.$file_name); + } + return $file_name; + } + + // }}} + // {{{ function apiVersion() + + /** + * Return the MDB2 API version + * + * @return string the MDB2 API version number + * + * @access public + */ + function apiVersion() + { + return '2.5.0b2'; + } + + // }}} + // {{{ function &raiseError($code = null, $mode = null, $options = null, $userinfo = null) + + /** + * This method is used to communicate an error and invoke error + * callbacks etc. Basically a wrapper for PEAR::raiseError + * without the message string. + * + * @param mixed int error code + * + * @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. + * + * @return PEAR_Error instance of a PEAR Error object + * + * @access private + * @see PEAR_Error + */ + function &raiseError($code = null, + $mode = null, + $options = null, + $userinfo = null, + $dummy1 = null, + $dummy2 = null, + $dummy3 = false) + { + $err =& PEAR::raiseError(null, $code, $mode, $options, $userinfo, 'MDB2_Error', true); + return $err; + } + + // }}} + // {{{ function isError($data, $code = null) + + /** + * Tell whether a value is a MDB2 error. + * + * @param mixed the value to test + * @param int if is an error object, return true + * only if $code is a string and + * $db->getMessage() == $code or + * $code is an integer and $db->getCode() == $code + * + * @return bool true if parameter is an error + * + * @access public + */ + function isError($data, $code = null) + { + if (is_a($data, 'MDB2_Error')) { + if (is_null($code)) { + return true; + } elseif (is_string($code)) { + return $data->getMessage() === $code; + } else { + $code = (array)$code; + return in_array($data->getCode(), $code); + } + } + return false; + } + + // }}} + // {{{ function isConnection($value) + + /** + * Tell whether a value is a MDB2 connection + * + * @param mixed value to test + * + * @return bool whether $value is a MDB2 connection + * + * @access public + */ + function isConnection($value) + { + return is_a($value, 'MDB2_Driver_Common'); + } + + // }}} + // {{{ function isResult($value) + + /** + * Tell whether a value is a MDB2 result + * + * @param mixed value to test + * + * @return bool whether $value is a MDB2 result + * + * @access public + */ + function isResult($value) + { + return is_a($value, 'MDB2_Result'); + } + + // }}} + // {{{ function isResultCommon($value) + + /** + * Tell whether a value is a MDB2 result implementing the common interface + * + * @param mixed value to test + * + * @return bool whether $value is a MDB2 result implementing the common interface + * + * @access public + */ + function isResultCommon($value) + { + return is_a($value, 'MDB2_Result_Common'); + } + + // }}} + // {{{ function isStatement($value) + + /** + * Tell whether a value is a MDB2 statement interface + * + * @param mixed value to test + * + * @return bool whether $value is a MDB2 statement interface + * + * @access public + */ + function isStatement($value) + { + return is_a($value, 'MDB2_Statement_Common'); + } + + // }}} + // {{{ function errorMessage($value = null) + + /** + * Return a textual error message for a MDB2 error code + * + * @param int|array integer error code, + null to get the current error code-message map, + or an array with a new error code-message map + * + * @return string error message, or false if the error code was + * not recognized + * + * @access public + */ + function errorMessage($value = null) + { + static $errorMessages; + + if (is_array($value)) { + $errorMessages = $value; + return MDB2_OK; + } + + if (!isset($errorMessages)) { + $errorMessages = array( + MDB2_OK => 'no error', + MDB2_ERROR => 'unknown error', + MDB2_ERROR_ALREADY_EXISTS => 'already exists', + MDB2_ERROR_CANNOT_CREATE => 'can not create', + MDB2_ERROR_CANNOT_ALTER => 'can not alter', + MDB2_ERROR_CANNOT_REPLACE => 'can not replace', + MDB2_ERROR_CANNOT_DELETE => 'can not delete', + MDB2_ERROR_CANNOT_DROP => 'can not drop', + MDB2_ERROR_CONSTRAINT => 'constraint violation', + MDB2_ERROR_CONSTRAINT_NOT_NULL=> 'null value violates not-null constraint', + MDB2_ERROR_DIVZERO => 'division by zero', + MDB2_ERROR_INVALID => 'invalid', + MDB2_ERROR_INVALID_DATE => 'invalid date or time', + MDB2_ERROR_INVALID_NUMBER => 'invalid number', + MDB2_ERROR_MISMATCH => 'mismatch', + MDB2_ERROR_NODBSELECTED => 'no database selected', + MDB2_ERROR_NOSUCHFIELD => 'no such field', + MDB2_ERROR_NOSUCHTABLE => 'no such table', + MDB2_ERROR_NOT_CAPABLE => 'MDB2 backend not capable', + MDB2_ERROR_NOT_FOUND => 'not found', + MDB2_ERROR_NOT_LOCKED => 'not locked', + MDB2_ERROR_SYNTAX => 'syntax error', + MDB2_ERROR_UNSUPPORTED => 'not supported', + MDB2_ERROR_VALUE_COUNT_ON_ROW => 'value count on row', + MDB2_ERROR_INVALID_DSN => 'invalid DSN', + MDB2_ERROR_CONNECT_FAILED => 'connect failed', + MDB2_ERROR_NEED_MORE_DATA => 'insufficient data supplied', + MDB2_ERROR_EXTENSION_NOT_FOUND=> 'extension not found', + MDB2_ERROR_NOSUCHDB => 'no such database', + MDB2_ERROR_ACCESS_VIOLATION => 'insufficient permissions', + MDB2_ERROR_LOADMODULE => 'error while including on demand module', + MDB2_ERROR_TRUNCATED => 'truncated', + MDB2_ERROR_DEADLOCK => 'deadlock detected', + MDB2_ERROR_NO_PERMISSION => 'no permission', + MDB2_ERROR_DISCONNECT_FAILED => 'disconnect failed', + ); + } + + if (is_null($value)) { + return $errorMessages; + } + + if (PEAR::isError($value)) { + $value = $value->getCode(); + } + + return isset($errorMessages[$value]) ? + $errorMessages[$value] : $errorMessages[MDB2_ERROR]; + } + + // }}} + // {{{ function parseDSN($dsn) + + /** + * Parse a data source name. + * + * Additional keys can be added by appending a URI query string to the + * end of the DSN. + * + * The format of the supplied DSN is in its fullest form: + * + * phptype(dbsyntax)://username:password@protocol+hostspec/database?option=8&another=true + * + * + * Most variations are allowed: + * + * phptype://username:password@protocol+hostspec:110//usr/db_file.db?mode=0644 + * phptype://username:password@hostspec/database_name + * phptype://username:password@hostspec + * phptype://username@hostspec + * phptype://hostspec/database + * phptype://hostspec + * phptype(dbsyntax) + * phptype + * + * + * @param string 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 + * + * @access public + * @author Tomas V.V.Cox + */ + function parseDSN($dsn) + { + $parsed = $GLOBALS['_MDB2_dsninfo_default']; + + if (is_array($dsn)) { + $dsn = array_merge($parsed, $dsn); + if (!$dsn['dbsyntax']) { + $dsn['dbsyntax'] = $dsn['phptype']; + } + return $dsn; + } + + // Find phptype and dbsyntax + if (($pos = strpos($dsn, '://')) !== false) { + $str = substr($dsn, 0, $pos); + $dsn = substr($dsn, $pos + 3); + } else { + $str = $dsn; + $dsn = null; + } + + // Get phptype and dbsyntax + // $str => phptype(dbsyntax) + if (preg_match('|^(.+?)\((.*?)\)$|', $str, $arr)) { + $parsed['phptype'] = $arr[1]; + $parsed['dbsyntax'] = !$arr[2] ? $arr[1] : $arr[2]; + } else { + $parsed['phptype'] = $str; + $parsed['dbsyntax'] = $str; + } + + if (!count($dsn)) { + return $parsed; + } + + // Get (if found): username and password + // $dsn => username:password@protocol+hostspec/database + if (($at = strrpos($dsn,'@')) !== false) { + $str = substr($dsn, 0, $at); + $dsn = substr($dsn, $at + 1); + if (($pos = strpos($str, ':')) !== false) { + $parsed['username'] = rawurldecode(substr($str, 0, $pos)); + $parsed['password'] = rawurldecode(substr($str, $pos + 1)); + } else { + $parsed['username'] = rawurldecode($str); + } + } + + // Find protocol and hostspec + + // $dsn => proto(proto_opts)/database + if (preg_match('|^([^(]+)\((.*?)\)/?(.*?)$|', $dsn, $match)) { + $proto = $match[1]; + $proto_opts = $match[2] ? $match[2] : false; + $dsn = $match[3]; + + // $dsn => protocol+hostspec/database (old format) + } else { + if (strpos($dsn, '+') !== false) { + list($proto, $dsn) = explode('+', $dsn, 2); + } + if ( strpos($dsn, '//') === 0 + && strpos($dsn, '/', 2) !== false + && $parsed['phptype'] == 'oci8' + ) { + //oracle's "Easy Connect" syntax: + //"username/password@[//]host[:port][/service_name]" + //e.g. "scott/tiger@//mymachine:1521/oracle" + $proto_opts = $dsn; + $dsn = substr($proto_opts, strrpos($proto_opts, '/') + 1); + } elseif (strpos($dsn, '/') !== false) { + list($proto_opts, $dsn) = explode('/', $dsn, 2); + } else { + $proto_opts = $dsn; + $dsn = null; + } + } + + // process the different protocol options + $parsed['protocol'] = (!empty($proto)) ? $proto : 'tcp'; + $proto_opts = rawurldecode($proto_opts); + if (strpos($proto_opts, ':') !== false) { + list($proto_opts, $parsed['port']) = explode(':', $proto_opts); + } + if ($parsed['protocol'] == 'tcp') { + $parsed['hostspec'] = $proto_opts; + } elseif ($parsed['protocol'] == 'unix') { + $parsed['socket'] = $proto_opts; + } + + // Get dabase if any + // $dsn => database + if ($dsn) { + // /database + if (($pos = strpos($dsn, '?')) === false) { + $parsed['database'] = $dsn; + // /database?param1=value1¶m2=value2 + } else { + $parsed['database'] = substr($dsn, 0, $pos); + $dsn = substr($dsn, $pos + 1); + if (strpos($dsn, '&') !== false) { + $opts = explode('&', $dsn); + } else { // database?param1=value1 + $opts = array($dsn); + } + foreach ($opts as $opt) { + list($key, $value) = explode('=', $opt); + if (!isset($parsed[$key])) { + // don't allow params overwrite + $parsed[$key] = rawurldecode($value); + } + } + } + } + + return $parsed; + } + + // }}} + // {{{ function fileExists($file) + + /** + * Checks if a file exists in the include path + * + * @param string filename + * + * @return bool true success and false on error + * + * @access public + */ + function fileExists($file) + { + // safe_mode does notwork with is_readable() + if (!@ini_get('safe_mode')) { + $dirs = explode(PATH_SEPARATOR, ini_get('include_path')); + foreach ($dirs as $dir) { + if (is_readable($dir . DIRECTORY_SEPARATOR . $file)) { + return true; + } + } + } else { + $fp = @fopen($file, 'r', true); + if (is_resource($fp)) { + @fclose($fp); + return true; + } + } + return false; + } + // }}} +} + +// }}} +// {{{ class MDB2_Error extends PEAR_Error + +/** + * MDB2_Error implements a class for reporting portable database error + * messages. + * + * @package MDB2 + * @category Database + * @author Stig Bakken + */ +class MDB2_Error extends PEAR_Error +{ + // {{{ constructor: function MDB2_Error($code = MDB2_ERROR, $mode = PEAR_ERROR_RETURN, $level = E_USER_NOTICE, $debuginfo = null) + + /** + * MDB2_Error constructor. + * + * @param mixed MDB2 error code, or string with error message. + * @param int what 'error mode' to operate in + * @param int what error level to use for $mode & PEAR_ERROR_TRIGGER + * @param mixed additional debug info, such as the last query + */ + function MDB2_Error($code = MDB2_ERROR, $mode = PEAR_ERROR_RETURN, + $level = E_USER_NOTICE, $debuginfo = null, $dummy = null) + { + if (is_null($code)) { + $code = MDB2_ERROR; + } + $this->PEAR_Error('MDB2 Error: '.MDB2::errorMessage($code), $code, + $mode, $level, $debuginfo); + } + + // }}} +} + +// }}} +// {{{ class MDB2_Driver_Common extends PEAR + +/** + * MDB2_Driver_Common: Base class that is extended by each MDB2 driver + * + * @package MDB2 + * @category Database + * @author Lukas Smith + */ +class MDB2_Driver_Common extends PEAR +{ + // {{{ Variables (Properties) + + /** + * index of the MDB2 object within the $GLOBALS['_MDB2_databases'] array + * @var int + * @access public + */ + var $db_index = 0; + + /** + * DSN used for the next query + * @var array + * @access protected + */ + var $dsn = array(); + + /** + * DSN that was used to create the current connection + * @var array + * @access protected + */ + var $connected_dsn = array(); + + /** + * connection resource + * @var mixed + * @access protected + */ + var $connection = 0; + + /** + * if the current opened connection is a persistent connection + * @var bool + * @access protected + */ + var $opened_persistent; + + /** + * the name of the database for the next query + * @var string + * @access protected + */ + var $database_name = ''; + + /** + * the name of the database currently selected + * @var string + * @access protected + */ + var $connected_database_name = ''; + + /** + * server version information + * @var string + * @access protected + */ + var $connected_server_info = ''; + + /** + * list of all supported features of the given driver + * @var array + * @access public + */ + var $supported = array( + 'sequences' => false, + 'indexes' => false, + 'affected_rows' => false, + 'summary_functions' => false, + 'order_by_text' => false, + 'transactions' => false, + 'savepoints' => false, + 'current_id' => false, + 'limit_queries' => false, + 'LOBs' => false, + 'replace' => false, + 'sub_selects' => false, + 'triggers' => false, + 'auto_increment' => false, + 'primary_key' => false, + 'result_introspection' => false, + 'prepared_statements' => false, + 'identifier_quoting' => false, + 'pattern_escaping' => false, + 'new_link' => false, + ); + + /** + * Array of supported options that can be passed to the MDB2 instance. + * + * The options can be set during object creation, using + * MDB2::connect(), MDB2::factory() or MDB2::singleton(). The options can + * also be set after the object is created, using MDB2::setOptions() or + * MDB2_Driver_Common::setOption(). + * The list of available option includes: + *
      + *
    • $options['ssl'] -> boolean: determines if ssl should be used for connections
    • + *
    • $options['field_case'] -> CASE_LOWER|CASE_UPPER: determines what case to force on field/table names
    • + *
    • $options['disable_query'] -> boolean: determines if queries should be executed
    • + *
    • $options['result_class'] -> string: class used for result sets
    • + *
    • $options['buffered_result_class'] -> string: class used for buffered result sets
    • + *
    • $options['result_wrap_class'] -> string: class used to wrap result sets into
    • + *
    • $options['result_buffering'] -> boolean should results be buffered or not?
    • + *
    • $options['fetch_class'] -> string: class to use when fetch mode object is used
    • + *
    • $options['persistent'] -> boolean: persistent connection?
    • + *
    • $options['debug'] -> integer: numeric debug level
    • + *
    • $options['debug_handler'] -> string: function/method that captures debug messages
    • + *
    • $options['debug_expanded_output'] -> bool: BC option to determine if more context information should be send to the debug handler
    • + *
    • $options['default_text_field_length'] -> integer: default text field length to use
    • + *
    • $options['lob_buffer_length'] -> integer: LOB buffer length
    • + *
    • $options['log_line_break'] -> string: line-break format
    • + *
    • $options['idxname_format'] -> string: pattern for index name
    • + *
    • $options['seqname_format'] -> string: pattern for sequence name
    • + *
    • $options['savepoint_format'] -> string: pattern for auto generated savepoint names
    • + *
    • $options['statement_format'] -> string: pattern for prepared statement names
    • + *
    • $options['seqcol_name'] -> string: sequence column name
    • + *
    • $options['quote_identifier'] -> boolean: if identifier quoting should be done when check_option is used
    • + *
    • $options['use_transactions'] -> boolean: if transaction use should be enabled
    • + *
    • $options['decimal_places'] -> integer: number of decimal places to handle
    • + *
    • $options['portability'] -> integer: portability constant
    • + *
    • $options['modules'] -> array: short to long module name mapping for __call()
    • + *
    • $options['emulate_prepared'] -> boolean: force prepared statements to be emulated
    • + *
    • $options['datatype_map'] -> array: map user defined datatypes to other primitive datatypes
    • + *
    • $options['datatype_map_callback'] -> array: callback function/method that should be called
    • + *
    • $options['bindname_format'] -> string: regular expression pattern for named parameters
    • + *
    • $options['multi_query'] -> boolean: determines if queries returning multiple result sets should be executed
    • + *
    • $options['max_identifiers_length'] -> integer: max identifier length
    • + *
    • $options['default_fk_action_onupdate'] -> string: default FOREIGN KEY ON UPDATE action ['RESTRICT'|'NO ACTION'|'SET DEFAULT'|'SET NULL'|'CASCADE']
    • + *
    • $options['default_fk_action_ondelete'] -> string: default FOREIGN KEY ON DELETE action ['RESTRICT'|'NO ACTION'|'SET DEFAULT'|'SET NULL'|'CASCADE']
    • + *
    + * + * @var array + * @access public + * @see MDB2::connect() + * @see MDB2::factory() + * @see MDB2::singleton() + * @see MDB2_Driver_Common::setOption() + */ + var $options = array( + 'ssl' => false, + 'field_case' => CASE_LOWER, + 'disable_query' => false, + 'result_class' => 'MDB2_Result_%s', + 'buffered_result_class' => 'MDB2_BufferedResult_%s', + 'result_wrap_class' => false, + 'result_buffering' => true, + 'fetch_class' => 'stdClass', + 'persistent' => false, + 'debug' => 0, + 'debug_handler' => 'MDB2_defaultDebugOutput', + 'debug_expanded_output' => false, + 'default_text_field_length' => 4096, + 'lob_buffer_length' => 8192, + 'log_line_break' => "\n", + 'idxname_format' => '%s_idx', + 'seqname_format' => '%s_seq', + 'savepoint_format' => 'MDB2_SAVEPOINT_%s', + 'statement_format' => 'MDB2_STATEMENT_%1$s_%2$s', + 'seqcol_name' => 'sequence', + 'quote_identifier' => false, + 'use_transactions' => true, + 'decimal_places' => 2, + 'portability' => MDB2_PORTABILITY_ALL, + 'modules' => array( + 'ex' => 'Extended', + 'dt' => 'Datatype', + 'mg' => 'Manager', + 'rv' => 'Reverse', + 'na' => 'Native', + 'fc' => 'Function', + ), + 'emulate_prepared' => false, + 'datatype_map' => array(), + 'datatype_map_callback' => array(), + 'nativetype_map_callback' => array(), + 'lob_allow_url_include' => false, + 'bindname_format' => '(?:\d+)|(?:[a-zA-Z][a-zA-Z0-9_]*)', + 'max_identifiers_length' => 30, + 'default_fk_action_onupdate' => 'RESTRICT', + 'default_fk_action_ondelete' => 'RESTRICT', + ); + + /** + * string array + * @var string + * @access protected + */ + var $string_quoting = array('start' => "'", 'end' => "'", 'escape' => false, 'escape_pattern' => false); + + /** + * identifier quoting + * @var array + * @access protected + */ + var $identifier_quoting = array('start' => '"', 'end' => '"', 'escape' => '"'); + + /** + * sql comments + * @var array + * @access protected + */ + var $sql_comments = array( + array('start' => '--', 'end' => "\n", 'escape' => false), + array('start' => '/*', 'end' => '*/', 'escape' => false), + ); + + /** + * comparision wildcards + * @var array + * @access protected + */ + var $wildcards = array('%', '_'); + + /** + * column alias keyword + * @var string + * @access protected + */ + var $as_keyword = ' AS '; + + /** + * warnings + * @var array + * @access protected + */ + var $warnings = array(); + + /** + * string with the debugging information + * @var string + * @access public + */ + var $debug_output = ''; + + /** + * determine if there is an open transaction + * @var bool + * @access protected + */ + var $in_transaction = false; + + /** + * the smart transaction nesting depth + * @var int + * @access protected + */ + var $nested_transaction_counter = null; + + /** + * the first error that occured inside a nested transaction + * @var MDB2_Error|bool + * @access protected + */ + var $has_transaction_error = false; + + /** + * result offset used in the next query + * @var int + * @access protected + */ + var $offset = 0; + + /** + * result limit used in the next query + * @var int + * @access protected + */ + var $limit = 0; + + /** + * Database backend used in PHP (mysql, odbc etc.) + * @var string + * @access public + */ + var $phptype; + + /** + * Database used with regards to SQL syntax etc. + * @var string + * @access public + */ + var $dbsyntax; + + /** + * the last query sent to the driver + * @var string + * @access public + */ + var $last_query; + + /** + * the default fetchmode used + * @var int + * @access protected + */ + var $fetchmode = MDB2_FETCHMODE_ORDERED; + + /** + * array of module instances + * @var array + * @access protected + */ + var $modules = array(); + + /** + * determines of the PHP4 destructor emulation has been enabled yet + * @var array + * @access protected + */ + var $destructor_registered = true; + + // }}} + // {{{ constructor: function __construct() + + /** + * Constructor + */ + function __construct() + { + end($GLOBALS['_MDB2_databases']); + $db_index = key($GLOBALS['_MDB2_databases']) + 1; + $GLOBALS['_MDB2_databases'][$db_index] = &$this; + $this->db_index = $db_index; + } + + // }}} + // {{{ function MDB2_Driver_Common() + + /** + * PHP 4 Constructor + */ + function MDB2_Driver_Common() + { + $this->destructor_registered = false; + $this->__construct(); + } + + // }}} + // {{{ destructor: function __destruct() + + /** + * Destructor + */ + function __destruct() + { + $this->disconnect(false); + } + + // }}} + // {{{ function free() + + /** + * Free the internal references so that the instance can be destroyed + * + * @return bool true on success, false if result is invalid + * + * @access public + */ + function free() + { + unset($GLOBALS['_MDB2_databases'][$this->db_index]); + unset($this->db_index); + return MDB2_OK; + } + + // }}} + // {{{ function __toString() + + /** + * String conversation + * + * @return string representation of the object + * + * @access public + */ + function __toString() + { + $info = get_class($this); + $info.= ': (phptype = '.$this->phptype.', dbsyntax = '.$this->dbsyntax.')'; + if ($this->connection) { + $info.= ' [connected]'; + } + return $info; + } + + // }}} + // {{{ function errorInfo($error = null) + + /** + * This method is used to collect information about an error + * + * @param mixed error code or resource + * + * @return array with MDB2 errorcode, native error code, native message + * + * @access public + */ + function errorInfo($error = null) + { + return array($error, null, null); + } + + // }}} + // {{{ function &raiseError($code = null, $mode = null, $options = null, $userinfo = null) + + /** + * This method is used to communicate an error and invoke error + * callbacks etc. Basically a wrapper for PEAR::raiseError + * without the message string. + * + * @param mixed $code integer error code, or a PEAR error object (all + * other parameters are ignored if this parameter is + * an object + * @param int $mode error mode, see PEAR_Error docs + * @param mixed $options 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 $userinfo Extra debug information. Defaults to the last + * query and native error code. + * @param string $method name of the method that triggered the error + * @param string $dummy1 not used + * @param bool $dummy2 not used + * + * @return PEAR_Error instance of a PEAR Error object + * @access public + * @see PEAR_Error + */ + function &raiseError($code = null, + $mode = null, + $options = null, + $userinfo = null, + $method = null, + $dummy1 = null, + $dummy2 = false + ) { + $userinfo = "[Error message: $userinfo]\n"; + // The error is yet a MDB2 error object + if (PEAR::isError($code)) { + // because we use the static PEAR::raiseError, our global + // handler should be used if it is set + if (is_null($mode) && !empty($this->_default_error_mode)) { + $mode = $this->_default_error_mode; + $options = $this->_default_error_options; + } + if (is_null($userinfo)) { + $userinfo = $code->getUserinfo(); + } + $code = $code->getCode(); + } elseif ($code == MDB2_ERROR_NOT_FOUND) { + // extension not loaded: don't call $this->errorInfo() or the script + // will die + } elseif (isset($this->connection)) { + if (!empty($this->last_query)) { + $userinfo.= "[Last executed query: {$this->last_query}]\n"; + } + $native_errno = $native_msg = null; + list($code, $native_errno, $native_msg) = $this->errorInfo($code); + if (!is_null($native_errno) && $native_errno !== '') { + $userinfo.= "[Native code: $native_errno]\n"; + } + if (!is_null($native_msg) && $native_msg !== '') { + $userinfo.= "[Native message: ". strip_tags($native_msg) ."]\n"; + } + if (!is_null($method)) { + $userinfo = $method.': '.$userinfo; + } + } + + $err =& PEAR::raiseError(null, $code, $mode, $options, $userinfo, 'MDB2_Error', true); + if ($err->getMode() !== PEAR_ERROR_RETURN + && isset($this->nested_transaction_counter) && !$this->has_transaction_error) { + $this->has_transaction_error =& $err; + } + return $err; + } + + // }}} + // {{{ function resetWarnings() + + /** + * reset the warning array + * + * @return void + * + * @access public + */ + function resetWarnings() + { + $this->warnings = array(); + } + + // }}} + // {{{ function getWarnings() + + /** + * Get all warnings in reverse order. + * This means that the last warning is the first element in the array + * + * @return array with warnings + * + * @access public + * @see resetWarnings() + */ + function getWarnings() + { + return array_reverse($this->warnings); + } + + // }}} + // {{{ function setFetchMode($fetchmode, $object_class = 'stdClass') + + /** + * Sets which fetch mode should be used by default on queries + * on this connection + * + * @param int MDB2_FETCHMODE_ORDERED, MDB2_FETCHMODE_ASSOC + * or MDB2_FETCHMODE_OBJECT + * @param string the class name of the object to be returned + * by the fetch methods when the + * MDB2_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 possibility to use + * and extend the 'MDB2_row' class. + * + * @return mixed MDB2_OK or MDB2 Error Object + * + * @access public + * @see MDB2_FETCHMODE_ORDERED, MDB2_FETCHMODE_ASSOC, MDB2_FETCHMODE_OBJECT + */ + function setFetchMode($fetchmode, $object_class = 'stdClass') + { + switch ($fetchmode) { + case MDB2_FETCHMODE_OBJECT: + $this->options['fetch_class'] = $object_class; + case MDB2_FETCHMODE_ORDERED: + case MDB2_FETCHMODE_ASSOC: + $this->fetchmode = $fetchmode; + break; + default: + return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'invalid fetchmode mode', __FUNCTION__); + } + + return MDB2_OK; + } + + // }}} + // {{{ function setOption($option, $value) + + /** + * set the option for the db class + * + * @param string option name + * @param mixed value for the option + * + * @return mixed MDB2_OK or MDB2 Error Object + * + * @access public + */ + function setOption($option, $value) + { + if (array_key_exists($option, $this->options)) { + $this->options[$option] = $value; + return MDB2_OK; + } + return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + "unknown option $option", __FUNCTION__); + } + + // }}} + // {{{ function getOption($option) + + /** + * Returns the value of an option + * + * @param string option name + * + * @return mixed the option value or error object + * + * @access public + */ + function getOption($option) + { + if (array_key_exists($option, $this->options)) { + return $this->options[$option]; + } + return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + "unknown option $option", __FUNCTION__); + } + + // }}} + // {{{ function debug($message, $scope = '', $is_manip = null) + + /** + * set a debug message + * + * @param string message that should be appended to the debug variable + * @param string usually the method name that triggered the debug call: + * for example 'query', 'prepare', 'execute', 'parameters', + * 'beginTransaction', 'commit', 'rollback' + * @param array contains context information about the debug() call + * common keys are: is_manip, time, result etc. + * + * @return void + * + * @access public + */ + function debug($message, $scope = '', $context = array()) + { + if ($this->options['debug'] && $this->options['debug_handler']) { + if (!$this->options['debug_expanded_output']) { + if (!empty($context['when']) && $context['when'] !== 'pre') { + return null; + } + $context = empty($context['is_manip']) ? false : $context['is_manip']; + } + return call_user_func_array($this->options['debug_handler'], array(&$this, $scope, $message, $context)); + } + return null; + } + + // }}} + // {{{ function getDebugOutput() + + /** + * output debug info + * + * @return string content of the debug_output class variable + * + * @access public + */ + function getDebugOutput() + { + return $this->debug_output; + } + + // }}} + // {{{ function escape($text) + + /** + * Quotes a string so it can be safely used in a query. It will quote + * the text so it can safely be used within a query. + * + * @param string the input string to quote + * @param bool escape wildcards + * + * @return string quoted string + * + * @access public + */ + function escape($text, $escape_wildcards = false) + { + if ($escape_wildcards) { + $text = $this->escapePattern($text); + } + + $text = str_replace($this->string_quoting['end'], $this->string_quoting['escape'] . $this->string_quoting['end'], $text); + return $text; + } + + // }}} + // {{{ function escapePattern($text) + + /** + * Quotes pattern (% and _) characters in a string) + * + * @param string the input string to quote + * + * @return string quoted string + * + * @access public + */ + function escapePattern($text) + { + if ($this->string_quoting['escape_pattern']) { + $text = str_replace($this->string_quoting['escape_pattern'], $this->string_quoting['escape_pattern'] . $this->string_quoting['escape_pattern'], $text); + foreach ($this->wildcards as $wildcard) { + $text = str_replace($wildcard, $this->string_quoting['escape_pattern'] . $wildcard, $text); + } + } + return $text; + } + + // }}} + // {{{ function quoteIdentifier($str, $check_option = false) + + /** + * 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. + * + * NOTE: if you have table names containing periods, don't use this method + * (@see bug #11906) + * + * Portability is broken by using the following characters inside + * delimited identifiers: + * + backtick (`) -- due to MySQL + * + double quote (") -- due to Oracle + * + brackets ([ or ]) -- due to Access + * + * Delimited identifiers are known to generally work correctly under + * the following drivers: + * + mssql + * + mysql + * + mysqli + * + oci8 + * + pgsql + * + sqlite + * + * InterBase doesn't seem to be able to use delimited identifiers + * via PHP 4. They work fine under PHP 5. + * + * @param string identifier name to be quoted + * @param bool check the 'quote_identifier' option + * + * @return string quoted identifier string + * + * @access public + */ + function quoteIdentifier($str, $check_option = false) + { + if ($check_option && !$this->options['quote_identifier']) { + return $str; + } + $str = str_replace($this->identifier_quoting['end'], $this->identifier_quoting['escape'] . $this->identifier_quoting['end'], $str); + $parts = explode('.', $str); + foreach (array_keys($parts) as $k) { + $parts[$k] = $this->identifier_quoting['start'] . $parts[$k] . $this->identifier_quoting['end']; + } + return implode('.', $parts); + } + + // }}} + // {{{ function getAsKeyword() + + /** + * Gets the string to alias column + * + * @return string to use when aliasing a column + */ + function getAsKeyword() + { + return $this->as_keyword; + } + + // }}} + // {{{ function getConnection() + + /** + * Returns a native connection + * + * @return mixed a valid MDB2 connection object, + * or a MDB2 error object on error + * + * @access public + */ + function getConnection() + { + $result = $this->connect(); + if (PEAR::isError($result)) { + return $result; + } + return $this->connection; + } + + // }}} + // {{{ function _fixResultArrayValues(&$row, $mode) + + /** + * Do all necessary conversions on result arrays to fix DBMS quirks + * + * @param array the array to be fixed (passed by reference) + * @param array bit-wise addition of the required portability modes + * + * @return void + * + * @access protected + */ + function _fixResultArrayValues(&$row, $mode) + { + switch ($mode) { + case MDB2_PORTABILITY_EMPTY_TO_NULL: + foreach ($row as $key => $value) { + if ($value === '') { + $row[$key] = null; + } + } + break; + case MDB2_PORTABILITY_RTRIM: + foreach ($row as $key => $value) { + if (is_string($value)) { + $row[$key] = rtrim($value); + } + } + break; + case MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES: + $tmp_row = array(); + foreach ($row as $key => $value) { + $tmp_row[preg_replace('/^(?:.*\.)?([^.]+)$/', '\\1', $key)] = $value; + } + $row = $tmp_row; + break; + case (MDB2_PORTABILITY_RTRIM + MDB2_PORTABILITY_EMPTY_TO_NULL): + foreach ($row as $key => $value) { + if ($value === '') { + $row[$key] = null; + } elseif (is_string($value)) { + $row[$key] = rtrim($value); + } + } + break; + case (MDB2_PORTABILITY_RTRIM + MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES): + $tmp_row = array(); + foreach ($row as $key => $value) { + if (is_string($value)) { + $value = rtrim($value); + } + $tmp_row[preg_replace('/^(?:.*\.)?([^.]+)$/', '\\1', $key)] = $value; + } + $row = $tmp_row; + break; + case (MDB2_PORTABILITY_EMPTY_TO_NULL + MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES): + $tmp_row = array(); + foreach ($row as $key => $value) { + if ($value === '') { + $value = null; + } + $tmp_row[preg_replace('/^(?:.*\.)?([^.]+)$/', '\\1', $key)] = $value; + } + $row = $tmp_row; + break; + case (MDB2_PORTABILITY_RTRIM + MDB2_PORTABILITY_EMPTY_TO_NULL + MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES): + $tmp_row = array(); + foreach ($row as $key => $value) { + if ($value === '') { + $value = null; + } elseif (is_string($value)) { + $value = rtrim($value); + } + $tmp_row[preg_replace('/^(?:.*\.)?([^.]+)$/', '\\1', $key)] = $value; + } + $row = $tmp_row; + break; + } + } + + // }}} + // {{{ function &loadModule($module, $property = null, $phptype_specific = null) + + /** + * loads a module + * + * @param string name of the module that should be loaded + * (only used for error messages) + * @param string name of the property into which the class will be loaded + * @param bool if the class to load for the module is specific to the + * phptype + * + * @return object on success a reference to the given module is returned + * and on failure a PEAR error + * + * @access public + */ + function &loadModule($module, $property = null, $phptype_specific = null) + { + if (!$property) { + $property = strtolower($module); + } + + if (!isset($this->{$property})) { + $version = $phptype_specific; + if ($phptype_specific !== false) { + $version = true; + $class_name = 'MDB2_Driver_'.$module.'_'.$this->phptype; + $file_name = str_replace('_', DIRECTORY_SEPARATOR, $class_name).'.php'; + } + if ($phptype_specific === false + || (!MDB2::classExists($class_name) && !MDB2::fileExists($file_name)) + ) { + $version = false; + $class_name = 'MDB2_'.$module; + $file_name = str_replace('_', DIRECTORY_SEPARATOR, $class_name).'.php'; + } + + $err = MDB2::loadClass($class_name, $this->getOption('debug')); + if (PEAR::isError($err)) { + return $err; + } + + // load module in a specific version + if ($version) { + if (method_exists($class_name, 'getClassName')) { + $class_name_new = call_user_func(array($class_name, 'getClassName'), $this->db_index); + if ($class_name != $class_name_new) { + $class_name = $class_name_new; + $err = MDB2::loadClass($class_name, $this->getOption('debug')); + if (PEAR::isError($err)) { + return $err; + } + } + } + } + + if (!MDB2::classExists($class_name)) { + $err =& $this->raiseError(MDB2_ERROR_LOADMODULE, null, null, + "unable to load module '$module' into property '$property'", __FUNCTION__); + return $err; + } + $this->{$property} = new $class_name($this->db_index); + $this->modules[$module] =& $this->{$property}; + if ($version) { + // this will be used in the connect method to determine if the module + // needs to be loaded with a different version if the server + // version changed in between connects + $this->loaded_version_modules[] = $property; + } + } + + return $this->{$property}; + } + + // }}} + // {{{ function __call($method, $params) + + /** + * Calls a module method using the __call magic method + * + * @param string Method name. + * @param array Arguments. + * + * @return mixed Returned value. + */ + function __call($method, $params) + { + $module = null; + if (preg_match('/^([a-z]+)([A-Z])(.*)$/', $method, $match) + && isset($this->options['modules'][$match[1]]) + ) { + $module = $this->options['modules'][$match[1]]; + $method = strtolower($match[2]).$match[3]; + if (!isset($this->modules[$module]) || !is_object($this->modules[$module])) { + $result =& $this->loadModule($module); + if (PEAR::isError($result)) { + return $result; + } + } + } else { + foreach ($this->modules as $key => $foo) { + if (is_object($this->modules[$key]) + && method_exists($this->modules[$key], $method) + ) { + $module = $key; + break; + } + } + } + if (!is_null($module)) { + return call_user_func_array(array(&$this->modules[$module], $method), $params); + } + trigger_error(sprintf('Call to undefined function: %s::%s().', get_class($this), $method), E_USER_ERROR); + } + + // }}} + // {{{ function beginTransaction($savepoint = null) + + /** + * Start a transaction or set a savepoint. + * + * @param string name of a savepoint to set + * @return mixed MDB2_OK on success, a MDB2 error on failure + * + * @access public + */ + function beginTransaction($savepoint = null) + { + $this->debug('Starting transaction', __FUNCTION__, array('is_manip' => true, 'savepoint' => $savepoint)); + return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'transactions are not supported', __FUNCTION__); + } + + // }}} + // {{{ function commit($savepoint = null) + + /** + * Commit the database changes done during a transaction that is in + * progress or release a savepoint. This function may only be called when + * auto-committing is disabled, otherwise it will fail. Therefore, a new + * transaction is implicitly started after committing the pending changes. + * + * @param string name of a savepoint to release + * @return mixed MDB2_OK on success, a MDB2 error on failure + * + * @access public + */ + function commit($savepoint = null) + { + $this->debug('Committing transaction/savepoint', __FUNCTION__, array('is_manip' => true, 'savepoint' => $savepoint)); + return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'commiting transactions is not supported', __FUNCTION__); + } + + // }}} + // {{{ function rollback($savepoint = null) + + /** + * Cancel any database changes done during a transaction or since a specific + * savepoint that is in progress. This function may only be called when + * auto-committing is disabled, otherwise it will fail. Therefore, a new + * transaction is implicitly started after canceling the pending changes. + * + * @param string name of a savepoint to rollback to + * @return mixed MDB2_OK on success, a MDB2 error on failure + * + * @access public + */ + function rollback($savepoint = null) + { + $this->debug('Rolling back transaction/savepoint', __FUNCTION__, array('is_manip' => true, 'savepoint' => $savepoint)); + return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'rolling back transactions is not supported', __FUNCTION__); + } + + // }}} + // {{{ function inTransaction($ignore_nested = false) + + /** + * If a transaction is currently open. + * + * @param bool if the nested transaction count should be ignored + * @return int|bool - an integer with the nesting depth is returned if a + * nested transaction is open + * - true is returned for a normal open transaction + * - false is returned if no transaction is open + * + * @access public + */ + function inTransaction($ignore_nested = false) + { + if (!$ignore_nested && isset($this->nested_transaction_counter)) { + return $this->nested_transaction_counter; + } + return $this->in_transaction; + } + + // }}} + // {{{ function setTransactionIsolation($isolation) + + /** + * Set the transacton isolation level. + * + * @param string standard isolation level + * READ UNCOMMITTED (allows dirty reads) + * READ COMMITTED (prevents dirty reads) + * REPEATABLE READ (prevents nonrepeatable reads) + * SERIALIZABLE (prevents phantom reads) + * @param array some transaction options: + * 'wait' => 'WAIT' | 'NO WAIT' + * 'rw' => 'READ WRITE' | 'READ ONLY' + * @return mixed MDB2_OK on success, a MDB2 error on failure + * + * @access public + * @since 2.1.1 + */ + function setTransactionIsolation($isolation, $options = array()) + { + $this->debug('Setting transaction isolation level', __FUNCTION__, array('is_manip' => true)); + return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'isolation level setting is not supported', __FUNCTION__); + } + + // }}} + // {{{ function beginNestedTransaction($savepoint = false) + + /** + * Start a nested transaction. + * + * @return mixed MDB2_OK on success/savepoint name, a MDB2 error on failure + * + * @access public + * @since 2.1.1 + */ + function beginNestedTransaction() + { + if ($this->in_transaction) { + ++$this->nested_transaction_counter; + $savepoint = sprintf($this->options['savepoint_format'], $this->nested_transaction_counter); + if ($this->supports('savepoints') && $savepoint) { + return $this->beginTransaction($savepoint); + } + return MDB2_OK; + } + $this->has_transaction_error = false; + $result = $this->beginTransaction(); + $this->nested_transaction_counter = 1; + return $result; + } + + // }}} + // {{{ function completeNestedTransaction($force_rollback = false, $release = false) + + /** + * Finish a nested transaction by rolling back if an error occured or + * committing otherwise. + * + * @param bool if the transaction should be rolled back regardless + * even if no error was set within the nested transaction + * @return mixed MDB_OK on commit/counter decrementing, false on rollback + * and a MDB2 error on failure + * + * @access public + * @since 2.1.1 + */ + function completeNestedTransaction($force_rollback = false) + { + if ($this->nested_transaction_counter > 1) { + $savepoint = sprintf($this->options['savepoint_format'], $this->nested_transaction_counter); + if ($this->supports('savepoints') && $savepoint) { + if ($force_rollback || $this->has_transaction_error) { + $result = $this->rollback($savepoint); + if (!PEAR::isError($result)) { + $result = false; + $this->has_transaction_error = false; + } + } else { + $result = $this->commit($savepoint); + } + } else { + $result = MDB2_OK; + } + --$this->nested_transaction_counter; + return $result; + } + + $this->nested_transaction_counter = null; + $result = MDB2_OK; + + // transaction has not yet been rolled back + if ($this->in_transaction) { + if ($force_rollback || $this->has_transaction_error) { + $result = $this->rollback(); + if (!PEAR::isError($result)) { + $result = false; + } + } else { + $result = $this->commit(); + } + } + $this->has_transaction_error = false; + return $result; + } + + // }}} + // {{{ function failNestedTransaction($error = null, $immediately = false) + + /** + * Force setting nested transaction to failed. + * + * @param mixed value to return in getNestededTransactionError() + * @param bool if the transaction should be rolled back immediately + * @return bool MDB2_OK + * + * @access public + * @since 2.1.1 + */ + function failNestedTransaction($error = null, $immediately = false) + { + if (is_null($error)) { + $error = $this->has_transaction_error ? $this->has_transaction_error : true; + } elseif (!$error) { + $error = true; + } + $this->has_transaction_error = $error; + if (!$immediately) { + return MDB2_OK; + } + return $this->rollback(); + } + + // }}} + // {{{ function getNestedTransactionError() + + /** + * The first error that occured since the transaction start. + * + * @return MDB2_Error|bool MDB2 error object if an error occured or false. + * + * @access public + * @since 2.1.1 + */ + function getNestedTransactionError() + { + return $this->has_transaction_error; + } + + // }}} + // {{{ connect() + + /** + * Connect to the database + * + * @return true on success, MDB2 Error Object on failure + */ + function connect() + { + return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'method not implemented', __FUNCTION__); + } + + // }}} + // {{{ databaseExists() + + /** + * check if given database name is exists? + * + * @param string $name name of the database that should be checked + * + * @return mixed true/false on success, a MDB2 error on failure + * @access public + */ + function databaseExists($name) + { + return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'method not implemented', __FUNCTION__); + } + + // }}} + // {{{ setCharset($charset, $connection = null) + + /** + * Set the charset on the current connection + * + * @param string charset + * @param resource connection handle + * + * @return true on success, MDB2 Error Object on failure + */ + function setCharset($charset, $connection = null) + { + return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'method not implemented', __FUNCTION__); + } + + // }}} + // {{{ function disconnect($force = true) + + /** + * Log out and disconnect from the database. + * + * @param boolean $force whether the disconnect should be forced even if the + * connection is opened persistently + * + * @return mixed true on success, false if not connected and error object on error + * + * @access public + */ + function disconnect($force = true) + { + $this->connection = 0; + $this->connected_dsn = array(); + $this->connected_database_name = ''; + $this->opened_persistent = null; + $this->connected_server_info = ''; + $this->in_transaction = null; + $this->nested_transaction_counter = null; + return MDB2_OK; + } + + // }}} + // {{{ function setDatabase($name) + + /** + * Select a different database + * + * @param string name of the database that should be selected + * + * @return string name of the database previously connected to + * + * @access public + */ + function setDatabase($name) + { + $previous_database_name = (isset($this->database_name)) ? $this->database_name : ''; + $this->database_name = $name; + if (!empty($this->connected_database_name) && ($this->connected_database_name != $this->database_name)) { + $this->disconnect(false); + } + return $previous_database_name; + } + + // }}} + // {{{ function getDatabase() + + /** + * Get the current database + * + * @return string name of the database + * + * @access public + */ + function getDatabase() + { + return $this->database_name; + } + + // }}} + // {{{ function setDSN($dsn) + + /** + * set the DSN + * + * @param mixed DSN string or array + * + * @return MDB2_OK + * + * @access public + */ + function setDSN($dsn) + { + $dsn_default = $GLOBALS['_MDB2_dsninfo_default']; + $dsn = MDB2::parseDSN($dsn); + if (array_key_exists('database', $dsn)) { + $this->database_name = $dsn['database']; + unset($dsn['database']); + } + $this->dsn = array_merge($dsn_default, $dsn); + return $this->disconnect(false); + } + + // }}} + // {{{ function getDSN($type = 'string', $hidepw = false) + + /** + * return the DSN as a string + * + * @param string format to return ("array", "string") + * @param string string to hide the password with + * + * @return mixed DSN in the chosen type + * + * @access public + */ + function getDSN($type = 'string', $hidepw = false) + { + $dsn = array_merge($GLOBALS['_MDB2_dsninfo_default'], $this->dsn); + $dsn['phptype'] = $this->phptype; + $dsn['database'] = $this->database_name; + if ($hidepw) { + $dsn['password'] = $hidepw; + } + switch ($type) { + // expand to include all possible options + case 'string': + $dsn = $dsn['phptype']. + ($dsn['dbsyntax'] ? ('('.$dsn['dbsyntax'].')') : ''). + '://'.$dsn['username'].':'. + $dsn['password'].'@'.$dsn['hostspec']. + ($dsn['port'] ? (':'.$dsn['port']) : ''). + '/'.$dsn['database']; + break; + case 'array': + default: + break; + } + return $dsn; + } + + // }}} + // {{{ _isNewLinkSet() + + /** + * Check if the 'new_link' option is set + * + * @return boolean + * + * @access protected + */ + function _isNewLinkSet() + { + return (isset($this->dsn['new_link']) + && ($this->dsn['new_link'] === true + || (is_string($this->dsn['new_link']) && preg_match('/^true$/i', $this->dsn['new_link'])) + || (is_numeric($this->dsn['new_link']) && 0 != (int)$this->dsn['new_link']) + ) + ); + } + + // }}} + // {{{ function &standaloneQuery($query, $types = null, $is_manip = false) + + /** + * execute a query as database administrator + * + * @param string the SQL query + * @param mixed array that contains the types of the columns in + * the result set + * @param bool if the query is a manipulation query + * + * @return mixed MDB2_OK on success, a MDB2 error on failure + * + * @access public + */ + function &standaloneQuery($query, $types = null, $is_manip = false) + { + $offset = $this->offset; + $limit = $this->limit; + $this->offset = $this->limit = 0; + $query = $this->_modifyQuery($query, $is_manip, $limit, $offset); + + $connection = $this->getConnection(); + if (PEAR::isError($connection)) { + return $connection; + } + + $result =& $this->_doQuery($query, $is_manip, $connection, false); + if (PEAR::isError($result)) { + return $result; + } + + if ($is_manip) { + $affected_rows = $this->_affectedRows($connection, $result); + return $affected_rows; + } + $result =& $this->_wrapResult($result, $types, true, false, $limit, $offset); + return $result; + } + + // }}} + // {{{ function _modifyQuery($query, $is_manip, $limit, $offset) + + /** + * Changes a query string for various DBMS specific reasons + * + * @param string query to modify + * @param bool if it is a DML query + * @param int limit the number of rows + * @param int start reading from given offset + * + * @return string modified query + * + * @access protected + */ + function _modifyQuery($query, $is_manip, $limit, $offset) + { + return $query; + } + + // }}} + // {{{ function &_doQuery($query, $is_manip = false, $connection = null, $database_name = null) + + /** + * Execute a query + * @param string query + * @param bool if the query is a manipulation query + * @param resource connection handle + * @param string database name + * + * @return result or error object + * + * @access protected + */ + function &_doQuery($query, $is_manip = false, $connection = null, $database_name = null) + { + $this->last_query = $query; + $result = $this->debug($query, 'query', array('is_manip' => $is_manip, 'when' => 'pre')); + if ($result) { + if (PEAR::isError($result)) { + return $result; + } + $query = $result; + } + $err =& $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'method not implemented', __FUNCTION__); + return $err; + } + + // }}} + // {{{ function _affectedRows($connection, $result = null) + + /** + * Returns the number of rows affected + * + * @param resource result handle + * @param resource connection handle + * + * @return mixed MDB2 Error Object or the number of rows affected + * + * @access private + */ + function _affectedRows($connection, $result = null) + { + return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'method not implemented', __FUNCTION__); + } + + // }}} + // {{{ function &exec($query) + + /** + * Execute a manipulation query to the database and return the number of affected rows + * + * @param string the SQL query + * + * @return mixed number of affected rows on success, a MDB2 error on failure + * + * @access public + */ + function &exec($query) + { + $offset = $this->offset; + $limit = $this->limit; + $this->offset = $this->limit = 0; + $query = $this->_modifyQuery($query, true, $limit, $offset); + + $connection = $this->getConnection(); + if (PEAR::isError($connection)) { + return $connection; + } + + $result =& $this->_doQuery($query, true, $connection, $this->database_name); + if (PEAR::isError($result)) { + return $result; + } + + $affectedRows = $this->_affectedRows($connection, $result); + return $affectedRows; + } + + // }}} + // {{{ function &query($query, $types = null, $result_class = true, $result_wrap_class = false) + + /** + * Send a query to the database and return any results + * + * @param string the SQL query + * @param mixed array that contains the types of the columns in + * the result set + * @param mixed string which specifies which result class to use + * @param mixed string which specifies which class to wrap results in + * + * @return mixed an MDB2_Result handle on success, a MDB2 error on failure + * + * @access public + */ + function &query($query, $types = null, $result_class = true, $result_wrap_class = false) + { + $offset = $this->offset; + $limit = $this->limit; + $this->offset = $this->limit = 0; + $query = $this->_modifyQuery($query, false, $limit, $offset); + + $connection = $this->getConnection(); + if (PEAR::isError($connection)) { + return $connection; + } + + $result =& $this->_doQuery($query, false, $connection, $this->database_name); + if (PEAR::isError($result)) { + return $result; + } + + $result =& $this->_wrapResult($result, $types, $result_class, $result_wrap_class, $limit, $offset); + return $result; + } + + // }}} + // {{{ function &_wrapResult($result, $types = array(), $result_class = true, $result_wrap_class = false, $limit = null, $offset = null) + + /** + * wrap a result set into the correct class + * + * @param resource result handle + * @param mixed array that contains the types of the columns in + * the result set + * @param mixed string which specifies which result class to use + * @param mixed string which specifies which class to wrap results in + * @param string number of rows to select + * @param string first row to select + * + * @return mixed an MDB2_Result, a MDB2 error on failure + * + * @access protected + */ + function &_wrapResult($result, $types = array(), $result_class = true, + $result_wrap_class = false, $limit = null, $offset = null) + { + if ($types === true) { + if ($this->supports('result_introspection')) { + $this->loadModule('Reverse', null, true); + $tableInfo = $this->reverse->tableInfo($result); + if (PEAR::isError($tableInfo)) { + return $tableInfo; + } + $types = array(); + foreach ($tableInfo as $field) { + $types[] = $field['mdb2type']; + } + } else { + $types = null; + } + } + + if ($result_class === true) { + $result_class = $this->options['result_buffering'] + ? $this->options['buffered_result_class'] : $this->options['result_class']; + } + + if ($result_class) { + $class_name = sprintf($result_class, $this->phptype); + if (!MDB2::classExists($class_name)) { + $err =& $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null, + 'result class does not exist '.$class_name, __FUNCTION__); + return $err; + } + $result =& new $class_name($this, $result, $limit, $offset); + if (!MDB2::isResultCommon($result)) { + $err =& $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null, + 'result class is not extended from MDB2_Result_Common', __FUNCTION__); + return $err; + } + if (!empty($types)) { + $err = $result->setResultTypes($types); + if (PEAR::isError($err)) { + $result->free(); + return $err; + } + } + } + if ($result_wrap_class === true) { + $result_wrap_class = $this->options['result_wrap_class']; + } + if ($result_wrap_class) { + if (!MDB2::classExists($result_wrap_class)) { + $err =& $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null, + 'result wrap class does not exist '.$result_wrap_class, __FUNCTION__); + return $err; + } + $result = new $result_wrap_class($result, $this->fetchmode); + } + return $result; + } + + // }}} + // {{{ function getServerVersion($native = false) + + /** + * return version information about the server + * + * @param bool determines if the raw version string should be returned + * + * @return mixed array with version information or row string + * + * @access public + */ + function getServerVersion($native = false) + { + return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'method not implemented', __FUNCTION__); + } + + // }}} + // {{{ function setLimit($limit, $offset = null) + + /** + * set the range of the next query + * + * @param string number of rows to select + * @param string first row to select + * + * @return mixed MDB2_OK on success, a MDB2 error on failure + * + * @access public + */ + function setLimit($limit, $offset = null) + { + if (!$this->supports('limit_queries')) { + return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'limit is not supported by this driver', __FUNCTION__); + } + $limit = (int)$limit; + if ($limit < 0) { + return $this->raiseError(MDB2_ERROR_SYNTAX, null, null, + 'it was not specified a valid selected range row limit', __FUNCTION__); + } + $this->limit = $limit; + if (!is_null($offset)) { + $offset = (int)$offset; + if ($offset < 0) { + return $this->raiseError(MDB2_ERROR_SYNTAX, null, null, + 'it was not specified a valid first selected range row', __FUNCTION__); + } + $this->offset = $offset; + } + return MDB2_OK; + } + + // }}} + // {{{ function subSelect($query, $type = false) + + /** + * simple subselect emulation: leaves the query untouched for all RDBMS + * that support subselects + * + * @param string the SQL query for the subselect that may only + * return a column + * @param string determines type of the field + * + * @return string the query + * + * @access public + */ + function subSelect($query, $type = false) + { + if ($this->supports('sub_selects') === true) { + return $query; + } + + if (!$this->supports('sub_selects')) { + return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'method not implemented', __FUNCTION__); + } + + $col = $this->queryCol($query, $type); + if (PEAR::isError($col)) { + return $col; + } + if (!is_array($col) || count($col) == 0) { + return 'NULL'; + } + if ($type) { + $this->loadModule('Datatype', null, true); + return $this->datatype->implodeArray($col, $type); + } + return implode(', ', $col); + } + + // }}} + // {{{ function replace($table, $fields) + + /** + * Execute a SQL REPLACE query. A REPLACE query is identical to a INSERT + * query, except that if there is already a row in the table with the same + * key field values, the old row is deleted before the new row is inserted. + * + * The REPLACE type of query does not make part of the SQL standards. Since + * practically only MySQL and SQLite implement it natively, this type of + * query isemulated through this method for other DBMS using standard types + * of queries inside a transaction to assure the atomicity of the operation. + * + * @param string name of the table on which the REPLACE query will + * be executed. + * @param array associative array that describes the fields and the + * values that will be inserted or updated in the specified table. The + * indexes of the array are the names of all the fields of the table. + * The values of the array are also associative arrays that describe + * the values and other properties of the table fields. + * + * Here follows a list of field properties that need to be specified: + * + * value + * Value to be assigned to the specified field. This value may be + * of specified in database independent type format as this + * function can perform the necessary datatype conversions. + * + * Default: this property is required unless the Null property is + * set to 1. + * + * type + * Name of the type of the field. Currently, all types MDB2 + * are supported except for clob and blob. + * + * Default: no type conversion + * + * null + * bool property that indicates that the value for this field + * should be set to null. + * + * The default value for fields missing in INSERT queries may be + * specified the definition of a table. Often, the default value + * is already null, but since the REPLACE may be emulated using + * an UPDATE query, make sure that all fields of the table are + * listed in this function argument array. + * + * Default: 0 + * + * key + * bool property that indicates that this field should be + * handled as a primary key or at least as part of the compound + * unique index of the table that will determine the row that will + * updated if it exists or inserted a new row otherwise. + * + * This function will fail if no key field is specified or if the + * value of a key field is set to null because fields that are + * part of unique index they may not be null. + * + * Default: 0 + * + * @return mixed MDB2_OK on success, a MDB2 error on failure + * + * @access public + */ + function replace($table, $fields) + { + if (!$this->supports('replace')) { + return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'replace query is not supported', __FUNCTION__); + } + $count = count($fields); + $condition = $values = array(); + for ($colnum = 0, reset($fields); $colnum < $count; next($fields), $colnum++) { + $name = key($fields); + if (isset($fields[$name]['null']) && $fields[$name]['null']) { + $value = 'NULL'; + } else { + $type = isset($fields[$name]['type']) ? $fields[$name]['type'] : null; + $value = $this->quote($fields[$name]['value'], $type); + } + $values[$name] = $value; + if (isset($fields[$name]['key']) && $fields[$name]['key']) { + if ($value === 'NULL') { + return $this->raiseError(MDB2_ERROR_CANNOT_REPLACE, null, null, + 'key value '.$name.' may not be NULL', __FUNCTION__); + } + $condition[] = $this->quoteIdentifier($name, true) . '=' . $value; + } + } + if (empty($condition)) { + return $this->raiseError(MDB2_ERROR_CANNOT_REPLACE, null, null, + 'not specified which fields are keys', __FUNCTION__); + } + + $result = null; + $in_transaction = $this->in_transaction; + if (!$in_transaction && PEAR::isError($result = $this->beginTransaction())) { + return $result; + } + + $connection = $this->getConnection(); + if (PEAR::isError($connection)) { + return $connection; + } + + $condition = ' WHERE '.implode(' AND ', $condition); + $query = 'DELETE FROM ' . $this->quoteIdentifier($table, true) . $condition; + $result =& $this->_doQuery($query, true, $connection); + if (!PEAR::isError($result)) { + $affected_rows = $this->_affectedRows($connection, $result); + $insert = ''; + foreach ($values as $key => $value) { + $insert .= ($insert?', ':'') . $this->quoteIdentifier($key, true); + } + $values = implode(', ', $values); + $query = 'INSERT INTO '. $this->quoteIdentifier($table, true) . "($insert) VALUES ($values)"; + $result =& $this->_doQuery($query, true, $connection); + if (!PEAR::isError($result)) { + $affected_rows += $this->_affectedRows($connection, $result);; + } + } + + if (!$in_transaction) { + if (PEAR::isError($result)) { + $this->rollback(); + } else { + $result = $this->commit(); + } + } + + if (PEAR::isError($result)) { + return $result; + } + + return $affected_rows; + } + + // }}} + // {{{ function &prepare($query, $types = null, $result_types = null, $lobs = array()) + + /** + * Prepares a query for multiple execution with execute(). + * With some database backends, this is emulated. + * prepare() requires a generic query as string like + * 'INSERT INTO numbers VALUES(?,?)' or + * 'INSERT INTO numbers VALUES(:foo,:bar)'. + * The ? and :name and are placeholders which can be set using + * bindParam() and the query can be sent off using the execute() method. + * The allowed format for :name can be set with the 'bindname_format' option. + * + * @param string the query to prepare + * @param mixed array that contains the types of the placeholders + * @param mixed array that contains the types of the columns in + * the result set or MDB2_PREPARE_RESULT, if set to + * MDB2_PREPARE_MANIP the query is handled as a manipulation query + * @param mixed key (field) value (parameter) pair for all lob placeholders + * + * @return mixed resource handle for the prepared query on success, + * a MDB2 error on failure + * + * @access public + * @see bindParam, execute + */ + function &prepare($query, $types = null, $result_types = null, $lobs = array()) + { + $is_manip = ($result_types === MDB2_PREPARE_MANIP); + $offset = $this->offset; + $limit = $this->limit; + $this->offset = $this->limit = 0; + $result = $this->debug($query, __FUNCTION__, array('is_manip' => $is_manip, 'when' => 'pre')); + if ($result) { + if (PEAR::isError($result)) { + return $result; + } + $query = $result; + } + $placeholder_type_guess = $placeholder_type = null; + $question = '?'; + $colon = ':'; + $positions = array(); + $position = 0; + while ($position < strlen($query)) { + $q_position = strpos($query, $question, $position); + $c_position = strpos($query, $colon, $position); + if ($q_position && $c_position) { + $p_position = min($q_position, $c_position); + } elseif ($q_position) { + $p_position = $q_position; + } elseif ($c_position) { + $p_position = $c_position; + } else { + break; + } + if (is_null($placeholder_type)) { + $placeholder_type_guess = $query[$p_position]; + } + + $new_pos = $this->_skipDelimitedStrings($query, $position, $p_position); + if (PEAR::isError($new_pos)) { + return $new_pos; + } + if ($new_pos != $position) { + $position = $new_pos; + continue; //evaluate again starting from the new position + } + + if ($query[$position] == $placeholder_type_guess) { + if (is_null($placeholder_type)) { + $placeholder_type = $query[$p_position]; + $question = $colon = $placeholder_type; + if (!empty($types) && is_array($types)) { + if ($placeholder_type == ':') { + if (is_int(key($types))) { + $types_tmp = $types; + $types = array(); + $count = -1; + } + } else { + $types = array_values($types); + } + } + } + if ($placeholder_type == ':') { + $regexp = '/^.{'.($position+1).'}('.$this->options['bindname_format'].').*$/s'; + $parameter = preg_replace($regexp, '\\1', $query); + if ($parameter === '') { + $err =& $this->raiseError(MDB2_ERROR_SYNTAX, null, null, + 'named parameter name must match "bindname_format" option', __FUNCTION__); + return $err; + } + $positions[$p_position] = $parameter; + $query = substr_replace($query, '?', $position, strlen($parameter)+1); + // use parameter name in type array + if (isset($count) && isset($types_tmp[++$count])) { + $types[$parameter] = $types_tmp[$count]; + } + } else { + $positions[$p_position] = count($positions); + } + $position = $p_position + 1; + } else { + $position = $p_position; + } + } + $class_name = 'MDB2_Statement_'.$this->phptype; + $statement = null; + $obj = new $class_name($this, $statement, $positions, $query, $types, $result_types, $is_manip, $limit, $offset); + $this->debug($query, __FUNCTION__, array('is_manip' => $is_manip, 'when' => 'post', 'result' => $obj)); + return $obj; + } + + // }}} + // {{{ function _skipDelimitedStrings($query, $position, $p_position) + + /** + * Utility method, used by prepare() to avoid replacing placeholders within delimited strings. + * Check if the placeholder is contained within a delimited string. + * If so, skip it and advance the position, otherwise return the current position, + * which is valid + * + * @param string $query + * @param integer $position current string cursor position + * @param integer $p_position placeholder position + * + * @return mixed integer $new_position on success + * MDB2_Error on failure + * + * @access protected + */ + function _skipDelimitedStrings($query, $position, $p_position) + { + $ignores = $this->string_quoting; + $ignores[] = $this->identifier_quoting; + $ignores = array_merge($ignores, $this->sql_comments); + + foreach ($ignores as $ignore) { + if (!empty($ignore['start'])) { + if (is_int($start_quote = strpos($query, $ignore['start'], $position)) && $start_quote < $p_position) { + $end_quote = $start_quote; + do { + if (!is_int($end_quote = strpos($query, $ignore['end'], $end_quote + 1))) { + if ($ignore['end'] === "\n") { + $end_quote = strlen($query) - 1; + } else { + $err =& $this->raiseError(MDB2_ERROR_SYNTAX, null, null, + 'query with an unterminated text string specified', __FUNCTION__); + return $err; + } + } + } while ($ignore['escape'] + && $end_quote-1 != $start_quote + && $query[($end_quote - 1)] == $ignore['escape'] + && ( $ignore['escape_pattern'] !== $ignore['escape'] + || $query[($end_quote - 2)] != $ignore['escape']) + ); + + $position = $end_quote + 1; + return $position; + } + } + } + return $position; + } + + // }}} + // {{{ function quote($value, $type = null, $quote = true) + + /** + * Convert a text value into a DBMS specific format that is suitable to + * compose query statements. + * + * @param string text string value that is intended to be converted. + * @param string type to which the value should be converted to + * @param bool quote + * @param bool escape wildcards + * + * @return string text string that represents the given argument value in + * a DBMS specific format. + * + * @access public + */ + function quote($value, $type = null, $quote = true, $escape_wildcards = false) + { + $result = $this->loadModule('Datatype', null, true); + if (PEAR::isError($result)) { + return $result; + } + + return $this->datatype->quote($value, $type, $quote, $escape_wildcards); + } + + // }}} + // {{{ function getDeclaration($type, $name, $field) + + /** + * Obtain DBMS specific SQL code portion needed to declare + * of the given type + * + * @param string type to which the value should be converted to + * @param string name the field to be declared. + * @param string definition of the field + * + * @return string DBMS specific SQL code portion that should be used to + * declare the specified field. + * + * @access public + */ + function getDeclaration($type, $name, $field) + { + $result = $this->loadModule('Datatype', null, true); + if (PEAR::isError($result)) { + return $result; + } + return $this->datatype->getDeclaration($type, $name, $field); + } + + // }}} + // {{{ function compareDefinition($current, $previous) + + /** + * Obtain an array of changes that may need to applied + * + * @param array new definition + * @param array old definition + * + * @return array containing all changes that will need to be applied + * + * @access public + */ + function compareDefinition($current, $previous) + { + $result = $this->loadModule('Datatype', null, true); + if (PEAR::isError($result)) { + return $result; + } + return $this->datatype->compareDefinition($current, $previous); + } + + // }}} + // {{{ function supports($feature) + + /** + * Tell whether a DB implementation or its backend extension + * supports a given feature. + * + * @param string name of the feature (see the MDB2 class doc) + * + * @return bool|string if this DB implementation supports a given feature + * false means no, true means native, + * 'emulated' means emulated + * + * @access public + */ + function supports($feature) + { + if (array_key_exists($feature, $this->supported)) { + return $this->supported[$feature]; + } + return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + "unknown support feature $feature", __FUNCTION__); + } + + // }}} + // {{{ function getSequenceName($sqn) + + /** + * adds sequence name formatting to a sequence name + * + * @param string name of the sequence + * + * @return string formatted sequence name + * + * @access public + */ + function getSequenceName($sqn) + { + return sprintf($this->options['seqname_format'], + preg_replace('/[^a-z0-9_\-\$.]/i', '_', $sqn)); + } + + // }}} + // {{{ function getIndexName($idx) + + /** + * adds index name formatting to a index name + * + * @param string name of the index + * + * @return string formatted index name + * + * @access public + */ + function getIndexName($idx) + { + return sprintf($this->options['idxname_format'], + preg_replace('/[^a-z0-9_\-\$.]/i', '_', $idx)); + } + + // }}} + // {{{ function nextID($seq_name, $ondemand = true) + + /** + * Returns the next free id of a sequence + * + * @param string name of the sequence + * @param bool when true missing sequences are automatic created + * + * @return mixed MDB2 Error Object or id + * + * @access public + */ + function nextID($seq_name, $ondemand = true) + { + return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'method not implemented', __FUNCTION__); + } + + // }}} + // {{{ function lastInsertID($table = null, $field = null) + + /** + * Returns the autoincrement ID if supported or $id or fetches the current + * ID in a sequence called: $table.(empty($field) ? '' : '_'.$field) + * + * @param string name of the table into which a new row was inserted + * @param string name of the field into which a new row was inserted + * + * @return mixed MDB2 Error Object or id + * + * @access public + */ + function lastInsertID($table = null, $field = null) + { + return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'method not implemented', __FUNCTION__); + } + + // }}} + // {{{ function currID($seq_name) + + /** + * Returns the current id of a sequence + * + * @param string name of the sequence + * + * @return mixed MDB2 Error Object or id + * + * @access public + */ + function currID($seq_name) + { + $this->warnings[] = 'database does not support getting current + sequence value, the sequence value was incremented'; + return $this->nextID($seq_name); + } + + // }}} + // {{{ function queryOne($query, $type = null, $colnum = 0) + + /** + * Execute the specified query, fetch the value from the first column of + * the first row of the result set and then frees + * the result set. + * + * @param string $query the SELECT query statement to be executed. + * @param string $type optional argument that specifies the expected + * datatype of the result set field, so that an eventual + * conversion may be performed. The default datatype is + * text, meaning that no conversion is performed + * @param mixed $colnum the column number (or name) to fetch + * + * @return mixed MDB2_OK or field value on success, a MDB2 error on failure + * + * @access public + */ + function queryOne($query, $type = null, $colnum = 0) + { + $result = $this->query($query, $type); + if (!MDB2::isResultCommon($result)) { + return $result; + } + + $one = $result->fetchOne($colnum); + $result->free(); + return $one; + } + + // }}} + // {{{ function queryRow($query, $types = null, $fetchmode = MDB2_FETCHMODE_DEFAULT) + + /** + * Execute the specified query, fetch the values from the first + * row of the result set into an array and then frees + * the result set. + * + * @param string the SELECT query statement to be executed. + * @param array optional array argument that specifies a list of + * expected datatypes of the result set columns, so that the eventual + * conversions may be performed. The default list of datatypes is + * empty, meaning that no conversion is performed. + * @param int how the array data should be indexed + * + * @return mixed MDB2_OK or data array on success, a MDB2 error on failure + * + * @access public + */ + function queryRow($query, $types = null, $fetchmode = MDB2_FETCHMODE_DEFAULT) + { + $result = $this->query($query, $types); + if (!MDB2::isResultCommon($result)) { + return $result; + } + + $row = $result->fetchRow($fetchmode); + $result->free(); + return $row; + } + + // }}} + // {{{ function queryCol($query, $type = null, $colnum = 0) + + /** + * Execute the specified query, fetch the value from the first column of + * each row of the result set into an array and then frees the result set. + * + * @param string $query the SELECT query statement to be executed. + * @param string $type optional argument that specifies the expected + * datatype of the result set field, so that an eventual + * conversion may be performed. The default datatype is text, + * meaning that no conversion is performed + * @param mixed $colnum the column number (or name) to fetch + * + * @return mixed MDB2_OK or data array on success, a MDB2 error on failure + * @access public + */ + function queryCol($query, $type = null, $colnum = 0) + { + $result = $this->query($query, $type); + if (!MDB2::isResultCommon($result)) { + return $result; + } + + $col = $result->fetchCol($colnum); + $result->free(); + return $col; + } + + // }}} + // {{{ function queryAll($query, $types = null, $fetchmode = MDB2_FETCHMODE_DEFAULT, $rekey = false, $force_array = false, $group = false) + + /** + * Execute the specified query, fetch all the rows of the result set into + * a two dimensional array and then frees the result set. + * + * @param string the SELECT query statement to be executed. + * @param array optional array argument that specifies a list of + * expected datatypes of the result set columns, so that the eventual + * conversions may be performed. The default list of datatypes is + * empty, meaning that no conversion is performed. + * @param int how the array data should be indexed + * @param bool if set to true, the $all will have the first + * column as its first dimension + * @param bool 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 bool 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 mixed MDB2_OK or data array on success, a MDB2 error on failure + * + * @access public + */ + function queryAll($query, $types = null, $fetchmode = MDB2_FETCHMODE_DEFAULT, + $rekey = false, $force_array = false, $group = false) + { + $result = $this->query($query, $types); + if (!MDB2::isResultCommon($result)) { + return $result; + } + + $all = $result->fetchAll($fetchmode, $rekey, $force_array, $group); + $result->free(); + return $all; + } + + // }}} +} + +// }}} +// {{{ class MDB2_Result + +/** + * The dummy class that all user space result classes should extend from + * + * @package MDB2 + * @category Database + * @author Lukas Smith + */ +class MDB2_Result +{ +} + +// }}} +// {{{ class MDB2_Result_Common extends MDB2_Result + +/** + * The common result class for MDB2 result objects + * + * @package MDB2 + * @category Database + * @author Lukas Smith + */ +class MDB2_Result_Common extends MDB2_Result +{ + // {{{ Variables (Properties) + + var $db; + var $result; + var $rownum = -1; + var $types = array(); + var $values = array(); + var $offset; + var $offset_count = 0; + var $limit; + var $column_names; + + // }}} + // {{{ constructor: function __construct(&$db, &$result, $limit = 0, $offset = 0) + + /** + * Constructor + */ + function __construct(&$db, &$result, $limit = 0, $offset = 0) + { + $this->db =& $db; + $this->result =& $result; + $this->offset = $offset; + $this->limit = max(0, $limit - 1); + } + + // }}} + // {{{ function MDB2_Result_Common(&$db, &$result, $limit = 0, $offset = 0) + + /** + * PHP 4 Constructor + */ + function MDB2_Result_Common(&$db, &$result, $limit = 0, $offset = 0) + { + $this->__construct($db, $result, $limit, $offset); + } + + // }}} + // {{{ function setResultTypes($types) + + /** + * Define the list of types to be associated with the columns of a given + * result set. + * + * This function may be called before invoking fetchRow(), fetchOne(), + * fetchCol() and fetchAll() so that the necessary data type + * conversions are performed on the data to be retrieved by them. If this + * function is not called, the type of all result set columns is assumed + * to be text, thus leading to not perform any conversions. + * + * @param array variable that lists the + * data types to be expected in the result set columns. If this array + * contains less types than the number of columns that are returned + * in the result set, the remaining columns are assumed to be of the + * type text. Currently, the types clob and blob are not fully + * supported. + * + * @return mixed MDB2_OK on success, a MDB2 error on failure + * + * @access public + */ + function setResultTypes($types) + { + $load = $this->db->loadModule('Datatype', null, true); + if (PEAR::isError($load)) { + return $load; + } + $types = $this->db->datatype->checkResultTypes($types); + if (PEAR::isError($types)) { + return $types; + } + $this->types = $types; + return MDB2_OK; + } + + // }}} + // {{{ function seek($rownum = 0) + + /** + * Seek to a specific row in a result set + * + * @param int number of the row where the data can be found + * + * @return mixed MDB2_OK on success, a MDB2 error on failure + * + * @access public + */ + function seek($rownum = 0) + { + $target_rownum = $rownum - 1; + if ($this->rownum > $target_rownum) { + return $this->db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'seeking to previous rows not implemented', __FUNCTION__); + } + while ($this->rownum < $target_rownum) { + $this->fetchRow(); + } + return MDB2_OK; + } + + // }}} + // {{{ function &fetchRow($fetchmode = MDB2_FETCHMODE_DEFAULT, $rownum = null) + + /** + * Fetch and return a row of data + * + * @param int how the array data should be indexed + * @param int number of the row where the data can be found + * + * @return int data array on success, a MDB2 error on failure + * + * @access public + */ + function &fetchRow($fetchmode = MDB2_FETCHMODE_DEFAULT, $rownum = null) + { + $err =& $this->db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'method not implemented', __FUNCTION__); + return $err; + } + + // }}} + // {{{ function fetchOne($colnum = 0) + + /** + * fetch single column from the next row from a result set + * + * @param int|string the column number (or name) to fetch + * @param int number of the row where the data can be found + * + * @return string data on success, a MDB2 error on failure + * @access public + */ + function fetchOne($colnum = 0, $rownum = null) + { + $fetchmode = is_numeric($colnum) ? MDB2_FETCHMODE_ORDERED : MDB2_FETCHMODE_ASSOC; + $row = $this->fetchRow($fetchmode, $rownum); + if (!is_array($row) || PEAR::isError($row)) { + return $row; + } + if (!array_key_exists($colnum, $row)) { + return $this->db->raiseError(MDB2_ERROR_TRUNCATED, null, null, + 'column is not defined in the result set: '.$colnum, __FUNCTION__); + } + return $row[$colnum]; + } + + // }}} + // {{{ function fetchCol($colnum = 0) + + /** + * Fetch and return a column from the current row pointer position + * + * @param int|string the column number (or name) to fetch + * + * @return mixed data array on success, a MDB2 error on failure + * @access public + */ + function fetchCol($colnum = 0) + { + $column = array(); + $fetchmode = is_numeric($colnum) ? MDB2_FETCHMODE_ORDERED : MDB2_FETCHMODE_ASSOC; + $row = $this->fetchRow($fetchmode); + if (is_array($row)) { + if (!array_key_exists($colnum, $row)) { + return $this->db->raiseError(MDB2_ERROR_TRUNCATED, null, null, + 'column is not defined in the result set: '.$colnum, __FUNCTION__); + } + do { + $column[] = $row[$colnum]; + } while (is_array($row = $this->fetchRow($fetchmode))); + } + if (PEAR::isError($row)) { + return $row; + } + return $column; + } + + // }}} + // {{{ function fetchAll($fetchmode = MDB2_FETCHMODE_DEFAULT, $rekey = false, $force_array = false, $group = false) + + /** + * Fetch and return all rows from the current row pointer position + * + * @param int $fetchmode the fetch mode to use: + * + MDB2_FETCHMODE_ORDERED + * + MDB2_FETCHMODE_ASSOC + * + MDB2_FETCHMODE_ORDERED | MDB2_FETCHMODE_FLIPPED + * + MDB2_FETCHMODE_ASSOC | MDB2_FETCHMODE_FLIPPED + * @param bool if set to true, the $all will have the first + * column as its first dimension + * @param bool 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 bool 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 mixed data array on success, a MDB2 error on failure + * + * @access public + * @see getAssoc() + */ + function fetchAll($fetchmode = MDB2_FETCHMODE_DEFAULT, $rekey = false, + $force_array = false, $group = false) + { + $all = array(); + $row = $this->fetchRow($fetchmode); + if (PEAR::isError($row)) { + return $row; + } elseif (!$row) { + return $all; + } + + $shift_array = $rekey ? false : null; + if (!is_null($shift_array)) { + if (is_object($row)) { + $colnum = count(get_object_vars($row)); + } else { + $colnum = count($row); + } + if ($colnum < 2) { + return $this->db->raiseError(MDB2_ERROR_TRUNCATED, null, null, + 'rekey feature requires atleast 2 column', __FUNCTION__); + } + $shift_array = (!$force_array && $colnum == 2); + } + + if ($rekey) { + do { + if (is_object($row)) { + $arr = get_object_vars($row); + $key = reset($arr); + unset($row->{$key}); + } else { + if ($fetchmode & MDB2_FETCHMODE_ASSOC) { + $key = reset($row); + unset($row[key($row)]); + } else { + $key = array_shift($row); + } + if ($shift_array) { + $row = array_shift($row); + } + } + if ($group) { + $all[$key][] = $row; + } else { + $all[$key] = $row; + } + } while (($row = $this->fetchRow($fetchmode))); + } elseif ($fetchmode & MDB2_FETCHMODE_FLIPPED) { + do { + foreach ($row as $key => $val) { + $all[$key][] = $val; + } + } while (($row = $this->fetchRow($fetchmode))); + } else { + do { + $all[] = $row; + } while (($row = $this->fetchRow($fetchmode))); + } + + return $all; + } + + // }}} + // {{{ function rowCount() + /** + * Returns the actual row number that was last fetched (count from 0) + * @return int + * + * @access public + */ + function rowCount() + { + return $this->rownum + 1; + } + + // }}} + // {{{ function numRows() + + /** + * Returns the number of rows in a result object + * + * @return mixed MDB2 Error Object or the number of rows + * + * @access public + */ + function numRows() + { + return $this->db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'method not implemented', __FUNCTION__); + } + + // }}} + // {{{ function nextResult() + + /** + * Move the internal result pointer to the next available result + * + * @return true on success, false if there is no more result set or an error object on failure + * + * @access public + */ + function nextResult() + { + return $this->db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'method not implemented', __FUNCTION__); + } + + // }}} + // {{{ function getColumnNames() + + /** + * Retrieve the names of columns returned by the DBMS in a query result or + * from the cache. + * + * @param bool If set to true the values are the column names, + * otherwise the names of the columns are the keys. + * @return mixed Array variable that holds the names of columns or an + * MDB2 error on failure. + * Some DBMS may not return any columns when the result set + * does not contain any rows. + * + * @access public + */ + function getColumnNames($flip = false) + { + if (!isset($this->column_names)) { + $result = $this->_getColumnNames(); + if (PEAR::isError($result)) { + return $result; + } + $this->column_names = $result; + } + if ($flip) { + return array_flip($this->column_names); + } + return $this->column_names; + } + + // }}} + // {{{ function _getColumnNames() + + /** + * Retrieve the names of columns returned by the DBMS in a query result. + * + * @return mixed Array variable that holds the names of columns as keys + * or an MDB2 error on failure. + * Some DBMS may not return any columns when the result set + * does not contain any rows. + * + * @access private + */ + function _getColumnNames() + { + return $this->db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'method not implemented', __FUNCTION__); + } + + // }}} + // {{{ function numCols() + + /** + * Count the number of columns returned by the DBMS in a query result. + * + * @return mixed integer value with the number of columns, a MDB2 error + * on failure + * + * @access public + */ + function numCols() + { + return $this->db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null, + 'method not implemented', __FUNCTION__); + } + + // }}} + // {{{ function getResource() + + /** + * return the resource associated with the result object + * + * @return resource + * + * @access public + */ + function getResource() + { + return $this->result; + } + + // }}} + // {{{ function bindColumn($column, &$value, $type = null) + + /** + * Set bind variable to a column. + * + * @param int column number or name + * @param mixed variable reference + * @param string specifies the type of the field + * + * @return mixed MDB2_OK on success, a MDB2 error on failure + * + * @access public + */ + function bindColumn($column, &$value, $type = null) + { + if (!is_numeric($column)) { + $column_names = $this->getColumnNames(); + if ($this->db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) { + if ($this->db->options['field_case'] == CASE_LOWER) { + $column = strtolower($column); + } else { + $column = strtoupper($column); + } + } + $column = $column_names[$column]; + } + $this->values[$column] =& $value; + if (!is_null($type)) { + $this->types[$column] = $type; + } + return MDB2_OK; + } + + // }}} + // {{{ function _assignBindColumns($row) + + /** + * Bind a variable to a value in the result row. + * + * @param array row data + * + * @return mixed MDB2_OK on success, a MDB2 error on failure + * + * @access private + */ + function _assignBindColumns($row) + { + $row = array_values($row); + foreach ($row as $column => $value) { + if (array_key_exists($column, $this->values)) { + $this->values[$column] = $value; + } + } + return MDB2_OK; + } + + // }}} + // {{{ function free() + + /** + * Free the internal resources associated with result. + * + * @return bool true on success, false if result is invalid + * + * @access public + */ + function free() + { + $this->result = false; + return MDB2_OK; + } + + // }}} +} + +// }}} +// {{{ class MDB2_Row + +/** + * The simple class that accepts row data as an array + * + * @package MDB2 + * @category Database + * @author Lukas Smith + */ +class MDB2_Row +{ + // {{{ constructor: function __construct(&$row) + + /** + * constructor + * + * @param resource row data as array + */ + function __construct(&$row) + { + foreach ($row as $key => $value) { + $this->$key = &$row[$key]; + } + } + + // }}} + // {{{ function MDB2_Row(&$row) + + /** + * PHP 4 Constructor + * + * @param resource row data as array + */ + function MDB2_Row(&$row) + { + $this->__construct($row); + } + + // }}} +} + +// }}} +// {{{ class MDB2_Statement_Common + +/** + * The common statement class for MDB2 statement objects + * + * @package MDB2 + * @category Database + * @author Lukas Smith + */ +class MDB2_Statement_Common +{ + // {{{ Variables (Properties) + + var $db; + var $statement; + var $query; + var $result_types; + var $types; + var $values = array(); + var $limit; + var $offset; + var $is_manip; + + // }}} + // {{{ constructor: function __construct(&$db, &$statement, $positions, $query, $types, $result_types, $is_manip = false, $limit = null, $offset = null) + + /** + * Constructor + */ + function __construct(&$db, &$statement, $positions, $query, $types, $result_types, $is_manip = false, $limit = null, $offset = null) + { + $this->db =& $db; + $this->statement =& $statement; + $this->positions = $positions; + $this->query = $query; + $this->types = (array)$types; + $this->result_types = (array)$result_types; + $this->limit = $limit; + $this->is_manip = $is_manip; + $this->offset = $offset; + } + + // }}} + // {{{ function MDB2_Statement_Common(&$db, &$statement, $positions, $query, $types, $result_types, $is_manip = false, $limit = null, $offset = null) + + /** + * PHP 4 Constructor + */ + function MDB2_Statement_Common(&$db, &$statement, $positions, $query, $types, $result_types, $is_manip = false, $limit = null, $offset = null) + { + $this->__construct($db, $statement, $positions, $query, $types, $result_types, $is_manip, $limit, $offset); + } + + // }}} + // {{{ function bindValue($parameter, &$value, $type = null) + + /** + * Set the value of a parameter of a prepared query. + * + * @param int the order number of the parameter in the query + * statement. The order number of the first parameter is 1. + * @param mixed value that is meant to be assigned to specified + * parameter. The type of the value depends on the $type argument. + * @param string specifies the type of the field + * + * @return mixed MDB2_OK on success, a MDB2 error on failure + * + * @access public + */ + function bindValue($parameter, $value, $type = null) + { + if (!is_numeric($parameter)) { + $parameter = preg_replace('/^:(.*)$/', '\\1', $parameter); + } + if (!in_array($parameter, $this->positions)) { + return $this->db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, + 'Unable to bind to missing placeholder: '.$parameter, __FUNCTION__); + } + $this->values[$parameter] = $value; + if (!is_null($type)) { + $this->types[$parameter] = $type; + } + return MDB2_OK; + } + + // }}} + // {{{ function bindValueArray($values, $types = null) + + /** + * Set the values of multiple a parameter of a prepared query in bulk. + * + * @param array specifies all necessary information + * for bindValue() the array elements must use keys corresponding to + * the number of the position of the parameter. + * @param array specifies the types of the fields + * + * @return mixed MDB2_OK on success, a MDB2 error on failure + * + * @access public + * @see bindParam() + */ + function bindValueArray($values, $types = null) + { + $types = is_array($types) ? array_values($types) : array_fill(0, count($values), null); + $parameters = array_keys($values); + foreach ($parameters as $key => $parameter) { + $this->db->pushErrorHandling(PEAR_ERROR_RETURN); + $this->db->expectError(MDB2_ERROR_NOT_FOUND); + $err = $this->bindValue($parameter, $values[$parameter], $types[$key]); + $this->db->popExpect(); + $this->db->popErrorHandling(); + if (PEAR::isError($err)) { + if ($err->getCode() == MDB2_ERROR_NOT_FOUND) { + //ignore (extra value for missing placeholder) + continue; + } + return $err; + } + } + return MDB2_OK; + } + + // }}} + // {{{ function bindParam($parameter, &$value, $type = null) + + /** + * Bind a variable to a parameter of a prepared query. + * + * @param int the order number of the parameter in the query + * statement. The order number of the first parameter is 1. + * @param mixed variable that is meant to be bound to specified + * parameter. The type of the value depends on the $type argument. + * @param string specifies the type of the field + * + * @return mixed MDB2_OK on success, a MDB2 error on failure + * + * @access public + */ + function bindParam($parameter, &$value, $type = null) + { + if (!is_numeric($parameter)) { + $parameter = preg_replace('/^:(.*)$/', '\\1', $parameter); + } + if (!in_array($parameter, $this->positions)) { + return $this->db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, + 'Unable to bind to missing placeholder: '.$parameter, __FUNCTION__); + } + $this->values[$parameter] =& $value; + if (!is_null($type)) { + $this->types[$parameter] = $type; + } + return MDB2_OK; + } + + // }}} + // {{{ function bindParamArray(&$values, $types = null) + + /** + * Bind the variables of multiple a parameter of a prepared query in bulk. + * + * @param array specifies all necessary information + * for bindParam() the array elements must use keys corresponding to + * the number of the position of the parameter. + * @param array specifies the types of the fields + * + * @return mixed MDB2_OK on success, a MDB2 error on failure + * + * @access public + * @see bindParam() + */ + function bindParamArray(&$values, $types = null) + { + $types = is_array($types) ? array_values($types) : array_fill(0, count($values), null); + $parameters = array_keys($values); + foreach ($parameters as $key => $parameter) { + $err = $this->bindParam($parameter, $values[$parameter], $types[$key]); + if (PEAR::isError($err)) { + return $err; + } + } + return MDB2_OK; + } + + // }}} + // {{{ function &execute($values = null, $result_class = true, $result_wrap_class = false) + + /** + * Execute a prepared query statement. + * + * @param array specifies all necessary information + * for bindParam() the array elements must use keys corresponding + * to the number of the position of the parameter. + * @param mixed specifies which result class to use + * @param mixed specifies which class to wrap results in + * + * @return mixed MDB2_Result or integer (affected rows) on success, + * a MDB2 error on failure + * @access public + */ + function &execute($values = null, $result_class = true, $result_wrap_class = false) + { + if (is_null($this->positions)) { + return $this->db->raiseError(MDB2_ERROR, null, null, + 'Prepared statement has already been freed', __FUNCTION__); + } + + $values = (array)$values; + if (!empty($values)) { + $err = $this->bindValueArray($values); + if (PEAR::isError($err)) { + return $this->db->raiseError(MDB2_ERROR, null, null, + 'Binding Values failed with message: ' . $err->getMessage(), __FUNCTION__); + } + } + $result =& $this->_execute($result_class, $result_wrap_class); + return $result; + } + + // }}} + // {{{ function &_execute($result_class = true, $result_wrap_class = false) + + /** + * Execute a prepared query statement helper method. + * + * @param mixed specifies which result class to use + * @param mixed specifies which class to wrap results in + * + * @return mixed MDB2_Result or integer (affected rows) on success, + * a MDB2 error on failure + * @access private + */ + function &_execute($result_class = true, $result_wrap_class = false) + { + $this->last_query = $this->query; + $query = ''; + $last_position = 0; + foreach ($this->positions as $current_position => $parameter) { + if (!array_key_exists($parameter, $this->values)) { + return $this->db->raiseError(MDB2_ERROR_NOT_FOUND, null, null, + 'Unable to bind to missing placeholder: '.$parameter, __FUNCTION__); + } + $value = $this->values[$parameter]; + $query.= substr($this->query, $last_position, $current_position - $last_position); + if (!isset($value)) { + $value_quoted = 'NULL'; + } else { + $type = !empty($this->types[$parameter]) ? $this->types[$parameter] : null; + $value_quoted = $this->db->quote($value, $type); + if (PEAR::isError($value_quoted)) { + return $value_quoted; + } + } + $query.= $value_quoted; + $last_position = $current_position + 1; + } + $query.= substr($this->query, $last_position); + + $this->db->offset = $this->offset; + $this->db->limit = $this->limit; + if ($this->is_manip) { + $result = $this->db->exec($query); + } else { + $result =& $this->db->query($query, $this->result_types, $result_class, $result_wrap_class); + } + return $result; + } + + // }}} + // {{{ function free() + + /** + * Release resources allocated for the specified prepared query. + * + * @return mixed MDB2_OK on success, a MDB2 error on failure + * + * @access public + */ + function free() + { + if (is_null($this->positions)) { + return $this->db->raiseError(MDB2_ERROR, null, null, + 'Prepared statement has already been freed', __FUNCTION__); + } + + $this->statement = null; + $this->positions = null; + $this->query = null; + $this->types = null; + $this->result_types = null; + $this->limit = null; + $this->is_manip = null; + $this->offset = null; + $this->values = null; + + return MDB2_OK; + } + + // }}} +} + +// }}} +// {{{ class MDB2_Module_Common + +/** + * The common modules class for MDB2 module objects + * + * @package MDB2 + * @category Database + * @author Lukas Smith + */ +class MDB2_Module_Common +{ + // {{{ Variables (Properties) + + /** + * contains the key to the global MDB2 instance array of the associated + * MDB2 instance + * + * @var int + * @access protected + */ + var $db_index; + + // }}} + // {{{ constructor: function __construct($db_index) + + /** + * Constructor + */ + function __construct($db_index) + { + $this->db_index = $db_index; + } + + // }}} + // {{{ function MDB2_Module_Common($db_index) + + /** + * PHP 4 Constructor + */ + function MDB2_Module_Common($db_index) + { + $this->__construct($db_index); + } + + // }}} + // {{{ function &getDBInstance() + + /** + * Get the instance of MDB2 associated with the module instance + * + * @return object MDB2 instance or a MDB2 error on failure + * + * @access public + */ + function &getDBInstance() + { + if (isset($GLOBALS['_MDB2_databases'][$this->db_index])) { + $result =& $GLOBALS['_MDB2_databases'][$this->db_index]; + } else { + $result =& MDB2::raiseError(MDB2_ERROR_NOT_FOUND, null, null, + 'could not find MDB2 instance'); + } + return $result; + } + + // }}} +} + +// }}} +// {{{ function MDB2_closeOpenTransactions() + +/** + * Close any open transactions form persistent connections + * + * @return void + * + * @access public + */ + +function MDB2_closeOpenTransactions() +{ + reset($GLOBALS['_MDB2_databases']); + while (next($GLOBALS['_MDB2_databases'])) { + $key = key($GLOBALS['_MDB2_databases']); + if ($GLOBALS['_MDB2_databases'][$key]->opened_persistent + && $GLOBALS['_MDB2_databases'][$key]->in_transaction + ) { + $GLOBALS['_MDB2_databases'][$key]->rollback(); + } + } +} + +// }}} +// {{{ function MDB2_defaultDebugOutput(&$db, $scope, $message, $is_manip = null) + +/** + * default debug output handler + * + * @param object reference to an MDB2 database object + * @param string usually the method name that triggered the debug call: + * for example 'query', 'prepare', 'execute', 'parameters', + * 'beginTransaction', 'commit', 'rollback' + * @param string message that should be appended to the debug variable + * @param array contains context information about the debug() call + * common keys are: is_manip, time, result etc. + * + * @return void|string optionally return a modified message, this allows + * rewriting a query before being issued or prepared + * + * @access public + */ +function MDB2_defaultDebugOutput(&$db, $scope, $message, $context = array()) +{ + $db->debug_output.= $scope.'('.$db->db_index.'): '; + $db->debug_output.= $message.$db->getOption('log_line_break'); + return $message; +} + +// }}} +?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/tests/basic.phpt /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/basic.phpt --- php-mdb2-2.4.1/MDB2-2.5.0b2/tests/basic.phpt 1970-01-01 01:00:00.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/basic.phpt 2009-01-14 16:28:08.000000000 +0000 @@ -0,0 +1,26 @@ +--TEST-- +MDB2: Basic connectivity +--FILE-- +connect(); + +if (PEAR::isError($e)) { + print $e->getMessage() . "\n"; +} + +die(); + + +?> +echo 'Success!'; + +--EXPECT-- +Success! diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/tests/clitest.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/clitest.php --- php-mdb2-2.4.1/MDB2-2.5.0b2/tests/clitest.php 1970-01-01 01:00:00.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/clitest.php 2009-01-14 16:28:08.000000000 +0000 @@ -0,0 +1,134 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: clitest.php,v 1.15 2006/10/20 16:36:32 lsmith Exp $ + +/* + This is a small test suite for MDB2 using PHPUnit + + This is the command line version and should be used like so; + + php -q clitest.php + + This will run through all tests in all testcases (as defined in + test_setup.php). To run individual tests add their names to the command + line and all testcases will be searched for matching test names, e.g. + + php -q clitest.php teststorage testreplace +*/ + +require_once 'test_setup.php'; +require_once 'PHPUnit.php'; +require_once 'testUtils.php'; +require_once 'MDB2.php'; +require_once 'Console_TestListener.php'; + +MDB2::loadFile('Date'); + +foreach ($testcases as $testcase) { + include_once $testcase.'.php'; +} + +$database = 'driver_test'; + +$inputMethods = $argv; + +if ($argc > 1) { + array_shift($inputMethods); + $exclude = false; + if ($inputMethods[0] == '-exclude') { + array_shift($inputMethods); + $exclude = true; + } + foreach ($testcases as $testcase) { + $possibleMethods = getTests($testcase); + if ($exclude) { + $intersect = array_diff($possibleMethods, $inputMethods); + } else { + $intersect = array_intersect($possibleMethods, $inputMethods); + } + if (count($intersect) > 0) { + $testmethods[$testcase] = array_flip($intersect); + } + } +} + +$database = 'driver_test'; + +if (!isset($testmethods) || !is_array($testmethods)) { + foreach ($testcases as $testcase) { + $testmethods[$testcase] = array_flip(getTests($testcase)); + } +} + +foreach ($dbarray as $db) { + $dsn = $db['dsn']; + $options = !empty($db['options']) ? $db['options'] : array(); + $GLOBALS['_show_silenced'] = !empty($options['debug']) ? $options['debug'] : false; + + $display_dsn = $dsn['phptype'] . "://" . $dsn['username'] . ":XXX@" . $dsn['hostspec'] . "/" . $database; + echo "=== Start test of $display_dsn on ".PHP_VERSION." ===\n"; + + $suite = new PHPUnit_TestSuite(); + + foreach ($testcases as $testcase) { + if (is_array($testmethods[$testcase])) { + $methods = array_keys($testmethods[$testcase]); + foreach ($methods as $method) { + $suite->addTest(new $testcase($method)); + } + } + } + + $result = new PHPUnit_TestResult; + $result->addListener(new Console_TestListener); + + $suite->run($result); + $count = $result->runCount(); + $failed = $result->failureCount(); + + echo "=== Summary: $failed failed assertions in $count tests ===\n\n"; + echo "=== End test of $display_dsn ===\n\n"; +} + +?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/tests/config.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/config.php --- php-mdb2-2.4.1/MDB2-2.5.0b2/tests/config.php 1970-01-01 01:00:00.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/config.php 2009-01-14 16:28:08.000000000 +0000 @@ -0,0 +1,19 @@ + diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/tests/Console_TestListener.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/Console_TestListener.php --- php-mdb2-2.4.1/MDB2-2.5.0b2/tests/Console_TestListener.php 1970-01-01 01:00:00.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/Console_TestListener.php 2009-01-14 16:28:08.000000000 +0000 @@ -0,0 +1,32 @@ +_errors += 1; + echo(" Error $this->_errors in ".$test->getName()." : $t\n"); + } + + function addFailure(&$test, &$t) { + $this->_fails += 1; + if ($this->_fails == 1) { + echo("\n"); + } + echo("Failure $this->_fails : $t\n"); + } + + function endTest(&$test) { + if ($this->_fails == 0 && $this->_errors == 0) { + echo(' Test passed'); + } else { + echo("There were $this->_fails failures for ".$test->getName()."\n"); + echo("There were $this->_errors errors for ".$test->getName()."\n"); + } + echo("\n"); + } + + function startTest(&$test) { + $this->_fails = 0; + $this->_errors = 0; + echo(get_class($test).' : Starting '.$test->getName().' ...'); + } +} +?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/tests/driver_test.schema.xml /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/driver_test.schema.xml --- php-mdb2-2.4.1/MDB2-2.5.0b2/tests/driver_test.schema.xml 1970-01-01 01:00:00.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/driver_test.schema.xml 2009-01-14 16:28:08.000000000 +0000 @@ -0,0 +1,49 @@ + + + + + + name + create + + + + users + + user_name text 12 false + user_password text 8 true + subscribed boolean + user_id integer 0 1 1 + quota decimal + weight float + access_date date + access_time time + approved timestamp + + users_id_index + 1 + user_id + + +
    + + + files + + id integer 0 1 + document clob + picture blob + + lob_id_index + 1 + id + + +
    + +
    diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/tests/HTML_TestListener.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/HTML_TestListener.php --- php-mdb2-2.4.1/MDB2-2.5.0b2/tests/HTML_TestListener.php 1970-01-01 01:00:00.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/HTML_TestListener.php 2009-01-14 16:28:08.000000000 +0000 @@ -0,0 +1,34 @@ +_errors += 1; + echo("
    Error $this->_errors in ".$test->getName()." : $t
    "); + } + + function addFailure(&$test, &$t) { + $this->_fails += 1; + if ($this->_fails == 1) { + echo("\n
    "); + } + echo("Failure $this->_fails : $t
    \n"); + } + + function endTest(&$test) { + if ($this->_fails == 0 && $this->_errors == 0) { + echo(' Test passed'); + } else { + echo("There were $this->_fails failures for ".$test->getName()."
    \n"); + echo("There were $this->_errors errors for ".$test->getName()."
    \n"); + } + echo(''); + } + + function startTest(&$test) { + $this->_fails = 0; + $this->_errors = 0; + echo("\n
    ".get_class($test).' : Starting '.$test->getName().' ...'); + } +} + +?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/tests/import.schema.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/import.schema.php --- php-mdb2-2.4.1/MDB2-2.5.0b2/tests/import.schema.php 1970-01-01 01:00:00.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/import.schema.php 2009-01-14 16:28:08.000000000 +0000 @@ -0,0 +1,45 @@ + 'mysql', + 'username' => 'username', + 'password' => 'password', + 'hostspec' => 'host', +); +$db_options = array(); + + +$file = dirname(__FILE__).DIRECTORY_SEPARATOR.'driver_test.schema.xml'; +$variables = array( + 'name' => 'driver_test', + 'create' => true, +); + +$options = array( + 'log_line_break' => '
    ', + 'idxname_format' => '%s', + 'debug' => true, + 'quote_identifier' => true, + 'force_defaults' => false, + 'portability' => false +); +$options = array_merge($options, $db_options); + +$schema =& MDB2_Schema::factory($dsn, $options); +if (PEAR::isError($schema)) { + echo $schema->getMessage() . ' ' . $schema->getUserInfo(); + exit; +} + +$definition = $schema->parseDatabaseDefinitionFile($file, $variables, true, true); +if (PEAR::isError($definition)) { + echo $definition->getMessage() . ' - ' . $definition->getUserInfo(); +} else { + $operation = $schema->createDatabase($definition); + if (PEAR::isError($operation)) { + echo $operation->getMessage() . ' ' . $operation->getUserInfo(); + } +} +?> +DONE! \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/tests/MDB2_api_testcase.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/MDB2_api_testcase.php --- php-mdb2-2.4.1/MDB2-2.5.0b2/tests/MDB2_api_testcase.php 1970-01-01 01:00:00.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/MDB2_api_testcase.php 2009-01-14 16:28:08.000000000 +0000 @@ -0,0 +1,321 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: MDB2_api_testcase.php,v 1.24 2007/10/15 21:57:42 quipo Exp $ + +require_once 'MDB2_testcase.php'; + +class MDB2_Api_TestCase extends MDB2_TestCase { + var $clear_tables = false; + + function testParseDSN() { + $expected = array ( + 'phptype' => 'phptype', + 'dbsyntax' => 'phptype', + 'username' => 'username', + 'password' => 'password', + 'protocol' => 'protocol', + 'hostspec' => false, + 'port' => '110', + 'socket' => false, + 'database' => '/usr/db_file.db', + 'mode' => false, + ); + $original = 'phptype://username:password@protocol+hostspec:110//usr/db_file.db?mode=0644'; + $this->assertEquals($expected, MDB2::parseDSN($original)); + + // --------------------------------------------------------------------- + + $original = 'phptype(dbsyntax)://username:password@hostspec/database_name'; + $expected = array ( + 'phptype' => 'phptype', + 'dbsyntax' => 'dbsyntax', + 'username' => 'username', + 'password' => 'password', + 'protocol' => 'tcp', + 'hostspec' => 'hostspec', + 'port' => false, + 'socket' => false, + 'database' => 'database_name', + 'mode' => false, + ); + $this->assertEquals($expected, MDB2::parseDSN($original)); + + // --------------------------------------------------------------------- + + $original = 'phptype://username:password@hostspec/database_name'; + $expected['dbsyntax'] = 'phptype'; + $this->assertEquals($expected, MDB2::parseDSN($original)); + + // --------------------------------------------------------------------- + + $original = 'phptype://username:password@hostspec'; + $expected['database'] = false; + $this->assertEquals($expected, MDB2::parseDSN($original)); + + // --------------------------------------------------------------------- + + $original = 'phptype://username@hostspec'; + $expected['password'] = false; + $this->assertEquals($expected, MDB2::parseDSN($original)); + + // --------------------------------------------------------------------- + + $original = 'phptype://hostspec/database'; + $expected['username'] = false; + $expected['database'] = 'database'; + $this->assertEquals($expected, MDB2::parseDSN($original)); + + // --------------------------------------------------------------------- + + $original = 'phptype(dbsyntax)'; + $expected['database'] = false; + $expected['hostspec'] = false; + $expected['protocol'] = false; + $expected['dbsyntax'] = 'dbsyntax'; + $this->assertEquals($expected, MDB2::parseDSN($original)); + + // --------------------------------------------------------------------- + + //oracle's "Easy Connect" syntax (Oracle 10g, @see Bug #4854) + $original = 'oci8://scott:tiger@//localhost/XE'; + $expected = array ( + 'phptype' => 'oci8', + 'dbsyntax' => 'oci8', + 'username' => 'scott', + 'password' => 'tiger', + 'protocol' => 'tcp', + 'hostspec' => '//localhost/XE', + 'port' => false, + 'socket' => false, + 'database' => false, + 'mode' => false, + ); + $this->assertEquals($expected, MDB2::parseDSN($original)); + + // --------------------------------------------------------------------- + + //ibase dbname+path on windows + $original = 'ibase://user:pwd@localhost/C:\\PATH_TO_DB\\TEST.FDB'; + $expected = array ( + 'phptype' => 'ibase', + 'dbsyntax' => 'ibase', + 'username' => 'user', + 'password' => 'pwd', + 'protocol' => 'tcp', + 'hostspec' => 'localhost', + 'port' => false, + 'socket' => false, + 'database' => 'C:\\PATH_TO_DB\\TEST.FDB', + 'mode' => false, + ); + $this->assertEquals($expected, MDB2::parseDSN($original)); + + // --------------------------------------------------------------------- + + //sqlite dbname+path on unix + $original = 'sqlite:////full/unix/path/to/file.db?mode=0666'; + $expected = array ( + 'phptype' => 'sqlite', + 'dbsyntax' => 'sqlite', + 'username' => false, + 'password' => false, + 'protocol' => 'tcp', + 'hostspec' => '', + 'port' => false, + 'socket' => false, + 'database' => '/full/unix/path/to/file.db', + 'mode' => false, + ); + $this->assertEquals($expected, MDB2::parseDSN($original)); + } + + //test stuff in common.php + function testConnect() { + $db =& MDB2::factory($this->dsn, $this->options); + if (PEAR::isError($db)) { + $this->assertTrue(false, 'Connect failed bailing out - ' .$db->getMessage() . ' - ' .$db->getUserInfo()); + } + if (PEAR::isError($this->db)) { + exit; + } + } + + function testGetOption() { + if (!$this->methodExists($this->db, 'getOption')) { + return; + } + $option = $this->db->getOption('persistent'); + $this->assertEquals($option, $this->db->options['persistent']); + } + + function testSetOption() { + if (!$this->methodExists($this->db, 'setOption')) { + return; + } + $option = $this->db->getOption('persistent'); + $this->db->setOption('persistent', !$option); + $this->assertEquals(!$option, $this->db->getOption('persistent')); + $this->db->setOption('persistent', $option); + } + + function testLoadModule() { + if (!$this->methodExists($this->db, 'loadModule')) { + return; + } + $this->assertTrue(!PEAR::isError($this->db->loadModule('Manager', null, true))); + } + + // test of the driver + // helper function so that we don't have to write out a query a million times + function standardQuery() { + $query = 'SELECT * FROM users'; + // run the query and get a result handler + if (!PEAR::isError($this->db)) { + return $this->db->query($query); + } + return false; + } + + function testQuery() { + if (!$this->methodExists($this->db, 'query')) { + return; + } + $result = $this->standardQuery(); + $this->assertTrue(MDB2::isResult($result), 'query: $result returned is not a resource'); + $this->assertTrue(MDB2::isResultCommon($result), 'query: $result returned is not a resource'); + } + + function testExec() { + if (!$this->methodExists($this->db, 'exec')) { + return; + } + $result = $this->db->exec('UPDATE users SET user_name = user_name WHERE user_id = user_id'); + $this->assertFalse(PEAR::isError($result), 'exec: $result returned is an error'); + $this->assertEquals(0, $result, 'exec: incorrect number of affected rows returned'); + } + + function testPrepare() { + if (!$this->methodExists($this->db, 'prepare')) { + return; + } + $stmt = $this->db->prepare('SELECT user_name FROM users WHERE user_id = ?', array('integer'), MDB2_PREPARE_RESULT); + $this->assertTrue(MDB2::isStatement($stmt)); + $stmt->free(); + } + + function testFetchRow() { + $result = $this->standardQuery(); + if (!$this->methodExists($result, 'fetchRow')) { + return; + } + $err = $result->fetchRow(); + $result->free(); + + if (PEAR::isError($err)) { + $this->assertTrue(false, 'Error testFetch: '.$err->getMessage().' - '.$err->getUserInfo()); + } + } + + function testNumRows() { + $result = $this->standardQuery(); + if (!$this->methodExists($result, 'numRows')) { + return; + } + $numrows = $result->numRows(); + $this->assertTrue(!PEAR::isError($numrows) && is_int($numrows)); + $result->free(); + } + + function testNumCols() { + $result = $this->standardQuery(); + if (!$this->methodExists($result, 'numCols')) { + return; + } + $numcols = $result->numCols(); + $this->assertTrue(!PEAR::isError($numcols) && $numcols > 0); + $result->free(); + } + + function testSingleton() { + $db =& MDB2::singleton(); + $this->assertTrue(MDB2::isConnection($db)); + + // should have a different database name set + $db =& MDB2::singleton($this->dsn, $this->options); + + $this->assertTrue($db->db_index != $this->db->db_index); + } + + function testGetServerVersion() { + $server_info = $this->db->getServerVersion(true); + if (PEAR::isError($server_info)) { + $this->assertTrue(false, 'Error: '.$server_info->getMessage().' - '.$server_info->getUserInfo()); + } else { + $this->assertTrue(is_string($server_info), 'Error: Server info is not returned as a string: '. serialize($server_info)); + } + $server_info = $this->db->getServerVersion(); + if (PEAR::isError($server_info)) { + $this->assertTrue(false, 'Error: '.$server_info->getMessage().' - '.$server_info->getUserInfo()); + } else { + $this->assertTrue(is_array($server_info), 'Error: Server info is not returned as an array: '. serialize($server_info)); + } + } + + function testQuoteIdentifier() { + if ($this->db->phptype != 'ibase') { + $start = $this->db->identifier_quoting['start']; + $end = $this->db->identifier_quoting['end']; + + $string = 'test'; + $expected = $start . $string . $end; + $this->assertEquals($expected, $this->db->quoteIdentifier($string, false), 'Error: identifier not quoted properly'); + + $string = 'test.test'; + $expected = $start . 'test' . $end . '.' . $start . 'test' . $end; + $this->assertEquals($expected, $this->db->quoteIdentifier($string, false), 'Error: identifier not quoted properly'); + } + } +} + +?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/tests/MDB2_bugs_testcase.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/MDB2_bugs_testcase.php --- php-mdb2-2.4.1/MDB2-2.5.0b2/tests/MDB2_bugs_testcase.php 1970-01-01 01:00:00.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/MDB2_bugs_testcase.php 2009-01-14 16:28:08.000000000 +0000 @@ -0,0 +1,291 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: MDB2_bugs_testcase.php,v 1.31 2006/12/09 16:58:16 quipo Exp $ + +require_once 'MDB2_testcase.php'; + +class MDB2_Bugs_TestCase extends MDB2_TestCase { + /** + * + */ + function testFetchModeBug() { + $data = array(); + + $stmt = $this->db->prepare('INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)', array_values($this->fields), MDB2_PREPARE_MANIP); + + $data['user_name'] = 'user_='; + $data['user_password'] = 'somepass'; + $data['subscribed'] = true; + $data['user_id'] = 0; + $data['quota'] = sprintf("%.2f", strval(2/100)); + $data['weight'] = sqrt(0); + $data['access_date'] = MDB2_Date::mdbToday(); + $data['access_time'] = MDB2_Date::mdbTime(); + $data['approved'] = MDB2_Date::mdbNow(); + + $result = $stmt->execute(array_values($data)); + + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error executing prepared query '.$result->getMessage()); + } + + $stmt->free(); + + $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users ORDER BY user_name'; + $result =& $this->db->query($query); + + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error selecting from users: '.$result->getMessage()); + } + + $this->db->setFetchMode(MDB2_FETCHMODE_ASSOC); + + $firstRow = $result->fetchRow(); + $this->assertEquals($firstRow['user_name'], $data['user_name'], 'The data returned does not match that expected'); + + $result =& $this->db->query('SELECT user_name, user_id, quota FROM users ORDER BY user_name'); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error selecting from users: '.$result->getMessage()); + } + $this->db->setFetchMode(MDB2_FETCHMODE_ORDERED); + + $value = $result->fetchOne(); + $this->assertEquals($data['user_name'], $value, 'The data returned does not match that expected'); + $result->free(); + } + + /** + * @see http://bugs.php.net/bug.php?id=22328 + */ + function testBug22328() { + $result =& $this->db->query('SELECT * FROM users'); + $this->db->pushErrorHandling(PEAR_ERROR_RETURN); + $result2 = $this->db->query('SELECT * FROM foo'); + + $data = $result->fetchRow(); + $this->db->popErrorHandling(); + $this->assertFalse(PEAR::isError($data), 'Error messages for a query affect result reading of other queries'); + } + + /** + * @see http://pear.php.net/bugs/bug.php?id=670 + */ + function testBug670() { + $data['user_name'] = null; + $data['user_password'] = 'somepass'; + $data['subscribed'] = true; + $data['user_id'] = 1; + $data['quota'] = sprintf("%.2f",strval(3/100)); + $data['weight'] = sqrt(1); + $data['access_date'] = MDB2_Date::mdbToday(); + $data['access_time'] = MDB2_Date::mdbTime(); + $data['approved'] = MDB2_Date::mdbNow(); + + $stmt = $this->db->prepare('INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)', array_values($this->fields), MDB2_PREPARE_MANIP); + $result = $stmt->execute(array_values($data)); + + $result =& $this->db->query('SELECT user_name FROM users'); + $col = $result->fetchCol('user_name'); + if (PEAR::isError($col)) { + $this->assertTrue(false, 'Error when fetching column first first row as NULL: '.$col->getMessage()); + } + + $data['user_name'] = "user_1"; + $data['user_id'] = 2; + + $result = $stmt->execute(array_values($data)); + + $result =& $this->db->query('SELECT user_name FROM users'); + $col = $result->fetchCol('user_name'); + if (PEAR::isError($col)) { + $this->assertTrue(false, 'Error when fetching column: '.$col->getMessage()); + } + + $data['user_name'] = null; + + $stmt->free(); + } + + /** + * @see http://pear.php.net/bugs/bug.php?id=681 + */ + function testBug681() { + $result =& $this->db->query('SELECT * FROM users WHERE 1=0'); + + $numrows = $result->numRows(); + $this->assertEquals(0, $numrows, 'Numrows is not returning 0 for empty result sets'); + + $data = $this->getSampleData(1); + + $stmt = $this->db->prepare('INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)', array_values($this->fields), MDB2_PREPARE_MANIP); + $result = $stmt->execute(array_values($data)); + + $result =& $this->db->query('SELECT * FROM users'); + $numrows = $result->numRows(); + $this->assertEquals(1, $numrows, 'Numrows is not returning proper value'); + + $stmt->free(); + } + + /** + * @see http://pear.php.net/bugs/bug.php?id=718 + */ + function testBug718() { + $data = $this->getSampleData(1); + + $stmt = $this->db->prepare('INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)', array_values($this->fields), MDB2_PREPARE_MANIP); + $result = $stmt->execute(array_values($data)); + + $row = $this->db->queryRow('SELECT a.user_id, b.user_id FROM users a, users b where a.user_id = b.user_id', array('integer', 'integer'), MDB2_FETCHMODE_ORDERED); + $this->assertEquals(2, count($row), "Columns with the same name get overwritten in ordered mode"); + + $stmt->free(); + } + + /** + * @see http://pear.php.net/bugs/bug.php?id=946 + */ + function testBug946() { + $data = array(); + $total_rows = 5; + + $stmt = $this->db->prepare('INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)', array_values($this->fields), MDB2_PREPARE_MANIP); + + for ($row = 0; $row < $total_rows; $row++) { + $data[$row] = $this->getSampleData($row); + + $result = $stmt->execute(array_values($data[$row])); + + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error executing prepared query: '.$result->getMessage()); + } + } + $stmt->free(); + + $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users'; + + $this->db->setLimit(3, 1); + $result =& $this->db->query($query); + $numrows = $result->numRows(); + while ($row = $result->fetchRow()) { + if (PEAR::isError($row)) { + $this->assertTrue(false, 'Error fetching a row: '.$row->getMessage()); + } + } + $result->free(); + + $result =& $this->db->query($query); + $numrows = $result->numRows(); + while ($row = $result->fetchRow()) { + if (PEAR::isError($row)) { + $this->assertTrue(false, 'Error fetching a row: '.$row->getMessage()); + } + } + $result->free(); + } + + /** + * @see http://pear.php.net/bugs/bug.php?id=3146 + */ + function testBug3146() { + $data = array(); + $total_rows = 5; + + $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')'; + $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP); + + for ($row = 0; $row < $total_rows; $row++) { + $data[$row] = $this->getSampleData($row); + + $result = $stmt->execute(array_values($data[$row])); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error executing prepared query: '.$result->getMessage()); + } + } + $stmt->free(); + + $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users ORDER BY user_id'; + $result =& $this->db->query($query, $this->fields); + + $numrows = $result->numRows($result); + + $this->verifyFetchedValues($result, 0, $data[0]); + $this->verifyFetchedValues($result, 2, $data[2]); + $this->verifyFetchedValues($result, null, $data[3]); + $this->verifyFetchedValues($result, 1, $data[1]); + + $result->free(); + } + + /** + * Strong typing query result misbehaves when $n_columns > $n_types + * @see http://pear.php.net/bugs/bug.php?id=9502 + */ + function testBug9502() { + $row = 5; + $data = $this->getSampleData($row); + $stmt = $this->db->prepare('INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)', array_values($this->fields), MDB2_PREPARE_MANIP); + $result = $stmt->execute(array_values($data)); + $stmt->free(); + + //provide an incomplete and scrambled types array + $types = array(); + $types['subscribed'] = $this->fields['subscribed']; + $types['user_name'] = $this->fields['user_name']; + $types['weight'] = $this->fields['weight']; + + $query = 'SELECT weight, user_name, user_id, quota, subscribed FROM users WHERE user_id = '.$row; + $result =& $this->db->queryRow($query, $types, MDB2_FETCHMODE_ASSOC); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error executing query: '.$result->getMessage() .' - '. $result->getUserInfo()); + } else { + $this->assertTrue(is_bool($result['subscribed'])); + $this->assertTrue(is_numeric($result['user_id'])); + $this->assertTrue(is_float($result['weight'])); + $this->assertFalse(is_bool($result['user_name'])); + } + } +} + +?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/tests/MDB2_Connect_Test.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/MDB2_Connect_Test.php --- php-mdb2-2.4.1/MDB2-2.5.0b2/tests/MDB2_Connect_Test.php 1970-01-01 01:00:00.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/MDB2_Connect_Test.php 2009-01-14 16:28:08.000000000 +0000 @@ -0,0 +1,52 @@ +_dsn = array( + 'phptype' => DSN_PHPTYPE, + 'username' => DSN_USERNAME, + 'password' => DSN_PASSWORD, + 'hostspec' => DSN_HOSTNAME, + 'database' => DSN_DATABASE, + ); + + } + // }}} + // {{{ PHP4 constructor.. + function MDB2_Connect_Test() + { + $this->__construct($connect); + } + // }}} + // {{{ connect + function connect() + { + // connect to database + $options = array( + 'portability' => (MDB2_PORTABILITY_ALL ^ MDB2_PORTABILITY_EMPTY_TO_NULL), + ); + + $this->dbc =& MDB2::singleton($this->_dsn, $options); + if (PEAR::isError($this->dbc)) { + return $this->dbc; + } + } + // }}} +} +// }}} +?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/tests/MDB2_datatype_testcase.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/MDB2_datatype_testcase.php --- php-mdb2-2.4.1/MDB2-2.5.0b2/tests/MDB2_datatype_testcase.php 1970-01-01 01:00:00.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/MDB2_datatype_testcase.php 2009-01-14 16:28:08.000000000 +0000 @@ -0,0 +1,885 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: MDB2_datatype_testcase.php,v 1.22 2008/02/23 09:38:22 quipo Exp $ + +require_once 'MDB2_testcase.php'; + +/** + * A test callback function to be used in the test class below for + * ensuring that custom datatype callback features are handled + * correctly. + * + * @param MDB2 $db The MDB2 database resource object. + * @param string $method The name of the MDB2_Driver_Datatype_Common method + * the callback function was called from. One of + * "getValidTypes", "convertResult", "getDeclaration", + * "compareDefinition", "quote" and "mapPrepareDatatype". + * See {@link MDB2_Driver_Datatype_Common} for the + * details of what each method does. + * @param array $aParameters An array of parameters, being the parameters that + * were passed to the method calling the callback + * function. + * @return mixed Returns the appropriate value depending on the method that + * called the function. See {@link MDB2_Driver_Datatype_Common} + * for details of the expected return values of the five possible + * calling methods. + */ +function datatype_test_callback(&$db, $method, $aParameters) +{ + // Ensure the datatype module is loaded + if (is_null($db->datatype)) { + $db->loadModule('Datatype', null, true); + } + // Lowercase method names for PHP4/PHP5 compatibility + $method = strtolower($method); + switch($method) { + // For all cases, return a string that identifies that the + // callback method was able to call to the appropriate point + case 'getvalidtypes': + return 'datatype_test_callback::getvalidtypes'; + case 'convertresult': + return 'datatype_test_callback::convertresult'; + case 'getdeclaration': + return 'datatype_test_callback::getdeclaration'; + case 'comparedefinition': + return 'datatype_test_callback::comparedefinition'; + case 'quote': + return 'datatype_test_callback::quote'; + case 'mappreparedatatype': + return 'datatype_test_callback::mappreparedatatype'; + } +} + +/** + * A test callback function to be used in the test class below for + * ensuring that custom nativetype to datatype mapping is handled + * correctly. + * + * @param MDB2 $db The MDB2 database reource object. + * @param array $aFields The standard array of fields produced from the + * MySQL command "SHOW COLUMNS". See + * {@link http://dev.mysql.com/doc/refman/5.0/en/describe.html} + * for more details on the format of the fields. + * "type" The nativetype column type + * "null" "YES" or "NO" + * "key" "PRI", "UNI", "MUL", or null + * "default" The default value of the column + * "extra" "auto_increment", or null + * @return array Returns an array of the following items: + * 0 => An array of possible MDB2 datatypes. As this is + * a custom type, always has one entry, "test". + * 1 => The length of the type, if defined by the nativetype, + * otherwise null. + * 2 => A boolean value indicating the "unsigned" nature of numeric + * fields. Always null in this case, as this custom test + * type is not numeric. + * 3 => A boolean value indicating the "fixed" nature of text + * fields. Always bull in this case, as this custom test + * type is not textual. + */ +function nativetype_test_callback(&$db, $aFields) +{ + // Prepare the type array + $aType = array(); + $aType[] = 'test'; + // Can the length of the field be found? + $length = null; + $start = strpos($aFields['type'], '('); + $end = strpos($aFields['type'], ')'); + if ($start && $end) { + $start++; + $chars = $end - $start; + $length = substr($aFields['type'], $start, $chars); + } + // No unsigned value needed + $unsigned = null; + // No fixed value needed + $fixed = null; + return array($aType, $length, $unsigned, $fixed); +} + +class MDB2_Datatype_TestCase extends MDB2_TestCase +{ + // Test table name (it is dynamically created/dropped) + var $table = 'datatypetable'; + + function setUp() { + parent::setUp(); + $this->db->loadModule('Manager', null, true); + $this->fields = array( + 'id' => array( + 'type' => 'integer', + 'unsigned' => true, + 'notnull' => true, + 'default' => 0, + ), + 'textfield' => array( + 'type' => 'text', + 'length' => 12, + ), + 'booleanfield' => array( + 'type' => 'boolean', + ), + 'decimalfield' => array( + 'type' => 'decimal', + ), + 'floatfield' => array( + 'type' => 'float', + ), + 'datefield' => array( + 'type' => 'date', + ), + 'timefield' => array( + 'type' => 'time', + ), + 'timestampfield' => array( + 'type' => 'timestamp', + ), + ); + if (!$this->tableExists($this->table)) { + $this->db->manager->createTable($this->table, $this->fields); + } + } + + /** + * The teardown method to clean up the testing environment. + */ + function tearDown() { + if ($this->tableExists($this->table)) { + $this->db->manager->dropTable($this->table); + } + $this->db->popExpect(); + unset($this->dsn); + if (!PEAR::isError($this->db->manager)) { + $this->db->disconnect(); + } + unset($this->db); + } + + /** + * Get the types of each field given its name + * + * @param array $names list of field names + * @return array $types list of matching field types + */ + function getFieldTypes($names) { + $types = array(); + foreach ($names as $name) { + foreach ($this->fields as $fieldname => $field) { + if ($name == $fieldname) { + $types[$name] = $field['type']; + } + } + } + return $types; + } + + /** + * Insert the values into the sample table + * + * @param array $values associative array (name => value) + */ + function insertValues($values) { + $types = $this->getFieldTypes(array_keys($values)); + + $result = $this->db->exec('DELETE FROM '.$this->table); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error emptying table: '.$result->getMessage()); + } + + $query = sprintf('INSERT INTO %s (%s) VALUES (%s)', + $this->table, + implode(', ', array_keys($values)), + implode(', ', array_fill(0, count($values), '?')) + ); + $stmt = $this->db->prepare($query, array_values($types), MDB2_PREPARE_MANIP); + if (PEAR::isError($stmt)) { + $this->assertTrue(false, 'Error creating prepared query: '.$stmt->getMessage()); + } + $result = $stmt->execute(array_values($values)); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error executing prepared query: '.$result->getMessage()); + } + $stmt->free(); + } + + /** + * Select the inserted row from the db and check the inserted values + * @param array $values associative array (name => value) of inserted data + */ + function selectAndCheck($values) { + $types = $this->getFieldTypes(array_keys($values)); + + $query = 'SELECT '. implode (', ', array_keys($values)). ' FROM '.$this->table; + $result = $this->db->queryRow($query, $types, MDB2_FETCHMODE_ASSOC); + foreach ($values as $name => $value) { + $this->assertEquals($result[$name], $values[$name], 'Error in '.$types[$name].' value: incorrect conversion'); + } + } + + /** + * Test the TEXT datatype for incorrect conversions + */ + function testTextDataType($emulate_prepared = false) { + if ($emulate_prepared) { + $this->db->setOption('emulate_prepared', true); + } + + $data = array( + 'id' => 1, + 'textfield' => 'test', + ); + $this->insertValues($data); + $this->selectAndCheck($data); + + if (!$emulate_prepared && !$this->db->getOption('emulate_prepared')) { + $this->testTextDataType(true); + } elseif($emulate_prepared) { + $this->db->setOption('emulate_prepared', false); + } + } + + /** + * Test the DECIMAL datatype for incorrect conversions + */ + function testDecimalDataType($emulate_prepared = false) { + if ($emulate_prepared) { + $this->db->setOption('emulate_prepared', true); + } + + $data = array( + 'id' => 1, + 'decimalfield' => 10.35, + ); + $this->insertValues($data); + $this->selectAndCheck($data); + + $old_locale = setlocale(LC_NUMERIC, 0); + if (OS_UNIX) { + setlocale(LC_NUMERIC, 'de_DE@euro', 'de_DE', 'de', 'ge'); + } else { + setlocale(LC_NUMERIC, 'de_DE@euro', 'de_DE', 'deu_deu'); + } + + $this->insertValues($data); + $this->selectAndCheck($data); + + setlocale(LC_NUMERIC, $old_locale); + + $expected = 10.35; + + $actual = $this->db->quote($expected, 'decimal'); + $this->assertEquals($expected, $actual); + + $non_us = number_format($expected, 2, ',', ''); + $actual = $this->db->quote($non_us, 'decimal'); + $this->assertEquals($expected, $actual); + + $expected = 1000.35; + + $non_us = '1,000.35'; + $actual = $this->db->quote($non_us, 'decimal'); + $this->assertEquals($expected, $actual); + + $non_us = '1000,35'; + $actual = $this->db->quote($non_us, 'decimal'); + $this->assertEquals($expected, $actual); + + $non_us = '1.000,35'; + $actual = $this->db->quote($non_us, 'decimal'); + $this->assertEquals($expected, $actual); + + // test quoting with invalid chars + $val = '100.3abc";d@a[\\'; + $this->assertEquals(100.3, $this->db->quote($val, 'decimal')); + + if (!$emulate_prepared && !$this->db->getOption('emulate_prepared')) { + $this->testDecimalDataType(true); + } elseif($emulate_prepared) { + $this->db->setOption('emulate_prepared', false); + } + } + + /** + * Test the FLOAT datatype for incorrect conversions + */ + function testFloatDataType($emulate_prepared = false) { + if ($emulate_prepared) { + $this->db->setOption('emulate_prepared', true); + } + + $data = array( + 'id' => 1, + 'floatfield' => 10.35, + ); + $this->insertValues($data); + $this->selectAndCheck($data); + + $old_locale = setlocale(LC_NUMERIC, 0); + if (OS_UNIX) { + setlocale(LC_NUMERIC, 'de_DE@euro', 'de_DE', 'de', 'ge'); + } else { + setlocale(LC_NUMERIC, 'de_DE@euro', 'de_DE', 'deu_deu'); + } + + + $this->insertValues($data); + $this->selectAndCheck($data); + + setlocale(LC_NUMERIC, $old_locale); + + $data['floatfield'] = '1.035e+1'; + $this->insertValues($data); + $this->selectAndCheck($data); + + $data['floatfield'] = '1.035E+01'; + $this->insertValues($data); + $this->selectAndCheck($data); + + $expected = '1.035E+01'; + $non_us = '1,035e+1'; + $actual = $this->db->quote($non_us, 'float'); + $this->assertEquals($expected, $actual); + + $expected = 10.35; + + $actual = $this->db->quote($expected, 'float'); + $this->assertEquals($expected, $actual); + + $non_us = number_format($expected, 2, ',', ''); + $actual = $this->db->quote($non_us, 'float'); + $this->assertEquals($expected, $actual); + + $expected = 1000.35; + + $non_us = '1,000.35'; + $actual = $this->db->quote($non_us, 'float'); + $this->assertEquals($expected, $actual); + + $non_us = '1000,35'; + $actual = $this->db->quote($non_us, 'float'); + $this->assertEquals($expected, $actual); + + $non_us = '1.000,35'; + $actual = $this->db->quote($non_us, 'float'); + $this->assertEquals($expected, $actual); + + // test quoting with invalid chars + $val = '100.3abc";d@a[\\'; + $this->assertEquals(100.3, $this->db->quote($val, 'float')); + + if (!$emulate_prepared && !$this->db->getOption('emulate_prepared')) { + $this->testFloatDataType(true); + } elseif($emulate_prepared) { + $this->db->setOption('emulate_prepared', false); + } + } + + /** + * Test the BOOLEAN datatype for incorrect conversions + */ + function testBooleanDataType($emulate_prepared = false) { + if ($emulate_prepared) { + $this->db->setOption('emulate_prepared', true); + } + + $data = array( + 'id' => 1, + 'booleanfield' => true, + ); + $this->insertValues($data); + $this->selectAndCheck($data); + + $data['booleanfield'] = false; + $this->insertValues($data); + $this->selectAndCheck($data); + + if (!$emulate_prepared && !$this->db->getOption('emulate_prepared')) { + $this->testBooleanDataType(true); + } elseif($emulate_prepared) { + $this->db->setOption('emulate_prepared', false); + } + } + + /** + * Test the DATE datatype for incorrect conversions + */ + function testDateDataType($emulate_prepared = false) { + if ($emulate_prepared) { + $this->db->setOption('emulate_prepared', true); + } + + $data = array( + 'id' => 1, + 'datefield' => date('Y-m-d'), + ); + $this->insertValues($data, 'date'); + $this->selectAndCheck($data); + + if (!$emulate_prepared && !$this->db->getOption('emulate_prepared')) { + $this->testDateDataType(true); + } elseif($emulate_prepared) { + $this->db->setOption('emulate_prepared', false); + } + } + + /** + * Test the TIME datatype for incorrect conversions + */ + function testTimeDataType($emulate_prepared = false) { + if ($emulate_prepared) { + $this->db->setOption('emulate_prepared', true); + } + + $data = array( + 'id' => 1, + 'timefield' => date('H:i:s'), + ); + $this->insertValues($data, 'time'); + $this->selectAndCheck($data); + + if (!$emulate_prepared && !$this->db->getOption('emulate_prepared')) { + $this->testTimeDataType(true); + } elseif($emulate_prepared) { + $this->db->setOption('emulate_prepared', false); + } + } + + /** + * Test the TIMESTAMP datatype for incorrect conversions + */ + function testTimestampDataType($emulate_prepared = false) { + if ($emulate_prepared) { + $this->db->setOption('emulate_prepared', true); + } + + $data = array( + 'id' => 1, + 'timestampfield' => date('Y-m-d H:i:s'), + ); + $this->insertValues($data, 'timestamp'); + $this->selectAndCheck($data); + + if (!$emulate_prepared && !$this->db->getOption('emulate_prepared')) { + $this->testTimestampDataType(true); + } elseif($emulate_prepared) { + $this->db->setOption('emulate_prepared', false); + } + } + + /** + * Tests escaping of text values with special characters + */ + function testEscapeSequences() { + $test_strings = array( + "'", + "\"", + "\\", + "%", + "_", + "''", + "\"\"", + "\\\\", + "\\'\\'", + "\\\"\\\"" + ); + + $this->clearTables(); + foreach($test_strings as $key => $string) { + $value = $this->db->quote($string, 'text'); + $query = "INSERT INTO users (user_name,user_id) VALUES ($value, $key)"; + $result = $this->db->exec($query); + + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error executing insert query'.$result->getMessage()); + } + + $query = 'SELECT user_name FROM users WHERE user_id = '.$key; + $value = $this->db->queryOne($query, 'text'); + + if (PEAR::isError($value)) { + $this->assertTrue(false, 'Error executing select query'.$value->getMessage()); + } + + $this->assertEquals($string, $value, "the value retrieved for field \"user_name\" doesn't match what was stored"); + } + } + + /** + * Tests escaping of text pattern strings with special characters + */ + function testPatternSequences() { + $test_strings = array( + "Foo", + "FOO", + "foo", + ); + + $this->clearTables(); + foreach($test_strings as $key => $string) { + $value = $this->db->quote($string, 'text'); + $query = "INSERT INTO users (user_name,user_id) VALUES ($value, $key)"; + $result = $this->db->exec($query); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error executing insert query'.$result->getMessage()); + } + } + + $query = 'SELECT user_name FROM users WHERE '.$this->db->datatype->matchPattern(array('F', '%'), 'LIKE', 'user_name'); + $values = $this->db->queryCol($query, 'text'); + $this->assertEquals(2, count($values), "case sensitive search was expected to return 2 rows but returned: ".count($values)); + + $query = 'SELECT user_name FROM users WHERE '.$this->db->datatype->matchPattern(array('foo'), 'ILIKE', 'user_name'); + $values = $this->db->queryCol($query, 'text'); + $this->assertEquals(3, count($values), "case insensitive search was expected to return 3 rows but returned: ".count($values)); + + $query = 'SELECT user_name FROM users WHERE '.$this->db->datatype->matchPattern(array(1 => '_', 'o', '%'), 'LIKE', 'user_name'); + $values = $this->db->queryCol($query, 'text'); + $this->assertEquals(2, count($values), "case sensitive search was expected to return 2 rows but returned: ".count($values)); + + $query = 'SELECT user_name FROM users WHERE '.$this->db->datatype->matchPattern(array(1 => '_', 'o', '%'), 'ILIKE', 'user_name'); + $values = $this->db->queryCol($query, 'text'); + $this->assertEquals(3, count($values), "case insensitive search was expected to return 3 rows but returned: ".count($values)); + } + + /** + * Tests escaping of text pattern strings with special characters + */ + function testEscapePatternSequences() { + if (!$this->supported('pattern_escaping')) { + return; + } + + $test_strings = array( + "%", + "_", + "%_", + "_%", + "%Foo%", + "%Foo_", + "Foo%123", + "Foo_123", + "_Foo%", + "_Foo_", + "%'", + "_'", + "'%", + "'_", + "'%'", + "'_'", + ); + + $this->clearTables(); + foreach($test_strings as $key => $string) { + $value = $this->db->quote($string, 'text'); + $query = "INSERT INTO users (user_name,user_id) VALUES ($value, $key)"; + $result = $this->db->exec($query); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error executing insert query'.$result->getMessage()); + } + + $query = 'SELECT user_name FROM users WHERE user_name LIKE '.$this->db->quote($string, 'text', true, true); + $value = $this->db->queryOne($query, 'text'); + if (PEAR::isError($value)) { + $this->assertTrue(false, 'Error executing select query'.$value->getMessage()); + } + + $this->assertEquals($string, $value, "the value retrieved for field \"user_name\" doesn't match what was stored"); + } + + $this->db->loadModule('Datatype', null, true); + $query = 'SELECT user_name FROM users WHERE user_name LIKE '.$this->db->datatype->matchPattern(array('Foo%', '_', '23')); + $value = $this->db->queryOne($query, 'text'); + $this->assertEquals('Foo%123', $value, "the value retrieved for field \"user_name\" doesn't match what was stored"); + + $query = 'SELECT user_name FROM users WHERE user_name LIKE '.$this->db->datatype->matchPattern(array(1 => '_', 'oo', '%')); + $value = $this->db->queryOne($query, 'text'); + $this->assertEquals('Foo', substr($value, 0, 3), "the value retrieved for field \"user_name\" doesn't match what was stored"); + } + + /** + * A method to test that the MDB2_Driver_Datatype_Common::getValidTypes() + * method returns the correct data array. + */ + function testGetValidTypes() + { + $this->db->loadModule('Datatype', null, true); + // Test with just the default MDB2 datatypes. + $aExpected = $this->db->datatype->valid_default_values; + $aResult = $this->db->datatype->getValidTypes(); + $this->assertEquals($aExpected, $aResult, 'getValidTypes'); + + // Test with a custom datatype + $this->db->setOption('datatype_map', array('test' => 'test')); + $this->db->setOption('datatype_map_callback', array('test' => 'datatype_test_callback')); + $aExpected = array_merge( + $this->db->datatype->valid_default_values, + array('test' => 'datatype_test_callback::getvalidtypes') + ); + $aResult = $this->db->datatype->getValidTypes(); + $this->assertEquals($aExpected, $aResult, 'getValidTypes'); + unset($this->db->options['datatype_map']); + unset($this->db->options['datatype_map_callback']); + + } + + /** + * A method to test that the MDB2_Driver_Datatype_Common::convertResult() + * method returns correctly converted column data. + */ + function testConvertResult() + { + $this->db->loadModule('Datatype', null, true); + // Test with an MDB2 datatype, eg. "text" + $value = 'text'; + $type = 'text'; + $result = $this->db->datatype->convertResult($value, $type); + $this->assertEquals($value, $result, 'convertResult'); + + // Test with a custom datatype + $this->db->setOption('datatype_map', array('test' => 'test')); + $this->db->setOption('datatype_map_callback', array('test' => 'datatype_test_callback')); + $value = 'text'; + $type = 'test'; + $result = $this->db->datatype->convertResult($value, $type); + $this->assertEquals('datatype_test_callback::convertresult', $result, 'mapPrepareDatatype'); + unset($this->db->options['datatype_map']); + unset($this->db->options['datatype_map_callback']); + } + + /** + * A method to test that the MDB2_Driver_Datatype_Common::getDeclaration() + * method returns correctly formatted SQL for declaring columns. + */ + function testGetDeclaration() + { + $this->db->loadModule('Datatype', null, true); + // Test with an MDB2 datatype, eg. "integer" + $name = 'column'; + $type = 'integer'; + $field = array('type' => 'integer'); + $result = $this->db->datatype->getDeclaration($type, $name, $field); + $actual_type = $this->db->phptype == 'sqlite' ? 'INTEGER' : 'INT'; + $default = $this->db->phptype == 'mssql' ? ' NULL' : ''; + $this->assertEquals('column '.$actual_type.$default, $result, 'getDeclaration'); + + // Test with a custom datatype + $this->db->setOption('datatype_map', array('test' => 'test')); + $this->db->setOption('datatype_map_callback', array('test' => 'datatype_test_callback')); + $name = 'column'; + $type = 'test'; + $field = array('type' => 'test'); + $result = $this->db->datatype->getDeclaration($type, $name, $field); + $this->assertEquals('datatype_test_callback::getdeclaration', $result, 'getDeclaration'); + + // Test with a custom datatype without datatype_map_callback function #1 + $name = 'address'; + $type = 'text'; + $field = array( + 'name' => 'company_addr', + 'type' => 'text', + 'notnull' => 'true' + ); + $this->db->setOption('datatype_map', array($name => $type)); + $result = $this->db->datatype->getDeclaration($field['type'], $field['name'], $field); + $notnull = ' NOT NULL'; + $expected = $field['name'].' '.$this->db->datatype->getTypeDeclaration(array('type' => $type)).$notnull; + $this->assertEquals($expected, $result); + + // Test with a custom datatype without datatype_map_callback function #2 + $name = 'address'; + $type = 'text'; + $field = array( + 'name' => 'company_addr', + 'type' => 'address', + ); + $this->db->setOption('datatype_map', array($name => $type)); + $result = $this->db->datatype->getDeclaration($field['type'], $field['name'], $field); + $default = $this->db->phptype == 'mssql' ? ' NULL' : ''; + $expected = $field['name'].' '.$this->db->datatype->getTypeDeclaration(array('type' => $type)).$default; + $this->assertEquals($expected, $result); + unset($this->db->options['datatype_map']); + unset($this->db->options['datatype_map_callback']); + } + + /** + * A method to test that the MDB2_Driver_Datatype_Common::compareDefinition() + * method + */ + function testCompareDefinition() + { + // Test with an MDB2 datatype, eg. "text" + $aPrevious = array( + 'type' => 'text', + 'length' => 4 + ); + $aCurrent = array( + 'type' => 'text', + 'length' => 5 + ); + $aResult = $this->db->datatype->compareDefinition($aCurrent, $aPrevious); + $this->assertTrue(is_array($aResult), 'compareDefinition'); + $this->assertEquals(1, count($aResult), 'compareDefinition'); + $this->assertTrue($aResult['length'], 'compareDefinition'); + + // Test with a custom datatype + $this->db->setOption('datatype_map', array('test' => 'test')); + $this->db->setOption('datatype_map_callback', array('test' => 'datatype_test_callback')); + $aPrevious = array( + 'type' => 'test' + ); + $aCurrent = array( + 'type' => 'test' + ); + $result = $this->db->datatype->compareDefinition($aCurrent, $aPrevious); + $this->assertEquals('datatype_test_callback::comparedefinition', $result, 'compareDefinition'); + unset($this->db->options['datatype_map']); + unset($this->db->options['datatype_map_callback']); + } + + /** + * A method to test that the MDB2_Driver_Datatype_Common::quote() + * method returns correctly quoted column data. + */ + function testQuote() + { + $this->db->loadModule('Datatype', null, true); + // Test with an MDB2 datatype, eg. "text" + $value = 'text'; + $type = 'text'; + $result = $this->db->datatype->quote($value, $type); + $this->assertEquals("'$value'", $result, 'quote'); + + // Test with a custom datatype + $this->db->setOption('datatype_map', array('test' => 'test')); + $this->db->setOption('datatype_map_callback', array('test' => 'datatype_test_callback')); + $value = 'text'; + $type = 'test'; + $result = $this->db->datatype->quote($value, $type); + $this->assertEquals('datatype_test_callback::quote', $result, 'quote'); + unset($this->db->options['datatype_map']); + unset($this->db->options['datatype_map_callback']); + } + + /** + * A method to test that the MDB2_Driver_Datatype_Common::mapPrepareDatatype() + * method returns the correct data type. + */ + function testMapPrepareDatatype() + { + $this->db->loadModule('Datatype', null, true); + // Test with an MDB2 datatype, eg. "text" + $type = 'text'; + $result = $this->db->datatype->mapPrepareDatatype($type); + if ($this->db->phptype == 'mysqli') { + $type = 's'; + } + $this->assertEquals($type, $result, 'mapPrepareDatatype'); + + // Test with a custom datatype + $this->db->setOption('datatype_map', array('test' => 'test')); + $this->db->setOption('datatype_map_callback', array('test' => 'datatype_test_callback')); + $type = 'test'; + $result = $this->db->datatype->mapPrepareDatatype($type); + $this->assertEquals('datatype_test_callback::mappreparedatatype', $result, 'mapPrepareDatatype'); + unset($this->db->options['datatype_map']); + unset($this->db->options['datatype_map_callback']); + } + + /** + * A method to test that the MDB2_Driver_Datatype_Common::mapNativeDatatype() + * method returns the correct MDB2 datatype from a given nativetype. + */ + function testMapNativeDatatype() + { + $this->db->loadModule('Datatype', null, true); + // Test with an common nativetype, eg. "text" + $field = array( + 'type' => 'int', + 'length' => 8 + ); + if (in_array($this->db->phptype, array('ibase', 'oci8'))) { + $field['type'] = 'integer'; + } + $expected_length = 8; + if (in_array($this->db->phptype, array('mysql', 'mysqli', 'pgsql', 'sqlite', 'mssql'))) { + $expected_length = 4; + } + $result = $this->db->datatype->mapNativeDatatype($field); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'mapNativeDatatype: '.$result->getUserInfo()); + } else { + $this->assertTrue(is_array($result), 'mapNativeDatatype'); + $this->assertEquals(4, count($result), 'mapNativeDatatype'); + $this->assertEquals('integer', $result[0][0], 'mapNativeDatatype'); + $this->assertEquals($expected_length, $result[1], 'mapNativeDatatype'); + } + + // Test with a custom nativetype mapping + $this->db->setOption('nativetype_map_callback', array('test' => 'nativetype_test_callback')); + $field = array( + 'type' => 'test' + ); + $result = $this->db->datatype->mapNativeDatatype($field); + $this->assertTrue(is_array($result), 'mapNativeDatatype'); + $this->assertEquals(4, count($result), 'mapNativeDatatype'); + $this->assertEquals('test', $result[0][0], 'mapNativeDatatype'); + $this->assertNull($result[1], 'mapNativeDatatype'); + $this->assertNull($result[2], 'mapNativeDatatype'); + $this->assertNull($result[3], 'mapNativeDatatype'); + $field = array( + 'type' => 'test(10)' + ); + $result = $this->db->datatype->mapNativeDatatype($field); + $this->assertTrue(is_array($result), 'mapNativeDatatype'); + $this->assertEquals(count($result), 4, 'mapNativeDatatype'); + $this->assertEquals($result[0][0], 'test', 'mapNativeDatatype'); + $this->assertEquals($result[1], 10, 'mapNativeDatatype'); + $this->assertNull($result[2], 'mapNativeDatatype'); + $this->assertNull($result[3], 'mapNativeDatatype'); + unset($this->db->options['nativetype_map_callback']); + } +} + +?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/tests/MDB2_extended_testcase.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/MDB2_extended_testcase.php --- php-mdb2-2.4.1/MDB2-2.5.0b2/tests/MDB2_extended_testcase.php 1970-01-01 01:00:00.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/MDB2_extended_testcase.php 2009-01-14 16:28:09.000000000 +0000 @@ -0,0 +1,580 @@ + | +// | Lorenzo Alberton | +// +----------------------------------------------------------------------+ +// +// $Id: MDB2_extended_testcase.php,v 1.13 2007/02/28 12:15:26 quipo Exp $ + +require_once 'MDB2_testcase.php'; + +class MDB2_Extended_TestCase extends MDB2_TestCase +{ + /** + * + */ + function testAutoExecute() + { + $data = $this->getSampleData(); + $select_query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users'; + + $result = $this->db->loadModule('Extended'); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error loading "Extended" module: '.$result->getMessage()); + } + $result = $this->db->extended->autoExecute('users', $data, MDB2_AUTOQUERY_INSERT, null, $this->fields); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error auto executing insert: '.$result->getMessage()); + } + + $this->db->setFetchMode(MDB2_FETCHMODE_ASSOC); + $result =& $this->db->query($select_query, $this->fields); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error selecting from users: '.$result->getMessage()); + } else { + $this->verifyFetchedValues($result, null, $data); + $result->free(); + } + + $where = 'user_id = '.$this->db->quote($data['user_id'], 'integer'); + $result = $this->db->extended->autoExecute('users', null, MDB2_AUTOQUERY_SELECT, $where, null, true, $this->fields); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error auto executing select: '.$result->getMessage()); + } else { + $this->verifyFetchedValues($result, null, $data); + $result->free(); + } + + $where = 'user_id = '.$this->db->quote($data['user_id'], 'integer'); + $result = $this->db->extended->autoExecute('users', null, MDB2_AUTOQUERY_SELECT, $where, null, true, MDB2_PREPARE_RESULT); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error auto executing select: '.$result->getMessage()); + } else { + $result->setResultTypes($this->fields); + $this->verifyFetchedValues($result, null, $data); + $result->free(); + } + + $update_data = array(); + $data['user_name'] = $update_data['user_name'] = 'foo'; + + $where = 'user_id = '.$this->db->quote($data['user_id'], 'integer'); + $result = $this->db->extended->autoExecute('users', $update_data, MDB2_AUTOQUERY_UPDATE, $where, $this->fields); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error auto executing insert: '.$result->getMessage()); + } + + $this->db->setFetchMode(MDB2_FETCHMODE_ASSOC); + $result =& $this->db->query($select_query, $this->fields); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error selecting from users: '.$result->getMessage()); + } else { + $this->verifyFetchedValues($result, null, $data); + $result->free(); + } + + $where = array($where, 'user_name = '.$this->db->quote($data['user_name'], 'text')); + $result = $this->db->extended->autoExecute('users', null, MDB2_AUTOQUERY_DELETE, $where, null); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error auto executing insert: '.$result->getMessage()); + } + + $this->db->setFetchMode(MDB2_FETCHMODE_ASSOC); + $result =& $this->db->query($select_query, $this->fields); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error selecting from users: '.$result->getMessage()); + } else { + $this->assertEquals(0, $result->numRows(), 'No rows were expected to be returned'); + $result->free(); + } + } + + /** + * Test getAssoc() + * + * Test fetching two columns from a resultset. Return them as (key,value) pairs. + */ + function testGetAssoc() + { + $result = $this->db->loadModule('Extended'); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error loading "Extended" module: '.$result->getMessage()); + } + + $data = $this->getSampleData(1234); + + $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')'; + $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP); + $result = $stmt->execute(array_values($data)); + $stmt->free(); + + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error executing prepared query: '.$result->getMessage()); + } + + //test getAssoc() with query parameters + $query = 'SELECT user_id, user_name FROM users WHERE user_id=?'; + $result = $this->db->extended->getAssoc($query, array('integer', 'text'), array(1234), array('integer')); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error executing getAssoc(): '.$result->getMessage()); + } + $this->assertTrue(array_key_exists($data['user_id'], $result), 'Unexpected returned key'); + $this->assertEquals($data['user_name'], $result[$data['user_id']], 'Unexpected returned value'); + + //test getAssoc() without query parameters + $query = 'SELECT user_id, user_name FROM users WHERE user_id=1234'; + $result = $this->db->extended->getAssoc($query, array('integer', 'text')); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error executing getAssoc(): '.$result->getMessage()); + } else { + $this->assertTrue(array_key_exists($data['user_id'], $result), 'Unexpected returned key'); + $this->assertEquals($data['user_name'], $result[$data['user_id']], 'Unexpected returned value'); + } + + //add another record to the db + $data2 = $this->getSampleData(4321); + $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')'; + $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP); + $result = $stmt->execute(array_values($data2)); + $stmt->free(); + + //test getAssoc() with $force_array=true + $query = 'SELECT user_id, user_name FROM users ORDER BY user_id'; + $values = $this->db->extended->getAssoc($query, array('integer', 'text'), null, null, MDB2_FETCHMODE_ASSOC, true); + if (PEAR::isError($values)) { + $this->assertTrue(false, 'Error executing getAssoc(): '.$values->getMessage()); + } else { + $this->assertEquals(2, count($values), 'Error: incorrect number of returned rows'); + list($id, $value) = each($values); + $this->assertEquals($data['user_id'], $id, 'Unexpected returned value'); + $this->assertEquals($data['user_name'], $value['user_name'], 'Unexpected returned value'); + list($id, $value) = each($values); + $this->assertEquals($data2['user_id'], $id, 'Unexpected returned value'); + $this->assertEquals($data2['user_name'], $value['user_name'], 'Unexpected returned value'); + } + + + //test getAssoc() with $force_array=false and $group=true + $query = 'SELECT user_id, user_name FROM users ORDER BY user_id'; + $values = $this->db->extended->getAssoc($query, array('integer', 'text'), null, null, MDB2_FETCHMODE_ASSOC, false, true); + if (PEAR::isError($values)) { + $this->assertTrue(false, 'Error executing getAssoc(): '.$values->getMessage()); + } else { + //@todo: check if MDB2_FETCHMODE_ASSOC is behaving correctly in this case + $this->assertEquals(2, count($values), 'Error: incorrect number of returned rows'); + list($id, $value) = each($values); + $this->assertEquals($data['user_id'], $id, 'Unexpected returned value'); + $this->assertEquals($data['user_name'], $value[0], 'Unexpected returned value'); + list($id, $value) = each($values); + $this->assertEquals($data2['user_id'], $id, 'Unexpected returned value'); + $this->assertEquals($data2['user_name'], $value[0], 'Unexpected returned value'); + + } + + //test $group=true with 3 fields + $query = 'SELECT user_password, user_id, user_name FROM users ORDER BY user_id'; + $values = $this->db->extended->getAssoc($query, array('integer', 'text', 'text'), null, null, MDB2_FETCHMODE_ASSOC, false, true); + if (PEAR::isError($values)) { + $this->assertTrue(false, 'Error executing getAssoc(): '.$values->getMessage()); + } else { + //the 2 values for user_password are equals, so they are collapsed in the same array + $this->assertEquals(1, count($values), 'Error: incorrect number of returned rows'); + $values = $values[0]; + //there are 2 records + $this->assertEquals(2, count($values), 'Error: incorrect number of returned rows'); + $value = array_shift($values); + $this->assertEquals($data['user_id'], $value['user_id'], 'Unexpected returned value'); + $this->assertEquals($data['user_name'], $value['user_name'], 'Unexpected returned value'); + $value = array_shift($values); + $this->assertEquals($data2['user_id'], $value['user_id'], 'Unexpected returned value'); + $this->assertEquals($data2['user_name'], $value['user_name'], 'Unexpected returned value'); + } + + //test $group=false with 3 fields + $values = $this->db->extended->getAssoc($query, array('integer', 'text', 'text'), null, null, MDB2_FETCHMODE_ASSOC, false, false); + if (PEAR::isError($values)) { + $this->assertTrue(false, 'Error executing getAssoc(): '.$values->getMessage()); + } else { + //the 2 values for user_password are equals, so the first record is overwritten + $this->assertEquals(1, count($values), 'Error: incorrect number of returned rows'); + $values = $values[0]; + $this->assertEquals($data2['user_id'], $value['user_id'], 'Unexpected returned value'); + $this->assertEquals($data2['user_name'], $value['user_name'], 'Unexpected returned value'); + } + } + + /** + * Test getOne() + * + * Test fetching a single value + */ + function testGetOne() + { + $result = $this->db->loadModule('Extended'); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error loading "Extended" module: '.$result->getMessage()); + } + + $data = $this->getSampleData(1234); + + $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')'; + $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP); + $result = $stmt->execute(array_values($data)); + $stmt->free(); + + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error executing prepared query: '.$result->getMessage()); + } + + //test getOne() with query parameters + $query = 'SELECT user_name FROM users WHERE user_id=?'; + $result = $this->db->extended->getOne($query, 'text', array(1234), array('integer')); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error executing getOne(): '.$result->getMessage()); + } + $this->assertEquals($data['user_name'], $result, 'Unexpected returned value'); + + //test getOne() without query parameters + $query = 'SELECT user_name FROM users WHERE user_id=1234'; + $result = $this->db->extended->getOne($query, 'text'); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error executing getOne(): '.$result->getMessage()); + } + $this->assertEquals($data['user_name'], $result, 'Unexpected returned value'); + + //test getOne() with column number (resultset: 0-based array) + $query = 'SELECT user_id, user_name, approved FROM users WHERE user_id=1234'; + $result = $this->db->extended->getOne($query, 'text', null, null, 1); //get the 2nd column + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error executing getOne(): '.$result->getMessage()); + } + $this->assertEquals($data['user_name'], $result, 'Unexpected returned value'); + } + + /** + * Test getCol() + * + * Test fetching a column of result data. + */ + function testGetCol() + { + $result = $this->db->loadModule('Extended'); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error loading "Extended" module: '.$result->getMessage()); + } + + $data = array( + 0 => $this->getSampleData(1234), + 1 => $this->getSampleData(4321), + ); + $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')'; + $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP); + $result = $stmt->execute(array_values($data[0])); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error executing prepared query: '.$result->getMessage()); + } + $result = $stmt->execute(array_values($data[1])); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error executing prepared query: '.$result->getMessage()); + } + $stmt->free(); + + //test getCol() with query parameters + $query = 'SELECT user_name FROM users WHERE user_id>?'; + $result = $this->db->extended->getCol($query, 'text', array(1), array('integer')); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error executing getCol(): '.$result->getMessage()); + } + $expected = array( + $data[0]['user_name'], + $data[1]['user_name'], + ); + $this->assertEquals($expected, $result, 'Unexpected returned value'); + + //test getCol() without query parameters + $query = 'SELECT user_name FROM users'; + $result = $this->db->extended->getCol($query, 'text'); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error executing getCol(): '.$result->getMessage()); + } + $this->assertEquals($expected, $result, 'Unexpected returned value'); + + //test getCol() with column number (resultset: 0-based array) + $query = 'SELECT user_id, user_name, approved FROM users'; + $result = $this->db->extended->getCol($query, 'text', null, null, 1); //get the 2nd column + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error executing getCol(): '.$result->getMessage()); + } + $this->assertEquals($expected, $result, 'Unexpected returned value'); + } + + /** + * Test getRow() + * + * Test fetching a row of result data. + */ + function testGetRow() + { + $result = $this->db->loadModule('Extended'); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error loading "Extended" module: '.$result->getMessage()); + } + + $data = $this->getSampleData(1234); + $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')'; + $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP); + $result = $stmt->execute(array_values($data)); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error executing prepared query: '.$result->getMessage()); + } + $stmt->free(); + + //test getRow() with query parameters + $query = 'SELECT user_id, user_name, user_password FROM users WHERE user_id=?'; + $result = $this->db->extended->getRow($query, array('integer', 'text', 'text'), array(1234), array('integer'), MDB2_FETCHMODE_ASSOC); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error executing getRow(): '.$result->getMessage()); + } + $this->assertEquals($data['user_id'], $result['user_id'], 'Unexpected returned value'); + $this->assertEquals($data['user_name'], $result['user_name'], 'Unexpected returned value'); + $this->assertEquals($data['user_password'], $result['user_password'], 'Unexpected returned value'); + + //test getRow() without query parameters + $query = 'SELECT user_id, user_name, user_password FROM users'; + $result = $this->db->extended->getRow($query, array('integer', 'text', 'text'), null, null, MDB2_FETCHMODE_ASSOC); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error executing getRow(): '.$result->getMessage()); + } + $this->assertEquals($data['user_id'], $result['user_id'], 'Unexpected returned value'); + $this->assertEquals($data['user_name'], $result['user_name'], 'Unexpected returned value'); + $this->assertEquals($data['user_password'], $result['user_password'], 'Unexpected returned value'); + } + + /** + * Test getAll() + * + * Test fetching result data all at once. + */ + function testGetAll() + { + $result = $this->db->loadModule('Extended'); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error loading "Extended" module: '.$result->getMessage()); + } + + $data = array(); + $total_rows = 5; + + $stmt = $this->db->prepare('INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')', array_values($this->fields), MDB2_PREPARE_MANIP); + + for ($row = 0; $row < $total_rows; $row++) { + $data[$row] = $this->getSampleData($row); + $result = $stmt->execute(array_values($data[$row])); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error executing prepared query: '.$result->getMessage()); + } + } + $stmt->free(); + + //test getAll() with query parameters + $query = 'SELECT user_id, user_name, user_password FROM users WHERE user_id > ? ORDER BY user_id'; + $values = $this->db->extended->getAll($query, array('integer', 'text', 'text'), array(2), array('integer'), MDB2_FETCHMODE_ASSOC); + if (PEAR::isError($values)) { + $this->assertTrue(false, 'Error fetching the result set: '.$values->getMessage()); + } else { + $this->assertEquals(2, count($values), 'Error: incorrect number of returned rows'); + for ($i=0; $i<2; $i++) { + $this->assertEquals($data[$i+3]['user_id'], $values[$i]['user_id'], 'Unexpected returned value'); + $this->assertEquals($data[$i+3]['user_name'], $values[$i]['user_name'], 'Unexpected returned value'); + $this->assertEquals($data[$i+3]['user_password'], $values[$i]['user_password'], 'Unexpected returned value'); + } + } + + //test getAll() without query parameters + $query = 'SELECT user_id, user_name, user_password FROM users ORDER BY user_id'; + $values = $this->db->extended->getAll($query, array('integer', 'text', 'text'), null, null, MDB2_FETCHMODE_ASSOC); + if (PEAR::isError($values)) { + $this->assertTrue(false, 'Error fetching the result set: '.$values->getMessage()); + } else { + $this->assertEquals($total_rows, count($values), 'Error: incorrect number of returned rows'); + for ($i=0; $i<$total_rows; $i++) { + $this->assertEquals($data[$i]['user_id'], $values[$i]['user_id'], 'Unexpected returned value'); + $this->assertEquals($data[$i]['user_name'], $values[$i]['user_name'], 'Unexpected returned value'); + $this->assertEquals($data[$i]['user_password'], $values[$i]['user_password'], 'Unexpected returned value'); + } + } + } + + /** + * Test limitQuery() + * + * Test fetching a limited resultset. + */ + function testLimitQuery() + { + $result = $this->db->loadModule('Extended'); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error loading "Extended" module: '.$result->getMessage()); + } + + $data = array(); + $total_rows = 5; + + $stmt = $this->db->prepare('INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')', array_values($this->fields), MDB2_PREPARE_MANIP); + + for ($row = 0; $row < $total_rows; $row++) { + $data[$row] = $this->getSampleData($row); + $result = $stmt->execute(array_values($data[$row])); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error executing prepared query: '.$result->getMessage()); + } + } + $stmt->free(); + + $query = 'SELECT user_id, user_name, user_password FROM users ORDER BY user_id'; + $types = array('integer', 'text', 'text'); + + //test limitQuery() with offset = 0 + $result = $this->db->extended->limitQuery($query, $types, 2); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error executing limitQuery(): '.$result->getMessage()); + } + $values = $result->fetchAll(MDB2_FETCHMODE_ASSOC); + if (PEAR::isError($values)) { + $this->assertTrue(false, 'Error fetching the result set'); + } else { + $this->assertEquals(2, count($values), 'Error: incorrect number of returned rows'); + for ($i=0; $i<2; $i++) { + $this->assertEquals($data[$i]['user_id'], $values[$i]['user_id'], 'Unexpected returned value'); + $this->assertEquals($data[$i]['user_name'], $values[$i]['user_name'], 'Unexpected returned value'); + $this->assertEquals($data[$i]['user_password'], $values[$i]['user_password'], 'Unexpected returned value'); + } + } + $result->free(); + + //test limitQuery() with offset > 0 + $result = $this->db->extended->limitQuery($query, $types, 3, 2); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error executing limitQuery(): '.$result->getMessage()); + } + $values = $result->fetchAll(MDB2_FETCHMODE_ASSOC); + if (PEAR::isError($values)) { + $this->assertTrue(false, 'Error fetching the result set'); + } else { + $this->assertEquals(3, count($values), 'Error: incorrect number of returned rows'); + for ($i=0; $i<3; $i++) { + $this->assertEquals($data[$i+2]['user_id'], $values[$i]['user_id'], 'Unexpected returned value'); + $this->assertEquals($data[$i+2]['user_name'], $values[$i]['user_name'], 'Unexpected returned value'); + $this->assertEquals($data[$i+2]['user_password'], $values[$i]['user_password'], 'Unexpected returned value'); + } + } + $result->free(); + } + + /** + * Test execParam() + * + * Test executing a query with parameters + */ + function testExecParam() + { + $result = $this->db->loadModule('Extended'); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error loading "Extended" module: '.$result->getMessage()); + } + + $data = $this->getSampleData(1234); + + $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')'; + + $result = $this->db->extended->execParam($query, array_values($data), $this->fields); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error executing execParam(): '.$result->getMessage()); + } + + $query = 'SELECT user_id, user_name, user_password FROM users WHERE user_id=?'; + $result = $this->db->extended->getRow($query, array('integer', 'text', 'text'), array(1234), array('integer'), MDB2_FETCHMODE_ASSOC); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error executing getRow(): '.$result->getMessage()); + } + $this->assertEquals($data['user_id'], $result['user_id'], 'Unexpected returned value'); + $this->assertEquals($data['user_name'], $result['user_name'], 'Unexpected returned value'); + $this->assertEquals($data['user_password'], $result['user_password'], 'Unexpected returned value'); + } + + /** + * Test executeMultiple() + * + * Test executing multiple prepared queries + */ + function testExecuteMultiple() + { + $result = $this->db->loadModule('Extended'); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error loading "Extended" module: '.$result->getMessage()); + } + + $data = array(); + $total_rows = 5; + + for ($row = 0; $row < $total_rows; $row++) { + $data[$row] = array_values($this->getSampleData($row)); + } + + $stmt = $this->db->prepare('INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')'); + $result = $this->db->extended->executeMultiple($stmt, $data); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error executing executeMultiple(): '.$result->getMessage()); + } + $stmt->free(); + + $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users'; + $values = $this->db->queryAll($query, $this->fields, MDB2_FETCHMODE_ORDERED); + + $n_fields = count($this->fields); + for ($i=0; $i<$total_rows; $i++) { + for ($field=0; $field<$n_fields; $field++) { + $this->assertEquals(strval($data[$i][$field]), strval($values[$i][$field]), 'Unexpected returned value'); + } + } + } +} +?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/tests/MDB2_function_testcase.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/MDB2_function_testcase.php --- php-mdb2-2.4.1/MDB2-2.5.0b2/tests/MDB2_function_testcase.php 1970-01-01 01:00:00.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/MDB2_function_testcase.php 2009-01-14 16:28:09.000000000 +0000 @@ -0,0 +1,313 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: MDB2_function_testcase.php,v 1.24 2008/02/17 18:54:08 quipo Exp $ + +class MDB2_Function_TestCase extends MDB2_TestCase +{ + function setUp() { + parent::setUp(); + $this->db->loadModule('Function', null, true); + } + + /** + * Test functionTable() + */ + function testFunctionTable() + { + if (!$this->methodExists($this->db->function, 'functionTable')) { + return; + } + + $functionTable_clause = $this->db->function->functionTable(); + $query = 'SELECT 1 '.$functionTable_clause; + $result = $this->db->queryOne($query); + if (PEAR::isError($result)) { + $this->assertFalse(true, 'Error fetching from function table'); + } else { + $this->assertEquals('1', $result, 'Error fetching value from function table'); + } + } + + /** + * Test now() + */ + function testNow() + { + if (!$this->methodExists($this->db->function, 'now')) { + return; + } + + $tests = array( + 'timestamp' => '/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/', + 'date' => '/^\d{4}-\d{2}-\d{2}$/', + 'time' => '/^\d{2}:\d{2}:\d{2}$/', + ); + + foreach ($tests as $type => $regexp) { + $functionTable_clause = $this->db->function->functionTable(); + $now_clause = $this->db->function->now($type); + $query = 'SELECT '.$now_clause . $functionTable_clause; + $result = $this->db->queryOne($query, $type); + if (PEAR::isError($result)) { + $this->assertFalse(true, 'Error getting '.$type); + } else { + $this->assertRegExp($regexp, $result, 'Error: not a proper '.$type); + } + } + } + + /** + * Test substring() + */ + function testSubstring() + { + if (!$this->methodExists($this->db->function, 'substring')) { + return; + } + $data = $this->getSampleData(1234); + + $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')'; + $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP); + + $result = $stmt->execute(array_values($data)); + $stmt->free(); + + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error executing prepared query'.$result->getMessage()); + } + + $substring_clause = $this->db->function->substring('user_name', 1, 4); + $query = 'SELECT '.$substring_clause .' FROM users'; + $result = $this->db->queryOne($query); + if (PEAR::isError($result)) { + $this->assertFalse(true, 'Error getting substring'); + } else { + $this->assertEquals('user', $result, 'Error: substrings not equals'); + } + + $substring_clause = $this->db->function->substring('user_name', 5, 1); + $query = 'SELECT '.$substring_clause .' FROM users'; + $result = $this->db->queryOne($query); + if (PEAR::isError($result)) { + $this->assertFalse(true, 'Error getting substring'); + } else { + $this->assertEquals('_', $result, 'Error: substrings not equals'); + } + + //test NULL 2nd parameter + $substring_clause = $this->db->function->substring('user_name', 6); + $query = 'SELECT '.$substring_clause .' FROM users'; + $result = $this->db->queryOne($query); + if (PEAR::isError($result)) { + $this->assertFalse(true, 'Error getting substring'); + } else { + $this->assertEquals('1234', $result, 'Error: substrings not equals'); + } + } + + /** + * Test concat() + */ + function testConcat() + { + if (!$this->methodExists($this->db->function, 'concat')) { + return; + } + + $functionTable_clause = $this->db->function->functionTable(); + $concat_clause = $this->db->function->concat($this->db->quote('time', 'text'), $this->db->quote('stamp', 'text')); + $query = 'SELECT '.$concat_clause . $functionTable_clause; + $result = $this->db->queryOne($query); + if (PEAR::isError($result)) { + $this->assertFalse(true, 'Error getting concat'); + } else { + $this->assertEquals('timestamp', $result, 'Error: could not concatenate "time+stamp"'); + } + } + + /** + * Test random() + */ + function testRandom() + { + if (!$this->methodExists($this->db->function, 'random')) { + return; + } + + $rand_clause = $this->db->function->random(); + $functionTable_clause = $this->db->function->functionTable(); + $query = 'SELECT '.$rand_clause . $functionTable_clause; + $result = $this->db->queryOne($query, 'float'); + if (PEAR::isError($result)) { + $this->assertFalse(true, 'Error getting random value:'. $result->getMessage()); + } else { + $this->assertTrue(($result >= 0 && $result <= 1), 'Error: could not get random value between 0 and 1: '.$result); + } + } + + /** + * Test lower() + */ + function testLower() + { + if (!$this->methodExists($this->db->function, 'lower')) { + return; + } + $string = $this->db->quote('FoO'); + $lower_clause = $this->db->function->lower($string); + $functionTable_clause = $this->db->function->functionTable(); + $query = 'SELECT '.$lower_clause . $functionTable_clause; + $result = $this->db->queryOne($query, 'text'); + if (PEAR::isError($result)) { + $this->assertFalse(true, 'Error getting lower case value:'. $result->getMessage()); + } else { + $this->assertTrue(($result === 'foo'), 'Error: could not lower case "FoO": '.$result); + } + } + + /** + * Test upper() + */ + function testUpper() + { + if (!$this->methodExists($this->db->function, 'upper')) { + return; + } + $string = $this->db->quote('FoO'); + $upper_clause = $this->db->function->upper($string); + $functionTable_clause = $this->db->function->functionTable(); + $query = 'SELECT '.$upper_clause . $functionTable_clause; + $result = $this->db->queryOne($query, 'text'); + if (PEAR::isError($result)) { + $this->assertFalse(true, 'Error getting upper case value:'. $result->getMessage()); + } else { + $this->assertTrue(($result === 'FOO'), 'Error: could not upper case "FoO": '.$result); + } + } + + /** + * Test length() + */ + function testLenght() + { + if (!$this->methodExists($this->db->function, 'length')) { + return; + } + $string = $this->db->quote('foo'); + $length_clause = $this->db->function->length($string); + $functionTable_clause = $this->db->function->functionTable(); + $query = 'SELECT '.$length_clause . $functionTable_clause; + $len = $this->db->queryOne($query, 'integer'); + if (PEAR::isError($len)) { + $this->assertFalse(true, 'Error getting upper case value:'. $len->getMessage()); + } else { + $this->assertEquals(3, $len, 'Error: incorrect length for "foo" string: '.$len); + } + } + + /** + * Test replace() + */ + function testReplace() + { + if (!$this->methodExists($this->db->function, 'replace')) { + return; + } + + $string = $this->db->quote('so what'); + $search = $this->db->quote('o'); + $replace = $this->db->quote('ay'); + $replace_clause = $this->db->function->replace($string, $search, $replace); + $this->db->pushErrorHandling(PEAR_ERROR_RETURN); + $this->db->expectError(MDB2_ERROR_UNSUPPORTED); + $replace_clause = $this->db->function->replace($string, $search, $replace); + $this->db->popExpect(); + $this->db->popErrorHandling(); + if (PEAR::isError($replace_clause) && $replace_clause->getCode() == MDB2_ERROR_UNSUPPORTED) { + return; + } + + $functionTable_clause = $this->db->function->functionTable(); + $query = 'SELECT '.$replace_clause . $functionTable_clause; + $result = $this->db->queryOne($query, 'text'); + if (PEAR::isError($result)) { + $this->assertFalse(true, 'Error getting replaced value:'. $result->getMessage()); + } else { + $this->assertEquals('say what', $result, 'Error: could not get replace string: '.$result); + } + } + + /** + * Test unixtimestamp() + */ + function testUnixtimestamp() + { + if (!$this->methodExists($this->db->function, 'unixtimestamp')) { + return; + } + + $datetime = '2008-01-01 00:00:00'; + $quoted_dt = $this->db->quote($datetime, 'timestamp'); + $this->db->pushErrorHandling(PEAR_ERROR_RETURN); + $this->db->expectError(MDB2_ERROR_UNSUPPORTED); + $unixts_clause = $this->db->function->unixtimestamp($quoted_dt); + $this->db->popExpect(); + $this->db->popErrorHandling(); + if (PEAR::isError($unixts_clause) && $unixts_clause->getCode() == MDB2_ERROR_UNSUPPORTED) { + return; + } + + $expected = strtotime($datetime); + + $functionTable_clause = $this->db->function->functionTable(); + $query = 'SELECT '.$unixts_clause . $functionTable_clause; + $result = $this->db->queryOne($query, 'text'); + if (PEAR::isError($result)) { + $this->assertFalse(true, 'Error getting UNIX timestamp:'. $result->getMessage() . ' :: ' . $result->getUserInfo()); + } else { + $this->assertEquals($expected, $result, 'Error: could not get correct UNIX timestamp: '.$result); + } + } +} +?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/tests/MDB2_internals_testcase.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/MDB2_internals_testcase.php --- php-mdb2-2.4.1/MDB2-2.5.0b2/tests/MDB2_internals_testcase.php 1970-01-01 01:00:00.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/MDB2_internals_testcase.php 2009-01-14 16:28:09.000000000 +0000 @@ -0,0 +1,628 @@ + | +// | Andrew Hill | +// +----------------------------------------------------------------------+ +// +// $Id: MDB2_internals_testcase.php,v 1.4 2008/06/12 11:10:43 quipo Exp $ + +require_once 'MDB2_testcase.php'; + +class MDB2_Internals_TestCase extends MDB2_TestCase { + + var $clear_tables = false; + + /** + * Tests that the MDB2::apiVersion() method returns an API version number. + */ + function test_apiVersion() + { + $result = MDB2::apiVersion(); + $this->assertNotNull($result, 'apiVersion'); + $result = strtok($result, '.'); + $this->assertTrue(is_numeric($result), 'apiVersion'); + $result = strtok('.'); + $this->assertTrue(is_numeric($result), 'apiVersion'); + $result = strtok('.'); + $this->assertTrue(is_numeric($result), 'apiVersion'); + } + + /** + * Tests that the MDB2::classExists() method correctly tests for + * existence of a class. + */ + function test_classExists() + { + $this->assertFalse(MDB2::classExists('null'), 'classExists'); + $this->assertTrue(MDB2::classExists('MDB2'), 'classExists'); + } + + /** + * Tests that the MDB2::loadClass() method correctly loads classes. + */ + function test_loadClass() + { + $this->assertTrue(MDB2::loadClass('MDB2', false), 'loadClass'); + // Suppress handling of PEAR errors while testing next case + PEAR::pushErrorHandling(null); + $result = MDB2::loadClass('null', false); + $this->assertTrue(is_a($result, 'pear_error'), 'loadClass'); + PEAR::popErrorHandling(); + } + + /** + * Tests that the MDB2::factory() method correctly connects to a + * database. + */ + function test_factory() + { + $db =& MDB2::factory($this->dsn); + $this->assertTrue(MDB2::isConnection($db), 'factory'); + // Suppress handling of PEAR errors while preparing the + // next test case database connection + PEAR::pushErrorHandling(null); + $db =& MDB2::factory(null); + PEAR::popErrorHandling(); + $this->assertFalse(MDB2::isConnection($db), 'factory'); + } + + /** + * Tests that the MDB2::loadFile() method returns the expected + * filename. + */ + function test_loadFile() + { + $filename = 'Extended'; + $this->assertEquals('MDB2'.DIRECTORY_SEPARATOR.$filename.'.php', MDB2::loadFile($filename), 'loadFile'); + } + + /** + * Tests that the MDB2::isConnection() method correctly reports + * connections. + */ + function test_isConnection() + { + $this->assertTrue(MDB2::isConnection($this->db), 'isConnection'); + $this->assertFalse(MDB2::isConnection(null), 'isConnection'); + } + + /** + * Tests that the MDB2::isResult() method correctly identifies + * results. + */ + function test_isResult() + { + $obj = new MDB2_Result(); + $this->assertTrue(MDB2::isResult($obj), 'isResult'); + $obj = null; + $this->assertFalse(MDB2::isResult($obj), 'isResult'); + } + + /** + * Tests that the MDB2::isResultCommon() method correctly identifies + * common results. + */ + function test_isResultCommon() + { + $result = null; + $obj = new MDB2_Result_Common($this->db, $result); + $this->assertTrue(MDB2::isResultCommon($obj), 'isResultCommon'); + $obj = null; + $this->assertFalse(MDB2::isResultCommon($obj), 'isResultCommon'); + } + + /** + * Tests that the MDB2::parseDSN() method works. + */ + function test_parseDSN() + { + $dsn = $this->dsn; + $result = MDB2::parseDSN($dsn); + $this->assertEquals($dsn['phptype'],$result['dbsyntax'],'parseDSN'); + + $dsn = "mydbms://myname:mypassword@localhost"; + $result = MDB2::parseDSN($dsn); + $this->assertEquals('mydbms', $result['phptype'],'parseDSN'); + $this->assertEquals('mydbms',$result['dbsyntax'],'parseDSN'); + $this->assertEquals('tcp',$result['protocol'],'parseDSN'); + $this->assertEquals('localhost',$result['hostspec'],'parseDSN'); + $this->assertEquals(false,$result['port'],'parseDSN'); + $this->assertEquals(false,$result['socket'],'parseDSN'); + $this->assertEquals('myname',$result['username'],'parseDSN'); + $this->assertEquals('mypassword',$result['password'],'parseDSN'); + $this->assertEquals(false,$result['database'],'parseDSN'); + + $dsn = "somesql://myname:mypassword@localhost:1234/mydb"; + $result = MDB2::parseDSN($dsn); + $this->assertEquals('somesql',$result['phptype'],'parseDSN'); + $this->assertEquals('somesql',$result['dbsyntax'],'parseDSN'); + $this->assertEquals('tcp',$result['protocol'],'parseDSN'); + $this->assertEquals('localhost',$result['hostspec'],'parseDSN'); + $this->assertEquals('1234',$result['port'],'parseDSN'); + $this->assertEquals(false,$result['socket'],'parseDSN'); + $this->assertEquals('myname',$result['username'],'parseDSN'); + $this->assertEquals('mypassword',$result['password'],'parseDSN'); + $this->assertEquals('mydb',$result['database'],'parseDSN'); + + $dsn = "dbms1://myname@unix(opts)/mydb?param1=value1"; + $result = MDB2::parseDSN($dsn); + $this->assertEquals('dbms1',$result['phptype'],'parseDSN'); + $this->assertEquals('dbms1',$result['dbsyntax'],'parseDSN'); + $this->assertEquals('unix',$result['protocol'],'parseDSN'); + $this->assertEquals(false,$result['hostspec'],'parseDSN'); + $this->assertEquals(false,$result['port'],'parseDSN'); + $this->assertEquals('opts',$result['socket'],'parseDSN'); + $this->assertEquals('myname',$result['username'],'parseDSN'); + $this->assertEquals(false,$result['password'],'parseDSN'); + $this->assertEquals('mydb',$result['database'],'parseDSN'); + $this->assertEquals('value1',$result['param1'],'parseDSN'); + } + + /** + * Tests that the MDB2::fileExists() method correctly identifies + * existing/non-existing files. + */ + function test_fileExists() + { + $this->assertTrue(MDB2::fileExists('PEAR.php'), 'fileExists'); + $this->assertFalse(MDB2::fileExists('itIsHopedThatNoOneHasAFileWithThisName.php'), 'fileExists'); + } + + /** + * Tests that the MDB2::__toString() method returns the expected + * string result. + */ + function test__toString() + { + $expected = "MDB2_Driver_{$this->dsn['phptype']}: (phptype = {$this->dsn['phptype']}, dbsyntax = {$this->db->dbsyntax})"; + if (version_compare(PHP_VERSION, "5.0.0", "<")) { + $expected = strtolower($expected); + } + $this->assertEquals($expected ,$this->db->__toString(), '__toString'); + } + + /** + * Tests that the MDB2::setFetchMode() method correctly sets the + * fetch mode. + */ + function test_setFetchMode() + { + $tmp = $this->db->fetchmode; + $this->db->setFetchMode(MDB2_FETCHMODE_OBJECT); + $this->assertEquals('stdClass', $this->db->options['fetch_class'], 'setFetchMode'); + $this->db->setFetchMode(MDB2_FETCHMODE_ORDERED); + $this->assertEquals(MDB2_FETCHMODE_ORDERED, $this->db->fetchmode, 'setFetchMode'); + $this->db->setFetchMode(MDB2_FETCHMODE_ASSOC); + $this->assertEquals(MDB2_FETCHMODE_ASSOC, $this->db->fetchmode, 'setFetchMode'); + $this->db->fetchmode = $tmp; + } + + /** + * Tests that the MDB2::escape() method correctly escapes strings. + */ + function test_escape() + { + $tmp = $this->db->string_quoting; + $this->string_quoting['escape'] = '\\'; + $this->string_quoting['end'] = '"'; + $text = 'xxx"z"xxx'; + $this->assertEquals('xxx\"z\"xxx', MDB2_Driver_Common::escape($text), 'escape'); + $this->db->string_quoting = $tmp; + } + + /** + * Tests that the MDB2::quoteIdentifier() method correctly quotes strings. + */ + function test_quoteIdentifier() + { + if ($this->db->phptype == 'ibase') { + return; + } + $tmp = $this->db->identifier_quoting; + $this->db->identifier_quoting['start'] = '"'; + $this->db->identifier_quoting['end'] = '`'; + $this->db->identifier_quoting['escape'] = '/'; + $text = 'my`identifier'; + $this->assertEquals('"my/`identifier`', $this->db->quoteIdentifier($text), 'quoteIdentifier'); + $this->db->identifier_quoting = $tmp; + } + + /** + * Tests that the MDB2::getAsKeyword() method correctly returns + * the set "as" keyword. + */ + function test_getAsKeyword() + { + $tmp = $this->db->as_keyword; + $this->db->as_keyword = 'ALIAS'; + $this->assertEquals('ALIAS', $this->db->getAsKeyword(), 'getAsKeyword'); + $this->db->as_keyword = $tmp; + } + + /** + * Tests that the MDB2::getConnection() method correctly returns + * a database resource. + */ + function test_getConnection() + { + $result = $this->db->getConnection(); + $this->assertTrue(is_resource($result), 'getConnection'); + } + + /** + * A private method to return a defined "row" of data for use + * in the next set of tests. + * + * @access private + * @return array The array of "row" data. + */ + function _fetchRowData() + { + return array( + 0 => '', + 1 => 'notnull', + 2 => 'length7 ', + '1?2:3.4' => 'assoc' + ); + } + + /** + * A private method to test results from the MDB2::_fixResultArrayValues() + * method when the $mode parameter was set to MDB2_PORTABILITY_EMPTY_TO_NULL. + * + * @access private + * @param array $row The result of the call to MDB2::_fixResultArrayValues(). + */ + function _fixResultArrayValues_Test_EmptyToNull($row) + { + $this->assertNull($row[0], '_fixResultArrayValues'); + $this->assertNotNull($row[1], '_fixResultArrayValues'); + $this->assertNotNull($row[2], '_fixResultArrayValues'); + } + + /** + * A private method to test results from the MDB2::_fixResultArrayValues() + * method when the $mode parameter was set to MDB2_PORTABILITY_RTRIM. + * + * @access private + * @param array $row The result of the call to MDB2::_fixResultArrayValues(). + */ + function _fixResultArrayValues_Test_Rtrim($row) + { + $this->assertEquals(strlen($row[0]), 0, '_fixResultArrayValues'); + $this->assertEquals(strlen($row[1]), 7, '_fixResultArrayValues'); + $this->assertEquals(strlen($row[2]), 7, '_fixResultArrayValues'); + } + + /** + * A private method to test results from the MDB2::_fixResultArrayValues() + * method when the $mode parameter was set to MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES. + * + * @access private + * @param array $row The result of the call to MDB2::_fixResultArrayValues(). + */ + function _fixResultArrayValues_Test_FixAssocFieldNames($row) + { + $this->assertTrue(array_key_exists(4, $row), '_fixResultArrayValues'); + $this->assertTrue($row[4] == 'assoc', '_fixResultArrayValues'); + } + + /** + * Tests that the MDB2::_fixResultArrayValues() method fixes array + * values when used with various $mode parameters. + */ + function test__fixResultArrayValues() + { + $mode = MDB2_PORTABILITY_EMPTY_TO_NULL; + $row = $this->_fetchRowData(); + $this->db->_fixResultArrayValues($row, $mode); + $this->_fixResultArrayValues_Test_EmptyToNull($row); + + $mode = MDB2_PORTABILITY_RTRIM; + $row = $this->_fetchRowData(); + $this->db->_fixResultArrayValues($row, $mode); + $this->_fixResultArrayValues_Test_Rtrim($row); + + $mode = MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES; + $row = $this->_fetchRowData(); + $this->db->_fixResultArrayValues($row, $mode); + $this->_fixResultArrayValues_Test_FixAssocFieldNames($row); + + $mode = MDB2_PORTABILITY_EMPTY_TO_NULL + MDB2_PORTABILITY_RTRIM; + $row = $this->_fetchRowData(); + $this->db->_fixResultArrayValues($row, $mode); + $this->_fixResultArrayValues_Test_EmptyToNull($row); + $this->_fixResultArrayValues_Test_Rtrim($row); + + $mode = MDB2_PORTABILITY_EMPTY_TO_NULL + MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES; + $row = $this->_fetchRowData(); + $this->db->_fixResultArrayValues($row, $mode); + $this->_fixResultArrayValues_Test_EmptyToNull($row); + $this->_fixResultArrayValues_Test_FixAssocFieldNames($row); + + $mode = MDB2_PORTABILITY_RTRIM + MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES; + $row = $this->_fetchRowData(); + $this->db->_fixResultArrayValues($row, $mode); + $this->_fixResultArrayValues_Test_Rtrim($row); + $this->_fixResultArrayValues_Test_FixAssocFieldNames($row); + + $mode = MDB2_PORTABILITY_EMPTY_TO_NULL + MDB2_PORTABILITY_RTRIM + MDB2_PORTABILITY_FIX_ASSOC_FIELD_NAMES; + $row = $this->_fetchRowData(); + $this->db->_fixResultArrayValues($row, $mode); + $this->_fixResultArrayValues_Test_EmptyToNull($row); + $this->_fixResultArrayValues_Test_Rtrim($row); + $this->_fixResultArrayValues_Test_FixAssocFieldNames($row); + } + + /** + * Tests that the MDB2::transaction() method returns expected values + * when starting or rolling back a transaction, and for testing if + * the connection is in a transaction. + */ + function test_transaction() + { + if (!$this->db->supports('transactions')) + { + $this->assertTrue($this->db->beginTransaction(), 'transaction'); + $this->assertTrue($this->db->in_transaction, 'transaction'); + $this->assertTrue($this->db->rollback(), 'transaction'); + $this->assertFalse($this->db->in_transaction, 'transaction'); + + $this->assertTrue($this->db->beginTransaction(), 'transaction'); + $this->assertTrue($this->db->in_transaction, 'transaction'); + $this->assertTrue($this->db->commit(), 'transaction'); + $this->assertFalse($this->db->in_transaction, 'transaction'); + } + } + + // Nested transactions are not yet tested, due to a MySQL 5 problem with + // savepoints causing netsted transactions to fail. + // + // See http://bugs.mysql.com/bug.php?id=26288 + + /** + * Tests that the MDB2::setDatabase() and MDB2::getDatabase() methods + * correctly set and get the database name. + */ + function test_setGetDatabase() + { + $old_name = $this->db->database_name; + $this->assertEquals($old_name, $this->db->setDatabase('test_database'), 'setDatabase'); + $this->assertEquals('test_database', $this->db->database_name, 'setDatabase'); + $this->assertEquals('test_database', $this->db->getDatabase(), 'getDatabase'); + $this->db->database_name = $old_name; + } + + /** + * Tests that the MDB2::setDSN() method correctly sets the DSN. + */ + function test_setDSN() + { + $dsn = "mydbms://myname:mypassword@localhost"; + $result = $this->db->setDSN($dsn); + $dsn_set = $this->db->dsn; + + $this->assertEquals('mydbms', $dsn_set['phptype'],'setDSN'); + $this->assertEquals('mydbms',$dsn_set['dbsyntax'],'setDSN'); + $this->assertEquals('tcp',$dsn_set['protocol'],'setDSN'); + $this->assertEquals('localhost',$dsn_set['hostspec'],'setDSN'); + $this->assertEquals(false,$dsn_set['port'],'setDSN'); + $this->assertEquals(false,$dsn_set['socket'],'setDSN'); + $this->assertEquals('myname',$dsn_set['username'],'setDSN'); + $this->assertEquals('mypassword',$dsn_set['password'],'setDSN'); + $this->assertEquals(false,$dsn_set['database'],'setDSN'); + } + + /** + * Tests that the MDB2::getDSN() method correctly gets the DSN. + */ + function test_getDSN() + { + $dsn_set = "mydbms://myname:mypassword@localhost"; + $result = $this->db->setDSN($dsn_set); + $dsn_get = $this->db->getDSN(); + $dsn_rex = "/(([\w]+)\(mydbms\):\/\/myname:mypassword@localhost\/)/"; + //preg_match($dsn_rex, $dsn_get, $matches); + $this->assertRegExp($dsn_rex, $dsn_get, 'testGetDSN'); + $dsn_rex = "/{$this->dsn['phptype']}[\w\W]+/"; + $this->assertRegExp($dsn_rex, $dsn_get, 'testGetDSN'); + + $dsn_set = "mydbms://myname:mypassword@localhost"; + $result = $this->db->setDSN($dsn_set); + $dsn_get = $this->db->getDSN('string', true); + $dsn_rex = "/(([\w]+)\(mydbms\):\/\/myname:1@localhost\/)/"; + $this->assertRegExp($dsn_rex, $dsn_get, 'testGetDSN'); + $dsn_rex = "/{$this->dsn['phptype']}[\w\W]+/"; + $this->assertRegExp($dsn_rex, $dsn_get, 'testGetDSN'); + } + + /** + * Tests that the 'new_link' DSN option is read correctly + */ + function test_isNewLinkSet() + { + $dsn = array( + 'phptype' => 'mydbms', + 'host' => 'localhost', + 'database' => 'dbname', + 'username' => 'myname', + 'password' => 'mypassword', + ); + $this->db->setDSN($dsn); + $this->assertFalse($this->db->_isNewLinkSet()); + $dsn['new_link'] = true; + $this->db->setDSN($dsn); + $this->assertTrue($this->db->_isNewLinkSet()); + $dsn['new_link'] = false; + $this->db->setDSN($dsn); + $this->assertFalse($this->db->_isNewLinkSet()); + $dsn['new_link'] = 'true'; + $this->db->setDSN($dsn); + $this->assertTrue($this->db->_isNewLinkSet()); + $dsn['new_link'] = 'false'; + $this->db->setDSN($dsn); + $this->assertFalse($this->db->_isNewLinkSet()); + $dsn['new_link'] = 1; + $this->db->setDSN($dsn); + $this->assertTrue($this->db->_isNewLinkSet()); + $dsn['new_link'] = 0; + $this->db->setDSN($dsn); + $this->assertFalse($this->db->_isNewLinkSet()); + $dsn['new_link'] = '1'; + $this->db->setDSN($dsn); + $this->assertTrue($this->db->_isNewLinkSet()); + $dsn['new_link'] = '0'; + $this->db->setDSN($dsn); + $this->assertFalse($this->db->_isNewLinkSet()); + $dsn['new_link'] = 'True'; + $this->db->setDSN($dsn); + $this->assertTrue($this->db->_isNewLinkSet()); + $dsn['new_link'] = 'TRUE'; + $this->db->setDSN($dsn); + $this->assertTrue($this->db->_isNewLinkSet()); + //now test some invalid values... + $dsn['new_link'] = new StdClass; + $this->db->setDSN($dsn); + $this->assertFalse($this->db->_isNewLinkSet()); + $dsn['new_link'] = ''; + $this->db->setDSN($dsn); + $this->assertFalse($this->db->_isNewLinkSet()); + $dsn['new_link'] = 'blah'; + $this->db->setDSN($dsn); + $this->assertFalse($this->db->_isNewLinkSet()); + } + + /** + * Tests that the MDB2::setLimit() method correctly sets the limit + * and offset values. + */ + function test_setLimit() + { + if (!$this->db->supports('limit_queries')) + { + $this->db->limit = null; + $this->db->offset = null; + $this->db->setLimit(100, 50); + $this->assertEquals(100, $this->db->limit , 'setLimit'); + $this->assertEquals( 50, $this->db->offset, 'setLimit'); + } + } + + /** + * Tests that the MDB2::supports() method correctly finds keys + * in the "supports" array. + */ + function test_supports() + { + $this->db->supports['testkey'] = true; + $this->assertTrue($this->db->supports('testkey'), 'supports'); + unset($this->db->supports['testkey']); + } + + /** + * Tests that the MDB2::getSequenceName() method correctly gets + * sequence names. + */ + function test_getSequenceName() + { + $tmp = $this->db->options['seqname_format']; + $this->db->options['seqname_format'] = '%s_seq'; + $this->assertEquals('test_seq', strtolower($this->db->getSequenceName('test')), 'getSequenceName'); + $this->db->options['seqname_format'] = $tmp; + } + + /** + * Tests that the MDB2::getIndexName() method correctly gets index names. + */ + function test_getIndexName() + { + $tmp = $this->db->options['idxname_format']; + $this->db->options['idxname_format'] = 'idx_%s'; + $this->assertEquals('idx_test', $this->db->getIndexName('test'), 'getIndexName'); + $this->db->options['idxname_format'] = $tmp; + } + + /** + * Tests that the MDB2::disconnect() method correctly disconnects. + */ + function test_disconnect() + { + $this->assertTrue($this->db->disconnect(), 'disconnect'); + $this->assertEquals(0, $this->db->connection, 'disconnect'); + $this->assertEquals(array(), $this->db->connected_dsn, 'disconnect'); + $this->assertEquals('', $this->db->connected_database_name, 'disconnect'); + $this->assertNull($this->db->opened_persistent, 'disconnect'); + $this->assertEquals('', $this->db->connected_server_info, 'disconnect'); + $this->assertNull($this->db->in_transaction, 'disconnect'); + $this->assertNull($this->db->nested_transaction_counter, 'disconnect'); + } + + /** + * Test that the MDB2::_skipDelimitedStrings() method correctly recognizes + * parameter placeholders from quoted strings + */ + function test_skipDelimitedStrings() { + $query = "UPDATE tbl SET fld='' WHERE fld2=:param AND fld3=':fakeparam' AND fld3=:param2"; + $this->assertEquals(0, $this->db->_skipDelimitedStrings($query, 0, 0)); + $this->assertEquals(18, $this->db->_skipDelimitedStrings($query, 18, 19)); + $this->assertEquals(20, $this->db->_skipDelimitedStrings($query, 20, 20)); + $this->assertEquals(21, $this->db->_skipDelimitedStrings($query, 19, 21)); + $this->assertEquals(30, $this->db->_skipDelimitedStrings($query, 30, 33)); + $this->assertEquals(30, $this->db->_skipDelimitedStrings($query, 30, 34)); + $this->assertEquals(33, $this->db->_skipDelimitedStrings($query, 33, 33)); + $this->assertEquals(50, $this->db->_skipDelimitedStrings($query, 50, 50)); + $this->assertEquals(61, $this->db->_skipDelimitedStrings($query, 49, 51)); + $this->assertEquals(52, $this->db->_skipDelimitedStrings($query, 52, 52)); + $this->assertEquals(70, $this->db->_skipDelimitedStrings($query, 70, 72)); + $this->assertEquals(71, $this->db->_skipDelimitedStrings($query, 71, 72)); + $this->assertEquals(72, $this->db->_skipDelimitedStrings($query, 72, 72)); + + //be careful about SQL comments that are not comments (because within quotes) + $query = "UPDATE tbl SET fld='--some text' WHERE col2=?"; + $this->assertEquals(0, $this->db->_skipDelimitedStrings($query, 0, 0)); + $this->assertEquals(18, $this->db->_skipDelimitedStrings($query, 18, 19)); + $this->assertEquals(20, $this->db->_skipDelimitedStrings($query, 20, 20)); + $this->assertEquals(32, $this->db->_skipDelimitedStrings($query, 19, 21)); + } + +} + +?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/tests/MDB2_manager_testcase.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/MDB2_manager_testcase.php --- php-mdb2-2.4.1/MDB2-2.5.0b2/tests/MDB2_manager_testcase.php 1970-01-01 01:00:00.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/MDB2_manager_testcase.php 2009-01-14 16:28:09.000000000 +0000 @@ -0,0 +1,919 @@ + | +// | Lorenzo Alberton | +// +----------------------------------------------------------------------+ +// +// $Id: MDB2_manager_testcase.php,v 1.65 2008/03/08 14:04:15 quipo Exp $ + +require_once 'MDB2_testcase.php'; + +class MDB2_Manager_TestCase extends MDB2_TestCase { + //test table name (it is dynamically created/dropped) + var $table = 'newtable'; + + function setUp() { + parent::setUp(); + $this->db->loadModule('Manager', null, true); + $this->fields = array( + 'id' => array( + 'type' => 'integer', + 'unsigned' => true, + 'notnull' => true, + 'default' => 0, + ), + 'somename' => array( + 'type' => 'text', + 'length' => 12, + ), + 'somedescription' => array( + 'type' => 'text', + 'length' => 12, + ), + 'sex' => array( + 'type' => 'text', + 'length' => 1, + 'default' => 'M', + ), + ); + $options = array(); + if ('mysql' == substr($this->db->phptype, 0, 5)) { + $options['type'] = 'innodb'; + } + if (!$this->tableExists($this->table)) { + $result = $this->db->manager->createTable($this->table, $this->fields, $options); + $this->assertFalse(PEAR::isError($result), 'Error creating table'); + $this->assertEquals(MDB2_OK, $result, 'Invalid return value for createTable()'); + } + } + + function tearDown() { + if ($this->tableExists($this->table)) { + $result = $this->db->manager->dropTable($this->table); + $this->assertFalse(PEAR::isError($result), 'Error dropping table'); + } + $this->db->popExpect(); + unset($this->dsn); + if (!PEAR::isError($this->db->manager)) { + $this->db->disconnect(); + } + unset($this->db); + } + + /** + * Create a sample table, test the new fields, and drop it. + */ + function testCreateTable() { + if (!$this->methodExists($this->db->manager, 'createTable')) { + return; + } + if ($this->tableExists($this->table)) { + $this->db->manager->dropTable($this->table); + } + + $result = $this->db->manager->createTable($this->table, $this->fields); + $this->assertFalse(PEAR::isError($result), 'Error creating table'); + } + + /** + * Create a sample table, test the new fields, and drop it. + */ + function testCreateAutoIncrementTable() { + if (!$this->methodExists($this->db->manager, 'createTable')) { + return; + } + if ($this->tableExists($this->table)) { + $this->db->manager->dropTable($this->table); + } + $seq_name = $this->table; + if ('ibase' == $this->db->phptype) { + $seq_name .= '_id'; + } + //remove existing PK sequence + $sequences = $this->db->manager->listSequences(); + if (in_array($seq_name, $sequences)) { + $this->db->manager->dropSequence($seq_name); + } + + $fields = $this->fields; + $fields['id']['autoincrement'] = true; + $result = $this->db->manager->createTable($this->table, $fields); + $this->assertFalse(PEAR::isError($result), 'Error creating table'); + $this->assertEquals(MDB2_OK, $result, 'Error creating table: unexpected return value'); + $query = 'INSERT INTO '.$this->db->quoteIdentifier($this->table, true); + $query.= ' (somename, somedescription)'; + $query.= ' VALUES (:somename, :somedescription)'; + $stmt =& $this->db->prepare($query, array('text', 'text'), MDB2_PREPARE_MANIP); + if (PEAR::isError($stmt)) { + $this->assertFalse(true, 'Preparing insert'); + return; + } + $values = array( + 'somename' => 'foo', + 'somedescription' => 'bar', + ); + $rows = 5; + for ($i =0; $i < $rows; ++$i) { + $result = $stmt->execute($values); + if (PEAR::isError($result)) { + $this->assertFalse(true, 'Error executing autoincrementing insert number: '.$i); + return; + } + } + $stmt->free(); + $query = 'SELECT id FROM '.$this->table; + $data = $this->db->queryCol($query, 'integer'); + if (PEAR::isError($data)) { + $this->assertFalse(true, 'Error executing select: ' . $data->getMessage()); + return; + } + for ($i =0; $i < $rows; ++$i) { + if (!isset($data[$i])) { + $this->assertFalse(true, 'Error in data returned by select'); + return; + } + if ($data[$i] !== ($i+1)) { + $this->assertFalse(true, 'Error executing autoincrementing insert'); + return; + } + } + } + + /** + * + */ + function testListTableFields() { + if (!$this->methodExists($this->db->manager, 'listTableFields')) { + return; + } + $this->assertEquals( + array_keys($this->fields), + $this->db->manager->listTableFields($this->table), + 'Error creating table: incorrect fields' + ); + } + + /** + * + */ + function testCreateIndex() { + if (!$this->methodExists($this->db->manager, 'createIndex')) { + return; + } + $index = array( + 'fields' => array( + 'somename' => array( + 'sorting' => 'ascending', + ), + ), + ); + $name = 'simpleindex'; + $result = $this->db->manager->createIndex($this->table, $name, $index); + $this->assertFalse(PEAR::isError($result), 'Error creating index'); + } + + /** + * + */ + function testDropIndex() { + if (!$this->methodExists($this->db->manager, 'dropIndex')) { + return; + } + $index = array( + 'fields' => array( + 'somename' => array( + 'sorting' => 'ascending', + ), + ), + ); + $name = 'simpleindex'; + $result = $this->db->manager->createIndex($this->table, $name, $index); + if (PEAR::isError($result)) { + $this->assertFalse(true, 'Error creating index'); + } else { + $result = $this->db->manager->dropIndex($this->table, $name); + $this->assertFalse(PEAR::isError($result), 'Error dropping index'); + $indices = $this->db->manager->listTableIndexes($this->table); + $this->assertFalse(PEAR::isError($indices), 'Error listing indices'); + $this->assertFalse(in_array($name, $indices), 'Error dropping index'); + } + } + + /** + * + */ + function testListIndexes() { + if (!$this->methodExists($this->db->manager, 'listTableIndexes')) { + return; + } + $index = array( + 'fields' => array( + 'somename' => array( + 'sorting' => 'ascending', + ), + ), + ); + $name = 'simpleindex'; + $result = $this->db->manager->createIndex($this->table, $name, $index); + if (PEAR::isError($result)) { + $this->assertFalse(true, 'Error creating index'); + } else { + $indices = $this->db->manager->listTableIndexes($this->table); + $this->assertFalse(PEAR::isError($indices), 'Error listing indices'); + $this->assertTrue(in_array($name, $indices), 'Error listing indices'); + } + } + + /** + * + */ + function testCreatePrimaryKey() { + if (!$this->methodExists($this->db->manager, 'createConstraint')) { + return; + } + $constraint = array( + 'fields' => array( + 'id' => array( + 'sorting' => 'ascending', + ), + ), + 'primary' => true, + ); + $name = 'pkindex'; + $result = $this->db->manager->createConstraint($this->table, $name, $constraint); + $this->assertFalse(PEAR::isError($result), 'Error creating primary key constraint'); + } + + /** + * + */ + function testCreateUniqueConstraint() { + if (!$this->methodExists($this->db->manager, 'createConstraint')) { + return; + } + $constraint = array( + 'fields' => array( + 'somename' => array( + 'sorting' => 'ascending', + ), + ), + 'unique' => true, + ); + $name = 'uniqueindex'; + $result = $this->db->manager->createConstraint($this->table, $name, $constraint); + $this->assertFalse(PEAR::isError($result), 'Error creating unique constraint'); + } + + /** + * + */ + function testCreateForeignKeyConstraint() { + if (!$this->methodExists($this->db->manager, 'createConstraint')) { + return; + } + $constraint = array( + 'fields' => array( + 'id' => array( + 'sorting' => 'ascending', + ), + ), + 'foreign' => true, + 'references' => array( + 'table' => 'users', + 'fields' => array( + 'user_id' => array( + 'position' => 1, + ), + ), + ), + 'initiallydeferred' => false, + 'deferrable' => false, + 'match' => 'SIMPLE', + 'onupdate' => 'CASCADE', + 'ondelete' => 'CASCADE', + ); + $constraint_name = 'fkconstraint'; + $result = $this->db->manager->createConstraint($this->table, $constraint_name, $constraint); + $this->assertFalse(PEAR::isError($result), 'Error creating FOREIGN KEY constraint'); + + //see if it was created successfully + $constraints = $this->db->manager->listTableConstraints($this->table); + $this->assertTrue(!PEAR::isError($constraints), 'Error listing table constraints'); + $constraint_name_idx = $this->db->getIndexName($constraint_name); + $this->assertTrue(in_array($constraint_name_idx, $constraints) || in_array($constraint_name, $constraints), 'Error, FK constraint not found'); + + //now check that it is enforced... + + //insert a row in the primary table + $result = $this->db->exec('INSERT INTO users (user_id) VALUES (1)'); + $this->assertTrue(!PEAR::isError($result), 'Insert failed'); + + //insert a row in the FK table with an id that references + //the newly inserted row on the primary table: should not fail + $query = 'INSERT INTO '.$this->db->quoteIdentifier($this->table, true) + .' ('.$this->db->quoteIdentifier('id', true).') VALUES (1)'; + $result = $this->db->exec($query); + $this->assertTrue(!PEAR::isError($result), 'Insert failed'); + + //try to insert a row into the FK table with an id that does not + //exist in the primary table: should fail + $query = 'INSERT INTO '.$this->db->quoteIdentifier($this->table, true) + .' ('.$this->db->quoteIdentifier('id', true).') VALUES (123456)'; + $this->db->pushErrorHandling(PEAR_ERROR_RETURN); + $this->db->expectError('*'); + $result = $this->db->exec($query); + $this->db->popExpect(); + $this->db->popErrorHandling(); + $this->assertTrue(PEAR::isError($result), 'Foreign Key constraint is not enforced for INSERT query'); + + //try to update the first row of the FK table with an id that does not + //exist in the primary table: should fail + $query = 'UPDATE '.$this->db->quoteIdentifier($this->table, true) + .' SET '.$this->db->quoteIdentifier('id', true).' = 123456 ' + .' WHERE '.$this->db->quoteIdentifier('id', true).' = 1'; + $this->db->expectError('*'); + $result = $this->db->exec($query); + $this->db->popExpect(); + $this->assertTrue(PEAR::isError($result), 'Foreign Key constraint is not enforced for UPDATE query'); + + $numrows_query = 'SELECT COUNT(*) FROM '. $this->db->quoteIdentifier($this->table, true); + $numrows = $this->db->queryOne($numrows_query, 'integer'); + $this->assertEquals(1, $numrows, 'Invalid number of rows in the FK table'); + + //update the PK value of the primary table: the new value should be + //propagated to the FK table (ON UPDATE CASCADE) + $result = $this->db->exec('UPDATE users SET user_id = 2'); + $this->assertTrue(!PEAR::isError($result), 'Update failed'); + + $numrows = $this->db->queryOne($numrows_query, 'integer'); + $this->assertEquals(1, $numrows, 'Invalid number of rows in the FK table'); + + $query = 'SELECT id FROM '.$this->db->quoteIdentifier($this->table, true); + $newvalue = $this->db->queryOne($query, 'integer'); + $this->assertEquals(2, $newvalue, 'The value of the FK field was not updated (CASCADE failed)'); + + //delete the row of the primary table: the row in the FK table should be + //deleted automatically (ON DELETE CASCADE) + $result = $this->db->exec('DELETE FROM users'); + $this->assertTrue(!PEAR::isError($result), 'Delete failed'); + + $numrows = $this->db->queryOne($numrows_query, 'integer'); + $this->assertEquals(0, $numrows, 'Invalid number of rows in the FK table (CASCADE failed)'); + + //cleanup + $result = $this->db->manager->dropConstraint($this->table, $constraint_name); + $this->assertTrue(!PEAR::isError($result), 'Error dropping the constraint'); + } + + /** + * + */ + function testDropPrimaryKey() { + if (!$this->methodExists($this->db->manager, 'dropConstraint')) { + return; + } + $index = array( + 'fields' => array( + 'id' => array( + 'sorting' => 'ascending', + ), + ), + 'primary' => true, + ); + $name = 'pkindex'; + $result = $this->db->manager->createConstraint($this->table, $name, $index); + if (PEAR::isError($result)) { + $this->assertFalse(true, 'Error creating primary index'); + } else { + $result = $this->db->manager->dropConstraint($this->table, $name, true); + $this->assertFalse(PEAR::isError($result), 'Error dropping primary key index'); + } + } + + /** + * + */ + function testListDatabases() { + if (!$this->methodExists($this->db->manager, 'listDatabases')) { + return; + } + $result = $this->db->manager->listDatabases(); + if (PEAR::isError($result)) { + $this->assertFalse(true, 'Error listing databases ('.$result->getMessage().')'); + } else { + $this->assertTrue(in_array(strtolower($this->database), $result), 'Error listing databases'); + } + } + + /** + * + */ + function testListConstraints() { + if (!$this->methodExists($this->db->manager, 'listTableConstraints')) { + return; + } + $index = array( + 'fields' => array( + 'id' => array( + 'sorting' => 'ascending', + ), + ), + 'unique' => true, + ); + $name = 'uniqueindex'; + $result = $this->db->manager->createConstraint($this->table, $name, $index); + if (PEAR::isError($result)) { + $this->assertFalse(true, 'Error creating unique constraint'); + } else { + $constraints = $this->db->manager->listTableConstraints($this->table); + $this->assertFalse(PEAR::isError($constraints), 'Error listing constraints'); + $this->assertTrue(in_array($name, $constraints), 'Error listing unique key index'); + } + } + + /** + * + */ + function testListTables() { + if (!$this->methodExists($this->db->manager, 'listTables')) { + return; + } + $this->assertTrue($this->tableExists($this->table), 'Error listing tables'); + } + + /** + * + */ + function testAlterTable() { + if (!$this->methodExists($this->db->manager, 'alterTable')) { + return; + } + $newer = 'newertable'; + if ($this->tableExists($newer)) { + $this->db->manager->dropTable($newer); + } + $changes = array( + 'add' => array( + 'quota' => array( + 'type' => 'integer', + 'unsigned' => 1, + ), + 'note' => array( + 'type' => 'text', + 'length' => '20', + ), + ), + 'rename' => array( + 'sex' => array( + 'name' => 'gender', + 'definition' => array( + 'type' => 'text', + 'length' => 1, + 'default' => 'M', + ), + ), + ), + 'change' => array( + 'id' => array( + 'unsigned' => false, + 'definition' => array( + 'type' => 'integer', + 'notnull' => false, + 'default' => 0, + ), + ), + 'somename' => array( + 'length' => '20', + 'definition' => array( + 'type' => 'text', + 'length' => 20, + ), + ) + ), + 'remove' => array( + 'somedescription' => array(), + ), + 'name' => $newer, + ); + + $this->db->expectError(MDB2_ERROR_CANNOT_ALTER); + $result = $this->db->manager->alterTable($this->table, $changes, true); + $this->db->popExpect(); + if (PEAR::isError($result)) { + $this->assertFalse(true, 'Cannot alter table'); + } else { + $result = $this->db->manager->alterTable($this->table, $changes, false); + if (PEAR::isError($result)) { + $this->assertFalse(true, 'Error altering table'); + } else { + $this->db->manager->dropTable($newer); + } + } + } + + /** + * + */ + function testAlterTable2() { + if (!$this->methodExists($this->db->manager, 'alterTable')) { + return; + } + $newer = 'newertable2'; + if ($this->tableExists($newer)) { + $this->db->manager->dropTable($newer); + } + $changes_all = array( + 'add' => array( + 'quota' => array( + 'type' => 'integer', + 'unsigned' => 1, + ), + ), + 'rename' => array( + 'sex' => array( + 'name' => 'gender', + 'definition' => array( + 'type' => 'text', + 'length' => 1, + 'default' => 'M', + ), + ), + ), + 'change' => array( + 'somename' => array( + 'length' => '20', + 'definition' => array( + 'type' => 'text', + 'length' => 20, + ), + ) + ), + 'remove' => array( + 'somedescription' => array(), + ), + 'name' => $newer, + ); + + foreach ($changes_all as $type => $change) { + $changes = array($type => $change); + $this->db->expectError(MDB2_ERROR_CANNOT_ALTER); + $result = $this->db->manager->alterTable($this->table, $changes, true); + $this->db->popExpect(); + if (PEAR::isError($result)) { + $this->assertFalse(true, 'Cannot alter table: '.$type); + return; + } + $result = $this->db->manager->alterTable($this->table, $changes, false); + if (PEAR::isError($result)) { + $this->assertFalse(true, 'Error altering table: '.$type); + } else { + switch ($type) { + case 'add': + $altered_table_fields = $this->db->manager->listTableFields($this->table); + foreach ($change as $newfield => $dummy) { + $this->assertTrue(in_array($newfield, $altered_table_fields), 'Error: new field "'.$newfield.'" not added'); + } + break; + case 'rename': + $altered_table_fields = $this->db->manager->listTableFields($this->table); + foreach ($change as $oldfield => $newfield) { + $this->assertFalse(in_array($oldfield, $altered_table_fields), 'Error: field "'.$oldfield.'" not renamed'); + $this->assertTrue(in_array($newfield['name'], $altered_table_fields), 'Error: field "'.$oldfield.'" not renamed correctly'); + } + break; + case 'change': + break; + case 'remove': + $altered_table_fields = $this->db->manager->listTableFields($this->table); + foreach ($change as $newfield => $dummy) { + $this->assertFalse(in_array($newfield, $altered_table_fields), 'Error: field "'.$newfield.'" not removed'); + } + break; + case 'name': + if ($this->tableExists($newer)) { + $this->db->manager->dropTable($newer); + } else { + $this->assertFalse(true, 'Error: table "'.$this->table.'" not renamed'); + } + break; + } + } + } + } + + /** + * + */ + function testTruncateTable() { + if (!$this->methodExists($this->db->manager, 'truncateTable')) { + return; + } + + $query = 'INSERT INTO '.$this->table; + $query.= ' (id, somename, somedescription)'; + $query.= ' VALUES (:id, :somename, :somedescription)'; + $stmt =& $this->db->prepare($query, array('integer', 'text', 'text'), MDB2_PREPARE_MANIP); + if (PEAR::isError($stmt)) { + $this->assertFalse(true, 'Error preparing INSERT'); + return; + } + $rows = 5; + for ($i=1; $i<=$rows; ++$i) { + $values = array( + 'id' => $i, + 'somename' => 'foo'.$i, + 'somedescription' => 'bar'.$i, + ); + $result = $stmt->execute($values); + if (PEAR::isError($result)) { + $this->assertFalse(true, 'Error executing insert number: '.$i); + return; + } + } + $stmt->free(); + $count = $this->db->queryOne('SELECT COUNT(*) FROM '.$this->table, 'integer'); + if (PEAR::isError($count)) { + $this->assertFalse(true, 'Error executing SELECT'); + return; + } + $this->assertEquals($rows, $count, 'Error: invalid number of rows returned'); + + $result = $this->db->manager->truncateTable($this->table); + if (PEAR::isError($result)) { + $this->assertFalse(true, 'Error truncating table'); + } + + $count = $this->db->queryOne('SELECT COUNT(*) FROM '.$this->table, 'integer'); + if (PEAR::isError($count)) { + $this->assertFalse(true, 'Error executing SELECT'); + return; + } + $this->assertEquals(0, $count, 'Error: invalid number of rows returned'); + } + + /** + * + */ + function testDropTable() { + if (!$this->methodExists($this->db->manager, 'dropTable')) { + return; + } + $result = $this->db->manager->dropTable($this->table); + $this->assertFalse(PEAR::isError($result), 'Error dropping table'); + } + + /** + * + */ + function testListTablesNoTable() { + if (!$this->methodExists($this->db->manager, 'listTables')) { + return; + } + $result = $this->db->manager->dropTable($this->table); + $this->assertFalse($this->tableExists($this->table), 'Error listing tables'); + } + + /** + * + */ + function testSequences() { + if (!$this->methodExists($this->db->manager, 'createSequence')) { + return; + } + $seq_name = 'testsequence'; + $result = $this->db->manager->createSequence($seq_name); + $this->assertFalse(PEAR::isError($result), 'Error creating a sequence'); + $this->assertTrue(in_array($seq_name, $this->db->manager->listSequences()), 'Error listing sequences'); + $result = $this->db->manager->dropSequence($seq_name); + $this->assertFalse(PEAR::isError($result), 'Error dropping a sequence'); + $this->assertFalse(in_array($seq_name, $this->db->manager->listSequences()), 'Error listing sequences'); + } + + /** + * Test listTableTriggers($table) + */ + function testListTableTriggers() { + //setup + $trigger_name = 'test_newtrigger'; + + include_once 'MDB2_nonstandard.php'; + $nonstd =& MDB2_nonstandard::factory($this->db, $this); + if (PEAR::isError($nonstd)) { + $this->assertTrue(false, 'Cannot instanciate MDB2_nonstandard object: '.$nonstd->getMessage()); + return; + } + + $result = $nonstd->createTrigger($trigger_name, $this->table); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Cannot create trigger: '.$result->getMessage()); + return; + } + + //test + $triggers = $this->db->manager->listTableTriggers($this->table); + if (PEAR::isError($triggers)) { + $this->assertTrue(false, 'Error listing the table triggers: '.$triggers->getMessage()); + } else { + $this->assertTrue(in_array($trigger_name, $triggers), 'Error: trigger not found'); + //check that only the triggers referencing the given table are returned + $triggers = $this->db->manager->listTableTriggers('fake_table'); + $this->assertFalse(in_array($trigger_name, $triggers), 'Error: trigger found'); + } + + + //cleanup + $result = $nonstd->dropTrigger($trigger_name, $this->table); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error dropping the trigger: '.$result->getMessage()); + } + } + + /** + * Test listTableViews($table) + */ + function testListTableViews() { + //setup + $view_name = 'test_newview'; + + include_once 'MDB2_nonstandard.php'; + $nonstd =& MDB2_nonstandard::factory($this->db, $this); + if (PEAR::isError($nonstd)) { + $this->assertTrue(false, 'Cannot instanciate MDB2_nonstandard object: '.$nonstd->getMessage()); + return; + } + + $result = $nonstd->createView($view_name, $this->table); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Cannot create view: '.$result->getMessage()); + return; + } + + //test + $views = $this->db->manager->listTableViews($this->table); + if (PEAR::isError($views)) { + $this->assertTrue(false, 'Error listing the table views: '.$views->getMessage()); + } else { + $this->assertTrue(in_array($view_name, $views), 'Error: view not found'); + //check that only the views referencing the given table are returned + $views = $this->db->manager->listTableViews('fake_table'); + $this->assertFalse(in_array($view_name, $views), 'Error: view found'); + } + + + //cleanup + $result = $nonstd->dropView($view_name); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error dropping the view: '.$result->getMessage()); + } + } + + /** + * Test listViews() + */ + function testListViews() { + //setup + $view_name = 'test_brandnewview'; + + include_once 'MDB2_nonstandard.php'; + $nonstd =& MDB2_nonstandard::factory($this->db, $this); + if (PEAR::isError($nonstd)) { + $this->assertTrue(false, 'Cannot instanciate MDB2_nonstandard object: '.$nonstd->getMessage()); + return; + } + + $result = $nonstd->createView($view_name, $this->table); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Cannot create view: '.$result->getMessage()); + return; + } + + //test + $views = $this->db->manager->listViews(); + if (PEAR::isError($views)) { + $this->assertTrue(false, 'Error listing the views: '.$views->getMessage()); + } else { + $this->assertTrue(in_array($view_name, $views), 'Error: view not found'); + } + + //cleanup + $result = $nonstd->dropView($view_name); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error dropping the view: '.$result->getMessage()); + } + } + + /** + * Test listUsers() + */ + function testListUsers() { + $users = $this->db->manager->listUsers(); + if (PEAR::isError($users)) { + $this->assertTrue(false, 'Error listing the users: '.$users->getMessage()); + } else { + $users = array_map('strtolower', $users); + $this->assertTrue(in_array(strtolower($this->db->dsn['username']), $users), 'Error: user not found'); + } + } + + /** + * Test listFunctions() + */ + function testListFunctions() { + //setup + $function_name = 'test_add'; + + include_once 'MDB2_nonstandard.php'; + $nonstd =& MDB2_nonstandard::factory($this->db, $this); + if (PEAR::isError($nonstd)) { + $this->assertTrue(false, 'Cannot instanciate MDB2_nonstandard object: '.$nonstd->getMessage()); + return; + } + + $result = $nonstd->createFunction($function_name); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Cannot create function: '.$result->getMessage().' :: '.$result->getUserInfo()); + return; + } + + //test + $functions = $this->db->manager->listFunctions(); + if (PEAR::isError($functions)) { + $this->assertTrue(false, 'Error listing the functions: '.$functions->getMessage()); + } else { + $this->assertTrue(in_array($function_name, $functions), 'Error: function not found'); + } + + //cleanup + $result = $nonstd->dropFunction($function_name); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error dropping the function: '.$result->getMessage()); + } + } + + /** + * Test vacuum + */ + function testVacuum() { + //vacuum table + $result = $this->db->manager->vacuum($this->table); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error: cannot vacuum table: ' . $result->getMessage()); + } + + //vacuum and analyze table + $options = array( + 'analyze' => true, + 'full' => true, + 'freeze' => true, + ); + $result = $this->db->manager->vacuum($this->table, $options); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error: cannot vacuum table: ' . $result->getMessage()); + } + + //vacuum all tables + $result = $this->db->manager->vacuum(); + if (PEAR::isError($result)) { + $this->assertTrue(false, 'Error: cannot vacuum table: ' . $result->getMessage()); + } + } +} +?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/tests/MDB2_native_testcase.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/MDB2_native_testcase.php --- php-mdb2-2.4.1/MDB2-2.5.0b2/tests/MDB2_native_testcase.php 1970-01-01 01:00:00.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/MDB2_native_testcase.php 2009-01-14 16:28:09.000000000 +0000 @@ -0,0 +1,52 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: MDB2_native_testcase.php,v 1.12 2006/03/01 12:15:38 lsmith Exp $ + +require_once 'MDB2_testcase.php'; + +class MDB2_Native_TestCase extends MDB2_TestCase +{ +} + +?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/tests/MDB2_nonstandard_ibase.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/MDB2_nonstandard_ibase.php --- php-mdb2-2.4.1/MDB2-2.5.0b2/tests/MDB2_nonstandard_ibase.php 1970-01-01 01:00:00.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/MDB2_nonstandard_ibase.php 2009-01-14 16:28:09.000000000 +0000 @@ -0,0 +1,90 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: MDB2_nonstandard_ibase.php,v 1.5 2007/03/04 21:32:31 quipo Exp $ + +class MDB2_nonstandard_ibase extends MDB2_nonstandard { + + var $trigger_body = 'AS +BEGIN + NEW.somedescription = OLD.somename; +END'; + + function createTrigger($trigger_name, $table_name) { + $query = 'CREATE OR ALTER TRIGGER '. $trigger_name .' FOR '. $table_name .' + AFTER UPDATE '. $this->trigger_body .';'; + return $this->db->exec($query); + } + + function checkTrigger($trigger_name, $table_name, $def) { + parent::checkTrigger($trigger_name, $table_name, $def); + $this->test->assertEquals($this->trigger_body, $def['trigger_body']); + } + + function dropTrigger($trigger_name, $table_name) { + return $this->db->exec('DROP TRIGGER '.$trigger_name); + } + + function createFunction($name) { + $query = 'CREATE PROCEDURE '.$name.'(N1 DECIMAL(6,2), N2 DECIMAL(6,2)) +RETURNS ( + res DECIMAL(6,2) +) +AS +BEGIN + FOR + SELECT (:N1 + :N2) FROM RDB$DATABASE INTO :res + DO + BEGIN + SUSPEND; + END +END'; + return $this->db->exec($query); + } + + function dropFunction($name) { + return $this->db->exec('DROP PROCEDURE '.$name); + } +} + +?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/tests/MDB2_nonstandard_mssql.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/MDB2_nonstandard_mssql.php --- php-mdb2-2.4.1/MDB2-2.5.0b2/tests/MDB2_nonstandard_mssql.php 1970-01-01 01:00:00.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/MDB2_nonstandard_mssql.php 2009-01-14 16:28:09.000000000 +0000 @@ -0,0 +1,88 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: MDB2_nonstandard_mssql.php,v 1.2 2007/03/04 21:27:44 quipo Exp $ + +class MDB2_nonstandard_mssql extends MDB2_nonstandard { + + var $trigger_body = ''; + + function createTrigger($trigger_name, $table_name) { + $this->trigger_body = 'CREATE TRIGGER '. $trigger_name .' ON '. $table_name .' +FOR UPDATE AS +DECLARE @oldName VARCHAR(100) +DECLARE @newId INTEGER +SELECT @oldName = (SELECT somename FROM Deleted) +SELECT @newId = (SELECT id FROM Inserted) +BEGIN + UPDATE '. $table_name .' SET somedescription = @oldName WHERE id = @newId; +END;'; + + return $this->db->exec($this->trigger_body); + } + + function checkTrigger($trigger_name, $table_name, $def) { + parent::checkTrigger($trigger_name, $table_name, $def); + $this->test->assertEquals($this->trigger_body, $def['trigger_body']); + echo '
    ';
    +        var_dump($this->trigger_body);
    +        var_dump($def['trigger_body']);
    +    }
    +
    +    function dropTrigger($trigger_name, $table_name) {
    +        return $this->db->exec('DROP TRIGGER '.$trigger_name);
    +    }
    +    
    +    function createFunction($name) {
    +        $query = 'CREATE FUNCTION '.$name.'(@Number1 Decimal(6,2), @Number2 Decimal(6,2))
    +RETURNS Decimal(6,2)
    +BEGIN
    +    DECLARE @Result Decimal(6,2)
    +    SET @Result = @Number1 + @Number2
    +    RETURN @Result
    +END';
    +        return $this->db->exec($query);
    +    }
    +}
    +
    +?>
    \ No newline at end of file
    diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/tests/MDB2_nonstandard_mysqli.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/MDB2_nonstandard_mysqli.php
    --- php-mdb2-2.4.1/MDB2-2.5.0b2/tests/MDB2_nonstandard_mysqli.php	1970-01-01 01:00:00.000000000 +0100
    +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/MDB2_nonstandard_mysqli.php	2009-01-14 16:28:09.000000000 +0000
    @@ -0,0 +1,52 @@
    +                       |
    +// +----------------------------------------------------------------------+
    +//
    +// $Id: MDB2_nonstandard_mysqli.php,v 1.1 2006/12/09 14:31:54 quipo Exp $
    +
    +require_once 'MDB2_nonstandard_mysql.php';
    +
    +class MDB2_nonstandard_mysqli extends MDB2_nonstandard_mysql {
    +
    +}
    +
    +?>
    \ No newline at end of file
    diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/tests/MDB2_nonstandard_mysql.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/MDB2_nonstandard_mysql.php
    --- php-mdb2-2.4.1/MDB2-2.5.0b2/tests/MDB2_nonstandard_mysql.php	1970-01-01 01:00:00.000000000 +0100
    +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/MDB2_nonstandard_mysql.php	2009-01-14 16:28:09.000000000 +0000
    @@ -0,0 +1,75 @@
    +                       |
    +// +----------------------------------------------------------------------+
    +//
    +// $Id: MDB2_nonstandard_mysql.php,v 1.4 2007/03/04 22:51:06 quipo Exp $
    +
    +class MDB2_nonstandard_mysql extends MDB2_nonstandard {
    +
    +    var $trigger_body = '';
    +
    +    function createTrigger($trigger_name, $table_name) {
    +        $this->trigger_body = 'BEGIN
    +  UPDATE '. $table_name .' SET somedescription = OLD.somename WHERE id = NEW.id;
    +END';
    +        $query = 'CREATE TRIGGER '. $trigger_name .' AFTER UPDATE ON '. $table_name .'
    +                  FOR EACH ROW '. $this->trigger_body .';';
    +        return $this->db->exec($query);
    +    }
    +
    +    function checkTrigger($trigger_name, $table_name, $def) {
    +        parent::checkTrigger($trigger_name, $table_name, $def);
    +        $this->test->assertEquals($this->trigger_body, $def['trigger_body']);
    +    }
    +
    +    function dropTrigger($trigger_name, $table_name) {
    +        return $this->db->exec('DROP TRIGGER '.$trigger_name);
    +    }
    +
    +    function createFunction($name) {
    +        $query = 'CREATE FUNCTION '.$name.'(a INT, b INT) RETURNS INT
    +RETURN a + b;';
    +        return $this->db->exec($query);
    +    }
    +}
    +
    +?>
    \ No newline at end of file
    diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/tests/MDB2_nonstandard_oci8.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/MDB2_nonstandard_oci8.php
    --- php-mdb2-2.4.1/MDB2-2.5.0b2/tests/MDB2_nonstandard_oci8.php	1970-01-01 01:00:00.000000000 +0100
    +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/MDB2_nonstandard_oci8.php	2009-01-14 16:28:09.000000000 +0000
    @@ -0,0 +1,82 @@
    +                       |
    +// +----------------------------------------------------------------------+
    +//
    +// $Id: MDB2_nonstandard_oci8.php,v 1.5 2007/03/04 22:28:23 quipo Exp $
    +
    +class MDB2_nonstandard_oci8 extends MDB2_nonstandard {
    +
    +    var $trigger_body = '';
    +    var $when_clause = 'new.id > 0';
    +
    +    function createTrigger($trigger_name, $table_name) {
    +        $this->trigger_body = 'BEGIN INSERT INTO '.$table_name
    +            .' (id, somename, somedescription) VALUES'
    +            .' (:new.id+1, :new.somename, :new.somedescription); END '. $trigger_name .';';
    +        $query = 'CREATE OR REPLACE TRIGGER '. $trigger_name
    +                .' AFTER UPDATE ON '. $table_name
    +                .' FOR EACH ROW WHEN ('.$this->when_clause.') '
    +                . $this->trigger_body;
    +        return $this->db->exec($query);
    +    }
    +
    +    function checkTrigger($trigger_name, $table_name, $def) {
    +        parent::checkTrigger($trigger_name, $table_name, $def);
    +        $this->test->assertEquals($this->trigger_body, $def['trigger_body']);
    +        $this->test->assertEquals($this->when_clause, $def['when_clause']);
    +    }
    +
    +    function dropTrigger($trigger_name, $table_name) {
    +        return $this->db->exec('DROP TRIGGER '.$trigger_name);
    +    }
    +
    +    function createFunction($name) {
    +        $query = 'CREATE FUNCTION '.$name.'(a IN INT, b IN INT)
    +RETURN INT AS
    +BEGIN
    +    RETURN a + b;
    +END;';
    +        return $this->db->exec($query);
    +    }
    +}
    +
    +?>
    \ No newline at end of file
    diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/tests/MDB2_nonstandard_pgsql.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/MDB2_nonstandard_pgsql.php
    --- php-mdb2-2.4.1/MDB2-2.5.0b2/tests/MDB2_nonstandard_pgsql.php	1970-01-01 01:00:00.000000000 +0100
    +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/MDB2_nonstandard_pgsql.php	2009-01-14 16:28:09.000000000 +0000
    @@ -0,0 +1,94 @@
    +                       |
    +// +----------------------------------------------------------------------+
    +//
    +// $Id: MDB2_nonstandard_pgsql.php,v 1.5 2007/03/04 21:36:08 quipo Exp $
    +
    +class MDB2_nonstandard_pgsql extends MDB2_nonstandard {
    +
    +    var $trigger_body = '';
    +
    +    function createTrigger($trigger_name, $table_name) {
    +        $this->trigger_body = 'EXECUTE PROCEDURE '.$trigger_name.'_func();';
    +        $table_name = $this->db->quoteIdentifier($table_name);
    +        $sql = 'CREATE OR REPLACE FUNCTION '.$trigger_name.'_func() RETURNS trigger AS \'
    +                DECLARE
    +                    id_number INTEGER;
    +                BEGIN
    +                    SELECT INTO id_number id FROM '. $table_name .' WHERE id = NEW.id;
    +                    RETURN NEW;
    +                END;
    +                \' LANGUAGE \'plpgsql\';';
    +        $res = $this->db->exec($sql);
    +        if (PEAR::isError($res)) {
    +            return $res;
    +        }
    +    
    +        $query = 'CREATE TRIGGER '. $trigger_name .' AFTER UPDATE ON '. $table_name .'
    +                  FOR EACH ROW ' .$this->trigger_body;
    +        return $this->db->exec($query);
    +    }
    +
    +    function checkTrigger($trigger_name, $table_name, $def) {
    +        parent::checkTrigger($trigger_name, $table_name, $def);
    +        $this->test->assertEquals($this->trigger_body, $def['trigger_body']);
    +    }
    +
    +    function dropTrigger($trigger_name, $table_name) {
    +        return $this->db->exec('DROP TRIGGER '.$trigger_name .' ON '. $table_name);
    +    }
    +
    +    function createFunction($name) {
    +        $query = "CREATE FUNCTION $name (Decimal(6,2), Decimal(6,2)) RETURNS Decimal(6,2)
    +AS 'select $1 + $2;'
    +LANGUAGE SQL
    +IMMUTABLE
    +RETURNS NULL ON NULL INPUT";
    +        return $this->db->exec($query);
    +    }
    +
    +    function dropFunction($name) {
    +        return $this->db->exec('DROP FUNCTION '.$name.' (Decimal(6,2), Decimal(6,2))');
    +    }
    +}
    +
    +?>
    \ No newline at end of file
    diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/tests/MDB2_nonstandard.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/MDB2_nonstandard.php
    --- php-mdb2-2.4.1/MDB2-2.5.0b2/tests/MDB2_nonstandard.php	1970-01-01 01:00:00.000000000 +0100
    +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/MDB2_nonstandard.php	2009-01-14 16:28:09.000000000 +0000
    @@ -0,0 +1,130 @@
    +                       |
    +// +----------------------------------------------------------------------+
    +//
    +// $Id: MDB2_nonstandard.php,v 1.5 2007/03/04 21:26:52 quipo Exp $
    +
    +class MDB2_nonstandard {
    +    //contains the MDB2 object of the db once we have connected
    +    var $db;
    +    
    +    //contains the PHPUnit_TestCase object
    +    var $test;
    +    
    +    /**
    +     * Returns a driver-specific object
    +     */
    +    function factory($db, $test) {
    +        $classname = 'MDB2_nonstandard_'.$db->phptype;
    +        include_once $classname.'.php';
    +        if (class_exists($classname)) {
    +            $obj =& new $classname();
    +            $obj->db =& $db;
    +            $obj->test =& $test;
    +            return $obj;
    +        }
    +        return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
    +            'not capable', __FUNCTION__);
    +    }
    +    
    +    /**
    +     * Create a TRIGGER
    +     */
    +    function createTrigger($trigger_name, $table_name) {
    +        return $this->db->raiseError(MDB2_ERROR_NOT_CAPABLE, null, null,
    +            'not capable', __FUNCTION__);
    +    }
    +
    +    /**
    +     * Check if getTriggerDefinition() returns the correct definition for the trigger
    +     */
    +    function checkTrigger($trigger_name, $table_name, $def) {
    +        $this->test->assertEquals(strtoupper($trigger_name), strtoupper($def['trigger_name']), 'Error getting trigger definition (name)');
    +        $this->test->assertEquals(strtoupper($table_name),  strtoupper($def['table_name']),   'Error getting trigger definition (table)');
    +        $this->test->assertEquals('AFTER',  $def['trigger_type'], 'Error getting trigger definition (type)');
    +        $this->test->assertEquals('UPDATE', $def['trigger_event'], 'Error getting trigger definition (event)');
    +        $this->test->assertTrue(is_string($def['trigger_body']), 'Error getting trigger definition (body)');
    +        $this->test->assertTrue($def['trigger_enabled'], 'Error getting trigger definition (enabled)');
    +        //$this->test->assertTrue(empty($def['trigger_comment']),  'Error getting trigger definition (comment)');
    +    }
    +
    +    /**
    +     * Drop a TRIGGER
    +     */
    +    function dropTrigger($trigger_name, $table_name) {
    +        return $this->db->raiseError(MDB2_ERROR_NOT_CAPABLE, null, null,
    +            'not capable', __FUNCTION__);
    +    }
    +    
    +    /**
    +     * Create a VIEW
    +     */
    +    function createView($view_name, $table_name) {
    +        $query = 'CREATE VIEW '. $this->db->quoteIdentifier($view_name, true)
    +                .' (id) AS SELECT id FROM '
    +                . $this->db->quoteIdentifier($table_name, true) .' WHERE id > 1';
    +        return $this->db->exec($query);
    +    }
    +
    +    /**
    +     * Drop a VIEW
    +     */
    +    function dropView($view_name) {
    +        return $this->db->exec('DROP VIEW '.$view_name);
    +    }
    +
    +    /**
    +     * Create a FUNCTION
    +     */
    +    function createFunction($name) {
    +        return $this->db->raiseError(MDB2_ERROR_NOT_CAPABLE, null, null,
    +            'not capable', __FUNCTION__);
    +    }
    +
    +    /**
    +     * Drop a FUNCTION
    +     */
    +    function dropFunction($name) {
    +        return $this->db->exec('DROP FUNCTION '.$name);
    +    }
    +}
    +?>
    \ No newline at end of file
    diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/tests/MDB2_nonstandard_sqlite.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/MDB2_nonstandard_sqlite.php
    --- php-mdb2-2.4.1/MDB2-2.5.0b2/tests/MDB2_nonstandard_sqlite.php	1970-01-01 01:00:00.000000000 +0100
    +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/MDB2_nonstandard_sqlite.php	2009-01-14 16:28:09.000000000 +0000
    @@ -0,0 +1,75 @@
    +                       |
    +// +----------------------------------------------------------------------+
    +//
    +// $Id: MDB2_nonstandard_sqlite.php,v 1.5 2007/03/05 21:35:54 quipo Exp $
    +
    +class MDB2_nonstandard_sqlite extends MDB2_nonstandard {
    +
    +    var $trigger_body = '';
    +
    +    function createTrigger($trigger_name, $table_name) {
    +        $this->trigger_body = 'CREATE TRIGGER '. $trigger_name .' AFTER UPDATE ON '. $table_name .'
    +BEGIN
    +    UPDATE '. $table_name .' SET somedescription = new.somename WHERE id = old.id;
    +END';
    +        return $this->db->standaloneQuery($this->trigger_body);
    +    }
    +
    +    function checkTrigger($trigger_name, $table_name, $def) {
    +        parent::checkTrigger($trigger_name, $table_name, $def);
    +        $this->test->assertEquals($this->trigger_body, $def['trigger_body']);
    +    }
    +
    +    function dropTrigger($trigger_name, $table_name) {
    +        return $this->db->standaloneQuery('DROP TRIGGER '.$trigger_name);
    +    }
    +    
    +    function createView($view_name, $table_name) {
    +        $query = 'CREATE VIEW '. $this->db->quoteIdentifier($view_name, true)
    +                .' AS SELECT id FROM '
    +                . $this->db->quoteIdentifier($table_name, true) .' WHERE id > 1';
    +        return $this->db->exec($query);
    +    }
    +}
    +
    +?>
    \ No newline at end of file
    diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/tests/MDB2_reverse_testcase.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/MDB2_reverse_testcase.php
    --- php-mdb2-2.4.1/MDB2-2.5.0b2/tests/MDB2_reverse_testcase.php	1970-01-01 01:00:00.000000000 +0100
    +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/MDB2_reverse_testcase.php	2009-01-14 16:28:09.000000000 +0000
    @@ -0,0 +1,671 @@
    +            |
    +// +----------------------------------------------------------------------+
    +//
    +// $Id: MDB2_reverse_testcase.php,v 1.50 2008/02/17 15:44:05 quipo Exp $
    +
    +require_once 'MDB2_testcase.php';
    +
    +class MDB2_Reverse_TestCase extends MDB2_TestCase
    +{
    +    //test table name (it is dynamically created/dropped)
    +    var $table       = 'testtable';
    +    var $fields      = array();
    +    var $indices     = array();
    +    var $constraints = array();
    +
    +    var $table2      = 'testtable2';
    +    var $fields2      = array();
    +    var $indices2     = array();
    +    var $constraints2 = array();
    +
    +    function setUp() {
    +        parent::setUp();
    +        $this->db->loadModule('Reverse', null, true);
    +        $this->db->loadModule('Manager', null, true);
    +
    +        //Table structure
    +        $this->fields = array(
    +            'id' => array(  //PK
    +                'type'     => 'integer',
    +                'unsigned' => 1,
    +                'notnull'  => 1,
    +                'default'  => 0,
    +                'length'  => 4,
    +            ),
    +            'id2' => array( //UNIQUE_MULTIFIELD(1/2)
    +                'type'     => 'integer',
    +                'unsigned' => 1,
    +                'notnull'  => 1,
    +                'default'  => 0,
    +            ),
    +            'id3' => array( //UNIQUE_MULTIFIELD(2/2)
    +                'type'     => 'integer',
    +                'unsigned' => 1,
    +                'notnull'  => 1,
    +                'default'  => 0,
    +            ),
    +            'id4' => array( //UNIQUE
    +                'type'     => 'integer',
    +                'unsigned' => 1,
    +                'notnull'  => 1,
    +                'default'  => 0,
    +            ),
    +            'somename' => array( //NORMAL INDEX
    +                'type'   => 'text',
    +                'length' => 12,
    +            ),
    +            'somedescription' => array( //INDEX_MULTIFIELD(1/2)
    +                'type'   => 'text',
    +                'length' => 12,
    +            ),
    +            'sex' => array( //INDEX_MULTIFIELD(2/2)
    +                'type' => 'text',
    +                'length' => 1,
    +                'default' => 'M',
    +            ),
    +        );
    +
    +        $options = array();
    +        if ('mysql' == substr($this->db->phptype, 0, 5)) {
    +            $options['type'] = 'innodb';
    +        }
    +
    +        if (!$this->tableExists($this->table)) {
    +            $this->db->manager->createTable($this->table, $this->fields, $options);
    +        }
    +
    +        //Table2 structure
    +        $this->fields2 = array(
    +            'ext_id' => array(  //SINGLE_FK
    +                'type'     => 'integer',
    +                'unsigned' => 1,
    +                'notnull'  => 1,
    +                'default'  => 0,
    +            ),
    +            'ext_id2' => array( //MULTI_FK(1/2)
    +                'type'     => 'integer',
    +                'unsigned' => 1,
    +                'notnull'  => 1,
    +                'default'  => 0,
    +            ),
    +            'ext_id3' => array( //MULTI_FK(2/2)
    +                'type'     => 'integer',
    +                'unsigned' => 1,
    +                'notnull'  => 1,
    +                'default'  => 0,
    +            ),
    +        );
    +
    +        if (!$this->tableExists($this->table2)) {
    +            $this->db->manager->createTable($this->table2, $this->fields2, $options);
    +        }
    +    }
    +
    +    function tearDown() {
    +        if ($this->tableExists($this->table2)) {
    +            $this->db->manager->dropTable($this->table2);
    +        }
    +        if ($this->tableExists($this->table)) {
    +            $this->db->manager->dropTable($this->table);
    +        }
    +        $this->db->popExpect();
    +        unset($this->dsn);
    +        if (!PEAR::isError($this->db->manager)) {
    +            $this->db->disconnect();
    +        }
    +        unset($this->db);
    +    }
    +
    +    function setUpIndices()
    +    {
    +        //Indices definition
    +        $this->indices = array(
    +            'sometestindex' => array(
    +                'fields' => array(
    +                    'somename' => array(
    +                        'sorting' => 'ascending',
    +                    ),
    +                ),
    +                'unique' => false,
    +            ),
    +            'multipletestindex' => array(
    +                'fields' => array(
    +                    'somedescription' => array(
    +                        'sorting' => 'ascending',
    +                    ),
    +                    'sex' => array(
    +                        'sorting' => 'ascending',
    +                    ),
    +                ),
    +            ),
    +        );
    +        foreach ($this->indices as $index_name => $index) {
    +            $result = $this->db->manager->createIndex($this->table, $index_name, $index);
    +            $this->assertFalse(PEAR::isError($result), 'Error creating index: '.$index_name);
    +            if (PEAR::isError($result)) {
    +                break;
    +            }
    +        }
    +        return PEAR::isError($result);
    +    }
    +
    +    function setUpConstraints()
    +    {
    +        //Constraints definition
    +        $this->constraints = array(
    +            'pkfield' => array(
    +                'fields' => array(
    +                    'id' => array(
    +                        'sorting' => 'ascending',
    +                    ),
    +                ),
    +                'primary' => true,
    +            ),
    +            'multipleunique' => array(
    +                'fields' => array(
    +                    'id2' => array(
    +                        'sorting' => 'ascending',
    +                    ),
    +                    'id3' => array(
    +                        'sorting' => 'ascending',
    +                    ),
    +                ),
    +                'unique' => true,
    +            ),
    +            'singleunique' => array(
    +                'fields' => array(
    +                    'id4' => array(
    +                        'sorting' => 'ascending',
    +                    ),
    +                ),
    +                'unique' => true,
    +            ),
    +        );
    +        $failed1 = false;
    +        foreach ($this->constraints as $constraint_name => $constraint) {
    +            //$this->db->manager->dropConstraint($this->table, $constraint_name);
    +            $result = $this->db->manager->createConstraint($this->table, $constraint_name, $constraint);
    +            $this->assertFalse(PEAR::isError($result), 'Error creating constraint: '.$constraint_name);
    +            if (PEAR::isError($result)) {
    +                $failed1 = true;
    +                break;
    +            }
    +        }
    +
    +        $this->fk_constraint1_name = $this->table2.'_fk_'.$this->table.'_id';
    +        //$this->fk_constraint2_name = $this->table2.'_fk_'.$this->table.'_id2_id3';
    +        $this->fk_constraint2_name = $this->table2.'_fk_'.$this->table.'_2f';
    +        $this->constraints2 = array(
    +            $this->fk_constraint1_name => array(
    +                'primary' => false,
    +                'unique'  => false,
    +                'foreign' => true,
    +                'check'   => false,
    +                'fields' => array(
    +                    'ext_id' => array(
    +                        'position' => 1,
    +                        'sorting' => 'ascending',
    +                    ),
    +                ),
    +                'references' => array(
    +                    'table'  => $this->table,
    +                    'fields' => array(
    +                        'id' => array(
    +                            'position' => 1,
    +                        ),
    +                    ),
    +                ),
    +                'onupdate' => 'CASCADE',
    +                'ondelete' => 'CASCADE',
    +                'match'    => 'FULL',
    +                'deferrable'        => false,
    +                'initiallydeferred' => false,
    +            ),
    +            $this->fk_constraint2_name => array(
    +                'primary' => false,
    +                'unique'  => false,
    +                'foreign' => true,
    +                'check'   => false,
    +                'fields' => array(
    +                    'ext_id2' => array(
    +                        'position' => 1,
    +                        'sorting'  => 'ascending',
    +                    ),
    +                    'ext_id3' => array(
    +                        'position' => 2,
    +                        'sorting'  => 'ascending',
    +                    ),
    +                ),
    +                'references' => array(
    +                    'table'  => $this->table,
    +                    'fields' => array(
    +                        'id2' => array(
    +                            'position' => 1,
    +                        ),
    +                        'id3' => array(
    +                            'position' => 2,
    +                        ),
    +                    ),
    +                ),
    +                'onupdate' => 'NO ACTION',
    +                'ondelete' => 'NO ACTION',
    +                'match'    => 'FULL',
    +                'deferrable'        => false,
    +                'initiallydeferred' => false,
    +            ),
    +        );
    +        $failed2 = false;
    +        foreach ($this->constraints2 as $constraint_name => $constraint) {
    +            //$this->db->manager->dropConstraint($this->table, $constraint_name);
    +            $result = $this->db->manager->createConstraint($this->table2, $constraint_name, $constraint);
    +            $this->assertFalse(PEAR::isError($result), 'Error creating constraint: '.$constraint_name);
    +            if (PEAR::isError($result)) {
    +                $failed2 = true;
    +                break;
    +            }
    +        }
    +
    +        return !($failed1 || $failed2);
    +    }
    +
    +    /**
    +     * Test tableInfo('table_name')
    +     */
    +    function testTableInfo()
    +    {
    +        if (!$this->methodExists($this->db->reverse, 'tableInfo')) {
    +            return;
    +        }
    +
    +        $table_info = $this->db->reverse->tableInfo($this->table);
    +        if (PEAR::isError($table_info)) {
    +            $this->assertTrue(false, 'Error in tableInfo(): '.$table_info->getMessage().' :: '.$table_info->getUserInfo());
    +        } else {
    +            $this->assertEquals(count($this->fields), count($table_info), 'The number of fields retrieved is different from the expected one');
    +            foreach ($table_info as $field_info) {
    +                $this->assertEquals($this->table, $field_info['table'], 'the table name is not correct');
    +                if (!array_key_exists(strtolower($field_info['name']), $this->fields)) {
    +                    $this->assertTrue(false, 'Field names do not match ('.$field_info['name'].' is unknown)');
    +                }
    +                //expand test, for instance adding a check on types...
    +            }
    +        }
    +
    +        if (!$this->supported('result_introspection')) {
    +            return;
    +        }
    +
    +        $result = $this->db->query('SELECT * FROM '.$this->table);
    +        $table_info = $this->db->reverse->tableInfo($result);
    +        if (PEAR::isError($table_info)) {
    +            $this->assertTrue(false, 'Error in tableInfo(): '.$table_info->getMessage().' :: '.$table_info->getUserInfo());
    +        } else {
    +            $this->assertEquals(count($this->fields), count($table_info), 'The number of fields retrieved is different from the expected one');
    +            foreach ($table_info as $field_info) {
    +                //not all the drivers are capable of returning the table name,
    +                //and may return an empty value
    +                if (!empty($field_info['table'])) {
    +                    $this->assertEquals($this->table, $field_info['table'], 'the table name is not correct');
    +                }
    +                if (!array_key_exists(strtolower($field_info['name']), $this->fields)) {
    +                    $this->assertTrue(false, 'Field names do not match ('.$field_info['name'].' is unknown)');
    +                }
    +                //expand test, for instance adding a check on types...
    +            }
    +        }
    +        $result->free();
    +    }
    +
    +    /**
    +     * Test getTableFieldDefinition($table, $field_name)
    +     */
    +    function testGetTableFieldDefinition()
    +    {
    +        if (!$this->methodExists($this->db->reverse, 'getTableFieldDefinition')) {
    +            return;
    +        }
    +
    +        //test integer not null
    +        $field_info = $this->db->reverse->getTableFieldDefinition($this->table, 'id');
    +        if (PEAR::isError($field_info)) {
    +            $this->assertTrue(false, 'Error in getTableFieldDefinition(): '.$field_info->getMessage());
    +        } else {
    +            $field_info = array_shift($field_info);
    +            $this->assertEquals('integer', $field_info['type'], 'The field type is different from the expected one');
    +            $expected_length = ($this->db->phptype == 'oci8') ? 10 : 4;
    +            $this->assertEquals($expected_length, $field_info['length'], 'The field length is different from the expected one');
    +            $this->assertTrue($field_info['notnull'], 'The field can be null unlike it was expected');
    +            $this->assertEquals('0', $field_info['default'], 'The field default value is different from the expected one');
    +        }
    +
    +        //test blob
    +        $field_info = $this->db->reverse->getTableFieldDefinition('files', 'picture');
    +        if (PEAR::isError($field_info)) {
    +            $this->assertTrue(false, 'Error in getTableFieldDefinition(): '.$field_info->getMessage().' :: '.$field_info->getUserInfo());
    +        } else {
    +            $field_info = array_shift($field_info);
    +            $this->assertEquals($field_info['type'], 'blob', 'The field type is different from the expected one');
    +            $this->assertFalse($field_info['notnull'], 'The field cannot be null unlike it was expected');
    +        }
    +
    +        //test varchar(100) not null
    +        $field_info = $this->db->reverse->getTableFieldDefinition('users', 'user_name');
    +        if (PEAR::isError($field_info)) {
    +            $this->assertTrue(false, 'Error in getTableFieldDefinition(): '.$field_info->getMessage());
    +        } else {
    +            $field_info = array_shift($field_info);
    +            $this->assertEquals('text', $field_info['type'], 'The field type is different from the expected one');
    +            $this->assertEquals(12, $field_info['length'], 'The field length is different from the expected one');
    +            $this->assertFalse($field_info['notnull'], 'The field can be null unlike it was expected');
    +            $this->assertNull($field_info['default'], 'The field default value is different from the expected one');
    +            $this->assertFalse($field_info['fixed'], 'The field fixed value is different from the expected one');
    +        }
    +
    +        //test decimal
    +        $field_info = $this->db->reverse->getTableFieldDefinition('users', 'quota');
    +        if (PEAR::isError($field_info)) {
    +            $this->assertTrue(false, 'Error in getTableFieldDefinition(): '.$field_info->getMessage());
    +        } else {
    +            $field_info = array_shift($field_info);
    +            $this->assertEquals('decimal', $field_info['type'], 'The field type is different from the expected one');
    +            $expected_length = ($this->db->phptype == 'oci8') ? '22,2' : '18,2';
    +            $this->assertEquals($expected_length, $field_info['length'], 'The field length is different from the expected one');
    +        }
    +
    +        $field_info = $this->db->reverse->getTableFieldDefinition('users', 'user_name');
    +        if (PEAR::isError($field_info)) {
    +            $this->assertTrue(false, 'Error in getTableFieldDefinition(): '.$field_info->getMessage());
    +        } else {
    +            $field_info = array_shift($field_info);
    +            $this->assertEquals('text', $field_info['type'], 'The field type is different from the expected one');
    +            $this->assertEquals(12, $field_info['length'], 'The field length is different from the expected one');
    +            $this->assertFalse($field_info['notnull'], 'The field can be null unlike it was expected');
    +            $this->assertNull($field_info['default'], 'The field default value is different from the expected one');
    +            $this->assertFalse($field_info['fixed'], 'The field fixed value is different from the expected one');
    +        }
    +    }
    +
    +    /**
    +     * Test getTableIndexDefinition($table, $index_name)
    +     */
    +    function testGetTableIndexDefinition()
    +    {
    +        if (!$this->methodExists($this->db->reverse, 'getTableIndexDefinition')) {
    +            return;
    +        }
    +
    +        $this->setUpIndices();
    +
    +        //test index names
    +        foreach ($this->indices as $index_name => $index) {
    +            $index_info = $this->db->reverse->getTableIndexDefinition($this->table, $index_name);
    +            if (PEAR::isError($index_info)) {
    +                $this->assertFalse(true, 'Error getting table index definition');
    +            } else {
    +                $field_names = array_keys($index['fields']);
    +                $this->assertEquals($field_names, array_keys($index_info['fields']), 'Error listing index fields');
    +            }
    +        }
    +
    +        //test INDEX
    +        $index_name = 'sometestindex';
    +        $index_info = $this->db->reverse->getTableIndexDefinition($this->table, $index_name);
    +        if (PEAR::isError($index_info)) {
    +            $this->assertTrue(false, 'Error in getTableIndexDefinition(): '.$index_info->getMessage());
    +        } else {
    +            $this->assertEquals(1, count($index_info['fields']), 'The INDEX is not on one field unlike it was expected');
    +            $expected_fields = array_keys($this->indices[$index_name]['fields']);
    +            $actual_fields = array_keys($index_info['fields']);
    +            $this->assertEquals($expected_fields, $actual_fields, 'The INDEX field names don\'t match');
    +            $this->assertEquals(1, $index_info['fields'][$expected_fields[0]]['position'], 'The field position in the INDEX is not correct');
    +        }
    +
    +        //test INDEX on MULTIPLE FIELDS
    +        $index_name = 'multipletestindex';
    +        $index_info = $this->db->reverse->getTableIndexDefinition($this->table, $index_name);
    +        if (PEAR::isError($index_info)) {
    +            $this->assertTrue(false, 'Error in getTableIndexDefinition(): '.$index_info->getMessage());
    +        } else {
    +            $this->assertEquals(2, count($index_info['fields']), 'The INDEX is not on two fields unlike it was expected');
    +            $expected_fields = array_keys($this->indices[$index_name]['fields']);
    +            $actual_fields = array_keys($index_info['fields']);
    +            $this->assertEquals($expected_fields, $actual_fields, 'The INDEX field names don\'t match');
    +            $this->assertEquals(1, $index_info['fields'][$expected_fields[0]]['position'], 'The field position in the INDEX is not correct');
    +            $this->assertEquals(2, $index_info['fields'][$expected_fields[1]]['position'], 'The field position in the INDEX is not correct');
    +        }
    +
    +        if (!$this->setUpConstraints()) {
    +            return;
    +        }
    +        //constraints should NOT be listed
    +        foreach (array_keys($this->constraints) as $constraint_name) {
    +            $this->db->expectError(MDB2_ERROR_NOT_FOUND);
    +            $result = $this->db->reverse->getTableIndexDefinition($this->table, $constraint_name);
    +            $this->assertTrue(PEAR::isError($result), 'Error listing index definition, this is a CONSTRAINT');
    +        }
    +
    +        //test index created WITHOUT using MDB2 (i.e. without the "_idx" suffix)
    +        //NB: MDB2 > v.2.3.0 provides a fallback mechanism
    +    }
    +
    +    /**
    +     * Test testGetTableConstraintDefinition($table, $constraint_name)
    +     */
    +    function testGetTableConstraintDefinition()
    +    {
    +        if (!$this->methodExists($this->db->reverse, 'getTableConstraintDefinition')) {
    +            return;
    +        }
    +
    +        if (!$this->setUpConstraints()) {
    +            return;
    +        }
    +
    +        //test constraint names
    +        foreach ($this->constraints as $constraint_name => $constraint) {
    +            $this->db->expectError(MDB2_ERROR_NOT_FOUND);
    +            $result = $this->db->reverse->getTableConstraintDefinition($this->table, $constraint_name);
    +            $this->db->popExpect();
    +            if (PEAR::isError($result) && isset($constraint['primary']) && $constraint['primary']) {
    +                echo 'Error reading primary constraint, trying with name "primary" instead .. ';
    +                $constraint_name = 'primary';
    +                $result = $this->db->reverse->getTableConstraintDefinition($this->table, $constraint_name);
    +            }
    +            if (PEAR::isError($result)) {
    +                $this->assertFalse(true, 'Error getting table constraint definition ('.$constraint_name.')');
    +            } else {
    +                $constraint_names = array_keys($constraint['fields']);
    +                $this->assertEquals($constraint_names, array_keys($result['fields']), 'Error listing constraint fields');
    +            }
    +        }
    +
    +        $this->setUpIndices();
    +        //indices should NOT be listed
    +        foreach (array_keys($this->indices) as $index_name) {
    +            $this->db->expectError(MDB2_ERROR_NOT_FOUND);
    +            $result = $this->db->reverse->getTableConstraintDefinition($this->table, $index_name);
    +            $this->db->popExpect();
    +            $this->assertTrue(PEAR::isError($result), 'Error listing constraint definition, this is a normal INDEX');
    +        }
    +
    +        //test PK
    +        $this->db->expectError(MDB2_ERROR_NOT_FOUND);
    +        $constraint_info = $this->db->reverse->getTableConstraintDefinition($this->table, 'pkfield');
    +        $this->db->popExpect();
    +        if (PEAR::isError($constraint_info)) {
    +            echo 'Error reading primary constraint, trying with name "primary" instead .. ';
    +            $constraint_info = $this->db->reverse->getTableConstraintDefinition($this->table, 'primary');
    +        }
    +        if (PEAR::isError($constraint_info)) {
    +            $this->assertTrue(false, 'Error in getTableConstraintDefinition(): '.$constraint_info->getMessage());
    +        } else {
    +            $this->assertTrue($constraint_info['primary'], 'The field is not a PK unlike it was expected');
    +        }
    +
    +        //test UNIQUE
    +        $constraint_name = 'singleunique';
    +        $constraint_info = $this->db->reverse->getTableConstraintDefinition($this->table, $constraint_name);
    +        if (PEAR::isError($constraint_info)) {
    +            $this->assertTrue(false, 'Error in getTableConstraintDefinition(): '.$constraint_info->getMessage());
    +        } else {
    +            $this->assertTrue($constraint_info['unique'], 'The field is not a PK unlike it was expected');
    +            $this->assertTrue(empty($constraint_info['primary']), 'The field is a PK unlike it was expected');
    +            $this->assertEquals(1, count($constraint_info['fields']), 'The UNIQUE INDEX is not on one field unlike it was expected');
    +            $expected_fields = array_keys($this->constraints[$constraint_name]['fields']);
    +            $actual_fields = array_keys($constraint_info['fields']);
    +            $this->assertEquals($expected_fields, $actual_fields, 'The UNIQUE INDEX field names don\'t match');
    +            $this->assertEquals(1, $constraint_info['fields'][$expected_fields[0]]['position'], 'The field position in the INDEX is not correct');
    +        }
    +
    +        //test UNIQUE on MULTIPLE FIELDS
    +        $constraint_name = 'multipleunique';
    +        $constraint_info = $this->db->reverse->getTableConstraintDefinition($this->table, $constraint_name);
    +        if (PEAR::isError($constraint_info)) {
    +            $this->assertTrue(false, 'Error in getTableConstraintDefinition(): '.$constraint_info->getMessage());
    +        } else {
    +            $this->assertTrue($constraint_info['unique'], 'The field is not a PK unlike it was expected');
    +            $this->assertTrue(empty($constraint_info['primary']), 'The field is a PK unlike it was expected');
    +            $this->assertEquals(2, count($constraint_info['fields']), 'The UNIQUE INDEX is not on two fields unlike it was expected');
    +            $expected_fields = array_keys($this->constraints[$constraint_name]['fields']);
    +            $actual_fields = array_keys($constraint_info['fields']);
    +            $this->assertEquals($expected_fields, $actual_fields, 'The UNIQUE INDEX field names don\'t match');
    +            $this->assertEquals(1, $constraint_info['fields'][$expected_fields[0]]['position'], 'The field position in the INDEX is not correct');
    +            $this->assertEquals(2, $constraint_info['fields'][$expected_fields[1]]['position'], 'The field position in the INDEX is not correct');
    +        }
    +
    +        //test FOREIGN KEYs
    +        foreach (array_keys($this->constraints2) as $constraint_name) {
    +            $constraint_info = $this->db->reverse->getTableConstraintDefinition($this->table2, $constraint_name);
    +            if (PEAR::isError($constraint_info)) {
    +                $this->assertTrue(false, 'Error in getTableConstraintDefinition():'. $constraint_info->getMessage());
    +            } else {
    +                $this->_compareFKdefinitions($this->constraints2[$constraint_name], $constraint_info);
    +            }
    +        }
    +    }
    +
    +    /**
    +     * Check the original FK constraint definition against the reverse engineered one.
    +     *
    +     * Ideally, the retrieved FK constraint definition should be equal to the
    +     * one used to create the constraint, but not all the DBMS support all the
    +     * parameters, so check the common base and do some generic checks for the
    +     * other patameters.
    +     */
    +    function _compareFKdefinitions($expected, $actual) {
    +        //ideal case: all the parameters are supported by all the DBMS:
    +        //$this->assertEquals($expected, $actual);
    +
    +        $this->assertEquals($expected['primary'], $actual['primary']);
    +        $this->assertEquals($expected['unique'],  $actual['unique']);
    +        $this->assertEquals($expected['foreign'], $actual['foreign']);
    +        $this->assertEquals($expected['check'],   $actual['check']);
    +        $this->assertEquals(array_keys($expected['fields']), array_keys($actual['fields']));
    +        $this->assertEquals($expected['references'],   $actual['references']);
    +        $this->assertEquals($expected['deferrable'],   $actual['deferrable']);
    +        $this->assertEquals($expected['initiallydeferred'],   $actual['initiallydeferred']);
    +        $this->assertTrue(!empty($actual['match']));
    +        $this->assertTrue(!empty($actual['onupdate']));
    +        $this->assertTrue(!empty($actual['ondelete']));
    +    }
    +
    +    /**
    +     * Test getSequenceDefinition($sequence)
    +     */
    +    function testGetSequenceDefinition() {
    +        //setup
    +        $this->db->loadModule('Manager', null, true);
    +        $sequence = 'test_sequence';
    +        $sequences = $this->db->manager->listSequences();
    +        if (!in_array($sequence, $sequences)) {
    +            $result = $this->db->manager->createSequence($sequence);
    +            $this->assertFalse(PEAR::isError($result), 'Error creating a sequence');
    +        }
    +
    +        //test
    +        $start = $this->db->nextId($sequence);
    +        $def = $this->db->reverse->getSequenceDefinition($sequence);
    +        $this->assertEquals($start+1, (isset($def['start']) ? $def['start'] : 1), 'Error getting sequence definition');
    +
    +        //cleanup
    +        $result = $this->db->manager->dropSequence($sequence);
    +        $this->assertFalse(PEAR::isError($result), 'Error dropping a sequence');
    +    }
    +
    +    /**
    +     * Test getTriggerDefinition($trigger)
    +     */
    +    function testGetTriggerDefinition() {
    +        //setup
    +        $trigger_name = 'test_trigger';
    +
    +        include_once 'MDB2_nonstandard.php';
    +        $nonstd =& MDB2_nonstandard::factory($this->db, $this);
    +        if (PEAR::isError($nonstd)) {
    +            $this->assertTrue(false, 'Cannot create trigger: '.$nonstd->getMessage());
    +            return;
    +        }
    +
    +        $result = $nonstd->createTrigger($trigger_name, $this->table);
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Cannot create trigger: '.$result->getMessage());
    +            return;
    +        }
    +
    +        //test
    +        $def = $this->db->reverse->getTriggerDefinition($trigger_name);
    +        if (PEAR::isError($def)) {
    +            $this->assertTrue(false, 'getTriggerDefinition: '.$def->getMessage());
    +        } else {
    +            $nonstd->checkTrigger($trigger_name, $this->table, $def);
    +        }
    +
    +        //cleanup
    +        $result = $nonstd->dropTrigger($trigger_name, $this->table);
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Error dropping the trigger: '.$result->getMessage());
    +            return;
    +        }
    +    }
    +}
    +?>
    \ No newline at end of file
    diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/tests/MDB2_testcase.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/MDB2_testcase.php
    --- php-mdb2-2.4.1/MDB2-2.5.0b2/tests/MDB2_testcase.php	1970-01-01 01:00:00.000000000 +0100
    +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/MDB2_testcase.php	2009-01-14 16:28:09.000000000 +0000
    @@ -0,0 +1,168 @@
    +                                 |
    +// +----------------------------------------------------------------------+
    +//
    +// $Id: MDB2_testcase.php,v 1.18 2006/12/19 15:04:53 quipo Exp $
    +
    +class MDB2_TestCase extends PHPUnit_TestCase {
    +    //contains the dsn of the database we are testing
    +    var $dsn;
    +    //contains the options that should be used during testing
    +    var $options;
    +    //contains the name of the database we are testing
    +    var $database;
    +    //contains the MDB2 object of the db once we have connected
    +    var $db;
    +    // contains field names from the test table
    +    var $fields;
    +    // if the tables should be cleared in the setUp() and tearDown() methods
    +    var $clear_tables = true;
    +
    +    function MDB2_TestCase($name) {
    +        $this->PHPUnit_TestCase($name);
    +    }
    +
    +    function setUp() {
    +        $this->dsn = $GLOBALS['dsn'];
    +        $this->options  = $GLOBALS['options'];
    +        $this->database = $GLOBALS['database'];
    +        $this->db =& MDB2::factory($this->dsn, $this->options);
    +        $this->db->setDatabase($this->database);
    +        $this->db->expectError(MDB2_ERROR_UNSUPPORTED);
    +        $this->fields = array(
    +            'user_name' => 'text',
    +            'user_password' => 'text',
    +            'subscribed' => 'boolean',
    +            'user_id' => 'integer',
    +            'quota' => 'decimal',
    +            'weight' => 'float',
    +            'access_date' => 'date',
    +            'access_time' => 'time',
    +            'approved' => 'timestamp',
    +        );
    +        $this->clearTables();
    +    }
    +
    +    function tearDown() {
    +        $this->clearTables();
    +        $this->db->popExpect();
    +        unset($this->dsn);
    +        if (!PEAR::isError($this->db)) {
    +            $this->db->disconnect();
    +        }
    +        unset($this->db);
    +    }
    +
    +    function clearTables() {
    +        if (!$this->clear_tables) {
    +            return;
    +        }
    +        if (PEAR::isError($this->db->exec('DELETE FROM users'))) {
    +            $this->assertTrue(false, 'Error deleting from table users');
    +        }
    +        if (PEAR::isError($this->db->exec('DELETE FROM files'))) {
    +            $this->assertTrue(false, 'Error deleting from table users');
    +        }
    +    }
    +
    +    function supported($feature) {
    +        if (!$this->db->supports($feature)) {
    +            $this->assertTrue(false, 'This database does not support '.$feature);
    +            return false;
    +        }
    +        return true;
    +    }
    +
    +    function verifyFetchedValues(&$result, $rownum, $data) {
    +        //$row = $result->fetchRow(MDB2_FETCHMODE_DEFAULT, $rownum);
    +        $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC, $rownum);
    +        if (!is_array($row)) {
    +            $this->assertTrue(false, 'Error result row is not an array');
    +            return;
    +        }
    +        //reset($row);
    +        foreach ($this->fields as $field => $type) {
    +            //$value = current($row);
    +            $value = $row[$field];
    +            if ($type == 'float') {
    +                $delta = 0.0000000001;
    +            } else {
    +                $delta = 0;
    +            }
    +
    +            $this->assertEquals($data[$field], $value, "the value retrieved for field \"$field\" doesn't match what was stored into the rownum $rownum", $delta);
    +            //next($row);
    +        }
    +    }
    +
    +    function getSampleData($row = 1) {
    +        $data = array();
    +        $data['user_name']     = 'user_' . $row;
    +        $data['user_password'] = 'somepass';
    +        $data['subscribed']    = $row % 2 ? true : false;
    +        $data['user_id']       = $row;
    +        $data['quota']         = strval($row/100);
    +        $data['weight']        = sqrt($row);
    +        $data['access_date']   = MDB2_Date::mdbToday();
    +        $data['access_time']   = MDB2_Date::mdbTime();
    +        $data['approved']      = MDB2_Date::mdbNow();
    +        return $data;
    +    }
    +
    +    function methodExists(&$class, $name) {
    +        if (is_object($class)
    +            && in_array(strtolower($name), array_map('strtolower', get_class_methods($class)))
    +        ) {
    +            return true;
    +        }
    +        $this->assertTrue(false, 'method '. $name.' not implemented in '.get_class($class));
    +        return false;
    +    }
    +
    +    function tableExists($table) {
    +        $this->db->loadModule('Manager', null, true);
    +        $tables = $this->db->manager->listTables();
    +        return in_array(strtolower($table), array_map('strtolower', $tables));
    +    }
    +}
    +
    +?>
    \ No newline at end of file
    diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/tests/MDB2_usage_testcase.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/MDB2_usage_testcase.php
    --- php-mdb2-2.4.1/MDB2-2.5.0b2/tests/MDB2_usage_testcase.php	1970-01-01 01:00:00.000000000 +0100
    +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/MDB2_usage_testcase.php	2009-01-14 16:28:09.000000000 +0000
    @@ -0,0 +1,1853 @@
    +                                 |
    +// +----------------------------------------------------------------------+
    +//
    +// $Id: MDB2_usage_testcase.php,v 1.108 2008/03/01 14:02:29 quipo Exp $
    +
    +require_once 'MDB2_testcase.php';
    +
    +class MDB2_Usage_TestCase extends MDB2_TestCase {
    +    /**
    +     * Test typed data storage and retrieval
    +     *
    +     * This tests typed data storage and retrieval by executing a single
    +     * prepared query and then selecting the data back from the database
    +     * and comparing the results
    +     */
    +    function testStorage() {
    +        $data = $this->getSampleData(1234);
    +
    +        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
    +        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
    +        $result = $stmt->execute(array_values($data));
    +        $stmt->free();
    +
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Error executing prepared query: '.$result->getMessage());
    +        }
    +
    +        $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users';
    +        $result =& $this->db->query($query, $this->fields);
    +
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Error selecting from users'.$result->getMessage());
    +        }
    +
    +        $this->verifyFetchedValues($result, 0, $data);
    +    }
    +
    +    /**
    +     * Test fetchOne()
    +     *
    +     * This test bulk fetching of result data by using a prepared query to
    +     * insert an number of rows of data and then retrieving the data columns
    +     * one by one
    +     */
    +    function testFetchOne() {
    +        $data = array();
    +        $total_rows = 5;
    +
    +        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
    +        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
    +
    +        for ($row = 0; $row < $total_rows; $row++) {
    +            $data[$row] = $this->getSampleData($row);
    +            $result = $stmt->execute(array_values($data[$row]));
    +
    +            if (PEAR::isError($result)) {
    +                $this->assertTrue(false, 'Error executing prepared query: '.$result->getMessage());
    +            }
    +        }
    +
    +        $stmt->free();
    +
    +        foreach ($this->fields as $field => $type) {
    +            for ($row = 0; $row < $total_rows; $row++) {
    +                $result =& $this->db->query('SELECT '.$field.' FROM users WHERE user_id='.$row, $type);
    +                $value = $result->fetchOne();
    +                if (PEAR::isError($value)) {
    +                    $this->assertTrue(false, 'Error fetching row '.$row.' for field '.$field.' of type '.$type);
    +                } else {
    +                    $this->assertEquals(strval($data[$row][$field]), strval(trim($value)), 'the query field '.$field.' of type '.$type.' for row '.$row);
    +                    $result->free();
    +                }
    +            }
    +        }
    +    }
    +
    +    /**
    +     * Test fetchCol()
    +     *
    +     * Test fetching a column of result data. Two different columns are retrieved
    +     */
    +    function testFetchCol() {
    +        $data = array();
    +        $total_rows = 5;
    +
    +        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
    +        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
    +
    +        for ($row = 0; $row < $total_rows; $row++) {
    +            $data[$row] = $this->getSampleData($row);
    +            $result = $stmt->execute(array_values($data[$row]));
    +
    +            if (PEAR::isError($result)) {
    +                $this->assertTrue(false, 'Error executing prepared query: '.$result->getMessage());
    +            }
    +        }
    +
    +        $stmt->free();
    +
    +        $first_col = array();
    +        for ($row = 0; $row < $total_rows; $row++) {
    +            $first_col[$row] = "user_$row";
    +        }
    +
    +        $second_col = array();
    +        for ($row = 0; $row < $total_rows; $row++) {
    +            $second_col[$row] = $row;
    +        }
    +
    +        $query = 'SELECT user_name, user_id FROM users ORDER BY user_name';
    +        $result =& $this->db->query($query, array('text', 'integer'));
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Error during query: '.$result->getMessage());
    +        }
    +        $values = $result->fetchCol(0);
    +        if (PEAR::isError($values)) {
    +            $this->assertTrue(false, 'Error fetching first column');
    +        } else {
    +            $this->assertEquals($first_col, $values);
    +        }
    +        $result->free();
    +
    +        $query = 'SELECT user_name, user_id FROM users ORDER BY user_name';
    +        $result =& $this->db->query($query, array('text', 'integer'));
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Error during query: '.$result->getMessage());
    +        }
    +        $values = $result->fetchCol(1);
    +        if (PEAR::isError($values)) {
    +            $this->assertTrue(false, 'Error fetching second column');
    +        } else {
    +            $this->assertEquals($second_col, $values);
    +        }
    +        $result->free();
    +    }
    +
    +    /**
    +     * Test fetchAll()
    +     *
    +     * Test fetching an entire result set in one shot.
    +     */
    +    function testFetchAll() {
    +        $data = array();
    +        $total_rows = 5;
    +
    +        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
    +        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
    +
    +        for ($row = 0; $row < $total_rows; $row++) {
    +            $data[$row] = $this->getSampleData($row);
    +            $result = $stmt->execute(array_values($data[$row]));
    +
    +            if (PEAR::isError($result)) {
    +                $this->assertTrue(false, 'Error executing prepared query: '.$result->getMessage());
    +            }
    +        }
    +        $fields = array_keys($data[0]);
    +        $query = 'SELECT '. implode (', ', $fields). ' FROM users ORDER BY user_name';
    +
    +        $stmt->free();
    +
    +        $result =& $this->db->query($query, $this->fields);
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Error during query: ' .$result->getMessage());
    +        }
    +        $values = $result->fetchAll(MDB2_FETCHMODE_ASSOC);
    +        if (PEAR::isError($values)) {
    +            $this->assertTrue(false, 'Error fetching the result set');
    +        } else {
    +            for ($i=0; $i<$total_rows; $i++) {
    +                foreach ($data[$i] as $key => $val) {
    +                    $this->assertEquals(strval($val), strval($values[$i][$key]), 'Row #'.$i.' ['.$key.']');
    +                }
    +            }
    +        }
    +        $result->free();
    +        
    +        //test $rekey=true
    +        $result =& $this->db->query('SELECT user_id, user_name FROM users ORDER BY user_id', $this->fields);
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Error during query: '.$result->getMessage());
    +        }
    +        $values = $result->fetchAll(MDB2_FETCHMODE_ASSOC, true);
    +        if (PEAR::isError($values)) {
    +            $this->assertTrue(false, 'Error fetching the result set');
    +        } else {
    +            for ($i=0; $i<$total_rows; $i++) {
    +                list($id, $name) = each($values);
    +                $this->assertEquals($data[$i]['user_id'],   $id,   'Row #'.$i.' ["user_id"]');
    +                $this->assertEquals($data[$i]['user_name'], $name, 'Row #'.$i.' ["user_name"]');
    +            }
    +        }
    +        $result->free();
    +
    +
    +        //test $rekey=true, $force_array=true
    +        $result =& $this->db->query('SELECT user_id, user_name FROM users ORDER BY user_id', $this->fields);
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Error during query: '.$result->getMessage());
    +        }
    +        $values = $result->fetchAll(MDB2_FETCHMODE_ASSOC, true, true);
    +        if (PEAR::isError($values)) {
    +            $this->assertTrue(false, 'Error fetching the result set');
    +        } else {
    +            for ($i=0; $i<$total_rows; $i++) {
    +                list($id, $value) = each($values);
    +                $this->assertEquals($data[$i]['user_id'],   $id,                 'Row #'.$i.' ["user_id"]');
    +                $this->assertEquals($data[$i]['user_name'], $value['user_name'], 'Row #'.$i.' ["user_name"]');
    +            }
    +        }
    +        $result->free();
    +
    +        //test $rekey=true, $force_array=true, $group=true
    +        $result =& $this->db->query('SELECT user_password, user_name FROM users ORDER BY user_name', $this->fields);
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Error during query: '.$result->getMessage());
    +        }
    +        $values = $result->fetchAll(MDB2_FETCHMODE_ASSOC, true, true, true);
    +        if (PEAR::isError($values)) {
    +            $this->assertTrue(false, 'Error fetching the result set');
    +        } else {
    +            //all the records have the same user_password value
    +            $this->assertEquals(1, count($values), 'Error: incorrect number of returned rows');
    +            $values = $values[$data[0]['user_password']];
    +            for ($i=0; $i<$total_rows; $i++) {
    +                $this->assertEquals($data[$i]['user_name'], $values[$i]['user_name'], 'Row #'.$i.' ["user_name"]');
    +            }
    +        }
    +        $result->free();
    +
    +        //test $rekey=true, $force_array=true, $group=false (with non unique key)
    +        $result =& $this->db->query('SELECT user_password, user_name FROM users ORDER BY user_name', $this->fields);
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Error during query: '.$result->getMessage());
    +        }
    +        $values = $result->fetchAll(MDB2_FETCHMODE_ASSOC, true, true, false);
    +        if (PEAR::isError($values)) {
    +            $this->assertTrue(false, 'Error fetching the result set');
    +        } else {
    +            //all the records have the same user_password value, they are overwritten
    +            $this->assertEquals(1, count($values), 'Error: incorrect number of returned rows');
    +            $key = $data[0]['user_password'];
    +            $this->assertEquals(1, count($values[$key]), 'Error: incorrect number of returned rows');
    +            $this->assertEquals($data[4]['user_name'], $values[$key]['user_name']);
    +        }
    +        $result->free();
    +    }
    +
    +    /**
    +     * Test different fetch modes
    +     *
    +     * Test fetching results using different fetch modes
    +     * NOTE: several tests still missing
    +     */
    +    function testFetchModes() {
    +        $data = array();
    +        $total_rows = 5;
    +
    +        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
    +        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
    +
    +        for ($row = 0; $row < $total_rows; $row++) {
    +            $data[$row] = $this->getSampleData($row);
    +            $result = $stmt->execute(array_values($data[$row]));
    +
    +            if (PEAR::isError($result)) {
    +                $this->assertTrue(false, 'Error executing prepared query: '.$result->getMessage());
    +            }
    +        }
    +
    +        $stmt->free();
    +
    +        // test ASSOC
    +        $query = 'SELECT A.user_name FROM users A, users B WHERE A.user_id = B.user_id';
    +        $value = $this->db->queryRow($query, array($this->fields['user_name']), MDB2_FETCHMODE_ASSOC);
    +        if (PEAR::isError($value)) {
    +            $this->assertTrue(false, 'Error fetching the result set');
    +        } else {
    +            $this->assertTrue(!empty($value['user_name']), 'Error fetching the associative result set from join');
    +        }
    +    }
    +
    +    /**
    +     * Test multi_query option
    +     *
    +     * This test attempts to send multiple queries at once using the multi_query
    +     * option and then retrieves each result.
    +     */
    +    function testMultiQuery() {
    +        $multi_query_orig = $this->db->getOption('multi_query');
    +        if (PEAR::isError($multi_query_orig)) {
    +            $this->assertTrue(false, 'Error getting multi_query option value: '.$multi_query_orig->getMessage());
    +            return;
    +        }
    +
    +        $this->db->setOption('multi_query', true);
    +
    +        $data = array();
    +        $total_rows = 5;
    +
    +        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
    +        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
    +
    +        for ($row = 0; $row < $total_rows; $row++) {
    +            $data[$row] = $this->getSampleData($row);
    +            $result = $stmt->execute(array_values($data[$row]));
    +
    +            if (PEAR::isError($result)) {
    +                $this->assertTrue(false, 'Error executing prepared query: '.$result->getMessage());
    +            }
    +        }
    +
    +        $stmt->free();
    +
    +        $query = '';
    +        for ($row = 0; $row < $total_rows; $row++) {
    +            $query.= 'SELECT user_name FROM users WHERE user_id='.$row.';';
    +        }
    +        $result =& $this->db->query($query, 'text');
    +
    +        for ($row = 0; $row < $total_rows; $row++) {
    +            $value = $result->fetchOne();
    +            if (PEAR::isError($value)) {
    +                $this->assertTrue(false, 'Error fetching row '.$row);
    +            } else {
    +                $this->assertEquals(strval($data[$row]['user_name']), strval(trim($value)), 'the query field username of type "text" for row '.$row);
    +            }
    +            if (PEAR::isError($result->nextResult())) {
    +                $this->assertTrue(false, 'Error moving result pointer');
    +            }
    +        }
    +
    +        $result->free();
    +        $this->db->setOption('multi_query', $multi_query_orig);
    +    }
    +
    +    /**
    +     * Test prepared queries
    +     *
    +     * Tests prepared queries, making sure they correctly deal with ?, !, and '
    +     */
    +    function testPreparedQueries() {
    +        $data = array(
    +            array(
    +                'user_name' => 'Sure!',
    +                'user_password' => 'Do work?',
    +                'user_id' => 1,
    +            ),
    +            array(
    +                'user_name' => 'For Sure!',
    +                'user_password' => "Doesn't?",
    +                'user_id' => 2,
    +            ),
    +        );
    +
    +        $query = "INSERT INTO users (user_name, user_password, user_id) VALUES (?, ?, ?)";
    +        $stmt = $this->db->prepare($query, array('text', 'text', 'integer'), MDB2_PREPARE_MANIP);
    +
    +        $text = $data[0]['user_name'];
    +        $question = $data[0]['user_password'];
    +        $userid = $data[0]['user_id'];
    +
    +        // bind out of order
    +        $stmt->bindParam(0, $text);
    +        $stmt->bindParam(2, $userid);
    +        $stmt->bindParam(1, $question);
    +
    +        $result = $stmt->execute();
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(true, 'Could not execute prepared query with question mark placeholders. Error: '.$error);
    +        }
    +
    +        $text = $data[1]['user_name'];
    +        $question = $data[1]['user_password'];
    +        $userid = $data[1]['user_id'];
    +
    +        $result = $stmt->execute();
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(true, 'Could not execute prepared query with bound parameters. Error: '.$error);
    +        }
    +        $stmt->free();
    +        $this->clearTables();
    +
    +        $query = "INSERT INTO users (user_name, user_password, user_id) VALUES (:text, :question, :userid)";
    +        $stmt = $this->db->prepare($query, array('text', 'text', 'integer'), MDB2_PREPARE_MANIP);
    +        if (PEAR::isError($stmt)) {
    +            $this->assertTrue(false, 'Error preparing query: ' . $stmt->getMessage. ' :: '.$stmt->getUserInfo());
    +        }
    +
    +        $stmt->bindValue('text', $data[0]['user_name']);
    +        $stmt->bindValue('question', $data[0]['user_password']);
    +        $stmt->bindValue('userid', $data[0]['user_id']);
    +
    +        $result = $stmt->execute();
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(true, 'Could not execute prepared query with named placeholders. Error: '.$error);
    +        }
    +        $stmt->free();
    +
    +        $query = "INSERT INTO users (user_name, user_password, user_id) VALUES (".$this->db->quote($data[1]['user_name'], 'text').", :question, :userid)";
    +        $stmt = $this->db->prepare($query, array('text', 'integer'), MDB2_PREPARE_MANIP);
    +
    +        $stmt->bindValue('question', $data[1]['user_password']);
    +        $stmt->bindValue('userid', $data[1]['user_id']);
    +
    +        $result = $stmt->execute();
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(true, 'Could not execute prepared query with named placeholders and a quoted text value in front. Error: '.$result->getMessage());
    +        }
    +        $stmt->free();
    +
    +        $query = 'SELECT user_name, user_password, user_id FROM users WHERE user_id=:user_id';
    +        $stmt = $this->db->prepare($query, array('integer'), array('text', 'text', 'integer'));
    +        foreach ($data as $row_data) {
    +            $result =& $stmt->execute(array('user_id' => $row_data['user_id']));
    +            if (PEAR::isError($result)) {
    +                $this->assertTrue(!PEAR::isError($result), 'Could not execute prepared. Error: '.$result->getUserinfo());
    +                break;
    +            }
    +            $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
    +            if (!is_array($row)) {
    +                $this->assertTrue(false, 'Prepared SELECT failed');
    +            } else {
    +                $diff = (array)array_diff($row, $row_data);
    +                $this->assertTrue(empty($diff), 'Prepared SELECT failed for fields: '.implode(', ', array_keys($diff)));
    +            }
    +        }
    +        $stmt->free();
    +
    +        $row_data = reset($data);
    +        $query = 'SELECT user_name, user_password, user_id FROM users WHERE user_id='.$this->db->quote($row_data['user_id'], 'integer');
    +        $stmt = $this->db->prepare($query, null, array('text', 'text', 'integer'));
    +        $result =& $stmt->execute(array());
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(!PEAR::isError($result), 'Could not execute prepared statement with no placeholders. Error: '.$result->getUserinfo());
    +            break;
    +        }
    +        $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
    +        if (!is_array($row)) {
    +            $this->assertTrue(false, 'Prepared SELECT failed');
    +        } else {
    +            $diff = (array)array_diff($row, $row_data);
    +            $this->assertTrue(empty($diff), 'Prepared SELECT failed for fields: '.implode(', ', array_keys($diff)));
    +        }
    +        $stmt->free();
    +
    +        $row_data = reset($data);
    +        $query = 'SELECT user_name, user_password, user_id FROM users WHERE user_name='.$this->db->quote($row_data['user_name'], 'text').' AND user_id = ? AND user_password='.$this->db->quote($row_data['user_password'], 'text');
    +        $stmt = $this->db->prepare($query, array('integer'), array('text', 'text', 'integer'));
    +        $result =& $stmt->execute(array($row_data['user_id']));
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(!PEAR::isError($result), 'Could not execute prepared with quoted text fields around a placeholder. Error: '.$result->getUserinfo());
    +            break;
    +        }
    +        $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
    +        if (!is_array($row)) {
    +            $this->assertTrue(false, 'Prepared SELECT failed');
    +        } else {
    +            $diff = (array)array_diff($row, $row_data);
    +            $this->assertTrue(empty($diff), 'Prepared SELECT failed for fields: '.implode(', ', array_keys($diff)));
    +        }
    +        $stmt->free();
    +
    +        foreach ($this->db->sql_comments as $comment) {
    +            $query = 'SELECT user_name, user_password, user_id FROM users WHERE '.$comment['start'].' maps to class::foo() '.$comment['end'].' user_name=:username';
    +            $row_data = reset($data);
    +            $stmt = $this->db->prepare($query, array('text'), array('text', 'text', 'integer'));
    +            $result =& $stmt->execute(array('username' => $row_data['user_name']));
    +            if (PEAR::isError($result)) {
    +                $this->assertTrue(!PEAR::isError($result), 'Could not execute prepared where a name parameter is contained in an SQL comment ('.$comment['start'].'). Error: '.$result->getUserinfo());
    +                break;
    +            }
    +            $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
    +            if (!is_array($row)) {
    +                $this->assertTrue(false, 'Prepared SELECT failed');
    +            } else {
    +                $diff = (array)array_diff($row, $row_data);
    +                $this->assertTrue(empty($diff), 'Prepared SELECT failed for fields: '.implode(', ', array_keys($diff)));
    +            }
    +            $stmt->free();
    +        }
    +        
    +        $row_data = reset($data);
    +        $query = 'SELECT user_name, user_password, user_id FROM users WHERE user_name=:username OR user_password=:username';
    +        $stmt = $this->db->prepare($query, array('text'), array('text', 'text', 'integer'));
    +        $result =& $stmt->execute(array('username' => $row_data['user_name']));
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(!PEAR::isError($result), 'Could not execute prepared where the same named parameter is used twice. Error: '.$result->getUserinfo());
    +            break;
    +        }
    +        $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
    +        if (!is_array($row)) {
    +            $this->assertTrue(false, 'Prepared SELECT failed');
    +        } else {
    +            $diff = (array)array_diff($row, $row_data);
    +            $this->assertTrue(empty($diff), 'Prepared SELECT failed for fields: '.implode(', ', array_keys($diff)));
    +        }
    +        $stmt->free();
    +    }
    +
    +    /**
    +     * Test _skipDelimitedStrings(), used by prepare()
    +     *
    +     * If the placeholder is contained within a delimited string, it must be skipped,
    +     * and the cursor position must be advanced
    +     */
    +    function testSkipDelimitedStrings() {
    +        //test correct placeholder
    +        $query = 'SELECT what FROM tbl WHERE x = ?';
    +        $position = 0;
    +        $p_position = strpos($query, '?');
    +        $this->assertEquals($position, $this->db->_skipDelimitedStrings($query, $position, $p_position), 'Error: the cursor position has changed');
    +
    +        //test placeholder within a quoted string
    +        $query = 'SELECT what FROM tbl WHERE x = '. $this->db->string_quoting['start'] .'blah?blah'. $this->db->string_quoting['end'] .' AND y = ?';
    +        $position = 0;
    +        $p_position = strpos($query, '?');
    +        $new_pos = $this->db->_skipDelimitedStrings($query, $position, $p_position);
    +        $this->assertTrue($position !=$new_pos, 'Error: the cursor position was not advanced');
    +
    +        //test placeholder within a comment
    +        foreach ($this->db->sql_comments as $comment) {
    +            $query = 'SELECT what FROM tbl WHERE x = '. $comment['start'] .'blah?blah'. $comment['end'] .' AND y = ?';
    +            $position = 0;
    +            $p_position = strpos($query, '?');
    +            $new_pos = $this->db->_skipDelimitedStrings($query, $position, $p_position);
    +            $this->assertTrue($position != $new_pos, 'Error: the cursor position was not advanced');
    +        }
    +
    +        //add some tests for named placeholders and for identifier_quoting
    +    }
    +
    +    /**
    +     * Test retrieval of result metadata
    +     *
    +     * This tests the result metadata by executing a prepared query and
    +     * select the data, and checking the result contains the correct
    +     * number of columns and that the column names are in the correct order
    +     */
    +    function testMetadata() {
    +        $data = $this->getSampleData(1234);
    +
    +        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
    +        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
    +
    +        $result = $stmt->execute(array_values($data));
    +        $stmt->free();
    +
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Error executing prepared query: '.$result->getMessage());
    +        }
    +
    +        $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users';
    +        $result =& $this->db->query($query, $this->fields);
    +
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Error selecting from users'.$result->getMessage());
    +        }
    +
    +        $numcols = $result->numCols();
    +
    +        $this->assertEquals(count($this->fields), $numcols, "The query result returned an incorrect number of columns unlike expected");
    +
    +        $column_names = $result->getColumnNames();
    +        $fields = array_keys($this->fields);
    +        for ($column = 0; $column < $numcols; $column++) {
    +            $this->assertEquals($column, $column_names[$fields[$column]], "The query result column \"".$fields[$column]."\" was returned in an incorrect position");
    +        }
    +
    +    }
    +
    +    /**
    +     * Test storage and retrieval of nulls
    +     *
    +     * This tests null storage and retrieval by successively inserting,
    +     * selecting, and testing a number of null / not null values
    +     */
    +    function testNulls() {
    +        $portability = $this->db->getOption('portability');
    +        if ($portability & MDB2_PORTABILITY_EMPTY_TO_NULL) {
    +            $nullisempty = true;
    +        } else {
    +            $nullisempty = false;
    +        }
    +        $test_values = array(
    +            array('test', false),
    +            array('NULL', false),
    +            array('null', false),
    +            array('', $nullisempty),
    +            array(null, true)
    +        );
    +
    +        for ($test_value = 0; $test_value <= count($test_values); $test_value++) {
    +            if ($test_value == count($test_values)) {
    +                $value = 'NULL';
    +                $is_null = true;
    +            } else {
    +                $value = $this->db->quote($test_values[$test_value][0], 'text');
    +                $is_null = $test_values[$test_value][1];
    +            }
    +
    +            $this->clearTables();
    +
    +            $result = $this->db->exec("INSERT INTO users (user_name,user_password,user_id) VALUES ($value,$value,0)");
    +
    +            if (PEAR::isError($result)) {
    +                $this->assertTrue(false, 'Error executing insert query: '.$result->getMessage());
    +            }
    +
    +            $result =& $this->db->query('SELECT user_name,user_password FROM users', array('text', 'text'));
    +
    +            if (PEAR::isError($result)) {
    +                $this->assertTrue(false, 'Error executing select query: '.$result->getMessage());
    +            }
    +
    +            if ($is_null) {
    +                $error_message = 'A query result column is not NULL unlike what was expected';
    +            } else {
    +                $error_message = 'A query result column is NULL even though it was expected to be different';
    +            }
    +
    +            $row = $result->fetchRow();
    +            $this->assertTrue((is_null($row[0]) == $is_null), $error_message);
    +            $this->assertTrue((is_null($row[1]) == $is_null), $error_message);
    +
    +            $result->free();
    +        }
    +
    +        $methods = array('fetchOne', 'fetchRow');
    +
    +        foreach ($methods as $method) {
    +            $result =& $this->db->query('SELECT user_name FROM users WHERE user_id=123', array('text'));
    +            $value = $result->$method();
    +            if (PEAR::isError($value)) {
    +                $this->assertTrue(false, 'Error fetching non existent row');
    +            } else {
    +                $this->assertNull($value, 'selecting non existent row with "'.$method.'()" did not return NULL');
    +                $result->free();
    +            }
    +        }
    +
    +        $methods = array('fetchCol', 'fetchAll');
    +
    +        foreach ($methods as $method) {
    +            $result =& $this->db->query('SELECT user_name FROM users WHERE user_id=123', array('text'));
    +            $value = $result->$method();
    +            if (PEAR::isError($value)) {
    +                $this->assertTrue(false, 'Error fetching non existent row');
    +            } else {
    +                $this->assertTrue((is_array($value) && empty($value)), 'selecting non existent row with "'.$method.'()" did not return empty array');
    +                $result->free();
    +            }
    +        }
    +
    +        $methods = array('queryOne', 'queryRow');
    +
    +        foreach ($methods as $method) {
    +            $value = $this->db->$method('SELECT user_name FROM users WHERE user_id=123', array('text'));
    +            if (PEAR::isError($value)) {
    +                $this->assertTrue(false, 'Error fetching non existent row');
    +            } else {
    +                $this->assertNull($value, 'selecting non existent row with "'.$method.'()" did not return NULL');
    +                $result->free();
    +            }
    +        }
    +
    +        $methods = array('queryCol', 'queryAll');
    +
    +        foreach ($methods as $method) {
    +            $value = $this->db->$method('SELECT user_name FROM users WHERE user_id=123', array('text'));
    +            if (PEAR::isError($value)) {
    +                $this->assertTrue(false, 'Error fetching non existent row');
    +            } else {
    +                $this->assertTrue((is_array($value) && empty($value)), 'selecting non existent row with "'.$method.'()" did not return empty array');
    +                $result->free();
    +            }
    +        }
    +    }
    +
    +    /**
    +     * Test paged queries
    +     *
    +     * Test the use of setLimit to return paged queries
    +     */
    +    function testRanges() {
    +        if (!$this->supported('limit_queries')) {
    +            return;
    +        }
    +
    +        $data = array();
    +        $total_rows = 5;
    +
    +        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
    +        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
    +
    +        for ($row = 0; $row < $total_rows; $row++) {
    +            $data[$row] = $this->getSampleData($row);
    +            $result = $stmt->execute(array_values($data[$row]));
    +
    +            if (PEAR::isError($result)) {
    +                $this->assertTrue(false, 'Error executing prepared query: '.$result->getMessage());
    +            }
    +        }
    +
    +        $stmt->free();
    +
    +        for ($rows = 2, $start_row = 0; $start_row < $total_rows; $start_row += $rows) {
    +
    +            $this->db->setLimit($rows, $start_row);
    +
    +            $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users ORDER BY user_name';
    +            $result =& $this->db->query($query, $this->fields);
    +
    +            if (PEAR::isError($result)) {
    +                $this->assertTrue(false, 'Error executing select query: '.$result->getMessage());
    +            }
    +
    +            for ($row = 0; $row < $rows && ($row + $start_row < $total_rows); $row++) {
    +                $this->verifyFetchedValues($result, $row, $data[$row + $start_row]);
    +            }
    +        }
    +
    +        $this->assertFalse($result->valid(), "The query result did not seem to have reached the end of result as expected starting row $start_row after fetching upto row $row");
    +
    +        $result->free();
    +
    +        for ($rows = 2, $start_row = 0; $start_row < $total_rows; $start_row += $rows) {
    +
    +            $this->db->setLimit($rows, $start_row);
    +
    +            $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users ORDER BY user_name';
    +            $result =& $this->db->query($query, $this->fields);
    +
    +            if (PEAR::isError($result)) {
    +                $this->assertTrue(false, 'Error executing select query: '.$result->getMessage());
    +            }
    +
    +            $result_rows = $result->numRows();
    +
    +            $expected = ($start_row == ($total_rows-1)) ? 1 : $rows;
    +            $this->assertEquals($expected, $result_rows, 'invalid number of rows returned');
    +            $this->assertTrue(($result_rows <= $rows), 'expected a result of no more than '.$rows.' but the returned number of rows is '.$result_rows);
    +
    +            for ($row = 0; $row < $result_rows; $row++) {
    +                $this->assertTrue($result->valid(), 'The query result seem to have reached the end of result at row '.$row.' that is before '.$result_rows.' as expected');
    +                $this->verifyFetchedValues($result, $row, $data[$row + $start_row]);
    +            }
    +        }
    +
    +        $this->assertTrue(!$result->valid(), "The query result did not seem to have reached the end of result as expected starting row $start_row after fetching upto row $row");
    +
    +        $result->free();
    +    }
    +
    +    /**
    +     * Test the handling of sequences
    +     */
    +    function testSequences() {
    +        if (!$this->supported('sequences')) {
    +           return;
    +        }
    +
    +        $this->db->loadModule('Manager', null, true);
    +
    +        for ($start_value = 1; $start_value < 4; $start_value++) {
    +            $sequence_name = "test_sequence_$start_value";
    +
    +            $result = $this->db->manager->createSequence($sequence_name, $start_value);
    +            if (PEAR::isError($result)) {
    +                $this->assertTrue(false, "Error creating sequence $sequence_name with start value $start_value: ".$result->getMessage());
    +            } else {
    +                for ($sequence_value = $start_value; $sequence_value < ($start_value + 4); $sequence_value++) {
    +                    $value = $this->db->nextID($sequence_name, false);
    +
    +                    $this->assertEquals($sequence_value, $value, "The returned sequence value for $sequence_name is not expected with sequence start value with $start_value");
    +                }
    +
    +                $result = $this->db->manager->dropSequence($sequence_name);
    +
    +                if (PEAR::isError($result)) {
    +                    $this->assertTrue(false, "Error dropping sequence $sequence_name : ".$result->getMessage());
    +                }
    +            }
    +        }
    +
    +        // Test ondemand creation of sequences
    +        $sequence_name = 'test_ondemand';
    +        $this->db->expectError(MDB2_ERROR_NOSUCHTABLE);
    +        $this->db->manager->dropSequence($sequence_name);
    +        $this->db->popExpect();
    +
    +        for ($sequence_value = 1; $sequence_value < 4; $sequence_value++) {
    +            $value = $this->db->nextID($sequence_name);
    +
    +            if (PEAR::isError($result)) {
    +                $this->assertTrue(false, "Error creating with ondemand sequence: ".$result->getMessage());
    +            } else {
    +                $this->assertEquals($sequence_value, $value, "Error in ondemand sequences. The returned sequence value is not expected value");
    +            }
    +        }
    +
    +        $result = $this->db->manager->dropSequence($sequence_name);
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, "Error dropping sequence $sequence_name : ".$result->getMessage());
    +        }
    +
    +        // Test currId()
    +        $sequence_name = 'test_currid';
    +
    +        $next = $this->db->nextID($sequence_name);
    +        $curr = $this->db->currID($sequence_name);
    +
    +        if (PEAR::isError($curr)) {
    +            $this->assertTrue(false, "Error getting the current value of sequence $sequence_name : ".$curr->getMessage());
    +        } else {
    +            if ($next != $curr) {
    +                if ($next+1 == $curr) {
    +                    $this->assertTrue(false, "Warning: currID() is using nextID() instead of a native implementation");
    +                } else {
    +                    $this->assertEquals($next, $curr, "return value if currID() does not match the previous call to nextID()");
    +                }
    +            }
    +        }
    +        $result = $this->db->manager->dropSequence($sequence_name);
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, "Error dropping sequence $sequence_name : ".$result->getMessage());
    +        }
    +
    +        // Test lastInsertid()
    +        if (!$this->db->supports('new_link')) {
    +           return;
    +        }
    +
    +        $sequence_name = 'test_lastinsertid';
    +
    +        $dsn = MDB2::parseDSN($this->dsn);
    +        $dsn['new_link'] = true;
    +        $dsn['database'] = $this->database;
    +        $db =& MDB2::connect($dsn, $this->options);
    +
    +        $next = $this->db->nextID($sequence_name);
    +        $next2 = $db->nextID($sequence_name);
    +        $last = $this->db->lastInsertID($sequence_name);
    +
    +        if (PEAR::isError($last)) {
    +            $this->assertTrue(false, "Error getting the last value of sequence $sequence_name : ".$last->getMessage());
    +        } else {
    +            $this->assertEquals($next, $last, "return value if lastInsertID() does not match the previous call to nextID()");
    +        }
    +        $result = $this->db->manager->dropSequence($sequence_name);
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, "Error dropping sequence $sequence_name : ".$result->getMessage());
    +        }
    +    }
    +
    +    /**
    +     * Test replace query
    +     *
    +     * The replace method emulates the replace query of mysql
    +     */
    +    function testReplace() {
    +        if (!$this->supported('replace')) {
    +            return;
    +        }
    +
    +        $row = 1234;
    +        $data = $this->getSampleData($row);
    +
    +        $fields = array(
    +            'user_name' => array(
    +                'value' => "user_$row",
    +                'type' => 'text'
    +            ),
    +            'user_password' => array(
    +                'value' => $data['user_password'],
    +                'type' => 'text'
    +            ),
    +            'subscribed' => array(
    +                'value' => $data['subscribed'],
    +                'type' => 'boolean'
    +            ),
    +            'user_id' => array(
    +                'value' => $data['user_id'],
    +                'type' => 'integer',
    +                'key' => 1
    +            ),
    +            'quota' => array(
    +                'value' => $data['quota'],
    +                'type' => 'decimal'
    +            ),
    +            'weight' => array(
    +                'value' => $data['weight'],
    +                'type' => 'float'
    +            ),
    +            'access_date' => array(
    +                'value' => $data['access_date'],
    +                'type' => 'date'
    +            ),
    +            'access_time' => array(
    +                'value' => $data['access_time'],
    +                'type' => 'time'
    +            ),
    +            'approved' => array(
    +                'value' => $data['approved'],
    +                'type' => 'timestamp'
    +            )
    +        );
    +
    +        $result = $this->db->replace('users', $fields);
    +
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Replace failed');
    +        }
    +
    +        if ($this->db->supports('affected_rows')) {
    +            $affected_rows = $result;
    +            $this->assertEquals(1, $result, "replacing a row in an empty table returned incorrect value");
    +        } else {
    +            $this->assertTrue(false, '"affected_rows" is not supported');
    +        }
    +
    +        $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users';
    +        $result =& $this->db->query($query, $this->fields);
    +
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Error selecting from users'.$result->getMessage());
    +        }
    +
    +        $this->verifyFetchedValues($result, 0, $data);
    +
    +        $row = 4321;
    +        $fields['user_name']['value']     = $data['user_name']     = 'user_'.$row;
    +        $fields['user_password']['value'] = $data['user_password'] = 'somepass';
    +        $fields['subscribed']['value']    = $data['subscribed']    = $row % 2 ? true : false;
    +        $fields['quota']['value']         = $data['quota']         = strval($row/100);
    +        $fields['weight']['value']        = $data['weight']        = sqrt($row);
    +        $fields['access_date']['value']   = $data['access_date']   = MDB2_Date::mdbToday();
    +        $fields['access_time']['value']   = $data['access_time']   = MDB2_Date::mdbTime();
    +        $fields['approved']['value']      = $data['approved']      = MDB2_Date::mdbNow();
    +
    +        $result = $this->db->replace('users', $fields);
    +
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Replace failed');
    +        }
    +        if ($this->db->supports('affected_rows')) {
    +            $this->assertEquals(2, $result, "replacing a row returned incorrect result");
    +        }
    +
    +        $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users';
    +        $result =& $this->db->query($query, $this->fields);
    +
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Error selecting from users'.$result->getMessage());
    +        }
    +
    +        $this->verifyFetchedValues($result, 0, $data);
    +
    +        $this->assertTrue(!$result->valid(), 'the query result did not seem to have reached the end of result as expected');
    +
    +        $result->free();
    +    }
    +
    +    /**
    +     * Test affected rows methods
    +     */
    +    function testAffectedRows() {
    +        if (!$this->supported('affected_rows')) {
    +            return;
    +        }
    +
    +        $data = array();
    +        $total_rows = 7;
    +
    +        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
    +        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
    +
    +        for ($row = 0; $row < $total_rows; $row++) {
    +            $data[$row] = $this->getSampleData($row);
    +            $result = $stmt->execute(array_values($data[$row]));
    +
    +            if (PEAR::isError($result)) {
    +                $this->assertTrue(false, 'Error executing prepared query: '.$result->getMessage());
    +            }
    +
    +            $this->assertEquals(1, $result, "Inserting the row $row returned incorrect affected row count");
    +        }
    +
    +        $stmt->free();
    +
    +        $query = 'UPDATE users SET user_password=? WHERE user_id < ?';
    +        $stmt = $this->db->prepare($query, array('text', 'integer'), MDB2_PREPARE_MANIP);
    +
    +        for ($row = 0; $row < $total_rows; $row++) {
    +            $password = "pass_$row";
    +            if ($row == 0) {
    +                $stmt->bindParam(0, $password);
    +                $stmt->bindParam(1, $row);
    +            }
    +
    +            $result = $stmt->execute();
    +
    +            if (PEAR::isError($result)) {
    +                $this->assertTrue(false, 'Error executing prepared query: '.$result->getMessage());
    +            }
    +
    +            $this->assertEquals($row, $result, "Updating the $row rows returned incorrect affected row count");
    +        }
    +
    +        $stmt->free();
    +
    +        $query = 'DELETE FROM users WHERE user_id >= ?';
    +        $stmt = $this->db->prepare($query, array('integer'), MDB2_PREPARE_MANIP);
    +
    +        $row = intval($total_rows / 2);
    +        $stmt->bindParam(0, $row);
    +        for ($row = $total_rows; $total_rows; $total_rows = $row) {
    +            $row = intval($total_rows / 2);
    +
    +            $result = $stmt->execute();
    +
    +            if (PEAR::isError($result)) {
    +                $this->assertTrue(false, 'Error executing prepared query: '.$result->getMessage());
    +            }
    +
    +            $this->assertEquals(($total_rows - $row), $result, 'Deleting rows returned incorrect affected row count');
    +
    +        }
    +
    +        $stmt->free();
    +    }
    +
    +    /**
    +     * Testing transaction support - Test ROLLBACK
    +     */
    +    function testTransactionsRollback() {
    +        if (!$this->supported('transactions')) {
    +            return;
    +        }
    +
    +        $data = $this->getSampleData(0);
    +
    +        $this->db->beginTransaction();
    +
    +        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
    +        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
    +
    +        $result = $stmt->execute(array_values($data));
    +        $this->db->rollback();
    +        $stmt->free();
    +
    +        $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users';
    +        $result =& $this->db->query($query);
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Error selecting from users'.$result->getMessage());
    +        }
    +        $this->assertTrue(!$result->valid(), 'Transaction rollback did not revert the row that was inserted');
    +        $result->free();
    +    }
    +
    +    /**
    +     * Testing transaction support - Test COMMIT
    +     */
    +    function testTransactionsCommit() {
    +        if (!$this->supported('transactions')) {
    +            return;
    +        }
    +
    +        $data = $this->getSampleData(1);
    +
    +        $this->db->beginTransaction();
    +
    +        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
    +        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
    +
    +        $result = $stmt->execute(array_values($data));
    +        $this->db->commit();
    +        $stmt->free();
    +
    +        $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users';
    +        $result =& $this->db->query($query);
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Error selecting from users'.$result->getMessage());
    +        }
    +        $this->assertTrue($result->valid(), 'Transaction commit did not make permanent the row that was inserted');
    +        $result->free();
    +    }
    +
    +    /**
    +     * Testing transaction support - Test COMMIT and ROLLBACK
    +     */
    +    function testTransactionsBoth()
    +    {
    +        if (!$this->supported('transactions')) {
    +            return;
    +        }
    +
    +        $data = $this->getSampleData(0);
    +
    +        $this->db->beginTransaction();
    +        $result = $this->db->exec('DELETE FROM users');
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Error deleting from users'.$result->getMessage());
    +            $this->db->rollback();
    +        } else {
    +            $this->db->commit();
    +        }
    +
    +        $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users';
    +        $result =& $this->db->query($query);
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Error selecting from users'.$result->getMessage());
    +        }
    +
    +        $this->assertTrue(!$result->valid(), 'Transaction end with implicit commit when re-enabling auto-commit did not make permanent the rows that were deleted');
    +        $result->free();
    +    }
    +
    +    /**
    +     * Testing emulated nested transaction support
    +     */
    +    function testNestedTransactions() {
    +        if (!$this->supported('transactions')) {
    +            return;
    +        }
    +
    +        $data = array(
    +            1 => $this->getSampleData(1234),
    +            2 => $this->getSampleData(4321),
    +        );
    +
    +        $this->db->beginNestedTransaction();
    +
    +        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
    +        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
    +
    +        $result = $stmt->execute(array_values($data[1]));
    +
    +        $this->db->beginNestedTransaction();
    +
    +        $result = $stmt->execute(array_values($data[2]));
    +        $stmt->free();
    +
    +        $result = $this->db->completeNestedTransaction();
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Inner transaction was not committed: '.$result->getMessage());
    +        }
    +
    +        $result = $this->db->completeNestedTransaction();
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Outer transaction was not committed: '.$result->getMessage());
    +        }
    +
    +        $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users';
    +        $result =& $this->db->query($query);
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Error selecting from users'.$result->getMessage());
    +        }
    +        $this->assertTrue($result->valid(), 'Transaction commit did not make permanent the row that was inserted');
    +        $result->free();
    +    }
    +
    +    /**
    +     * Testing savepoints
    +     */
    +    function testSavepoint() {
    +        if (!$this->supported('savepoints')) {
    +            return;
    +        }
    +
    +        $savepoint = 'test_savepoint';
    +
    +        $data = array(
    +            1 => $this->getSampleData(1234),
    +            2 => $this->getSampleData(4321),
    +        );
    +
    +        $this->db->beginTransaction();
    +
    +        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
    +        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
    +
    +        $result = $stmt->execute(array_values($data[1]));
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Error executing prepared query: '.$result->getMessage());
    +        }
    +
    +        $result = $this->db->beginTransaction($savepoint);
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Error setting savepoint: '.$result->getMessage());
    +        }
    +
    +        $result = $stmt->execute(array_values($data[2]));
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Error executing prepared query: '.$result->getMessage());
    +        }
    +        $stmt->free();
    +
    +        $result = $this->db->rollback($savepoint);
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Error rolling back to savepoint: '.$result->getMessage());
    +        }
    +
    +        $result = $this->db->commit();
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Transaction not committed: '.$result->getMessage());
    +        }
    +
    +        $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users';
    +        $result = $this->db->queryAll($query);
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Error selecting from users'.$result->getMessage());
    +        }
    +        $rows_inserted = count($result);
    +        $this->assertEquals(1, $rows_inserted, 'Error during transaction, invalid number of records inserted');
    +
    +        // test release savepoint
    +        $this->db->beginTransaction();
    +        $result = $this->db->beginTransaction($savepoint);
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Error setting savepoint: '.$result->getMessage());
    +        }
    +        $result = $this->db->commit($savepoint);
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Error setting savepoint: '.$result->getMessage());
    +        }
    +        $result = $this->db->commit();
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Transaction not committed: '.$result->getMessage());
    +        }
    +    }
    +
    +    /**
    +     * Testing LOB storage
    +     *
    +     * N.B. for the mssql driver: if this test fails, use an higher limit in these
    +     * two php.ini settings: "mssql.textlimit" and "mssql.textsize"
    +     */
    +    function testLOBStorage() {
    +        if (!$this->supported('LOBs')) {
    +            return;
    +        }
    +
    +        $query = 'INSERT INTO files (ID, document, picture) VALUES (1, ?, ?)';
    +        $stmt = $this->db->prepare($query, array('clob', 'blob'), MDB2_PREPARE_MANIP, array('document', 'picture'));
    +        if (PEAR::isError($stmt)) {
    +            $this->assertTrue(false, 'Failed prepared statement to insert LOB values: '.$stmt->getUserInfo());
    +        }
    +
    +        $character_lob = '';
    +        $binary_lob = '';
    +
    +        for ($i = 0; $i < 1000; $i++) {
    +            for ($code = 32; $code <= 127; $code++) {
    +                $character_lob.= chr($code);
    +            }
    +            for ($code = 0; $code <= 255; $code++) {
    +                $binary_lob.= chr($code);
    +            }
    +        }
    +
    +        $stmt->bindValue(0, $character_lob);
    +        $stmt->bindValue(1, $binary_lob);
    +
    +        $result = $stmt->execute();
    +
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Error executing prepared query: '.$result->getUserInfo());
    +        }
    +
    +        $stmt->free();
    +
    +        $result =& $this->db->query('SELECT document, picture FROM files WHERE id = 1', array('clob', 'blob'));
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Error selecting from files'.$result->getMessage());
    +        }
    +
    +        $this->assertTrue($result->valid(), 'The query result seem to have reached the end of result too soon.');
    +
    +        $row = $result->fetchRow();
    +        $clob = $row[0];
    +        if (!PEAR::isError($clob) && is_resource($clob)) {
    +            $value = '';
    +            while (!feof($clob)) {
    +                $data = fread($clob, 8192);
    +                $this->assertTrue(strlen($data) >= 0, 'Could not read CLOB');
    +                $value.= $data;
    +            }
    +            $this->db->datatype->destroyLOB($clob);
    +            $this->assertEquals($character_lob, $value, 'Retrieved character LOB value is different from what was stored');
    +        } else {
    +            $this->assertTrue(false, 'Error retrieving CLOB result');
    +        }
    +
    +        $blob = $row[1];
    +        if (!PEAR::isError($blob) && is_resource($blob)) {
    +            $value = '';
    +            while (!feof($blob)) {
    +                $data = fread($blob, 8192);
    +                $this->assertTrue(strlen($data) >= 0, 'Could not read BLOB');
    +                $value.= $data;
    +            }
    +
    +            $this->db->datatype->destroyLOB($blob);
    +            $this->assertEquals($binary_lob, $value, 'Retrieved binary LOB value is different from what was stored');
    +        } else {
    +            $this->assertTrue(false, 'Error retrieving BLOB result');
    +        }
    +        $result->free();
    +    }
    +
    +    /**
    +     * Test LOB reading of multiple records both buffered and unbuffered. See bug #8793 for why this must be tested.
    +     */
    +    function testLOBRead() {
    +        if (!$this->supported('LOBs')) {
    +            return;
    +        }
    +
    +        for ($i = 20; $i < 30; ++$i) {
    +            $query = 'INSERT INTO files (ID, document, picture) VALUES (?, ?, ?)';
    +            $stmt = $this->db->prepare($query, array('integer', 'clob', 'blob'), MDB2_PREPARE_MANIP, array(1 => 'document', 2 => 'picture'));
    +            $character_lob = $binary_lob = $i;
    +            $stmt->bindValue(1, $character_lob);
    +            $stmt->bindValue(2, $binary_lob);
    +
    +            $result = $stmt->execute(array($i));
    +
    +            if (PEAR::isError($result)) {
    +                $this->assertTrue(false, 'Error executing prepared query: '.$result->getUserInfo());
    +            }
    +            $stmt->free();
    +        }
    +
    +        $oldBuffered = $this->db->getOption('result_buffering');
    +        foreach (array(true, false) as $buffered) {
    +            $this->db->setOption('result_buffering', $buffered);
    +            $msgPost = ' with result_buffering = '.($buffered ? 'true' : 'false');
    +            $result =& $this->db->query('SELECT id, document, picture FROM files WHERE id >= 20 AND id <= 30 ORDER BY id ASC', array('integer', 'clob', 'blob'));
    +            if (PEAR::isError($result)) {
    +                $this->assertTrue(false, 'Error selecting from files'.$msgPost.$result->getMessage());
    +            } else {
    +                if ($buffered) {
    +                    $this->assertTrue($result->valid(), 'The query result seem to have reached the end of result too soon'.$msgPost);
    +                    $this->assertEquals('mdb2_bufferedresult_', strtolower(substr(get_class($result), 0, 20)), 'Error: not a buffered result');
    +                } else {
    +                    $this->assertEquals('mdb2_result_', strtolower(substr(get_class($result), 0, 12)), 'Error: an unbuffered result was expected');
    +                }
    +                for ($i = 1; $i <= ($buffered ? 2 : 1); ++$i) {
    +                    $result->seek(0);
    +                    while ($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC)) {
    +                        foreach (array('document' => 'clob', 'picture' => 'blob') as $field => $type) {
    +                            $lob = $row[$field];
    +                            if (is_a($lob, 'oci-lob')) {
    +                                $lob = $lob->load();
    +                            } elseif (is_resource($lob)) {
    +                                $lob = fread($lob, 1000);
    +                            }
    +                            $this->assertEquals($lob, $row['id'], 'LOB ('.$type.') field ('.$field.') not equal to expected value ('.$row['id'].')'.$msgPost.' on run-through '.$i);
    +                        }
    +                    }
    +                }
    +                $result->free();
    +            }
    +        }
    +        $this->db->setOption('result_buffering', $oldBuffered);
    +    }
    +
    +    /**
    +     * Test for lob storage from and to files
    +     */
    +    function testLOBFiles() {
    +        if (!$this->supported('LOBs')) {
    +            return;
    +        }
    +
    +        $query = 'INSERT INTO files (ID, document, picture) VALUES (1, :document, :picture)';
    +        $stmt = $this->db->prepare($query, array('document' => 'clob', 'picture' => 'blob'), MDB2_PREPARE_MANIP);
    +
    +        $character_data_file = 'character_data';
    +        $file = fopen($character_data_file, 'w');
    +        $this->assertTrue(((bool)$file), 'Error creating clob file to read from');
    +        $character_data = '';
    +        for ($i = 0; $i < 1000; $i++) {
    +            for ($code = 32; $code <= 127; $code++) {
    +                $character_data.= chr($code);
    +            }
    +        }
    +        $this->assertTrue((fwrite($file, $character_data, strlen($character_data)) == strlen($character_data)), 'Error creating clob file to read from');
    +        fclose($file);
    +
    +        $binary_data_file = 'binary_data';
    +        $file = fopen($binary_data_file, 'wb');
    +        $this->assertTrue(((bool)$file), 'Error creating blob file to read from');
    +        $binary_data = '';
    +        for ($i = 0; $i < 1000; $i++) {
    +            for ($code = 0; $code <= 255; $code++) {
    +                $binary_data.= chr($code);
    +            }
    +        }
    +        $this->assertTrue((fwrite($file, $binary_data, strlen($binary_data)) == strlen($binary_data)), 'Error creating blob file to read from');
    +        fclose($file);
    +
    +        $character_data_file_tmp = 'file://'.$character_data_file;
    +        $stmt->bindParam('document', $character_data_file_tmp);
    +        $binary_data_file_tmp = 'file://'.$binary_data_file;
    +        $stmt->bindParam('picture', $binary_data_file_tmp);
    +
    +        $result = $stmt->execute();
    +        $this->assertTrue(!PEAR::isError($result), 'Error executing prepared query - inserting LOB from files');
    +
    +        $stmt->free();
    +
    +        $result =& $this->db->query('SELECT document, picture FROM files WHERE id = 1', array('clob', 'blob'));
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Error selecting from files'.$result->getMessage());
    +        }
    +
    +        $this->assertTrue($result->valid(), 'The query result seem to have reached the end of result too soon.');
    +
    +        $row = $result->fetchRow();
    +        $clob = $row[0];
    +        if (!PEAR::isError($clob) && is_resource($clob)) {
    +            unlink($character_data_file);
    +            $res = $this->db->datatype->writeLOBToFile($clob, $character_data_file);
    +            $this->db->datatype->destroyLOB($clob);
    +
    +            if (PEAR::isError($res)) {
    +                $this->assertTrue(false, 'Error writing character LOB in a file');
    +            } else {
    +                $file = fopen($character_data_file, 'r');
    +                $this->assertTrue($file, "Error opening character data file: $character_data_file");
    +                $value = '';
    +                while (!feof($file)) {
    +                    $value.= fread($file, 8192);
    +                }
    +                $this->assertEquals('string', gettype($value), "Could not read from character LOB file: $character_data_file");
    +                fclose($file);
    +
    +                $this->assertEquals($character_data, $value, "retrieved character LOB value is different from what was stored");
    +            }
    +        } else {
    +            $this->assertTrue(false, 'Error creating character LOB in a file');
    +        }
    +
    +        $blob = $row[1];
    +        if (!PEAR::isError($blob) && is_resource($blob)) {
    +            unlink($binary_data_file);
    +            $res = $this->db->datatype->writeLOBToFile($blob, $binary_data_file);
    +            $this->db->datatype->destroyLOB($blob);
    +
    +            if (PEAR::isError($res)) {
    +                $this->assertTrue(false, 'Error writing binary LOB in a file');
    +            } else {
    +                $file = fopen($binary_data_file, 'rb');
    +                $this->assertTrue($file, "Error opening binary data file: $binary_data_file");
    +                $value = '';
    +                while (!feof($file)) {
    +                    $value.= fread($file, 8192);
    +                }
    +                $this->assertEquals('string', gettype($value), "Could not read from binary LOB file: $binary_data_file");
    +                fclose($file);
    +
    +                $this->assertEquals($binary_data, $value, "retrieved binary LOB value is different from what was stored");
    +            }
    +        } else {
    +            $this->assertTrue(false, 'Error creating binary LOB in a file');
    +        }
    +
    +        $result->free();
    +    }
    +
    +    /**
    +     * Test handling of lob nulls
    +     */
    +    function testLOBNulls() {
    +        if (!$this->supported('LOBs')) {
    +            return;
    +        }
    +
    +        $query = 'INSERT INTO files (ID, document, picture) VALUES (1, :document, :picture)';
    +        $stmt = $this->db->prepare($query, array('document' => 'clob', 'picture' => 'blob'), MDB2_PREPARE_MANIP);
    +
    +        $null = null;
    +        $stmt->bindParam('document', $null);
    +        $stmt->bindParam('picture', $null);
    +
    +        $result = $stmt->execute();
    +        $this->assertTrue(!PEAR::isError($result), 'Error executing prepared query - inserting NULL lobs');
    +
    +        $stmt->free();
    +
    +        $result =& $this->db->query('SELECT document, picture FROM files', array('clob', 'blob'));
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Error selecting from files'.$result->getMessage());
    +        }
    +
    +        $this->assertTrue($result->valid(), 'The query result seem to have reached the end of result too soon.');
    +
    +        $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
    +        $this->assertTrue(is_null($row['document']), 'A query result large object column document is not NULL unlike what was expected');
    +        $this->assertTrue(is_null($row['picture']), 'A query result large object column picture is not NULL unlike what was expected');
    +
    +        $result->free();
    +    }
    +
    +    function testLOBUpdate() {
    +        if (!$this->supported('LOBs')) {
    +            return;
    +        }
    +
    +        $query = 'INSERT INTO files (ID, document, picture) VALUES (1, ?, ?)';
    +        $stmt = $this->db->prepare($query, array('clob', 'blob'), MDB2_PREPARE_MANIP, array('document', 'picture'));
    +
    +        $character_lob = '';
    +        $binary_lob = '';
    +
    +        for ($i = 0; $i < 1000; $i++) {
    +            for ($code = 32; $code <= 127; ++$code) {
    +                $character_lob .= chr($code);
    +            }
    +            for ($code = 0; $code <= 255; ++$code) {
    +                $binary_lob .= chr($code);
    +            }
    +        }
    +
    +        $stmt->bindValue(0, $character_lob);
    +        $stmt->bindValue(1, $binary_lob);
    +
    +        $result = $stmt->execute();
    +
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Error executing prepared query: '.$result->getUserInfo());
    +        }
    +
    +        $stmt->free();
    +
    +        $query = 'UPDATE files SET document = ?, picture = ? WHERE ID = 1';
    +        $stmt = $this->db->prepare($query, array('clob', 'blob'), MDB2_PREPARE_MANIP, array('document', 'picture'));
    +
    +        $character_lob = '';
    +        $binary_lob = '';
    +
    +        for ($i = 0; $i < 999; $i++) {
    +            for ($code = 127; $code >= 32; --$code) {
    +                $character_lob .= chr($code);
    +            }
    +            for ($code = 255; $code >= 0; --$code) {
    +                $binary_lob .= chr($code);
    +            }
    +        }
    +
    +        $stmt->bindValue(0, $character_lob);
    +        $stmt->bindValue(1, $binary_lob);
    +
    +        $result = $stmt->execute();
    +
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Error executing prepared query: '.$result->getUserInfo());
    +        }
    +
    +        $stmt->free();
    +
    +        $result =& $this->db->query('SELECT document, picture FROM files WHERE id = 1', array('clob', 'blob'));
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Error selecting from files'.$result->getMessage());
    +        }
    +
    +        $this->assertTrue($result->valid(), 'The query result seem to have reached the end of result too soon.');
    +
    +        $row = $result->fetchRow();
    +        $clob = $row[0];
    +        if (!PEAR::isError($clob) && is_resource($clob)) {
    +            $value = '';
    +            while (!feof($clob)) {
    +                $data = fread($clob, 8192);
    +                $this->assertTrue(strlen($data) >= 0, 'Could not read CLOB');
    +                $value.= $data;
    +            }
    +            $this->db->datatype->destroyLOB($clob);
    +            $this->assertEquals($character_lob, $value, 'Retrieved character LOB value is different from what was stored');
    +        } else {
    +            $this->assertTrue(false, 'Error retrieving CLOB result');
    +        }
    +
    +        $blob = $row[1];
    +        if (!PEAR::isError($blob) && is_resource($blob)) {
    +            $value = '';
    +            while (!feof($blob)) {
    +                $data = fread($blob, 8192);
    +                $this->assertTrue(strlen($data) >= 0, 'Could not read BLOB');
    +                $value.= $data;
    +            }
    +
    +            $this->db->datatype->destroyLOB($blob);
    +            $this->assertEquals($binary_lob, $value, 'Retrieved binary LOB value is different from what was stored');
    +        } else {
    +            $this->assertTrue(false, 'Error retrieving BLOB result');
    +        }
    +        $result->free();
    +    }
    +
    +    /**
    +     * Test retrieval of result metadata
    +     *
    +     * This tests the result metadata by executing a prepared query and
    +     * select the data, and checking the result contains the correct
    +     * number of columns and that the column names are in the correct order
    +     */
    +    function testConvertEmpty2Null() {
    +#$this->db->setOption('portability', MDB2_PORTABILITY_ALL ^ MDB2_PORTABILITY_EMPTY_TO_NULL);
    +
    +        $data = $this->getSampleData(1234);
    +        $data['user_password'] = '';
    +
    +        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
    +        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
    +        $result = $stmt->execute(array_values($data));
    +        $stmt->free();
    +
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Error executing prepared query: '.$result->getMessage());
    +        }
    +
    +        $row = $this->db->queryRow('SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users WHERE user_password IS NULL', $this->fields);
    +
    +        if (PEAR::isError($row)) {
    +            $this->assertTrue(false, 'Error selecting from users'.$result->getMessage());
    +        }
    +
    +        $this->assertEquals(count($this->fields), count($row), "The query result returned a number of columns unlike ".count($this->fields) .' as expected');
    +    }
    +
    +    function testPortabilityOptions() {
    +        // MDB2_PORTABILITY_DELETE_COUNT
    +        $data = array();
    +        $total_rows = 5;
    +
    +        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
    +        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
    +        for ($row = 0; $row < $total_rows; $row++) {
    +            $data[$row] = $this->getSampleData($row);
    +            $result = $stmt->execute(array_values($data[$row]));
    +            if (PEAR::isError($result)) {
    +                $this->assertTrue(false, 'Error executing prepared query: '.$result->getMessage());
    +            }
    +        }
    +        $stmt->free();
    +
    +        $this->db->setOption('portability', MDB2_PORTABILITY_NONE | MDB2_PORTABILITY_DELETE_COUNT);
    +        $affected_rows = $this->db->exec('DELETE FROM users');
    +        if (PEAR::isError($affected_rows)) {
    +            $this->assertTrue(false, 'Error executing query: '.$affected_rows->getMessage());
    +        }
    +        $this->assertEquals($total_rows, $affected_rows, 'MDB2_PORTABILITY_DELETE_COUNT not working');
    +
    +        // MDB2_PORTABILITY_FIX_CASE
    +        $fields = array_keys($this->fields);
    +        $this->db->setOption('portability', MDB2_PORTABILITY_NONE | MDB2_PORTABILITY_FIX_CASE);
    +        $this->db->setOption('field_case', CASE_UPPER);
    +
    +        $data = $this->getSampleData(1234);
    +        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
    +        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
    +        $result = $stmt->execute(array_values($data));
    +        $stmt->free();
    +
    +        $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users';
    +        $result =& $this->db->queryRow($query, $this->fields, MDB2_FETCHMODE_ASSOC);
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Error selecting from users'.$result->getMessage());
    +        }
    +        $field = reset($fields);
    +        foreach (array_keys($result) as $fieldname) {
    +            $this->assertEquals(strtoupper($field), $fieldname, 'MDB2_PORTABILITY_FIX_CASE CASE_UPPER not working');
    +            $field = next($fields);
    +        }
    +
    +        $this->db->setOption('field_case', CASE_LOWER);
    +        $query = 'SELECT ' . implode(', ', array_keys($this->fields)) . ' FROM users';
    +        $result =& $this->db->queryRow($query, $this->fields, MDB2_FETCHMODE_ASSOC);
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Error selecting from users'.$result->getMessage());
    +        }
    +        $field = reset($fields);
    +        foreach (array_keys($result) as $fieldname) {
    +            $this->assertEquals(strtolower($field), $fieldname, 'MDB2_PORTABILITY_FIX_CASE CASE_LOWER not working');
    +            $field = next($fields);
    +        }
    +
    +        // MDB2_PORTABILITY_RTRIM
    +        $this->db->setOption('portability', MDB2_PORTABILITY_NONE | MDB2_PORTABILITY_RTRIM);
    +        $value = 'rtrim   ';
    +        $query = 'INSERT INTO users (user_id, user_password) VALUES (1, ' . $this->db->quote($value, 'text') .')';
    +        $res = $this->db->exec($query);
    +        if (PEAR::isError($res)) {
    +            $this->assertTrue(false, 'Error executing query: '.$res->getMessage());
    +        }
    +        $query = 'SELECT user_password FROM users WHERE user_id = 1';
    +        $result = $this->db->queryOne($query, array('text'));
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Error selecting from users: '.$result->getMessage());
    +        }
    +        $this->assertEquals(rtrim($value), $result, '"MDB2_PORTABILITY_RTRIM = on" not working');
    +
    +        $this->db->setOption('portability', MDB2_PORTABILITY_NONE | MDB2_PORTABILITY_RTRIM);
    +        $value = ' ';
    +        $query = 'INSERT INTO users (user_id, user_name) VALUES (2, ' . $this->db->quote($value, 'text') .')';
    +        $res = $this->db->exec($query);
    +        if (PEAR::isError($res)) {
    +            $this->assertTrue(false, 'Error executing query: '.$res->getMessage());
    +        }
    +        $query = 'SELECT user_name FROM users WHERE user_id = 2';
    +        $result = $this->db->queryOne($query, array('text'));
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Error selecting from users: '.$result->getMessage());
    +        }
    +        $this->assertEquals(0, strlen($result), '"MDB2_PORTABILITY_RTRIM = on" not working');
    +
    +        if (!$this->supported('LOBs')) {
    +            return;
    +        }
    +
    +        $query = 'INSERT INTO files (ID, document, picture) VALUES (1, ?, ?)';
    +        $stmt = $this->db->prepare($query, array('clob', 'blob'), MDB2_PREPARE_MANIP, array('document', 'picture'));
    +
    +        $character_lob = '';
    +        $binary_lob = '';
    +
    +        for ($i = 0; $i < 999; $i++) {
    +            for ($code = 127; $code >= 32; --$code) {
    +                $character_lob .= chr($code);
    +            }
    +            for ($code = 255; $code >= 0; --$code) {
    +                $binary_lob .= chr($code);
    +            }
    +        }
    +
    +        $stmt->bindValue(0, $character_lob);
    +        $stmt->bindValue(1, $binary_lob);
    +
    +        $result = $stmt->execute();
    +
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Error executing prepared query: '.$result->getUserInfo());
    +        }
    +
    +        $stmt->free();
    +
    +        $result =& $this->db->query('SELECT document, picture FROM files WHERE id = 1', array('clob', 'blob'));
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Error selecting from files'.$result->getMessage());
    +        }
    +
    +        $this->assertTrue($result->valid(), 'The query result seem to have reached the end of result too soon.');
    +
    +        $row = $result->fetchRow();
    +        $clob = $row[0];
    +        if (!PEAR::isError($clob) && is_resource($clob)) {
    +            $value = '';
    +            while (!feof($clob)) {
    +                $data = fread($clob, 8192);
    +                $this->assertTrue(strlen($data) >= 0, 'Could not read CLOB');
    +                $value.= $data;
    +            }
    +            $this->db->datatype->destroyLOB($clob);
    +            $this->assertEquals($character_lob, $value, '"MDB2_PORTABILITY_RTRIM = on" Retrieved character LOB value is different from what was stored');
    +        } else {
    +            $this->assertTrue(false, 'Error retrieving CLOB result');
    +        }
    +
    +        $blob = $row[1];
    +        if (!PEAR::isError($blob) && is_resource($blob)) {
    +            $value = '';
    +            while (!feof($blob)) {
    +                $data = fread($blob, 8192);
    +                $this->assertTrue(strlen($data) >= 0, 'Could not read BLOB');
    +                $value.= $data;
    +            }
    +
    +            $this->db->datatype->destroyLOB($blob);
    +            $this->assertEquals($binary_lob, $value, '"MDB2_PORTABILITY_RTRIM = on" Retrieved binary LOB value is different from what was stored');
    +        } else {
    +            $this->assertTrue(false, 'Error retrieving BLOB result');
    +        }
    +        $result->free();
    +    }
    +
    +    /**
    +     * Test getAsKeyword()
    +     */
    +    function testgetAsKeyword()
    +    {
    +        $query = 'INSERT INTO users (' . implode(', ', array_keys($this->fields)) . ') VALUES ('.implode(', ', array_fill(0, count($this->fields), '?')).')';
    +        $stmt = $this->db->prepare($query, array_values($this->fields), MDB2_PREPARE_MANIP);
    +        $data = $this->getSampleData(1);
    +        $result = $stmt->execute(array_values($data));
    +        if (PEAR::isError($result)) {
    +            $this->assertTrue(false, 'Error executing prepared query: '.$result->getMessage());
    +        }
    +        $stmt->free();
    +
    +        $query = 'SELECT user_id'.$this->db->getAsKeyword().'foo FROM users';
    +        $result = $this->db->queryRow($query, array('integer'), MDB2_FETCHMODE_ASSOC);
    +        if (PEAR::isError($result)) {
    +            $this->assertFalse(true, 'Error getting alias column: '. $result->getMessage());
    +        } else {
    +            $this->assertTrue((array_key_exists('foo', $result)), 'Error: could not alias "user_id" with "foo" : '.var_export($result, true));
    +        }
    +    }
    +}
    +
    +?>
    \ No newline at end of file
    diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/tests/README /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/README
    --- php-mdb2-2.4.1/MDB2-2.5.0b2/tests/README	1970-01-01 01:00:00.000000000 +0100
    +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/README	2009-01-14 16:28:09.000000000 +0000
    @@ -0,0 +1,55 @@
    +This is a test framework for MDB2 built using PHPUnit.
    +These tests directly access the MDB2 API - hopefully this framework
    +should give better feedback as to where or what caused when error are encountered.
    +
    +Usage:
    +In order for the tests to work they need to access a database called
    +"driver_test". This database is created using the MDB2_Schema test or
    +running the import.schema.php script (edit the db DSN information).
    +If you have problems running these test or the driver you are using does not yet
    +provide the necessary methods you may create the "driver_test" database manually:
    +
    +CREATE TABLE "files" (
    +  "id" int(11) NOT NULL default '0',
    +  "document" longtext,
    +  "picture" longblob,
    +  UNIQUE KEY "lob_id_index_idx" ("id")
    +);
    +
    +CREATE TABLE "users" (
    +  "user_name" varchar(12) default NULL,
    +  "user_password" char(8) default NULL,
    +  "subscribed" tinyint(1) default '1',
    +  "user_id" int(11) NOT NULL default '0',
    +  "quota" decimal(18,2) default '0.00',
    +  "weight" double default '0',
    +  "access_date" date default '1970-01-01',
    +  "access_time" time default '00:00:00',
    +  "approved" datetime default '1970-01-01 00:00:00',
    +  UNIQUE KEY "users_id_index_idx" ("user_id")
    +);
    +
    +To setup the tests
    +
    +* requires PHPUnit to be installed
    +
    +* requires MDB2 (with the given driver) to be installed
    +  in a php include path.
    +
    +* copy the file test_setup.php.dist to test_setup.php
    +
    +* edit test_setup.php. The array $testarray specifies which testcases
    +  to carry out. $dbarray is an array of databases to test.
    +
    +* point your browser at test.php or your CLI at clitest.php for the results,
    +  and then fix the bugs!
    +
    +* by default test.php/clitest.php will use all tests in the testcases - if
    +  you want to pick specific tests, use testchoose.php to pick just the
    +  tests you want to run
    +
    +Writing tests:
    +
    +The tests are written using PHPUnit from pear so first make sure you
    +have the latest stable release, and have read the docs,
    +http://pear.php.net/manual/en/packages.phpunit.php
    \ No newline at end of file
    diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/tests/testchoose.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/testchoose.php
    --- php-mdb2-2.4.1/MDB2-2.5.0b2/tests/testchoose.php	1970-01-01 01:00:00.000000000 +0100
    +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/testchoose.php	2009-01-14 16:28:09.000000000 +0000
    @@ -0,0 +1,64 @@
    +'."\n";
    +    $output.= ' TestCase : '.$testcase.''."\n";
    +    $testmethods[$testcase] = getTests($testcase);
    +    foreach ($testmethods[$testcase] as $method) {
    +        $output.= testCheck($testcase, $method);
    +    }
    +    $output.= "
    \n\n"; + $output.= "

    \n\n"; +} + +?> + + +MDB2 Tests + + + + + +
    + + +
    + + \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/tests/test.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/test.php --- php-mdb2-2.4.1/MDB2-2.5.0b2/tests/test.php 1970-01-01 01:00:00.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/test.php 2009-01-14 16:28:09.000000000 +0000 @@ -0,0 +1,131 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: test.php,v 1.18 2006/10/20 16:36:32 lsmith Exp $ + +/* + This is a small test suite for MDB2 using PHPUnit + */ + +require_once 'test_setup.php'; +require_once 'PHPUnit.php'; +require_once 'testUtils.php'; +require_once 'MDB2.php'; +require_once 'HTML_TestListener.php'; + +function htmlErrorHandler($errno, $errstr, $errfile, $errline) +{ + if ((!$GLOBALS['_show_silenced'] && !error_reporting()) || $errno == 2048) { + return; + } + echo '
    ';
    +    errorHandler($errno, $errstr, $errfile, $errline);
    +    echo '
    '; +} +set_error_handler('htmlErrorHandler'); + +function htmlErrorHandlerPEAR($error_obj) +{ + echo '
    ';
    +    errorHandlerPEAR($error_obj);
    +    echo '
    '; +} +PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'htmlErrorHandlerPEAR'); + +MDB2::loadFile('Date'); + +foreach ($testcases as $testcase) { + include_once $testcase.'.php'; +} + +$database = 'driver_test'; + +$testmethods = !empty($_POST['testmethods']) ? $_POST['testmethods'] : null; + +if (!is_array($testmethods)) { + foreach ($testcases as $testcase) { + $testmethods[$testcase] = array_flip(getTests($testcase)); + } +} + +?> + + +MDB2 Tests + + + +\n"; + echo "
    Testing $display_dsn on ".PHP_VERSION."
    \n"; + + $suite = new PHPUnit_TestSuite(); + + foreach ($testcases as $testcase) { + if (isset($testmethods[$testcase]) && is_array($testmethods[$testcase])) { + $methods = array_keys($testmethods[$testcase]); + foreach ($methods as $method) { + $suite->addTest(new $testcase($method)); + } + } + } + + $result = new PHPUnit_TestResult; + $result->addListener(new HTML_TestListener); + $suite->run($result); + $count = $result->runCount(); + $failed = $result->failureCount(); + + echo "
    Summary: $failed failed assertions in $count tests
    \n"; + echo "\n
    \n"; +} +?> + + diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/tests/tests.css /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/tests.css --- php-mdb2-2.4.1/MDB2-2.5.0b2/tests/tests.css 1970-01-01 01:00:00.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/tests.css 2009-01-14 16:28:09.000000000 +0000 @@ -0,0 +1,37 @@ + + +body { + background-color: #ffffff; + color: #000000; +} + +div.failure { + border: 2px #FF0000 solid; + margin : 1em; +} + +h1 { + font-size: x-small +} + +div.test { + border : 1px #000000 solid; + width : 100%; + margin-top : 1em; + padding : 2px; +} + +.title { + top : 0px; + left : 0px; + text-align : center; + background : #000000; + color : #FFFFFF; + padding : 4px; +} + +div.testlineup { + border: 2px #000000 solid; +} + + diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/tests/test_setup.php.dist /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/test_setup.php.dist --- php-mdb2-2.4.1/MDB2-2.5.0b2/tests/test_setup.php.dist 1970-01-01 01:00:00.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/test_setup.php.dist 2009-01-14 16:28:09.000000000 +0000 @@ -0,0 +1,151 @@ + array( + 'phptype' => 'mysql', + 'username' => 'username', + 'password' => 'password', + 'hostspec' => 'hostname', + ), + 'options' => array( + 'use_transactions' => true + ) +); + +$pgsql = array( + 'dsn' => array( + 'phptype' => 'pgsql', + 'username' => 'username', + 'password' => 'password', + 'hostspec' => 'hostname', + ) +); + +$oci8 = array( + 'dsn' => array( + 'phptype' => 'oci8', + 'username' => '', + 'password' => 'password', + 'hostspec' => 'hostname', + ), + 'options' => array( + 'DBA_username' => 'username', + 'DBA_password' => 'password' + ) +); + +$sqlite = array( + 'dsn' => array( + 'phptype' => 'sqlite', + 'username' => '', + 'password' => 'password', + 'hostspec' => 'hostname', + ), + 'options' => array( + 'database_path' => '', + 'database_extension' => '', + ) +); + +// must be a user with system administrator privileges +$mssql = array( + 'dsn' => array( + 'phptype' => 'mssql', + 'username' => 'username', + 'password' => 'password', + 'hostspec' => 'hostname', + ) +); + +$fbsql = array( + 'dsn' => array( + 'phptype' => 'fbsql', + 'username' => 'username', + 'password' => 'password', + 'hostspec' => 'hostname', + ) +); + + +$ibase = array( + 'dsn' => array( + 'phptype' => 'ibase', + 'username' => 'username', + 'password' => 'password', + 'hostspec' => 'hostname', + ) +); + +$dbarray = array(); +#$dbarray[] = $mysql; +#$dbarray[] = $pgsql; +#$dbarray[] = $oci8; +#$dbarray[] = $sqlite; +#$dbarray[] = $mssql; +#$dbarray[] = $fbsql; +#$dbarray[] = $ibase; + +// you may need to uncomment the line and modify the multiplier as you see fit +#set_time_limit(60*count($dbarray)); + +//if uncommented, the following will drop and recreate the test database when running the test +// the paths assumes that MDB2_Schema is checked out in the same parent directory as MDB2 +/* +require_once('MDB2/Schema.php'); +$schema_path = '../../MDB2_Schema/tests/'; + +function pe($e) { + die($e->getMessage().' '.$e->getUserInfo()); +} +PEAR::pushErrorHandling(PEAR_ERROR_CALLBACK, 'pe'); +foreach ($dbarray as $dbtype) { + // Work around oci8 problems with dropping the connected user + $dsn = $dbtype['dsn']; + if ($dbtype['dsn']['phptype'] == 'oci8') { + $dsn['username'] = $dbtype['options']['DBA_username']; + $dsn['password'] = $dbtype['options']['DBA_password']; + $dsn['database'] = $dbtype['options']['DBA_username']; + } + $db =& MDB2::connect($dsn, $dbtype['options']); + $db->loadModule('Manager'); + if (in_array('driver_test', $db->manager->listDatabases())) { + $db->manager->dropDatabase('driver_test'); + } + // Work around oci8 problems with dropping the connected user + if ($dbtype['dsn']['phptype'] == 'oci8') { + $db->query('CREATE USER '.$dbtype['dsn']['username'].' IDENTIFIED BY '.$dbtype['dsn']['password'].' DEFAULT TABLESPACE USERS QUOTA UNLIMITED ON USERS'); + $db->query('GRANT CREATE SESSION, CREATE TABLE, CREATE SEQUENCE, CREATE TRIGGER to '.$dbtype['dsn']['username']); + } + $schema =& MDB2_Schema::factory($dbtype['dsn'], $dbtype['options']); + $schema->updateDatabase( + '../../MDB2_Schema/tests/driver_test.schema', + false, + array('create' => '1', 'name' => 'driver_test') + ); + $schema->updateDatabase( + '../../MDB2_Schema/tests/lob_test.schema', + false, + array('create' => '1', 'name' => 'driver_test') + ); +} +PEAR::popErrorHandling(); +*/ + +?> diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/MDB2-2.5.0b2/tests/testUtils.php /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/testUtils.php --- php-mdb2-2.4.1/MDB2-2.5.0b2/tests/testUtils.php 1970-01-01 01:00:00.000000000 +0100 +++ php-mdb2-2.5.0b2/MDB2-2.5.0b2/tests/testUtils.php 2009-01-14 16:28:09.000000000 +0000 @@ -0,0 +1,123 @@ +$testmethod
    \n"; +} + +/** + * Little helper function that gets a backtrace if available + */ +function getBacktrace($errline = 0) +{ + $message = ''; + if (!function_exists('debug_backtrace')) { + $message.= 'function debug_backtrace does not exists'."\n"; + } + + $debug_backtrace = debug_backtrace(); + array_shift($debug_backtrace); + $message.= 'Debug backtrace:'."\n"; + + foreach ($debug_backtrace as $trace_item) { + $message.= "\t" . ' @ '; + if (!empty($trace_item['file'])) { + $message.= basename($trace_item['file']) . ':' . $trace_item['line']; + } else { + $message.= '- PHP inner-code - '; + } + $message.= ' -- '; + if (!empty($trace_item['class'])) { + $message.= $trace_item['class'] . $trace_item['type']; + } + $message.= $trace_item['function']; + + if (!empty($trace_item['args']) && is_array($trace_item['args'])) { + $args = array(); + foreach ($trace_item['args'] as $arg) { + $args[] = is_scalar($arg) ? $arg : (is_object($arg) ? get_class($arg) : gettype($arg)); + } + $message.= '('.implode(', ', $args).')'; + } else { + $message.= '()'; + } + $message.= "\n"; + } + + return $message; +} + +require_once 'PEAR.php'; +function errorHandlerPEAR($error_obj) +{ + $message = "-- PEAR-Error --\n"; + $message.= $error_obj->getMessage().': '.$error_obj->getUserinfo()."\n"; + $message.= getBacktrace(); + + print_r($message); +} + +PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'errorHandlerPEAR'); + +$GLOBALS['_show_silenced'] = false; +function errorHandler($errno, $errstr, $errfile, $errline) +{ + if ((!$GLOBALS['_show_silenced'] && !error_reporting()) || $errno == 2048) { + return; + } + $message = "\n"; + switch ($errno) { + case E_USER_ERROR: + $message.= "FATAL [$errno] $errstr\n"; + $message.= " Fatal error in line $errline of file $errfile"; + $message.= ", PHP " . PHP_VERSION . " (" . PHP_OS . ")\n"; + $message.= "Aborting...\n"; + die($message); + break; + case E_USER_WARNING: + $message.= "ERROR [$errno] $errstr in line $errline of file $errfile\n"; + break; + case E_USER_NOTICE: + $message.= "WARNING [$errno] $errstr in line $errline of file $errfile\n"; + break; + default: + $message.= "Unkown error type: [$errno] $errstr in line $errline of file $errfile\n"; + break; + } + + $message.= getBacktrace($errline); + + print_r($message); +} + +set_error_handler('errorHandler'); +if (function_exists('xdebug_disable')) { + xdebug_disable(); +} +?> \ No newline at end of file diff -Nru /tmp/pISzB1q5JQ/php-mdb2-2.4.1/package.xml /tmp/XCLlDwJ82A/php-mdb2-2.5.0b2/package.xml --- php-mdb2-2.4.1/package.xml 2007-05-03 19:58:15.000000000 +0100 +++ php-mdb2-2.5.0b2/package.xml 2009-01-14 16:28:09.000000000 +0000 @@ -1,5 +1,5 @@ - + MDB2 pear.php.net MDB @@ -64,28 +64,35 @@ david@jaws.com.mx yes - 2007-05-03 - + + Ali Fazelzadeh + afz + afz@dev-code.com + yes + + 2009-01-14 + - 2.4.1 - 2.4.1 + 2.5.0b2 + 2.5.0b2 - stable - stable + beta + beta BSD License - - fixed bug #10407: propagate errors in MDB2_Statement_Common::execute() -- fixed bug #10452: error in getDeclaration() with custom datatype_map and no - datatype_map_callback function -- fixed bug #10521: quote($val,'decimal') and quote($val,'float') pass unsafe characters -- return length as "precision,scale" for NUMERIC and DECIMAL fields in mapNativeDatatype() -- fixed bug #10537: safer check for valid MDB2 connection in singleton() [fornax] -- fixed bug #10598: MDB2::singleton() not working in some rare conditions [fornax] -- in getTableIndexDefinition() and getTableConstraintDefinition() in the Reverse - module, also return the field position in the index/constraint -- exec() now returns a reference instead of a copy to prevent memory leaks -- request #10787: MDB2_Driver_Common::$phptype and $dbsyntax properties are now public + - fixed bug #12117: disconnect() does not work as documented +- fixed bug #12912: replace() documentation +- fixed bug #13811: _skipDelimitedStrings() fails on empty strings +- fixed bug #13898: more tolerant check for 'new_link' DSN option +- request #13929: added 'default_fk_action_ondelete' and 'default_fk_action_onupdate' + options for default FOREIGN KEY constraints actions +- fixed bug #14124: _skipDelimitedStrings() and prepare() fail with sql comments + inside quoted strings +- fixed bug #14179: declaration of MDB2_Driver_Common::raiseError() must be + compatible with that of PEAR::raiseError() +- fixed doc bug #14290: connect should mention the type of object returned +- fixed bug #14831: $ignores in _skipDelimitedStrings() [patch by Aleksander Machniak] open todo items: - handle autoincrement fields in alterTable() @@ -94,9 +101,9 @@ - add cursor support along the lines of PDO (Request #3660 etc.) - add PDO based drivers, especially a driver to support SQLite 3 (Request #6907) - add support to export/import in CSV format -- add more functions to the Function module (MD5(), IFNULL(), LENGTH() etc.) +- add more functions to the Function module (MD5(), IFNULL(), etc.) - add support for database/table/row LOCKs -- add support for FOREIGN KEYs and CHECK (ENUM as possible mysql fallback) constraints +- add support for CHECK (ENUM as possible mysql fallback) constraints - generate STATUS file from test suite results and allow users to submit test results - add support for full text index creation and querying - add tests to check if the RDBMS specific handling with portability options @@ -105,7 +112,6 @@ - add a getTableFieldsDefinitions() method to be used in tableInfo() - drop ILIKE from matchPattern() and instead add a second parameter to handle case sensitivity with arbitrary operators -- add charset and collation support to field declaration in all drivers - handle LOBs in buffered result sets (Request #8793) @@ -136,25 +142,25 @@ - + - + - + - + - + - + @@ -175,12 +181,12 @@ - + - + @@ -189,17 +195,17 @@ - + - + - - + + @@ -213,13 +219,13 @@ - + - + @@ -241,7 +247,7 @@ - + @@ -271,42 +277,42 @@ MDB2_Driver_ibase pear.php.net - 1.4.1 + 1.5.0b2 - + - MDB2_Driver_mysql + MDB2_Driver_mssql pear.php.net - 1.4.1 + 1.3.0b2 - + - MDB2_Driver_mysqli + MDB2_Driver_mysql pear.php.net - 1.4.1 + 1.5.0b2 - + - MDB2_Driver_mssql + MDB2_Driver_mysqli pear.php.net - 1.2.1 + 1.5.0b2 MDB2_Driver_oci8 pear.php.net - 1.4.1 + 1.5.0b2 MDB2_Driver_pgsql pear.php.net - 1.4.1 + 1.5.0b2 @@ -320,7 +326,7 @@ MDB2_Driver_sqlite pear.php.net - 1.4.1 + 1.5.0b2 @@ -328,6 +334,179 @@ + 2.5.0b2 + 2.5.0b2 + + + beta + beta + + 2009-01-14 + BSD License + - fixed bug #12117: disconnect() does not work as documented +- fixed bug #12912: replace() documentation +- fixed bug #13811: _skipDelimitedStrings() fails on empty strings +- fixed bug #13898: more tolerant check for 'new_link' DSN option +- request #13929: added 'default_fk_action_ondelete' and 'default_fk_action_onupdate' + options for default FOREIGN KEY constraints actions +- fixed bug #14124: _skipDelimitedStrings() and prepare() fail with sql comments + inside quoted strings +- fixed bug #14179: declaration of MDB2_Driver_Common::raiseError() must be + compatible with that of PEAR::raiseError() +- fixed doc bug #14290: connect should mention the type of object returned +- fixed bug #14831: $ignores in _skipDelimitedStrings() [patch by Aleksander Machniak] + +open todo items: +- handle autoincrement fields in alterTable() +- add length handling to LOB reverse engineering +- add EXPLAIN abstraction +- add cursor support along the lines of PDO (Request #3660 etc.) +- add PDO based drivers, especially a driver to support SQLite 3 (Request #6907) +- add support to export/import in CSV format +- add more functions to the Function module (MD5(), IFNULL(), etc.) +- add support for database/table/row LOCKs +- add support for CHECK (ENUM as possible mysql fallback) constraints +- generate STATUS file from test suite results and allow users to submit test results +- add support for full text index creation and querying +- add tests to check if the RDBMS specific handling with portability options + disabled behaves as expected +- handle implicit commits (like for DDL) in any affected driver (mysql, sqlite..) +- add a getTableFieldsDefinitions() method to be used in tableInfo() +- drop ILIKE from matchPattern() and instead add a second parameter to + handle case sensitivity with arbitrary operators +- handle LOBs in buffered result sets (Request #8793) + + + + 2.5.0b1 + 2.5.0b1 + + + alpha + alpha + + 2008-03-15 + BSD License + - request #12731: added truncateTable() in the Manager module +- request #12732: added vacuum() in the Manager module for OPTIMIZE/VACUUM TABLE abstraction +- request #12800: added alterDatabase() in the Manager module [afz] +- fixed bug #12924: correctly handle internal expected errors even with custom error handling +- fixed bug #12991: new error code in errorInfo() [afz] +- added databaseExists() method [afz] +- request #13106: added unixtimestamp() in the Function module +- added max_identifiers_length option + +open todo items: +- handle autoincrement fields in alterTable() +- add length handling to LOB reverse engineering +- add EXPLAIN abstraction +- add cursor support along the lines of PDO (Request #3660 etc.) +- add PDO based drivers, especially a driver to support SQLite 3 (Request #6907) +- add support to export/import in CSV format +- add more functions to the Function module (MD5(), IFNULL(), etc.) +- add support for database/table/row LOCKs +- add support for CHECK (ENUM as possible mysql fallback) constraints +- generate STATUS file from test suite results and allow users to submit test results +- add support for full text index creation and querying +- add tests to check if the RDBMS specific handling with portability options + disabled behaves as expected +- handle implicit commits (like for DDL) in any affected driver (mysql, sqlite..) +- add a getTableFieldsDefinitions() method to be used in tableInfo() +- drop ILIKE from matchPattern() and instead add a second parameter to + handle case sensitivity with arbitrary operators +- handle LOBs in buffered result sets (Request #8793) + + + + 2.5.0a2 + 2.5.0a2 + + + alpha + alpha + + 2007-12-06 + BSD License + - fixed bug #12358: E_STRICT changes in latest alpha broke PHP4 compatibility +- fixed bug #12351: wrong case for function PEAR::isError() in the Reverse module + [was: IsError()] +- fixed bug #12530: MDB2_Extended::autoPrepare() gives error if $types is null +- request #12012: added charset/collation support in createDatabase() for the + drivers that support this feature +- added bindname_format option (this is the regexp used to recognize named + placeholders in prepared statements) + +open todo items: +- handle autoincrement fields in alterTable() +- add length handling to LOB reverse engineering +- add EXPLAIN abstraction +- add cursor support along the lines of PDO (Request #3660 etc.) +- add PDO based drivers, especially a driver to support SQLite 3 (Request #6907) +- add support to export/import in CSV format +- add more functions to the Function module (MD5(), IFNULL(), etc.) +- add support for database/table/row LOCKs +- add support for CHECK (ENUM as possible mysql fallback) constraints +- generate STATUS file from test suite results and allow users to submit test results +- add support for full text index creation and querying +- add tests to check if the RDBMS specific handling with portability options + disabled behaves as expected +- handle implicit commits (like for DDL) in any affected driver (mysql, sqlite..) +- add a getTableFieldsDefinitions() method to be used in tableInfo() +- drop ILIKE from matchPattern() and instead add a second parameter to + handle case sensitivity with arbitrary operators +- handle LOBs in buffered result sets (Request #8793) + + + + 2.5.0a1 + 2.5.0a1 + + + alpha + alpha + + 2007-10-28 + BSD License + - fixed bug #10024: Security fix for LOBs. Added an option to turn lob_allow_url_include off by default +- fixed bug #11179: prepared statements with named placeholders fail if extra values are provided +- request #11297: added support for "schema.table" (or "owner.table") notation in the Reverse module +- initial support for FOREIGN KEY and CHECK constraints in the Reverse and Manager modules +- fixed bug #11428: propagate quote() errors with invalid data types +- added new test cases in the test suite +- added LENGTH() function in the Function module +- fixed bug #11612: raiseError() must be compatible with PEAR::raiseError() [PHP6] +- fixed bug #11790: avoid array_diff() because it has a memory leak in PHP 5.1.x +- fixed bug #11906: quoteIdentifier fails for names with dots +- fixed bug #11975: Extended::autoExecute() does not work with Oracle when using LOBs + (patch by Pieter Meulen, van der) +- fixed some E_STRICT errors with PHP5 +- fixed bug #12083: createTable() in the Manager module now returns MDB2_OK on success, + as documented +- fixed bug #12246: wrong check in MDB2::isStatement() (thanks to zaa@zaa.pp.ru) + +open todo items: +- handle autoincrement fields in alterTable() +- add length handling to LOB reverse engineering +- add EXPLAIN abstraction +- add cursor support along the lines of PDO (Request #3660 etc.) +- add PDO based drivers, especially a driver to support SQLite 3 (Request #6907) +- add support to export/import in CSV format +- add more functions to the Function module (MD5(), IFNULL(), etc.) +- add support for database/table/row LOCKs +- add support for CHECK (ENUM as possible mysql fallback) constraints +- generate STATUS file from test suite results and allow users to submit test results +- add support for full text index creation and querying +- add tests to check if the RDBMS specific handling with portability options + disabled behaves as expected +- handle implicit commits (like for DDL) in any affected driver (mysql, sqlite..) +- add a getTableFieldsDefinitions() method to be used in tableInfo() +- drop ILIKE from matchPattern() and instead add a second parameter to + handle case sensitivity with arbitrary operators +- add charset and collation support to field declaration in all drivers +- handle LOBs in buffered result sets (Request #8793) + + + 2.4.1 2.4.1