[DATABASE] Switch from PEAR DB to MDB2
This commit is contained in:
parent
2f7d6ef07b
commit
9e94b7f145
@ -173,10 +173,6 @@ The ones that you may want to set are listed below for clarity.
|
||||
Note that the real name of your database should go in there, not literally
|
||||
'yourdbname'.
|
||||
|
||||
* `db_driver`(enum['DB','MDB2'], default null): You can try changing this to
|
||||
'MDB2' to use the other driver type for DB_DataObject, but note that it
|
||||
breaks the OpenID libraries, which only support PEAR::DB.
|
||||
|
||||
* `type` (enum["mysql", "pgsql"], default 'mysql'): Used for certain
|
||||
database-specific optimization code. Assumes mysql if not set. "mysql"
|
||||
covers MariaDB, Oracle MySQL, mysqli or otherwise.
|
||||
|
1506
extlib/DB.php
1506
extlib/DB.php
File diff suppressed because it is too large
Load Diff
@ -701,7 +701,13 @@ class DB_DataObject_Generator extends DB_DataObject
|
||||
die($res->getMessage());
|
||||
}
|
||||
|
||||
while ($row = $res->fetchRow(DB_FETCHMODE_ASSOC)) {
|
||||
if ($db_driver == 'DB') {
|
||||
$fetchmode = DB_FETCHMODE_ASSOC;
|
||||
} else {
|
||||
$fetchmode = MDB2_FETCHMODE_ASSOC;
|
||||
}
|
||||
|
||||
while ($row = $res->fetchRow($fetchmode)) {
|
||||
$treffer = array();
|
||||
// this only picks up one of these.. see this for why: http://pear.php.net/bugs/bug.php?id=17049
|
||||
preg_match(
|
||||
@ -731,7 +737,11 @@ class DB_DataObject_Generator extends DB_DataObject
|
||||
die($res->getMessage());
|
||||
}
|
||||
|
||||
if ($db_driver == 'DB') {
|
||||
$text = $res->fetchRow(DB_FETCHMODE_DEFAULT, 0);
|
||||
} else {
|
||||
$text = $res->fetchRow(MDB2_FETCHMODE_DEFAULT, 0);
|
||||
}
|
||||
$treffer = array();
|
||||
// Extract FOREIGN KEYS
|
||||
preg_match_all(
|
||||
@ -1558,7 +1568,11 @@ class DB_DataObject_Generator extends DB_DataObject
|
||||
$options = (new PEAR)->getStaticProperty('DB_DataObject', 'options');
|
||||
$db_driver = empty($options['db_driver']) ? 'DB' : $options['db_driver'];
|
||||
$method = $db_driver == 'DB' ? 'getAll' : 'queryAll';
|
||||
if ($db_driver == 'DB') {
|
||||
$res = $__DB->$method('DESCRIBE ' . $table, DB_FETCHMODE_ASSOC);
|
||||
} else {
|
||||
$res = $__DB->$method('DESCRIBE ' . $table, MDB2_FETCHMODE_ASSOC);
|
||||
}
|
||||
$defaults = array();
|
||||
foreach ($res as $ar) {
|
||||
// this is initially very dumb... -> and it may mess up..
|
||||
|
2313
extlib/DB/common.php
2313
extlib/DB/common.php
File diff suppressed because it is too large
Load Diff
@ -1,531 +0,0 @@
|
||||
<?php
|
||||
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
||||
|
||||
/**
|
||||
* The PEAR DB driver for PHP's dbase extension
|
||||
* for interacting with dBase databases
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENSE: This source file is subject to version 3.0 of the PHP license
|
||||
* that is available through the world-wide-web at the following URI:
|
||||
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
|
||||
* the PHP License and are unable to obtain it through the web, please
|
||||
* send a note to license@php.net so we can mail you a copy immediately.
|
||||
*
|
||||
* @category Database
|
||||
* @package DB
|
||||
* @author Tomas V.V. Cox <cox@idecnet.com>
|
||||
* @author Daniel Convissor <danielc@php.net>
|
||||
* @copyright 1997-2007 The PHP Group
|
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0
|
||||
* @version CVS: $Id$
|
||||
* @link http://pear.php.net/package/DB
|
||||
*/
|
||||
|
||||
/**
|
||||
* Obtain the DB_common class so it can be extended from
|
||||
*/
|
||||
//require_once 'DB/common.php';
|
||||
require_once 'common.php';
|
||||
|
||||
/**
|
||||
* The methods PEAR DB uses to interact with PHP's dbase extension
|
||||
* for interacting with dBase databases
|
||||
*
|
||||
* These methods overload the ones declared in DB_common.
|
||||
*
|
||||
* @category Database
|
||||
* @package DB
|
||||
* @author Tomas V.V. Cox <cox@idecnet.com>
|
||||
* @author Daniel Convissor <danielc@php.net>
|
||||
* @copyright 1997-2007 The PHP Group
|
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0
|
||||
* @version Release: 1.9.2
|
||||
* @link http://pear.php.net/package/DB
|
||||
*/
|
||||
class DB_dbase extends DB_common
|
||||
{
|
||||
// {{{ properties
|
||||
|
||||
/**
|
||||
* The DB driver type (mysql, oci8, odbc, etc.)
|
||||
* @var string
|
||||
*/
|
||||
public $phptype = 'dbase';
|
||||
|
||||
/**
|
||||
* The database syntax variant to be used (db2, access, etc.), if any
|
||||
* @var string
|
||||
*/
|
||||
public $dbsyntax = 'dbase';
|
||||
|
||||
/**
|
||||
* The capabilities of this DB implementation
|
||||
*
|
||||
* The 'new_link' element contains the PHP version that first provided
|
||||
* new_link support for this DBMS. Contains false if it's unsupported.
|
||||
*
|
||||
* Meaning of the 'limit' element:
|
||||
* + 'emulate' = emulate with fetch row by number
|
||||
* + 'alter' = alter the query
|
||||
* + false = skip rows
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $features = array(
|
||||
'limit' => false,
|
||||
'new_link' => false,
|
||||
'numrows' => true,
|
||||
'pconnect' => false,
|
||||
'prepare' => false,
|
||||
'ssl' => false,
|
||||
'transactions' => false,
|
||||
);
|
||||
|
||||
/**
|
||||
* A mapping of native error codes to DB error codes
|
||||
* @var array
|
||||
*/
|
||||
public $errorcode_map = array();
|
||||
|
||||
/**
|
||||
* The raw database connection created by PHP
|
||||
* @var resource
|
||||
*/
|
||||
public $connection;
|
||||
|
||||
/**
|
||||
* The DSN information for connecting to a database
|
||||
* @var array
|
||||
*/
|
||||
public $dsn = array();
|
||||
|
||||
|
||||
/**
|
||||
* A means of emulating result resources
|
||||
* @var array
|
||||
*/
|
||||
public $res_row = array();
|
||||
|
||||
/**
|
||||
* The quantity of results so far
|
||||
*
|
||||
* For emulating result resources.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $result = 0;
|
||||
|
||||
/**
|
||||
* Maps dbase data type id's to human readable strings
|
||||
*
|
||||
* The human readable values are based on the output of PHP's
|
||||
* dbase_get_header_info() function.
|
||||
*
|
||||
* @var array
|
||||
* @since Property available since Release 1.7.0
|
||||
*/
|
||||
public $types = array(
|
||||
'C' => 'character',
|
||||
'D' => 'date',
|
||||
'L' => 'boolean',
|
||||
'M' => 'memo',
|
||||
'N' => 'number',
|
||||
);
|
||||
|
||||
|
||||
// }}}
|
||||
// {{{ constructor
|
||||
|
||||
/**
|
||||
* This constructor calls <kbd>parent::__construct()</kbd>
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ connect()
|
||||
|
||||
/**
|
||||
* Connect to the database and create it if it doesn't exist
|
||||
*
|
||||
* Don't call this method directly. Use DB::connect() instead.
|
||||
*
|
||||
* PEAR DB's dbase driver supports the following extra DSN options:
|
||||
* + mode An integer specifying the read/write mode to use
|
||||
* (0 = read only, 1 = write only, 2 = read/write).
|
||||
* Available since PEAR DB 1.7.0.
|
||||
* + fields An array of arrays that PHP's dbase_create() function needs
|
||||
* to create a new database. This information is used if the
|
||||
* dBase file specified in the "database" segment of the DSN
|
||||
* does not exist. For more info, see the PHP manual's
|
||||
* {@link http://php.net/dbase_create dbase_create()} page.
|
||||
* Available since PEAR DB 1.7.0.
|
||||
*
|
||||
* Example of how to connect and establish a new dBase file if necessary:
|
||||
* <code>
|
||||
* require_once 'DB.php';
|
||||
*
|
||||
* $dsn = array(
|
||||
* 'phptype' => 'dbase',
|
||||
* 'database' => '/path/and/name/of/dbase/file',
|
||||
* 'mode' => 2,
|
||||
* 'fields' => array(
|
||||
* array('a', 'N', 5, 0),
|
||||
* array('b', 'C', 40),
|
||||
* array('c', 'C', 255),
|
||||
* array('d', 'C', 20),
|
||||
* ),
|
||||
* );
|
||||
* $options = array(
|
||||
* 'debug' => 2,
|
||||
* 'portability' => DB_PORTABILITY_ALL,
|
||||
* );
|
||||
*
|
||||
* $db = DB::connect($dsn, $options);
|
||||
* if ((new PEAR)->isError($db)) {
|
||||
* die($db->getMessage());
|
||||
* }
|
||||
* </code>
|
||||
*
|
||||
* @param array $dsn the data source name
|
||||
* @param bool $persistent should the connection be persistent?
|
||||
*
|
||||
* @return int|object
|
||||
*/
|
||||
public function connect($dsn, $persistent = false)
|
||||
{
|
||||
if (!PEAR::loadExtension('dbase')) {
|
||||
return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
|
||||
}
|
||||
|
||||
$this->dsn = $dsn;
|
||||
if ($dsn['dbsyntax']) {
|
||||
$this->dbsyntax = $dsn['dbsyntax'];
|
||||
}
|
||||
|
||||
/*
|
||||
* Turn track_errors on for entire script since $php_errormsg
|
||||
* is the only way to find errors from the dbase extension.
|
||||
*/
|
||||
@ini_set('track_errors', 1);
|
||||
$php_errormsg = '';
|
||||
|
||||
if (!file_exists($dsn['database'])) {
|
||||
$this->dsn['mode'] = 2;
|
||||
if (empty($dsn['fields']) || !is_array($dsn['fields'])) {
|
||||
return $this->raiseError(
|
||||
DB_ERROR_CONNECT_FAILED,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
'the dbase file does not exist and '
|
||||
. 'it could not be created because '
|
||||
. 'the "fields" element of the DSN '
|
||||
. 'is not properly set'
|
||||
);
|
||||
}
|
||||
$this->connection = @dbase_create(
|
||||
$dsn['database'],
|
||||
$dsn['fields']
|
||||
);
|
||||
if (!$this->connection) {
|
||||
return $this->raiseError(
|
||||
DB_ERROR_CONNECT_FAILED,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
'the dbase file does not exist and '
|
||||
. 'the attempt to create it failed: '
|
||||
. $php_errormsg
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (!isset($this->dsn['mode'])) {
|
||||
$this->dsn['mode'] = 0;
|
||||
}
|
||||
$this->connection = @dbase_open(
|
||||
$dsn['database'],
|
||||
$this->dsn['mode']
|
||||
);
|
||||
if (!$this->connection) {
|
||||
return $this->raiseError(
|
||||
DB_ERROR_CONNECT_FAILED,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
$php_errormsg
|
||||
);
|
||||
}
|
||||
}
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ disconnect()
|
||||
|
||||
/**
|
||||
* Disconnects from the database server
|
||||
*
|
||||
* @return bool TRUE on success, FALSE on failure
|
||||
*/
|
||||
public function disconnect()
|
||||
{
|
||||
$ret = @dbase_close($this->connection);
|
||||
$this->connection = null;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ &query()
|
||||
|
||||
public function &query($query = null)
|
||||
{
|
||||
// emulate result resources
|
||||
$this->res_row[(int)$this->result] = 0;
|
||||
$tmp = new DB_result($this, $this->result++);
|
||||
return $tmp;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ fetchInto()
|
||||
|
||||
/**
|
||||
* Places a row from the result set into the given array
|
||||
*
|
||||
* Formating of the array and the data therein are configurable.
|
||||
* See DB_result::fetchInto() for more information.
|
||||
*
|
||||
* This method is not meant to be called directly. Use
|
||||
* DB_result::fetchInto() instead. It can't be declared "protected"
|
||||
* because DB_result is a separate object.
|
||||
*
|
||||
* @param resource $result the query result resource
|
||||
* @param array $arr the referenced array to put the data in
|
||||
* @param int $fetchmode how the resulting array should be indexed
|
||||
* @param int $rownum the row number to fetch (0 = first row)
|
||||
*
|
||||
* @return mixed DB_OK on success, NULL when the end of a result set is
|
||||
* reached or on failure
|
||||
*
|
||||
* @see DB_result::fetchInto()
|
||||
*/
|
||||
public function fetchInto($result, &$arr, $fetchmode, $rownum = null)
|
||||
{
|
||||
if ($rownum === null) {
|
||||
$rownum = $this->res_row[(int)$result]++;
|
||||
}
|
||||
if ($fetchmode & DB_FETCHMODE_ASSOC) {
|
||||
$arr = @dbase_get_record_with_names($this->connection, $rownum);
|
||||
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) {
|
||||
$arr = array_change_key_case($arr, CASE_LOWER);
|
||||
}
|
||||
} else {
|
||||
$arr = @dbase_get_record($this->connection, $rownum);
|
||||
}
|
||||
if (!$arr) {
|
||||
return null;
|
||||
}
|
||||
if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
|
||||
$this->_rtrimArrayValues($arr);
|
||||
}
|
||||
if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
|
||||
$this->_convertNullArrayValuesToEmpty($arr);
|
||||
}
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ freeResult()
|
||||
|
||||
/**
|
||||
* Deletes the result set and frees the memory occupied by the result set.
|
||||
*
|
||||
* This method is a no-op for dbase, as there aren't result resources in
|
||||
* the same sense as most other database backends.
|
||||
*
|
||||
* @param resource $result PHP's query result resource
|
||||
*
|
||||
* @return bool TRUE on success, FALSE if $result is invalid
|
||||
*
|
||||
* @see DB_result::free()
|
||||
*/
|
||||
public function freeResult($result)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ numCols()
|
||||
|
||||
/**
|
||||
* Gets the number of columns in a result set
|
||||
*
|
||||
* This method is not meant to be called directly. Use
|
||||
* DB_result::numCols() instead. It can't be declared "protected"
|
||||
* because DB_result is a separate object.
|
||||
*
|
||||
* @param $foo
|
||||
* @return int the number of columns. A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_result::numCols()
|
||||
*/
|
||||
public function numCols($foo)
|
||||
{
|
||||
return @dbase_numfields($this->connection);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ numRows()
|
||||
|
||||
/**
|
||||
* Gets the number of rows in a result set
|
||||
*
|
||||
* This method is not meant to be called directly. Use
|
||||
* DB_result::numRows() instead. It can't be declared "protected"
|
||||
* because DB_result is a separate object.
|
||||
*
|
||||
* @param $foo
|
||||
* @return int the number of rows. A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_result::numRows()
|
||||
*/
|
||||
public function numRows($foo)
|
||||
{
|
||||
return @dbase_numrecords($this->connection);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ quoteBoolean()
|
||||
|
||||
/**
|
||||
* Formats a boolean value for use within a query in a locale-independent
|
||||
* manner.
|
||||
*
|
||||
* @param boolean the boolean value to be quoted.
|
||||
* @return string the quoted string.
|
||||
* @see DB_common::quoteSmart()
|
||||
* @since Method available since release 1.7.8.
|
||||
*/
|
||||
public function quoteBoolean($boolean)
|
||||
{
|
||||
return $boolean ? 'T' : 'F';
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ tableInfo()
|
||||
|
||||
/**
|
||||
* Returns information about the current database
|
||||
*
|
||||
* @param mixed $result THIS IS UNUSED IN DBASE. The current database
|
||||
* is examined regardless of what is provided here.
|
||||
* @param int $mode a valid tableInfo mode
|
||||
*
|
||||
* @return array|object
|
||||
* A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_common::tableInfo()
|
||||
* @since Method available since Release 1.7.0
|
||||
*/
|
||||
public function tableInfo($result = null, $mode = null)
|
||||
{
|
||||
if (function_exists('dbase_get_header_info')) {
|
||||
$id = @dbase_get_header_info($this->connection);
|
||||
if (!$id && $php_errormsg) {
|
||||
return $this->raiseError(
|
||||
DB_ERROR,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
$php_errormsg
|
||||
);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* This segment for PHP 4 is loosely based on code by
|
||||
* Hadi Rusiah <deegos@yahoo.com> in the comments on
|
||||
* the dBase reference page in the PHP manual.
|
||||
*/
|
||||
$db = @fopen($this->dsn['database'], 'r');
|
||||
if (!$db) {
|
||||
return $this->raiseError(
|
||||
DB_ERROR_CONNECT_FAILED,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
$php_errormsg
|
||||
);
|
||||
}
|
||||
|
||||
$id = array();
|
||||
$i = 0;
|
||||
|
||||
$line = fread($db, 32);
|
||||
while (!feof($db)) {
|
||||
$line = fread($db, 32);
|
||||
if (substr($line, 0, 1) == chr(13)) {
|
||||
break;
|
||||
} else {
|
||||
$pos = strpos(substr($line, 0, 10), chr(0));
|
||||
$pos = ($pos == 0 ? 10 : $pos);
|
||||
$id[$i] = array(
|
||||
'name' => substr($line, 0, $pos),
|
||||
'type' => $this->types[substr($line, 11, 1)],
|
||||
'length' => ord(substr($line, 16, 1)),
|
||||
'precision' => ord(substr($line, 17, 1)),
|
||||
);
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
|
||||
fclose($db);
|
||||
}
|
||||
|
||||
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
|
||||
$case_func = 'strtolower';
|
||||
} else {
|
||||
$case_func = 'strval';
|
||||
}
|
||||
|
||||
$res = array();
|
||||
$count = count($id);
|
||||
|
||||
if ($mode) {
|
||||
$res['num_fields'] = $count;
|
||||
}
|
||||
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
$res[$i] = array(
|
||||
'table' => $this->dsn['database'],
|
||||
'name' => $case_func($id[$i]['name']),
|
||||
'type' => $id[$i]['type'],
|
||||
'len' => $id[$i]['length'],
|
||||
'flags' => ''
|
||||
);
|
||||
if ($mode & DB_TABLEINFO_ORDER) {
|
||||
$res['order'][$res[$i]['name']] = $i;
|
||||
}
|
||||
if ($mode & DB_TABLEINFO_ORDERTABLE) {
|
||||
$res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
|
||||
}
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
// }}}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* tab-width: 4
|
||||
* c-basic-offset: 4
|
||||
* End:
|
||||
*/
|
@ -1,795 +0,0 @@
|
||||
<?php
|
||||
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
||||
|
||||
/**
|
||||
* The PEAR DB driver for PHP's fbsql extension
|
||||
* for interacting with FrontBase databases
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENSE: This source file is subject to version 3.0 of the PHP license
|
||||
* that is available through the world-wide-web at the following URI:
|
||||
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
|
||||
* the PHP License and are unable to obtain it through the web, please
|
||||
* send a note to license@php.net so we can mail you a copy immediately.
|
||||
*
|
||||
* @category Database
|
||||
* @package DB
|
||||
* @author Frank M. Kromann <frank@frontbase.com>
|
||||
* @author Daniel Convissor <danielc@php.net>
|
||||
* @copyright 1997-2007 The PHP Group
|
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0
|
||||
* @version CVS: $Id$
|
||||
* @link http://pear.php.net/package/DB
|
||||
*/
|
||||
|
||||
/**
|
||||
* Obtain the DB_common class so it can be extended from
|
||||
*/
|
||||
//require_once 'DB/common.php';
|
||||
require_once 'common.php';
|
||||
|
||||
/**
|
||||
* The methods PEAR DB uses to interact with PHP's fbsql extension
|
||||
* for interacting with FrontBase databases
|
||||
*
|
||||
* These methods overload the ones declared in DB_common.
|
||||
*
|
||||
* @category Database
|
||||
* @package DB
|
||||
* @author Frank M. Kromann <frank@frontbase.com>
|
||||
* @author Daniel Convissor <danielc@php.net>
|
||||
* @copyright 1997-2007 The PHP Group
|
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0
|
||||
* @version Release: 1.9.2
|
||||
* @link http://pear.php.net/package/DB
|
||||
* @since Class functional since Release 1.7.0
|
||||
*/
|
||||
class DB_fbsql extends DB_common
|
||||
{
|
||||
// {{{ properties
|
||||
|
||||
/**
|
||||
* The DB driver type (mysql, oci8, odbc, etc.)
|
||||
* @var string
|
||||
*/
|
||||
public $phptype = 'fbsql';
|
||||
|
||||
/**
|
||||
* The database syntax variant to be used (db2, access, etc.), if any
|
||||
* @var string
|
||||
*/
|
||||
public $dbsyntax = 'fbsql';
|
||||
|
||||
/**
|
||||
* The capabilities of this DB implementation
|
||||
*
|
||||
* The 'new_link' element contains the PHP version that first provided
|
||||
* new_link support for this DBMS. Contains false if it's unsupported.
|
||||
*
|
||||
* Meaning of the 'limit' element:
|
||||
* + 'emulate' = emulate with fetch row by number
|
||||
* + 'alter' = alter the query
|
||||
* + false = skip rows
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $features = array(
|
||||
'limit' => 'alter',
|
||||
'new_link' => false,
|
||||
'numrows' => true,
|
||||
'pconnect' => true,
|
||||
'prepare' => false,
|
||||
'ssl' => false,
|
||||
'transactions' => true,
|
||||
);
|
||||
|
||||
/**
|
||||
* A mapping of native error codes to DB error codes
|
||||
* @var array
|
||||
*/
|
||||
public $errorcode_map = array(
|
||||
22 => DB_ERROR_SYNTAX,
|
||||
85 => DB_ERROR_ALREADY_EXISTS,
|
||||
108 => DB_ERROR_SYNTAX,
|
||||
116 => DB_ERROR_NOSUCHTABLE,
|
||||
124 => DB_ERROR_VALUE_COUNT_ON_ROW,
|
||||
215 => DB_ERROR_NOSUCHFIELD,
|
||||
217 => DB_ERROR_INVALID_NUMBER,
|
||||
226 => DB_ERROR_NOSUCHFIELD,
|
||||
231 => DB_ERROR_INVALID,
|
||||
239 => DB_ERROR_TRUNCATED,
|
||||
251 => DB_ERROR_SYNTAX,
|
||||
266 => DB_ERROR_NOT_FOUND,
|
||||
357 => DB_ERROR_CONSTRAINT_NOT_NULL,
|
||||
358 => DB_ERROR_CONSTRAINT,
|
||||
360 => DB_ERROR_CONSTRAINT,
|
||||
361 => DB_ERROR_CONSTRAINT,
|
||||
);
|
||||
|
||||
/**
|
||||
* The raw database connection created by PHP
|
||||
* @var resource
|
||||
*/
|
||||
public $connection;
|
||||
|
||||
/**
|
||||
* The DSN information for connecting to a database
|
||||
* @var array
|
||||
*/
|
||||
public $dsn = array();
|
||||
|
||||
|
||||
// }}}
|
||||
// {{{ constructor
|
||||
|
||||
/**
|
||||
* This constructor calls <kbd>parent::__construct()</kbd>
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ connect()
|
||||
|
||||
/**
|
||||
* Connect to the database server, log in and open the database
|
||||
*
|
||||
* Don't call this method directly. Use DB::connect() instead.
|
||||
*
|
||||
* @param array $dsn the data source name
|
||||
* @param bool $persistent should the connection be persistent?
|
||||
*
|
||||
* @return int|object
|
||||
*/
|
||||
public function connect($dsn, $persistent = false)
|
||||
{
|
||||
if (!PEAR::loadExtension('fbsql')) {
|
||||
return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
|
||||
}
|
||||
|
||||
$this->dsn = $dsn;
|
||||
if ($dsn['dbsyntax']) {
|
||||
$this->dbsyntax = $dsn['dbsyntax'];
|
||||
}
|
||||
|
||||
$params = array(
|
||||
$dsn['hostspec'] ? $dsn['hostspec'] : 'localhost',
|
||||
$dsn['username'] ? $dsn['username'] : null,
|
||||
$dsn['password'] ? $dsn['password'] : null,
|
||||
);
|
||||
|
||||
$connect_function = $persistent ? 'fbsql_pconnect' : 'fbsql_connect';
|
||||
|
||||
$ini = ini_get('track_errors');
|
||||
$php_errormsg = '';
|
||||
if ($ini) {
|
||||
$this->connection = @call_user_func_array(
|
||||
$connect_function,
|
||||
$params
|
||||
);
|
||||
} else {
|
||||
@ini_set('track_errors', 1);
|
||||
$this->connection = @call_user_func_array(
|
||||
$connect_function,
|
||||
$params
|
||||
);
|
||||
@ini_set('track_errors', $ini);
|
||||
}
|
||||
|
||||
if (!$this->connection) {
|
||||
return $this->raiseError(
|
||||
DB_ERROR_CONNECT_FAILED,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
$php_errormsg
|
||||
);
|
||||
}
|
||||
|
||||
if ($dsn['database']) {
|
||||
if (!@fbsql_select_db($dsn['database'], $this->connection)) {
|
||||
return $this->fbsqlRaiseError();
|
||||
}
|
||||
}
|
||||
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ disconnect()
|
||||
|
||||
/**
|
||||
* Produces a DB_Error object regarding the current problem
|
||||
*
|
||||
* @param int $errno if the error is being manually raised pass a
|
||||
* DB_ERROR* constant here. If this isn't passed
|
||||
* the error information gathered from the DBMS.
|
||||
*
|
||||
* @return object the DB_Error object
|
||||
*
|
||||
* @see DB_common::raiseError(),
|
||||
* DB_fbsql::errorNative(), DB_common::errorCode()
|
||||
*/
|
||||
public function fbsqlRaiseError($errno = null)
|
||||
{
|
||||
if ($errno === null) {
|
||||
$errno = $this->errorCode(fbsql_errno($this->connection));
|
||||
}
|
||||
return $this->raiseError(
|
||||
$errno,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
@fbsql_error($this->connection)
|
||||
);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ simpleQuery()
|
||||
|
||||
/**
|
||||
* Disconnects from the database server
|
||||
*
|
||||
* @return bool TRUE on success, FALSE on failure
|
||||
*/
|
||||
public function disconnect()
|
||||
{
|
||||
$ret = @fbsql_close($this->connection);
|
||||
$this->connection = null;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ nextResult()
|
||||
|
||||
/**
|
||||
* Sends a query to the database server
|
||||
*
|
||||
* @param string the SQL query string
|
||||
*
|
||||
* @return mixed + a PHP result resrouce for successful SELECT queries
|
||||
* + the DB_OK constant for other successful queries
|
||||
* + a DB_Error object on failure
|
||||
*/
|
||||
public function simpleQuery($query)
|
||||
{
|
||||
$this->last_query = $query;
|
||||
$query = $this->modifyQuery($query);
|
||||
$result = @fbsql_query("$query;", $this->connection);
|
||||
if (!$result) {
|
||||
return $this->fbsqlRaiseError();
|
||||
}
|
||||
// Determine which queries that should return data, and which
|
||||
// should return an error code only.
|
||||
if ($this->_checkManip($query)) {
|
||||
return DB_OK;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ fetchInto()
|
||||
|
||||
/**
|
||||
* Move the internal fbsql result pointer to the next available result
|
||||
*
|
||||
* @param a valid fbsql result resource
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return true if a result is available otherwise return false
|
||||
*/
|
||||
public function nextResult($result)
|
||||
{
|
||||
return @fbsql_next_result($result);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ freeResult()
|
||||
|
||||
/**
|
||||
* Places a row from the result set into the given array
|
||||
*
|
||||
* Formating of the array and the data therein are configurable.
|
||||
* See DB_result::fetchInto() for more information.
|
||||
*
|
||||
* This method is not meant to be called directly. Use
|
||||
* DB_result::fetchInto() instead. It can't be declared "protected"
|
||||
* because DB_result is a separate object.
|
||||
*
|
||||
* @param resource $result the query result resource
|
||||
* @param array $arr the referenced array to put the data in
|
||||
* @param int $fetchmode how the resulting array should be indexed
|
||||
* @param int $rownum the row number to fetch (0 = first row)
|
||||
*
|
||||
* @return mixed DB_OK on success, NULL when the end of a result set is
|
||||
* reached or on failure
|
||||
*
|
||||
* @see DB_result::fetchInto()
|
||||
*/
|
||||
public function fetchInto($result, &$arr, $fetchmode, $rownum = null)
|
||||
{
|
||||
if ($rownum !== null) {
|
||||
if (!@fbsql_data_seek($result, $rownum)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if ($fetchmode & DB_FETCHMODE_ASSOC) {
|
||||
$arr = @fbsql_fetch_array($result, FBSQL_ASSOC);
|
||||
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) {
|
||||
$arr = array_change_key_case($arr, CASE_LOWER);
|
||||
}
|
||||
} else {
|
||||
$arr = @fbsql_fetch_row($result);
|
||||
}
|
||||
if (!$arr) {
|
||||
return null;
|
||||
}
|
||||
if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
|
||||
$this->_rtrimArrayValues($arr);
|
||||
}
|
||||
if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
|
||||
$this->_convertNullArrayValuesToEmpty($arr);
|
||||
}
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ autoCommit()
|
||||
|
||||
/**
|
||||
* Deletes the result set and frees the memory occupied by the result set
|
||||
*
|
||||
* This method is not meant to be called directly. Use
|
||||
* DB_result::free() instead. It can't be declared "protected"
|
||||
* because DB_result is a separate object.
|
||||
*
|
||||
* @param resource $result PHP's query result resource
|
||||
*
|
||||
* @return bool TRUE on success, FALSE if $result is invalid
|
||||
*
|
||||
* @see DB_result::free()
|
||||
*/
|
||||
public function freeResult($result)
|
||||
{
|
||||
return is_resource($result) ? fbsql_free_result($result) : false;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ commit()
|
||||
|
||||
/**
|
||||
* Enables or disables automatic commits
|
||||
*
|
||||
* @param bool $onoff true turns it on, false turns it off
|
||||
*
|
||||
* @return int DB_OK on success. A DB_Error object if the driver
|
||||
* doesn't support auto-committing transactions.
|
||||
*/
|
||||
public function autoCommit($onoff = false)
|
||||
{
|
||||
if ($onoff) {
|
||||
$this->query("SET COMMIT TRUE");
|
||||
} else {
|
||||
$this->query("SET COMMIT FALSE");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ rollback()
|
||||
|
||||
/**
|
||||
* Commits the current transaction
|
||||
*
|
||||
* @return int DB_OK on success. A DB_Error object on failure.
|
||||
*/
|
||||
public function commit()
|
||||
{
|
||||
@fbsql_commit($this->connection);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ numCols()
|
||||
|
||||
/**
|
||||
* Reverts the current transaction
|
||||
*
|
||||
* @return int DB_OK on success. A DB_Error object on failure.
|
||||
*/
|
||||
public function rollback()
|
||||
{
|
||||
@fbsql_rollback($this->connection);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ numRows()
|
||||
|
||||
/**
|
||||
* Gets the number of columns in a result set
|
||||
*
|
||||
* This method is not meant to be called directly. Use
|
||||
* DB_result::numCols() instead. It can't be declared "protected"
|
||||
* because DB_result is a separate object.
|
||||
*
|
||||
* @param resource $result PHP's query result resource
|
||||
*
|
||||
* @return int|object
|
||||
*
|
||||
* @see DB_result::numCols()
|
||||
*/
|
||||
public function numCols($result)
|
||||
{
|
||||
$cols = @fbsql_num_fields($result);
|
||||
if (!$cols) {
|
||||
return $this->fbsqlRaiseError();
|
||||
}
|
||||
return $cols;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ affectedRows()
|
||||
|
||||
/**
|
||||
* Gets the number of rows in a result set
|
||||
*
|
||||
* This method is not meant to be called directly. Use
|
||||
* DB_result::numRows() instead. It can't be declared "protected"
|
||||
* because DB_result is a separate object.
|
||||
*
|
||||
* @param resource $result PHP's query result resource
|
||||
*
|
||||
* @return int|object
|
||||
*
|
||||
* @see DB_result::numRows()
|
||||
*/
|
||||
public function numRows($result)
|
||||
{
|
||||
$rows = @fbsql_num_rows($result);
|
||||
if ($rows === null) {
|
||||
return $this->fbsqlRaiseError();
|
||||
}
|
||||
return $rows;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ nextId()
|
||||
|
||||
/**
|
||||
* Determines the number of rows affected by a data maniuplation query
|
||||
*
|
||||
* 0 is returned for queries that don't manipulate data.
|
||||
*
|
||||
* @return int the number of rows. A DB_Error object on failure.
|
||||
*/
|
||||
public function affectedRows()
|
||||
{
|
||||
if ($this->_last_query_manip) {
|
||||
$result = @fbsql_affected_rows($this->connection);
|
||||
} else {
|
||||
$result = 0;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next free id in a sequence
|
||||
*
|
||||
* @param string $seq_name name of the sequence
|
||||
* @param boolean $ondemand when true, the seqence is automatically
|
||||
* created if it does not exist
|
||||
*
|
||||
* @return int|object
|
||||
* A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_common::nextID(), DB_common::getSequenceName(),
|
||||
* DB_fbsql::createSequence(), DB_fbsql::dropSequence()
|
||||
*/
|
||||
public function nextId($seq_name, $ondemand = true)
|
||||
{
|
||||
$seqname = $this->getSequenceName($seq_name);
|
||||
do {
|
||||
$repeat = 0;
|
||||
$this->pushErrorHandling(PEAR_ERROR_RETURN);
|
||||
$result = $this->query('SELECT UNIQUE FROM ' . $seqname);
|
||||
$this->popErrorHandling();
|
||||
if ($ondemand && DB::isError($result) &&
|
||||
$result->getCode() == DB_ERROR_NOSUCHTABLE) {
|
||||
$repeat = 1;
|
||||
$result = $this->createSequence($seq_name);
|
||||
if (DB::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
} else {
|
||||
$repeat = 0;
|
||||
}
|
||||
} while ($repeat);
|
||||
if (DB::isError($result)) {
|
||||
return $this->fbsqlRaiseError();
|
||||
}
|
||||
$result->fetchInto($tmp, DB_FETCHMODE_ORDERED);
|
||||
return $tmp[0];
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ dropSequence()
|
||||
|
||||
/**
|
||||
* Creates a new sequence
|
||||
*
|
||||
* @param string $seq_name name of the new sequence
|
||||
*
|
||||
* @return int DB_OK on success. A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_common::createSequence(), DB_common::getSequenceName(),
|
||||
* DB_fbsql::nextID(), DB_fbsql::dropSequence()
|
||||
*/
|
||||
public function createSequence($seq_name)
|
||||
{
|
||||
$seqname = $this->getSequenceName($seq_name);
|
||||
$res = $this->query('CREATE TABLE ' . $seqname
|
||||
. ' (id INTEGER NOT NULL,'
|
||||
. ' PRIMARY KEY(id))');
|
||||
if ($res) {
|
||||
$res = $this->query('SET UNIQUE = 0 FOR ' . $seqname);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ modifyLimitQuery()
|
||||
|
||||
/**
|
||||
* Deletes a sequence
|
||||
*
|
||||
* @param string $seq_name name of the sequence to be deleted
|
||||
*
|
||||
* @return int DB_OK on success. A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_common::dropSequence(), DB_common::getSequenceName(),
|
||||
* DB_fbsql::nextID(), DB_fbsql::createSequence()
|
||||
*/
|
||||
public function dropSequence($seq_name)
|
||||
{
|
||||
return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name)
|
||||
. ' RESTRICT');
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ quoteBoolean()
|
||||
|
||||
/**
|
||||
* Adds LIMIT clauses to a query string according to current DBMS standards
|
||||
*
|
||||
* @param string $query the query to modify
|
||||
* @param int $from the row to start to fetching (0 = the first row)
|
||||
* @param int $count the numbers of rows to fetch
|
||||
* @param mixed $params array, string or numeric data to be used in
|
||||
* execution of the statement. Quantity of items
|
||||
* passed must match quantity of placeholders in
|
||||
* query: meaning 1 placeholder for non-array
|
||||
* parameters or 1 placeholder per array element.
|
||||
*
|
||||
* @return string the query string with LIMIT clauses added
|
||||
*
|
||||
* @access protected
|
||||
*/
|
||||
public function modifyLimitQuery($query, $from, $count, $params = array())
|
||||
{
|
||||
if (DB::isManip($query) || $this->_next_query_manip) {
|
||||
return preg_replace(
|
||||
'/^([\s(])*SELECT/i',
|
||||
"\\1SELECT TOP($count)",
|
||||
$query
|
||||
);
|
||||
} else {
|
||||
return preg_replace(
|
||||
'/([\s(])*SELECT/i',
|
||||
"\\1SELECT TOP($from, $count)",
|
||||
$query
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ quoteFloat()
|
||||
|
||||
/**
|
||||
* Formats a boolean value for use within a query in a locale-independent
|
||||
* manner.
|
||||
*
|
||||
* @param boolean the boolean value to be quoted.
|
||||
* @return string the quoted string.
|
||||
* @see DB_common::quoteSmart()
|
||||
* @since Method available since release 1.7.8.
|
||||
*/
|
||||
public function quoteBoolean($boolean)
|
||||
{
|
||||
return $boolean ? 'TRUE' : 'FALSE';
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ fbsqlRaiseError()
|
||||
|
||||
/**
|
||||
* Formats a float value for use within a query in a locale-independent
|
||||
* manner.
|
||||
*
|
||||
* @param float the float value to be quoted.
|
||||
* @return string the quoted string.
|
||||
* @see DB_common::quoteSmart()
|
||||
* @since Method available since release 1.7.8.
|
||||
*/
|
||||
public function quoteFloat($float)
|
||||
{
|
||||
return $this->escapeSimple(str_replace(',', '.', strval(floatval($float))));
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ errorNative()
|
||||
|
||||
/**
|
||||
* Gets the DBMS' native error code produced by the last query
|
||||
*
|
||||
* @return int the DBMS' error code
|
||||
*/
|
||||
public function errorNative()
|
||||
{
|
||||
return @fbsql_errno($this->connection);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ tableInfo()
|
||||
|
||||
/**
|
||||
* Returns information about a table or a result set
|
||||
*
|
||||
* @param object|string $result DB_result object from a query or a
|
||||
* string containing the name of a table.
|
||||
* While this also accepts a query result
|
||||
* resource identifier, this behavior is
|
||||
* deprecated.
|
||||
* @param int $mode a valid tableInfo mode
|
||||
*
|
||||
* @return array|object
|
||||
* A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_common::tableInfo()
|
||||
*/
|
||||
public function tableInfo($result, $mode = null)
|
||||
{
|
||||
if (is_string($result)) {
|
||||
/*
|
||||
* Probably received a table name.
|
||||
* Create a result resource identifier.
|
||||
*/
|
||||
$id = @fbsql_list_fields(
|
||||
$this->dsn['database'],
|
||||
$result,
|
||||
$this->connection
|
||||
);
|
||||
$got_string = true;
|
||||
} elseif (isset($result->result)) {
|
||||
/*
|
||||
* Probably received a result object.
|
||||
* Extract the result resource identifier.
|
||||
*/
|
||||
$id = $result->result;
|
||||
$got_string = false;
|
||||
} else {
|
||||
/*
|
||||
* Probably received a result resource identifier.
|
||||
* Copy it.
|
||||
* Deprecated. Here for compatibility only.
|
||||
*/
|
||||
$id = $result;
|
||||
$got_string = false;
|
||||
}
|
||||
|
||||
if (!is_resource($id)) {
|
||||
return $this->fbsqlRaiseError(DB_ERROR_NEED_MORE_DATA);
|
||||
}
|
||||
|
||||
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
|
||||
$case_func = 'strtolower';
|
||||
} else {
|
||||
$case_func = 'strval';
|
||||
}
|
||||
|
||||
$count = @fbsql_num_fields($id);
|
||||
$res = array();
|
||||
|
||||
if ($mode) {
|
||||
$res['num_fields'] = $count;
|
||||
}
|
||||
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
$res[$i] = array(
|
||||
'table' => $case_func(@fbsql_field_table($id, $i)),
|
||||
'name' => $case_func(@fbsql_field_name($id, $i)),
|
||||
'type' => @fbsql_field_type($id, $i),
|
||||
'len' => @fbsql_field_len($id, $i),
|
||||
'flags' => @fbsql_field_flags($id, $i),
|
||||
);
|
||||
if ($mode & DB_TABLEINFO_ORDER) {
|
||||
$res['order'][$res[$i]['name']] = $i;
|
||||
}
|
||||
if ($mode & DB_TABLEINFO_ORDERTABLE) {
|
||||
$res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
|
||||
}
|
||||
}
|
||||
|
||||
// free the result only if we were called on a table
|
||||
if ($got_string) {
|
||||
@fbsql_free_result($id);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ getSpecialQuery()
|
||||
|
||||
/**
|
||||
* Obtains the query string needed for listing a given type of objects
|
||||
*
|
||||
* @param string $type the kind of objects you want to retrieve
|
||||
*
|
||||
* @return string the SQL query string or null if the driver doesn't
|
||||
* support the object type requested
|
||||
*
|
||||
* @access protected
|
||||
* @see DB_common::getListOf()
|
||||
*/
|
||||
public function getSpecialQuery($type)
|
||||
{
|
||||
switch ($type) {
|
||||
case 'tables':
|
||||
return 'SELECT "table_name" FROM information_schema.tables'
|
||||
. ' t0, information_schema.schemata t1'
|
||||
. ' WHERE t0.schema_pk=t1.schema_pk AND'
|
||||
. ' "table_type" = \'BASE TABLE\''
|
||||
. ' AND "schema_name" = current_schema';
|
||||
case 'views':
|
||||
return 'SELECT "table_name" FROM information_schema.tables'
|
||||
. ' t0, information_schema.schemata t1'
|
||||
. ' WHERE t0.schema_pk=t1.schema_pk AND'
|
||||
. ' "table_type" = \'VIEW\''
|
||||
. ' AND "schema_name" = current_schema';
|
||||
case 'users':
|
||||
return 'SELECT "user_name" from information_schema.users';
|
||||
case 'functions':
|
||||
return 'SELECT "routine_name" FROM'
|
||||
. ' information_schema.psm_routines'
|
||||
. ' t0, information_schema.schemata t1'
|
||||
. ' WHERE t0.schema_pk=t1.schema_pk'
|
||||
. ' AND "routine_kind"=\'FUNCTION\''
|
||||
. ' AND "schema_name" = current_schema';
|
||||
case 'procedures':
|
||||
return 'SELECT "routine_name" FROM'
|
||||
. ' information_schema.psm_routines'
|
||||
. ' t0, information_schema.schemata t1'
|
||||
. ' WHERE t0.schema_pk=t1.schema_pk'
|
||||
. ' AND "routine_kind"=\'PROCEDURE\''
|
||||
. ' AND "schema_name" = current_schema';
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* tab-width: 4
|
||||
* c-basic-offset: 4
|
||||
* End:
|
||||
*/
|
1092
extlib/DB/ibase.php
1092
extlib/DB/ibase.php
File diff suppressed because it is too large
Load Diff
@ -1,686 +0,0 @@
|
||||
<?php
|
||||
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
||||
|
||||
/**
|
||||
* The PEAR DB driver for PHP's ifx extension
|
||||
* for interacting with Informix databases
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENSE: This source file is subject to version 3.0 of the PHP license
|
||||
* that is available through the world-wide-web at the following URI:
|
||||
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
|
||||
* the PHP License and are unable to obtain it through the web, please
|
||||
* send a note to license@php.net so we can mail you a copy immediately.
|
||||
*
|
||||
* @category Database
|
||||
* @package DB
|
||||
* @author Tomas V.V.Cox <cox@idecnet.com>
|
||||
* @author Daniel Convissor <danielc@php.net>
|
||||
* @copyright 1997-2007 The PHP Group
|
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0
|
||||
* @version CVS: $Id$
|
||||
* @link http://pear.php.net/package/DB
|
||||
*/
|
||||
|
||||
/**
|
||||
* Obtain the DB_common class so it can be extended from
|
||||
*/
|
||||
//require_once 'DB/common.php';
|
||||
require_once 'common.php';
|
||||
|
||||
/**
|
||||
* The methods PEAR DB uses to interact with PHP's ifx extension
|
||||
* for interacting with Informix databases
|
||||
*
|
||||
* These methods overload the ones declared in DB_common.
|
||||
*
|
||||
* More info on Informix errors can be found at:
|
||||
* http://www.informix.com/answers/english/ierrors.htm
|
||||
*
|
||||
* TODO:
|
||||
* - set needed env Informix vars on connect
|
||||
* - implement native prepare/execute
|
||||
*
|
||||
* @category Database
|
||||
* @package DB
|
||||
* @author Tomas V.V.Cox <cox@idecnet.com>
|
||||
* @author Daniel Convissor <danielc@php.net>
|
||||
* @copyright 1997-2007 The PHP Group
|
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0
|
||||
* @version Release: 1.9.2
|
||||
* @link http://pear.php.net/package/DB
|
||||
*/
|
||||
class DB_ifx extends DB_common
|
||||
{
|
||||
// {{{ properties
|
||||
|
||||
/**
|
||||
* The DB driver type (mysql, oci8, odbc, etc.)
|
||||
* @var string
|
||||
*/
|
||||
public $phptype = 'ifx';
|
||||
|
||||
/**
|
||||
* The database syntax variant to be used (db2, access, etc.), if any
|
||||
* @var string
|
||||
*/
|
||||
public $dbsyntax = 'ifx';
|
||||
|
||||
/**
|
||||
* The capabilities of this DB implementation
|
||||
*
|
||||
* The 'new_link' element contains the PHP version that first provided
|
||||
* new_link support for this DBMS. Contains false if it's unsupported.
|
||||
*
|
||||
* Meaning of the 'limit' element:
|
||||
* + 'emulate' = emulate with fetch row by number
|
||||
* + 'alter' = alter the query
|
||||
* + false = skip rows
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $features = array(
|
||||
'limit' => 'emulate',
|
||||
'new_link' => false,
|
||||
'numrows' => 'emulate',
|
||||
'pconnect' => true,
|
||||
'prepare' => false,
|
||||
'ssl' => false,
|
||||
'transactions' => true,
|
||||
);
|
||||
|
||||
/**
|
||||
* A mapping of native error codes to DB error codes
|
||||
* @var array
|
||||
*/
|
||||
public $errorcode_map = array(
|
||||
'-201' => DB_ERROR_SYNTAX,
|
||||
'-206' => DB_ERROR_NOSUCHTABLE,
|
||||
'-217' => DB_ERROR_NOSUCHFIELD,
|
||||
'-236' => DB_ERROR_VALUE_COUNT_ON_ROW,
|
||||
'-239' => DB_ERROR_CONSTRAINT,
|
||||
'-253' => DB_ERROR_SYNTAX,
|
||||
'-268' => DB_ERROR_CONSTRAINT,
|
||||
'-292' => DB_ERROR_CONSTRAINT_NOT_NULL,
|
||||
'-310' => DB_ERROR_ALREADY_EXISTS,
|
||||
'-316' => DB_ERROR_ALREADY_EXISTS,
|
||||
'-319' => DB_ERROR_NOT_FOUND,
|
||||
'-329' => DB_ERROR_NODBSELECTED,
|
||||
'-346' => DB_ERROR_CONSTRAINT,
|
||||
'-386' => DB_ERROR_CONSTRAINT_NOT_NULL,
|
||||
'-391' => DB_ERROR_CONSTRAINT_NOT_NULL,
|
||||
'-554' => DB_ERROR_SYNTAX,
|
||||
'-691' => DB_ERROR_CONSTRAINT,
|
||||
'-692' => DB_ERROR_CONSTRAINT,
|
||||
'-703' => DB_ERROR_CONSTRAINT_NOT_NULL,
|
||||
'-1202' => DB_ERROR_DIVZERO,
|
||||
'-1204' => DB_ERROR_INVALID_DATE,
|
||||
'-1205' => DB_ERROR_INVALID_DATE,
|
||||
'-1206' => DB_ERROR_INVALID_DATE,
|
||||
'-1209' => DB_ERROR_INVALID_DATE,
|
||||
'-1210' => DB_ERROR_INVALID_DATE,
|
||||
'-1212' => DB_ERROR_INVALID_DATE,
|
||||
'-1213' => DB_ERROR_INVALID_NUMBER,
|
||||
);
|
||||
|
||||
/**
|
||||
* The raw database connection created by PHP
|
||||
* @var resource
|
||||
*/
|
||||
public $connection;
|
||||
|
||||
/**
|
||||
* The DSN information for connecting to a database
|
||||
* @var array
|
||||
*/
|
||||
public $dsn = array();
|
||||
|
||||
|
||||
/**
|
||||
* Should data manipulation queries be committed automatically?
|
||||
* @var bool
|
||||
* @access private
|
||||
*/
|
||||
public $autocommit = true;
|
||||
|
||||
/**
|
||||
* The quantity of transactions begun
|
||||
*
|
||||
* {@internal While this is private, it can't actually be designated
|
||||
* private in PHP 5 because it is directly accessed in the test suite.}}
|
||||
*
|
||||
* @var integer
|
||||
* @access private
|
||||
*/
|
||||
public $transaction_opcount = 0;
|
||||
|
||||
/**
|
||||
* The number of rows affected by a data manipulation query
|
||||
* @var integer
|
||||
* @access private
|
||||
*/
|
||||
public $affected = 0;
|
||||
|
||||
|
||||
// }}}
|
||||
// {{{ constructor
|
||||
|
||||
/**
|
||||
* This constructor calls <kbd>parent::__construct()</kbd>
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ connect()
|
||||
|
||||
/**
|
||||
* Connect to the database server, log in and open the database
|
||||
*
|
||||
* Don't call this method directly. Use DB::connect() instead.
|
||||
*
|
||||
* @param array $dsn the data source name
|
||||
* @param bool $persistent should the connection be persistent?
|
||||
*
|
||||
* @return int|object
|
||||
*/
|
||||
public function connect($dsn, $persistent = false)
|
||||
{
|
||||
if (!PEAR::loadExtension('informix') &&
|
||||
!PEAR::loadExtension('Informix')) {
|
||||
return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
|
||||
}
|
||||
|
||||
$this->dsn = $dsn;
|
||||
if ($dsn['dbsyntax']) {
|
||||
$this->dbsyntax = $dsn['dbsyntax'];
|
||||
}
|
||||
|
||||
$dbhost = $dsn['hostspec'] ? '@' . $dsn['hostspec'] : '';
|
||||
$dbname = $dsn['database'] ? $dsn['database'] . $dbhost : '';
|
||||
$user = $dsn['username'] ? $dsn['username'] : '';
|
||||
$pw = $dsn['password'] ? $dsn['password'] : '';
|
||||
|
||||
$connect_function = $persistent ? 'ifx_pconnect' : 'ifx_connect';
|
||||
|
||||
$this->connection = @$connect_function($dbname, $user, $pw);
|
||||
if (!is_resource($this->connection)) {
|
||||
return $this->ifxRaiseError(DB_ERROR_CONNECT_FAILED);
|
||||
}
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ disconnect()
|
||||
|
||||
/**
|
||||
* Produces a DB_Error object regarding the current problem
|
||||
*
|
||||
* @param int $errno if the error is being manually raised pass a
|
||||
* DB_ERROR* constant here. If this isn't passed
|
||||
* the error information gathered from the DBMS.
|
||||
*
|
||||
* @return object the DB_Error object
|
||||
*
|
||||
* @see DB_common::raiseError(),
|
||||
* DB_ifx::errorNative(), DB_ifx::errorCode()
|
||||
*/
|
||||
public function ifxRaiseError($errno = null)
|
||||
{
|
||||
if ($errno === null) {
|
||||
$errno = $this->errorCode(ifx_error());
|
||||
}
|
||||
return $this->raiseError(
|
||||
$errno,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
$this->errorNative()
|
||||
);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ simpleQuery()
|
||||
|
||||
/**
|
||||
* Maps native error codes to DB's portable ones.
|
||||
*
|
||||
* Requires that the DB implementation's constructor fills
|
||||
* in the <var>$errorcode_map</var> property.
|
||||
*
|
||||
* @param string $nativecode error code returned by the database
|
||||
* @return int a portable DB error code, or DB_ERROR if this DB
|
||||
* implementation has no mapping for the given error code.
|
||||
*/
|
||||
public function errorCode($nativecode)
|
||||
{
|
||||
if (preg_match('/SQLCODE=(.*)]/', $nativecode, $match)) {
|
||||
$code = $match[1];
|
||||
if (isset($this->errorcode_map[$code])) {
|
||||
return $this->errorcode_map[$code];
|
||||
}
|
||||
}
|
||||
return DB_ERROR;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ nextResult()
|
||||
|
||||
/**
|
||||
* Gets the DBMS' native error code and message produced by the last query
|
||||
*
|
||||
* @return string the DBMS' error code and message
|
||||
*/
|
||||
public function errorNative()
|
||||
{
|
||||
return @ifx_error() . ' ' . @ifx_errormsg();
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ affectedRows()
|
||||
|
||||
/**
|
||||
* Disconnects from the database server
|
||||
*
|
||||
* @return bool TRUE on success, FALSE on failure
|
||||
*/
|
||||
public function disconnect()
|
||||
{
|
||||
$ret = @ifx_close($this->connection);
|
||||
$this->connection = null;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ fetchInto()
|
||||
|
||||
/**
|
||||
* Sends a query to the database server
|
||||
*
|
||||
* @param string the SQL query string
|
||||
*
|
||||
* @return mixed + a PHP result resrouce for successful SELECT queries
|
||||
* + the DB_OK constant for other successful queries
|
||||
* + a DB_Error object on failure
|
||||
*/
|
||||
public function simpleQuery($query)
|
||||
{
|
||||
$ismanip = $this->_checkManip($query);
|
||||
$this->last_query = $query;
|
||||
$this->affected = null;
|
||||
if (preg_match('/(SELECT|EXECUTE)/i', $query)) { //TESTME: Use !DB::isManip()?
|
||||
// the scroll is needed for fetching absolute row numbers
|
||||
// in a select query result
|
||||
$result = @ifx_query($query, $this->connection, IFX_SCROLL);
|
||||
} else {
|
||||
if (!$this->autocommit && $ismanip) {
|
||||
if ($this->transaction_opcount == 0) {
|
||||
$result = @ifx_query('BEGIN WORK', $this->connection);
|
||||
if (!$result) {
|
||||
return $this->ifxRaiseError();
|
||||
}
|
||||
}
|
||||
$this->transaction_opcount++;
|
||||
}
|
||||
$result = @ifx_query($query, $this->connection);
|
||||
}
|
||||
if (!$result) {
|
||||
return $this->ifxRaiseError();
|
||||
}
|
||||
$this->affected = @ifx_affected_rows($result);
|
||||
// Determine which queries should return data, and which
|
||||
// should return an error code only.
|
||||
if (preg_match('/(SELECT|EXECUTE)/i', $query)) {
|
||||
return $result;
|
||||
}
|
||||
// XXX Testme: free results inside a transaction
|
||||
// may cause to stop it and commit the work?
|
||||
|
||||
// Result has to be freed even with a insert or update
|
||||
@ifx_free_result($result);
|
||||
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ numCols()
|
||||
|
||||
/**
|
||||
* Move the internal ifx result pointer to the next available result
|
||||
*
|
||||
* @param a valid fbsql result resource
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return true if a result is available otherwise return false
|
||||
*/
|
||||
public function nextResult($result)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ freeResult()
|
||||
|
||||
/**
|
||||
* Determines the number of rows affected by a data maniuplation query
|
||||
*
|
||||
* 0 is returned for queries that don't manipulate data.
|
||||
*
|
||||
* @return int the number of rows. A DB_Error object on failure.
|
||||
*/
|
||||
public function affectedRows()
|
||||
{
|
||||
if ($this->_last_query_manip) {
|
||||
return $this->affected;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ autoCommit()
|
||||
|
||||
/**
|
||||
* Places a row from the result set into the given array
|
||||
*
|
||||
* Formating of the array and the data therein are configurable.
|
||||
* See DB_result::fetchInto() for more information.
|
||||
*
|
||||
* This method is not meant to be called directly. Use
|
||||
* DB_result::fetchInto() instead. It can't be declared "protected"
|
||||
* because DB_result is a separate object.
|
||||
*
|
||||
* @param resource $result the query result resource
|
||||
* @param array $arr the referenced array to put the data in
|
||||
* @param int $fetchmode how the resulting array should be indexed
|
||||
* @param int $rownum the row number to fetch (0 = first row)
|
||||
*
|
||||
* @return mixed DB_OK on success, NULL when the end of a result set is
|
||||
* reached or on failure
|
||||
*
|
||||
* @see DB_result::fetchInto()
|
||||
*/
|
||||
public function fetchInto($result, &$arr, $fetchmode, $rownum = null)
|
||||
{
|
||||
if (($rownum !== null) && ($rownum < 0)) {
|
||||
return null;
|
||||
}
|
||||
if ($rownum === null) {
|
||||
/*
|
||||
* Even though fetch_row() should return the next row if
|
||||
* $rownum is null, it doesn't in all cases. Bug 598.
|
||||
*/
|
||||
$rownum = 'NEXT';
|
||||
} else {
|
||||
// Index starts at row 1, unlike most DBMS's starting at 0.
|
||||
$rownum++;
|
||||
}
|
||||
if (!$arr = @ifx_fetch_row($result, $rownum)) {
|
||||
return null;
|
||||
}
|
||||
if ($fetchmode !== DB_FETCHMODE_ASSOC) {
|
||||
$i = 0;
|
||||
$order = array();
|
||||
foreach ($arr as $val) {
|
||||
$order[$i++] = $val;
|
||||
}
|
||||
$arr = $order;
|
||||
} elseif ($fetchmode == DB_FETCHMODE_ASSOC &&
|
||||
$this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
|
||||
$arr = array_change_key_case($arr, CASE_LOWER);
|
||||
}
|
||||
if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
|
||||
$this->_rtrimArrayValues($arr);
|
||||
}
|
||||
if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
|
||||
$this->_convertNullArrayValuesToEmpty($arr);
|
||||
}
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ commit()
|
||||
|
||||
/**
|
||||
* Gets the number of columns in a result set
|
||||
*
|
||||
* This method is not meant to be called directly. Use
|
||||
* DB_result::numCols() instead. It can't be declared "protected"
|
||||
* because DB_result is a separate object.
|
||||
*
|
||||
* @param resource $result PHP's query result resource
|
||||
*
|
||||
* @return int|object
|
||||
*
|
||||
* @see DB_result::numCols()
|
||||
*/
|
||||
public function numCols($result)
|
||||
{
|
||||
if (!$cols = @ifx_num_fields($result)) {
|
||||
return $this->ifxRaiseError();
|
||||
}
|
||||
return $cols;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ rollback()
|
||||
|
||||
/**
|
||||
* Deletes the result set and frees the memory occupied by the result set
|
||||
*
|
||||
* This method is not meant to be called directly. Use
|
||||
* DB_result::free() instead. It can't be declared "protected"
|
||||
* because DB_result is a separate object.
|
||||
*
|
||||
* @param resource $result PHP's query result resource
|
||||
*
|
||||
* @return bool TRUE on success, FALSE if $result is invalid
|
||||
*
|
||||
* @see DB_result::free()
|
||||
*/
|
||||
public function freeResult($result)
|
||||
{
|
||||
return is_resource($result) ? ifx_free_result($result) : false;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ ifxRaiseError()
|
||||
|
||||
/**
|
||||
* Enables or disables automatic commits
|
||||
*
|
||||
* @param bool $onoff true turns it on, false turns it off
|
||||
*
|
||||
* @return int DB_OK on success. A DB_Error object if the driver
|
||||
* doesn't support auto-committing transactions.
|
||||
*/
|
||||
public function autoCommit($onoff = true)
|
||||
{
|
||||
// XXX if $this->transaction_opcount > 0, we should probably
|
||||
// issue a warning here.
|
||||
$this->autocommit = $onoff ? true : false;
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ errorNative()
|
||||
|
||||
/**
|
||||
* Commits the current transaction
|
||||
*
|
||||
* @return int|object
|
||||
*/
|
||||
public function commit()
|
||||
{
|
||||
if ($this->transaction_opcount > 0) {
|
||||
$result = @ifx_query('COMMIT WORK', $this->connection);
|
||||
$this->transaction_opcount = 0;
|
||||
if (!$result) {
|
||||
return $this->ifxRaiseError();
|
||||
}
|
||||
}
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ errorCode()
|
||||
|
||||
/**
|
||||
* Reverts the current transaction
|
||||
*
|
||||
* @return int|object
|
||||
*/
|
||||
public function rollback()
|
||||
{
|
||||
if ($this->transaction_opcount > 0) {
|
||||
$result = @ifx_query('ROLLBACK WORK', $this->connection);
|
||||
$this->transaction_opcount = 0;
|
||||
if (!$result) {
|
||||
return $this->ifxRaiseError();
|
||||
}
|
||||
}
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ tableInfo()
|
||||
|
||||
/**
|
||||
* Returns information about a table or a result set
|
||||
*
|
||||
* NOTE: only supports 'table' if <var>$result</var> is a table name.
|
||||
*
|
||||
* If analyzing a query result and the result has duplicate field names,
|
||||
* an error will be raised saying
|
||||
* <samp>can't distinguish duplicate field names</samp>.
|
||||
*
|
||||
* @param object|string $result DB_result object from a query or a
|
||||
* string containing the name of a table.
|
||||
* While this also accepts a query result
|
||||
* resource identifier, this behavior is
|
||||
* deprecated.
|
||||
* @param int $mode a valid tableInfo mode
|
||||
*
|
||||
* @return array|object
|
||||
* A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_common::tableInfo()
|
||||
* @since Method available since Release 1.6.0
|
||||
*/
|
||||
public function tableInfo($result, $mode = null)
|
||||
{
|
||||
if (is_string($result)) {
|
||||
/*
|
||||
* Probably received a table name.
|
||||
* Create a result resource identifier.
|
||||
*/
|
||||
$id = @ifx_query(
|
||||
"SELECT * FROM $result WHERE 1=0",
|
||||
$this->connection
|
||||
);
|
||||
$got_string = true;
|
||||
} elseif (isset($result->result)) {
|
||||
/*
|
||||
* Probably received a result object.
|
||||
* Extract the result resource identifier.
|
||||
*/
|
||||
$id = $result->result;
|
||||
$got_string = false;
|
||||
} else {
|
||||
/*
|
||||
* Probably received a result resource identifier.
|
||||
* Copy it.
|
||||
*/
|
||||
$id = $result;
|
||||
$got_string = false;
|
||||
}
|
||||
|
||||
if (!is_resource($id)) {
|
||||
return $this->ifxRaiseError(DB_ERROR_NEED_MORE_DATA);
|
||||
}
|
||||
|
||||
$flds = @ifx_fieldproperties($id);
|
||||
$count = @ifx_num_fields($id);
|
||||
|
||||
if (count($flds) != $count) {
|
||||
return $this->raiseError("can't distinguish duplicate field names");
|
||||
}
|
||||
|
||||
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
|
||||
$case_func = 'strtolower';
|
||||
} else {
|
||||
$case_func = 'strval';
|
||||
}
|
||||
|
||||
$i = 0;
|
||||
$res = array();
|
||||
|
||||
if ($mode) {
|
||||
$res['num_fields'] = $count;
|
||||
}
|
||||
|
||||
foreach ($flds as $key => $value) {
|
||||
$props = explode(';', $value);
|
||||
$res[$i] = array(
|
||||
'table' => $got_string ? $case_func($result) : '',
|
||||
'name' => $case_func($key),
|
||||
'type' => $props[0],
|
||||
'len' => $props[1],
|
||||
'flags' => $props[4] == 'N' ? 'not_null' : '',
|
||||
);
|
||||
if ($mode & DB_TABLEINFO_ORDER) {
|
||||
$res['order'][$res[$i]['name']] = $i;
|
||||
}
|
||||
if ($mode & DB_TABLEINFO_ORDERTABLE) {
|
||||
$res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
|
||||
// free the result only if we were called on a table
|
||||
if ($got_string) {
|
||||
@ifx_free_result($id);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ getSpecialQuery()
|
||||
|
||||
/**
|
||||
* Obtains the query string needed for listing a given type of objects
|
||||
*
|
||||
* @param string $type the kind of objects you want to retrieve
|
||||
*
|
||||
* @return string the SQL query string or null if the driver doesn't
|
||||
* support the object type requested
|
||||
*
|
||||
* @access protected
|
||||
* @see DB_common::getListOf()
|
||||
*/
|
||||
public function getSpecialQuery($type)
|
||||
{
|
||||
switch ($type) {
|
||||
case 'tables':
|
||||
return 'SELECT tabname FROM systables WHERE tabid >= 100';
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* tab-width: 4
|
||||
* c-basic-offset: 4
|
||||
* End:
|
||||
*/
|
@ -1,845 +0,0 @@
|
||||
<?php
|
||||
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
||||
|
||||
/**
|
||||
* The PEAR DB driver for PHP's msql extension
|
||||
* for interacting with Mini SQL databases
|
||||
*
|
||||
* PHP's mSQL extension did weird things with NULL values prior to PHP
|
||||
* 4.3.11 and 5.0.4. Make sure your version of PHP meets or exceeds
|
||||
* those versions.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENSE: This source file is subject to version 3.0 of the PHP license
|
||||
* that is available through the world-wide-web at the following URI:
|
||||
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
|
||||
* the PHP License and are unable to obtain it through the web, please
|
||||
* send a note to license@php.net so we can mail you a copy immediately.
|
||||
*
|
||||
* @category Database
|
||||
* @package DB
|
||||
* @author Daniel Convissor <danielc@php.net>
|
||||
* @copyright 1997-2007 The PHP Group
|
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0
|
||||
* @version CVS: $Id$
|
||||
* @link http://pear.php.net/package/DB
|
||||
*/
|
||||
|
||||
/**
|
||||
* Obtain the DB_common class so it can be extended from
|
||||
*/
|
||||
//require_once 'DB/common.php';
|
||||
require_once 'common.php';
|
||||
|
||||
/**
|
||||
* The methods PEAR DB uses to interact with PHP's msql extension
|
||||
* for interacting with Mini SQL databases
|
||||
*
|
||||
* These methods overload the ones declared in DB_common.
|
||||
*
|
||||
* PHP's mSQL extension did weird things with NULL values prior to PHP
|
||||
* 4.3.11 and 5.0.4. Make sure your version of PHP meets or exceeds
|
||||
* those versions.
|
||||
*
|
||||
* @category Database
|
||||
* @package DB
|
||||
* @author Daniel Convissor <danielc@php.net>
|
||||
* @copyright 1997-2007 The PHP Group
|
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0
|
||||
* @version Release: 1.9.2
|
||||
* @link http://pear.php.net/package/DB
|
||||
* @since Class not functional until Release 1.7.0
|
||||
*/
|
||||
class DB_msql extends DB_common
|
||||
{
|
||||
// {{{ properties
|
||||
|
||||
/**
|
||||
* The DB driver type (mysql, oci8, odbc, etc.)
|
||||
* @var string
|
||||
*/
|
||||
public $phptype = 'msql';
|
||||
|
||||
/**
|
||||
* The database syntax variant to be used (db2, access, etc.), if any
|
||||
* @var string
|
||||
*/
|
||||
public $dbsyntax = 'msql';
|
||||
|
||||
/**
|
||||
* The capabilities of this DB implementation
|
||||
*
|
||||
* The 'new_link' element contains the PHP version that first provided
|
||||
* new_link support for this DBMS. Contains false if it's unsupported.
|
||||
*
|
||||
* Meaning of the 'limit' element:
|
||||
* + 'emulate' = emulate with fetch row by number
|
||||
* + 'alter' = alter the query
|
||||
* + false = skip rows
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $features = array(
|
||||
'limit' => 'emulate',
|
||||
'new_link' => false,
|
||||
'numrows' => true,
|
||||
'pconnect' => true,
|
||||
'prepare' => false,
|
||||
'ssl' => false,
|
||||
'transactions' => false,
|
||||
);
|
||||
|
||||
/**
|
||||
* A mapping of native error codes to DB error codes
|
||||
* @var array
|
||||
*/
|
||||
public $errorcode_map = array();
|
||||
|
||||
/**
|
||||
* The raw database connection created by PHP
|
||||
* @var resource
|
||||
*/
|
||||
public $connection;
|
||||
|
||||
/**
|
||||
* The DSN information for connecting to a database
|
||||
* @var array
|
||||
*/
|
||||
public $dsn = array();
|
||||
|
||||
|
||||
/**
|
||||
* The query result resource created by PHP
|
||||
*
|
||||
* Used to make affectedRows() work. Only contains the result for
|
||||
* data manipulation queries. Contains false for other queries.
|
||||
*
|
||||
* @var resource
|
||||
* @access private
|
||||
*/
|
||||
public $_result;
|
||||
|
||||
|
||||
// }}}
|
||||
// {{{ constructor
|
||||
|
||||
/**
|
||||
* This constructor calls <kbd>parent::__construct()</kbd>
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ connect()
|
||||
|
||||
/**
|
||||
* Connect to the database server, log in and open the database
|
||||
*
|
||||
* Don't call this method directly. Use DB::connect() instead.
|
||||
*
|
||||
* Example of how to connect:
|
||||
* <code>
|
||||
* require_once 'DB.php';
|
||||
*
|
||||
* // $dsn = 'msql://hostname/dbname'; // use a TCP connection
|
||||
* $dsn = 'msql:///dbname'; // use a socket
|
||||
* $options = array(
|
||||
* 'portability' => DB_PORTABILITY_ALL,
|
||||
* );
|
||||
*
|
||||
* $db = DB::connect($dsn, $options);
|
||||
* if ((new PEAR)->isError($db)) {
|
||||
* die($db->getMessage());
|
||||
* }
|
||||
* </code>
|
||||
*
|
||||
* @param array $dsn the data source name
|
||||
* @param bool $persistent should the connection be persistent?
|
||||
*
|
||||
* @return int|object
|
||||
*/
|
||||
public function connect($dsn, $persistent = false)
|
||||
{
|
||||
if (!PEAR::loadExtension('msql')) {
|
||||
return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
|
||||
}
|
||||
|
||||
$this->dsn = $dsn;
|
||||
if ($dsn['dbsyntax']) {
|
||||
$this->dbsyntax = $dsn['dbsyntax'];
|
||||
}
|
||||
|
||||
$params = array();
|
||||
if ($dsn['hostspec']) {
|
||||
$params[] = $dsn['port']
|
||||
? $dsn['hostspec'] . ',' . $dsn['port']
|
||||
: $dsn['hostspec'];
|
||||
}
|
||||
|
||||
$connect_function = $persistent ? 'msql_pconnect' : 'msql_connect';
|
||||
|
||||
$ini = ini_get('track_errors');
|
||||
$php_errormsg = '';
|
||||
if ($ini) {
|
||||
$this->connection = @call_user_func_array(
|
||||
$connect_function,
|
||||
$params
|
||||
);
|
||||
} else {
|
||||
@ini_set('track_errors', 1);
|
||||
$this->connection = @call_user_func_array(
|
||||
$connect_function,
|
||||
$params
|
||||
);
|
||||
@ini_set('track_errors', $ini);
|
||||
}
|
||||
|
||||
if (!$this->connection) {
|
||||
if (($err = @msql_error()) != '') {
|
||||
return $this->raiseError(
|
||||
DB_ERROR_CONNECT_FAILED,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
$err
|
||||
);
|
||||
} else {
|
||||
return $this->raiseError(
|
||||
DB_ERROR_CONNECT_FAILED,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
$php_errormsg
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (!@msql_select_db($dsn['database'], $this->connection)) {
|
||||
return $this->msqlRaiseError();
|
||||
}
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ disconnect()
|
||||
|
||||
/**
|
||||
* Produces a DB_Error object regarding the current problem
|
||||
*
|
||||
* @param int $errno if the error is being manually raised pass a
|
||||
* DB_ERROR* constant here. If this isn't passed
|
||||
* the error information gathered from the DBMS.
|
||||
*
|
||||
* @return object the DB_Error object
|
||||
*
|
||||
* @see DB_common::raiseError(),
|
||||
* DB_msql::errorNative(), DB_msql::errorCode()
|
||||
*/
|
||||
public function msqlRaiseError($errno = null)
|
||||
{
|
||||
$native = $this->errorNative();
|
||||
if ($errno === null) {
|
||||
$errno = $this->errorCode($native);
|
||||
}
|
||||
return $this->raiseError($errno, null, null, null, $native);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ simpleQuery()
|
||||
|
||||
/**
|
||||
* Gets the DBMS' native error message produced by the last query
|
||||
*
|
||||
* @return string the DBMS' error message
|
||||
*/
|
||||
public function errorNative()
|
||||
{
|
||||
return @msql_error();
|
||||
}
|
||||
|
||||
|
||||
// }}}
|
||||
// {{{ nextResult()
|
||||
|
||||
/**
|
||||
* Determines PEAR::DB error code from the database's text error message
|
||||
*
|
||||
* @param string $errormsg the error message returned from the database
|
||||
*
|
||||
* @return integer the error number from a DB_ERROR* constant
|
||||
*/
|
||||
public function errorCode($errormsg)
|
||||
{
|
||||
static $error_regexps;
|
||||
|
||||
// PHP 5.2+ prepends the function name to $php_errormsg, so we need
|
||||
// this hack to work around it, per bug #9599.
|
||||
$errormsg = preg_replace('/^msql[a-z_]+\(\): /', '', $errormsg);
|
||||
|
||||
if (!isset($error_regexps)) {
|
||||
$error_regexps = array(
|
||||
'/^Access to database denied/i'
|
||||
=> DB_ERROR_ACCESS_VIOLATION,
|
||||
'/^Bad index name/i'
|
||||
=> DB_ERROR_ALREADY_EXISTS,
|
||||
'/^Bad order field/i'
|
||||
=> DB_ERROR_SYNTAX,
|
||||
'/^Bad type for comparison/i'
|
||||
=> DB_ERROR_SYNTAX,
|
||||
'/^Can\'t perform LIKE on/i'
|
||||
=> DB_ERROR_SYNTAX,
|
||||
'/^Can\'t use TEXT fields in LIKE comparison/i'
|
||||
=> DB_ERROR_SYNTAX,
|
||||
'/^Couldn\'t create temporary table/i'
|
||||
=> DB_ERROR_CANNOT_CREATE,
|
||||
'/^Error creating table file/i'
|
||||
=> DB_ERROR_CANNOT_CREATE,
|
||||
'/^Field .* cannot be null$/i'
|
||||
=> DB_ERROR_CONSTRAINT_NOT_NULL,
|
||||
'/^Index (field|condition) .* cannot be null$/i'
|
||||
=> DB_ERROR_SYNTAX,
|
||||
'/^Invalid date format/i'
|
||||
=> DB_ERROR_INVALID_DATE,
|
||||
'/^Invalid time format/i'
|
||||
=> DB_ERROR_INVALID,
|
||||
'/^Literal value for .* is wrong type$/i'
|
||||
=> DB_ERROR_INVALID_NUMBER,
|
||||
'/^No Database Selected/i'
|
||||
=> DB_ERROR_NODBSELECTED,
|
||||
'/^No value specified for field/i'
|
||||
=> DB_ERROR_VALUE_COUNT_ON_ROW,
|
||||
'/^Non unique value for unique index/i'
|
||||
=> DB_ERROR_CONSTRAINT,
|
||||
'/^Out of memory for temporary table/i'
|
||||
=> DB_ERROR_CANNOT_CREATE,
|
||||
'/^Permission denied/i'
|
||||
=> DB_ERROR_ACCESS_VIOLATION,
|
||||
'/^Reference to un-selected table/i'
|
||||
=> DB_ERROR_SYNTAX,
|
||||
'/^syntax error/i'
|
||||
=> DB_ERROR_SYNTAX,
|
||||
'/^Table .* exists$/i'
|
||||
=> DB_ERROR_ALREADY_EXISTS,
|
||||
'/^Unknown database/i'
|
||||
=> DB_ERROR_NOSUCHDB,
|
||||
'/^Unknown field/i'
|
||||
=> DB_ERROR_NOSUCHFIELD,
|
||||
'/^Unknown (index|system variable)/i'
|
||||
=> DB_ERROR_NOT_FOUND,
|
||||
'/^Unknown table/i'
|
||||
=> DB_ERROR_NOSUCHTABLE,
|
||||
'/^Unqualified field/i'
|
||||
=> DB_ERROR_SYNTAX,
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($error_regexps as $regexp => $code) {
|
||||
if (preg_match($regexp, $errormsg)) {
|
||||
return $code;
|
||||
}
|
||||
}
|
||||
return DB_ERROR;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ fetchInto()
|
||||
|
||||
/**
|
||||
* Disconnects from the database server
|
||||
*
|
||||
* @return bool TRUE on success, FALSE on failure
|
||||
*/
|
||||
public function disconnect()
|
||||
{
|
||||
$ret = @msql_close($this->connection);
|
||||
$this->connection = null;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ freeResult()
|
||||
|
||||
/**
|
||||
* Sends a query to the database server
|
||||
*
|
||||
* @param string the SQL query string
|
||||
*
|
||||
* @return mixed + a PHP result resrouce for successful SELECT queries
|
||||
* + the DB_OK constant for other successful queries
|
||||
* + a DB_Error object on failure
|
||||
*/
|
||||
public function simpleQuery($query)
|
||||
{
|
||||
$this->last_query = $query;
|
||||
$query = $this->modifyQuery($query);
|
||||
$result = @msql_query($query, $this->connection);
|
||||
if (!$result) {
|
||||
return $this->msqlRaiseError();
|
||||
}
|
||||
// Determine which queries that should return data, and which
|
||||
// should return an error code only.
|
||||
if ($this->_checkManip($query)) {
|
||||
$this->_result = $result;
|
||||
return DB_OK;
|
||||
} else {
|
||||
$this->_result = false;
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ numCols()
|
||||
|
||||
/**
|
||||
* Move the internal msql result pointer to the next available result
|
||||
*
|
||||
* @param a valid fbsql result resource
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return true if a result is available otherwise return false
|
||||
*/
|
||||
public function nextResult($result)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ numRows()
|
||||
|
||||
/**
|
||||
* Places a row from the result set into the given array
|
||||
*
|
||||
* Formating of the array and the data therein are configurable.
|
||||
* See DB_result::fetchInto() for more information.
|
||||
*
|
||||
* This method is not meant to be called directly. Use
|
||||
* DB_result::fetchInto() instead. It can't be declared "protected"
|
||||
* because DB_result is a separate object.
|
||||
*
|
||||
* PHP's mSQL extension did weird things with NULL values prior to PHP
|
||||
* 4.3.11 and 5.0.4. Make sure your version of PHP meets or exceeds
|
||||
* those versions.
|
||||
*
|
||||
* @param resource $result the query result resource
|
||||
* @param array $arr the referenced array to put the data in
|
||||
* @param int $fetchmode how the resulting array should be indexed
|
||||
* @param int $rownum the row number to fetch (0 = first row)
|
||||
*
|
||||
* @return mixed DB_OK on success, NULL when the end of a result set is
|
||||
* reached or on failure
|
||||
*
|
||||
* @see DB_result::fetchInto()
|
||||
*/
|
||||
public function fetchInto($result, &$arr, $fetchmode, $rownum = null)
|
||||
{
|
||||
if ($rownum !== null) {
|
||||
if (!@msql_data_seek($result, $rownum)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if ($fetchmode & DB_FETCHMODE_ASSOC) {
|
||||
$arr = @msql_fetch_array($result, MSQL_ASSOC);
|
||||
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) {
|
||||
$arr = array_change_key_case($arr, CASE_LOWER);
|
||||
}
|
||||
} else {
|
||||
$arr = @msql_fetch_row($result);
|
||||
}
|
||||
if (!$arr) {
|
||||
return null;
|
||||
}
|
||||
if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
|
||||
$this->_rtrimArrayValues($arr);
|
||||
}
|
||||
if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
|
||||
$this->_convertNullArrayValuesToEmpty($arr);
|
||||
}
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ affected()
|
||||
|
||||
/**
|
||||
* Deletes the result set and frees the memory occupied by the result set
|
||||
*
|
||||
* This method is not meant to be called directly. Use
|
||||
* DB_result::free() instead. It can't be declared "protected"
|
||||
* because DB_result is a separate object.
|
||||
*
|
||||
* @param resource $result PHP's query result resource
|
||||
*
|
||||
* @return bool TRUE on success, FALSE if $result is invalid
|
||||
*
|
||||
* @see DB_result::free()
|
||||
*/
|
||||
public function freeResult($result)
|
||||
{
|
||||
return is_resource($result) ? msql_free_result($result) : false;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ nextId()
|
||||
|
||||
/**
|
||||
* Gets the number of columns in a result set
|
||||
*
|
||||
* This method is not meant to be called directly. Use
|
||||
* DB_result::numCols() instead. It can't be declared "protected"
|
||||
* because DB_result is a separate object.
|
||||
*
|
||||
* @param resource $result PHP's query result resource
|
||||
*
|
||||
* @return int|object
|
||||
*
|
||||
* @see DB_result::numCols()
|
||||
*/
|
||||
public function numCols($result)
|
||||
{
|
||||
$cols = @msql_num_fields($result);
|
||||
if (!$cols) {
|
||||
return $this->msqlRaiseError();
|
||||
}
|
||||
return $cols;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ createSequence()
|
||||
|
||||
/**
|
||||
* Gets the number of rows in a result set
|
||||
*
|
||||
* This method is not meant to be called directly. Use
|
||||
* DB_result::numRows() instead. It can't be declared "protected"
|
||||
* because DB_result is a separate object.
|
||||
*
|
||||
* @param resource $result PHP's query result resource
|
||||
*
|
||||
* @return int|object
|
||||
*
|
||||
* @see DB_result::numRows()
|
||||
*/
|
||||
public function numRows($result)
|
||||
{
|
||||
$rows = @msql_num_rows($result);
|
||||
if ($rows === false) {
|
||||
return $this->msqlRaiseError();
|
||||
}
|
||||
return $rows;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ dropSequence()
|
||||
|
||||
/**
|
||||
* Determines the number of rows affected by a data maniuplation query
|
||||
*
|
||||
* 0 is returned for queries that don't manipulate data.
|
||||
*
|
||||
* @return int the number of rows. A DB_Error object on failure.
|
||||
*/
|
||||
public function affectedRows()
|
||||
{
|
||||
if (!$this->_result) {
|
||||
return 0;
|
||||
}
|
||||
return msql_affected_rows($this->_result);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ quoteIdentifier()
|
||||
|
||||
/**
|
||||
* Returns the next free id in a sequence
|
||||
*
|
||||
* @param string $seq_name name of the sequence
|
||||
* @param boolean $ondemand when true, the seqence is automatically
|
||||
* created if it does not exist
|
||||
*
|
||||
* @return int|object
|
||||
* A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_common::nextID(), DB_common::getSequenceName(),
|
||||
* DB_msql::createSequence(), DB_msql::dropSequence()
|
||||
*/
|
||||
public function nextId($seq_name, $ondemand = true)
|
||||
{
|
||||
$seqname = $this->getSequenceName($seq_name);
|
||||
$repeat = false;
|
||||
do {
|
||||
$this->pushErrorHandling(PEAR_ERROR_RETURN);
|
||||
$result = $this->query("SELECT _seq FROM ${seqname}");
|
||||
$this->popErrorHandling();
|
||||
if ($ondemand && DB::isError($result) &&
|
||||
$result->getCode() == DB_ERROR_NOSUCHTABLE) {
|
||||
$repeat = true;
|
||||
$this->pushErrorHandling(PEAR_ERROR_RETURN);
|
||||
$result = $this->createSequence($seq_name);
|
||||
$this->popErrorHandling();
|
||||
if (DB::isError($result)) {
|
||||
return $this->raiseError($result);
|
||||
}
|
||||
} else {
|
||||
$repeat = false;
|
||||
}
|
||||
} while ($repeat);
|
||||
if (DB::isError($result)) {
|
||||
return $this->raiseError($result);
|
||||
}
|
||||
$arr = $result->fetchRow(DB_FETCHMODE_ORDERED);
|
||||
$result->free();
|
||||
return $arr[0];
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ quoteFloat()
|
||||
|
||||
/**
|
||||
* Creates a new sequence
|
||||
*
|
||||
* Also creates a new table to associate the sequence with. Uses
|
||||
* a separate table to ensure portability with other drivers.
|
||||
*
|
||||
* @param string $seq_name name of the new sequence
|
||||
*
|
||||
* @return int DB_OK on success. A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_common::createSequence(), DB_common::getSequenceName(),
|
||||
* DB_msql::nextID(), DB_msql::dropSequence()
|
||||
*/
|
||||
public function createSequence($seq_name)
|
||||
{
|
||||
$seqname = $this->getSequenceName($seq_name);
|
||||
$res = $this->query('CREATE TABLE ' . $seqname
|
||||
. ' (id INTEGER NOT NULL)');
|
||||
if (DB::isError($res)) {
|
||||
return $res;
|
||||
}
|
||||
$res = $this->query("CREATE SEQUENCE ON ${seqname}");
|
||||
return $res;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ escapeSimple()
|
||||
|
||||
/**
|
||||
* Deletes a sequence
|
||||
*
|
||||
* @param string $seq_name name of the sequence to be deleted
|
||||
*
|
||||
* @return int DB_OK on success. A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_common::dropSequence(), DB_common::getSequenceName(),
|
||||
* DB_msql::nextID(), DB_msql::createSequence()
|
||||
*/
|
||||
public function dropSequence($seq_name)
|
||||
{
|
||||
return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name));
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ msqlRaiseError()
|
||||
|
||||
/**
|
||||
* mSQL does not support delimited identifiers
|
||||
*
|
||||
* @param string $str the identifier name to be quoted
|
||||
*
|
||||
* @return object a DB_Error object
|
||||
*
|
||||
* @see DB_common::quoteIdentifier()
|
||||
* @since Method available since Release 1.7.0
|
||||
*/
|
||||
public function quoteIdentifier($str)
|
||||
{
|
||||
return $this->raiseError(DB_ERROR_UNSUPPORTED);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ errorNative()
|
||||
|
||||
/**
|
||||
* Formats a float value for use within a query in a locale-independent
|
||||
* manner.
|
||||
*
|
||||
* @param float the float value to be quoted.
|
||||
* @return string the quoted string.
|
||||
* @see DB_common::quoteSmart()
|
||||
* @since Method available since release 1.7.8.
|
||||
*/
|
||||
public function quoteFloat($float)
|
||||
{
|
||||
return $this->escapeSimple(str_replace(',', '.', strval(floatval($float))));
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ errorCode()
|
||||
|
||||
/**
|
||||
* Escapes a string according to the current DBMS's standards
|
||||
*
|
||||
* @param string $str the string to be escaped
|
||||
*
|
||||
* @return string the escaped string
|
||||
*
|
||||
* @see DB_common::quoteSmart()
|
||||
* @since Method available since Release 1.7.0
|
||||
*/
|
||||
public function escapeSimple($str)
|
||||
{
|
||||
return addslashes($str);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ tableInfo()
|
||||
|
||||
/**
|
||||
* Returns information about a table or a result set
|
||||
*
|
||||
* @param object|string $result DB_result object from a query or a
|
||||
* string containing the name of a table.
|
||||
* While this also accepts a query result
|
||||
* resource identifier, this behavior is
|
||||
* deprecated.
|
||||
* @param int $mode a valid tableInfo mode
|
||||
*
|
||||
* @return array|object
|
||||
* A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_common::setOption()
|
||||
*/
|
||||
public function tableInfo($result, $mode = null)
|
||||
{
|
||||
if (is_string($result)) {
|
||||
/*
|
||||
* Probably received a table name.
|
||||
* Create a result resource identifier.
|
||||
*/
|
||||
$id = @msql_query(
|
||||
"SELECT * FROM $result",
|
||||
$this->connection
|
||||
);
|
||||
$got_string = true;
|
||||
} elseif (isset($result->result)) {
|
||||
/*
|
||||
* Probably received a result object.
|
||||
* Extract the result resource identifier.
|
||||
*/
|
||||
$id = $result->result;
|
||||
$got_string = false;
|
||||
} else {
|
||||
/*
|
||||
* Probably received a result resource identifier.
|
||||
* Copy it.
|
||||
* Deprecated. Here for compatibility only.
|
||||
*/
|
||||
$id = $result;
|
||||
$got_string = false;
|
||||
}
|
||||
|
||||
if (!is_resource($id)) {
|
||||
return $this->raiseError(DB_ERROR_NEED_MORE_DATA);
|
||||
}
|
||||
|
||||
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
|
||||
$case_func = 'strtolower';
|
||||
} else {
|
||||
$case_func = 'strval';
|
||||
}
|
||||
|
||||
$count = @msql_num_fields($id);
|
||||
$res = array();
|
||||
|
||||
if ($mode) {
|
||||
$res['num_fields'] = $count;
|
||||
}
|
||||
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
$tmp = @msql_fetch_field($id);
|
||||
|
||||
$flags = '';
|
||||
if ($tmp->not_null) {
|
||||
$flags .= 'not_null ';
|
||||
}
|
||||
if ($tmp->unique) {
|
||||
$flags .= 'unique_key ';
|
||||
}
|
||||
$flags = trim($flags);
|
||||
|
||||
$res[$i] = array(
|
||||
'table' => $case_func($tmp->table),
|
||||
'name' => $case_func($tmp->name),
|
||||
'type' => $tmp->type,
|
||||
'len' => msql_field_len($id, $i),
|
||||
'flags' => $flags,
|
||||
);
|
||||
|
||||
if ($mode & DB_TABLEINFO_ORDER) {
|
||||
$res['order'][$res[$i]['name']] = $i;
|
||||
}
|
||||
if ($mode & DB_TABLEINFO_ORDERTABLE) {
|
||||
$res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
|
||||
}
|
||||
}
|
||||
|
||||
// free the result only if we were called on a table
|
||||
if ($got_string) {
|
||||
@msql_free_result($id);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ getSpecialQuery()
|
||||
|
||||
/**
|
||||
* Obtain a list of a given type of objects
|
||||
*
|
||||
* @param string $type the kind of objects you want to retrieve
|
||||
*
|
||||
* @return array|object
|
||||
*
|
||||
* @access protected
|
||||
* @see DB_common::getListOf()
|
||||
*/
|
||||
public function getSpecialQuery($type)
|
||||
{
|
||||
switch ($type) {
|
||||
case 'databases':
|
||||
$id = @msql_list_dbs($this->connection);
|
||||
break;
|
||||
case 'tables':
|
||||
$id = @msql_list_tables(
|
||||
$this->dsn['database'],
|
||||
$this->connection
|
||||
);
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
if (!$id) {
|
||||
return $this->msqlRaiseError();
|
||||
}
|
||||
$out = array();
|
||||
while ($row = @msql_fetch_row($id)) {
|
||||
$out[] = $row[0];
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
// }}}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* tab-width: 4
|
||||
* c-basic-offset: 4
|
||||
* End:
|
||||
*/
|
@ -1,994 +0,0 @@
|
||||
<?php
|
||||
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
||||
|
||||
/**
|
||||
* The PEAR DB driver for PHP's mssql extension
|
||||
* for interacting with Microsoft SQL Server databases
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENSE: This source file is subject to version 3.0 of the PHP license
|
||||
* that is available through the world-wide-web at the following URI:
|
||||
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
|
||||
* the PHP License and are unable to obtain it through the web, please
|
||||
* send a note to license@php.net so we can mail you a copy immediately.
|
||||
*
|
||||
* @category Database
|
||||
* @package DB
|
||||
* @author Sterling Hughes <sterling@php.net>
|
||||
* @author Daniel Convissor <danielc@php.net>
|
||||
* @copyright 1997-2007 The PHP Group
|
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0
|
||||
* @version CVS: $Id$
|
||||
* @link http://pear.php.net/package/DB
|
||||
*/
|
||||
|
||||
/**
|
||||
* Obtain the DB_common class so it can be extended from
|
||||
*/
|
||||
//require_once 'DB/common.php';
|
||||
require_once 'common.php';
|
||||
|
||||
/**
|
||||
* The methods PEAR DB uses to interact with PHP's mssql extension
|
||||
* for interacting with Microsoft SQL Server databases
|
||||
*
|
||||
* These methods overload the ones declared in DB_common.
|
||||
*
|
||||
* DB's mssql driver is only for Microsfoft SQL Server databases.
|
||||
*
|
||||
* If you're connecting to a Sybase database, you MUST specify "sybase"
|
||||
* as the "phptype" in the DSN.
|
||||
*
|
||||
* This class only works correctly if you have compiled PHP using
|
||||
* --with-mssql=[dir_to_FreeTDS].
|
||||
*
|
||||
* @category Database
|
||||
* @package DB
|
||||
* @author Sterling Hughes <sterling@php.net>
|
||||
* @author Daniel Convissor <danielc@php.net>
|
||||
* @copyright 1997-2007 The PHP Group
|
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0
|
||||
* @version Release: 1.9.2
|
||||
* @link http://pear.php.net/package/DB
|
||||
*/
|
||||
class DB_mssql extends DB_common
|
||||
{
|
||||
// {{{ properties
|
||||
|
||||
/**
|
||||
* The DB driver type (mysql, oci8, odbc, etc.)
|
||||
* @var string
|
||||
*/
|
||||
public $phptype = 'mssql';
|
||||
|
||||
/**
|
||||
* The database syntax variant to be used (db2, access, etc.), if any
|
||||
* @var string
|
||||
*/
|
||||
public $dbsyntax = 'mssql';
|
||||
|
||||
/**
|
||||
* The capabilities of this DB implementation
|
||||
*
|
||||
* The 'new_link' element contains the PHP version that first provided
|
||||
* new_link support for this DBMS. Contains false if it's unsupported.
|
||||
*
|
||||
* Meaning of the 'limit' element:
|
||||
* + 'emulate' = emulate with fetch row by number
|
||||
* + 'alter' = alter the query
|
||||
* + false = skip rows
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $features = array(
|
||||
'limit' => 'emulate',
|
||||
'new_link' => false,
|
||||
'numrows' => true,
|
||||
'pconnect' => true,
|
||||
'prepare' => false,
|
||||
'ssl' => false,
|
||||
'transactions' => true,
|
||||
);
|
||||
|
||||
/**
|
||||
* A mapping of native error codes to DB error codes
|
||||
* @var array
|
||||
*/
|
||||
// XXX Add here error codes ie: 'S100E' => DB_ERROR_SYNTAX
|
||||
public $errorcode_map = array(
|
||||
102 => DB_ERROR_SYNTAX,
|
||||
110 => DB_ERROR_VALUE_COUNT_ON_ROW,
|
||||
155 => DB_ERROR_NOSUCHFIELD,
|
||||
156 => DB_ERROR_SYNTAX,
|
||||
170 => DB_ERROR_SYNTAX,
|
||||
207 => DB_ERROR_NOSUCHFIELD,
|
||||
208 => DB_ERROR_NOSUCHTABLE,
|
||||
245 => DB_ERROR_INVALID_NUMBER,
|
||||
319 => DB_ERROR_SYNTAX,
|
||||
321 => DB_ERROR_NOSUCHFIELD,
|
||||
325 => DB_ERROR_SYNTAX,
|
||||
336 => DB_ERROR_SYNTAX,
|
||||
515 => DB_ERROR_CONSTRAINT_NOT_NULL,
|
||||
547 => DB_ERROR_CONSTRAINT,
|
||||
1018 => DB_ERROR_SYNTAX,
|
||||
1035 => DB_ERROR_SYNTAX,
|
||||
1913 => DB_ERROR_ALREADY_EXISTS,
|
||||
2209 => DB_ERROR_SYNTAX,
|
||||
2223 => DB_ERROR_SYNTAX,
|
||||
2248 => DB_ERROR_SYNTAX,
|
||||
2256 => DB_ERROR_SYNTAX,
|
||||
2257 => DB_ERROR_SYNTAX,
|
||||
2627 => DB_ERROR_CONSTRAINT,
|
||||
2714 => DB_ERROR_ALREADY_EXISTS,
|
||||
3607 => DB_ERROR_DIVZERO,
|
||||
3701 => DB_ERROR_NOSUCHTABLE,
|
||||
7630 => DB_ERROR_SYNTAX,
|
||||
8134 => DB_ERROR_DIVZERO,
|
||||
9303 => DB_ERROR_SYNTAX,
|
||||
9317 => DB_ERROR_SYNTAX,
|
||||
9318 => DB_ERROR_SYNTAX,
|
||||
9331 => DB_ERROR_SYNTAX,
|
||||
9332 => DB_ERROR_SYNTAX,
|
||||
15253 => DB_ERROR_SYNTAX,
|
||||
);
|
||||
|
||||
/**
|
||||
* The raw database connection created by PHP
|
||||
* @var resource
|
||||
*/
|
||||
public $connection;
|
||||
|
||||
/**
|
||||
* The DSN information for connecting to a database
|
||||
* @var array
|
||||
*/
|
||||
public $dsn = array();
|
||||
|
||||
|
||||
/**
|
||||
* Should data manipulation queries be committed automatically?
|
||||
* @var bool
|
||||
* @access private
|
||||
*/
|
||||
public $autocommit = true;
|
||||
|
||||
/**
|
||||
* The quantity of transactions begun
|
||||
*
|
||||
* {@internal While this is private, it can't actually be designated
|
||||
* private in PHP 5 because it is directly accessed in the test suite.}}
|
||||
*
|
||||
* @var integer
|
||||
* @access private
|
||||
*/
|
||||
public $transaction_opcount = 0;
|
||||
|
||||
/**
|
||||
* The database specified in the DSN
|
||||
*
|
||||
* It's a fix to allow calls to different databases in the same script.
|
||||
*
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
public $_db = null;
|
||||
|
||||
|
||||
// }}}
|
||||
// {{{ constructor
|
||||
|
||||
/**
|
||||
* This constructor calls <kbd>parent::__construct()</kbd>
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ connect()
|
||||
|
||||
/**
|
||||
* Connect to the database server, log in and open the database
|
||||
*
|
||||
* Don't call this method directly. Use DB::connect() instead.
|
||||
*
|
||||
* @param array $dsn the data source name
|
||||
* @param bool $persistent should the connection be persistent?
|
||||
*
|
||||
* @return int|object
|
||||
*/
|
||||
public function connect($dsn, $persistent = false)
|
||||
{
|
||||
if (!PEAR::loadExtension('mssql') && !PEAR::loadExtension('sybase')
|
||||
&& !PEAR::loadExtension('sybase_ct')) {
|
||||
return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
|
||||
}
|
||||
|
||||
$this->dsn = $dsn;
|
||||
if ($dsn['dbsyntax']) {
|
||||
$this->dbsyntax = $dsn['dbsyntax'];
|
||||
}
|
||||
|
||||
$params = array(
|
||||
$dsn['hostspec'] ? $dsn['hostspec'] : 'localhost',
|
||||
$dsn['username'] ? $dsn['username'] : null,
|
||||
$dsn['password'] ? $dsn['password'] : null,
|
||||
);
|
||||
if ($dsn['port']) {
|
||||
$params[0] .= ((substr(PHP_OS, 0, 3) == 'WIN') ? ',' : ':')
|
||||
. $dsn['port'];
|
||||
}
|
||||
|
||||
$connect_function = $persistent ? 'mssql_pconnect' : 'mssql_connect';
|
||||
|
||||
$this->connection = @call_user_func_array($connect_function, $params);
|
||||
|
||||
if (!$this->connection) {
|
||||
return $this->raiseError(
|
||||
DB_ERROR_CONNECT_FAILED,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
@mssql_get_last_message()
|
||||
);
|
||||
}
|
||||
if ($dsn['database']) {
|
||||
if (!@mssql_select_db($dsn['database'], $this->connection)) {
|
||||
return $this->raiseError(
|
||||
DB_ERROR_NODBSELECTED,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
@mssql_get_last_message()
|
||||
);
|
||||
}
|
||||
$this->_db = $dsn['database'];
|
||||
}
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ disconnect()
|
||||
|
||||
/**
|
||||
* Disconnects from the database server
|
||||
*
|
||||
* @return bool TRUE on success, FALSE on failure
|
||||
*/
|
||||
public function disconnect()
|
||||
{
|
||||
$ret = @mssql_close($this->connection);
|
||||
$this->connection = null;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ simpleQuery()
|
||||
|
||||
/**
|
||||
* Sends a query to the database server
|
||||
*
|
||||
* @param string the SQL query string
|
||||
*
|
||||
* @return mixed + a PHP result resrouce for successful SELECT queries
|
||||
* + the DB_OK constant for other successful queries
|
||||
* + a DB_Error object on failure
|
||||
*/
|
||||
public function simpleQuery($query)
|
||||
{
|
||||
$ismanip = $this->_checkManip($query);
|
||||
$this->last_query = $query;
|
||||
if (!@mssql_select_db($this->_db, $this->connection)) {
|
||||
return $this->mssqlRaiseError(DB_ERROR_NODBSELECTED);
|
||||
}
|
||||
$query = $this->modifyQuery($query);
|
||||
if (!$this->autocommit && $ismanip) {
|
||||
if ($this->transaction_opcount == 0) {
|
||||
$result = @mssql_query('BEGIN TRAN', $this->connection);
|
||||
if (!$result) {
|
||||
return $this->mssqlRaiseError();
|
||||
}
|
||||
}
|
||||
$this->transaction_opcount++;
|
||||
}
|
||||
$result = @mssql_query($query, $this->connection);
|
||||
if (!$result) {
|
||||
return $this->mssqlRaiseError();
|
||||
}
|
||||
// Determine which queries that should return data, and which
|
||||
// should return an error code only.
|
||||
return $ismanip ? DB_OK : $result;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ nextResult()
|
||||
|
||||
/**
|
||||
* Produces a DB_Error object regarding the current problem
|
||||
*
|
||||
* @param null $code
|
||||
* @return object the DB_Error object
|
||||
*
|
||||
* @see DB_common::raiseError(),
|
||||
* DB_mssql::errorNative(), DB_mssql::errorCode()
|
||||
*/
|
||||
public function mssqlRaiseError($code = null)
|
||||
{
|
||||
$message = @mssql_get_last_message();
|
||||
if (!$code) {
|
||||
$code = $this->errorNative();
|
||||
}
|
||||
return $this->raiseError(
|
||||
$this->errorCode($code, $message),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
"$code - $message"
|
||||
);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ fetchInto()
|
||||
|
||||
/**
|
||||
* Gets the DBMS' native error code produced by the last query
|
||||
*
|
||||
* @return int the DBMS' error code
|
||||
*/
|
||||
public function errorNative()
|
||||
{
|
||||
$res = @mssql_query('select @@ERROR as ErrorCode', $this->connection);
|
||||
if (!$res) {
|
||||
return DB_ERROR;
|
||||
}
|
||||
$row = @mssql_fetch_row($res);
|
||||
return $row[0];
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ freeResult()
|
||||
|
||||
/**
|
||||
* Determines PEAR::DB error code from mssql's native codes.
|
||||
*
|
||||
* If <var>$nativecode</var> isn't known yet, it will be looked up.
|
||||
*
|
||||
* @param mixed $nativecode mssql error code, if known
|
||||
* @param string $msg
|
||||
* @return integer an error number from a DB error constant
|
||||
* @see errorNative()
|
||||
*/
|
||||
public function errorCode($nativecode = null, $msg = '')
|
||||
{
|
||||
if (!$nativecode) {
|
||||
$nativecode = $this->errorNative();
|
||||
}
|
||||
if (isset($this->errorcode_map[$nativecode])) {
|
||||
if ($nativecode == 3701
|
||||
&& preg_match('/Cannot drop the index/i', $msg)) {
|
||||
return DB_ERROR_NOT_FOUND;
|
||||
}
|
||||
return $this->errorcode_map[$nativecode];
|
||||
} else {
|
||||
return DB_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ numCols()
|
||||
|
||||
/**
|
||||
* Move the internal mssql result pointer to the next available result
|
||||
*
|
||||
* @param a valid fbsql result resource
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return true if a result is available otherwise return false
|
||||
*/
|
||||
public function nextResult($result)
|
||||
{
|
||||
return @mssql_next_result($result);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ numRows()
|
||||
|
||||
/**
|
||||
* Places a row from the result set into the given array
|
||||
*
|
||||
* Formating of the array and the data therein are configurable.
|
||||
* See DB_result::fetchInto() for more information.
|
||||
*
|
||||
* This method is not meant to be called directly. Use
|
||||
* DB_result::fetchInto() instead. It can't be declared "protected"
|
||||
* because DB_result is a separate object.
|
||||
*
|
||||
* @param resource $result the query result resource
|
||||
* @param array $arr the referenced array to put the data in
|
||||
* @param int $fetchmode how the resulting array should be indexed
|
||||
* @param int $rownum the row number to fetch (0 = first row)
|
||||
*
|
||||
* @return mixed DB_OK on success, NULL when the end of a result set is
|
||||
* reached or on failure
|
||||
*
|
||||
* @see DB_result::fetchInto()
|
||||
*/
|
||||
public function fetchInto($result, &$arr, $fetchmode, $rownum = null)
|
||||
{
|
||||
if ($rownum !== null) {
|
||||
if (!@mssql_data_seek($result, $rownum)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if ($fetchmode & DB_FETCHMODE_ASSOC) {
|
||||
$arr = @mssql_fetch_assoc($result);
|
||||
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) {
|
||||
$arr = array_change_key_case($arr, CASE_LOWER);
|
||||
}
|
||||
} else {
|
||||
$arr = @mssql_fetch_row($result);
|
||||
}
|
||||
if (!$arr) {
|
||||
return null;
|
||||
}
|
||||
if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
|
||||
$this->_rtrimArrayValues($arr);
|
||||
}
|
||||
if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
|
||||
$this->_convertNullArrayValuesToEmpty($arr);
|
||||
}
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ autoCommit()
|
||||
|
||||
/**
|
||||
* Deletes the result set and frees the memory occupied by the result set
|
||||
*
|
||||
* This method is not meant to be called directly. Use
|
||||
* DB_result::free() instead. It can't be declared "protected"
|
||||
* because DB_result is a separate object.
|
||||
*
|
||||
* @param resource $result PHP's query result resource
|
||||
*
|
||||
* @return bool TRUE on success, FALSE if $result is invalid
|
||||
*
|
||||
* @see DB_result::free()
|
||||
*/
|
||||
public function freeResult($result)
|
||||
{
|
||||
return is_resource($result) ? mssql_free_result($result) : false;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ commit()
|
||||
|
||||
/**
|
||||
* Gets the number of columns in a result set
|
||||
*
|
||||
* This method is not meant to be called directly. Use
|
||||
* DB_result::numCols() instead. It can't be declared "protected"
|
||||
* because DB_result is a separate object.
|
||||
*
|
||||
* @param resource $result PHP's query result resource
|
||||
*
|
||||
* @return int|object
|
||||
*
|
||||
* @see DB_result::numCols()
|
||||
*/
|
||||
public function numCols($result)
|
||||
{
|
||||
$cols = @mssql_num_fields($result);
|
||||
if (!$cols) {
|
||||
return $this->mssqlRaiseError();
|
||||
}
|
||||
return $cols;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ rollback()
|
||||
|
||||
/**
|
||||
* Gets the number of rows in a result set
|
||||
*
|
||||
* This method is not meant to be called directly. Use
|
||||
* DB_result::numRows() instead. It can't be declared "protected"
|
||||
* because DB_result is a separate object.
|
||||
*
|
||||
* @param resource $result PHP's query result resource
|
||||
*
|
||||
* @return int|object
|
||||
*
|
||||
* @see DB_result::numRows()
|
||||
*/
|
||||
public function numRows($result)
|
||||
{
|
||||
$rows = @mssql_num_rows($result);
|
||||
if ($rows === false) {
|
||||
return $this->mssqlRaiseError();
|
||||
}
|
||||
return $rows;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ affectedRows()
|
||||
|
||||
/**
|
||||
* Enables or disables automatic commits
|
||||
*
|
||||
* @param bool $onoff true turns it on, false turns it off
|
||||
*
|
||||
* @return int DB_OK on success. A DB_Error object if the driver
|
||||
* doesn't support auto-committing transactions.
|
||||
*/
|
||||
public function autoCommit($onoff = false)
|
||||
{
|
||||
// XXX if $this->transaction_opcount > 0, we should probably
|
||||
// issue a warning here.
|
||||
$this->autocommit = $onoff ? true : false;
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ nextId()
|
||||
|
||||
/**
|
||||
* Commits the current transaction
|
||||
*
|
||||
* @return int|object
|
||||
*/
|
||||
public function commit()
|
||||
{
|
||||
if ($this->transaction_opcount > 0) {
|
||||
if (!@mssql_select_db($this->_db, $this->connection)) {
|
||||
return $this->mssqlRaiseError(DB_ERROR_NODBSELECTED);
|
||||
}
|
||||
$result = @mssql_query('COMMIT TRAN', $this->connection);
|
||||
$this->transaction_opcount = 0;
|
||||
if (!$result) {
|
||||
return $this->mssqlRaiseError();
|
||||
}
|
||||
}
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverts the current transaction
|
||||
*
|
||||
* @return int|object
|
||||
*/
|
||||
public function rollback()
|
||||
{
|
||||
if ($this->transaction_opcount > 0) {
|
||||
if (!@mssql_select_db($this->_db, $this->connection)) {
|
||||
return $this->mssqlRaiseError(DB_ERROR_NODBSELECTED);
|
||||
}
|
||||
$result = @mssql_query('ROLLBACK TRAN', $this->connection);
|
||||
$this->transaction_opcount = 0;
|
||||
if (!$result) {
|
||||
return $this->mssqlRaiseError();
|
||||
}
|
||||
}
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ dropSequence()
|
||||
|
||||
/**
|
||||
* Determines the number of rows affected by a data maniuplation query
|
||||
*
|
||||
* 0 is returned for queries that don't manipulate data.
|
||||
*
|
||||
* @return int|object
|
||||
*/
|
||||
public function affectedRows()
|
||||
{
|
||||
if ($this->_last_query_manip) {
|
||||
$res = @mssql_query('select @@rowcount', $this->connection);
|
||||
if (!$res) {
|
||||
return $this->mssqlRaiseError();
|
||||
}
|
||||
$ar = @mssql_fetch_row($res);
|
||||
if (!$ar) {
|
||||
$result = 0;
|
||||
} else {
|
||||
@mssql_free_result($res);
|
||||
$result = $ar[0];
|
||||
}
|
||||
} else {
|
||||
$result = 0;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ escapeSimple()
|
||||
|
||||
/**
|
||||
* Returns the next free id in a sequence
|
||||
*
|
||||
* @param string $seq_name name of the sequence
|
||||
* @param boolean $ondemand when true, the seqence is automatically
|
||||
* created if it does not exist
|
||||
*
|
||||
* @return int|object
|
||||
* A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_common::nextID(), DB_common::getSequenceName(),
|
||||
* DB_mssql::createSequence(), DB_mssql::dropSequence()
|
||||
*/
|
||||
public function nextId($seq_name, $ondemand = true)
|
||||
{
|
||||
$seqname = $this->getSequenceName($seq_name);
|
||||
if (!@mssql_select_db($this->_db, $this->connection)) {
|
||||
return $this->mssqlRaiseError(DB_ERROR_NODBSELECTED);
|
||||
}
|
||||
$repeat = 0;
|
||||
do {
|
||||
$this->pushErrorHandling(PEAR_ERROR_RETURN);
|
||||
$result = $this->query("INSERT INTO $seqname (vapor) VALUES (0)");
|
||||
$this->popErrorHandling();
|
||||
if ($ondemand && DB::isError($result) &&
|
||||
($result->getCode() == DB_ERROR || $result->getCode() == DB_ERROR_NOSUCHTABLE)) {
|
||||
$repeat = 1;
|
||||
$result = $this->createSequence($seq_name);
|
||||
if (DB::isError($result)) {
|
||||
return $this->raiseError($result);
|
||||
}
|
||||
} elseif (!DB::isError($result)) {
|
||||
$result = $this->query("SELECT IDENT_CURRENT('$seqname')");
|
||||
if (DB::isError($result)) {
|
||||
/* Fallback code for MS SQL Server 7.0, which doesn't have
|
||||
* IDENT_CURRENT. This is *not* safe for concurrent
|
||||
* requests, and really, if you're using it, you're in a
|
||||
* world of hurt. Nevertheless, it's here to ensure BC. See
|
||||
* bug #181 for the gory details.*/
|
||||
$result = $this->query("SELECT @@IDENTITY FROM $seqname");
|
||||
}
|
||||
$repeat = 0;
|
||||
} else {
|
||||
$repeat = false;
|
||||
}
|
||||
} while ($repeat);
|
||||
if (DB::isError($result)) {
|
||||
return $this->raiseError($result);
|
||||
}
|
||||
$result = $result->fetchRow(DB_FETCHMODE_ORDERED);
|
||||
return $result[0];
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ quoteIdentifier()
|
||||
|
||||
/**
|
||||
* Creates a new sequence
|
||||
*
|
||||
* @param string $seq_name name of the new sequence
|
||||
*
|
||||
* @return int DB_OK on success. A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_common::createSequence(), DB_common::getSequenceName(),
|
||||
* DB_mssql::nextID(), DB_mssql::dropSequence()
|
||||
*/
|
||||
public function createSequence($seq_name)
|
||||
{
|
||||
return $this->query('CREATE TABLE '
|
||||
. $this->getSequenceName($seq_name)
|
||||
. ' ([id] [int] IDENTITY (1, 1) NOT NULL,'
|
||||
. ' [vapor] [int] NULL)');
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ mssqlRaiseError()
|
||||
|
||||
/**
|
||||
* Deletes a sequence
|
||||
*
|
||||
* @param string $seq_name name of the sequence to be deleted
|
||||
*
|
||||
* @return int DB_OK on success. A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_common::dropSequence(), DB_common::getSequenceName(),
|
||||
* DB_mssql::nextID(), DB_mssql::createSequence()
|
||||
*/
|
||||
public function dropSequence($seq_name)
|
||||
{
|
||||
return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name));
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ errorNative()
|
||||
|
||||
/**
|
||||
* Escapes a string in a manner suitable for SQL Server.
|
||||
*
|
||||
* @param string $str the string to be escaped
|
||||
* @return string the escaped string
|
||||
*
|
||||
* @see DB_common::quoteSmart()
|
||||
* @since Method available since Release 1.6.0
|
||||
*/
|
||||
public function escapeSimple($str)
|
||||
{
|
||||
return str_replace(
|
||||
array("'", "\\\r\n", "\\\n"),
|
||||
array("''", "\\\\\r\n\r\n", "\\\\\n\n"),
|
||||
$str
|
||||
);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ errorCode()
|
||||
|
||||
/**
|
||||
* Quotes a string so it can be safely used as a table or column name
|
||||
*
|
||||
* @param string $str identifier name to be quoted
|
||||
*
|
||||
* @return string quoted identifier string
|
||||
*
|
||||
* @see DB_common::quoteIdentifier()
|
||||
* @since Method available since Release 1.6.0
|
||||
*/
|
||||
public function quoteIdentifier($str)
|
||||
{
|
||||
return '[' . str_replace(']', ']]', $str) . ']';
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ tableInfo()
|
||||
|
||||
/**
|
||||
* Returns information about a table or a result set
|
||||
*
|
||||
* NOTE: only supports 'table' and 'flags' if <var>$result</var>
|
||||
* is a table name.
|
||||
*
|
||||
* @param object|string $result DB_result object from a query or a
|
||||
* string containing the name of a table.
|
||||
* While this also accepts a query result
|
||||
* resource identifier, this behavior is
|
||||
* deprecated.
|
||||
* @param int $mode a valid tableInfo mode
|
||||
*
|
||||
* @return array|object
|
||||
* A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_common::tableInfo()
|
||||
*/
|
||||
public function tableInfo($result, $mode = null)
|
||||
{
|
||||
if (is_string($result)) {
|
||||
/*
|
||||
* Probably received a table name.
|
||||
* Create a result resource identifier.
|
||||
*/
|
||||
if (!@mssql_select_db($this->_db, $this->connection)) {
|
||||
return $this->mssqlRaiseError(DB_ERROR_NODBSELECTED);
|
||||
}
|
||||
$id = @mssql_query(
|
||||
"SELECT * FROM $result WHERE 1=0",
|
||||
$this->connection
|
||||
);
|
||||
$got_string = true;
|
||||
} elseif (isset($result->result)) {
|
||||
/*
|
||||
* Probably received a result object.
|
||||
* Extract the result resource identifier.
|
||||
*/
|
||||
$id = $result->result;
|
||||
$got_string = false;
|
||||
} else {
|
||||
/*
|
||||
* Probably received a result resource identifier.
|
||||
* Copy it.
|
||||
* Deprecated. Here for compatibility only.
|
||||
*/
|
||||
$id = $result;
|
||||
$got_string = false;
|
||||
}
|
||||
|
||||
if (!is_resource($id)) {
|
||||
return $this->mssqlRaiseError(DB_ERROR_NEED_MORE_DATA);
|
||||
}
|
||||
|
||||
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
|
||||
$case_func = 'strtolower';
|
||||
} else {
|
||||
$case_func = 'strval';
|
||||
}
|
||||
|
||||
$count = @mssql_num_fields($id);
|
||||
$res = array();
|
||||
|
||||
if ($mode) {
|
||||
$res['num_fields'] = $count;
|
||||
}
|
||||
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
if ($got_string) {
|
||||
$flags = $this->_mssql_field_flags(
|
||||
$result,
|
||||
@mssql_field_name($id, $i)
|
||||
);
|
||||
if (DB::isError($flags)) {
|
||||
return $flags;
|
||||
}
|
||||
} else {
|
||||
$flags = '';
|
||||
}
|
||||
|
||||
$res[$i] = array(
|
||||
'table' => $got_string ? $case_func($result) : '',
|
||||
'name' => $case_func(@mssql_field_name($id, $i)),
|
||||
'type' => @mssql_field_type($id, $i),
|
||||
'len' => @mssql_field_length($id, $i),
|
||||
'flags' => $flags,
|
||||
);
|
||||
if ($mode & DB_TABLEINFO_ORDER) {
|
||||
$res['order'][$res[$i]['name']] = $i;
|
||||
}
|
||||
if ($mode & DB_TABLEINFO_ORDERTABLE) {
|
||||
$res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
|
||||
}
|
||||
}
|
||||
|
||||
// free the result only if we were called on a table
|
||||
if ($got_string) {
|
||||
@mssql_free_result($id);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _mssql_field_flags()
|
||||
|
||||
/**
|
||||
* Get a column's flags
|
||||
*
|
||||
* Supports "not_null", "primary_key",
|
||||
* "auto_increment" (mssql identity), "timestamp" (mssql timestamp),
|
||||
* "unique_key" (mssql unique index, unique check or primary_key) and
|
||||
* "multiple_key" (multikey index)
|
||||
*
|
||||
* mssql timestamp is NOT similar to the mysql timestamp so this is maybe
|
||||
* not useful at all - is the behaviour of mysql_field_flags that primary
|
||||
* keys are alway unique? is the interpretation of multiple_key correct?
|
||||
*
|
||||
* @param string $table the table name
|
||||
* @param string $column the field name
|
||||
*
|
||||
* @return array|string
|
||||
*
|
||||
* @access private
|
||||
* @author Joern Barthel <j_barthel@web.de>
|
||||
*/
|
||||
public function _mssql_field_flags($table, $column)
|
||||
{
|
||||
static $tableName = null;
|
||||
static $flags = array();
|
||||
|
||||
if ($table != $tableName) {
|
||||
$flags = array();
|
||||
$tableName = $table;
|
||||
|
||||
// get unique and primary keys
|
||||
$res = $this->getAll("EXEC SP_HELPINDEX $table", DB_FETCHMODE_ASSOC);
|
||||
if (DB::isError($res)) {
|
||||
return $res;
|
||||
}
|
||||
|
||||
foreach ($res as $val) {
|
||||
$keys = explode(', ', $val['index_keys']);
|
||||
|
||||
if (sizeof($keys) > 1) {
|
||||
foreach ($keys as $key) {
|
||||
$this->_add_flag($flags[$key], 'multiple_key');
|
||||
}
|
||||
}
|
||||
|
||||
if (strpos($val['index_description'], 'primary key')) {
|
||||
foreach ($keys as $key) {
|
||||
$this->_add_flag($flags[$key], 'primary_key');
|
||||
}
|
||||
} elseif (strpos($val['index_description'], 'unique')) {
|
||||
foreach ($keys as $key) {
|
||||
$this->_add_flag($flags[$key], 'unique_key');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get auto_increment, not_null and timestamp
|
||||
$res = $this->getAll("EXEC SP_COLUMNS $table", DB_FETCHMODE_ASSOC);
|
||||
if (DB::isError($res)) {
|
||||
return $res;
|
||||
}
|
||||
|
||||
foreach ($res as $val) {
|
||||
$val = array_change_key_case($val, CASE_LOWER);
|
||||
if ($val['nullable'] == '0') {
|
||||
$this->_add_flag($flags[$val['column_name']], 'not_null');
|
||||
}
|
||||
if (strpos($val['type_name'], 'identity')) {
|
||||
$this->_add_flag($flags[$val['column_name']], 'auto_increment');
|
||||
}
|
||||
if (strpos($val['type_name'], 'timestamp')) {
|
||||
$this->_add_flag($flags[$val['column_name']], 'timestamp');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (array_key_exists($column, $flags)) {
|
||||
return (implode(' ', $flags[$column]));
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _add_flag()
|
||||
|
||||
/**
|
||||
* Adds a string to the flags array if the flag is not yet in there
|
||||
* - if there is no flag present the array is created
|
||||
*
|
||||
* @param array &$array the reference to the flag-array
|
||||
* @param string $value the flag value
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @access private
|
||||
* @author Joern Barthel <j_barthel@web.de>
|
||||
*/
|
||||
public function _add_flag(&$array, $value)
|
||||
{
|
||||
if (!is_array($array)) {
|
||||
$array = array($value);
|
||||
} elseif (!in_array($value, $array)) {
|
||||
array_push($array, $value);
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ getSpecialQuery()
|
||||
|
||||
/**
|
||||
* Obtains the query string needed for listing a given type of objects
|
||||
*
|
||||
* @param string $type the kind of objects you want to retrieve
|
||||
*
|
||||
* @return string the SQL query string or null if the driver doesn't
|
||||
* support the object type requested
|
||||
*
|
||||
* @access protected
|
||||
* @see DB_common::getListOf()
|
||||
*/
|
||||
public function getSpecialQuery($type)
|
||||
{
|
||||
switch ($type) {
|
||||
case 'tables':
|
||||
return "SELECT name FROM sysobjects WHERE type = 'U'"
|
||||
. ' ORDER BY name';
|
||||
case 'views':
|
||||
return "SELECT name FROM sysobjects WHERE type = 'V'";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* tab-width: 4
|
||||
* c-basic-offset: 4
|
||||
* End:
|
||||
*/
|
1049
extlib/DB/mysql.php
1049
extlib/DB/mysql.php
File diff suppressed because it is too large
Load Diff
1114
extlib/DB/mysqli.php
1114
extlib/DB/mysqli.php
File diff suppressed because it is too large
Load Diff
1182
extlib/DB/oci8.php
1182
extlib/DB/oci8.php
File diff suppressed because it is too large
Load Diff
@ -1,889 +0,0 @@
|
||||
<?php
|
||||
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
||||
|
||||
/**
|
||||
* The PEAR DB driver for PHP's odbc extension
|
||||
* for interacting with databases via ODBC connections
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENSE: This source file is subject to version 3.0 of the PHP license
|
||||
* that is available through the world-wide-web at the following URI:
|
||||
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
|
||||
* the PHP License and are unable to obtain it through the web, please
|
||||
* send a note to license@php.net so we can mail you a copy immediately.
|
||||
*
|
||||
* @category Database
|
||||
* @package DB
|
||||
* @author Stig Bakken <ssb@php.net>
|
||||
* @author Daniel Convissor <danielc@php.net>
|
||||
* @copyright 1997-2007 The PHP Group
|
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0
|
||||
* @version CVS: $Id$
|
||||
* @link http://pear.php.net/package/DB
|
||||
*/
|
||||
|
||||
/**
|
||||
* Obtain the DB_common class so it can be extended from
|
||||
*/
|
||||
//require_once 'DB/common.php';
|
||||
require_once 'common.php';
|
||||
|
||||
/**
|
||||
* The methods PEAR DB uses to interact with PHP's odbc extension
|
||||
* for interacting with databases via ODBC connections
|
||||
*
|
||||
* These methods overload the ones declared in DB_common.
|
||||
*
|
||||
* More info on ODBC errors could be found here:
|
||||
* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/trblsql/tr_err_odbc_5stz.asp
|
||||
*
|
||||
* @category Database
|
||||
* @package DB
|
||||
* @author Stig Bakken <ssb@php.net>
|
||||
* @author Daniel Convissor <danielc@php.net>
|
||||
* @copyright 1997-2007 The PHP Group
|
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0
|
||||
* @version Release: 1.9.2
|
||||
* @link http://pear.php.net/package/DB
|
||||
*/
|
||||
class DB_odbc extends DB_common
|
||||
{
|
||||
// {{{ properties
|
||||
|
||||
/**
|
||||
* The DB driver type (mysql, oci8, odbc, etc.)
|
||||
* @var string
|
||||
*/
|
||||
public $phptype = 'odbc';
|
||||
|
||||
/**
|
||||
* The database syntax variant to be used (db2, access, etc.), if any
|
||||
* @var string
|
||||
*/
|
||||
public $dbsyntax = 'sql92';
|
||||
|
||||
/**
|
||||
* The capabilities of this DB implementation
|
||||
*
|
||||
* The 'new_link' element contains the PHP version that first provided
|
||||
* new_link support for this DBMS. Contains false if it's unsupported.
|
||||
*
|
||||
* Meaning of the 'limit' element:
|
||||
* + 'emulate' = emulate with fetch row by number
|
||||
* + 'alter' = alter the query
|
||||
* + false = skip rows
|
||||
*
|
||||
* NOTE: The feature set of the following drivers are different than
|
||||
* the default:
|
||||
* + solid: 'transactions' = true
|
||||
* + navision: 'limit' = false
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $features = array(
|
||||
'limit' => 'emulate',
|
||||
'new_link' => false,
|
||||
'numrows' => true,
|
||||
'pconnect' => true,
|
||||
'prepare' => false,
|
||||
'ssl' => false,
|
||||
'transactions' => false,
|
||||
);
|
||||
|
||||
/**
|
||||
* A mapping of native error codes to DB error codes
|
||||
* @var array
|
||||
*/
|
||||
public $errorcode_map = array(
|
||||
'01004' => DB_ERROR_TRUNCATED,
|
||||
'07001' => DB_ERROR_MISMATCH,
|
||||
'21S01' => DB_ERROR_VALUE_COUNT_ON_ROW,
|
||||
'21S02' => DB_ERROR_MISMATCH,
|
||||
'22001' => DB_ERROR_INVALID,
|
||||
'22003' => DB_ERROR_INVALID_NUMBER,
|
||||
'22005' => DB_ERROR_INVALID_NUMBER,
|
||||
'22008' => DB_ERROR_INVALID_DATE,
|
||||
'22012' => DB_ERROR_DIVZERO,
|
||||
'23000' => DB_ERROR_CONSTRAINT,
|
||||
'23502' => DB_ERROR_CONSTRAINT_NOT_NULL,
|
||||
'23503' => DB_ERROR_CONSTRAINT,
|
||||
'23504' => DB_ERROR_CONSTRAINT,
|
||||
'23505' => DB_ERROR_CONSTRAINT,
|
||||
'24000' => DB_ERROR_INVALID,
|
||||
'34000' => DB_ERROR_INVALID,
|
||||
'37000' => DB_ERROR_SYNTAX,
|
||||
'42000' => DB_ERROR_SYNTAX,
|
||||
'42601' => DB_ERROR_SYNTAX,
|
||||
'IM001' => DB_ERROR_UNSUPPORTED,
|
||||
'S0000' => DB_ERROR_NOSUCHTABLE,
|
||||
'S0001' => DB_ERROR_ALREADY_EXISTS,
|
||||
'S0002' => DB_ERROR_NOSUCHTABLE,
|
||||
'S0011' => DB_ERROR_ALREADY_EXISTS,
|
||||
'S0012' => DB_ERROR_NOT_FOUND,
|
||||
'S0021' => DB_ERROR_ALREADY_EXISTS,
|
||||
'S0022' => DB_ERROR_NOSUCHFIELD,
|
||||
'S1009' => DB_ERROR_INVALID,
|
||||
'S1090' => DB_ERROR_INVALID,
|
||||
'S1C00' => DB_ERROR_NOT_CAPABLE,
|
||||
);
|
||||
|
||||
/**
|
||||
* The raw database connection created by PHP
|
||||
* @var resource
|
||||
*/
|
||||
public $connection;
|
||||
|
||||
/**
|
||||
* The DSN information for connecting to a database
|
||||
* @var array
|
||||
*/
|
||||
public $dsn = array();
|
||||
|
||||
|
||||
/**
|
||||
* The number of rows affected by a data manipulation query
|
||||
* @var integer
|
||||
* @access private
|
||||
*/
|
||||
public $affected = 0;
|
||||
|
||||
|
||||
// }}}
|
||||
// {{{ constructor
|
||||
|
||||
/**
|
||||
* This constructor calls <kbd>parent::__construct()</kbd>
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ connect()
|
||||
|
||||
/**
|
||||
* Connect to the database server, log in and open the database
|
||||
*
|
||||
* Don't call this method directly. Use DB::connect() instead.
|
||||
*
|
||||
* PEAR DB's odbc driver supports the following extra DSN options:
|
||||
* + cursor The type of cursor to be used for this connection.
|
||||
*
|
||||
* @param array $dsn the data source name
|
||||
* @param bool $persistent should the connection be persistent?
|
||||
*
|
||||
* @return int|object
|
||||
*/
|
||||
public function connect($dsn, $persistent = false)
|
||||
{
|
||||
if (!PEAR::loadExtension('odbc')) {
|
||||
return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
|
||||
}
|
||||
|
||||
$this->dsn = $dsn;
|
||||
if ($dsn['dbsyntax']) {
|
||||
$this->dbsyntax = $dsn['dbsyntax'];
|
||||
}
|
||||
switch ($this->dbsyntax) {
|
||||
case 'access':
|
||||
case 'db2':
|
||||
case 'solid':
|
||||
$this->features['transactions'] = true;
|
||||
break;
|
||||
case 'navision':
|
||||
$this->features['limit'] = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is hear for backwards compatibility. Should have been using
|
||||
* 'database' all along, but prior to 1.6.0RC3 'hostspec' was used.
|
||||
*/
|
||||
if ($dsn['database']) {
|
||||
$odbcdsn = $dsn['database'];
|
||||
} elseif ($dsn['hostspec']) {
|
||||
$odbcdsn = $dsn['hostspec'];
|
||||
} else {
|
||||
$odbcdsn = 'localhost';
|
||||
}
|
||||
|
||||
$connect_function = $persistent ? 'odbc_pconnect' : 'odbc_connect';
|
||||
|
||||
if (empty($dsn['cursor'])) {
|
||||
$this->connection = @$connect_function(
|
||||
$odbcdsn,
|
||||
$dsn['username'],
|
||||
$dsn['password']
|
||||
);
|
||||
} else {
|
||||
$this->connection = @$connect_function(
|
||||
$odbcdsn,
|
||||
$dsn['username'],
|
||||
$dsn['password'],
|
||||
$dsn['cursor']
|
||||
);
|
||||
}
|
||||
|
||||
if (!is_resource($this->connection)) {
|
||||
return $this->raiseError(
|
||||
DB_ERROR_CONNECT_FAILED,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
$this->errorNative()
|
||||
);
|
||||
}
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ disconnect()
|
||||
|
||||
/**
|
||||
* Gets the DBMS' native error code and message produced by the last query
|
||||
*
|
||||
* @return string the DBMS' error code and message
|
||||
*/
|
||||
public function errorNative()
|
||||
{
|
||||
if (!is_resource($this->connection)) {
|
||||
return @odbc_error() . ' ' . @odbc_errormsg();
|
||||
}
|
||||
return @odbc_error($this->connection) . ' ' . @odbc_errormsg($this->connection);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ simpleQuery()
|
||||
|
||||
/**
|
||||
* Disconnects from the database server
|
||||
*
|
||||
* @return bool|void
|
||||
*/
|
||||
public function disconnect()
|
||||
{
|
||||
$err = @odbc_close($this->connection);
|
||||
$this->connection = null;
|
||||
return $err;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ nextResult()
|
||||
|
||||
/**
|
||||
* Sends a query to the database server
|
||||
*
|
||||
* @param string the SQL query string
|
||||
*
|
||||
* @return mixed + a PHP result resrouce for successful SELECT queries
|
||||
* + the DB_OK constant for other successful queries
|
||||
* + a DB_Error object on failure
|
||||
*/
|
||||
public function simpleQuery($query)
|
||||
{
|
||||
$this->last_query = $query;
|
||||
$query = $this->modifyQuery($query);
|
||||
$result = @odbc_exec($this->connection, $query);
|
||||
if (!$result) {
|
||||
return $this->odbcRaiseError(); // XXX ERRORMSG
|
||||
}
|
||||
// Determine which queries that should return data, and which
|
||||
// should return an error code only.
|
||||
if ($this->_checkManip($query)) {
|
||||
$this->affected = $result; // For affectedRows()
|
||||
return DB_OK;
|
||||
}
|
||||
$this->affected = 0;
|
||||
return $result;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ fetchInto()
|
||||
|
||||
/**
|
||||
* Produces a DB_Error object regarding the current problem
|
||||
*
|
||||
* @param int $errno if the error is being manually raised pass a
|
||||
* DB_ERROR* constant here. If this isn't passed
|
||||
* the error information gathered from the DBMS.
|
||||
*
|
||||
* @return object the DB_Error object
|
||||
*
|
||||
* @see DB_common::raiseError(),
|
||||
* DB_odbc::errorNative(), DB_common::errorCode()
|
||||
*/
|
||||
public function odbcRaiseError($errno = null)
|
||||
{
|
||||
if ($errno === null) {
|
||||
switch ($this->dbsyntax) {
|
||||
case 'access':
|
||||
if ($this->options['portability'] & DB_PORTABILITY_ERRORS) {
|
||||
$this->errorcode_map['07001'] = DB_ERROR_NOSUCHFIELD;
|
||||
} else {
|
||||
// Doing this in case mode changes during runtime.
|
||||
$this->errorcode_map['07001'] = DB_ERROR_MISMATCH;
|
||||
}
|
||||
|
||||
$native_code = odbc_error($this->connection);
|
||||
|
||||
// S1000 is for "General Error." Let's be more specific.
|
||||
if ($native_code == 'S1000') {
|
||||
$errormsg = odbc_errormsg($this->connection);
|
||||
static $error_regexps;
|
||||
if (!isset($error_regexps)) {
|
||||
$error_regexps = array(
|
||||
'/includes related records.$/i' => DB_ERROR_CONSTRAINT,
|
||||
'/cannot contain a Null value/i' => DB_ERROR_CONSTRAINT_NOT_NULL,
|
||||
);
|
||||
}
|
||||
foreach ($error_regexps as $regexp => $code) {
|
||||
if (preg_match($regexp, $errormsg)) {
|
||||
return $this->raiseError(
|
||||
$code,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
$native_code . ' ' . $errormsg
|
||||
);
|
||||
}
|
||||
}
|
||||
$errno = DB_ERROR;
|
||||
} else {
|
||||
$errno = $this->errorCode($native_code);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$errno = $this->errorCode(odbc_error($this->connection));
|
||||
}
|
||||
}
|
||||
return $this->raiseError(
|
||||
$errno,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
$this->errorNative()
|
||||
);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ freeResult()
|
||||
|
||||
/**
|
||||
* Move the internal odbc result pointer to the next available result
|
||||
*
|
||||
* @param a valid fbsql result resource
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return true if a result is available otherwise return false
|
||||
*/
|
||||
public function nextResult($result)
|
||||
{
|
||||
return @odbc_next_result($result);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ numCols()
|
||||
|
||||
/**
|
||||
* Places a row from the result set into the given array
|
||||
*
|
||||
* Formating of the array and the data therein are configurable.
|
||||
* See DB_result::fetchInto() for more information.
|
||||
*
|
||||
* This method is not meant to be called directly. Use
|
||||
* DB_result::fetchInto() instead. It can't be declared "protected"
|
||||
* because DB_result is a separate object.
|
||||
*
|
||||
* @param resource $result the query result resource
|
||||
* @param array $arr the referenced array to put the data in
|
||||
* @param int $fetchmode how the resulting array should be indexed
|
||||
* @param int $rownum the row number to fetch (0 = first row)
|
||||
*
|
||||
* @return mixed DB_OK on success, NULL when the end of a result set is
|
||||
* reached or on failure
|
||||
*
|
||||
* @see DB_result::fetchInto()
|
||||
*/
|
||||
public function fetchInto($result, &$arr, $fetchmode, $rownum = null)
|
||||
{
|
||||
$arr = array();
|
||||
if ($rownum !== null) {
|
||||
$rownum++; // ODBC first row is 1
|
||||
if (version_compare(phpversion(), '4.2.0', 'ge')) {
|
||||
$cols = @odbc_fetch_into($result, $arr, $rownum);
|
||||
} else {
|
||||
$cols = @odbc_fetch_into($result, $rownum, $arr);
|
||||
}
|
||||
} else {
|
||||
$cols = @odbc_fetch_into($result, $arr);
|
||||
}
|
||||
if (!$cols) {
|
||||
return null;
|
||||
}
|
||||
if ($fetchmode !== DB_FETCHMODE_ORDERED) {
|
||||
for ($i = 0; $i < count($arr); $i++) {
|
||||
$colName = @odbc_field_name($result, $i + 1);
|
||||
$a[$colName] = $arr[$i];
|
||||
}
|
||||
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
|
||||
$a = array_change_key_case($a, CASE_LOWER);
|
||||
}
|
||||
$arr = $a;
|
||||
}
|
||||
if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
|
||||
$this->_rtrimArrayValues($arr);
|
||||
}
|
||||
if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
|
||||
$this->_convertNullArrayValuesToEmpty($arr);
|
||||
}
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ affectedRows()
|
||||
|
||||
/**
|
||||
* Deletes the result set and frees the memory occupied by the result set
|
||||
*
|
||||
* This method is not meant to be called directly. Use
|
||||
* DB_result::free() instead. It can't be declared "protected"
|
||||
* because DB_result is a separate object.
|
||||
*
|
||||
* @param resource $result PHP's query result resource
|
||||
*
|
||||
* @return bool TRUE on success, FALSE if $result is invalid
|
||||
*
|
||||
* @see DB_result::free()
|
||||
*/
|
||||
public function freeResult($result)
|
||||
{
|
||||
return is_resource($result) ? odbc_free_result($result) : false;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ numRows()
|
||||
|
||||
/**
|
||||
* Gets the number of columns in a result set
|
||||
*
|
||||
* This method is not meant to be called directly. Use
|
||||
* DB_result::numCols() instead. It can't be declared "protected"
|
||||
* because DB_result is a separate object.
|
||||
*
|
||||
* @param resource $result PHP's query result resource
|
||||
*
|
||||
* @return int|object
|
||||
*
|
||||
* @see DB_result::numCols()
|
||||
*/
|
||||
public function numCols($result)
|
||||
{
|
||||
$cols = @odbc_num_fields($result);
|
||||
if (!$cols) {
|
||||
return $this->odbcRaiseError();
|
||||
}
|
||||
return $cols;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ quoteIdentifier()
|
||||
|
||||
/**
|
||||
* Determines the number of rows affected by a data maniuplation query
|
||||
*
|
||||
* 0 is returned for queries that don't manipulate data.
|
||||
*
|
||||
* @return int|object
|
||||
*/
|
||||
public function affectedRows()
|
||||
{
|
||||
if (empty($this->affected)) { // In case of SELECT stms
|
||||
return 0;
|
||||
}
|
||||
$nrows = @odbc_num_rows($this->affected);
|
||||
if ($nrows == -1) {
|
||||
return $this->odbcRaiseError();
|
||||
}
|
||||
return $nrows;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ nextId()
|
||||
|
||||
/**
|
||||
* Gets the number of rows in a result set
|
||||
*
|
||||
* Not all ODBC drivers support this functionality. If they don't
|
||||
* a DB_Error object for DB_ERROR_UNSUPPORTED is returned.
|
||||
*
|
||||
* This method is not meant to be called directly. Use
|
||||
* DB_result::numRows() instead. It can't be declared "protected"
|
||||
* because DB_result is a separate object.
|
||||
*
|
||||
* @param resource $result PHP's query result resource
|
||||
*
|
||||
* @return int|object
|
||||
*
|
||||
* @see DB_result::numRows()
|
||||
*/
|
||||
public function numRows($result)
|
||||
{
|
||||
$nrows = @odbc_num_rows($result);
|
||||
if ($nrows == -1) {
|
||||
return $this->odbcRaiseError(DB_ERROR_UNSUPPORTED);
|
||||
}
|
||||
if ($nrows === false) {
|
||||
return $this->odbcRaiseError();
|
||||
}
|
||||
return $nrows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Quotes a string so it can be safely used as a table or column name
|
||||
*
|
||||
* Use 'mssql' as the dbsyntax in the DB DSN only if you've unchecked
|
||||
* "Use ANSI quoted identifiers" when setting up the ODBC data source.
|
||||
*
|
||||
* @param string $str identifier name to be quoted
|
||||
*
|
||||
* @return string quoted identifier string
|
||||
*
|
||||
* @see DB_common::quoteIdentifier()
|
||||
* @since Method available since Release 1.6.0
|
||||
*/
|
||||
public function quoteIdentifier($str)
|
||||
{
|
||||
switch ($this->dsn['dbsyntax']) {
|
||||
case 'access':
|
||||
return '[' . $str . ']';
|
||||
case 'mssql':
|
||||
case 'sybase':
|
||||
return '[' . str_replace(']', ']]', $str) . ']';
|
||||
case 'mysql':
|
||||
case 'mysqli':
|
||||
return '`' . $str . '`';
|
||||
default:
|
||||
return '"' . str_replace('"', '""', $str) . '"';
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ dropSequence()
|
||||
|
||||
/**
|
||||
* Returns the next free id in a sequence
|
||||
*
|
||||
* @param string $seq_name name of the sequence
|
||||
* @param boolean $ondemand when true, the seqence is automatically
|
||||
* created if it does not exist
|
||||
*
|
||||
* @return int|object
|
||||
* A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_common::nextID(), DB_common::getSequenceName(),
|
||||
* DB_odbc::createSequence(), DB_odbc::dropSequence()
|
||||
*/
|
||||
public function nextId($seq_name, $ondemand = true)
|
||||
{
|
||||
$seqname = $this->getSequenceName($seq_name);
|
||||
$repeat = 0;
|
||||
do {
|
||||
$this->pushErrorHandling(PEAR_ERROR_RETURN);
|
||||
$result = $this->query("update ${seqname} set id = id + 1");
|
||||
$this->popErrorHandling();
|
||||
if ($ondemand && DB::isError($result) &&
|
||||
$result->getCode() == DB_ERROR_NOSUCHTABLE) {
|
||||
$repeat = 1;
|
||||
$this->pushErrorHandling(PEAR_ERROR_RETURN);
|
||||
$result = $this->createSequence($seq_name);
|
||||
$this->popErrorHandling();
|
||||
if (DB::isError($result)) {
|
||||
return $this->raiseError($result);
|
||||
}
|
||||
$result = $this->query("insert into ${seqname} (id) values(0)");
|
||||
} else {
|
||||
$repeat = 0;
|
||||
}
|
||||
} while ($repeat);
|
||||
|
||||
if (DB::isError($result)) {
|
||||
return $this->raiseError($result);
|
||||
}
|
||||
|
||||
$result = $this->query("select id from ${seqname}");
|
||||
if (DB::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$row = $result->fetchRow(DB_FETCHMODE_ORDERED);
|
||||
if (DB::isError($row || !$row)) {
|
||||
return $row;
|
||||
}
|
||||
|
||||
return $row[0];
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ autoCommit()
|
||||
|
||||
/**
|
||||
* Creates a new sequence
|
||||
*
|
||||
* @param string $seq_name name of the new sequence
|
||||
*
|
||||
* @return int DB_OK on success. A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_common::createSequence(), DB_common::getSequenceName(),
|
||||
* DB_odbc::nextID(), DB_odbc::dropSequence()
|
||||
*/
|
||||
public function createSequence($seq_name)
|
||||
{
|
||||
return $this->query('CREATE TABLE '
|
||||
. $this->getSequenceName($seq_name)
|
||||
. ' (id integer NOT NULL,'
|
||||
. ' PRIMARY KEY(id))');
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ commit()
|
||||
|
||||
/**
|
||||
* Deletes a sequence
|
||||
*
|
||||
* @param string $seq_name name of the sequence to be deleted
|
||||
*
|
||||
* @return int DB_OK on success. A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_common::dropSequence(), DB_common::getSequenceName(),
|
||||
* DB_odbc::nextID(), DB_odbc::createSequence()
|
||||
*/
|
||||
public function dropSequence($seq_name)
|
||||
{
|
||||
return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name));
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ rollback()
|
||||
|
||||
/**
|
||||
* Enables or disables automatic commits
|
||||
*
|
||||
* @param bool $onoff true turns it on, false turns it off
|
||||
*
|
||||
* @return int|object
|
||||
* doesn't support auto-committing transactions.
|
||||
*/
|
||||
public function autoCommit($onoff = false)
|
||||
{
|
||||
if (!@odbc_autocommit($this->connection, $onoff)) {
|
||||
return $this->odbcRaiseError();
|
||||
}
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ odbcRaiseError()
|
||||
|
||||
/**
|
||||
* Commits the current transaction
|
||||
*
|
||||
* @return int|object
|
||||
*/
|
||||
public function commit()
|
||||
{
|
||||
if (!@odbc_commit($this->connection)) {
|
||||
return $this->odbcRaiseError();
|
||||
}
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ errorNative()
|
||||
|
||||
/**
|
||||
* Reverts the current transaction
|
||||
*
|
||||
* @return int|object
|
||||
*/
|
||||
public function rollback()
|
||||
{
|
||||
if (!@odbc_rollback($this->connection)) {
|
||||
return $this->odbcRaiseError();
|
||||
}
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ tableInfo()
|
||||
|
||||
/**
|
||||
* Returns information about a table or a result set
|
||||
*
|
||||
* @param object|string $result DB_result object from a query or a
|
||||
* string containing the name of a table.
|
||||
* While this also accepts a query result
|
||||
* resource identifier, this behavior is
|
||||
* deprecated.
|
||||
* @param int $mode a valid tableInfo mode
|
||||
*
|
||||
* @return array|object
|
||||
* A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_common::tableInfo()
|
||||
* @since Method available since Release 1.7.0
|
||||
*/
|
||||
public function tableInfo($result, $mode = null)
|
||||
{
|
||||
if (is_string($result)) {
|
||||
/*
|
||||
* Probably received a table name.
|
||||
* Create a result resource identifier.
|
||||
*/
|
||||
$id = @odbc_exec($this->connection, "SELECT * FROM $result");
|
||||
if (!$id) {
|
||||
return $this->odbcRaiseError();
|
||||
}
|
||||
$got_string = true;
|
||||
} elseif (isset($result->result)) {
|
||||
/*
|
||||
* Probably received a result object.
|
||||
* Extract the result resource identifier.
|
||||
*/
|
||||
$id = $result->result;
|
||||
$got_string = false;
|
||||
} else {
|
||||
/*
|
||||
* Probably received a result resource identifier.
|
||||
* Copy it.
|
||||
* Deprecated. Here for compatibility only.
|
||||
*/
|
||||
$id = $result;
|
||||
$got_string = false;
|
||||
}
|
||||
|
||||
if (!is_resource($id)) {
|
||||
return $this->odbcRaiseError(DB_ERROR_NEED_MORE_DATA);
|
||||
}
|
||||
|
||||
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
|
||||
$case_func = 'strtolower';
|
||||
} else {
|
||||
$case_func = 'strval';
|
||||
}
|
||||
|
||||
$count = @odbc_num_fields($id);
|
||||
$res = array();
|
||||
|
||||
if ($mode) {
|
||||
$res['num_fields'] = $count;
|
||||
}
|
||||
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
$col = $i + 1;
|
||||
$res[$i] = array(
|
||||
'table' => $got_string ? $case_func($result) : '',
|
||||
'name' => $case_func(@odbc_field_name($id, $col)),
|
||||
'type' => @odbc_field_type($id, $col),
|
||||
'len' => @odbc_field_len($id, $col),
|
||||
'flags' => '',
|
||||
);
|
||||
if ($mode & DB_TABLEINFO_ORDER) {
|
||||
$res['order'][$res[$i]['name']] = $i;
|
||||
}
|
||||
if ($mode & DB_TABLEINFO_ORDERTABLE) {
|
||||
$res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
|
||||
}
|
||||
}
|
||||
|
||||
// free the result only if we were called on a table
|
||||
if ($got_string) {
|
||||
@odbc_free_result($id);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ getSpecialQuery()
|
||||
|
||||
/**
|
||||
* Obtains the query string needed for listing a given type of objects
|
||||
*
|
||||
* Thanks to symbol1@gmail.com and Philippe.Jausions@11abacus.com.
|
||||
*
|
||||
* @param string $type the kind of objects you want to retrieve
|
||||
*
|
||||
* @return array|string
|
||||
*
|
||||
* @access protected
|
||||
* @see DB_common::getListOf()
|
||||
* @since Method available since Release 1.7.0
|
||||
*/
|
||||
public function getSpecialQuery($type)
|
||||
{
|
||||
switch ($type) {
|
||||
case 'databases':
|
||||
if (!function_exists('odbc_data_source')) {
|
||||
return null;
|
||||
}
|
||||
$res = @odbc_data_source($this->connection, SQL_FETCH_FIRST);
|
||||
if (is_array($res)) {
|
||||
$out = array($res['server']);
|
||||
while ($res = @odbc_data_source(
|
||||
$this->connection,
|
||||
SQL_FETCH_NEXT
|
||||
)) {
|
||||
$out[] = $res['server'];
|
||||
}
|
||||
return $out;
|
||||
} else {
|
||||
return $this->odbcRaiseError();
|
||||
}
|
||||
break;
|
||||
case 'tables':
|
||||
case 'schema.tables':
|
||||
$keep = 'TABLE';
|
||||
break;
|
||||
case 'views':
|
||||
$keep = 'VIEW';
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* Removing non-conforming items in the while loop rather than
|
||||
* in the odbc_tables() call because some backends choke on this:
|
||||
* odbc_tables($this->connection, '', '', '', 'TABLE')
|
||||
*/
|
||||
$res = @odbc_tables($this->connection);
|
||||
if (!$res) {
|
||||
return $this->odbcRaiseError();
|
||||
}
|
||||
$out = array();
|
||||
while ($row = odbc_fetch_array($res)) {
|
||||
if ($row['TABLE_TYPE'] != $keep) {
|
||||
continue;
|
||||
}
|
||||
if ($type == 'schema.tables') {
|
||||
$out[] = $row['TABLE_SCHEM'] . '.' . $row['TABLE_NAME'];
|
||||
} else {
|
||||
$out[] = $row['TABLE_NAME'];
|
||||
}
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
// }}}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* tab-width: 4
|
||||
* c-basic-offset: 4
|
||||
* End:
|
||||
*/
|
1131
extlib/DB/pgsql.php
1131
extlib/DB/pgsql.php
File diff suppressed because it is too large
Load Diff
@ -1,978 +0,0 @@
|
||||
<?php
|
||||
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
||||
|
||||
/**
|
||||
* The PEAR DB driver for PHP's sqlite extension
|
||||
* for interacting with SQLite databases
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENSE: This source file is subject to version 3.0 of the PHP license
|
||||
* that is available through the world-wide-web at the following URI:
|
||||
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
|
||||
* the PHP License and are unable to obtain it through the web, please
|
||||
* send a note to license@php.net so we can mail you a copy immediately.
|
||||
*
|
||||
* @category Database
|
||||
* @package DB
|
||||
* @author Urs Gehrig <urs@circle.ch>
|
||||
* @author Mika Tuupola <tuupola@appelsiini.net>
|
||||
* @author Daniel Convissor <danielc@php.net>
|
||||
* @copyright 1997-2007 The PHP Group
|
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0 3.0
|
||||
* @version CVS: $Id$
|
||||
* @link http://pear.php.net/package/DB
|
||||
*/
|
||||
|
||||
/**
|
||||
* Obtain the DB_common class so it can be extended from
|
||||
*/
|
||||
//require_once 'DB/common.php';
|
||||
require_once 'common.php';
|
||||
|
||||
/**
|
||||
* The methods PEAR DB uses to interact with PHP's sqlite extension
|
||||
* for interacting with SQLite databases
|
||||
*
|
||||
* These methods overload the ones declared in DB_common.
|
||||
*
|
||||
* NOTICE: This driver needs PHP's track_errors ini setting to be on.
|
||||
* It is automatically turned on when connecting to the database.
|
||||
* Make sure your scripts don't turn it off.
|
||||
*
|
||||
* @category Database
|
||||
* @package DB
|
||||
* @author Urs Gehrig <urs@circle.ch>
|
||||
* @author Mika Tuupola <tuupola@appelsiini.net>
|
||||
* @author Daniel Convissor <danielc@php.net>
|
||||
* @copyright 1997-2007 The PHP Group
|
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0 3.0
|
||||
* @version Release: 1.9.2
|
||||
* @link http://pear.php.net/package/DB
|
||||
*/
|
||||
class DB_sqlite extends DB_common
|
||||
{
|
||||
// {{{ properties
|
||||
|
||||
/**
|
||||
* The DB driver type (mysql, oci8, odbc, etc.)
|
||||
* @var string
|
||||
*/
|
||||
public $phptype = 'sqlite';
|
||||
|
||||
/**
|
||||
* The database syntax variant to be used (db2, access, etc.), if any
|
||||
* @var string
|
||||
*/
|
||||
public $dbsyntax = 'sqlite';
|
||||
|
||||
/**
|
||||
* The capabilities of this DB implementation
|
||||
*
|
||||
* The 'new_link' element contains the PHP version that first provided
|
||||
* new_link support for this DBMS. Contains false if it's unsupported.
|
||||
*
|
||||
* Meaning of the 'limit' element:
|
||||
* + 'emulate' = emulate with fetch row by number
|
||||
* + 'alter' = alter the query
|
||||
* + false = skip rows
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $features = array(
|
||||
'limit' => 'alter',
|
||||
'new_link' => false,
|
||||
'numrows' => true,
|
||||
'pconnect' => true,
|
||||
'prepare' => false,
|
||||
'ssl' => false,
|
||||
'transactions' => false,
|
||||
);
|
||||
|
||||
/**
|
||||
* A mapping of native error codes to DB error codes
|
||||
*
|
||||
* {@internal Error codes according to sqlite_exec. See the online
|
||||
* manual at http://sqlite.org/c_interface.html for info.
|
||||
* This error handling based on sqlite_exec is not yet implemented.}}
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $errorcode_map = array();
|
||||
|
||||
/**
|
||||
* The raw database connection created by PHP
|
||||
* @var resource
|
||||
*/
|
||||
public $connection;
|
||||
|
||||
/**
|
||||
* The DSN information for connecting to a database
|
||||
* @var array
|
||||
*/
|
||||
public $dsn = array();
|
||||
|
||||
|
||||
/**
|
||||
* SQLite data types
|
||||
*
|
||||
* @link http://www.sqlite.org/datatypes.html
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $keywords = array(
|
||||
'BLOB' => '',
|
||||
'BOOLEAN' => '',
|
||||
'CHARACTER' => '',
|
||||
'CLOB' => '',
|
||||
'FLOAT' => '',
|
||||
'INTEGER' => '',
|
||||
'KEY' => '',
|
||||
'NATIONAL' => '',
|
||||
'NUMERIC' => '',
|
||||
'NVARCHAR' => '',
|
||||
'PRIMARY' => '',
|
||||
'TEXT' => '',
|
||||
'TIMESTAMP' => '',
|
||||
'UNIQUE' => '',
|
||||
'VARCHAR' => '',
|
||||
'VARYING' => '',
|
||||
);
|
||||
|
||||
/**
|
||||
* The most recent error message from $php_errormsg
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
public $_lasterror = '';
|
||||
|
||||
|
||||
// }}}
|
||||
// {{{ constructor
|
||||
|
||||
/**
|
||||
* This constructor calls <kbd>parent::__construct()</kbd>
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ connect()
|
||||
|
||||
/**
|
||||
* Connect to the database server, log in and open the database
|
||||
*
|
||||
* Don't call this method directly. Use DB::connect() instead.
|
||||
*
|
||||
* PEAR DB's sqlite driver supports the following extra DSN options:
|
||||
* + mode The permissions for the database file, in four digit
|
||||
* chmod octal format (eg "0600").
|
||||
*
|
||||
* Example of connecting to a database in read-only mode:
|
||||
* <code>
|
||||
* require_once 'DB.php';
|
||||
*
|
||||
* $dsn = 'sqlite:///path/and/name/of/db/file?mode=0400';
|
||||
* $options = array(
|
||||
* 'portability' => DB_PORTABILITY_ALL,
|
||||
* );
|
||||
*
|
||||
* $db = DB::connect($dsn, $options);
|
||||
* if ((new PEAR)->isError($db)) {
|
||||
* die($db->getMessage());
|
||||
* }
|
||||
* </code>
|
||||
*
|
||||
* @param array $dsn the data source name
|
||||
* @param bool $persistent should the connection be persistent?
|
||||
*
|
||||
* @return int|object
|
||||
*/
|
||||
public function connect($dsn, $persistent = false)
|
||||
{
|
||||
if (!PEAR::loadExtension('sqlite')) {
|
||||
return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
|
||||
}
|
||||
|
||||
$this->dsn = $dsn;
|
||||
if ($dsn['dbsyntax']) {
|
||||
$this->dbsyntax = $dsn['dbsyntax'];
|
||||
}
|
||||
|
||||
if (!$dsn['database']) {
|
||||
return $this->sqliteRaiseError(DB_ERROR_ACCESS_VIOLATION);
|
||||
}
|
||||
|
||||
if ($dsn['database'] !== ':memory:') {
|
||||
if (!file_exists($dsn['database'])) {
|
||||
if (!touch($dsn['database'])) {
|
||||
return $this->sqliteRaiseError(DB_ERROR_NOT_FOUND);
|
||||
}
|
||||
if (!isset($dsn['mode']) ||
|
||||
!is_numeric($dsn['mode'])) {
|
||||
$mode = 0644;
|
||||
} else {
|
||||
$mode = octdec($dsn['mode']);
|
||||
}
|
||||
if (!chmod($dsn['database'], $mode)) {
|
||||
return $this->sqliteRaiseError(DB_ERROR_NOT_FOUND);
|
||||
}
|
||||
if (!file_exists($dsn['database'])) {
|
||||
return $this->sqliteRaiseError(DB_ERROR_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
if (!is_file($dsn['database'])) {
|
||||
return $this->sqliteRaiseError(DB_ERROR_INVALID);
|
||||
}
|
||||
if (!is_readable($dsn['database'])) {
|
||||
return $this->sqliteRaiseError(DB_ERROR_ACCESS_VIOLATION);
|
||||
}
|
||||
}
|
||||
|
||||
$connect_function = $persistent ? 'sqlite_popen' : 'sqlite_open';
|
||||
|
||||
// track_errors must remain on for simpleQuery()
|
||||
@ini_set('track_errors', 1);
|
||||
$php_errormsg = '';
|
||||
|
||||
if (!$this->connection = @$connect_function($dsn['database'])) {
|
||||
return $this->raiseError(
|
||||
DB_ERROR_NODBSELECTED,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
$php_errormsg
|
||||
);
|
||||
}
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ disconnect()
|
||||
|
||||
/**
|
||||
* Produces a DB_Error object regarding the current problem
|
||||
*
|
||||
* @param int $errno if the error is being manually raised pass a
|
||||
* DB_ERROR* constant here. If this isn't passed
|
||||
* the error information gathered from the DBMS.
|
||||
*
|
||||
* @return object the DB_Error object
|
||||
*
|
||||
* @see DB_common::raiseError(),
|
||||
* DB_sqlite::errorNative(), DB_sqlite::errorCode()
|
||||
*/
|
||||
public function sqliteRaiseError($errno = null)
|
||||
{
|
||||
$native = $this->errorNative();
|
||||
if ($errno === null) {
|
||||
$errno = $this->errorCode($native);
|
||||
}
|
||||
|
||||
$errorcode = @sqlite_last_error($this->connection);
|
||||
$userinfo = "$errorcode ** $this->last_query";
|
||||
|
||||
return $this->raiseError($errno, null, null, $userinfo, $native);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ simpleQuery()
|
||||
|
||||
/**
|
||||
* Gets the DBMS' native error message produced by the last query
|
||||
*
|
||||
* {@internal This is used to retrieve more meaningfull error messages
|
||||
* because sqlite_last_error() does not provide adequate info.}}
|
||||
*
|
||||
* @return string the DBMS' error message
|
||||
*/
|
||||
public function errorNative()
|
||||
{
|
||||
return $this->_lasterror;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ nextResult()
|
||||
|
||||
/**
|
||||
* Determines PEAR::DB error code from the database's text error message
|
||||
*
|
||||
* @param string $errormsg the error message returned from the database
|
||||
*
|
||||
* @return integer the DB error number
|
||||
*/
|
||||
public function errorCode($errormsg)
|
||||
{
|
||||
static $error_regexps;
|
||||
|
||||
// PHP 5.2+ prepends the function name to $php_errormsg, so we need
|
||||
// this hack to work around it, per bug #9599.
|
||||
$errormsg = preg_replace('/^sqlite[a-z_]+\(\): /', '', $errormsg);
|
||||
|
||||
if (!isset($error_regexps)) {
|
||||
$error_regexps = array(
|
||||
'/^no such table:/' => DB_ERROR_NOSUCHTABLE,
|
||||
'/^no such index:/' => DB_ERROR_NOT_FOUND,
|
||||
'/^(table|index) .* already exists$/' => DB_ERROR_ALREADY_EXISTS,
|
||||
'/PRIMARY KEY must be unique/i' => DB_ERROR_CONSTRAINT,
|
||||
'/is not unique/' => DB_ERROR_CONSTRAINT,
|
||||
'/columns .* are not unique/i' => DB_ERROR_CONSTRAINT,
|
||||
'/uniqueness constraint failed/' => DB_ERROR_CONSTRAINT,
|
||||
'/may not be NULL/' => DB_ERROR_CONSTRAINT_NOT_NULL,
|
||||
'/^no such column:/' => DB_ERROR_NOSUCHFIELD,
|
||||
'/no column named/' => DB_ERROR_NOSUCHFIELD,
|
||||
'/column not present in both tables/i' => DB_ERROR_NOSUCHFIELD,
|
||||
'/^near ".*": syntax error$/' => DB_ERROR_SYNTAX,
|
||||
'/[0-9]+ values for [0-9]+ columns/i' => DB_ERROR_VALUE_COUNT_ON_ROW,
|
||||
);
|
||||
}
|
||||
foreach ($error_regexps as $regexp => $code) {
|
||||
if (preg_match($regexp, $errormsg)) {
|
||||
return $code;
|
||||
}
|
||||
}
|
||||
// Fall back to DB_ERROR if there was no mapping.
|
||||
return DB_ERROR;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ fetchInto()
|
||||
|
||||
/**
|
||||
* Disconnects from the database server
|
||||
*
|
||||
* @return bool|void
|
||||
*/
|
||||
public function disconnect()
|
||||
{
|
||||
$ret = @sqlite_close($this->connection);
|
||||
$this->connection = null;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ freeResult()
|
||||
|
||||
/**
|
||||
* Sends a query to the database server
|
||||
*
|
||||
* NOTICE: This method needs PHP's track_errors ini setting to be on.
|
||||
* It is automatically turned on when connecting to the database.
|
||||
* Make sure your scripts don't turn it off.
|
||||
*
|
||||
* @param string the SQL query string
|
||||
*
|
||||
* @return mixed + a PHP result resrouce for successful SELECT queries
|
||||
* + the DB_OK constant for other successful queries
|
||||
* + a DB_Error object on failure
|
||||
*/
|
||||
public function simpleQuery($query)
|
||||
{
|
||||
$ismanip = $this->_checkManip($query);
|
||||
$this->last_query = $query;
|
||||
$query = $this->modifyQuery($query);
|
||||
|
||||
$php_errormsg = '';
|
||||
|
||||
$result = @sqlite_query($query, $this->connection);
|
||||
$this->_lasterror = $php_errormsg ? $php_errormsg : '';
|
||||
|
||||
$this->result = $result;
|
||||
if (!$this->result) {
|
||||
return $this->sqliteRaiseError(null);
|
||||
}
|
||||
|
||||
// sqlite_query() seems to allways return a resource
|
||||
// so cant use that. Using $ismanip instead
|
||||
if (!$ismanip) {
|
||||
$numRows = $this->numRows($result);
|
||||
if (is_object($numRows)) {
|
||||
// we've got PEAR_Error
|
||||
return $numRows;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ numCols()
|
||||
|
||||
/**
|
||||
* Changes a query string for various DBMS specific reasons
|
||||
*
|
||||
* This little hack lets you know how many rows were deleted
|
||||
* when running a "DELETE FROM table" query. Only implemented
|
||||
* if the DB_PORTABILITY_DELETE_COUNT portability option is on.
|
||||
*
|
||||
* @param string $query the query string to modify
|
||||
*
|
||||
* @return string the modified query string
|
||||
*
|
||||
* @access protected
|
||||
* @see DB_common::setOption()
|
||||
*/
|
||||
public function modifyQuery($query)
|
||||
{
|
||||
if ($this->options['portability'] & DB_PORTABILITY_DELETE_COUNT) {
|
||||
if (preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $query)) {
|
||||
$query = preg_replace(
|
||||
'/^\s*DELETE\s+FROM\s+(\S+)\s*$/',
|
||||
'DELETE FROM \1 WHERE 1=1',
|
||||
$query
|
||||
);
|
||||
}
|
||||
}
|
||||
return $query;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ numRows()
|
||||
|
||||
/**
|
||||
* Gets the number of rows in a result set
|
||||
*
|
||||
* This method is not meant to be called directly. Use
|
||||
* DB_result::numRows() instead. It can't be declared "protected"
|
||||
* because DB_result is a separate object.
|
||||
*
|
||||
* @param resource $result PHP's query result resource
|
||||
*
|
||||
* @return int|object
|
||||
*
|
||||
* @see DB_result::numRows()
|
||||
*/
|
||||
public function numRows($result)
|
||||
{
|
||||
$rows = @sqlite_num_rows($result);
|
||||
if ($rows === null) {
|
||||
return $this->sqliteRaiseError();
|
||||
}
|
||||
return $rows;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ affected()
|
||||
|
||||
/**
|
||||
* Move the internal sqlite result pointer to the next available result
|
||||
*
|
||||
* @param resource $result the valid sqlite result resource
|
||||
*
|
||||
* @return bool true if a result is available otherwise return false
|
||||
*/
|
||||
public function nextResult($result)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ dropSequence()
|
||||
|
||||
/**
|
||||
* Places a row from the result set into the given array
|
||||
*
|
||||
* Formating of the array and the data therein are configurable.
|
||||
* See DB_result::fetchInto() for more information.
|
||||
*
|
||||
* This method is not meant to be called directly. Use
|
||||
* DB_result::fetchInto() instead. It can't be declared "protected"
|
||||
* because DB_result is a separate object.
|
||||
*
|
||||
* @param resource $result the query result resource
|
||||
* @param array $arr the referenced array to put the data in
|
||||
* @param int $fetchmode how the resulting array should be indexed
|
||||
* @param int $rownum the row number to fetch (0 = first row)
|
||||
*
|
||||
* @return mixed DB_OK on success, NULL when the end of a result set is
|
||||
* reached or on failure
|
||||
*
|
||||
* @see DB_result::fetchInto()
|
||||
*/
|
||||
public function fetchInto($result, &$arr, $fetchmode, $rownum = null)
|
||||
{
|
||||
if ($rownum !== null) {
|
||||
if (!@sqlite_seek($this->result, $rownum)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if ($fetchmode & DB_FETCHMODE_ASSOC) {
|
||||
$arr = @sqlite_fetch_array($result, SQLITE_ASSOC);
|
||||
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) {
|
||||
$arr = array_change_key_case($arr, CASE_LOWER);
|
||||
}
|
||||
|
||||
/* Remove extraneous " characters from the fields in the result.
|
||||
* Fixes bug #11716. */
|
||||
if (is_array($arr) && count($arr) > 0) {
|
||||
$strippedArr = array();
|
||||
foreach ($arr as $field => $value) {
|
||||
$strippedArr[trim($field, '"')] = $value;
|
||||
}
|
||||
$arr = $strippedArr;
|
||||
}
|
||||
} else {
|
||||
$arr = @sqlite_fetch_array($result, SQLITE_NUM);
|
||||
}
|
||||
if (!$arr) {
|
||||
return null;
|
||||
}
|
||||
if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
|
||||
/*
|
||||
* Even though this DBMS already trims output, we do this because
|
||||
* a field might have intentional whitespace at the end that
|
||||
* gets removed by DB_PORTABILITY_RTRIM under another driver.
|
||||
*/
|
||||
$this->_rtrimArrayValues($arr);
|
||||
}
|
||||
if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
|
||||
$this->_convertNullArrayValuesToEmpty($arr);
|
||||
}
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the result set and frees the memory occupied by the result set
|
||||
*
|
||||
* This method is not meant to be called directly. Use
|
||||
* DB_result::free() instead. It can't be declared "protected"
|
||||
* because DB_result is a separate object.
|
||||
*
|
||||
* @param resource $result PHP's query result resource
|
||||
*
|
||||
* @return bool TRUE on success, FALSE if $result is invalid
|
||||
*
|
||||
* @see DB_result::free()
|
||||
*/
|
||||
public function freeResult(&$result)
|
||||
{
|
||||
// XXX No native free?
|
||||
if (!is_resource($result)) {
|
||||
return false;
|
||||
}
|
||||
$result = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ nextId()
|
||||
|
||||
/**
|
||||
* Gets the number of columns in a result set
|
||||
*
|
||||
* This method is not meant to be called directly. Use
|
||||
* DB_result::numCols() instead. It can't be declared "protected"
|
||||
* because DB_result is a separate object.
|
||||
*
|
||||
* @param resource $result PHP's query result resource
|
||||
*
|
||||
* @return int|object
|
||||
*
|
||||
* @see DB_result::numCols()
|
||||
*/
|
||||
public function numCols($result)
|
||||
{
|
||||
$cols = @sqlite_num_fields($result);
|
||||
if (!$cols) {
|
||||
return $this->sqliteRaiseError();
|
||||
}
|
||||
return $cols;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ getDbFileStats()
|
||||
|
||||
/**
|
||||
* Determines the number of rows affected by a data maniuplation query
|
||||
*
|
||||
* 0 is returned for queries that don't manipulate data.
|
||||
*
|
||||
* @return int the number of rows. A DB_Error object on failure.
|
||||
*/
|
||||
public function affectedRows()
|
||||
{
|
||||
return @sqlite_changes($this->connection);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ escapeSimple()
|
||||
|
||||
/**
|
||||
* Deletes a sequence
|
||||
*
|
||||
* @param string $seq_name name of the sequence to be deleted
|
||||
*
|
||||
* @return int DB_OK on success. A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_common::dropSequence(), DB_common::getSequenceName(),
|
||||
* DB_sqlite::nextID(), DB_sqlite::createSequence()
|
||||
*/
|
||||
public function dropSequence($seq_name)
|
||||
{
|
||||
return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name));
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ modifyLimitQuery()
|
||||
|
||||
/**
|
||||
* Returns the next free id in a sequence
|
||||
*
|
||||
* @param string $seq_name name of the sequence
|
||||
* @param boolean $ondemand when true, the seqence is automatically
|
||||
* created if it does not exist
|
||||
*
|
||||
* @return int|object
|
||||
* A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_common::nextID(), DB_common::getSequenceName(),
|
||||
* DB_sqlite::createSequence(), DB_sqlite::dropSequence()
|
||||
*/
|
||||
public function nextId($seq_name, $ondemand = true)
|
||||
{
|
||||
$seqname = $this->getSequenceName($seq_name);
|
||||
|
||||
do {
|
||||
$repeat = 0;
|
||||
$this->pushErrorHandling(PEAR_ERROR_RETURN);
|
||||
$result = $this->query("INSERT INTO $seqname (id) VALUES (NULL)");
|
||||
$this->popErrorHandling();
|
||||
if ($result === DB_OK) {
|
||||
$id = @sqlite_last_insert_rowid($this->connection);
|
||||
if ($id != 0) {
|
||||
return $id;
|
||||
}
|
||||
} elseif ($ondemand && DB::isError($result) &&
|
||||
$result->getCode() == DB_ERROR_NOSUCHTABLE) {
|
||||
$result = $this->createSequence($seq_name);
|
||||
if (DB::isError($result)) {
|
||||
return $this->raiseError($result);
|
||||
} else {
|
||||
$repeat = 1;
|
||||
}
|
||||
}
|
||||
} while ($repeat);
|
||||
|
||||
return $this->raiseError($result);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ modifyQuery()
|
||||
|
||||
/**
|
||||
* Creates a new sequence
|
||||
*
|
||||
* @param string $seq_name name of the new sequence
|
||||
*
|
||||
* @return int DB_OK on success. A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_common::createSequence(), DB_common::getSequenceName(),
|
||||
* DB_sqlite::nextID(), DB_sqlite::dropSequence()
|
||||
*/
|
||||
public function createSequence($seq_name)
|
||||
{
|
||||
$seqname = $this->getSequenceName($seq_name);
|
||||
$query = 'CREATE TABLE ' . $seqname .
|
||||
' (id INTEGER UNSIGNED PRIMARY KEY) ';
|
||||
$result = $this->query($query);
|
||||
if (DB::isError($result)) {
|
||||
return ($result);
|
||||
}
|
||||
$query = "CREATE TRIGGER ${seqname}_cleanup AFTER INSERT ON $seqname
|
||||
BEGIN
|
||||
DELETE FROM $seqname WHERE id<LAST_INSERT_ROWID();
|
||||
END ";
|
||||
$result = $this->query($query);
|
||||
//if (DB::isError($result)) {
|
||||
return ($result);
|
||||
//}
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ sqliteRaiseError()
|
||||
|
||||
/**
|
||||
* Get the file stats for the current database
|
||||
*
|
||||
* Possible arguments are dev, ino, mode, nlink, uid, gid, rdev, size,
|
||||
* atime, mtime, ctime, blksize, blocks or a numeric key between
|
||||
* 0 and 12.
|
||||
*
|
||||
* @param string $arg the array key for stats()
|
||||
*
|
||||
* @return mixed an array on an unspecified key, integer on a passed
|
||||
* arg and false at a stats error
|
||||
*/
|
||||
public function getDbFileStats($arg = '')
|
||||
{
|
||||
$stats = stat($this->dsn['database']);
|
||||
if ($stats == false) {
|
||||
return false;
|
||||
}
|
||||
if (is_array($stats)) {
|
||||
if (is_numeric($arg)) {
|
||||
if (((int)$arg <= 12) & ((int)$arg >= 0)) {
|
||||
return false;
|
||||
}
|
||||
return $stats[$arg];
|
||||
}
|
||||
if (array_key_exists(trim($arg), $stats)) {
|
||||
return $stats[$arg];
|
||||
}
|
||||
}
|
||||
return $stats;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ errorNative()
|
||||
|
||||
/**
|
||||
* Escapes a string according to the current DBMS's standards
|
||||
*
|
||||
* In SQLite, this makes things safe for inserts/updates, but may
|
||||
* cause problems when performing text comparisons against columns
|
||||
* containing binary data. See the
|
||||
* {@link http://php.net/sqlite_escape_string PHP manual} for more info.
|
||||
*
|
||||
* @param string $str the string to be escaped
|
||||
*
|
||||
* @return string the escaped string
|
||||
*
|
||||
* @since Method available since Release 1.6.1
|
||||
* @see DB_common::escapeSimple()
|
||||
*/
|
||||
public function escapeSimple($str)
|
||||
{
|
||||
return @sqlite_escape_string($str);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ errorCode()
|
||||
|
||||
/**
|
||||
* Adds LIMIT clauses to a query string according to current DBMS standards
|
||||
*
|
||||
* @param string $query the query to modify
|
||||
* @param int $from the row to start to fetching (0 = the first row)
|
||||
* @param int $count the numbers of rows to fetch
|
||||
* @param mixed $params array, string or numeric data to be used in
|
||||
* execution of the statement. Quantity of items
|
||||
* passed must match quantity of placeholders in
|
||||
* query: meaning 1 placeholder for non-array
|
||||
* parameters or 1 placeholder per array element.
|
||||
*
|
||||
* @return string the query string with LIMIT clauses added
|
||||
*
|
||||
* @access protected
|
||||
*/
|
||||
public function modifyLimitQuery($query, $from, $count, $params = array())
|
||||
{
|
||||
return "$query LIMIT $count OFFSET $from";
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ tableInfo()
|
||||
|
||||
/**
|
||||
* Returns information about a table
|
||||
*
|
||||
* @param string $result a string containing the name of a table
|
||||
* @param int $mode a valid tableInfo mode
|
||||
*
|
||||
* @return array|object
|
||||
* A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_common::tableInfo()
|
||||
* @since Method available since Release 1.7.0
|
||||
*/
|
||||
public function tableInfo($result, $mode = null)
|
||||
{
|
||||
if (is_string($result)) {
|
||||
/*
|
||||
* Probably received a table name.
|
||||
* Create a result resource identifier.
|
||||
*/
|
||||
$id = @sqlite_array_query(
|
||||
$this->connection,
|
||||
"PRAGMA table_info('$result');",
|
||||
SQLITE_ASSOC
|
||||
);
|
||||
$got_string = true;
|
||||
} else {
|
||||
$this->last_query = '';
|
||||
return $this->raiseError(
|
||||
DB_ERROR_NOT_CAPABLE,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
'This DBMS can not obtain tableInfo' .
|
||||
' from result sets'
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
|
||||
$case_func = 'strtolower';
|
||||
} else {
|
||||
$case_func = 'strval';
|
||||
}
|
||||
|
||||
$count = count($id);
|
||||
$res = array();
|
||||
|
||||
if ($mode) {
|
||||
$res['num_fields'] = $count;
|
||||
}
|
||||
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
if (strpos($id[$i]['type'], '(') !== false) {
|
||||
$bits = explode('(', $id[$i]['type']);
|
||||
$type = $bits[0];
|
||||
$len = rtrim($bits[1], ')');
|
||||
} else {
|
||||
$type = $id[$i]['type'];
|
||||
$len = 0;
|
||||
}
|
||||
|
||||
$flags = '';
|
||||
if ($id[$i]['pk']) {
|
||||
$flags .= 'primary_key ';
|
||||
if (strtoupper($type) == 'INTEGER') {
|
||||
$flags .= 'auto_increment ';
|
||||
}
|
||||
}
|
||||
if ($id[$i]['notnull']) {
|
||||
$flags .= 'not_null ';
|
||||
}
|
||||
if ($id[$i]['dflt_value'] !== null) {
|
||||
$flags .= 'default_' . rawurlencode($id[$i]['dflt_value']);
|
||||
}
|
||||
$flags = trim($flags);
|
||||
|
||||
$res[$i] = array(
|
||||
'table' => $case_func($result),
|
||||
'name' => $case_func($id[$i]['name']),
|
||||
'type' => $type,
|
||||
'len' => $len,
|
||||
'flags' => $flags,
|
||||
);
|
||||
|
||||
if ($mode & DB_TABLEINFO_ORDER) {
|
||||
$res['order'][$res[$i]['name']] = $i;
|
||||
}
|
||||
if ($mode & DB_TABLEINFO_ORDERTABLE) {
|
||||
$res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
|
||||
}
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ getSpecialQuery()
|
||||
|
||||
/**
|
||||
* Obtains the query string needed for listing a given type of objects
|
||||
*
|
||||
* @param string $type the kind of objects you want to retrieve
|
||||
* @param array $args SQLITE DRIVER ONLY: a private array of arguments
|
||||
* used by the getSpecialQuery(). Do not use
|
||||
* this directly.
|
||||
*
|
||||
* @return string the SQL query string or null if the driver doesn't
|
||||
* support the object type requested
|
||||
*
|
||||
* @access protected
|
||||
* @see DB_common::getListOf()
|
||||
*/
|
||||
public function getSpecialQuery($type, $args = array())
|
||||
{
|
||||
if (!is_array($args)) {
|
||||
return $this->raiseError(
|
||||
'no key specified',
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
'Argument has to be an array.'
|
||||
);
|
||||
}
|
||||
|
||||
switch ($type) {
|
||||
case 'master':
|
||||
return 'SELECT * FROM sqlite_master;';
|
||||
case 'tables':
|
||||
return "SELECT name FROM sqlite_master WHERE type='table' "
|
||||
. 'UNION ALL SELECT name FROM sqlite_temp_master '
|
||||
. "WHERE type='table' ORDER BY name;";
|
||||
case 'schema':
|
||||
return 'SELECT sql FROM (SELECT * FROM sqlite_master '
|
||||
. 'UNION ALL SELECT * FROM sqlite_temp_master) '
|
||||
. "WHERE type!='meta' "
|
||||
. 'ORDER BY tbl_name, type DESC, name;';
|
||||
case 'schemax':
|
||||
case 'schema_x':
|
||||
/*
|
||||
* Use like:
|
||||
* $res = $db->query($db->getSpecialQuery('schema_x',
|
||||
* array('table' => 'table3')));
|
||||
*/
|
||||
return 'SELECT sql FROM (SELECT * FROM sqlite_master '
|
||||
. 'UNION ALL SELECT * FROM sqlite_temp_master) '
|
||||
. "WHERE tbl_name LIKE '{$args['table']}' "
|
||||
. "AND type!='meta' "
|
||||
. 'ORDER BY type DESC, name;';
|
||||
case 'alter':
|
||||
/*
|
||||
* SQLite does not support ALTER TABLE; this is a helper query
|
||||
* to handle this. 'table' represents the table name, 'rows'
|
||||
* the news rows to create, 'save' the row(s) to keep _with_
|
||||
* the data.
|
||||
*
|
||||
* Use like:
|
||||
* $args = array(
|
||||
* 'table' => $table,
|
||||
* 'rows' => "id INTEGER PRIMARY KEY, firstname TEXT, surname TEXT, datetime TEXT",
|
||||
* 'save' => "NULL, titel, content, datetime"
|
||||
* );
|
||||
* $res = $db->query( $db->getSpecialQuery('alter', $args));
|
||||
*/
|
||||
$rows = strtr($args['rows'], $this->keywords);
|
||||
|
||||
$q = array(
|
||||
'BEGIN TRANSACTION',
|
||||
"CREATE TEMPORARY TABLE {$args['table']}_backup ({$args['rows']})",
|
||||
"INSERT INTO {$args['table']}_backup SELECT {$args['save']} FROM {$args['table']}",
|
||||
"DROP TABLE {$args['table']}",
|
||||
"CREATE TABLE {$args['table']} ({$args['rows']})",
|
||||
"INSERT INTO {$args['table']} SELECT {$rows} FROM {$args['table']}_backup",
|
||||
"DROP TABLE {$args['table']}_backup",
|
||||
'COMMIT',
|
||||
);
|
||||
|
||||
/*
|
||||
* This is a dirty hack, since the above query will not get
|
||||
* executed with a single query call so here the query method
|
||||
* will be called directly and return a select instead.
|
||||
*/
|
||||
foreach ($q as $query) {
|
||||
$this->query($query);
|
||||
}
|
||||
return "SELECT * FROM {$args['table']};";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* tab-width: 4
|
||||
* c-basic-offset: 4
|
||||
* End:
|
||||
*/
|
@ -1,548 +0,0 @@
|
||||
<?php
|
||||
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
||||
|
||||
/**
|
||||
* Provides an object interface to a table row
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENSE: This source file is subject to version 3.0 of the PHP license
|
||||
* that is available through the world-wide-web at the following URI:
|
||||
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
|
||||
* the PHP License and are unable to obtain it through the web, please
|
||||
* send a note to license@php.net so we can mail you a copy immediately.
|
||||
*
|
||||
* @category Database
|
||||
* @package DB
|
||||
* @author Stig Bakken <stig@php.net>
|
||||
* @copyright 1997-2007 The PHP Group
|
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0
|
||||
* @version CVS: $Id$
|
||||
* @link http://pear.php.net/package/DB
|
||||
*/
|
||||
|
||||
/**
|
||||
* Obtain the DB class so it can be extended from
|
||||
*/
|
||||
require_once 'DB.php';
|
||||
|
||||
/**
|
||||
* Provides an object interface to a table row
|
||||
*
|
||||
* It lets you add, delete and change rows using objects rather than SQL
|
||||
* statements.
|
||||
*
|
||||
* @category Database
|
||||
* @package DB
|
||||
* @author Stig Bakken <stig@php.net>
|
||||
* @copyright 1997-2007 The PHP Group
|
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0
|
||||
* @version Release: 1.9.2
|
||||
* @link http://pear.php.net/package/DB
|
||||
*/
|
||||
class DB_storage extends PEAR
|
||||
{
|
||||
// {{{ properties
|
||||
|
||||
/** the name of the table (or view, if the backend database supports
|
||||
* updates in views) we hold data from */
|
||||
public $_table = null;
|
||||
|
||||
/** which column(s) in the table contains primary keys, can be a
|
||||
* string for single-column primary keys, or an array of strings
|
||||
* for multiple-column primary keys */
|
||||
public $_keycolumn = null;
|
||||
|
||||
/** DB connection handle used for all transactions */
|
||||
public $_dbh = null;
|
||||
|
||||
/** an assoc with the names of database fields stored as properties
|
||||
* in this object */
|
||||
public $_properties = array();
|
||||
|
||||
/** an assoc with the names of the properties in this object that
|
||||
* have been changed since they were fetched from the database */
|
||||
public $_changes = array();
|
||||
|
||||
/** flag that decides if data in this object can be changed.
|
||||
* objects that don't have their table's key column in their
|
||||
* property lists will be flagged as read-only. */
|
||||
public $_readonly = false;
|
||||
|
||||
/** function or method that implements a validator for fields that
|
||||
* are set, this validator function returns true if the field is
|
||||
* valid, false if not */
|
||||
public $_validator = null;
|
||||
|
||||
// }}}
|
||||
// {{{ constructor
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param $table string the name of the database table
|
||||
*
|
||||
* @param $keycolumn mixed string with name of key column, or array of
|
||||
* strings if the table has a primary key of more than one column
|
||||
*
|
||||
* @param $dbh object database connection object
|
||||
*
|
||||
* @param $validator mixed function or method used to validate
|
||||
* each new value, called with three parameters: the name of the
|
||||
* field/column that is changing, a reference to the new value and
|
||||
* a reference to this object
|
||||
*
|
||||
*/
|
||||
public function __construct($table, $keycolumn, &$dbh, $validator = null)
|
||||
{
|
||||
$this->PEAR('DB_Error');
|
||||
$this->_table = $table;
|
||||
$this->_keycolumn = $keycolumn;
|
||||
$this->_dbh = $dbh;
|
||||
$this->_readonly = false;
|
||||
$this->_validator = $validator;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _makeWhere()
|
||||
|
||||
/**
|
||||
* Create a new (empty) row in the configured table for this
|
||||
* object.
|
||||
* @param $newpk
|
||||
* @return |null
|
||||
*/
|
||||
public function insert($newpk)
|
||||
{
|
||||
if (is_array($this->_keycolumn)) {
|
||||
$primarykey = $this->_keycolumn;
|
||||
} else {
|
||||
$primarykey = array($this->_keycolumn);
|
||||
}
|
||||
settype($newpk, "array");
|
||||
for ($i = 0; $i < sizeof($primarykey); $i++) {
|
||||
$pkvals[] = $this->_dbh->quote($newpk[$i]);
|
||||
}
|
||||
|
||||
$sth = $this->_dbh->query("INSERT INTO $this->_table (" .
|
||||
implode(",", $primarykey) . ") VALUES(" .
|
||||
implode(",", $pkvals) . ")");
|
||||
if (DB::isError($sth)) {
|
||||
return $sth;
|
||||
}
|
||||
if (sizeof($newpk) == 1) {
|
||||
$newpk = $newpk[0];
|
||||
}
|
||||
$this->setup($newpk);
|
||||
return null;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ setup()
|
||||
|
||||
/**
|
||||
* Method used to initialize a DB_storage object from the
|
||||
* configured table.
|
||||
*
|
||||
* @param $keyval mixed the key[s] of the row to fetch (string or array)
|
||||
*
|
||||
* @return int|object
|
||||
*/
|
||||
public function setup($keyval)
|
||||
{
|
||||
$whereclause = $this->_makeWhere($keyval);
|
||||
$query = 'SELECT * FROM ' . $this->_table . ' WHERE ' . $whereclause;
|
||||
$sth = $this->_dbh->query($query);
|
||||
if (DB::isError($sth)) {
|
||||
return $sth;
|
||||
}
|
||||
$row = $sth->fetchRow(DB_FETCHMODE_ASSOC);
|
||||
if (DB::isError($row)) {
|
||||
return $row;
|
||||
}
|
||||
if (!$row) {
|
||||
return $this->raiseError(
|
||||
null,
|
||||
DB_ERROR_NOT_FOUND,
|
||||
null,
|
||||
null,
|
||||
$query,
|
||||
null,
|
||||
true
|
||||
);
|
||||
}
|
||||
foreach ($row as $key => $value) {
|
||||
$this->_properties[$key] = true;
|
||||
$this->$key = $value;
|
||||
}
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ insert()
|
||||
|
||||
/**
|
||||
* Utility method to build a "WHERE" clause to locate ourselves in
|
||||
* the table.
|
||||
*
|
||||
* XXX future improvement: use rowids?
|
||||
*
|
||||
* @access private
|
||||
* @param null $keyval
|
||||
* @return mixed|string|null
|
||||
*/
|
||||
public function _makeWhere($keyval = null)
|
||||
{
|
||||
if (is_array($this->_keycolumn)) {
|
||||
if ($keyval === null) {
|
||||
for ($i = 0; $i < sizeof($this->_keycolumn); $i++) {
|
||||
$keyval[] = $this->{$this->_keycolumn[$i]};
|
||||
}
|
||||
}
|
||||
$whereclause = '';
|
||||
for ($i = 0; $i < sizeof($this->_keycolumn); $i++) {
|
||||
if ($i > 0) {
|
||||
$whereclause .= ' AND ';
|
||||
}
|
||||
$whereclause .= $this->_keycolumn[$i];
|
||||
if (is_null($keyval[$i])) {
|
||||
// there's not much point in having a NULL key,
|
||||
// but we support it anyway
|
||||
$whereclause .= ' IS NULL';
|
||||
} else {
|
||||
$whereclause .= ' = ' . $this->_dbh->quote($keyval[$i]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ($keyval === null) {
|
||||
$keyval = @$this->{$this->_keycolumn};
|
||||
}
|
||||
$whereclause = $this->_keycolumn;
|
||||
if (is_null($keyval)) {
|
||||
// there's not much point in having a NULL key,
|
||||
// but we support it anyway
|
||||
$whereclause .= ' IS NULL';
|
||||
} else {
|
||||
$whereclause .= ' = ' . $this->_dbh->quote($keyval);
|
||||
}
|
||||
}
|
||||
return $whereclause;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ toString()
|
||||
|
||||
/**
|
||||
* Output a simple description of this DB_storage object.
|
||||
* @return string object description
|
||||
*/
|
||||
public function toString()
|
||||
{
|
||||
$info = strtolower(get_class($this));
|
||||
$info .= " (table=";
|
||||
$info .= $this->_table;
|
||||
$info .= ", keycolumn=";
|
||||
if (is_array($this->_keycolumn)) {
|
||||
$info .= "(" . implode(",", $this->_keycolumn) . ")";
|
||||
} else {
|
||||
$info .= $this->_keycolumn;
|
||||
}
|
||||
$info .= ", dbh=";
|
||||
if (is_object($this->_dbh)) {
|
||||
$info .= $this->_dbh->toString();
|
||||
} else {
|
||||
$info .= "null";
|
||||
}
|
||||
$info .= ")";
|
||||
if (sizeof($this->_properties)) {
|
||||
$info .= " [loaded, key=";
|
||||
$keyname = $this->_keycolumn;
|
||||
if (is_array($keyname)) {
|
||||
$info .= "(";
|
||||
for ($i = 0; $i < sizeof($keyname); $i++) {
|
||||
if ($i > 0) {
|
||||
$info .= ",";
|
||||
}
|
||||
$info .= $this->$keyname[$i];
|
||||
}
|
||||
$info .= ")";
|
||||
} else {
|
||||
$info .= $this->$keyname;
|
||||
}
|
||||
$info .= "]";
|
||||
}
|
||||
if (sizeof($this->_changes)) {
|
||||
$info .= " [modified]";
|
||||
}
|
||||
return $info;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ dump()
|
||||
|
||||
/**
|
||||
* Dump the contents of this object to "standard output".
|
||||
*/
|
||||
public function dump()
|
||||
{
|
||||
foreach ($this->_properties as $prop => $foo) {
|
||||
print "$prop = ";
|
||||
print htmlentities($this->$prop);
|
||||
print "<br />\n";
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ &create()
|
||||
|
||||
/**
|
||||
* Static method used to create new DB storage objects.
|
||||
* @param $table
|
||||
* @param $data assoc. array where the keys are the names
|
||||
* of properties/columns
|
||||
* @return object a new instance of DB_storage or a subclass of it
|
||||
*/
|
||||
public function &create($table, &$data)
|
||||
{
|
||||
$classname = strtolower(get_class($this));
|
||||
$obj = new $classname($table);
|
||||
foreach ($data as $name => $value) {
|
||||
$obj->_properties[$name] = true;
|
||||
$obj->$name = &$value;
|
||||
}
|
||||
return $obj;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ loadFromQuery()
|
||||
|
||||
/**
|
||||
* Loads data into this object from the given query. If this
|
||||
* object already contains table data, changes will be saved and
|
||||
* the object re-initialized first.
|
||||
*
|
||||
* @param $query SQL query
|
||||
*
|
||||
* @param $params parameter list in case you want to use
|
||||
* prepare/execute mode
|
||||
*
|
||||
* @return int DB_OK on success, DB_WARNING_READ_ONLY if the
|
||||
* returned object is read-only (because the object's specified
|
||||
* key column was not found among the columns returned by $query),
|
||||
* or another DB error code in case of errors.
|
||||
*/
|
||||
// XXX commented out for now
|
||||
/*
|
||||
function loadFromQuery($query, $params = null)
|
||||
{
|
||||
if (sizeof($this->_properties)) {
|
||||
if (sizeof($this->_changes)) {
|
||||
$this->store();
|
||||
$this->_changes = array();
|
||||
}
|
||||
$this->_properties = array();
|
||||
}
|
||||
$rowdata = $this->_dbh->getRow($query, DB_FETCHMODE_ASSOC, $params);
|
||||
if (DB::isError($rowdata)) {
|
||||
return $rowdata;
|
||||
}
|
||||
reset($rowdata);
|
||||
$found_keycolumn = false;
|
||||
while (list($key, $value) = each($rowdata)) {
|
||||
if ($key == $this->_keycolumn) {
|
||||
$found_keycolumn = true;
|
||||
}
|
||||
$this->_properties[$key] = true;
|
||||
$this->$key = &$value;
|
||||
unset($value); // have to unset, or all properties will
|
||||
// refer to the same value
|
||||
}
|
||||
if (!$found_keycolumn) {
|
||||
$this->_readonly = true;
|
||||
return DB_WARNING_READ_ONLY;
|
||||
}
|
||||
return DB_OK;
|
||||
}
|
||||
*/
|
||||
|
||||
// }}}
|
||||
// {{{ set()
|
||||
|
||||
/**
|
||||
* Modify an attriute value.
|
||||
* @param $property
|
||||
* @param $newvalue
|
||||
* @return bool|object
|
||||
*/
|
||||
public function set($property, $newvalue)
|
||||
{
|
||||
// only change if $property is known and object is not
|
||||
// read-only
|
||||
if ($this->_readonly) {
|
||||
return $this->raiseError(
|
||||
null,
|
||||
DB_WARNING_READ_ONLY,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
true
|
||||
);
|
||||
}
|
||||
if (@isset($this->_properties[$property])) {
|
||||
if (empty($this->_validator)) {
|
||||
$valid = true;
|
||||
} else {
|
||||
$valid = @call_user_func(
|
||||
$this->_validator,
|
||||
$this->_table,
|
||||
$property,
|
||||
$newvalue,
|
||||
$this->$property,
|
||||
$this
|
||||
);
|
||||
}
|
||||
if ($valid) {
|
||||
$this->$property = $newvalue;
|
||||
if (empty($this->_changes[$property])) {
|
||||
$this->_changes[$property] = 0;
|
||||
} else {
|
||||
$this->_changes[$property]++;
|
||||
}
|
||||
} else {
|
||||
return $this->raiseError(
|
||||
null,
|
||||
DB_ERROR_INVALID,
|
||||
null,
|
||||
null,
|
||||
"invalid field: $property",
|
||||
null,
|
||||
true
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return $this->raiseError(
|
||||
null,
|
||||
DB_ERROR_NOSUCHFIELD,
|
||||
null,
|
||||
null,
|
||||
"unknown field: $property",
|
||||
null,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ &get()
|
||||
|
||||
/**
|
||||
* Fetch an attribute value.
|
||||
*
|
||||
* @param string attribute name
|
||||
*
|
||||
* @return attribute contents, or null if the attribute name is
|
||||
* unknown
|
||||
*/
|
||||
public function &get($property)
|
||||
{
|
||||
// only return if $property is known
|
||||
if (isset($this->_properties[$property])) {
|
||||
return $this->$property;
|
||||
}
|
||||
$tmp = null;
|
||||
return $tmp;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _DB_storage()
|
||||
|
||||
/**
|
||||
* Destructor, calls DB_storage::store() if there are changes
|
||||
* that are to be kept.
|
||||
*/
|
||||
public function _DB_storage()
|
||||
{
|
||||
if (sizeof($this->_changes)) {
|
||||
$this->store();
|
||||
}
|
||||
$this->_properties = array();
|
||||
$this->_changes = array();
|
||||
$this->_table = null;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ store()
|
||||
|
||||
/**
|
||||
* Stores changes to this object in the database.
|
||||
*
|
||||
* @return DB_OK|int
|
||||
*/
|
||||
public function store()
|
||||
{
|
||||
$params = array();
|
||||
$vars = array();
|
||||
foreach ($this->_changes as $name => $foo) {
|
||||
$params[] = &$this->$name;
|
||||
$vars[] = $name . ' = ?';
|
||||
}
|
||||
if ($vars) {
|
||||
$query = 'UPDATE ' . $this->_table . ' SET ' .
|
||||
implode(', ', $vars) . ' WHERE ' .
|
||||
$this->_makeWhere();
|
||||
$stmt = $this->_dbh->prepare($query);
|
||||
$res = $this->_dbh->execute($stmt, $params);
|
||||
if (DB::isError($res)) {
|
||||
return $res;
|
||||
}
|
||||
$this->_changes = array();
|
||||
}
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ remove()
|
||||
|
||||
/**
|
||||
* Remove the row represented by this object from the database.
|
||||
*
|
||||
* @return mixed DB_OK or a DB error
|
||||
*/
|
||||
public function remove()
|
||||
{
|
||||
if ($this->_readonly) {
|
||||
return $this->raiseError(
|
||||
null,
|
||||
DB_WARNING_READ_ONLY,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
true
|
||||
);
|
||||
}
|
||||
$query = 'DELETE FROM ' . $this->_table . ' WHERE ' .
|
||||
$this->_makeWhere();
|
||||
$res = $this->_dbh->query($query);
|
||||
if (DB::isError($res)) {
|
||||
return $res;
|
||||
}
|
||||
foreach ($this->_properties as $prop => $foo) {
|
||||
unset($this->$prop);
|
||||
}
|
||||
$this->_properties = array();
|
||||
$this->_changes = array();
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* tab-width: 4
|
||||
* c-basic-offset: 4
|
||||
* End:
|
||||
*/
|
@ -1,955 +0,0 @@
|
||||
<?php
|
||||
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
||||
|
||||
/**
|
||||
* The PEAR DB driver for PHP's sybase extension
|
||||
* for interacting with Sybase databases
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENSE: This source file is subject to version 3.0 of the PHP license
|
||||
* that is available through the world-wide-web at the following URI:
|
||||
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
|
||||
* the PHP License and are unable to obtain it through the web, please
|
||||
* send a note to license@php.net so we can mail you a copy immediately.
|
||||
*
|
||||
* @category Database
|
||||
* @package DB
|
||||
* @author Sterling Hughes <sterling@php.net>
|
||||
* @author Ant<EFBFBD>nio Carlos Ven<EFBFBD>ncio J<EFBFBD>nior <floripa@php.net>
|
||||
* @author Daniel Convissor <danielc@php.net>
|
||||
* @copyright 1997-2007 The PHP Group
|
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0
|
||||
* @version CVS: $Id$
|
||||
* @link http://pear.php.net/package/DB
|
||||
*/
|
||||
|
||||
/**
|
||||
* Obtain the DB_common class so it can be extended from
|
||||
*/
|
||||
//require_once 'DB/common.php';
|
||||
require_once 'common.php';
|
||||
|
||||
/**
|
||||
* The methods PEAR DB uses to interact with PHP's sybase extension
|
||||
* for interacting with Sybase databases
|
||||
*
|
||||
* These methods overload the ones declared in DB_common.
|
||||
*
|
||||
* WARNING: This driver may fail with multiple connections under the
|
||||
* same user/pass/host and different databases.
|
||||
*
|
||||
* @category Database
|
||||
* @package DB
|
||||
* @author Sterling Hughes <sterling@php.net>
|
||||
* @author Ant<EFBFBD>nio Carlos Ven<EFBFBD>ncio J<EFBFBD>nior <floripa@php.net>
|
||||
* @author Daniel Convissor <danielc@php.net>
|
||||
* @copyright 1997-2007 The PHP Group
|
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0
|
||||
* @version Release: 1.9.2
|
||||
* @link http://pear.php.net/package/DB
|
||||
*/
|
||||
class DB_sybase extends DB_common
|
||||
{
|
||||
// {{{ properties
|
||||
|
||||
/**
|
||||
* The DB driver type (mysql, oci8, odbc, etc.)
|
||||
* @var string
|
||||
*/
|
||||
public $phptype = 'sybase';
|
||||
|
||||
/**
|
||||
* The database syntax variant to be used (db2, access, etc.), if any
|
||||
* @var string
|
||||
*/
|
||||
public $dbsyntax = 'sybase';
|
||||
|
||||
/**
|
||||
* The capabilities of this DB implementation
|
||||
*
|
||||
* The 'new_link' element contains the PHP version that first provided
|
||||
* new_link support for this DBMS. Contains false if it's unsupported.
|
||||
*
|
||||
* Meaning of the 'limit' element:
|
||||
* + 'emulate' = emulate with fetch row by number
|
||||
* + 'alter' = alter the query
|
||||
* + false = skip rows
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $features = array(
|
||||
'limit' => 'emulate',
|
||||
'new_link' => false,
|
||||
'numrows' => true,
|
||||
'pconnect' => true,
|
||||
'prepare' => false,
|
||||
'ssl' => false,
|
||||
'transactions' => true,
|
||||
);
|
||||
|
||||
/**
|
||||
* A mapping of native error codes to DB error codes
|
||||
* @var array
|
||||
*/
|
||||
public $errorcode_map = array();
|
||||
|
||||
/**
|
||||
* The raw database connection created by PHP
|
||||
* @var resource
|
||||
*/
|
||||
public $connection;
|
||||
|
||||
/**
|
||||
* The DSN information for connecting to a database
|
||||
* @var array
|
||||
*/
|
||||
public $dsn = array();
|
||||
|
||||
|
||||
/**
|
||||
* Should data manipulation queries be committed automatically?
|
||||
* @var bool
|
||||
* @access private
|
||||
*/
|
||||
public $autocommit = true;
|
||||
|
||||
/**
|
||||
* The quantity of transactions begun
|
||||
*
|
||||
* {@internal While this is private, it can't actually be designated
|
||||
* private in PHP 5 because it is directly accessed in the test suite.}}
|
||||
*
|
||||
* @var integer
|
||||
* @access private
|
||||
*/
|
||||
public $transaction_opcount = 0;
|
||||
|
||||
/**
|
||||
* The database specified in the DSN
|
||||
*
|
||||
* It's a fix to allow calls to different databases in the same script.
|
||||
*
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
public $_db = '';
|
||||
|
||||
|
||||
// }}}
|
||||
// {{{ constructor
|
||||
|
||||
/**
|
||||
* This constructor calls <kbd>parent::__construct()</kbd>
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ connect()
|
||||
|
||||
/**
|
||||
* Connect to the database server, log in and open the database
|
||||
*
|
||||
* Don't call this method directly. Use DB::connect() instead.
|
||||
*
|
||||
* PEAR DB's sybase driver supports the following extra DSN options:
|
||||
* + appname The application name to use on this connection.
|
||||
* Available since PEAR DB 1.7.0.
|
||||
* + charset The character set to use on this connection.
|
||||
* Available since PEAR DB 1.7.0.
|
||||
*
|
||||
* @param array $dsn the data source name
|
||||
* @param bool $persistent should the connection be persistent?
|
||||
*
|
||||
* @return int|object
|
||||
*/
|
||||
public function connect($dsn, $persistent = false)
|
||||
{
|
||||
if (!PEAR::loadExtension('sybase') &&
|
||||
!PEAR::loadExtension('sybase_ct')) {
|
||||
return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
|
||||
}
|
||||
|
||||
$this->dsn = $dsn;
|
||||
if ($dsn['dbsyntax']) {
|
||||
$this->dbsyntax = $dsn['dbsyntax'];
|
||||
}
|
||||
|
||||
$dsn['hostspec'] = $dsn['hostspec'] ? $dsn['hostspec'] : 'localhost';
|
||||
$dsn['password'] = !empty($dsn['password']) ? $dsn['password'] : false;
|
||||
$dsn['charset'] = isset($dsn['charset']) ? $dsn['charset'] : false;
|
||||
$dsn['appname'] = isset($dsn['appname']) ? $dsn['appname'] : false;
|
||||
|
||||
$connect_function = $persistent ? 'sybase_pconnect' : 'sybase_connect';
|
||||
|
||||
if ($dsn['username']) {
|
||||
$this->connection = @$connect_function(
|
||||
$dsn['hostspec'],
|
||||
$dsn['username'],
|
||||
$dsn['password'],
|
||||
$dsn['charset'],
|
||||
$dsn['appname']
|
||||
);
|
||||
} else {
|
||||
return $this->raiseError(
|
||||
DB_ERROR_CONNECT_FAILED,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
'The DSN did not contain a username.'
|
||||
);
|
||||
}
|
||||
|
||||
if (!$this->connection) {
|
||||
return $this->raiseError(
|
||||
DB_ERROR_CONNECT_FAILED,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
@sybase_get_last_message()
|
||||
);
|
||||
}
|
||||
|
||||
if ($dsn['database']) {
|
||||
if (!@sybase_select_db($dsn['database'], $this->connection)) {
|
||||
return $this->raiseError(
|
||||
DB_ERROR_NODBSELECTED,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
@sybase_get_last_message()
|
||||
);
|
||||
}
|
||||
$this->_db = $dsn['database'];
|
||||
}
|
||||
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ disconnect()
|
||||
|
||||
/**
|
||||
* Disconnects from the database server
|
||||
*
|
||||
* @return bool TRUE on success, FALSE on failure
|
||||
*/
|
||||
public function disconnect()
|
||||
{
|
||||
$ret = @sybase_close($this->connection);
|
||||
$this->connection = null;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ simpleQuery()
|
||||
|
||||
/**
|
||||
* Sends a query to the database server
|
||||
*
|
||||
* @param string the SQL query string
|
||||
*
|
||||
* @return mixed + a PHP result resrouce for successful SELECT queries
|
||||
* + the DB_OK constant for other successful queries
|
||||
* + a DB_Error object on failure
|
||||
*/
|
||||
public function simpleQuery($query)
|
||||
{
|
||||
$ismanip = $this->_checkManip($query);
|
||||
$this->last_query = $query;
|
||||
if ($this->_db && !@sybase_select_db($this->_db, $this->connection)) {
|
||||
return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED);
|
||||
}
|
||||
$query = $this->modifyQuery($query);
|
||||
if (!$this->autocommit && $ismanip) {
|
||||
if ($this->transaction_opcount == 0) {
|
||||
$result = @sybase_query('BEGIN TRANSACTION', $this->connection);
|
||||
if (!$result) {
|
||||
return $this->sybaseRaiseError();
|
||||
}
|
||||
}
|
||||
$this->transaction_opcount++;
|
||||
}
|
||||
$result = @sybase_query($query, $this->connection);
|
||||
if (!$result) {
|
||||
return $this->sybaseRaiseError();
|
||||
}
|
||||
if (is_resource($result)) {
|
||||
return $result;
|
||||
}
|
||||
// Determine which queries that should return data, and which
|
||||
// should return an error code only.
|
||||
return $ismanip ? DB_OK : $result;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ nextResult()
|
||||
|
||||
/**
|
||||
* Produces a DB_Error object regarding the current problem
|
||||
*
|
||||
* @param int $errno if the error is being manually raised pass a
|
||||
* DB_ERROR* constant here. If this isn't passed
|
||||
* the error information gathered from the DBMS.
|
||||
*
|
||||
* @return object the DB_Error object
|
||||
*
|
||||
* @see DB_common::raiseError(),
|
||||
* DB_sybase::errorNative(), DB_sybase::errorCode()
|
||||
*/
|
||||
public function sybaseRaiseError($errno = null)
|
||||
{
|
||||
$native = $this->errorNative();
|
||||
if ($errno === null) {
|
||||
$errno = $this->errorCode($native);
|
||||
}
|
||||
return $this->raiseError($errno, null, null, null, $native);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ fetchInto()
|
||||
|
||||
/**
|
||||
* Gets the DBMS' native error message produced by the last query
|
||||
*
|
||||
* @return string the DBMS' error message
|
||||
*/
|
||||
public function errorNative()
|
||||
{
|
||||
return @sybase_get_last_message();
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ freeResult()
|
||||
|
||||
/**
|
||||
* Determines PEAR::DB error code from the database's text error message.
|
||||
*
|
||||
* @param string $errormsg error message returned from the database
|
||||
* @return integer an error number from a DB error constant
|
||||
*/
|
||||
public function errorCode($errormsg)
|
||||
{
|
||||
static $error_regexps;
|
||||
|
||||
// PHP 5.2+ prepends the function name to $php_errormsg, so we need
|
||||
// this hack to work around it, per bug #9599.
|
||||
$errormsg = preg_replace('/^sybase[a-z_]+\(\): /', '', $errormsg);
|
||||
|
||||
if (!isset($error_regexps)) {
|
||||
$error_regexps = array(
|
||||
'/Incorrect syntax near/'
|
||||
=> DB_ERROR_SYNTAX,
|
||||
'/^Unclosed quote before the character string [\"\'].*[\"\']\./'
|
||||
=> DB_ERROR_SYNTAX,
|
||||
'/Implicit conversion (from datatype|of NUMERIC value)/i'
|
||||
=> DB_ERROR_INVALID_NUMBER,
|
||||
'/Cannot drop the table [\"\'].+[\"\'], because it doesn\'t exist in the system catalogs\./'
|
||||
=> DB_ERROR_NOSUCHTABLE,
|
||||
'/Only the owner of object [\"\'].+[\"\'] or a user with System Administrator \(SA\) role can run this command\./'
|
||||
=> DB_ERROR_ACCESS_VIOLATION,
|
||||
'/^.+ permission denied on object .+, database .+, owner .+/'
|
||||
=> DB_ERROR_ACCESS_VIOLATION,
|
||||
'/^.* permission denied, database .+, owner .+/'
|
||||
=> DB_ERROR_ACCESS_VIOLATION,
|
||||
'/[^.*] not found\./'
|
||||
=> DB_ERROR_NOSUCHTABLE,
|
||||
'/There is already an object named/'
|
||||
=> DB_ERROR_ALREADY_EXISTS,
|
||||
'/Invalid column name/'
|
||||
=> DB_ERROR_NOSUCHFIELD,
|
||||
'/does not allow null values/'
|
||||
=> DB_ERROR_CONSTRAINT_NOT_NULL,
|
||||
'/Command has been aborted/'
|
||||
=> DB_ERROR_CONSTRAINT,
|
||||
'/^Cannot drop the index .* because it doesn\'t exist/i'
|
||||
=> DB_ERROR_NOT_FOUND,
|
||||
'/^There is already an index/i'
|
||||
=> DB_ERROR_ALREADY_EXISTS,
|
||||
'/^There are fewer columns in the INSERT statement than values specified/i'
|
||||
=> DB_ERROR_VALUE_COUNT_ON_ROW,
|
||||
'/Divide by zero/i'
|
||||
=> DB_ERROR_DIVZERO,
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($error_regexps as $regexp => $code) {
|
||||
if (preg_match($regexp, $errormsg)) {
|
||||
return $code;
|
||||
}
|
||||
}
|
||||
return DB_ERROR;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ numCols()
|
||||
|
||||
/**
|
||||
* Move the internal sybase result pointer to the next available result
|
||||
*
|
||||
* @param a valid sybase result resource
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return true if a result is available otherwise return false
|
||||
*/
|
||||
public function nextResult($result)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ numRows()
|
||||
|
||||
/**
|
||||
* Places a row from the result set into the given array
|
||||
*
|
||||
* Formating of the array and the data therein are configurable.
|
||||
* See DB_result::fetchInto() for more information.
|
||||
*
|
||||
* This method is not meant to be called directly. Use
|
||||
* DB_result::fetchInto() instead. It can't be declared "protected"
|
||||
* because DB_result is a separate object.
|
||||
*
|
||||
* @param resource $result the query result resource
|
||||
* @param array $arr the referenced array to put the data in
|
||||
* @param int $fetchmode how the resulting array should be indexed
|
||||
* @param int $rownum the row number to fetch (0 = first row)
|
||||
*
|
||||
* @return mixed DB_OK on success, NULL when the end of a result set is
|
||||
* reached or on failure
|
||||
*
|
||||
* @see DB_result::fetchInto()
|
||||
*/
|
||||
public function fetchInto($result, &$arr, $fetchmode, $rownum = null)
|
||||
{
|
||||
if ($rownum !== null) {
|
||||
if (!@sybase_data_seek($result, $rownum)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if ($fetchmode & DB_FETCHMODE_ASSOC) {
|
||||
if (function_exists('sybase_fetch_assoc')) {
|
||||
$arr = @sybase_fetch_assoc($result);
|
||||
} else {
|
||||
if ($arr = @sybase_fetch_array($result)) {
|
||||
foreach ($arr as $key => $value) {
|
||||
if (is_int($key)) {
|
||||
unset($arr[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) {
|
||||
$arr = array_change_key_case($arr, CASE_LOWER);
|
||||
}
|
||||
} else {
|
||||
$arr = @sybase_fetch_row($result);
|
||||
}
|
||||
if (!$arr) {
|
||||
return null;
|
||||
}
|
||||
if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
|
||||
$this->_rtrimArrayValues($arr);
|
||||
}
|
||||
if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
|
||||
$this->_convertNullArrayValuesToEmpty($arr);
|
||||
}
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ affectedRows()
|
||||
|
||||
/**
|
||||
* Deletes the result set and frees the memory occupied by the result set
|
||||
*
|
||||
* This method is not meant to be called directly. Use
|
||||
* DB_result::free() instead. It can't be declared "protected"
|
||||
* because DB_result is a separate object.
|
||||
*
|
||||
* @param resource $result PHP's query result resource
|
||||
*
|
||||
* @return bool TRUE on success, FALSE if $result is invalid
|
||||
*
|
||||
* @see DB_result::free()
|
||||
*/
|
||||
public function freeResult($result)
|
||||
{
|
||||
return is_resource($result) ? sybase_free_result($result) : false;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ nextId()
|
||||
|
||||
/**
|
||||
* Gets the number of columns in a result set
|
||||
*
|
||||
* This method is not meant to be called directly. Use
|
||||
* DB_result::numCols() instead. It can't be declared "protected"
|
||||
* because DB_result is a separate object.
|
||||
*
|
||||
* @param resource $result PHP's query result resource
|
||||
*
|
||||
* @return int|object
|
||||
*
|
||||
* @see DB_result::numCols()
|
||||
*/
|
||||
public function numCols($result)
|
||||
{
|
||||
$cols = @sybase_num_fields($result);
|
||||
if (!$cols) {
|
||||
return $this->sybaseRaiseError();
|
||||
}
|
||||
return $cols;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of rows in a result set
|
||||
*
|
||||
* This method is not meant to be called directly. Use
|
||||
* DB_result::numRows() instead. It can't be declared "protected"
|
||||
* because DB_result is a separate object.
|
||||
*
|
||||
* @param resource $result PHP's query result resource
|
||||
*
|
||||
* @return int|object
|
||||
*
|
||||
* @see DB_result::numRows()
|
||||
*/
|
||||
public function numRows($result)
|
||||
{
|
||||
$rows = @sybase_num_rows($result);
|
||||
if ($rows === false) {
|
||||
return $this->sybaseRaiseError();
|
||||
}
|
||||
return $rows;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ dropSequence()
|
||||
|
||||
/**
|
||||
* Determines the number of rows affected by a data maniuplation query
|
||||
*
|
||||
* 0 is returned for queries that don't manipulate data.
|
||||
*
|
||||
* @return int the number of rows. A DB_Error object on failure.
|
||||
*/
|
||||
public function affectedRows()
|
||||
{
|
||||
if ($this->_last_query_manip) {
|
||||
$result = @sybase_affected_rows($this->connection);
|
||||
} else {
|
||||
$result = 0;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ quoteFloat()
|
||||
|
||||
/**
|
||||
* Returns the next free id in a sequence
|
||||
*
|
||||
* @param string $seq_name name of the sequence
|
||||
* @param boolean $ondemand when true, the seqence is automatically
|
||||
* created if it does not exist
|
||||
*
|
||||
* @return int|object
|
||||
* A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_common::nextID(), DB_common::getSequenceName(),
|
||||
* DB_sybase::createSequence(), DB_sybase::dropSequence()
|
||||
*/
|
||||
public function nextId($seq_name, $ondemand = true)
|
||||
{
|
||||
$seqname = $this->getSequenceName($seq_name);
|
||||
if ($this->_db && !@sybase_select_db($this->_db, $this->connection)) {
|
||||
return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED);
|
||||
}
|
||||
$repeat = 0;
|
||||
do {
|
||||
$this->pushErrorHandling(PEAR_ERROR_RETURN);
|
||||
$result = $this->query("INSERT INTO $seqname (vapor) VALUES (0)");
|
||||
$this->popErrorHandling();
|
||||
if ($ondemand && DB::isError($result) &&
|
||||
($result->getCode() == DB_ERROR || $result->getCode() == DB_ERROR_NOSUCHTABLE)) {
|
||||
$repeat = 1;
|
||||
$result = $this->createSequence($seq_name);
|
||||
if (DB::isError($result)) {
|
||||
return $this->raiseError($result);
|
||||
}
|
||||
} elseif (!DB::isError($result)) {
|
||||
$result = $this->query("SELECT @@IDENTITY FROM $seqname");
|
||||
$repeat = 0;
|
||||
} else {
|
||||
$repeat = false;
|
||||
}
|
||||
} while ($repeat);
|
||||
if (DB::isError($result)) {
|
||||
return $this->raiseError($result);
|
||||
}
|
||||
$result = $result->fetchRow(DB_FETCHMODE_ORDERED);
|
||||
return $result[0];
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ autoCommit()
|
||||
|
||||
/**
|
||||
* Creates a new sequence
|
||||
*
|
||||
* @param string $seq_name name of the new sequence
|
||||
*
|
||||
* @return int DB_OK on success. A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_common::createSequence(), DB_common::getSequenceName(),
|
||||
* DB_sybase::nextID(), DB_sybase::dropSequence()
|
||||
*/
|
||||
public function createSequence($seq_name)
|
||||
{
|
||||
return $this->query('CREATE TABLE '
|
||||
. $this->getSequenceName($seq_name)
|
||||
. ' (id numeric(10, 0) IDENTITY NOT NULL,'
|
||||
. ' vapor int NULL)');
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ commit()
|
||||
|
||||
/**
|
||||
* Deletes a sequence
|
||||
*
|
||||
* @param string $seq_name name of the sequence to be deleted
|
||||
*
|
||||
* @return int DB_OK on success. A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_common::dropSequence(), DB_common::getSequenceName(),
|
||||
* DB_sybase::nextID(), DB_sybase::createSequence()
|
||||
*/
|
||||
public function dropSequence($seq_name)
|
||||
{
|
||||
return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name));
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ rollback()
|
||||
|
||||
/**
|
||||
* Formats a float value for use within a query in a locale-independent
|
||||
* manner.
|
||||
*
|
||||
* @param float the float value to be quoted.
|
||||
* @return string the quoted string.
|
||||
* @see DB_common::quoteSmart()
|
||||
* @since Method available since release 1.7.8.
|
||||
*/
|
||||
public function quoteFloat($float)
|
||||
{
|
||||
return $this->escapeSimple(str_replace(',', '.', strval(floatval($float))));
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ sybaseRaiseError()
|
||||
|
||||
/**
|
||||
* Enables or disables automatic commits
|
||||
*
|
||||
* @param bool $onoff true turns it on, false turns it off
|
||||
*
|
||||
* @return int DB_OK on success. A DB_Error object if the driver
|
||||
* doesn't support auto-committing transactions.
|
||||
*/
|
||||
public function autoCommit($onoff = false)
|
||||
{
|
||||
// XXX if $this->transaction_opcount > 0, we should probably
|
||||
// issue a warning here.
|
||||
$this->autocommit = $onoff ? true : false;
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ errorNative()
|
||||
|
||||
/**
|
||||
* Commits the current transaction
|
||||
*
|
||||
* @return int|object
|
||||
*/
|
||||
public function commit()
|
||||
{
|
||||
if ($this->transaction_opcount > 0) {
|
||||
if ($this->_db && !@sybase_select_db($this->_db, $this->connection)) {
|
||||
return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED);
|
||||
}
|
||||
$result = @sybase_query('COMMIT', $this->connection);
|
||||
$this->transaction_opcount = 0;
|
||||
if (!$result) {
|
||||
return $this->sybaseRaiseError();
|
||||
}
|
||||
}
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ errorCode()
|
||||
|
||||
/**
|
||||
* Reverts the current transaction
|
||||
*
|
||||
* @return int|object
|
||||
*/
|
||||
public function rollback()
|
||||
{
|
||||
if ($this->transaction_opcount > 0) {
|
||||
if ($this->_db && !@sybase_select_db($this->_db, $this->connection)) {
|
||||
return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED);
|
||||
}
|
||||
$result = @sybase_query('ROLLBACK', $this->connection);
|
||||
$this->transaction_opcount = 0;
|
||||
if (!$result) {
|
||||
return $this->sybaseRaiseError();
|
||||
}
|
||||
}
|
||||
return DB_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ tableInfo()
|
||||
|
||||
/**
|
||||
* Returns information about a table or a result set
|
||||
*
|
||||
* NOTE: only supports 'table' and 'flags' if <var>$result</var>
|
||||
* is a table name.
|
||||
*
|
||||
* @param object|string $result DB_result object from a query or a
|
||||
* string containing the name of a table.
|
||||
* While this also accepts a query result
|
||||
* resource identifier, this behavior is
|
||||
* deprecated.
|
||||
* @param int $mode a valid tableInfo mode
|
||||
*
|
||||
* @return array|object
|
||||
* A DB_Error object on failure.
|
||||
*
|
||||
* @see DB_common::tableInfo()
|
||||
* @since Method available since Release 1.6.0
|
||||
*/
|
||||
public function tableInfo($result, $mode = null)
|
||||
{
|
||||
if (is_string($result)) {
|
||||
/*
|
||||
* Probably received a table name.
|
||||
* Create a result resource identifier.
|
||||
*/
|
||||
if ($this->_db && !@sybase_select_db($this->_db, $this->connection)) {
|
||||
return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED);
|
||||
}
|
||||
$id = @sybase_query(
|
||||
"SELECT * FROM $result WHERE 1=0",
|
||||
$this->connection
|
||||
);
|
||||
$got_string = true;
|
||||
} elseif (isset($result->result)) {
|
||||
/*
|
||||
* Probably received a result object.
|
||||
* Extract the result resource identifier.
|
||||
*/
|
||||
$id = $result->result;
|
||||
$got_string = false;
|
||||
} else {
|
||||
/*
|
||||
* Probably received a result resource identifier.
|
||||
* Copy it.
|
||||
* Deprecated. Here for compatibility only.
|
||||
*/
|
||||
$id = $result;
|
||||
$got_string = false;
|
||||
}
|
||||
|
||||
if (!is_resource($id)) {
|
||||
return $this->sybaseRaiseError(DB_ERROR_NEED_MORE_DATA);
|
||||
}
|
||||
|
||||
if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
|
||||
$case_func = 'strtolower';
|
||||
} else {
|
||||
$case_func = 'strval';
|
||||
}
|
||||
|
||||
$count = @sybase_num_fields($id);
|
||||
$res = array();
|
||||
|
||||
if ($mode) {
|
||||
$res['num_fields'] = $count;
|
||||
}
|
||||
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
$f = @sybase_fetch_field($id, $i);
|
||||
// column_source is often blank
|
||||
$res[$i] = array(
|
||||
'table' => $got_string
|
||||
? $case_func($result)
|
||||
: $case_func($f->column_source),
|
||||
'name' => $case_func($f->name),
|
||||
'type' => $f->type,
|
||||
'len' => $f->max_length,
|
||||
'flags' => '',
|
||||
);
|
||||
if ($res[$i]['table']) {
|
||||
$res[$i]['flags'] = $this->_sybase_field_flags(
|
||||
$res[$i]['table'],
|
||||
$res[$i]['name']
|
||||
);
|
||||
}
|
||||
if ($mode & DB_TABLEINFO_ORDER) {
|
||||
$res['order'][$res[$i]['name']] = $i;
|
||||
}
|
||||
if ($mode & DB_TABLEINFO_ORDERTABLE) {
|
||||
$res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
|
||||
}
|
||||
}
|
||||
|
||||
// free the result only if we were called on a table
|
||||
if ($got_string) {
|
||||
@sybase_free_result($id);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _sybase_field_flags()
|
||||
|
||||
/**
|
||||
* Get the flags for a field
|
||||
*
|
||||
* Currently supports:
|
||||
* + <samp>unique_key</samp> (unique index, unique check or primary_key)
|
||||
* + <samp>multiple_key</samp> (multi-key index)
|
||||
*
|
||||
* @param string $table the table name
|
||||
* @param string $column the field name
|
||||
*
|
||||
* @return string space delimited string of flags. Empty string if none.
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
public function _sybase_field_flags($table, $column)
|
||||
{
|
||||
static $tableName = null;
|
||||
static $flags = array();
|
||||
|
||||
if ($table != $tableName) {
|
||||
$flags = array();
|
||||
$tableName = $table;
|
||||
|
||||
/* We're running sp_helpindex directly because it doesn't exist in
|
||||
* older versions of ASE -- unfortunately, we can't just use
|
||||
* DB::isError() because the user may be using callback error
|
||||
* handling. */
|
||||
$res = @sybase_query("sp_helpindex $table", $this->connection);
|
||||
|
||||
if ($res === false || $res === true) {
|
||||
// Fake a valid response for BC reasons.
|
||||
return '';
|
||||
}
|
||||
|
||||
while (($val = sybase_fetch_assoc($res)) !== false) {
|
||||
if (!isset($val['index_keys'])) {
|
||||
/* No useful information returned. Break and be done with
|
||||
* it, which preserves the pre-1.7.9 behaviour. */
|
||||
break;
|
||||
}
|
||||
|
||||
$keys = explode(', ', trim($val['index_keys']));
|
||||
|
||||
if (sizeof($keys) > 1) {
|
||||
foreach ($keys as $key) {
|
||||
$this->_add_flag($flags[$key], 'multiple_key');
|
||||
}
|
||||
}
|
||||
|
||||
if (strpos($val['index_description'], 'unique')) {
|
||||
foreach ($keys as $key) {
|
||||
$this->_add_flag($flags[$key], 'unique_key');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sybase_free_result($res);
|
||||
}
|
||||
|
||||
if (array_key_exists($column, $flags)) {
|
||||
return (implode(' ', $flags[$column]));
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _add_flag()
|
||||
|
||||
/**
|
||||
* Adds a string to the flags array if the flag is not yet in there
|
||||
* - if there is no flag present the array is created
|
||||
*
|
||||
* @param array $array reference of flags array to add a value to
|
||||
* @param mixed $value value to add to the flag array
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
public function _add_flag(&$array, $value)
|
||||
{
|
||||
if (!is_array($array)) {
|
||||
$array = array($value);
|
||||
} elseif (!in_array($value, $array)) {
|
||||
array_push($array, $value);
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ getSpecialQuery()
|
||||
|
||||
/**
|
||||
* Obtains the query string needed for listing a given type of objects
|
||||
*
|
||||
* @param string $type the kind of objects you want to retrieve
|
||||
*
|
||||
* @return string the SQL query string or null if the driver doesn't
|
||||
* support the object type requested
|
||||
*
|
||||
* @access protected
|
||||
* @see DB_common::getListOf()
|
||||
*/
|
||||
public function getSpecialQuery($type)
|
||||
{
|
||||
switch ($type) {
|
||||
case 'tables':
|
||||
return "SELECT name FROM sysobjects WHERE type = 'U'"
|
||||
. ' ORDER BY name';
|
||||
case 'views':
|
||||
return "SELECT name FROM sysobjects WHERE type = 'V'";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* tab-width: 4
|
||||
* c-basic-offset: 4
|
||||
* End:
|
||||
*/
|
4571
extlib/MDB2.php
Normal file
4571
extlib/MDB2.php
Normal file
File diff suppressed because it is too large
Load Diff
183
extlib/MDB2/Date.php
Normal file
183
extlib/MDB2/Date.php
Normal file
@ -0,0 +1,183 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 and 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Author: Lukas Smith <smith@pooteeweet.org> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
|
||||
/**
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lukas Smith <smith@pooteeweet.org>
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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 <smith@pooteeweet.org>
|
||||
*/
|
||||
class MDB2_Date
|
||||
{
|
||||
// {{{ mdbNow()
|
||||
|
||||
/**
|
||||
* return the current datetime
|
||||
*
|
||||
* @return string current datetime in the MDB2 format
|
||||
* @access public
|
||||
*/
|
||||
public static 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
|
||||
*/
|
||||
public static function mdbToday()
|
||||
{
|
||||
return date('Y-m-d');
|
||||
}
|
||||
// }}}
|
||||
|
||||
// {{{ mdbTime()
|
||||
|
||||
/**
|
||||
* return the current time
|
||||
*
|
||||
* @return string current time in the MDB2 format
|
||||
* @access public
|
||||
*/
|
||||
public static 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
|
||||
*/
|
||||
public static 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
|
||||
*/
|
||||
public static 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
|
||||
*/
|
||||
public static 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
|
||||
*/
|
||||
public static 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;
|
||||
}
|
||||
// }}}
|
||||
}
|
||||
|
||||
?>
|
1842
extlib/MDB2/Driver/Datatype/Common.php
Normal file
1842
extlib/MDB2/Driver/Datatype/Common.php
Normal file
File diff suppressed because it is too large
Load Diff
350
extlib/MDB2/Driver/Datatype/fbsql.php
Normal file
350
extlib/MDB2/Driver/Datatype/fbsql.php
Normal file
@ -0,0 +1,350 @@
|
||||
<?php
|
||||
// vim: set et ts=4 sw=4 fdm=marker:
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 and 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Author: Lukas Smith <smith@pooteeweet.org> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
|
||||
require_once 'MDB2/Driver/Datatype/Common.php';
|
||||
|
||||
/**
|
||||
* MDB2 FrontbaseSQL driver
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lukas Smith <smith@pooteeweet.org>
|
||||
*/
|
||||
class MDB2_Driver_Datatype_fbsql extends MDB2_Driver_Datatype_Common
|
||||
{
|
||||
// {{{ _baseConvertResult()
|
||||
|
||||
/**
|
||||
* general type conversion method
|
||||
*
|
||||
* @param mixed $value refernce to a value to be converted
|
||||
* @param string $type specifies which type to convert to
|
||||
* @param string $rtrim if text should be rtrimmed
|
||||
* @return object a MDB2 error on failure
|
||||
* @access protected
|
||||
*/
|
||||
function _baseConvertResult($value, $type, $rtrim = true)
|
||||
{
|
||||
if (null === $value) {
|
||||
return null;
|
||||
}
|
||||
switch ($type) {
|
||||
case 'boolean':
|
||||
return $value == 'T';
|
||||
case 'time':
|
||||
if ($value[0] == '+') {
|
||||
return substr($value, 1);
|
||||
} else {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
return parent::_baseConvertResult($value, $type, $rtrim);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 (MDB2::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 ? 'CHAR('.$length.')' : 'VARCHAR('.$length.')';
|
||||
case 'clob':
|
||||
return 'CLOB';
|
||||
case 'blob':
|
||||
return 'BLOB';
|
||||
case 'integer':
|
||||
return 'INT';
|
||||
case 'boolean':
|
||||
return 'BOOLEAN';
|
||||
case 'date':
|
||||
return 'DATE';
|
||||
case 'time':
|
||||
return 'TIME';
|
||||
case 'timestamp':
|
||||
return 'TIMESTAMP';
|
||||
case 'float':
|
||||
return 'FLOAT';
|
||||
case 'decimal':
|
||||
$length = !empty($field['length']) ? $field['length'] : 18;
|
||||
$scale = !empty($field['scale']) ? $field['scale'] : $db->options['decimal_places'];
|
||||
return 'DECIMAL('.$length.','.$scale.')';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _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 ? 'True' : 'False');
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _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)
|
||||
{
|
||||
return 'DATE'.$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)
|
||||
{
|
||||
return 'TIMESTAMP'.$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)
|
||||
{
|
||||
return 'TIME'.$this->_quoteText($value, $quote, $escape_wildcards);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _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_type = strtolower($field['type']);
|
||||
$length = $field['length'];
|
||||
if ($length == '-1' && !empty($field['atttypmod'])) {
|
||||
$length = $field['atttypmod'] - 4;
|
||||
}
|
||||
$type = array();
|
||||
$unsigned = $fixed = null;
|
||||
switch ($db_type) {
|
||||
case 'tinyint':
|
||||
$type[] = 'integer';
|
||||
$unsigned = preg_match('/ unsigned/i', $field['type']);
|
||||
$length = 1;
|
||||
break;
|
||||
case 'smallint':
|
||||
$type[] = 'integer';
|
||||
$unsigned = false;
|
||||
$length = 2;
|
||||
if ($length == '2') {
|
||||
$type[] = 'boolean';
|
||||
if (preg_match('/^(is|has)/', $field['name'])) {
|
||||
$type = array_reverse($type);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'int':
|
||||
case 'integer':
|
||||
$type[] = 'integer';
|
||||
$unsigned = false;
|
||||
$length = 4;
|
||||
break;
|
||||
case 'longint':
|
||||
$type[] = 'integer';
|
||||
$unsigned = false;
|
||||
$length = 8;
|
||||
break;
|
||||
case 'boolean':
|
||||
$type[] = 'boolean';
|
||||
$length = null;
|
||||
break;
|
||||
case 'character varying':
|
||||
case 'char varying':
|
||||
case 'varchar':
|
||||
case 'national character varying':
|
||||
case 'national char varying':
|
||||
case 'nchar varying':
|
||||
$fixed = false;
|
||||
case 'unknown':
|
||||
case 'char':
|
||||
case 'character':
|
||||
case 'national character':
|
||||
case 'national char':
|
||||
case 'nchar':
|
||||
$type[] = 'text';
|
||||
if (strstr($db_type, 'text')) {
|
||||
$type[] = 'clob';
|
||||
$type = array_reverse($type);
|
||||
}
|
||||
if ($fixed !== false) {
|
||||
$fixed = true;
|
||||
}
|
||||
break;
|
||||
case 'date':
|
||||
$type[] = 'date';
|
||||
$length = null;
|
||||
break;
|
||||
case 'timestamp':
|
||||
case 'timestamp with time zone':
|
||||
$type[] = 'timestamp';
|
||||
$length = null;
|
||||
break;
|
||||
case 'time':
|
||||
case 'time with time zone':
|
||||
$type[] = 'time';
|
||||
$length = null;
|
||||
break;
|
||||
case 'float':
|
||||
case 'double precision':
|
||||
case 'real':
|
||||
$type[] = 'float';
|
||||
break;
|
||||
case 'decimal':
|
||||
case 'numeric':
|
||||
$type[] = 'decimal';
|
||||
break;
|
||||
case 'blob':
|
||||
$type[] = 'blob';
|
||||
$length = null;
|
||||
break;
|
||||
case 'clob':
|
||||
$type[] = 'clob';
|
||||
$length = null;
|
||||
break;
|
||||
default:
|
||||
$db =& $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
|
||||
'unknown database attribute type: '.$db_type, __FUNCTION__);
|
||||
}
|
||||
|
||||
if ((int)$length <= 0) {
|
||||
$length = null;
|
||||
}
|
||||
|
||||
return array($type, $length, $unsigned, $fixed);
|
||||
}
|
||||
|
||||
// }}}
|
||||
}
|
||||
?>
|
455
extlib/MDB2/Driver/Datatype/ibase.php
Normal file
455
extlib/MDB2/Driver/Datatype/ibase.php
Normal file
@ -0,0 +1,455 @@
|
||||
<?php
|
||||
// vim: set et ts=4 sw=4 fdm=marker:
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 and 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox, |
|
||||
// | Stig. S. Bakken, Lukas Smith, Lorenzo Alberton |
|
||||
// | 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Author: Lukas Smith <smith@pooteeweet.org> |
|
||||
// | Lorenzo Alberton <l.alberton@quipo.it> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id$
|
||||
|
||||
require_once 'MDB2/Driver/Datatype/Common.php';
|
||||
|
||||
/**
|
||||
* MDB2 Firebird/Interbase driver
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lukas Smith <smith@pooteeweet.org>
|
||||
* @author Lorenzo Alberton <l.alberton@quipo.it>
|
||||
*/
|
||||
class MDB2_Driver_Datatype_ibase extends MDB2_Driver_Datatype_Common
|
||||
{
|
||||
// {{{ _baseConvertResult()
|
||||
|
||||
/**
|
||||
* General type conversion method
|
||||
*
|
||||
* @param mixed $value refernce 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 a MDB2 error on failure
|
||||
* @access protected
|
||||
*/
|
||||
function _baseConvertResult($value, $type, $rtrim = true)
|
||||
{
|
||||
if (null === $value) {
|
||||
return null;
|
||||
}
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
if (MDB2::isError($connection)) {
|
||||
return $connection;
|
||||
}
|
||||
|
||||
switch ($type) {
|
||||
case 'text':
|
||||
$blob_info = @ibase_blob_info($connection, $value);
|
||||
if (is_array($blob_info) && $blob_info['length'] > 0) {
|
||||
//LOB => fetch into variable
|
||||
$clob = $this->_baseConvertResult($value, 'clob', $rtrim);
|
||||
if (!MDB2::isError($clob) && is_resource($clob)) {
|
||||
$clob_value = '';
|
||||
while (!feof($clob)) {
|
||||
$clob_value .= fread($clob, 8192);
|
||||
}
|
||||
$this->destroyLOB($clob);
|
||||
}
|
||||
$value = $clob_value;
|
||||
}
|
||||
if ($rtrim) {
|
||||
$value = rtrim($value);
|
||||
}
|
||||
return $value;
|
||||
case 'timestamp':
|
||||
return substr($value, 0, strlen('YYYY-MM-DD HH:MM:SS'));
|
||||
}
|
||||
return parent::_baseConvertResult($value, $type, $rtrim);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _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 'CHARACTER SET '.$charset;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _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 'COLLATE '.$collation;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 (MDB2::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 ? 'CHAR('.$length.')' : 'VARCHAR('.$length.')';
|
||||
case 'clob':
|
||||
return 'BLOB SUB_TYPE 1';
|
||||
case 'blob':
|
||||
return 'BLOB SUB_TYPE 0';
|
||||
case 'integer':
|
||||
return 'INT';
|
||||
case 'boolean':
|
||||
return 'SMALLINT';
|
||||
case 'date':
|
||||
return 'DATE';
|
||||
case 'time':
|
||||
return 'TIME';
|
||||
case 'timestamp':
|
||||
return 'TIMESTAMP';
|
||||
case 'float':
|
||||
return 'DOUBLE PRECISION';
|
||||
case 'decimal':
|
||||
$length = !empty($field['length']) ? $field['length'] : 18;
|
||||
$scale = !empty($field['scale']) ? $field['scale'] : $db->options['decimal_places'];
|
||||
return 'DECIMAL('.$length.','.$scale.')';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _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)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$connection = $db->getConnection();
|
||||
if (MDB2::isError($connection)) {
|
||||
return $connection;
|
||||
}
|
||||
|
||||
$close = true;
|
||||
if (is_resource($value)) {
|
||||
$close = false;
|
||||
} elseif (preg_match('/^(\w+:\/\/)(.*)$/', $value, $match)) {
|
||||
if ($match[1] == 'file://') {
|
||||
$value = $match[2];
|
||||
}
|
||||
$value = @fopen($value, 'r');
|
||||
} else {
|
||||
$fp = @tmpfile();
|
||||
@fwrite($fp, $value);
|
||||
@rewind($fp);
|
||||
$value = $fp;
|
||||
}
|
||||
$blob_id = @ibase_blob_import($connection, $value);
|
||||
|
||||
if ($close) {
|
||||
@fclose($value);
|
||||
}
|
||||
return $blob_id;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _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 (empty($lob['handle'])) {
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
$connection = $db->getConnection();
|
||||
if (MDB2::isError($connection)) {
|
||||
return $connection;
|
||||
}
|
||||
$lob['handle'] = @ibase_blob_open($connection, $lob['resource']);
|
||||
if (!$lob['handle']) {
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
return $db->raiseError(null, null, null,
|
||||
'Could not open fetched large object field', __FUNCTION__);
|
||||
}
|
||||
}
|
||||
$lob['loaded'] = true;
|
||||
return MDB2_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _readLOB()
|
||||
|
||||
/**
|
||||
* Read data from large object input stream.
|
||||
*
|
||||
* @param array $lob array
|
||||
* @param blob $data reference to a variable that will hold data to be
|
||||
* read from the large object input stream
|
||||
* @param int $length integer value that indicates the largest ammount of
|
||||
* data to be read from the large object input stream.
|
||||
* @return mixed length on success, a MDB2 error on failure
|
||||
* @access protected
|
||||
*/
|
||||
function _readLOB(&$lob, $length)
|
||||
{
|
||||
$data = @ibase_blob_get($lob['handle'], $length);
|
||||
if (!is_string($data)) {
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
return $db->raiseError(null, null, null,
|
||||
'Unable to read LOB', __FUNCTION__);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _destroyLOB()
|
||||
|
||||
/**
|
||||
* Free any resources allocated during the lifetime of the large object
|
||||
* handler object.
|
||||
*
|
||||
* @param array $lob array
|
||||
* @access protected
|
||||
*/
|
||||
function _destroyLOB(&$lob)
|
||||
{
|
||||
if (isset($lob['handle'])) {
|
||||
@ibase_blob_close($lob['handle']);
|
||||
unset($lob['handle']);
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ patternEscapeString()
|
||||
|
||||
/**
|
||||
* build string to define escape pattern string
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return string define escape pattern
|
||||
*/
|
||||
function patternEscapeString()
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
return " ESCAPE '". $db->string_quoting['escape_pattern'] ."'";
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _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)
|
||||
{
|
||||
$length = $field['length'];
|
||||
if ((int)$length <= 0) {
|
||||
$length = null;
|
||||
}
|
||||
$type = array();
|
||||
$unsigned = $fixed = null;
|
||||
$db_type = strtolower($field['type']);
|
||||
$field['field_sub_type'] = !empty($field['field_sub_type'])
|
||||
? strtolower($field['field_sub_type']) : null;
|
||||
switch ($db_type) {
|
||||
case 'smallint':
|
||||
case 'integer':
|
||||
case 'int64':
|
||||
//these may be 'numeric' or 'decimal'
|
||||
if (isset($field['field_sub_type'])) {
|
||||
$field['type'] = $field['field_sub_type'];
|
||||
return $this->mapNativeDatatype($field);
|
||||
}
|
||||
case 'bigint':
|
||||
case 'quad':
|
||||
$type[] = 'integer';
|
||||
if ($length == '1') {
|
||||
$type[] = 'boolean';
|
||||
if (preg_match('/^(is|has)/', $field['name'])) {
|
||||
$type = array_reverse($type);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'varchar':
|
||||
$fixed = false;
|
||||
case 'char':
|
||||
case 'cstring':
|
||||
$type[] = 'text';
|
||||
if ($length == '1') {
|
||||
$type[] = 'boolean';
|
||||
if (preg_match('/^(is|has)/', $field['name'])) {
|
||||
$type = array_reverse($type);
|
||||
}
|
||||
}
|
||||
if ($fixed !== false) {
|
||||
$fixed = true;
|
||||
}
|
||||
break;
|
||||
case 'date':
|
||||
$type[] = 'date';
|
||||
$length = null;
|
||||
break;
|
||||
case 'timestamp':
|
||||
$type[] = 'timestamp';
|
||||
$length = null;
|
||||
break;
|
||||
case 'time':
|
||||
$type[] = 'time';
|
||||
$length = null;
|
||||
break;
|
||||
case 'float':
|
||||
case 'double':
|
||||
case 'double precision':
|
||||
case 'd_float':
|
||||
$type[] = 'float';
|
||||
break;
|
||||
case 'decimal':
|
||||
case 'numeric':
|
||||
$type[] = 'decimal';
|
||||
$length = $field['precision'].','.$field['scale'];
|
||||
break;
|
||||
case 'blob':
|
||||
$type[] = ($field['field_sub_type'] == 'text') ? 'clob' : 'blob';
|
||||
$length = null;
|
||||
break;
|
||||
default:
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
|
||||
'unknown database attribute type: '.$db_type, __FUNCTION__);
|
||||
}
|
||||
|
||||
if ((int)$length <= 0) {
|
||||
$length = null;
|
||||
}
|
||||
|
||||
return array($type, $length, $unsigned, $fixed);
|
||||
}
|
||||
|
||||
// }}}
|
||||
}
|
||||
?>
|
497
extlib/MDB2/Driver/Datatype/mssql.php
Normal file
497
extlib/MDB2/Driver/Datatype/mssql.php
Normal file
@ -0,0 +1,497 @@
|
||||
<?php
|
||||
// vim: set et ts=4 sw=4 fdm=marker:
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 and 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Copyright (c) 1998-2007 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Authors: Lukas Smith <smith@pooteeweet.org> |
|
||||
// | Daniel Convissor <danielc@php.net> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
|
||||
require_once 'MDB2/Driver/Datatype/Common.php';
|
||||
|
||||
/**
|
||||
* MDB2 MS SQL driver
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lukas Smith <smith@pooteeweet.org>
|
||||
*/
|
||||
class MDB2_Driver_Datatype_mssql extends MDB2_Driver_Datatype_Common
|
||||
{
|
||||
// {{{ _baseConvertResult()
|
||||
|
||||
/**
|
||||
* general type conversion method
|
||||
*
|
||||
* @param mixed $value refernce 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 a MDB2 error on failure
|
||||
* @access protected
|
||||
*/
|
||||
function _baseConvertResult($value, $type, $rtrim = true)
|
||||
{
|
||||
if (null === $value) {
|
||||
return null;
|
||||
}
|
||||
switch ($type) {
|
||||
case 'boolean':
|
||||
return ($value === 0)? false : !empty($value);
|
||||
case 'date':
|
||||
if (strlen($value) > 10) {
|
||||
$value = substr($value,0,10);
|
||||
}
|
||||
return $value;
|
||||
case 'time':
|
||||
if (strlen($value) > 8) {
|
||||
$value = substr($value,11,8);
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
return parent::_baseConvertResult($value, $type, $rtrim);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _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 'COLLATE '.$collation;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
switch ($field['type']) {
|
||||
case 'text':
|
||||
$length = !empty($field['length'])
|
||||
? $field['length'] : false;
|
||||
$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':
|
||||
if (!empty($field['length'])) {
|
||||
$length = $field['length'];
|
||||
if ($length <= 8000) {
|
||||
return 'VARCHAR('.$length.')';
|
||||
}
|
||||
}
|
||||
return 'TEXT';
|
||||
case 'blob':
|
||||
if (!empty($field['length'])) {
|
||||
$length = $field['length'];
|
||||
if ($length <= 8000) {
|
||||
return "VARBINARY($length)";
|
||||
}
|
||||
}
|
||||
return 'IMAGE';
|
||||
case 'integer':
|
||||
return 'INT';
|
||||
case 'boolean':
|
||||
return 'BIT';
|
||||
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 'FLOAT';
|
||||
case 'decimal':
|
||||
$length = !empty($field['length']) ? $field['length'] : 18;
|
||||
$scale = !empty($field['scale']) ? $field['scale'] : $db->options['decimal_places'];
|
||||
return 'DECIMAL('.$length.','.$scale.')';
|
||||
}
|
||||
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 string $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)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$notnull = empty($field['notnull']) ? ' NULL' : ' NOT NULL';
|
||||
$default = $autoinc = '';
|
||||
if (!empty($field['autoincrement'])) {
|
||||
$autoinc = ' IDENTITY PRIMARY KEY';
|
||||
} elseif (array_key_exists('default', $field)) {
|
||||
if ($field['default'] === '') {
|
||||
$field['default'] = 0;
|
||||
}
|
||||
if (null === $field['default']) {
|
||||
$default = ' DEFAULT (null)';
|
||||
} else {
|
||||
$default = ' DEFAULT (' . $this->quote($field['default'], 'integer') . ')';
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($field['unsigned'])) {
|
||||
$db->warnings[] = "unsigned integer field \"$name\" is being declared as signed integer";
|
||||
}
|
||||
|
||||
$name = $db->quoteIdentifier($name, true);
|
||||
return $name.' '.$this->getTypeDeclaration($field).$notnull.$default.$autoinc;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$notnull = empty($field['notnull']) ? ' NULL' : ' 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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$notnull = empty($field['notnull']) ? ' NULL' : ' NOT NULL';
|
||||
$name = $db->quoteIdentifier($name, true);
|
||||
return $name.' '.$this->getTypeDeclaration($field).$notnull;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _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)
|
||||
{
|
||||
if (!$quote) {
|
||||
return $value;
|
||||
}
|
||||
$value = '0x'.bin2hex($this->_readFile($value));
|
||||
return $value;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$match = '';
|
||||
if (null !== $operator) {
|
||||
$field = (null === $field) ? '' : $field.' ';
|
||||
$operator = strtoupper($operator);
|
||||
switch ($operator) {
|
||||
// case insensitive
|
||||
case 'ILIKE':
|
||||
$match = $field.'LIKE ';
|
||||
break;
|
||||
case 'NOT ILIKE':
|
||||
$match = $field.'NOT LIKE ';
|
||||
break;
|
||||
// case sensitive
|
||||
case 'LIKE':
|
||||
$match = $field.'LIKE ';
|
||||
break;
|
||||
case 'NOT LIKE':
|
||||
$match = $field.'NOT 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 {
|
||||
$match.= $db->escapePattern($db->escape($value));
|
||||
}
|
||||
}
|
||||
$match.= "'";
|
||||
$match.= $this->patternEscapeString();
|
||||
return $match;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _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)
|
||||
{
|
||||
// todo: handle length of various int variations
|
||||
$db_type = preg_replace('/\d/', '', strtolower($field['type']));
|
||||
$length = $field['length'];
|
||||
$type = array();
|
||||
// todo: unsigned handling seems to be missing
|
||||
$unsigned = $fixed = null;
|
||||
switch ($db_type) {
|
||||
case 'bit':
|
||||
$type[0] = 'boolean';
|
||||
break;
|
||||
case 'tinyint':
|
||||
$type[0] = 'integer';
|
||||
$length = 1;
|
||||
break;
|
||||
case 'smallint':
|
||||
$type[0] = 'integer';
|
||||
$length = 2;
|
||||
break;
|
||||
case 'int':
|
||||
$type[0] = 'integer';
|
||||
$length = 4;
|
||||
break;
|
||||
case 'bigint':
|
||||
$type[0] = 'integer';
|
||||
$length = 8;
|
||||
break;
|
||||
case 'smalldatetime':
|
||||
case 'datetime':
|
||||
$type[0] = 'timestamp';
|
||||
break;
|
||||
case 'float':
|
||||
case 'real':
|
||||
case 'numeric':
|
||||
$type[0] = 'float';
|
||||
break;
|
||||
case 'decimal':
|
||||
case 'money':
|
||||
$type[0] = 'decimal';
|
||||
$length = $field['numeric_precision'].','.$field['numeric_scale'];
|
||||
break;
|
||||
case 'text':
|
||||
case 'ntext':
|
||||
case 'varchar':
|
||||
case 'nvarchar':
|
||||
$fixed = false;
|
||||
case 'char':
|
||||
case 'nchar':
|
||||
$type[0] = 'text';
|
||||
if ($length == '1') {
|
||||
$type[] = 'boolean';
|
||||
if (preg_match('/^(is|has)/', $field['name'])) {
|
||||
$type = array_reverse($type);
|
||||
}
|
||||
} elseif (strstr($db_type, 'text')) {
|
||||
$type[] = 'clob';
|
||||
$type = array_reverse($type);
|
||||
}
|
||||
if ($fixed !== false) {
|
||||
$fixed = true;
|
||||
}
|
||||
break;
|
||||
case 'image':
|
||||
case 'varbinary':
|
||||
case 'timestamp':
|
||||
$type[] = 'blob';
|
||||
$length = null;
|
||||
break;
|
||||
default:
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
|
||||
'unknown database attribute type: '.$db_type, __FUNCTION__);
|
||||
}
|
||||
|
||||
if ((int)$length <= 0) {
|
||||
$length = null;
|
||||
}
|
||||
|
||||
return array($type, $length, $unsigned, $fixed);
|
||||
}
|
||||
// }}}
|
||||
}
|
||||
|
||||
?>
|
640
extlib/MDB2/Driver/Datatype/mysqli.php
Normal file
640
extlib/MDB2/Driver/Datatype/mysqli.php
Normal file
@ -0,0 +1,640 @@
|
||||
<?php
|
||||
// vim: set et ts=4 sw=4 fdm=marker:
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 and 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Copyright (c) 1998-2007 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Author: Lukas Smith <smith@pooteeweet.org> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
|
||||
require_once 'MDB2/Driver/Datatype/Common.php';
|
||||
|
||||
/**
|
||||
* MDB2 MySQLi driver
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lukas Smith <smith@pooteeweet.org>
|
||||
*/
|
||||
class MDB2_Driver_Datatype_mysqli extends MDB2_Driver_Datatype_Common
|
||||
{
|
||||
// {{{ _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 'CHARACTER SET '.$charset;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _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 'COLLATE '.$collation;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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)
|
||||
{
|
||||
// MySQL DDL syntax forbids combining NOT NULL with DEFAULT NULL.
|
||||
// To get a default of NULL for NOT NULL columns, omit it.
|
||||
if ( isset($field['notnull'])
|
||||
&& !empty($field['notnull'])
|
||||
&& array_key_exists('default', $field) // do not use isset() here!
|
||||
&& null === $field['default']
|
||||
) {
|
||||
unset($field['default']);
|
||||
}
|
||||
return parent::getDeclaration($type, $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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
switch ($field['type']) {
|
||||
case 'text':
|
||||
if (empty($field['length']) && array_key_exists('default', $field)) {
|
||||
$field['length'] = $db->varchar_max_length;
|
||||
}
|
||||
$length = !empty($field['length']) ? $field['length'] : false;
|
||||
$fixed = !empty($field['fixed']) ? $field['fixed'] : false;
|
||||
return $fixed ? ($length ? 'CHAR('.$length.')' : 'CHAR(255)')
|
||||
: ($length ? 'VARCHAR('.$length.')' : 'TEXT');
|
||||
case 'clob':
|
||||
if (!empty($field['length'])) {
|
||||
$length = $field['length'];
|
||||
if ($length <= 255) {
|
||||
return 'TINYTEXT';
|
||||
} elseif ($length <= 65532) {
|
||||
return 'TEXT';
|
||||
} elseif ($length <= 16777215) {
|
||||
return 'MEDIUMTEXT';
|
||||
}
|
||||
}
|
||||
return 'LONGTEXT';
|
||||
case 'blob':
|
||||
if (!empty($field['length'])) {
|
||||
$length = $field['length'];
|
||||
if ($length <= 255) {
|
||||
return 'TINYBLOB';
|
||||
} elseif ($length <= 65532) {
|
||||
return 'BLOB';
|
||||
} elseif ($length <= 16777215) {
|
||||
return 'MEDIUMBLOB';
|
||||
}
|
||||
}
|
||||
return 'LONGBLOB';
|
||||
case 'integer':
|
||||
if (!empty($field['length'])) {
|
||||
$length = $field['length'];
|
||||
if ($length <= 1) {
|
||||
return 'TINYINT';
|
||||
} elseif ($length == 2) {
|
||||
return 'SMALLINT';
|
||||
} elseif ($length == 3) {
|
||||
return 'MEDIUMINT';
|
||||
} elseif ($length == 4) {
|
||||
return 'INT';
|
||||
} elseif ($length > 4) {
|
||||
return 'BIGINT';
|
||||
}
|
||||
}
|
||||
return 'INT';
|
||||
case 'boolean':
|
||||
return 'TINYINT(1)';
|
||||
case 'date':
|
||||
return 'DATE';
|
||||
case 'time':
|
||||
return 'TIME';
|
||||
case 'timestamp':
|
||||
return 'DATETIME';
|
||||
case 'float':
|
||||
$l = '';
|
||||
if (!empty($field['length'])) {
|
||||
$l = '(' . $field['length'];
|
||||
if (!empty($field['scale'])) {
|
||||
$l .= ',' . $field['scale'];
|
||||
}
|
||||
$l .= ')';
|
||||
}
|
||||
return 'DOUBLE' . $l;
|
||||
case 'decimal':
|
||||
$length = !empty($field['length']) ? $field['length'] : 18;
|
||||
$scale = !empty($field['scale']) ? $field['scale'] : $db->options['decimal_places'];
|
||||
return 'DECIMAL('.$length.','.$scale.')';
|
||||
}
|
||||
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 string $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)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$default = $autoinc = '';
|
||||
if (!empty($field['autoincrement'])) {
|
||||
$autoinc = ' AUTO_INCREMENT PRIMARY KEY';
|
||||
} elseif (array_key_exists('default', $field)) {
|
||||
if ($field['default'] === '') {
|
||||
$field['default'] = empty($field['notnull']) ? null : 0;
|
||||
}
|
||||
$default = ' DEFAULT '.$this->quote($field['default'], 'integer');
|
||||
}
|
||||
|
||||
$notnull = empty($field['notnull']) ? '' : ' NOT NULL';
|
||||
$unsigned = empty($field['unsigned']) ? '' : ' UNSIGNED';
|
||||
if (empty($default) && empty($notnull)) {
|
||||
$default = ' DEFAULT NULL';
|
||||
}
|
||||
$name = $db->quoteIdentifier($name, true);
|
||||
return $name.' '.$this->getTypeDeclaration($field).$unsigned.$default.$notnull.$autoinc;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _getFloatDeclaration()
|
||||
|
||||
/**
|
||||
* Obtain DBMS specific SQL code portion needed to declare an float type
|
||||
* field to be used in statements like CREATE TABLE.
|
||||
*
|
||||
* @param string $name name the field to be declared.
|
||||
* @param string $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 float if
|
||||
* possible.
|
||||
*
|
||||
* 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)
|
||||
{
|
||||
// Since AUTO_INCREMENT can be used for integer or floating-point types,
|
||||
// reuse the INTEGER declaration
|
||||
// @see http://bugs.mysql.com/bug.php?id=31032
|
||||
return $this->_getIntegerDeclaration($name, $field);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _getDecimalDeclaration()
|
||||
|
||||
/**
|
||||
* Obtain DBMS specific SQL code portion needed to declare an decimal type
|
||||
* field to be used in statements like CREATE TABLE.
|
||||
*
|
||||
* @param string $name name the field to be declared.
|
||||
* @param string $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
|
||||
* 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)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$default = '';
|
||||
if (array_key_exists('default', $field)) {
|
||||
if ($field['default'] === '') {
|
||||
$field['default'] = empty($field['notnull']) ? null : 0;
|
||||
}
|
||||
$default = ' DEFAULT '.$this->quote($field['default'], 'integer');
|
||||
} elseif (empty($field['notnull'])) {
|
||||
$default = ' DEFAULT NULL';
|
||||
}
|
||||
|
||||
$notnull = empty($field['notnull']) ? '' : ' NOT NULL';
|
||||
$unsigned = empty($field['unsigned']) ? '' : ' UNSIGNED';
|
||||
$name = $db->quoteIdentifier($name, true);
|
||||
return $name.' '.$this->getTypeDeclaration($field).$unsigned.$default.$notnull;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$match = '';
|
||||
if (null !== $operator) {
|
||||
$field = (null === $field) ? '' : $field.' ';
|
||||
$operator = strtoupper($operator);
|
||||
switch ($operator) {
|
||||
// case insensitive
|
||||
case 'ILIKE':
|
||||
$match = $field.'LIKE ';
|
||||
break;
|
||||
case 'NOT ILIKE':
|
||||
$match = $field.'NOT LIKE ';
|
||||
break;
|
||||
// case sensitive
|
||||
case 'LIKE':
|
||||
$match = $field.'LIKE BINARY ';
|
||||
break;
|
||||
case 'NOT LIKE':
|
||||
$match = $field.'NOT LIKE BINARY ';
|
||||
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 {
|
||||
$match.= $db->escapePattern($db->escape($value));
|
||||
}
|
||||
}
|
||||
$match.= "'";
|
||||
$match.= $this->patternEscapeString();
|
||||
return $match;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _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_type = strtolower($field['type']);
|
||||
$db_type = strtok($db_type, '(), ');
|
||||
if ($db_type == 'national') {
|
||||
$db_type = strtok('(), ');
|
||||
}
|
||||
if (!empty($field['length'])) {
|
||||
$length = strtok($field['length'], ', ');
|
||||
$decimal = strtok(', ');
|
||||
} else {
|
||||
$length = strtok('(), ');
|
||||
$decimal = strtok('(), ');
|
||||
}
|
||||
$type = array();
|
||||
$unsigned = $fixed = null;
|
||||
switch ($db_type) {
|
||||
case 'tinyint':
|
||||
$type[] = 'integer';
|
||||
$type[] = 'boolean';
|
||||
if (preg_match('/^(is|has)/', $field['name'])) {
|
||||
$type = array_reverse($type);
|
||||
}
|
||||
$unsigned = preg_match('/ unsigned/i', $field['type']);
|
||||
$length = 1;
|
||||
break;
|
||||
case 'smallint':
|
||||
$type[] = 'integer';
|
||||
$unsigned = preg_match('/ unsigned/i', $field['type']);
|
||||
$length = 2;
|
||||
break;
|
||||
case 'mediumint':
|
||||
$type[] = 'integer';
|
||||
$unsigned = preg_match('/ unsigned/i', $field['type']);
|
||||
$length = 3;
|
||||
break;
|
||||
case 'int':
|
||||
case 'integer':
|
||||
$type[] = 'integer';
|
||||
$unsigned = preg_match('/ unsigned/i', $field['type']);
|
||||
$length = 4;
|
||||
break;
|
||||
case 'bigint':
|
||||
$type[] = 'integer';
|
||||
$unsigned = preg_match('/ unsigned/i', $field['type']);
|
||||
$length = 8;
|
||||
break;
|
||||
case 'tinytext':
|
||||
case 'mediumtext':
|
||||
case 'longtext':
|
||||
case 'text':
|
||||
case 'varchar':
|
||||
$fixed = false;
|
||||
case 'string':
|
||||
case 'char':
|
||||
$type[] = 'text';
|
||||
if ($length == '1') {
|
||||
$type[] = 'boolean';
|
||||
if (preg_match('/^(is|has)/', $field['name'])) {
|
||||
$type = array_reverse($type);
|
||||
}
|
||||
} elseif (strstr($db_type, 'text')) {
|
||||
$type[] = 'clob';
|
||||
if ($decimal == 'binary') {
|
||||
$type[] = 'blob';
|
||||
}
|
||||
$type = array_reverse($type);
|
||||
}
|
||||
if ($fixed !== false) {
|
||||
$fixed = true;
|
||||
}
|
||||
break;
|
||||
case 'enum':
|
||||
$type[] = 'text';
|
||||
preg_match_all('/\'.+\'/U', $field['type'], $matches);
|
||||
$length = 0;
|
||||
$fixed = false;
|
||||
if (is_array($matches)) {
|
||||
foreach ($matches[0] as $value) {
|
||||
$length = max($length, strlen($value)-2);
|
||||
}
|
||||
if ($length == '1' && count($matches[0]) == 2) {
|
||||
$type[] = 'boolean';
|
||||
if (preg_match('/^(is|has)/', $field['name'])) {
|
||||
$type = array_reverse($type);
|
||||
}
|
||||
}
|
||||
}
|
||||
$type[] = 'integer';
|
||||
case 'set':
|
||||
$fixed = false;
|
||||
$type[] = 'text';
|
||||
$type[] = 'integer';
|
||||
break;
|
||||
case 'date':
|
||||
$type[] = 'date';
|
||||
$length = null;
|
||||
break;
|
||||
case 'datetime':
|
||||
case 'timestamp':
|
||||
$type[] = 'timestamp';
|
||||
$length = null;
|
||||
break;
|
||||
case 'time':
|
||||
$type[] = 'time';
|
||||
$length = null;
|
||||
break;
|
||||
case 'float':
|
||||
case 'double':
|
||||
case 'real':
|
||||
$type[] = 'float';
|
||||
$unsigned = preg_match('/ unsigned/i', $field['type']);
|
||||
if ($decimal !== false) {
|
||||
$length = $length.','.$decimal;
|
||||
}
|
||||
break;
|
||||
case 'unknown':
|
||||
case 'decimal':
|
||||
case 'numeric':
|
||||
$type[] = 'decimal';
|
||||
$unsigned = preg_match('/ unsigned/i', $field['type']);
|
||||
if ($decimal !== false) {
|
||||
$length = $length.','.$decimal;
|
||||
}
|
||||
break;
|
||||
case 'tinyblob':
|
||||
case 'mediumblob':
|
||||
case 'longblob':
|
||||
case 'blob':
|
||||
$type[] = 'blob';
|
||||
$length = null;
|
||||
break;
|
||||
case 'binary':
|
||||
case 'varbinary':
|
||||
$type[] = 'blob';
|
||||
break;
|
||||
case 'year':
|
||||
$type[] = 'integer';
|
||||
$type[] = 'date';
|
||||
$length = null;
|
||||
break;
|
||||
default:
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
|
||||
'unknown database attribute type: '.$db_type, __FUNCTION__);
|
||||
}
|
||||
|
||||
if ((int)$length <= 0) {
|
||||
$length = null;
|
||||
}
|
||||
|
||||
return array($type, $length, $unsigned, $fixed);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ mapPrepareDatatype()
|
||||
|
||||
/**
|
||||
* Maps an MDB2 datatype to native prepare type
|
||||
*
|
||||
* @param string $type
|
||||
* @return string
|
||||
* @access public
|
||||
*/
|
||||
function mapPrepareDatatype($type)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::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));
|
||||
}
|
||||
}
|
||||
|
||||
switch ($type) {
|
||||
case 'boolean':
|
||||
case 'integer':
|
||||
return 'i';
|
||||
case 'float':
|
||||
return 'd';
|
||||
case 'blob':
|
||||
return 'b';
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 's';
|
||||
}
|
||||
|
||||
// }}}
|
||||
}
|
||||
?>
|
499
extlib/MDB2/Driver/Datatype/oci8.php
Normal file
499
extlib/MDB2/Driver/Datatype/oci8.php
Normal file
@ -0,0 +1,499 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 and 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Copyright (c) 1998-2007 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Author: Lukas Smith <smith@pooteeweet.org> |
|
||||
// +----------------------------------------------------------------------+
|
||||
|
||||
// $Id$
|
||||
|
||||
require_once 'MDB2/Driver/Datatype/Common.php';
|
||||
|
||||
/**
|
||||
* MDB2 OCI8 driver
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lukas Smith <smith@pooteeweet.org>
|
||||
*/
|
||||
class MDB2_Driver_Datatype_oci8 extends MDB2_Driver_Datatype_Common
|
||||
{
|
||||
// {{{ _baseConvertResult()
|
||||
|
||||
/**
|
||||
* general type conversion method
|
||||
*
|
||||
* @param mixed $value refernce 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 a MDB2 error on failure
|
||||
* @access protected
|
||||
*/
|
||||
function _baseConvertResult($value, $type, $rtrim = true)
|
||||
{
|
||||
if (null === $value) {
|
||||
return null;
|
||||
}
|
||||
switch ($type) {
|
||||
case 'text':
|
||||
if (is_object($value) && is_a($value, 'OCI-Lob')) {
|
||||
//LOB => fetch into variable
|
||||
$clob = $this->_baseConvertResult($value, 'clob', $rtrim);
|
||||
if (!MDB2::isError($clob) && is_resource($clob)) {
|
||||
$clob_value = '';
|
||||
while (!feof($clob)) {
|
||||
$clob_value .= fread($clob, 8192);
|
||||
}
|
||||
$this->destroyLOB($clob);
|
||||
}
|
||||
$value = $clob_value;
|
||||
}
|
||||
if ($rtrim) {
|
||||
$value = rtrim($value);
|
||||
}
|
||||
return $value;
|
||||
case 'date':
|
||||
return substr($value, 0, strlen('YYYY-MM-DD'));
|
||||
case 'time':
|
||||
return substr($value, strlen('YYYY-MM-DD '), strlen('HH:MI:SS'));
|
||||
}
|
||||
return parent::_baseConvertResult($value, $type, $rtrim);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 (MDB2::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 ? 'CHAR('.$length.')' : 'VARCHAR2('.$length.')';
|
||||
case 'clob':
|
||||
return 'CLOB';
|
||||
case 'blob':
|
||||
return 'BLOB';
|
||||
case 'integer':
|
||||
if (!empty($field['length'])) {
|
||||
switch((int)$field['length']) {
|
||||
case 1: $digit = 3; break;
|
||||
case 2: $digit = 5; break;
|
||||
case 3: $digit = 8; break;
|
||||
case 4: $digit = 10; break;
|
||||
case 5: $digit = 13; break;
|
||||
case 6: $digit = 15; break;
|
||||
case 7: $digit = 17; break;
|
||||
case 8: $digit = 20; break;
|
||||
default: $digit = 10;
|
||||
}
|
||||
return 'NUMBER('.$digit.')';
|
||||
}
|
||||
return 'INT';
|
||||
case 'boolean':
|
||||
return 'NUMBER(1)';
|
||||
case 'date':
|
||||
case 'time':
|
||||
case 'timestamp':
|
||||
return 'DATE';
|
||||
case 'float':
|
||||
return 'NUMBER';
|
||||
case 'decimal':
|
||||
$scale = !empty($field['scale']) ? $field['scale'] : $db->options['decimal_places'];
|
||||
return 'NUMBER(*,'.$scale.')';
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _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 'EMPTY_CLOB()';
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _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 'EMPTY_BLOB()';
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _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)
|
||||
{
|
||||
return $this->_quoteText("$value 00:00:00", $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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
return $this->_quoteText("0001-01-01 $value", $quote, $escape_wildcards);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ writeLOBToFile()
|
||||
|
||||
/**
|
||||
* retrieve LOB from the database
|
||||
*
|
||||
* @param array $lob array
|
||||
* @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)
|
||||
{
|
||||
if (preg_match('/^(\w+:\/\/)(.*)$/', $file, $match)) {
|
||||
if ($match[1] == 'file://') {
|
||||
$file = $match[2];
|
||||
}
|
||||
}
|
||||
$lob_data = stream_get_meta_data($lob);
|
||||
$lob_index = $lob_data['wrapper_data']->lob_index;
|
||||
$result = $this->lobs[$lob_index]['resource']->writetofile($file);
|
||||
$this->lobs[$lob_index]['resource']->seek(0);
|
||||
if (!$result) {
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
return $db->raiseError(null, null, null,
|
||||
'Unable to write LOB to file', __FUNCTION__);
|
||||
}
|
||||
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_object($lob['resource'])) {
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
'attemped to retrieve LOB from non existing or NULL column', __FUNCTION__);
|
||||
}
|
||||
|
||||
if (!$lob['loaded']
|
||||
# && !method_exists($lob['resource'], 'read')
|
||||
) {
|
||||
$lob['value'] = $lob['resource']->load();
|
||||
$lob['resource']->seek(0);
|
||||
}
|
||||
$lob['loaded'] = true;
|
||||
return MDB2_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _readLOB()
|
||||
|
||||
/**
|
||||
* Read data from large object input stream.
|
||||
*
|
||||
* @param array $lob array
|
||||
* @param blob $data reference to a variable that will hold data to be
|
||||
* read from the large object input stream
|
||||
* @param int $length integer value that indicates the largest ammount of
|
||||
* data to be read from the large object input stream.
|
||||
* @return mixed length on success, a MDB2 error on failure
|
||||
* @access protected
|
||||
*/
|
||||
function _readLOB($lob, $length)
|
||||
{
|
||||
if ($lob['loaded']) {
|
||||
return parent::_readLOB($lob, $length);
|
||||
}
|
||||
|
||||
if (!is_object($lob['resource'])) {
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
'attemped to retrieve LOB from non existing or NULL column', __FUNCTION__);
|
||||
}
|
||||
|
||||
$data = $lob['resource']->read($length);
|
||||
if (!is_string($data)) {
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
return $db->raiseError(null, null, null,
|
||||
'Unable to read LOB', __FUNCTION__);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ patternEscapeString()
|
||||
|
||||
/**
|
||||
* build string to define escape pattern string
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
*
|
||||
* @return string define escape pattern
|
||||
*/
|
||||
function patternEscapeString()
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
return " ESCAPE '". $db->string_quoting['escape_pattern'] ."'";
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _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_type = strtolower($field['type']);
|
||||
$type = array();
|
||||
$length = $unsigned = $fixed = null;
|
||||
if (!empty($field['length'])) {
|
||||
$length = $field['length'];
|
||||
}
|
||||
switch ($db_type) {
|
||||
case 'integer':
|
||||
case 'pls_integer':
|
||||
case 'binary_integer':
|
||||
$type[] = 'integer';
|
||||
if ($length == '1') {
|
||||
$type[] = 'boolean';
|
||||
if (preg_match('/^(is|has)/', $field['name'])) {
|
||||
$type = array_reverse($type);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'varchar':
|
||||
case 'varchar2':
|
||||
case 'nvarchar2':
|
||||
$fixed = false;
|
||||
case 'char':
|
||||
case 'nchar':
|
||||
$type[] = 'text';
|
||||
if ($length == '1') {
|
||||
$type[] = 'boolean';
|
||||
if (preg_match('/^(is|has)/', $field['name'])) {
|
||||
$type = array_reverse($type);
|
||||
}
|
||||
}
|
||||
if ($fixed !== false) {
|
||||
$fixed = true;
|
||||
}
|
||||
break;
|
||||
case 'date':
|
||||
case 'timestamp':
|
||||
$type[] = 'timestamp';
|
||||
$length = null;
|
||||
break;
|
||||
case 'float':
|
||||
$type[] = 'float';
|
||||
break;
|
||||
case 'number':
|
||||
if (!empty($field['scale'])) {
|
||||
$type[] = 'decimal';
|
||||
$length = $length.','.$field['scale'];
|
||||
} else {
|
||||
$type[] = 'integer';
|
||||
if ($length == '1') {
|
||||
$type[] = 'boolean';
|
||||
if (preg_match('/^(is|has)/', $field['name'])) {
|
||||
$type = array_reverse($type);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'long':
|
||||
$type[] = 'text';
|
||||
case 'clob':
|
||||
case 'nclob':
|
||||
$type[] = 'clob';
|
||||
break;
|
||||
case 'blob':
|
||||
case 'raw':
|
||||
case 'long raw':
|
||||
case 'bfile':
|
||||
$type[] = 'blob';
|
||||
$length = null;
|
||||
break;
|
||||
case 'rowid':
|
||||
case 'urowid':
|
||||
default:
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
|
||||
'unknown database attribute type: '.$db_type, __FUNCTION__);
|
||||
}
|
||||
|
||||
if ((int)$length <= 0) {
|
||||
$length = null;
|
||||
}
|
||||
|
||||
return array($type, $length, $unsigned, $fixed);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
397
extlib/MDB2/Driver/Datatype/odbc.php
Normal file
397
extlib/MDB2/Driver/Datatype/odbc.php
Normal file
@ -0,0 +1,397 @@
|
||||
<?php
|
||||
|
||||
|
||||
require_once 'MDB2/Driver/Datatype/Common.php';
|
||||
|
||||
/**
|
||||
* MDB2 MS SQL driver
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lukas Smith <smith@pooteeweet.org>
|
||||
*/
|
||||
class MDB2_Driver_Datatype_odbc extends MDB2_Driver_Datatype_Common
|
||||
{
|
||||
// {{{ _baseConvertResult()
|
||||
|
||||
/**
|
||||
* general type conversion method
|
||||
*
|
||||
* @param mixed $value refernce 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 a MDB2 error on failure
|
||||
* @access protected
|
||||
*/
|
||||
function _baseConvertResult($value, $type, $rtrim = true)
|
||||
{
|
||||
if (is_null($value)) {
|
||||
return null;
|
||||
}
|
||||
switch ($type) {
|
||||
case 'boolean':
|
||||
return $value == '1';
|
||||
case 'date':
|
||||
if (strlen($value) > 10) {
|
||||
$value = substr($value,0,10);
|
||||
}
|
||||
return $value;
|
||||
case 'time':
|
||||
if (strlen($value) > 8) {
|
||||
$value = substr($value,11,8);
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
return parent::_baseConvertResult($value, $type, $rtrim);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _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 'COLLATE '.$collation;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
switch ($field['type']) {
|
||||
case 'text':
|
||||
$length = !empty($field['length'])
|
||||
? $field['length'] : false;
|
||||
$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':
|
||||
if (!empty($field['length'])) {
|
||||
$length = $field['length'];
|
||||
if ($length <= 8000) {
|
||||
return 'VARCHAR('.$length.')';
|
||||
}
|
||||
}
|
||||
return 'TEXT';
|
||||
case 'blob':
|
||||
if (!empty($field['length'])) {
|
||||
$length = $field['length'];
|
||||
if ($length <= 8000) {
|
||||
return "VARBINARY($length)";
|
||||
}
|
||||
}
|
||||
return 'IMAGE';
|
||||
case 'integer':
|
||||
return 'INT';
|
||||
case 'boolean':
|
||||
return 'BIT';
|
||||
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 'FLOAT';
|
||||
case 'decimal':
|
||||
$length = !empty($field['length']) ? $field['length'] : 18;
|
||||
$scale = !empty($field['scale']) ? $field['scale'] : $db->options['decimal_places'];
|
||||
return 'DECIMAL('.$length.','.$scale.')';
|
||||
}
|
||||
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 string $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)
|
||||
{
|
||||
$db =& $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$notnull = empty($field['notnull']) ? ' NULL' : ' NOT NULL';
|
||||
$default = $autoinc = '';
|
||||
if (!empty($field['autoincrement'])) {
|
||||
$autoinc = ' IDENTITY PRIMARY KEY';
|
||||
} elseif (array_key_exists('default', $field)) {
|
||||
if ($field['default'] === '') {
|
||||
$field['default'] = 0;
|
||||
}
|
||||
if (is_null($field['default'])) {
|
||||
$default = ' DEFAULT (null)';
|
||||
} else {
|
||||
$default = ' DEFAULT (' . $this->quote($field['default'], 'integer') . ')';
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($field['unsigned'])) {
|
||||
$db->warnings[] = "unsigned integer field \"$name\" is being declared as signed integer";
|
||||
}
|
||||
|
||||
$name = $db->quoteIdentifier($name, true);
|
||||
return $name.' '.$this->getTypeDeclaration($field).$notnull.$default.$autoinc;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$notnull = empty($field['notnull']) ? ' NULL' : ' 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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$notnull = empty($field['notnull']) ? ' NULL' : ' NOT NULL';
|
||||
$name = $db->quoteIdentifier($name, true);
|
||||
return $name.' '.$this->getTypeDeclaration($field).$notnull;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _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)
|
||||
{
|
||||
if (!$quote) {
|
||||
return $value;
|
||||
}
|
||||
$value = '0x'.bin2hex($this->_readFile($value));
|
||||
return $value;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _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)
|
||||
{
|
||||
|
||||
// todo: handle length of various int variations
|
||||
$db_type = preg_replace('/\d/', '', strtolower($field['type']));
|
||||
$length = $field['length'];
|
||||
$type = array();
|
||||
// todo: unsigned handling seems to be missing
|
||||
$unsigned = $fixed = null;
|
||||
switch ($db_type) {
|
||||
case 'bit':
|
||||
$type[0] = 'boolean';
|
||||
break;
|
||||
case 'tinyint':
|
||||
$type[0] = 'integer';
|
||||
$length = 1;
|
||||
break;
|
||||
case 'smallint':
|
||||
$type[0] = 'integer';
|
||||
$length = 2;
|
||||
break;
|
||||
case 'integer':
|
||||
$type[0] = 'integer';
|
||||
$length = 4;
|
||||
break;
|
||||
case 'bigint':
|
||||
$type[0] = 'integer';
|
||||
$length = 8;
|
||||
break;
|
||||
case 'smalldatetime':
|
||||
case 'timestamp':
|
||||
case 'time':
|
||||
case 'date':
|
||||
$type[0] = 'timestamp';
|
||||
break;
|
||||
case 'float':
|
||||
case 'real':
|
||||
case 'numeric':
|
||||
$type[0] = 'float';
|
||||
break;
|
||||
case 'decimal':
|
||||
case 'money':
|
||||
$type[0] = 'decimal';
|
||||
$length = $field['numeric_precision'].','.$field['numeric_scale'];
|
||||
break;
|
||||
case 'text':
|
||||
case 'ntext':
|
||||
case 'varchar() for bit data':
|
||||
case 'varchar':
|
||||
case 'nvarchar':
|
||||
$fixed = false;
|
||||
case 'char':
|
||||
case 'nchar':
|
||||
$type[0] = 'text';
|
||||
if ($length == '1') {
|
||||
$type[] = 'boolean';
|
||||
if (preg_match('/^(is|has)/', $field['name'])) {
|
||||
$type = array_reverse($type);
|
||||
}
|
||||
} elseif (strstr($db_type, 'text')) {
|
||||
$type[] = 'clob';
|
||||
$type = array_reverse($type);
|
||||
}
|
||||
if ($fixed !== false) {
|
||||
$fixed = true;
|
||||
}
|
||||
break;
|
||||
case 'image':
|
||||
case 'blob':
|
||||
case 'vargraphic() ccsid ':
|
||||
case 'varbinary':
|
||||
$type[] = 'blob';
|
||||
$length = null;
|
||||
break;
|
||||
default:
|
||||
$db =& $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
|
||||
'unknown database attribute type: '.$db_type, __FUNCTION__);
|
||||
}
|
||||
|
||||
if ((int)$length <= 0) {
|
||||
$length = null;
|
||||
}
|
||||
|
||||
return array($type, $length, $unsigned, $fixed);
|
||||
}
|
||||
// }}}
|
||||
}
|
||||
|
||||
?>
|
579
extlib/MDB2/Driver/Datatype/pgsql.php
Normal file
579
extlib/MDB2/Driver/Datatype/pgsql.php
Normal file
@ -0,0 +1,579 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 and 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Copyright (c) 1998-2007 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Author: Paul Cooper <pgc@ucecom.com> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id$
|
||||
|
||||
require_once 'MDB2/Driver/Datatype/Common.php';
|
||||
|
||||
/**
|
||||
* MDB2 PostGreSQL driver
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Paul Cooper <pgc@ucecom.com>
|
||||
*/
|
||||
class MDB2_Driver_Datatype_pgsql extends MDB2_Driver_Datatype_Common
|
||||
{
|
||||
// {{{ _baseConvertResult()
|
||||
|
||||
/**
|
||||
* General type conversion method
|
||||
*
|
||||
* @param mixed $value refernce 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 a MDB2 error on failure
|
||||
* @access protected
|
||||
*/
|
||||
function _baseConvertResult($value, $type, $rtrim = true)
|
||||
{
|
||||
if (null === $value) {
|
||||
return null;
|
||||
}
|
||||
switch ($type) {
|
||||
case 'boolean':
|
||||
return ($value == 'f')? false : !empty($value);
|
||||
case 'float':
|
||||
return doubleval($value);
|
||||
case 'date':
|
||||
return $value;
|
||||
case 'time':
|
||||
return substr($value, 0, strlen('HH:MM:SS'));
|
||||
case 'timestamp':
|
||||
return substr($value, 0, strlen('YYYY-MM-DD HH:MM:SS'));
|
||||
case 'blob':
|
||||
$value = pg_unescape_bytea($value);
|
||||
return parent::_baseConvertResult($value, $type, $rtrim);
|
||||
}
|
||||
return parent::_baseConvertResult($value, $type, $rtrim);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
switch ($field['type']) {
|
||||
case 'text':
|
||||
$length = !empty($field['length']) ? $field['length'] : false;
|
||||
$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 'BYTEA';
|
||||
case 'integer':
|
||||
if (!empty($field['autoincrement'])) {
|
||||
if (!empty($field['length'])) {
|
||||
$length = $field['length'];
|
||||
if ($length > 4) {
|
||||
return 'BIGSERIAL PRIMARY KEY';
|
||||
}
|
||||
}
|
||||
return 'SERIAL PRIMARY KEY';
|
||||
}
|
||||
if (!empty($field['length'])) {
|
||||
$length = $field['length'];
|
||||
if ($length <= 2) {
|
||||
return 'SMALLINT';
|
||||
} elseif ($length == 3 || $length == 4) {
|
||||
return 'INT';
|
||||
} elseif ($length > 4) {
|
||||
return 'BIGINT';
|
||||
}
|
||||
}
|
||||
return 'INT';
|
||||
case 'boolean':
|
||||
return 'BOOLEAN';
|
||||
case 'date':
|
||||
return 'DATE';
|
||||
case 'time':
|
||||
return 'TIME without time zone';
|
||||
case 'timestamp':
|
||||
return 'TIMESTAMP without time zone';
|
||||
case 'float':
|
||||
return 'FLOAT8';
|
||||
case 'decimal':
|
||||
$length = !empty($field['length']) ? $field['length'] : 18;
|
||||
$scale = !empty($field['scale']) ? $field['scale'] : $db->options['decimal_places'];
|
||||
return 'NUMERIC('.$length.','.$scale.')';
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _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)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
if (!empty($field['unsigned'])) {
|
||||
$db->warnings[] = "unsigned integer field \"$name\" is being declared as signed integer";
|
||||
}
|
||||
if (!empty($field['autoincrement'])) {
|
||||
$name = $db->quoteIdentifier($name, true);
|
||||
return $name.' '.$this->getTypeDeclaration($field);
|
||||
}
|
||||
$default = '';
|
||||
if (array_key_exists('default', $field)) {
|
||||
if ($field['default'] === '') {
|
||||
$field['default'] = empty($field['notnull']) ? null : 0;
|
||||
}
|
||||
$default = ' DEFAULT '.$this->quote($field['default'], 'integer');
|
||||
}
|
||||
|
||||
$notnull = empty($field['notnull']) ? '' : ' NOT NULL';
|
||||
if (empty($default) && empty($notnull)) {
|
||||
$default = ' DEFAULT NULL';
|
||||
}
|
||||
$name = $db->quoteIdentifier($name, true);
|
||||
return $name.' '.$this->getTypeDeclaration($field).$default.$notnull;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _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)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
if ($db->options['lob_allow_url_include']) {
|
||||
$value = $this->_readFile($value);
|
||||
if (MDB2::isError($value)) {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
return $this->_quoteText($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)
|
||||
{
|
||||
if (!$quote) {
|
||||
return $value;
|
||||
}
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
if ($db->options['lob_allow_url_include']) {
|
||||
$value = $this->_readFile($value);
|
||||
if (MDB2::isError($value)) {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
if (version_compare(PHP_VERSION, '5.2.0RC6', '>=')) {
|
||||
$connection = $db->getConnection();
|
||||
if (MDB2::isError($connection)) {
|
||||
return $connection;
|
||||
}
|
||||
$value = @pg_escape_bytea($connection, $value);
|
||||
} else {
|
||||
$value = @pg_escape_bytea($value);
|
||||
}
|
||||
return "'".$value."'";
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _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)
|
||||
{
|
||||
$value = $value ? 't' : 'f';
|
||||
if (!$quote) {
|
||||
return $value;
|
||||
}
|
||||
return "'".$value."'";
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$match = '';
|
||||
if (null !== $operator) {
|
||||
$field = (null === $field) ? '' : $field.' ';
|
||||
$operator = strtoupper($operator);
|
||||
switch ($operator) {
|
||||
// case insensitive
|
||||
case 'ILIKE':
|
||||
$match = $field.'ILIKE ';
|
||||
break;
|
||||
case 'NOT ILIKE':
|
||||
$match = $field.'NOT ILIKE ';
|
||||
break;
|
||||
// case sensitive
|
||||
case 'LIKE':
|
||||
$match = $field.'LIKE ';
|
||||
break;
|
||||
case 'NOT LIKE':
|
||||
$match = $field.'NOT 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 {
|
||||
$match.= $db->escapePattern($db->escape($value));
|
||||
}
|
||||
}
|
||||
$match.= "'";
|
||||
$match.= $this->patternEscapeString();
|
||||
return $match;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ patternEscapeString()
|
||||
|
||||
/**
|
||||
* build string to define escape pattern string
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
*
|
||||
* @return string define escape pattern
|
||||
*/
|
||||
function patternEscapeString()
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
return ' ESCAPE '.$this->quote($db->string_quoting['escape_pattern']);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _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_type = strtolower($field['type']);
|
||||
$length = $field['length'];
|
||||
$type = array();
|
||||
$unsigned = $fixed = null;
|
||||
switch ($db_type) {
|
||||
case 'smallint':
|
||||
case 'int2':
|
||||
$type[] = 'integer';
|
||||
$unsigned = false;
|
||||
$length = 2;
|
||||
if ($length == '2') {
|
||||
$type[] = 'boolean';
|
||||
if (preg_match('/^(is|has)/', $field['name'])) {
|
||||
$type = array_reverse($type);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'int':
|
||||
case 'int4':
|
||||
case 'integer':
|
||||
case 'serial':
|
||||
case 'serial4':
|
||||
$type[] = 'integer';
|
||||
$unsigned = false;
|
||||
$length = 4;
|
||||
break;
|
||||
case 'bigint':
|
||||
case 'int8':
|
||||
case 'bigserial':
|
||||
case 'serial8':
|
||||
$type[] = 'integer';
|
||||
$unsigned = false;
|
||||
$length = 8;
|
||||
break;
|
||||
case 'bool':
|
||||
case 'boolean':
|
||||
$type[] = 'boolean';
|
||||
$length = null;
|
||||
break;
|
||||
case 'text':
|
||||
case 'varchar':
|
||||
$fixed = false;
|
||||
case 'unknown':
|
||||
case 'char':
|
||||
case 'bpchar':
|
||||
$type[] = 'text';
|
||||
if ($length == '1') {
|
||||
$type[] = 'boolean';
|
||||
if (preg_match('/^(is|has)/', $field['name'])) {
|
||||
$type = array_reverse($type);
|
||||
}
|
||||
} elseif (strstr($db_type, 'text')) {
|
||||
$type[] = 'clob';
|
||||
$type = array_reverse($type);
|
||||
}
|
||||
if ($fixed !== false) {
|
||||
$fixed = true;
|
||||
}
|
||||
break;
|
||||
case 'date':
|
||||
$type[] = 'date';
|
||||
$length = null;
|
||||
break;
|
||||
case 'datetime':
|
||||
case 'timestamp':
|
||||
case 'timestamptz':
|
||||
$type[] = 'timestamp';
|
||||
$length = null;
|
||||
break;
|
||||
case 'time':
|
||||
$type[] = 'time';
|
||||
$length = null;
|
||||
break;
|
||||
case 'float':
|
||||
case 'float4':
|
||||
case 'float8':
|
||||
case 'double':
|
||||
case 'real':
|
||||
$type[] = 'float';
|
||||
break;
|
||||
case 'decimal':
|
||||
case 'money':
|
||||
case 'numeric':
|
||||
$type[] = 'decimal';
|
||||
if (isset($field['scale'])) {
|
||||
$length = $length.','.$field['scale'];
|
||||
}
|
||||
break;
|
||||
case 'tinyblob':
|
||||
case 'mediumblob':
|
||||
case 'longblob':
|
||||
case 'blob':
|
||||
case 'bytea':
|
||||
$type[] = 'blob';
|
||||
$length = null;
|
||||
break;
|
||||
case 'oid':
|
||||
$type[] = 'blob';
|
||||
$type[] = 'clob';
|
||||
$length = null;
|
||||
break;
|
||||
case 'year':
|
||||
$type[] = 'integer';
|
||||
$type[] = 'date';
|
||||
$length = null;
|
||||
break;
|
||||
default:
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
|
||||
'unknown database attribute type: '.$db_type, __FUNCTION__);
|
||||
}
|
||||
|
||||
if ((int)$length <= 0) {
|
||||
$length = null;
|
||||
}
|
||||
|
||||
return array($type, $length, $unsigned, $fixed);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ mapPrepareDatatype()
|
||||
|
||||
/**
|
||||
* Maps an mdb2 datatype to native prepare type
|
||||
*
|
||||
* @param string $type
|
||||
* @return string
|
||||
* @access public
|
||||
*/
|
||||
function mapPrepareDatatype($type)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::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));
|
||||
}
|
||||
}
|
||||
|
||||
switch ($type) {
|
||||
case 'integer':
|
||||
return 'int';
|
||||
case 'boolean':
|
||||
return 'bool';
|
||||
case 'decimal':
|
||||
case 'float':
|
||||
return 'numeric';
|
||||
case 'clob':
|
||||
return 'text';
|
||||
case 'blob':
|
||||
return 'bytea';
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return $type;
|
||||
}
|
||||
// }}}
|
||||
}
|
||||
?>
|
99
extlib/MDB2/Driver/Datatype/querysim.php
Normal file
99
extlib/MDB2/Driver/Datatype/querysim.php
Normal file
@ -0,0 +1,99 @@
|
||||
<?php
|
||||
// vim: set et ts=4 sw=4 fdm=marker:
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 and 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Author: Lukas Smith <smith@pooteeweet.org> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
|
||||
require_once 'MDB2/Driver/Datatype/Common.php';
|
||||
|
||||
/**
|
||||
* MDB2 QuerySim driver
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lukas Smith <smith@pooteeweet.org>
|
||||
*/
|
||||
class MDB2_Driver_Datatype_querysim extends MDB2_Driver_Datatype_Common
|
||||
{
|
||||
// {{{ 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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
|
||||
'method not implemented', __FUNCTION__);
|
||||
}
|
||||
|
||||
// }}}
|
||||
}
|
||||
|
||||
?>
|
418
extlib/MDB2/Driver/Datatype/sqlite.php
Normal file
418
extlib/MDB2/Driver/Datatype/sqlite.php
Normal file
@ -0,0 +1,418 @@
|
||||
<?php
|
||||
// vim: set et ts=4 sw=4 fdm=marker:
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 and 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Copyright (c) 1998-2007 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Author: Lukas Smith <smith@pooteeweet.org> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
|
||||
require_once 'MDB2/Driver/Datatype/Common.php';
|
||||
|
||||
/**
|
||||
* MDB2 SQLite driver
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lukas Smith <smith@pooteeweet.org>
|
||||
*/
|
||||
class MDB2_Driver_Datatype_sqlite extends MDB2_Driver_Datatype_Common
|
||||
{
|
||||
// {{{ _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 'COLLATE '.$collation;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
switch ($field['type']) {
|
||||
case 'text':
|
||||
$length = !empty($field['length'])
|
||||
? $field['length'] : false;
|
||||
$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':
|
||||
if (!empty($field['length'])) {
|
||||
$length = $field['length'];
|
||||
if ($length <= 255) {
|
||||
return 'TINYTEXT';
|
||||
} elseif ($length <= 65532) {
|
||||
return 'TEXT';
|
||||
} elseif ($length <= 16777215) {
|
||||
return 'MEDIUMTEXT';
|
||||
}
|
||||
}
|
||||
return 'LONGTEXT';
|
||||
case 'blob':
|
||||
if (!empty($field['length'])) {
|
||||
$length = $field['length'];
|
||||
if ($length <= 255) {
|
||||
return 'TINYBLOB';
|
||||
} elseif ($length <= 65532) {
|
||||
return 'BLOB';
|
||||
} elseif ($length <= 16777215) {
|
||||
return 'MEDIUMBLOB';
|
||||
}
|
||||
}
|
||||
return 'LONGBLOB';
|
||||
case 'integer':
|
||||
if (!empty($field['length'])) {
|
||||
$length = $field['length'];
|
||||
if ($length <= 2) {
|
||||
return 'SMALLINT';
|
||||
} elseif ($length == 3 || $length == 4) {
|
||||
return 'INTEGER';
|
||||
} elseif ($length > 4) {
|
||||
return 'BIGINT';
|
||||
}
|
||||
}
|
||||
return 'INTEGER';
|
||||
case 'boolean':
|
||||
return 'BOOLEAN';
|
||||
case 'date':
|
||||
return 'DATE';
|
||||
case 'time':
|
||||
return 'TIME';
|
||||
case 'timestamp':
|
||||
return 'DATETIME';
|
||||
case 'float':
|
||||
return 'DOUBLE'.($db->options['fixed_float'] ? '('.
|
||||
($db->options['fixed_float']+2).','.$db->options['fixed_float'].')' : '');
|
||||
case 'decimal':
|
||||
$length = !empty($field['length']) ? $field['length'] : 18;
|
||||
$scale = !empty($field['scale']) ? $field['scale'] : $db->options['decimal_places'];
|
||||
return 'DECIMAL('.$length.','.$scale.')';
|
||||
}
|
||||
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 string $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)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$default = $autoinc = '';
|
||||
if (!empty($field['autoincrement'])) {
|
||||
$autoinc = ' PRIMARY KEY';
|
||||
} elseif (array_key_exists('default', $field)) {
|
||||
if ($field['default'] === '') {
|
||||
$field['default'] = empty($field['notnull']) ? null : 0;
|
||||
}
|
||||
$default = ' DEFAULT '.$this->quote($field['default'], 'integer');
|
||||
}
|
||||
|
||||
$notnull = empty($field['notnull']) ? '' : ' NOT NULL';
|
||||
$unsigned = empty($field['unsigned']) ? '' : ' UNSIGNED';
|
||||
if (empty($default) && empty($notnull)) {
|
||||
$default = ' DEFAULT NULL';
|
||||
}
|
||||
$name = $db->quoteIdentifier($name, true);
|
||||
return $name.' '.$this->getTypeDeclaration($field).$unsigned.$default.$notnull.$autoinc;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$match = '';
|
||||
if (null !== $operator) {
|
||||
$field = (null === $field) ? '' : $field.' ';
|
||||
$operator = strtoupper($operator);
|
||||
switch ($operator) {
|
||||
// case insensitive
|
||||
case 'ILIKE':
|
||||
$match = $field.'LIKE ';
|
||||
break;
|
||||
case 'NOT ILIKE':
|
||||
$match = $field.'NOT LIKE ';
|
||||
break;
|
||||
// case sensitive
|
||||
case 'LIKE':
|
||||
$match = $field.'LIKE ';
|
||||
break;
|
||||
case 'NOT LIKE':
|
||||
$match = $field.'NOT 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 {
|
||||
$match.= $db->escapePattern($db->escape($value));
|
||||
}
|
||||
}
|
||||
$match.= "'";
|
||||
$match.= $this->patternEscapeString();
|
||||
return $match;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _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_type = strtolower($field['type']);
|
||||
$length = !empty($field['length']) ? $field['length'] : null;
|
||||
$unsigned = !empty($field['unsigned']) ? $field['unsigned'] : null;
|
||||
$fixed = null;
|
||||
$type = array();
|
||||
switch ($db_type) {
|
||||
case 'boolean':
|
||||
$type[] = 'boolean';
|
||||
break;
|
||||
case 'tinyint':
|
||||
$type[] = 'integer';
|
||||
$type[] = 'boolean';
|
||||
if (preg_match('/^(is|has)/', $field['name'])) {
|
||||
$type = array_reverse($type);
|
||||
}
|
||||
$unsigned = preg_match('/ unsigned/i', $field['type']);
|
||||
$length = 1;
|
||||
break;
|
||||
case 'smallint':
|
||||
$type[] = 'integer';
|
||||
$unsigned = preg_match('/ unsigned/i', $field['type']);
|
||||
$length = 2;
|
||||
break;
|
||||
case 'mediumint':
|
||||
$type[] = 'integer';
|
||||
$unsigned = preg_match('/ unsigned/i', $field['type']);
|
||||
$length = 3;
|
||||
break;
|
||||
case 'int':
|
||||
case 'integer':
|
||||
case 'serial':
|
||||
$type[] = 'integer';
|
||||
$unsigned = preg_match('/ unsigned/i', $field['type']);
|
||||
$length = 4;
|
||||
break;
|
||||
case 'bigint':
|
||||
case 'bigserial':
|
||||
$type[] = 'integer';
|
||||
$unsigned = preg_match('/ unsigned/i', $field['type']);
|
||||
$length = 8;
|
||||
break;
|
||||
case 'clob':
|
||||
$type[] = 'clob';
|
||||
$fixed = false;
|
||||
break;
|
||||
case 'tinytext':
|
||||
case 'mediumtext':
|
||||
case 'longtext':
|
||||
case 'text':
|
||||
case 'varchar':
|
||||
case 'varchar2':
|
||||
$fixed = false;
|
||||
case 'char':
|
||||
$type[] = 'text';
|
||||
if ($length == '1') {
|
||||
$type[] = 'boolean';
|
||||
if (preg_match('/^(is|has)/', $field['name'])) {
|
||||
$type = array_reverse($type);
|
||||
}
|
||||
} elseif (strstr($db_type, 'text')) {
|
||||
$type[] = 'clob';
|
||||
$type = array_reverse($type);
|
||||
}
|
||||
if ($fixed !== false) {
|
||||
$fixed = true;
|
||||
}
|
||||
break;
|
||||
case 'date':
|
||||
$type[] = 'date';
|
||||
$length = null;
|
||||
break;
|
||||
case 'datetime':
|
||||
case 'timestamp':
|
||||
$type[] = 'timestamp';
|
||||
$length = null;
|
||||
break;
|
||||
case 'time':
|
||||
$type[] = 'time';
|
||||
$length = null;
|
||||
break;
|
||||
case 'float':
|
||||
case 'double':
|
||||
case 'real':
|
||||
$type[] = 'float';
|
||||
break;
|
||||
case 'decimal':
|
||||
case 'numeric':
|
||||
$type[] = 'decimal';
|
||||
$length = $length.','.$field['decimal'];
|
||||
break;
|
||||
case 'tinyblob':
|
||||
case 'mediumblob':
|
||||
case 'longblob':
|
||||
case 'blob':
|
||||
$type[] = 'blob';
|
||||
$length = null;
|
||||
break;
|
||||
case 'year':
|
||||
$type[] = 'integer';
|
||||
$type[] = 'date';
|
||||
$length = null;
|
||||
break;
|
||||
default:
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
|
||||
'unknown database attribute type: '.$db_type, __FUNCTION__);
|
||||
}
|
||||
|
||||
if ((int)$length <= 0) {
|
||||
$length = null;
|
||||
}
|
||||
|
||||
return array($type, $length, $unsigned, $fixed);
|
||||
}
|
||||
|
||||
// }}}
|
||||
}
|
||||
|
||||
?>
|
451
extlib/MDB2/Driver/Datatype/sqlite3.php
Normal file
451
extlib/MDB2/Driver/Datatype/sqlite3.php
Normal file
@ -0,0 +1,451 @@
|
||||
<?php
|
||||
// vim: set et ts=4 sw=4 fdm=marker:
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 - 7 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Copyright (c) 1998-2007 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Author: Lorenzo Alberton <l.alberton@quipo.it> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
|
||||
require_once 'MDB2/Driver/Datatype/Common.php';
|
||||
|
||||
/**
|
||||
* MDB2 SQLite driver
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lorenzo Alberton <l.alberton@quipo.it>
|
||||
*/
|
||||
class MDB2_Driver_Datatype_sqlite3 extends MDB2_Driver_Datatype_Common
|
||||
{
|
||||
// {{{ _baseConvertResult()
|
||||
|
||||
/**
|
||||
* General type conversion method
|
||||
*
|
||||
* @param mixed $value refernce 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 a MDB2 error on failure
|
||||
* @access protected
|
||||
*/
|
||||
function _baseConvertResult($value, $type, $rtrim = true)
|
||||
{
|
||||
if (null === $value) {
|
||||
return null;
|
||||
}
|
||||
switch ($type) {
|
||||
case 'decimal':
|
||||
switch (gettype($value)) {
|
||||
case 'integer':
|
||||
//return (float)($value * 1.0);
|
||||
return sprintf('%0.2f', $value);
|
||||
case 'string':
|
||||
if (!strpos($value, '.')) {
|
||||
$value .= '.00';
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return parent::_baseConvertResult($value, $type, $rtrim);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _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 'COLLATE '.$collation;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
switch ($field['type']) {
|
||||
case 'text':
|
||||
$length = !empty($field['length'])
|
||||
? $field['length'] : false;
|
||||
$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':
|
||||
if (!empty($field['length'])) {
|
||||
$length = $field['length'];
|
||||
if ($length <= 255) {
|
||||
return 'TINYTEXT';
|
||||
} elseif ($length <= 65532) {
|
||||
return 'TEXT';
|
||||
} elseif ($length <= 16777215) {
|
||||
return 'MEDIUMTEXT';
|
||||
}
|
||||
}
|
||||
return 'LONGTEXT';
|
||||
case 'blob':
|
||||
if (!empty($field['length'])) {
|
||||
$length = $field['length'];
|
||||
if ($length <= 255) {
|
||||
return 'TINYBLOB';
|
||||
} elseif ($length <= 65532) {
|
||||
return 'BLOB';
|
||||
} elseif ($length <= 16777215) {
|
||||
return 'MEDIUMBLOB';
|
||||
}
|
||||
}
|
||||
return 'LONGBLOB';
|
||||
case 'integer':
|
||||
if (!empty($field['length'])) {
|
||||
$length = $field['length'];
|
||||
if ($length <= 2) {
|
||||
return 'SMALLINT';
|
||||
} elseif ($length == 3 || $length == 4) {
|
||||
return 'INTEGER';
|
||||
} elseif ($length > 4) {
|
||||
return 'BIGINT';
|
||||
}
|
||||
}
|
||||
return 'INTEGER';
|
||||
case 'boolean':
|
||||
return 'BOOLEAN';
|
||||
case 'date':
|
||||
return 'DATE';
|
||||
case 'time':
|
||||
return 'TIME';
|
||||
case 'timestamp':
|
||||
return 'DATETIME';
|
||||
case 'float':
|
||||
return 'DOUBLE'.($db->options['fixed_float'] ? '('.
|
||||
($db->options['fixed_float']+2).','.$db->options['fixed_float'].')' : '');
|
||||
case 'decimal':
|
||||
$length = !empty($field['length']) ? $field['length'] : 18;
|
||||
$scale = !empty($field['scale']) ? $field['scale'] : $db->options['decimal_places'];
|
||||
return 'DECIMAL('.$length.','.$scale.')';
|
||||
}
|
||||
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 string $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)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$default = $autoinc = '';
|
||||
if (!empty($field['autoincrement'])) {
|
||||
$autoinc = ' PRIMARY KEY';
|
||||
} elseif (array_key_exists('default', $field)) {
|
||||
if ($field['default'] === '') {
|
||||
$field['default'] = empty($field['notnull']) ? null : 0;
|
||||
}
|
||||
$default = ' DEFAULT '.$this->quote($field['default'], 'integer');
|
||||
}
|
||||
|
||||
$notnull = empty($field['notnull']) ? '' : ' NOT NULL';
|
||||
$unsigned = empty($field['unsigned']) ? '' : ' UNSIGNED';
|
||||
if (empty($default) && empty($notnull)) {
|
||||
$default = ' DEFAULT NULL';
|
||||
}
|
||||
$name = $db->quoteIdentifier($name, true);
|
||||
return $name.' '.$this->getTypeDeclaration($field).$unsigned.$default.$notnull.$autoinc;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$match = '';
|
||||
if (null !== $operator) {
|
||||
$field = (null === $field) ? '' : $field.' ';
|
||||
$operator = strtoupper($operator);
|
||||
switch ($operator) {
|
||||
// case insensitive
|
||||
case 'ILIKE':
|
||||
$match = $field.'LIKE ';
|
||||
break;
|
||||
case 'NOT ILIKE':
|
||||
$match = $field.'NOT LIKE ';
|
||||
break;
|
||||
// case sensitive
|
||||
case 'LIKE':
|
||||
$match = $field.'LIKE ';
|
||||
break;
|
||||
case 'NOT LIKE':
|
||||
$match = $field.'NOT 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 {
|
||||
$match.= $db->escapePattern($db->escape($value));
|
||||
}
|
||||
}
|
||||
$match.= "'";
|
||||
$match.= $this->patternEscapeString();
|
||||
return $match;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _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_type = strtolower($field['type']);
|
||||
$length = !empty($field['length']) ? $field['length'] : null;
|
||||
$unsigned = !empty($field['unsigned']) ? $field['unsigned'] : null;
|
||||
$fixed = null;
|
||||
$type = array();
|
||||
switch ($db_type) {
|
||||
case 'boolean':
|
||||
$type[] = 'boolean';
|
||||
break;
|
||||
case 'tinyint':
|
||||
$type[] = 'integer';
|
||||
$type[] = 'boolean';
|
||||
if (preg_match('/^(is|has)/', $field['name'])) {
|
||||
$type = array_reverse($type);
|
||||
}
|
||||
$unsigned = preg_match('/ unsigned/i', $field['type']);
|
||||
$length = 1;
|
||||
break;
|
||||
case 'smallint':
|
||||
$type[] = 'integer';
|
||||
$unsigned = preg_match('/ unsigned/i', $field['type']);
|
||||
$length = 2;
|
||||
break;
|
||||
case 'mediumint':
|
||||
$type[] = 'integer';
|
||||
$unsigned = preg_match('/ unsigned/i', $field['type']);
|
||||
$length = 3;
|
||||
break;
|
||||
case 'int':
|
||||
case 'integer':
|
||||
case 'serial':
|
||||
$type[] = 'integer';
|
||||
$unsigned = preg_match('/ unsigned/i', $field['type']);
|
||||
$length = 4;
|
||||
break;
|
||||
case 'bigint':
|
||||
case 'bigserial':
|
||||
$type[] = 'integer';
|
||||
$unsigned = preg_match('/ unsigned/i', $field['type']);
|
||||
$length = 8;
|
||||
break;
|
||||
case 'clob':
|
||||
$type[] = 'clob';
|
||||
$fixed = false;
|
||||
break;
|
||||
case 'tinytext':
|
||||
case 'mediumtext':
|
||||
case 'longtext':
|
||||
case 'text':
|
||||
case 'varchar':
|
||||
case 'varchar2':
|
||||
$fixed = false;
|
||||
case 'char':
|
||||
$type[] = 'text';
|
||||
if ($length == '1') {
|
||||
$type[] = 'boolean';
|
||||
if (preg_match('/^(is|has)/', $field['name'])) {
|
||||
$type = array_reverse($type);
|
||||
}
|
||||
} elseif (strstr($db_type, 'text')) {
|
||||
$type[] = 'clob';
|
||||
$type = array_reverse($type);
|
||||
}
|
||||
if ($fixed !== false) {
|
||||
$fixed = true;
|
||||
}
|
||||
break;
|
||||
case 'date':
|
||||
$type[] = 'date';
|
||||
$length = null;
|
||||
break;
|
||||
case 'datetime':
|
||||
case 'timestamp':
|
||||
$type[] = 'timestamp';
|
||||
$length = null;
|
||||
break;
|
||||
case 'time':
|
||||
$type[] = 'time';
|
||||
$length = null;
|
||||
break;
|
||||
case 'float':
|
||||
case 'double':
|
||||
case 'real':
|
||||
$type[] = 'float';
|
||||
break;
|
||||
case 'decimal':
|
||||
case 'numeric':
|
||||
$type[] = 'decimal';
|
||||
$length = $length.','.$field['decimal'];
|
||||
break;
|
||||
case 'tinyblob':
|
||||
case 'mediumblob':
|
||||
case 'longblob':
|
||||
case 'blob':
|
||||
$type[] = 'blob';
|
||||
$length = null;
|
||||
break;
|
||||
case 'year':
|
||||
$type[] = 'integer';
|
||||
$type[] = 'date';
|
||||
$length = null;
|
||||
break;
|
||||
default:
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
|
||||
'unknown database attribute type: '.$db_type, __FUNCTION__);
|
||||
}
|
||||
|
||||
if ((int)$length <= 0) {
|
||||
$length = null;
|
||||
}
|
||||
|
||||
return array($type, $length, $unsigned, $fixed);
|
||||
}
|
||||
|
||||
// }}}
|
||||
}
|
||||
|
||||
?>
|
459
extlib/MDB2/Driver/Datatype/sqlsrv.php
Normal file
459
extlib/MDB2/Driver/Datatype/sqlsrv.php
Normal file
@ -0,0 +1,459 @@
|
||||
<?php
|
||||
// vim: set et ts=4 sw=4 fdm=marker:
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 and 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Copyright (c) 1998-2007 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Authors: Lukas Smith <smith@pooteeweet.org> |
|
||||
// | Daniel Convissor <danielc@php.net> |
|
||||
// +----------------------------------------------------------------------+
|
||||
|
||||
require_once 'MDB2/Driver/Datatype/Common.php';
|
||||
|
||||
/**
|
||||
* MDB2 MS SQL driver
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
*/
|
||||
class MDB2_Driver_Datatype_sqlsrv extends MDB2_Driver_Datatype_Common
|
||||
{
|
||||
// {{{ _baseConvertResult()
|
||||
|
||||
/**
|
||||
* general type conversion method
|
||||
*
|
||||
* @param mixed $value refernce 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 a MDB2 error on failure
|
||||
* @access protected
|
||||
*/
|
||||
function _baseConvertResult($value, $type, $rtrim = true)
|
||||
{
|
||||
if (null === $value) {
|
||||
return null;
|
||||
}
|
||||
switch ($type) {
|
||||
case 'boolean':
|
||||
return ($value === 0)? false : !empty($value);
|
||||
case 'date':
|
||||
if (strlen($value) > 10) {
|
||||
$value = substr($value,0,10);
|
||||
}
|
||||
return $value;
|
||||
case 'time':
|
||||
if (strlen($value) > 8) {
|
||||
$value = substr($value,11,8);
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
return parent::_baseConvertResult($value, $type, $rtrim);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _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 'COLLATE '.$collation;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
switch ($field['type']) {
|
||||
case 'text':
|
||||
$length = !empty($field['length'])
|
||||
? $field['length'] : false;
|
||||
$fixed = !empty($field['fixed']) ? $field['fixed'] : false;
|
||||
return $fixed ? ($length ? 'CHAR('.$length.')' : 'CHAR('.$db->options['default_text_field_length'].')')
|
||||
: ($length ? 'VARCHAR('.$length.')' : 'VARCHAR(MAX)');
|
||||
case 'clob':
|
||||
if (!empty($field['length'])) {
|
||||
$length = $field['length'];
|
||||
if ($length <= 8000) {
|
||||
return 'VARCHAR('.$length.')';
|
||||
}
|
||||
}
|
||||
return 'VARCHAR(MAX)';
|
||||
case 'blob':
|
||||
if (!empty($field['length'])) {
|
||||
$length = $field['length'];
|
||||
if ($length <= 8000) {
|
||||
return "VARBINARY($length)";
|
||||
}
|
||||
}
|
||||
return 'IMAGE';
|
||||
case 'integer':
|
||||
return 'INT';
|
||||
case 'boolean':
|
||||
return 'BIT';
|
||||
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 'FLOAT';
|
||||
case 'decimal':
|
||||
$length = !empty($field['length']) ? $field['length'] : 18;
|
||||
$scale = !empty($field['scale']) ? $field['scale'] : $db->options['decimal_places'];
|
||||
return 'DECIMAL('.$length.','.$scale.')';
|
||||
}
|
||||
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 string $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)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$notnull = empty($field['notnull']) ? ' NULL' : ' NOT NULL';
|
||||
$default = $autoinc = '';
|
||||
if (!empty($field['autoincrement'])) {
|
||||
$autoinc = ' IDENTITY PRIMARY KEY';
|
||||
} elseif (array_key_exists('default', $field)) {
|
||||
if ($field['default'] === '') {
|
||||
$field['default'] = 0;
|
||||
}
|
||||
if (null === $field['default']) {
|
||||
$default = ' DEFAULT (NULL)';
|
||||
} else {
|
||||
$default = ' DEFAULT (' . $this->quote($field['default'], 'integer') . ')';
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($field['unsigned'])) {
|
||||
$db->warnings[] = "unsigned integer field \"$name\" is being declared as signed integer";
|
||||
}
|
||||
|
||||
$name = $db->quoteIdentifier($name, true);
|
||||
return $name.' '.$this->getTypeDeclaration($field).$notnull.$default.$autoinc;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$notnull = empty($field['notnull']) ? ' NULL' : ' 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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$notnull = empty($field['notnull']) ? ' NULL' : ' NOT NULL';
|
||||
$name = $db->quoteIdentifier($name, true);
|
||||
return $name.' '.$this->getTypeDeclaration($field).$notnull;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _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)
|
||||
{
|
||||
if (!$quote) {
|
||||
return $value;
|
||||
}
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
if ($db->options['lob_allow_url_include']) {
|
||||
$value = '0x'.bin2hex($this->_readFile($value));
|
||||
}
|
||||
return "'".$value."'";
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _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)
|
||||
{
|
||||
// todo: handle length of various int variations
|
||||
$db_type = $field['type'];
|
||||
$length = $field['length'];
|
||||
$type = array();
|
||||
// todo: unsigned handling seems to be missing
|
||||
$unsigned = $fixed = null;
|
||||
switch ($db_type) {
|
||||
case 'bit':
|
||||
case SQLSRV_SQLTYPE_BIT:
|
||||
$type[0] = 'boolean';
|
||||
break;
|
||||
case 'tinyint':
|
||||
case SQLSRV_SQLTYPE_TINYINT:
|
||||
$type[0] = 'integer';
|
||||
$length = 1;
|
||||
break;
|
||||
case 'smallint':
|
||||
case SQLSRV_SQLTYPE_SMALLINT:
|
||||
$type[0] = 'integer';
|
||||
$length = 2;
|
||||
break;
|
||||
case 'int':
|
||||
case SQLSRV_SQLTYPE_INT:
|
||||
$type[0] = 'integer';
|
||||
$length = 4;
|
||||
break;
|
||||
case 'bigint':
|
||||
case SQLSRV_SQLTYPE_BIGINT:
|
||||
$type[0] = 'integer';
|
||||
$length = 8;
|
||||
break;
|
||||
case 'datetime':
|
||||
case SQLSRV_SQLTYPE_DATETIME:
|
||||
$type[0] = 'timestamp';
|
||||
break;
|
||||
case 'float':
|
||||
case SQLSRV_SQLTYPE_FLOAT:
|
||||
case 'real':
|
||||
case SQLSRV_SQLTYPE_REAL:
|
||||
$type[0] = 'float';
|
||||
break;
|
||||
case 'numeric':
|
||||
case SQLSRV_SQLTYPE_NUMERIC:
|
||||
case 'decimal':
|
||||
case SQLSRV_SQLTYPE_DECIMAL:
|
||||
case 'money':
|
||||
case SQLSRV_SQLTYPE_MONEY:
|
||||
$type[0] = 'decimal';
|
||||
$length = $field['numeric_precision'].','.$field['numeric_scale'];
|
||||
break;
|
||||
case 'text':
|
||||
case SQLSRV_SQLTYPE_TEXT:
|
||||
case 'ntext':
|
||||
case SQLSRV_SQLTYPE_NTEXT:
|
||||
case 'varchar':
|
||||
case SQLSRV_SQLTYPE_VARCHAR:
|
||||
case 'nvarchar':
|
||||
case SQLSRV_SQLTYPE_NVARCHAR:
|
||||
$fixed = false;
|
||||
case 'char':
|
||||
case SQLSRV_SQLTYPE_CHAR:
|
||||
case 'nchar':
|
||||
case SQLSRV_SQLTYPE_NCHAR:
|
||||
$type[0] = 'text';
|
||||
if ($length == '1') {
|
||||
$type[] = 'boolean';
|
||||
if (preg_match('/^(is|has)/', $field['name'])) {
|
||||
$type = array_reverse($type);
|
||||
}
|
||||
} elseif (strstr($db_type, 'text') || strstr($db_type, SQLSRV_SQLTYPE_TEXT)) {
|
||||
$type[] = 'clob';
|
||||
$type = array_reverse($type);
|
||||
}
|
||||
if ($fixed !== false) {
|
||||
$fixed = true;
|
||||
}
|
||||
break;
|
||||
case 'image':
|
||||
case SQLSRV_SQLTYPE_IMAGE:
|
||||
case 'varbinary':
|
||||
case SQLSRV_SQLTYPE_VARBINARY:
|
||||
case 'timestamp':
|
||||
case SQLSRV_SQLTYPE_TIMESTAMP:
|
||||
$type[] = 'blob';
|
||||
$length = null;
|
||||
break;
|
||||
default:
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
|
||||
'unknown database attribute type: '.$db_type, __FUNCTION__);
|
||||
}
|
||||
|
||||
if ((int)$length <= 0) {
|
||||
$length = null;
|
||||
}
|
||||
|
||||
return array($type, $length, $unsigned, $fixed);
|
||||
}
|
||||
// }}}
|
||||
}
|
||||
|
||||
?>
|
293
extlib/MDB2/Driver/Function/Common.php
Normal file
293
extlib/MDB2/Driver/Function/Common.php
Normal file
@ -0,0 +1,293 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 and 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Author: Lukas Smith <smith@pooteeweet.org> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
|
||||
/**
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lukas Smith <smith@pooteeweet.org>
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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 <smith@pooteeweet.org>
|
||||
*/
|
||||
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 (MDB2::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 (MDB2::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 (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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$error = $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
|
||||
'method not implemented', __FUNCTION__);
|
||||
return $error;
|
||||
}
|
||||
|
||||
// }}}
|
||||
}
|
||||
?>
|
61
extlib/MDB2/Driver/Function/fbsql.php
Normal file
61
extlib/MDB2/Driver/Function/fbsql.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 and 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, |
|
||||
// | Stig. S. Bakken, Lukas Smith, Frank M. Kromann |
|
||||
// | 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Author: Lukas Smith <smith@pooteeweet.org> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
|
||||
require_once 'MDB2/Driver/Function/Common.php';
|
||||
|
||||
/**
|
||||
* MDB2 FrontBase driver for the function modules
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lukas Smith <smith@pooteeweet.org>
|
||||
*/
|
||||
class MDB2_Driver_Function_fbsql extends MDB2_Driver_Function_Common
|
||||
{
|
||||
}
|
||||
|
||||
?>
|
108
extlib/MDB2/Driver/Function/ibase.php
Normal file
108
extlib/MDB2/Driver/Function/ibase.php
Normal file
@ -0,0 +1,108 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 and 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, |
|
||||
// | Stig. S. Bakken, Lukas Smith, Lorenzo Alberton |
|
||||
// | 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Author: Lorenzo Alberton <l.alberton@quipo.it> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id$
|
||||
|
||||
require_once 'MDB2/Driver/Function/Common.php';
|
||||
|
||||
/**
|
||||
* MDB2 FireBird/InterBase driver for the function modules
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lukas Smith <smith@pooteeweet.org>
|
||||
*/
|
||||
class MDB2_Driver_Function_ibase extends MDB2_Driver_Function_Common
|
||||
{
|
||||
// {{{ 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 ' FROM RDB$DATABASE';
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ length()
|
||||
|
||||
/**
|
||||
* return string to call a function to get a replacement inside an SQL statement.
|
||||
*
|
||||
* @return string to call a function to get a replace
|
||||
* @access public
|
||||
*/
|
||||
function length($expression)
|
||||
{
|
||||
return "STRLEN($expression)";
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ replace()
|
||||
|
||||
/**
|
||||
* return string to call a function to get a replacement inside an SQL statement.
|
||||
*
|
||||
* @return string to call a function to get a replace
|
||||
* @access public
|
||||
*/
|
||||
function replace($str, $from_str, $to_str)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$error = $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
|
||||
'method not implemented', __FUNCTION__);
|
||||
return $error;
|
||||
}
|
||||
|
||||
// }}}
|
||||
}
|
||||
?>
|
193
extlib/MDB2/Driver/Function/mssql.php
Normal file
193
extlib/MDB2/Driver/Function/mssql.php
Normal file
@ -0,0 +1,193 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 and 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Copyright (c) 1998-2008 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Author: Frank M. Kromann <frank@kromann.info> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
|
||||
require_once 'MDB2/Driver/Function/Common.php';
|
||||
|
||||
// {{{ class MDB2_Driver_Function_mssql
|
||||
/**
|
||||
* MDB2 MSSQL driver for the function modules
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lukas Smith <smith@pooteeweet.org>
|
||||
*/
|
||||
class MDB2_Driver_Function_mssql extends MDB2_Driver_Function_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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$query = 'EXECUTE '.$name;
|
||||
$query .= $params ? ' '.implode(', ', $params) : '';
|
||||
return $db->query($query, $types, $result_class, $result_wrap_class);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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':
|
||||
case 'date':
|
||||
case 'timestamp':
|
||||
default:
|
||||
return 'GETDATE()';
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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)
|
||||
{
|
||||
return 'DATEDIFF(second, \'19700101\', '. $expression.') + DATEDIFF(second, GETDATE(), GETUTCDATE())';
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 (null !== $length) {
|
||||
return "SUBSTRING($value, $position, $length)";
|
||||
}
|
||||
return "SUBSTRING($value, $position, LEN($value) - $position + 1)";
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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).")";
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 "LEN($expression)";
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ guid()
|
||||
|
||||
/**
|
||||
* Returns global unique identifier
|
||||
*
|
||||
* @return string to get global unique identifier
|
||||
* @access public
|
||||
*/
|
||||
function guid()
|
||||
{
|
||||
return 'NEWID()';
|
||||
}
|
||||
|
||||
// }}}
|
||||
}
|
||||
// }}}
|
||||
?>
|
144
extlib/MDB2/Driver/Function/mysqli.php
Normal file
144
extlib/MDB2/Driver/Function/mysqli.php
Normal file
@ -0,0 +1,144 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 and 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Copyright (c) 1998-2008 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Author: Lukas Smith <smith@pooteeweet.org> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
|
||||
require_once 'MDB2/Driver/Function/Common.php';
|
||||
|
||||
/**
|
||||
* MDB2 MySQLi driver for the function modules
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lukas Smith <smith@pooteeweet.org>
|
||||
*/
|
||||
class MDB2_Driver_Function_mysqli extends MDB2_Driver_Function_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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$multi_query = $db->getOption('multi_query');
|
||||
if (!$multi_query) {
|
||||
$db->setOption('multi_query', true);
|
||||
}
|
||||
$query = 'CALL '.$name;
|
||||
$query .= $params ? '('.implode(', ', $params).')' : '()';
|
||||
$result = $db->query($query, $types, $result_class, $result_wrap_class);
|
||||
if (!$multi_query) {
|
||||
$db->setOption('multi_query', false);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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)
|
||||
{
|
||||
return 'UNIX_TIMESTAMP('. $expression.')';
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 "CONCAT(".implode(', ', $args).")";
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ guid()
|
||||
|
||||
/**
|
||||
* Returns global unique identifier
|
||||
*
|
||||
* @return string to get global unique identifier
|
||||
* @access public
|
||||
*/
|
||||
function guid()
|
||||
{
|
||||
return 'UUID()';
|
||||
}
|
||||
|
||||
// }}}
|
||||
}
|
||||
?>
|
187
extlib/MDB2/Driver/Function/oci8.php
Normal file
187
extlib/MDB2/Driver/Function/oci8.php
Normal file
@ -0,0 +1,187 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 and 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Copyright (c) 1998-2008 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Author: Lukas Smith <smith@pooteeweet.org> |
|
||||
// +----------------------------------------------------------------------+
|
||||
|
||||
// $Id$
|
||||
|
||||
require_once 'MDB2/Driver/Function/Common.php';
|
||||
|
||||
/**
|
||||
* MDB2 oci8 driver for the function modules
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lukas Smith <smith@pooteeweet.org>
|
||||
*/
|
||||
class MDB2_Driver_Function_oci8 extends MDB2_Driver_Function_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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$query = 'EXEC '.$name;
|
||||
$query .= $params ? '('.implode(', ', $params).')' : '()';
|
||||
return $db->query($query, $types, $result_class, $result_wrap_class);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 ' FROM dual';
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 'date':
|
||||
case 'time':
|
||||
case 'timestamp':
|
||||
default:
|
||||
return 'TO_CHAR(CURRENT_TIMESTAMP, \'YYYY-MM-DD HH24:MI:SS\')';
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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)
|
||||
{
|
||||
$utc_offset = 'CAST(SYS_EXTRACT_UTC(SYSTIMESTAMP) AS DATE) - CAST(SYSTIMESTAMP AS DATE)';
|
||||
$epoch_date = 'to_date(\'19700101\', \'YYYYMMDD\')';
|
||||
return '(CAST('.$expression.' AS DATE) - '.$epoch_date.' + '.$utc_offset.') * 86400 seconds';
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 (null !== $length) {
|
||||
return "SUBSTR($value, $position, $length)";
|
||||
}
|
||||
return "SUBSTR($value, $position)";
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 'dbms_random.value';
|
||||
}
|
||||
|
||||
// }}}}
|
||||
// {{{ guid()
|
||||
|
||||
/**
|
||||
* Returns global unique identifier
|
||||
*
|
||||
* @return string to get global unique identifier
|
||||
* @access public
|
||||
*/
|
||||
function guid()
|
||||
{
|
||||
return 'SYS_GUID()';
|
||||
}
|
||||
|
||||
// }}}}
|
||||
}
|
||||
?>
|
132
extlib/MDB2/Driver/Function/pgsql.php
Normal file
132
extlib/MDB2/Driver/Function/pgsql.php
Normal file
@ -0,0 +1,132 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 and 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Copyright (c) 1998-2008 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Author: Paul Cooper <pgc@ucecom.com> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id$
|
||||
|
||||
require_once 'MDB2/Driver/Function/Common.php';
|
||||
|
||||
/**
|
||||
* MDB2 MySQL driver for the function modules
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lukas Smith <smith@pooteeweet.org>
|
||||
*/
|
||||
class MDB2_Driver_Function_pgsql extends MDB2_Driver_Function_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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$query = 'SELECT * FROM '.$name;
|
||||
$query .= $params ? '('.implode(', ', $params).')' : '()';
|
||||
return $db->query($query, $types, $result_class, $result_wrap_class);
|
||||
}
|
||||
// }}}
|
||||
// {{{ 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)
|
||||
{
|
||||
return 'EXTRACT(EPOCH FROM DATE_TRUNC(\'seconds\', CAST ((' . $expression . ') AS 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 (null !== $length) {
|
||||
return "SUBSTRING(CAST($value AS VARCHAR) FROM $position FOR $length)";
|
||||
}
|
||||
return "SUBSTRING(CAST($value AS VARCHAR) FROM $position)";
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 'RANDOM()';
|
||||
}
|
||||
|
||||
// }}}
|
||||
}
|
||||
?>
|
162
extlib/MDB2/Driver/Function/sqlite.php
Normal file
162
extlib/MDB2/Driver/Function/sqlite.php
Normal file
@ -0,0 +1,162 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 and 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Copyright (c) 1998-2008 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Author: Lukas Smith <smith@pooteeweet.org> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
|
||||
require_once 'MDB2/Driver/Function/Common.php';
|
||||
|
||||
/**
|
||||
* MDB2 SQLite driver for the function modules
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lukas Smith <smith@pooteeweet.org>
|
||||
*/
|
||||
class MDB2_Driver_Function_sqlite extends MDB2_Driver_Function_Common
|
||||
{
|
||||
// {{{ constructor
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
function __construct($db_index)
|
||||
{
|
||||
parent::__construct($db_index);
|
||||
// create all sorts of UDFs
|
||||
}
|
||||
|
||||
// {{{ 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.
|
||||
*
|
||||
* @return string to call a variable with the current timestamp
|
||||
* @access public
|
||||
*/
|
||||
function now($type = 'timestamp')
|
||||
{
|
||||
switch ($type) {
|
||||
case 'time':
|
||||
return 'time(\'now\')';
|
||||
case 'date':
|
||||
return 'date(\'now\')';
|
||||
case 'timestamp':
|
||||
default:
|
||||
return 'datetime(\'now\')';
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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)
|
||||
{
|
||||
return 'strftime("%s",'. $expression.', "utc")';
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 (null !== $length) {
|
||||
return "substr($value, $position, $length)";
|
||||
}
|
||||
return "substr($value, $position, length($value))";
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 '((RANDOM()+2147483648)/4294967296)';
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ replace()
|
||||
|
||||
/**
|
||||
* return string to call a function to get a replacement inside an SQL statement.
|
||||
*
|
||||
* @return string to call a function to get a replace
|
||||
* @access public
|
||||
*/
|
||||
function replace($str, $from_str, $to_str)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$error = $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
|
||||
'method not implemented', __FUNCTION__);
|
||||
return $error;
|
||||
}
|
||||
|
||||
// }}}
|
||||
}
|
||||
?>
|
162
extlib/MDB2/Driver/Function/sqlite3.php
Normal file
162
extlib/MDB2/Driver/Function/sqlite3.php
Normal file
@ -0,0 +1,162 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 - 7 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Copyright (c) 1998-2008 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Author: Lorenzo Alberton <l.alberton@quipo.it> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
|
||||
require_once 'MDB2/Driver/Function/Common.php';
|
||||
|
||||
/**
|
||||
* MDB2 SQLite3 driver for the function modules
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lorenzo Alberton <l.alberton@quipo.it>
|
||||
*/
|
||||
class MDB2_Driver_Function_sqlite3 extends MDB2_Driver_Function_Common
|
||||
{
|
||||
// {{{ constructor
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
function __construct($db_index)
|
||||
{
|
||||
parent::__construct($db_index);
|
||||
// create all sorts of UDFs
|
||||
}
|
||||
|
||||
// {{{ 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.
|
||||
*
|
||||
* @return string to call a variable with the current timestamp
|
||||
* @access public
|
||||
*/
|
||||
function now($type = 'timestamp')
|
||||
{
|
||||
switch ($type) {
|
||||
case 'time':
|
||||
return 'time(\'now\')';
|
||||
case 'date':
|
||||
return 'date(\'now\')';
|
||||
case 'timestamp':
|
||||
default:
|
||||
return 'datetime(\'now\')';
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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)
|
||||
{
|
||||
return 'strftime("%s",'. $expression.', "utc")';
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 (null !== $length) {
|
||||
return "substr($value, $position, $length)";
|
||||
}
|
||||
return "substr($value, $position, length($value))";
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 '((RANDOM()+9223372036854775808)/18446744073709551616)';
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ replace()
|
||||
|
||||
/**
|
||||
* return string to call a function to get a replacement inside an SQL statement.
|
||||
*
|
||||
* @return string to call a function to get a replace
|
||||
* @access public
|
||||
*/
|
||||
function replace($str, $from_str, $to_str)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$error = $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
|
||||
'method not implemented', __FUNCTION__);
|
||||
return $error;
|
||||
}
|
||||
|
||||
// }}}
|
||||
}
|
||||
?>
|
189
extlib/MDB2/Driver/Function/sqlsrv.php
Normal file
189
extlib/MDB2/Driver/Function/sqlsrv.php
Normal file
@ -0,0 +1,189 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 and 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Copyright (c) 1998-2008 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Author: Frank M. Kromann <frank@kromann.info> |
|
||||
// +----------------------------------------------------------------------+
|
||||
|
||||
require_once 'MDB2/Driver/Function/Common.php';
|
||||
|
||||
// {{{ class MDB2_Driver_Function_sqlsrv
|
||||
/**
|
||||
* MDB2 MSSQL driver for the function modules
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
*/
|
||||
class MDB2_Driver_Function_sqlsrv extends MDB2_Driver_Function_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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$query = 'EXECUTE '.$name;
|
||||
$query .= $params ? ' '.implode(', ', $params) : '';
|
||||
return $db->query($query, $types, $result_class, $result_wrap_class);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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':
|
||||
case 'date':
|
||||
case 'timestamp':
|
||||
default:
|
||||
return 'GETDATE()';
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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)
|
||||
{
|
||||
return 'DATEDIFF(second, \'19700101\', '. $expression.') + DATEDIFF(second, GETDATE(), GETUTCDATE())';
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 (null !== $length) {
|
||||
return "SUBSTRING($value, $position, $length)";
|
||||
}
|
||||
return "SUBSTRING($value, $position, LEN($value) - $position + 1)";
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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).")";
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 "LEN($expression)";
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ guid()
|
||||
|
||||
/**
|
||||
* Returns global unique identifier
|
||||
*
|
||||
* @return string to get global unique identifier
|
||||
* @access public
|
||||
*/
|
||||
function guid()
|
||||
{
|
||||
return 'NEWID()';
|
||||
}
|
||||
|
||||
// }}}
|
||||
}
|
||||
// }}}
|
||||
?>
|
1038
extlib/MDB2/Driver/Manager/Common.php
Normal file
1038
extlib/MDB2/Driver/Manager/Common.php
Normal file
File diff suppressed because it is too large
Load Diff
597
extlib/MDB2/Driver/Manager/fbsql.php
Normal file
597
extlib/MDB2/Driver/Manager/fbsql.php
Normal file
@ -0,0 +1,597 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 and 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, |
|
||||
// | Stig. S. Bakken, Lukas Smith, Frank M. Kromann |
|
||||
// | 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Author: Lukas Smith <smith@pooteeweet.org> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
|
||||
require_once 'MDB2/Driver/Manager/Common.php';
|
||||
|
||||
/**
|
||||
* MDB2 FrontBase driver for the management modules
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Frank M. Kromann <frank@kromann.info>
|
||||
*/
|
||||
class MDB2_Driver_Manager_fbsql extends MDB2_Driver_Manager_Common
|
||||
{
|
||||
// {{{ 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($name, $options = array())
|
||||
{
|
||||
$db =& $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$name = $db->quoteIdentifier($name, true);
|
||||
$query = "CREATE DATABASE $name";
|
||||
return $db->standaloneQuery($query, null, true);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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($name)
|
||||
{
|
||||
$db =& $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$name = $db->quoteIdentifier($name, true);
|
||||
$query = "DELETE DATABASE $name";
|
||||
return $db->standaloneQuery($query, null, true);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ dropTable()
|
||||
|
||||
/**
|
||||
* drop an existing table
|
||||
*
|
||||
* @param object $dbs database object that is extended by this class
|
||||
* @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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$name = $db->quoteIdentifier($name, true);
|
||||
$result = $db->exec("DROP TABLE $name CASCADE");
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
return MDB2_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
foreach ($changes as $change_name => $change){
|
||||
switch ($change_name) {
|
||||
case 'add':
|
||||
case 'remove':
|
||||
case 'change':
|
||||
case 'rename':
|
||||
case 'name':
|
||||
break;
|
||||
default:
|
||||
return $db->raiseError(MDB2_ERROR_CANNOT_ALTER, null, null,
|
||||
'change type "'.$change_name.'" not yet supported', __FUNCTION__);
|
||||
}
|
||||
}
|
||||
|
||||
if ($check) {
|
||||
return MDB2_OK;
|
||||
}
|
||||
|
||||
$query = '';
|
||||
if (!empty($changes['name'])) {
|
||||
$change_name = $db->quoteIdentifier($changes['name'], true);
|
||||
$query .= 'RENAME TO ' . $change_name;
|
||||
}
|
||||
|
||||
if (!empty($changes['add']) && is_array($changes['add'])) {
|
||||
foreach ($changes['add'] as $field_name => $field) {
|
||||
if ($query) {
|
||||
$query.= ', ';
|
||||
}
|
||||
$query.= 'ADD ' . $db->getDeclaration($field['type'], $field_name, $field);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($changes['remove']) && is_array($changes['remove'])) {
|
||||
foreach ($changes['remove'] as $field_name => $field) {
|
||||
if ($query) {
|
||||
$query.= ', ';
|
||||
}
|
||||
$field_name = $db->quoteIdentifier($field_name, true);
|
||||
$query.= 'DROP ' . $field_name;
|
||||
}
|
||||
}
|
||||
|
||||
$rename = array();
|
||||
if (!empty($changes['rename']) && is_array($changes['rename'])) {
|
||||
foreach ($changes['rename'] as $field_name => $field) {
|
||||
$rename[$field['name']] = $field_name;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($changes['change']) && is_array($changes['change'])) {
|
||||
foreach ($changes['change'] as $field_name => $field) {
|
||||
if ($query) {
|
||||
$query.= ', ';
|
||||
}
|
||||
if (isset($rename[$field_name])) {
|
||||
$old_field_name = $rename[$field_name];
|
||||
unset($rename[$field_name]);
|
||||
} else {
|
||||
$old_field_name = $field_name;
|
||||
}
|
||||
$old_field_name = $db->quoteIdentifier($old_field_name, true);
|
||||
$query.= "CHANGE $old_field_name " . $db->getDeclaration($field['definition']['type'], $old_field_name, $field['definition']);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($rename) && is_array($rename)) {
|
||||
foreach ($rename as $renamed_field_name => $renamed_field) {
|
||||
if ($query) {
|
||||
$query.= ', ';
|
||||
}
|
||||
$old_field_name = $rename[$renamed_field_name];
|
||||
$field = $changes['rename'][$old_field_name];
|
||||
$query.= 'CHANGE ' . $db->getDeclaration($field['definition']['type'], $old_field_name, $field['definition']);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$query) {
|
||||
return MDB2_OK;
|
||||
}
|
||||
|
||||
$name = $db->quoteIdentifier($name, true);
|
||||
$result = $db->exec("ALTER TABLE $name $query");
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
return MDB2_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
return $db->raiseError(MDB2_ERROR_NOT_CAPABLE, null, null,
|
||||
'not capable', __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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
return $db->queryCol('SELECT "user_name" FROM information_schema.users');
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ listTables()
|
||||
|
||||
/**
|
||||
* list all tables in the current database
|
||||
*
|
||||
* @return mixed array of table names on success, a MDB2 error on failure
|
||||
* @access public
|
||||
*/
|
||||
function listTables()
|
||||
{
|
||||
$db =& $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$table_names = $db->queryCol('SELECT "table_name"'
|
||||
. ' FROM information_schema.tables'
|
||||
. ' t0, information_schema.schemata t1'
|
||||
. ' WHERE t0.schema_pk=t1.schema_pk AND'
|
||||
. ' "table_type" = \'BASE TABLE\''
|
||||
. ' AND "schema_name" = current_schema');
|
||||
if (MDB2::isError($table_names)) {
|
||||
return $table_names;
|
||||
}
|
||||
$result = array();
|
||||
for ($i = 0, $j = count($table_names); $i < $j; ++$i) {
|
||||
if (!$this->_fixSequenceName($table_names[$i], true)) {
|
||||
$result[] = $table_names[$i];
|
||||
}
|
||||
}
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
$result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$table = $db->quoteIdentifier($table, true);
|
||||
$result = $db->queryCol("SHOW COLUMNS FROM $table");
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
$result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$table = $db->quoteIdentifier($table, true);
|
||||
$name = $db->quoteIdentifier($db->getIndexName($name), true);
|
||||
$result = $db->exec("ALTER TABLE $table DROP INDEX $name");
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
return MDB2_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$key_name = 'Key_name';
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
if ($db->options['field_case'] == CASE_LOWER) {
|
||||
$key_name = strtolower($key_name);
|
||||
} else {
|
||||
$key_name = strtoupper($key_name);
|
||||
}
|
||||
}
|
||||
|
||||
$table = $db->quoteIdentifier($table, true);
|
||||
$query = "SHOW INDEX FROM $table";
|
||||
$indexes = $db->queryCol($query, 'text', $key_name);
|
||||
if (MDB2::isError($indexes)) {
|
||||
return $indexes;
|
||||
}
|
||||
|
||||
$result = array();
|
||||
foreach ($indexes as $index) {
|
||||
if ($index != 'PRIMARY' && ($index = $this->_fixIndexName($index))) {
|
||||
$result[$index] = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
$result = array_change_key_case($result, $db->options['field_case']);
|
||||
}
|
||||
return array_keys($result);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$sequence_name = $db->quoteIdentifier($db->getSequenceName($seq_name), true);
|
||||
$seqcol_name = $db->quoteIdentifier($db->options['seqcol_name'], true);
|
||||
$query = "CREATE TABLE $sequence_name ($seqcol_name INTEGER DEFAULT UNIQUE, PRIMARY KEY($seqcol_name))";
|
||||
$res = $db->exec($query);
|
||||
$res = $db->exec("SET UNIQUE = 1 FOR $sequence_name");
|
||||
if (MDB2::isError($res)) {
|
||||
return $res;
|
||||
}
|
||||
if ($start == 1) {
|
||||
return MDB2_OK;
|
||||
}
|
||||
$res = $db->exec("INSERT INTO $sequence_name ($seqcol_name) VALUES (".($start-1).')');
|
||||
if (!MDB2::isError($res)) {
|
||||
return MDB2_OK;
|
||||
}
|
||||
// Handle error
|
||||
$result = $db->exec("DROP TABLE $sequence_name");
|
||||
if (MDB2::isError($result)) {
|
||||
return $db->raiseError($result, null, null,
|
||||
'could not drop inconsistent sequence table', __FUNCTION__);
|
||||
}
|
||||
return $db->raiseError($res, null, null,
|
||||
'could not create sequence table', __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($seq_name)
|
||||
{
|
||||
$db =& $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$sequence_name = $db->quoteIdentifier($db->getSequenceName($seq_name), true);
|
||||
$result = $db->exec("DROP TABLE $sequence_name CASCADE");
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
return MDB2_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ listSequences()
|
||||
|
||||
/**
|
||||
* list all sequences in the current database
|
||||
*
|
||||
* @return mixed array of sequence names on success, a MDB2 error on failure
|
||||
* @access public
|
||||
*/
|
||||
function listSequences()
|
||||
{
|
||||
$db =& $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$table_names = $db->queryCol('SHOW TABLES', 'text');
|
||||
if (MDB2::isError($table_names)) {
|
||||
return $table_names;
|
||||
}
|
||||
$result = array();
|
||||
for ($i = 0, $j = count($table_names); $i < $j; ++$i) {
|
||||
if ($sqn = $this->_fixSequenceName($table_names[$i], true)) {
|
||||
$result[] = $sqn;
|
||||
}
|
||||
}
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
$result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
// }}}
|
||||
}
|
||||
?>
|
1136
extlib/MDB2/Driver/Manager/ibase.php
Normal file
1136
extlib/MDB2/Driver/Manager/ibase.php
Normal file
File diff suppressed because it is too large
Load Diff
1145
extlib/MDB2/Driver/Manager/mssql.php
Normal file
1145
extlib/MDB2/Driver/Manager/mssql.php
Normal file
File diff suppressed because it is too large
Load Diff
1471
extlib/MDB2/Driver/Manager/mysqli.php
Normal file
1471
extlib/MDB2/Driver/Manager/mysqli.php
Normal file
File diff suppressed because it is too large
Load Diff
1355
extlib/MDB2/Driver/Manager/oci8.php
Normal file
1355
extlib/MDB2/Driver/Manager/oci8.php
Normal file
File diff suppressed because it is too large
Load Diff
1163
extlib/MDB2/Driver/Manager/odbc.php
Normal file
1163
extlib/MDB2/Driver/Manager/odbc.php
Normal file
File diff suppressed because it is too large
Load Diff
978
extlib/MDB2/Driver/Manager/pgsql.php
Normal file
978
extlib/MDB2/Driver/Manager/pgsql.php
Normal file
@ -0,0 +1,978 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 and 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Copyright (c) 1998-2008 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Author: Paul Cooper <pgc@ucecom.com> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id$
|
||||
|
||||
require_once 'MDB2/Driver/Manager/Common.php';
|
||||
|
||||
/**
|
||||
* MDB2 MySQL driver for the management modules
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Paul Cooper <pgc@ucecom.com>
|
||||
*/
|
||||
class MDB2_Driver_Manager_pgsql extends MDB2_Driver_Manager_Common
|
||||
{
|
||||
// {{{ createDatabase()
|
||||
|
||||
/**
|
||||
* create a new database
|
||||
*
|
||||
* @param string $name name of the database that should be created
|
||||
* @param array $options array with charset info
|
||||
*
|
||||
* @return mixed MDB2_OK on success, a MDB2 error on failure
|
||||
* @access public
|
||||
*/
|
||||
function createDatabase($name, $options = array())
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$name = $db->quoteIdentifier($name, true);
|
||||
$query = 'CREATE DATABASE ' . $name;
|
||||
if (!empty($options['charset'])) {
|
||||
$query .= ' WITH ENCODING ' . $db->quote($options['charset'], 'text');
|
||||
}
|
||||
return $db->standaloneQuery($query, null, true);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ alterDatabase()
|
||||
|
||||
/**
|
||||
* alter an existing database
|
||||
*
|
||||
* @param string $name name of the database that is intended to be changed
|
||||
* @param array $options array with name, owner info
|
||||
*
|
||||
* @return mixed MDB2_OK on success, a MDB2 error on failure
|
||||
* @access public
|
||||
*/
|
||||
function alterDatabase($name, $options = array())
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$query = '';
|
||||
if (!empty($options['name'])) {
|
||||
$query .= ' RENAME TO ' . $options['name'];
|
||||
}
|
||||
if (!empty($options['owner'])) {
|
||||
$query .= ' OWNER TO ' . $options['owner'];
|
||||
}
|
||||
|
||||
if (empty($query)) {
|
||||
return MDB2_OK;
|
||||
}
|
||||
|
||||
$query = 'ALTER DATABASE '. $db->quoteIdentifier($name, true) . $query;
|
||||
return $db->standaloneQuery($query, null, true);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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($name)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$name = $db->quoteIdentifier($name, true);
|
||||
$query = "DROP DATABASE $name";
|
||||
return $db->standaloneQuery($query, null, true);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _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)
|
||||
{
|
||||
$query = '';
|
||||
if (!empty($definition['match'])) {
|
||||
$query .= ' MATCH '.$definition['match'];
|
||||
}
|
||||
if (!empty($definition['onupdate'])) {
|
||||
$query .= ' ON UPDATE '.$definition['onupdate'];
|
||||
}
|
||||
if (!empty($definition['ondelete'])) {
|
||||
$query .= ' ON DELETE '.$definition['ondelete'];
|
||||
}
|
||||
if (!empty($definition['deferrable'])) {
|
||||
$query .= ' DEFERRABLE';
|
||||
} else {
|
||||
$query .= ' NOT DEFERRABLE';
|
||||
}
|
||||
if (!empty($definition['initiallydeferred'])) {
|
||||
$query .= ' INITIALLY DEFERRED';
|
||||
} else {
|
||||
$query .= ' INITIALLY IMMEDIATE';
|
||||
}
|
||||
return $query;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$name = $db->quoteIdentifier($name, true);
|
||||
$result = $db->exec("TRUNCATE TABLE $name");
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
return MDB2_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
$query = 'VACUUM';
|
||||
|
||||
if (!empty($options['full'])) {
|
||||
$query .= ' FULL';
|
||||
}
|
||||
if (!empty($options['freeze'])) {
|
||||
$query .= ' FREEZE';
|
||||
}
|
||||
if (!empty($options['analyze'])) {
|
||||
$query .= ' ANALYZE';
|
||||
}
|
||||
|
||||
if (!empty($table)) {
|
||||
$query .= ' '.$db->quoteIdentifier($table, true);
|
||||
}
|
||||
$result = $db->exec($query);
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
return MDB2_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
foreach ($changes as $change_name => $change) {
|
||||
switch ($change_name) {
|
||||
case 'add':
|
||||
case 'remove':
|
||||
case 'change':
|
||||
case 'name':
|
||||
case 'rename':
|
||||
break;
|
||||
default:
|
||||
return $db->raiseError(MDB2_ERROR_CANNOT_ALTER, null, null,
|
||||
'change type "'.$change_name.'\" not yet supported', __FUNCTION__);
|
||||
}
|
||||
}
|
||||
|
||||
if ($check) {
|
||||
return MDB2_OK;
|
||||
}
|
||||
|
||||
$name = $db->quoteIdentifier($name, true);
|
||||
|
||||
if (!empty($changes['remove']) && is_array($changes['remove'])) {
|
||||
foreach ($changes['remove'] as $field_name => $field) {
|
||||
$field_name = $db->quoteIdentifier($field_name, true);
|
||||
$query = 'DROP ' . $field_name;
|
||||
$result = $db->exec("ALTER TABLE $name $query");
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($changes['rename']) && is_array($changes['rename'])) {
|
||||
foreach ($changes['rename'] as $field_name => $field) {
|
||||
$field_name = $db->quoteIdentifier($field_name, true);
|
||||
$result = $db->exec("ALTER TABLE $name RENAME COLUMN $field_name TO ".$db->quoteIdentifier($field['name'], true));
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($changes['add']) && is_array($changes['add'])) {
|
||||
foreach ($changes['add'] as $field_name => $field) {
|
||||
$query = 'ADD ' . $db->getDeclaration($field['type'], $field_name, $field);
|
||||
$result = $db->exec("ALTER TABLE $name $query");
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($changes['change']) && is_array($changes['change'])) {
|
||||
foreach ($changes['change'] as $field_name => $field) {
|
||||
$field_name = $db->quoteIdentifier($field_name, true);
|
||||
if (!empty($field['definition']['type'])) {
|
||||
$server_info = $db->getServerVersion();
|
||||
if (MDB2::isError($server_info)) {
|
||||
return $server_info;
|
||||
}
|
||||
if (is_array($server_info) && $server_info['major'] < 8) {
|
||||
return $db->raiseError(MDB2_ERROR_CANNOT_ALTER, null, null,
|
||||
'changing column type for "'.$change_name.'\" requires PostgreSQL 8.0 or above', __FUNCTION__);
|
||||
}
|
||||
$db->loadModule('Datatype', null, true);
|
||||
$type = $db->datatype->getTypeDeclaration($field['definition']);
|
||||
$query = "ALTER $field_name TYPE $type USING CAST($field_name AS $type)";
|
||||
$result = $db->exec("ALTER TABLE $name $query");
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
if (array_key_exists('default', $field['definition'])) {
|
||||
$query = "ALTER $field_name SET DEFAULT ".$db->quote($field['definition']['default'], $field['definition']['type']);
|
||||
$result = $db->exec("ALTER TABLE $name $query");
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
if (array_key_exists('notnull', $field['definition'])) {
|
||||
$query = "ALTER $field_name ".($field['definition']['notnull'] ? 'SET' : 'DROP').' NOT NULL';
|
||||
$result = $db->exec("ALTER TABLE $name $query");
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($changes['name'])) {
|
||||
$change_name = $db->quoteIdentifier($changes['name'], true);
|
||||
$result = $db->exec("ALTER TABLE $name RENAME TO ".$change_name);
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
return MDB2_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$query = 'SELECT datname FROM pg_database';
|
||||
$result2 = $db->standaloneQuery($query, array('text'), false);
|
||||
if (!MDB2::isResultCommon($result2)) {
|
||||
return $result2;
|
||||
}
|
||||
|
||||
$result = $result2->fetchCol();
|
||||
$result2->free();
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
$result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$query = 'SELECT usename FROM pg_user';
|
||||
$result2 = $db->standaloneQuery($query, array('text'), false);
|
||||
if (!MDB2::isResultCommon($result2)) {
|
||||
return $result2;
|
||||
}
|
||||
|
||||
$result = $result2->fetchCol();
|
||||
$result2->free();
|
||||
return $result;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ listViews()
|
||||
|
||||
/**
|
||||
* list all views in the current database
|
||||
*
|
||||
* @return mixed array of view names on success, a MDB2 error on failure
|
||||
* @access public
|
||||
*/
|
||||
function listViews()
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$query = "SELECT viewname
|
||||
FROM pg_views
|
||||
WHERE schemaname NOT IN ('pg_catalog', 'information_schema')
|
||||
AND viewname !~ '^pg_'";
|
||||
$result = $db->queryCol($query);
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
$result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$query = 'SELECT viewname FROM pg_views NATURAL JOIN pg_tables';
|
||||
$query.= ' WHERE tablename ='.$db->quote($table, 'text');
|
||||
$result = $db->queryCol($query);
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
$result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$query = "
|
||||
SELECT
|
||||
proname
|
||||
FROM
|
||||
pg_proc pr,
|
||||
pg_type tp
|
||||
WHERE
|
||||
tp.oid = pr.prorettype
|
||||
AND pr.proisagg = FALSE
|
||||
AND tp.typname <> 'trigger'
|
||||
AND pr.pronamespace IN
|
||||
(SELECT oid FROM pg_namespace WHERE nspname NOT LIKE 'pg_%' AND nspname != 'information_schema')";
|
||||
$result = $db->queryCol($query);
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
$result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$query = 'SELECT trg.tgname AS trigger_name
|
||||
FROM pg_trigger trg,
|
||||
pg_class tbl
|
||||
WHERE trg.tgrelid = tbl.oid';
|
||||
if (null !== $table) {
|
||||
$table = $db->quote(strtoupper($table), 'text');
|
||||
$query .= " AND UPPER(tbl.relname) = $table";
|
||||
}
|
||||
$result = $db->queryCol($query);
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
$result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ listTables()
|
||||
|
||||
/**
|
||||
* list all tables in the current database
|
||||
*
|
||||
* @return mixed array of table names on success, a MDB2 error on failure
|
||||
* @access public
|
||||
*/
|
||||
function listTables()
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
// gratuitously stolen from PEAR DB _getSpecialQuery in pgsql.php
|
||||
$query = 'SELECT c.relname AS "Name"'
|
||||
. ' FROM pg_class c, pg_user u'
|
||||
. ' WHERE c.relowner = u.usesysid'
|
||||
. " AND c.relkind = 'r'"
|
||||
. ' AND NOT EXISTS'
|
||||
. ' (SELECT 1 FROM pg_views'
|
||||
. ' WHERE viewname = c.relname)'
|
||||
. " AND c.relname !~ '^(pg_|sql_)'"
|
||||
. ' UNION'
|
||||
. ' SELECT c.relname AS "Name"'
|
||||
. ' FROM pg_class c'
|
||||
. " WHERE c.relkind = 'r'"
|
||||
. ' AND NOT EXISTS'
|
||||
. ' (SELECT 1 FROM pg_views'
|
||||
. ' WHERE viewname = c.relname)'
|
||||
. ' AND NOT EXISTS'
|
||||
. ' (SELECT 1 FROM pg_user'
|
||||
. ' WHERE usesysid = c.relowner)'
|
||||
. " AND c.relname !~ '^pg_'";
|
||||
$result = $db->queryCol($query);
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
$result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
list($schema, $table) = $this->splitTableSchema($table);
|
||||
|
||||
$table = $db->quoteIdentifier($table, true);
|
||||
if (!empty($schema)) {
|
||||
$table = $db->quoteIdentifier($schema, true) . '.' .$table;
|
||||
}
|
||||
$db->setLimit(1);
|
||||
$result2 = $db->query("SELECT * FROM $table");
|
||||
if (MDB2::isError($result2)) {
|
||||
return $result2;
|
||||
}
|
||||
$result = $result2->getColumnNames();
|
||||
$result2->free();
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
return array_flip($result);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
list($schema, $table) = $this->splitTableSchema($table);
|
||||
|
||||
$table = $db->quote($table, 'text');
|
||||
$subquery = "SELECT indexrelid
|
||||
FROM pg_index
|
||||
LEFT JOIN pg_class ON pg_class.oid = pg_index.indrelid
|
||||
LEFT JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid
|
||||
WHERE pg_class.relname = $table
|
||||
AND indisunique != 't'
|
||||
AND indisprimary != 't'";
|
||||
if (!empty($schema)) {
|
||||
$subquery .= ' AND pg_namespace.nspname = '.$db->quote($schema, 'text');
|
||||
}
|
||||
$query = "SELECT relname FROM pg_class WHERE oid IN ($subquery)";
|
||||
$indexes = $db->queryCol($query, 'text');
|
||||
if (MDB2::isError($indexes)) {
|
||||
return $indexes;
|
||||
}
|
||||
|
||||
$result = array();
|
||||
foreach ($indexes as $index) {
|
||||
$index = $this->_fixIndexName($index);
|
||||
if (!empty($index)) {
|
||||
$result[$index] = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
$result = array_change_key_case($result, $db->options['field_case']);
|
||||
}
|
||||
return array_keys($result);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
// is it an UNIQUE index?
|
||||
$query = 'SELECT relname
|
||||
FROM pg_class
|
||||
WHERE oid IN (
|
||||
SELECT indexrelid
|
||||
FROM pg_index, pg_class
|
||||
WHERE pg_class.relname = '.$db->quote($table, 'text').'
|
||||
AND pg_class.oid = pg_index.indrelid
|
||||
AND indisunique = \'t\')
|
||||
EXCEPT
|
||||
SELECT conname
|
||||
FROM pg_constraint, pg_class
|
||||
WHERE pg_constraint.conrelid = pg_class.oid
|
||||
AND relname = '. $db->quote($table, 'text');
|
||||
$unique = $db->queryCol($query, 'text');
|
||||
if (MDB2::isError($unique) || empty($unique)) {
|
||||
// not an UNIQUE index, maybe a CONSTRAINT
|
||||
return parent::dropConstraint($table, $name, $primary);
|
||||
}
|
||||
|
||||
if (in_array($name, $unique)) {
|
||||
$result = $db->exec('DROP INDEX '.$db->quoteIdentifier($name, true));
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
return MDB2_OK;
|
||||
}
|
||||
$idxname = $db->getIndexName($name);
|
||||
if (in_array($idxname, $unique)) {
|
||||
$result = $db->exec('DROP INDEX '.$db->quoteIdentifier($idxname, true));
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
return MDB2_OK;
|
||||
}
|
||||
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
$name . ' is not an existing constraint for table ' . $table, __FUNCTION__);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
list($schema, $table) = $this->splitTableSchema($table);
|
||||
|
||||
$table = $db->quote($table, 'text');
|
||||
$query = 'SELECT conname
|
||||
FROM pg_constraint
|
||||
LEFT JOIN pg_class ON pg_constraint.conrelid = pg_class.oid
|
||||
LEFT JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid
|
||||
WHERE relname = ' .$table;
|
||||
if (!empty($schema)) {
|
||||
$query .= ' AND pg_namespace.nspname = ' . $db->quote($schema, 'text');
|
||||
}
|
||||
$query .= '
|
||||
UNION DISTINCT
|
||||
SELECT relname
|
||||
FROM pg_class
|
||||
WHERE oid IN (
|
||||
SELECT indexrelid
|
||||
FROM pg_index
|
||||
LEFT JOIN pg_class ON pg_class.oid = pg_index.indrelid
|
||||
LEFT JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid
|
||||
WHERE pg_class.relname = '.$table.'
|
||||
AND indisunique = \'t\'';
|
||||
if (!empty($schema)) {
|
||||
$query .= ' AND pg_namespace.nspname = ' . $db->quote($schema, 'text');
|
||||
}
|
||||
$query .= ')';
|
||||
$constraints = $db->queryCol($query);
|
||||
if (MDB2::isError($constraints)) {
|
||||
return $constraints;
|
||||
}
|
||||
|
||||
$result = array();
|
||||
foreach ($constraints as $constraint) {
|
||||
$constraint = $this->_fixIndexName($constraint);
|
||||
if (!empty($constraint)) {
|
||||
$result[$constraint] = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE
|
||||
&& $db->options['field_case'] == CASE_LOWER
|
||||
) {
|
||||
$result = array_change_key_case($result, $db->options['field_case']);
|
||||
}
|
||||
return array_keys($result);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$sequence_name = $db->quoteIdentifier($db->getSequenceName($seq_name), true);
|
||||
$result = $db->exec("CREATE SEQUENCE $sequence_name INCREMENT 1".
|
||||
($start < 1 ? " MINVALUE $start" : '')." START $start");
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
return MDB2_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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($seq_name)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$sequence_name = $db->quoteIdentifier($db->getSequenceName($seq_name), true);
|
||||
$result = $db->exec("DROP SEQUENCE $sequence_name");
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
return MDB2_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ listSequences()
|
||||
|
||||
/**
|
||||
* list all sequences in the current database
|
||||
*
|
||||
* @return mixed array of sequence names on success, a MDB2 error on failure
|
||||
* @access public
|
||||
*/
|
||||
function listSequences()
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$query = "SELECT relname FROM pg_class WHERE relkind = 'S' AND relnamespace IN";
|
||||
$query.= "(SELECT oid FROM pg_namespace WHERE nspname NOT LIKE 'pg_%' AND nspname != 'information_schema')";
|
||||
$table_names = $db->queryCol($query);
|
||||
if (MDB2::isError($table_names)) {
|
||||
return $table_names;
|
||||
}
|
||||
$result = array();
|
||||
foreach ($table_names as $table_name) {
|
||||
$result[] = $this->_fixSequenceName($table_name);
|
||||
}
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
$result = array_map(($db->options['field_case'] == CASE_LOWER ? 'strtolower' : 'strtoupper'), $result);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
?>
|
1390
extlib/MDB2/Driver/Manager/sqlite.php
Normal file
1390
extlib/MDB2/Driver/Manager/sqlite.php
Normal file
File diff suppressed because it is too large
Load Diff
1390
extlib/MDB2/Driver/Manager/sqlite3.php
Normal file
1390
extlib/MDB2/Driver/Manager/sqlite3.php
Normal file
File diff suppressed because it is too large
Load Diff
1416
extlib/MDB2/Driver/Manager/sqlsrv.php
Normal file
1416
extlib/MDB2/Driver/Manager/sqlsrv.php
Normal file
File diff suppressed because it is too large
Load Diff
61
extlib/MDB2/Driver/Native/Common.php
Normal file
61
extlib/MDB2/Driver/Native/Common.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 and 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Author: Lukas Smith <smith@pooteeweet.org> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
|
||||
/**
|
||||
* 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 <smith@pooteeweet.org>
|
||||
*/
|
||||
class MDB2_Driver_Native_Common extends MDB2_Module_Common
|
||||
{
|
||||
}
|
||||
?>
|
60
extlib/MDB2/Driver/Native/fbsql.php
Normal file
60
extlib/MDB2/Driver/Native/fbsql.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 and 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, |
|
||||
// | Stig. S. Bakken, Lukas Smith, Frank M. Kromann |
|
||||
// | 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Author: Lukas Smith <smith@pooteeweet.org> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
|
||||
require_once 'MDB2/Driver/Native/Common.php';
|
||||
|
||||
/**
|
||||
* MDB2 FrontBase driver for the native module
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lukas Smith <smith@dybnet.de>
|
||||
*/
|
||||
class MDB2_Driver_Native_fbsql extends MDB2_Driver_Native_Common
|
||||
{
|
||||
}
|
||||
?>
|
60
extlib/MDB2/Driver/Native/ibase.php
Normal file
60
extlib/MDB2/Driver/Native/ibase.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 and 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, |
|
||||
// | Stig. S. Bakken, Lukas Smith, Frank M. Kromann |
|
||||
// | 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Author: Lukas Smith <smith@pooteeweet.org> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
|
||||
require_once 'MDB2/Driver/Native/Common.php';
|
||||
|
||||
/**
|
||||
* MDB2 FireBird/InterBase driver for the native module
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lukas Smith <smith@dybnet.de>
|
||||
*/
|
||||
class MDB2_Driver_Native_ibase extends MDB2_Driver_Native_Common
|
||||
{
|
||||
}
|
||||
?>
|
60
extlib/MDB2/Driver/Native/mssql.php
Normal file
60
extlib/MDB2/Driver/Native/mssql.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 and 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, |
|
||||
// | Stig. S. Bakken, Lukas Smith, Frank M. Kromann |
|
||||
// | 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Author: Lukas Smith <smith@pooteeweet.org> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
|
||||
require_once 'MDB2/Driver/Native/Common.php';
|
||||
|
||||
/**
|
||||
* MDB2 MSSQL driver for the native module
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lukas Smith <smith@dybnet.de>
|
||||
*/
|
||||
class MDB2_Driver_Native_mssql extends MDB2_Driver_Native_Common
|
||||
{
|
||||
}
|
||||
?>
|
60
extlib/MDB2/Driver/Native/mysqli.php
Normal file
60
extlib/MDB2/Driver/Native/mysqli.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 and 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Author: Lukas Smith <smith@pooteeweet.org> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
|
||||
require_once 'MDB2/Driver/Native/Common.php';
|
||||
|
||||
/**
|
||||
* MDB2 MySQLi driver for the native module
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lukas Smith <smith@pooteeweet.org>
|
||||
*/
|
||||
class MDB2_Driver_Native_mysqli extends MDB2_Driver_Native_Common
|
||||
{
|
||||
}
|
||||
?>
|
60
extlib/MDB2/Driver/Native/oci8.php
Normal file
60
extlib/MDB2/Driver/Native/oci8.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 and 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, |
|
||||
// | Stig. S. Bakken, Lukas Smith, Frank M. Kromann |
|
||||
// | 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Author: Lukas Smith <smith@pooteeweet.org> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
|
||||
require_once 'MDB2/Driver/Native/Common.php';
|
||||
|
||||
/**
|
||||
* MDB2 Oracle driver for the native module
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lukas Smith <smith@dybnet.de>
|
||||
*/
|
||||
class MDB2_Driver_Native_oci8 extends MDB2_Driver_Native_Common
|
||||
{
|
||||
}
|
||||
?>
|
88
extlib/MDB2/Driver/Native/pgsql.php
Normal file
88
extlib/MDB2/Driver/Native/pgsql.php
Normal file
@ -0,0 +1,88 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 and 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Author: Paul Cooper <pgc@ucecom.com> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id$
|
||||
|
||||
require_once 'MDB2/Driver/Native/Common.php';
|
||||
|
||||
/**
|
||||
* MDB2 PostGreSQL driver for the native module
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Paul Cooper <pgc@ucecom.com>
|
||||
*/
|
||||
class MDB2_Driver_Native_pgsql extends MDB2_Driver_Native_Common
|
||||
{
|
||||
// }}}
|
||||
// {{{ deleteOID()
|
||||
|
||||
/**
|
||||
* delete an OID
|
||||
*
|
||||
* @param integer $OID
|
||||
* @return mixed MDB2_OK on success or MDB2 Error Object on failure
|
||||
* @access public
|
||||
*/
|
||||
function deleteOID($OID)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$connection = $db->getConnection();
|
||||
if (MDB2::isError($connection)) {
|
||||
return $connection;
|
||||
}
|
||||
|
||||
if (!@pg_lo_unlink($connection, $OID)) {
|
||||
return $db->raiseError(null, null, null,
|
||||
'Unable to unlink OID: '.$OID, __FUNCTION__);
|
||||
}
|
||||
return MDB2_OK;
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
60
extlib/MDB2/Driver/Native/sqlite.php
Normal file
60
extlib/MDB2/Driver/Native/sqlite.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 and 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Author: Lukas Smith <smith@pooteeweet.org> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
|
||||
require_once 'MDB2/Driver/Native/Common.php';
|
||||
|
||||
/**
|
||||
* MDB2 SQLite driver for the native module
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lukas Smith <smith@pooteeweet.org>
|
||||
*/
|
||||
class MDB2_Driver_Native_sqlite extends MDB2_Driver_Native_Common
|
||||
{
|
||||
}
|
||||
?>
|
60
extlib/MDB2/Driver/Native/sqlite3.php
Normal file
60
extlib/MDB2/Driver/Native/sqlite3.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 and 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Author: Lukas Smith <smith@pooteeweet.org> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
|
||||
require_once 'MDB2/Driver/Native/Common.php';
|
||||
|
||||
/**
|
||||
* MDB2 SQLite driver for the native module
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lukas Smith <smith@pooteeweet.org>
|
||||
*/
|
||||
class MDB2_Driver_Native_sqlite3 extends MDB2_Driver_Native_Common
|
||||
{
|
||||
}
|
||||
?>
|
57
extlib/MDB2/Driver/Native/sqlsrv.php
Normal file
57
extlib/MDB2/Driver/Native/sqlsrv.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 and 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, |
|
||||
// | Stig. S. Bakken, Lukas Smith, Frank M. Kromann |
|
||||
// | 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Author: Lukas Smith <smith@pooteeweet.org> |
|
||||
// +----------------------------------------------------------------------+
|
||||
|
||||
require_once 'MDB2/Driver/Native/Common.php';
|
||||
|
||||
/**
|
||||
* MDB2 MSSQL driver for the native module
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lukas Smith <smith@dybnet.de>
|
||||
*/
|
||||
class MDB2_Driver_Native_sqlsrv extends MDB2_Driver_Native_Common
|
||||
{
|
||||
}
|
||||
?>
|
517
extlib/MDB2/Driver/Reverse/Common.php
Normal file
517
extlib/MDB2/Driver/Reverse/Common.php
Normal file
@ -0,0 +1,517 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 and 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Copyright (c) 1998-2007 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Author: Lukas Smith <smith@pooteeweet.org> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
|
||||
/**
|
||||
* @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 <smith@pooteeweet.org>
|
||||
*/
|
||||
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 (MDB2::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:
|
||||
* </pre>
|
||||
* array (
|
||||
* [fields] => array (
|
||||
* [field1name] => array() // one entry per each field covered
|
||||
* [field2name] => array() // by the index
|
||||
* [field3name] => array(
|
||||
* [sorting] => ascending
|
||||
* )
|
||||
* )
|
||||
* );
|
||||
* </pre>
|
||||
* @access public
|
||||
*/
|
||||
function getTableIndexDefinition($table, $index)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::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:
|
||||
* <pre>
|
||||
* 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
|
||||
* );
|
||||
* </pre>
|
||||
* @access public
|
||||
*/
|
||||
function getTableConstraintDefinition($table, $index)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::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:
|
||||
* <pre>
|
||||
* array (
|
||||
* [start] => n
|
||||
* );
|
||||
* </pre>
|
||||
* @access public
|
||||
*/
|
||||
function getSequenceDefinition($sequence)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$start = $db->currId($sequence);
|
||||
if (MDB2::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:
|
||||
* <pre>
|
||||
* 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',
|
||||
* );
|
||||
* </pre>
|
||||
* The oci8 driver also returns a [when_clause] index.
|
||||
* @access public
|
||||
*/
|
||||
function getTriggerDefinition($trigger)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::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 <var>$mode</var>
|
||||
* you select. The sample output below is based on this query:
|
||||
* <pre>
|
||||
* SELECT tblFoo.fldID, tblFoo.fldPhone, tblBar.fldId
|
||||
* FROM tblFoo
|
||||
* JOIN tblBar ON tblFoo.fldId = tblBar.fldId
|
||||
* </pre>
|
||||
*
|
||||
* <ul>
|
||||
* <li>
|
||||
*
|
||||
* <kbd>null</kbd> (default)
|
||||
* <pre>
|
||||
* [0] => Array (
|
||||
* [table] => tblFoo
|
||||
* [name] => fldId
|
||||
* [type] => int
|
||||
* [len] => 11
|
||||
* [flags] => primary_key not_null
|
||||
* )
|
||||
* [1] => Array (
|
||||
* [table] => tblFoo
|
||||
* [name] => fldPhone
|
||||
* [type] => string
|
||||
* [len] => 20
|
||||
* [flags] =>
|
||||
* )
|
||||
* [2] => Array (
|
||||
* [table] => tblBar
|
||||
* [name] => fldId
|
||||
* [type] => int
|
||||
* [len] => 11
|
||||
* [flags] => primary_key not_null
|
||||
* )
|
||||
* </pre>
|
||||
*
|
||||
* </li><li>
|
||||
*
|
||||
* <kbd>MDB2_TABLEINFO_ORDER</kbd>
|
||||
*
|
||||
* <p>In addition to the information found in the default output,
|
||||
* a notation of the number of columns is provided by the
|
||||
* <samp>num_fields</samp> element while the <samp>order</samp>
|
||||
* element provides an array with the column names as the keys and
|
||||
* their location index number (corresponding to the keys in the
|
||||
* the default output) as the values.</p>
|
||||
*
|
||||
* <p>If a result set has identical field names, the last one is
|
||||
* used.</p>
|
||||
*
|
||||
* <pre>
|
||||
* [num_fields] => 3
|
||||
* [order] => Array (
|
||||
* [fldId] => 2
|
||||
* [fldTrans] => 1
|
||||
* )
|
||||
* </pre>
|
||||
*
|
||||
* </li><li>
|
||||
*
|
||||
* <kbd>MDB2_TABLEINFO_ORDERTABLE</kbd>
|
||||
*
|
||||
* <p>Similar to <kbd>MDB2_TABLEINFO_ORDER</kbd> but adds more
|
||||
* dimensions to the array in which the table names are keys and
|
||||
* the field names are sub-keys. This is helpful for queries that
|
||||
* join tables which have identical field names.</p>
|
||||
*
|
||||
* <pre>
|
||||
* [num_fields] => 3
|
||||
* [ordertable] => Array (
|
||||
* [tblFoo] => Array (
|
||||
* [fldId] => 0
|
||||
* [fldPhone] => 1
|
||||
* )
|
||||
* [tblBar] => Array (
|
||||
* [fldId] => 2
|
||||
* )
|
||||
* )
|
||||
* </pre>
|
||||
*
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* The <samp>flags</samp> element contains a space separated list
|
||||
* of extra information about the field. This data is inconsistent
|
||||
* between DBMS's due to the way each DBMS works.
|
||||
* + <samp>primary_key</samp>
|
||||
* + <samp>unique_key</samp>
|
||||
* + <samp>multiple_key</samp>
|
||||
* + <samp>not_null</samp>
|
||||
*
|
||||
* Most DBMS's only provide the <samp>table</samp> and <samp>flags</samp>
|
||||
* elements if <var>$result</var> is a table name. The following DBMS's
|
||||
* provide full information from queries:
|
||||
* + fbsql
|
||||
* + mysql
|
||||
*
|
||||
* If the 'portability' option has <samp>MDB2_PORTABILITY_FIX_CASE</samp>
|
||||
* 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:
|
||||
* <kbd>MDB2_TABLEINFO_ORDERTABLE</kbd>,
|
||||
* <kbd>MDB2_TABLEINFO_ORDER</kbd> or
|
||||
* <kbd>MDB2_TABLEINFO_FULL</kbd> (which does both).
|
||||
* These are bitwise, so the first two can be
|
||||
* combined using <kbd>|</kbd>.
|
||||
*
|
||||
* @return array an associative array with the information requested.
|
||||
* A MDB2_Error object on failure.
|
||||
*
|
||||
* @see MDB2_Driver_Common::setOption()
|
||||
*/
|
||||
function tableInfo($result, $mode = null)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::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 (MDB2::isError($fields)) {
|
||||
return $fields;
|
||||
}
|
||||
|
||||
$flags = array();
|
||||
|
||||
$idxname_format = $db->getOption('idxname_format');
|
||||
$db->setOption('idxname_format', '%s');
|
||||
|
||||
$indexes = $db->manager->listTableIndexes($result);
|
||||
if (MDB2::isError($indexes)) {
|
||||
$db->setOption('idxname_format', $idxname_format);
|
||||
return $indexes;
|
||||
}
|
||||
|
||||
foreach ($indexes as $index) {
|
||||
$definition = $this->getTableIndexDefinition($result, $index);
|
||||
if (MDB2::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 (MDB2::isError($constraints)) {
|
||||
return $constraints;
|
||||
}
|
||||
|
||||
foreach ($constraints as $constraint) {
|
||||
$definition = $this->getTableConstraintDefinition($result, $constraint);
|
||||
if (MDB2::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 (MDB2::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;
|
||||
}
|
||||
}
|
||||
?>
|
132
extlib/MDB2/Driver/Reverse/fbsql.php
Normal file
132
extlib/MDB2/Driver/Reverse/fbsql.php
Normal file
@ -0,0 +1,132 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 and 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, |
|
||||
// | Stig. S. Bakken, Lukas Smith, Frank M. Kromann |
|
||||
// | 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Author: Lukas Smith <smith@pooteeweet.org> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
|
||||
require_once 'MDB2/Driver/Reverse/Common.php';
|
||||
|
||||
/**
|
||||
* MDB2 FrontBase driver for the schema reverse engineering module
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lukas Smith <smith@dybnet.de>
|
||||
*/
|
||||
class MDB2_Driver_Reverse_fbsql extends MDB2_Driver_Reverse_Common
|
||||
{
|
||||
// }}}
|
||||
// {{{ tableInfo()
|
||||
|
||||
/**
|
||||
* Returns information about a table or a result set
|
||||
*
|
||||
* @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 a valid tableInfo mode
|
||||
*
|
||||
* @return array an associative array with the information requested.
|
||||
* A MDB2_Error object on failure.
|
||||
*
|
||||
* @see MDB2_Driver_Common::tableInfo()
|
||||
*/
|
||||
function tableInfo($result, $mode = null)
|
||||
{
|
||||
if (is_string($result)) {
|
||||
return parent::tableInfo($result, $mode);
|
||||
}
|
||||
|
||||
$db =& $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$resource = MDB2::isResultCommon($result) ? $result->getResource() : $result;
|
||||
if (!is_resource($resource)) {
|
||||
return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
|
||||
'Could not generate result resource', __FUNCTION__);
|
||||
}
|
||||
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
if ($db->options['field_case'] == CASE_LOWER) {
|
||||
$case_func = 'strtolower';
|
||||
} else {
|
||||
$case_func = 'strtoupper';
|
||||
}
|
||||
} else {
|
||||
$case_func = 'strval';
|
||||
}
|
||||
|
||||
$count = @fbsql_num_fields($resource);
|
||||
$res = array();
|
||||
|
||||
if ($mode) {
|
||||
$res['num_fields'] = $count;
|
||||
}
|
||||
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
$res[$i] = array(
|
||||
'table' => $case_func(@fbsql_field_table($resource, $i)),
|
||||
'name' => $case_func(@fbsql_field_name($resource, $i)),
|
||||
'type' => @fbsql_field_type($resource, $i),
|
||||
'length' => @fbsql_field_len($resource, $i),
|
||||
'flags' => @fbsql_field_flags($resource, $i),
|
||||
);
|
||||
// todo: implement $db->datatype->mapNativeDatatype();
|
||||
$res[$i]['mdb2type'] = $res[$i]['type'];
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
}
|
||||
?>
|
590
extlib/MDB2/Driver/Reverse/ibase.php
Normal file
590
extlib/MDB2/Driver/Reverse/ibase.php
Normal file
@ -0,0 +1,590 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 and 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox, |
|
||||
// | Stig. S. Bakken, Lukas Smith, Frank M. Kromann, Lorenzo Alberton |
|
||||
// | 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Author: Lorenzo Alberton <l.alberton@quipo.it> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
|
||||
require_once 'MDB2/Driver/Reverse/Common.php';
|
||||
|
||||
/**
|
||||
* MDB2 InterbaseBase driver for the reverse engineering module
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lorenzo Alberton <l.alberton@quipo.it>
|
||||
*/
|
||||
class MDB2_Driver_Reverse_ibase extends MDB2_Driver_Reverse_Common
|
||||
{
|
||||
/**
|
||||
* Array for converting constant values to text values
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $types = array(
|
||||
7 => 'smallint',
|
||||
8 => 'integer',
|
||||
9 => 'quad',
|
||||
10 => 'float',
|
||||
11 => 'd_float',
|
||||
12 => 'date', //dialect 3 DATE
|
||||
13 => 'time',
|
||||
14 => 'char',
|
||||
16 => 'int64',
|
||||
27 => 'double',
|
||||
35 => 'timestamp', //DATE in older versions
|
||||
37 => 'varchar',
|
||||
40 => 'cstring',
|
||||
261 => 'blob',
|
||||
);
|
||||
|
||||
/**
|
||||
* Array for converting constant values to text values
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $subtypes = array(
|
||||
//char subtypes
|
||||
14 => array(
|
||||
0 => 'unspecified',
|
||||
1 => 'fixed', //BINARY data
|
||||
),
|
||||
//blob subtypes
|
||||
261 => array(
|
||||
0 => 'unspecified',
|
||||
1 => 'text',
|
||||
2 => 'BLR', //Binary Language Representation
|
||||
3 => 'access control list',
|
||||
4 => 'reserved for future use',
|
||||
5 => 'encoded description of a table\'s current metadata',
|
||||
6 => 'description of multi-database transaction that finished irregularly',
|
||||
),
|
||||
//smallint subtypes
|
||||
7 => array(
|
||||
0 => 'RDB$FIELD_TYPE',
|
||||
1 => 'numeric',
|
||||
2 => 'decimal',
|
||||
),
|
||||
//integer subtypes
|
||||
8 => array(
|
||||
0 => 'RDB$FIELD_TYPE',
|
||||
1 => 'numeric',
|
||||
2 => 'decimal',
|
||||
),
|
||||
//int64 subtypes
|
||||
16 => array(
|
||||
0 => 'RDB$FIELD_TYPE',
|
||||
1 => 'numeric',
|
||||
2 => 'decimal',
|
||||
),
|
||||
);
|
||||
|
||||
// {{{ getTableFieldDefinition()
|
||||
|
||||
/**
|
||||
* Get the structure of a field into an array
|
||||
*
|
||||
* @param string $table_name name of table that should be used in method
|
||||
* @param string $field_name name of field that should be used in method
|
||||
* @return mixed data array on success, a MDB2 error on failure
|
||||
* @access public
|
||||
*/
|
||||
function getTableFieldDefinition($table_name, $field_name)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$result = $db->loadModule('Datatype', null, true);
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
list($schema, $table) = $this->splitTableSchema($table_name);
|
||||
|
||||
$table = $db->quote(strtoupper($table), 'text');
|
||||
$field_name = $db->quote(strtoupper($field_name), 'text');
|
||||
$query = "SELECT RDB\$RELATION_FIELDS.RDB\$FIELD_NAME AS name,
|
||||
RDB\$FIELDS.RDB\$FIELD_LENGTH AS \"length\",
|
||||
RDB\$FIELDS.RDB\$FIELD_PRECISION AS \"precision\",
|
||||
(RDB\$FIELDS.RDB\$FIELD_SCALE * -1) AS \"scale\",
|
||||
RDB\$FIELDS.RDB\$FIELD_TYPE AS field_type_code,
|
||||
RDB\$FIELDS.RDB\$FIELD_SUB_TYPE AS field_sub_type_code,
|
||||
RDB\$RELATION_FIELDS.RDB\$DESCRIPTION AS description,
|
||||
RDB\$RELATION_FIELDS.RDB\$NULL_FLAG AS null_flag,
|
||||
RDB\$FIELDS.RDB\$DEFAULT_SOURCE AS default_source,
|
||||
RDB\$CHARACTER_SETS.RDB\$CHARACTER_SET_NAME AS \"charset\",
|
||||
RDB\$COLLATIONS.RDB\$COLLATION_NAME AS \"collation\"
|
||||
FROM RDB\$FIELDS
|
||||
LEFT JOIN RDB\$RELATION_FIELDS ON RDB\$FIELDS.RDB\$FIELD_NAME = RDB\$RELATION_FIELDS.RDB\$FIELD_SOURCE
|
||||
LEFT JOIN RDB\$CHARACTER_SETS ON RDB\$FIELDS.RDB\$CHARACTER_SET_ID = RDB\$CHARACTER_SETS.RDB\$CHARACTER_SET_ID
|
||||
LEFT JOIN RDB\$COLLATIONS ON RDB\$FIELDS.RDB\$COLLATION_ID = RDB\$COLLATIONS.RDB\$COLLATION_ID
|
||||
WHERE UPPER(RDB\$RELATION_FIELDS.RDB\$RELATION_NAME)=$table
|
||||
AND UPPER(RDB\$RELATION_FIELDS.RDB\$FIELD_NAME)=$field_name;";
|
||||
$column = $db->queryRow($query, null, MDB2_FETCHMODE_ASSOC);
|
||||
if (MDB2::isError($column)) {
|
||||
return $column;
|
||||
}
|
||||
if (empty($column)) {
|
||||
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
'it was not specified an existing table column', __FUNCTION__);
|
||||
}
|
||||
$column = array_change_key_case($column, CASE_LOWER);
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
if ($db->options['field_case'] == CASE_LOWER) {
|
||||
$column['name'] = strtolower($column['name']);
|
||||
} else {
|
||||
$column['name'] = strtoupper($column['name']);
|
||||
}
|
||||
}
|
||||
|
||||
$column['type'] = array_key_exists((int)$column['field_type_code'], $this->types)
|
||||
? $this->types[(int)$column['field_type_code']] : 'undefined';
|
||||
if ($column['field_sub_type_code']
|
||||
&& array_key_exists((int)$column['field_type_code'], $this->subtypes)
|
||||
&& array_key_exists($column['field_sub_type_code'], $this->subtypes[(int)$column['field_type_code']])
|
||||
) {
|
||||
$column['field_sub_type'] = $this->subtypes[(int)$column['field_type_code']][$column['field_sub_type_code']];
|
||||
} else {
|
||||
$column['field_sub_type'] = null;
|
||||
}
|
||||
$mapped_datatype = $db->datatype->mapNativeDatatype($column);
|
||||
if (MDB2::isError($mapped_datatype)) {
|
||||
return $mapped_datatype;
|
||||
}
|
||||
list($types, $length, $unsigned, $fixed) = $mapped_datatype;
|
||||
$notnull = !empty($column['null_flag']);
|
||||
$default = $column['default_source'];
|
||||
if ((null === $default) && $notnull) {
|
||||
$default = ($types[0] == 'integer') ? 0 : '';
|
||||
}
|
||||
|
||||
$definition[0] = array(
|
||||
'notnull' => $notnull,
|
||||
'nativetype' => $column['type'],
|
||||
'charset' => $column['charset'],
|
||||
'collation' => $column['collation'],
|
||||
);
|
||||
if (null !== $length) {
|
||||
$definition[0]['length'] = $length;
|
||||
}
|
||||
if (null !== $unsigned) {
|
||||
$definition[0]['unsigned'] = $unsigned;
|
||||
}
|
||||
if (null !== $fixed) {
|
||||
$definition[0]['fixed'] = $fixed;
|
||||
}
|
||||
if (false !== $default) {
|
||||
$definition[0]['default'] = $default;
|
||||
}
|
||||
foreach ($types as $key => $type) {
|
||||
$definition[$key] = $definition[0];
|
||||
if ($type == 'clob' || $type == 'blob') {
|
||||
unset($definition[$key]['default']);
|
||||
}
|
||||
$definition[$key]['type'] = $type;
|
||||
$definition[$key]['mdb2type'] = $type;
|
||||
}
|
||||
return $definition;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ getTableIndexDefinition()
|
||||
|
||||
/**
|
||||
* Get the structure of an index into an array
|
||||
*
|
||||
* @param string $table_name name of table that should be used in method
|
||||
* @param string $index_name name of index that should be used in method
|
||||
* @return mixed data array on success, a MDB2 error on failure
|
||||
* @access public
|
||||
*/
|
||||
function getTableIndexDefinition($table_name, $index_name, $format_index_name = true)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
list($schema, $table) = $this->splitTableSchema($table_name);
|
||||
|
||||
$table = $db->quote(strtoupper($table), 'text');
|
||||
$query = "SELECT RDB\$INDEX_SEGMENTS.RDB\$FIELD_NAME AS field_name,
|
||||
RDB\$INDICES.RDB\$DESCRIPTION AS description,
|
||||
(RDB\$INDEX_SEGMENTS.RDB\$FIELD_POSITION + 1) AS field_position
|
||||
FROM RDB\$INDEX_SEGMENTS
|
||||
LEFT JOIN RDB\$INDICES ON RDB\$INDICES.RDB\$INDEX_NAME = RDB\$INDEX_SEGMENTS.RDB\$INDEX_NAME
|
||||
LEFT JOIN RDB\$RELATION_CONSTRAINTS ON RDB\$RELATION_CONSTRAINTS.RDB\$INDEX_NAME = RDB\$INDEX_SEGMENTS.RDB\$INDEX_NAME
|
||||
WHERE UPPER(RDB\$INDICES.RDB\$RELATION_NAME)=$table
|
||||
AND UPPER(RDB\$INDICES.RDB\$INDEX_NAME)=%s
|
||||
AND RDB\$RELATION_CONSTRAINTS.RDB\$CONSTRAINT_TYPE IS NULL
|
||||
ORDER BY RDB\$INDEX_SEGMENTS.RDB\$FIELD_POSITION";
|
||||
$index_name_mdb2 = $db->quote(strtoupper($db->getIndexName($index_name)), 'text');
|
||||
$result = $db->queryRow(sprintf($query, $index_name_mdb2));
|
||||
if (!MDB2::isError($result) && (null !== $result)) {
|
||||
// apply 'idxname_format' only if the query succeeded, otherwise
|
||||
// fallback to the given $index_name, without transformation
|
||||
$index_name = $index_name_mdb2;
|
||||
} else {
|
||||
$index_name = $db->quote(strtoupper($index_name), 'text');
|
||||
}
|
||||
$result = $db->query(sprintf($query, $index_name));
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$definition = array();
|
||||
while (is_array($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))) {
|
||||
$row = array_change_key_case($row, CASE_LOWER);
|
||||
$column_name = $row['field_name'];
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
if ($db->options['field_case'] == CASE_LOWER) {
|
||||
$column_name = strtolower($column_name);
|
||||
} else {
|
||||
$column_name = strtoupper($column_name);
|
||||
}
|
||||
}
|
||||
$definition['fields'][$column_name] = array(
|
||||
'position' => (int)$row['field_position'],
|
||||
);
|
||||
/*
|
||||
if (!empty($row['collation'])) {
|
||||
$definition['fields'][$column_name]['sorting'] = ($row['collation'] == 'A'
|
||||
? 'ascending' : 'descending');
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
$result->free();
|
||||
if (empty($definition)) {
|
||||
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
'it was not specified an existing table index', __FUNCTION__);
|
||||
}
|
||||
return $definition;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ getTableConstraintDefinition()
|
||||
|
||||
/**
|
||||
* Get the structure of a constraint into an array
|
||||
*
|
||||
* @param string $table_name name of table that should be used in method
|
||||
* @param string $constraint_name name of constraint that should be used in method
|
||||
* @return mixed data array on success, a MDB2 error on failure
|
||||
* @access public
|
||||
*/
|
||||
function getTableConstraintDefinition($table_name, $constraint_name)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
list($schema, $table) = $this->splitTableSchema($table_name);
|
||||
|
||||
$table = $db->quote(strtoupper($table), 'text');
|
||||
$query = "SELECT rc.RDB\$CONSTRAINT_NAME,
|
||||
s.RDB\$FIELD_NAME AS field_name,
|
||||
CASE WHEN rc.RDB\$CONSTRAINT_TYPE = 'PRIMARY KEY' THEN 1 ELSE 0 END AS \"primary\",
|
||||
CASE WHEN rc.RDB\$CONSTRAINT_TYPE = 'FOREIGN KEY' THEN 1 ELSE 0 END AS \"foreign\",
|
||||
CASE WHEN rc.RDB\$CONSTRAINT_TYPE = 'UNIQUE' THEN 1 ELSE 0 END AS \"unique\",
|
||||
CASE WHEN rc.RDB\$CONSTRAINT_TYPE = 'CHECK' THEN 1 ELSE 0 END AS \"check\",
|
||||
i.RDB\$DESCRIPTION AS description,
|
||||
CASE WHEN rc.RDB\$DEFERRABLE = 'NO' THEN 0 ELSE 1 END AS deferrable,
|
||||
CASE WHEN rc.RDB\$INITIALLY_DEFERRED = 'NO' THEN 0 ELSE 1 END AS initiallydeferred,
|
||||
refc.RDB\$UPDATE_RULE AS onupdate,
|
||||
refc.RDB\$DELETE_RULE AS ondelete,
|
||||
refc.RDB\$MATCH_OPTION AS \"match\",
|
||||
i2.RDB\$RELATION_NAME AS references_table,
|
||||
s2.RDB\$FIELD_NAME AS references_field,
|
||||
(s.RDB\$FIELD_POSITION + 1) AS field_position
|
||||
FROM RDB\$INDEX_SEGMENTS s
|
||||
LEFT JOIN RDB\$INDICES i ON i.RDB\$INDEX_NAME = s.RDB\$INDEX_NAME
|
||||
LEFT JOIN RDB\$RELATION_CONSTRAINTS rc ON rc.RDB\$INDEX_NAME = s.RDB\$INDEX_NAME
|
||||
LEFT JOIN RDB\$REF_CONSTRAINTS refc ON rc.RDB\$CONSTRAINT_NAME = refc.RDB\$CONSTRAINT_NAME
|
||||
LEFT JOIN RDB\$RELATION_CONSTRAINTS rc2 ON rc2.RDB\$CONSTRAINT_NAME = refc.RDB\$CONST_NAME_UQ
|
||||
LEFT JOIN RDB\$INDICES i2 ON i2.RDB\$INDEX_NAME = rc2.RDB\$INDEX_NAME
|
||||
LEFT JOIN RDB\$INDEX_SEGMENTS s2 ON i2.RDB\$INDEX_NAME = s2.RDB\$INDEX_NAME
|
||||
AND s.RDB\$FIELD_POSITION = s2.RDB\$FIELD_POSITION
|
||||
WHERE UPPER(i.RDB\$RELATION_NAME)=$table
|
||||
AND UPPER(rc.RDB\$CONSTRAINT_NAME)=%s
|
||||
AND rc.RDB\$CONSTRAINT_TYPE IS NOT NULL
|
||||
ORDER BY s.RDB\$FIELD_POSITION";
|
||||
$constraint_name_mdb2 = $db->quote(strtoupper($db->getIndexName($constraint_name)), 'text');
|
||||
$result = $db->queryRow(sprintf($query, $constraint_name_mdb2));
|
||||
if (!MDB2::isError($result) && (null !== $result)) {
|
||||
// apply 'idxname_format' only if the query succeeded, otherwise
|
||||
// fallback to the given $index_name, without transformation
|
||||
$constraint_name = $constraint_name_mdb2;
|
||||
} else {
|
||||
$constraint_name = $db->quote(strtoupper($constraint_name), 'text');
|
||||
}
|
||||
$result = $db->query(sprintf($query, $constraint_name));
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$definition = array();
|
||||
while (is_array($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))) {
|
||||
$row = array_change_key_case($row, CASE_LOWER);
|
||||
$column_name = $row['field_name'];
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
if ($db->options['field_case'] == CASE_LOWER) {
|
||||
$column_name = strtolower($column_name);
|
||||
} else {
|
||||
$column_name = strtoupper($column_name);
|
||||
}
|
||||
}
|
||||
$definition['fields'][$column_name] = array(
|
||||
'position' => (int)$row['field_position']
|
||||
);
|
||||
if ($row['foreign']) {
|
||||
$ref_column_name = $row['references_field'];
|
||||
$ref_table_name = $row['references_table'];
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
if ($db->options['field_case'] == CASE_LOWER) {
|
||||
$ref_column_name = strtolower($ref_column_name);
|
||||
$ref_table_name = strtolower($ref_table_name);
|
||||
} else {
|
||||
$ref_column_name = strtoupper($ref_column_name);
|
||||
$ref_table_name = strtoupper($ref_table_name);
|
||||
}
|
||||
}
|
||||
$definition['references']['table'] = $ref_table_name;
|
||||
$definition['references']['fields'][$ref_column_name] = array(
|
||||
'position' => (int)$row['field_position']
|
||||
);
|
||||
}
|
||||
//collation?!?
|
||||
/*
|
||||
if (!empty($row['collation'])) {
|
||||
$definition['fields'][$field]['sorting'] = ($row['collation'] == 'A'
|
||||
? 'ascending' : 'descending');
|
||||
}
|
||||
*/
|
||||
$lastrow = $row;
|
||||
// otherwise $row is no longer usable on exit from loop
|
||||
}
|
||||
$result->free();
|
||||
if (empty($definition)) {
|
||||
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
$constraint_name . ' is not an existing table constraint', __FUNCTION__);
|
||||
}
|
||||
|
||||
$definition['primary'] = (boolean)$lastrow['primary'];
|
||||
$definition['unique'] = (boolean)$lastrow['unique'];
|
||||
$definition['foreign'] = (boolean)$lastrow['foreign'];
|
||||
$definition['check'] = (boolean)$lastrow['check'];
|
||||
$definition['deferrable'] = (boolean)$lastrow['deferrable'];
|
||||
$definition['initiallydeferred'] = (boolean)$lastrow['initiallydeferred'];
|
||||
$definition['onupdate'] = $lastrow['onupdate'];
|
||||
$definition['ondelete'] = $lastrow['ondelete'];
|
||||
$definition['match'] = $lastrow['match'];
|
||||
|
||||
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
|
||||
* @access public
|
||||
*/
|
||||
function getTriggerDefinition($trigger)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$trigger = $db->quote(strtoupper($trigger), 'text');
|
||||
$query = "SELECT RDB\$TRIGGER_NAME AS trigger_name,
|
||||
RDB\$RELATION_NAME AS table_name,
|
||||
RDB\$TRIGGER_SOURCE AS trigger_body,
|
||||
CASE RDB\$TRIGGER_TYPE
|
||||
WHEN 1 THEN 'BEFORE'
|
||||
WHEN 2 THEN 'AFTER'
|
||||
WHEN 3 THEN 'BEFORE'
|
||||
WHEN 4 THEN 'AFTER'
|
||||
WHEN 5 THEN 'BEFORE'
|
||||
WHEN 6 THEN 'AFTER'
|
||||
END AS trigger_type,
|
||||
CASE RDB\$TRIGGER_TYPE
|
||||
WHEN 1 THEN 'INSERT'
|
||||
WHEN 2 THEN 'INSERT'
|
||||
WHEN 3 THEN 'UPDATE'
|
||||
WHEN 4 THEN 'UPDATE'
|
||||
WHEN 5 THEN 'DELETE'
|
||||
WHEN 6 THEN 'DELETE'
|
||||
END AS trigger_event,
|
||||
CASE RDB\$TRIGGER_INACTIVE
|
||||
WHEN 1 THEN 0 ELSE 1
|
||||
END AS trigger_enabled,
|
||||
RDB\$DESCRIPTION AS trigger_comment
|
||||
FROM RDB\$TRIGGERS
|
||||
WHERE UPPER(RDB\$TRIGGER_NAME)=$trigger";
|
||||
$types = array(
|
||||
'trigger_name' => 'text',
|
||||
'table_name' => 'text',
|
||||
'trigger_body' => 'clob',
|
||||
'trigger_type' => 'text',
|
||||
'trigger_event' => 'text',
|
||||
'trigger_comment' => 'text',
|
||||
'trigger_enabled' => 'boolean',
|
||||
);
|
||||
|
||||
$def = $db->queryRow($query, $types, MDB2_FETCHMODE_ASSOC);
|
||||
if (MDB2::isError($def)) {
|
||||
return $def;
|
||||
}
|
||||
|
||||
$clob = $def['trigger_body'];
|
||||
if (!MDB2::isError($clob) && is_resource($clob)) {
|
||||
$value = '';
|
||||
while (!feof($clob)) {
|
||||
$data = fread($clob, 8192);
|
||||
$value.= $data;
|
||||
}
|
||||
$db->datatype->destroyLOB($clob);
|
||||
$def['trigger_body'] = $value;
|
||||
}
|
||||
|
||||
return $def;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ tableInfo()
|
||||
|
||||
/**
|
||||
* Returns information about a table or a result set
|
||||
*
|
||||
* NOTE: only supports 'table' and 'flags' if <var>$result</var>
|
||||
* is a table name.
|
||||
*
|
||||
* @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 a valid tableInfo mode
|
||||
*
|
||||
* @return array an associative array with the information requested.
|
||||
* A MDB2_Error object on failure.
|
||||
*
|
||||
* @see MDB2_Driver_Common::tableInfo()
|
||||
*/
|
||||
function tableInfo($result, $mode = null)
|
||||
{
|
||||
if (is_string($result)) {
|
||||
return parent::tableInfo($result, $mode);
|
||||
}
|
||||
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$resource = MDB2::isResultCommon($result) ? $result->getResource() : $result;
|
||||
if (!is_resource($resource)) {
|
||||
return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
|
||||
'Could not generate result resource', __FUNCTION__);
|
||||
}
|
||||
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
if ($db->options['field_case'] == CASE_LOWER) {
|
||||
$case_func = 'strtolower';
|
||||
} else {
|
||||
$case_func = 'strtoupper';
|
||||
}
|
||||
} else {
|
||||
$case_func = 'strval';
|
||||
}
|
||||
|
||||
$count = @ibase_num_fields($resource);
|
||||
$res = array();
|
||||
|
||||
if ($mode) {
|
||||
$res['num_fields'] = $count;
|
||||
}
|
||||
|
||||
$db->loadModule('Datatype', null, true);
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
$info = @ibase_field_info($resource, $i);
|
||||
if (($pos = strpos($info['type'], '(')) !== false) {
|
||||
$info['type'] = substr($info['type'], 0, $pos);
|
||||
}
|
||||
$res[$i] = array(
|
||||
'table' => $case_func($info['relation']),
|
||||
'name' => $case_func($info['name']),
|
||||
'type' => $info['type'],
|
||||
'length' => $info['length'],
|
||||
'flags' => '',
|
||||
);
|
||||
$mdb2type_info = $db->datatype->mapNativeDatatype($res[$i]);
|
||||
if (MDB2::isError($mdb2type_info)) {
|
||||
return $mdb2type_info;
|
||||
}
|
||||
$res[$i]['mdb2type'] = $mdb2type_info[0][0];
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
}
|
||||
?>
|
653
extlib/MDB2/Driver/Reverse/mssql.php
Normal file
653
extlib/MDB2/Driver/Reverse/mssql.php
Normal file
@ -0,0 +1,653 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 and 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox, |
|
||||
// | Stig. S. Bakken, Lukas Smith, Frank M. Kromann, Lorenzo Alberton |
|
||||
// | 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Authors: Lukas Smith <smith@pooteeweet.org> |
|
||||
// | Lorenzo Alberton <l.alberton@quipo.it> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
|
||||
require_once 'MDB2/Driver/Reverse/Common.php';
|
||||
|
||||
/**
|
||||
* MDB2 MSSQL driver for the schema reverse engineering module
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lukas Smith <smith@dybnet.de>
|
||||
* @author Lorenzo Alberton <l.alberton@quipo.it>
|
||||
*/
|
||||
class MDB2_Driver_Reverse_mssql extends MDB2_Driver_Reverse_Common
|
||||
{
|
||||
// {{{ getTableFieldDefinition()
|
||||
|
||||
/**
|
||||
* Get the structure of a field into an array
|
||||
*
|
||||
* @param string $table_name name of table that should be used in method
|
||||
* @param string $field_name name of field that should be used in method
|
||||
* @return mixed data array on success, a MDB2 error on failure
|
||||
* @access public
|
||||
*/
|
||||
function getTableFieldDefinition($table_name, $field_name)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$result = $db->loadModule('Datatype', null, true);
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
list($schema, $table) = $this->splitTableSchema($table_name);
|
||||
|
||||
$table = $db->quoteIdentifier($table, true);
|
||||
$fldname = $db->quoteIdentifier($field_name, true);
|
||||
|
||||
$query = "SELECT t.table_name,
|
||||
c.column_name 'name',
|
||||
c.data_type 'type',
|
||||
CASE c.is_nullable WHEN 'YES' THEN 1 ELSE 0 END AS 'is_nullable',
|
||||
c.column_default,
|
||||
c.character_maximum_length 'length',
|
||||
c.numeric_precision,
|
||||
c.numeric_scale,
|
||||
c.character_set_name,
|
||||
c.collation_name
|
||||
FROM INFORMATION_SCHEMA.TABLES t,
|
||||
INFORMATION_SCHEMA.COLUMNS c
|
||||
WHERE t.table_name = c.table_name
|
||||
AND t.table_name = '$table'
|
||||
AND c.column_name = '$fldname'";
|
||||
if (!empty($schema)) {
|
||||
$query .= " AND t.table_schema = '" .$db->quoteIdentifier($schema, true) ."'";
|
||||
}
|
||||
$query .= ' ORDER BY t.table_name';
|
||||
$column = $db->queryRow($query, null, MDB2_FETCHMODE_ASSOC);
|
||||
if (MDB2::isError($column)) {
|
||||
return $column;
|
||||
}
|
||||
if (empty($column)) {
|
||||
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
'it was not specified an existing table column', __FUNCTION__);
|
||||
}
|
||||
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
if ($db->options['field_case'] == CASE_LOWER) {
|
||||
$column['name'] = strtolower($column['name']);
|
||||
} else {
|
||||
$column['name'] = strtoupper($column['name']);
|
||||
}
|
||||
} else {
|
||||
$column = array_change_key_case($column, $db->options['field_case']);
|
||||
}
|
||||
$mapped_datatype = $db->datatype->mapNativeDatatype($column);
|
||||
if (MDB2::isError($mapped_datatype)) {
|
||||
return $mapped_datatype;
|
||||
}
|
||||
list($types, $length, $unsigned, $fixed) = $mapped_datatype;
|
||||
$notnull = true;
|
||||
if ($column['is_nullable']) {
|
||||
$notnull = false;
|
||||
}
|
||||
$default = false;
|
||||
if (array_key_exists('column_default', $column)) {
|
||||
$default = $column['column_default'];
|
||||
if ((null === $default) && $notnull) {
|
||||
$default = '';
|
||||
} elseif (strlen($default) > 4
|
||||
&& substr($default, 0, 1) == '('
|
||||
&& substr($default, -1, 1) == ')'
|
||||
) {
|
||||
//mssql wraps the default value in parentheses: "((1234))", "(NULL)"
|
||||
$default = trim($default, '()');
|
||||
if ($default == 'NULL') {
|
||||
$default = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
$definition[0] = array(
|
||||
'notnull' => $notnull,
|
||||
'nativetype' => preg_replace('/^([a-z]+)[^a-z].*/i', '\\1', $column['type'])
|
||||
);
|
||||
if (null !== $length) {
|
||||
$definition[0]['length'] = $length;
|
||||
}
|
||||
if (null !== $unsigned) {
|
||||
$definition[0]['unsigned'] = $unsigned;
|
||||
}
|
||||
if (null !== $fixed) {
|
||||
$definition[0]['fixed'] = $fixed;
|
||||
}
|
||||
if (false !== $default) {
|
||||
$definition[0]['default'] = $default;
|
||||
}
|
||||
foreach ($types as $key => $type) {
|
||||
$definition[$key] = $definition[0];
|
||||
if ($type == 'clob' || $type == 'blob') {
|
||||
unset($definition[$key]['default']);
|
||||
}
|
||||
$definition[$key]['type'] = $type;
|
||||
$definition[$key]['mdb2type'] = $type;
|
||||
}
|
||||
return $definition;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ getTableIndexDefinition()
|
||||
|
||||
/**
|
||||
* Get the structure of an index into an array
|
||||
*
|
||||
* @param string $table_name name of table that should be used in method
|
||||
* @param string $index_name name of index that should be used in method
|
||||
* @return mixed data array on success, a MDB2 error on failure
|
||||
* @access public
|
||||
*/
|
||||
function getTableIndexDefinition($table_name, $index_name)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
list($schema, $table) = $this->splitTableSchema($table_name);
|
||||
|
||||
$table = $db->quoteIdentifier($table, true);
|
||||
//$idxname = $db->quoteIdentifier($index_name, true);
|
||||
|
||||
$query = "SELECT OBJECT_NAME(i.id) tablename,
|
||||
i.name indexname,
|
||||
c.name field_name,
|
||||
CASE INDEXKEY_PROPERTY(i.id, i.indid, ik.keyno, 'IsDescending')
|
||||
WHEN 1 THEN 'DESC' ELSE 'ASC'
|
||||
END 'collation',
|
||||
ik.keyno 'position'
|
||||
FROM sysindexes i
|
||||
JOIN sysindexkeys ik ON ik.id = i.id AND ik.indid = i.indid
|
||||
JOIN syscolumns c ON c.id = ik.id AND c.colid = ik.colid
|
||||
WHERE OBJECT_NAME(i.id) = '$table'
|
||||
AND i.name = '%s'
|
||||
AND NOT EXISTS (
|
||||
SELECT *
|
||||
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE k
|
||||
WHERE k.table_name = OBJECT_NAME(i.id)
|
||||
AND k.constraint_name = i.name";
|
||||
if (!empty($schema)) {
|
||||
$query .= " AND k.table_schema = '" .$db->quoteIdentifier($schema, true) ."'";
|
||||
}
|
||||
$query .= ')
|
||||
ORDER BY tablename, indexname, ik.keyno';
|
||||
|
||||
$index_name_mdb2 = $db->getIndexName($index_name);
|
||||
$result = $db->queryRow(sprintf($query, $index_name_mdb2));
|
||||
if (!MDB2::isError($result) && (null !== $result)) {
|
||||
// apply 'idxname_format' only if the query succeeded, otherwise
|
||||
// fallback to the given $index_name, without transformation
|
||||
$index_name = $index_name_mdb2;
|
||||
}
|
||||
$result = $db->query(sprintf($query, $index_name));
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$definition = array();
|
||||
while (is_array($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))) {
|
||||
$column_name = $row['field_name'];
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
if ($db->options['field_case'] == CASE_LOWER) {
|
||||
$column_name = strtolower($column_name);
|
||||
} else {
|
||||
$column_name = strtoupper($column_name);
|
||||
}
|
||||
}
|
||||
$definition['fields'][$column_name] = array(
|
||||
'position' => (int)$row['position'],
|
||||
);
|
||||
if (!empty($row['collation'])) {
|
||||
$definition['fields'][$column_name]['sorting'] = ($row['collation'] == 'ASC'
|
||||
? 'ascending' : 'descending');
|
||||
}
|
||||
}
|
||||
$result->free();
|
||||
if (empty($definition['fields'])) {
|
||||
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
'it was not specified an existing table index', __FUNCTION__);
|
||||
}
|
||||
return $definition;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ getTableConstraintDefinition()
|
||||
|
||||
/**
|
||||
* Get the structure of a constraint into an array
|
||||
*
|
||||
* @param string $table_name name of table that should be used in method
|
||||
* @param string $constraint_name name of constraint that should be used in method
|
||||
* @return mixed data array on success, a MDB2 error on failure
|
||||
* @access public
|
||||
*/
|
||||
function getTableConstraintDefinition($table_name, $constraint_name)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
list($schema, $table) = $this->splitTableSchema($table_name);
|
||||
|
||||
$table = $db->quoteIdentifier($table, true);
|
||||
$query = "SELECT k.table_name,
|
||||
k.column_name field_name,
|
||||
CASE c.constraint_type WHEN 'PRIMARY KEY' THEN 1 ELSE 0 END 'primary',
|
||||
CASE c.constraint_type WHEN 'UNIQUE' THEN 1 ELSE 0 END 'unique',
|
||||
CASE c.constraint_type WHEN 'FOREIGN KEY' THEN 1 ELSE 0 END 'foreign',
|
||||
CASE c.constraint_type WHEN 'CHECK' THEN 1 ELSE 0 END 'check',
|
||||
CASE c.is_deferrable WHEN 'NO' THEN 0 ELSE 1 END 'deferrable',
|
||||
CASE c.initially_deferred WHEN 'NO' THEN 0 ELSE 1 END 'initiallydeferred',
|
||||
rc.match_option 'match',
|
||||
rc.update_rule 'onupdate',
|
||||
rc.delete_rule 'ondelete',
|
||||
kcu.table_name 'references_table',
|
||||
kcu.column_name 'references_field',
|
||||
k.ordinal_position 'field_position'
|
||||
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE k
|
||||
LEFT JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS c
|
||||
ON k.table_name = c.table_name
|
||||
AND k.table_schema = c.table_schema
|
||||
AND k.table_catalog = c.table_catalog
|
||||
AND k.constraint_catalog = c.constraint_catalog
|
||||
AND k.constraint_name = c.constraint_name
|
||||
LEFT JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc
|
||||
ON rc.constraint_schema = c.constraint_schema
|
||||
AND rc.constraint_catalog = c.constraint_catalog
|
||||
AND rc.constraint_name = c.constraint_name
|
||||
LEFT JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu
|
||||
ON rc.unique_constraint_schema = kcu.constraint_schema
|
||||
AND rc.unique_constraint_catalog = kcu.constraint_catalog
|
||||
AND rc.unique_constraint_name = kcu.constraint_name
|
||||
AND k.ordinal_position = kcu.ordinal_position
|
||||
WHERE k.constraint_catalog = DB_NAME()
|
||||
AND k.table_name = '$table'
|
||||
AND k.constraint_name = '%s'";
|
||||
if (!empty($schema)) {
|
||||
$query .= " AND k.table_schema = '" .$db->quoteIdentifier($schema, true) ."'";
|
||||
}
|
||||
$query .= ' ORDER BY k.constraint_name,
|
||||
k.ordinal_position';
|
||||
|
||||
$constraint_name_mdb2 = $db->getIndexName($constraint_name);
|
||||
$result = $db->queryRow(sprintf($query, $constraint_name_mdb2));
|
||||
if (!MDB2::isError($result) && (null !== $result)) {
|
||||
// apply 'idxname_format' only if the query succeeded, otherwise
|
||||
// fallback to the given $index_name, without transformation
|
||||
$constraint_name = $constraint_name_mdb2;
|
||||
}
|
||||
$result = $db->query(sprintf($query, $constraint_name));
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$definition = array(
|
||||
'fields' => array()
|
||||
);
|
||||
while (is_array($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))) {
|
||||
$row = array_change_key_case($row, CASE_LOWER);
|
||||
$column_name = $row['field_name'];
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
if ($db->options['field_case'] == CASE_LOWER) {
|
||||
$column_name = strtolower($column_name);
|
||||
} else {
|
||||
$column_name = strtoupper($column_name);
|
||||
}
|
||||
}
|
||||
$definition['fields'][$column_name] = array(
|
||||
'position' => (int)$row['field_position']
|
||||
);
|
||||
if ($row['foreign']) {
|
||||
$ref_column_name = $row['references_field'];
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
if ($db->options['field_case'] == CASE_LOWER) {
|
||||
$ref_column_name = strtolower($ref_column_name);
|
||||
} else {
|
||||
$ref_column_name = strtoupper($ref_column_name);
|
||||
}
|
||||
}
|
||||
$definition['references']['table'] = $row['references_table'];
|
||||
$definition['references']['fields'][$ref_column_name] = array(
|
||||
'position' => (int)$row['field_position']
|
||||
);
|
||||
}
|
||||
//collation?!?
|
||||
/*
|
||||
if (!empty($row['collation'])) {
|
||||
$definition['fields'][$column_name]['sorting'] = ($row['collation'] == 'ASC'
|
||||
? 'ascending' : 'descending');
|
||||
}
|
||||
*/
|
||||
$lastrow = $row;
|
||||
// otherwise $row is no longer usable on exit from loop
|
||||
}
|
||||
$result->free();
|
||||
if (empty($definition['fields'])) {
|
||||
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
$constraint_name . ' is not an existing table constraint', __FUNCTION__);
|
||||
}
|
||||
|
||||
$definition['primary'] = (boolean)$lastrow['primary'];
|
||||
$definition['unique'] = (boolean)$lastrow['unique'];
|
||||
$definition['foreign'] = (boolean)$lastrow['foreign'];
|
||||
$definition['check'] = (boolean)$lastrow['check'];
|
||||
$definition['deferrable'] = (boolean)$lastrow['deferrable'];
|
||||
$definition['initiallydeferred'] = (boolean)$lastrow['initiallydeferred'];
|
||||
$definition['onupdate'] = $lastrow['onupdate'];
|
||||
$definition['ondelete'] = $lastrow['ondelete'];
|
||||
$definition['match'] = $lastrow['match'];
|
||||
|
||||
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
|
||||
* @access public
|
||||
*/
|
||||
function getTriggerDefinition($trigger)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$query = "SELECT sys1.name trigger_name,
|
||||
sys2.name table_name,
|
||||
c.text trigger_body,
|
||||
c.encrypted is_encripted,
|
||||
CASE
|
||||
WHEN OBJECTPROPERTY(sys1.id, 'ExecIsTriggerDisabled') = 1
|
||||
THEN 0 ELSE 1
|
||||
END trigger_enabled,
|
||||
CASE
|
||||
WHEN OBJECTPROPERTY(sys1.id, 'ExecIsInsertTrigger') = 1
|
||||
THEN 'INSERT'
|
||||
WHEN OBJECTPROPERTY(sys1.id, 'ExecIsUpdateTrigger') = 1
|
||||
THEN 'UPDATE'
|
||||
WHEN OBJECTPROPERTY(sys1.id, 'ExecIsDeleteTrigger') = 1
|
||||
THEN 'DELETE'
|
||||
END trigger_event,
|
||||
CASE WHEN OBJECTPROPERTY(sys1.id, 'ExecIsInsteadOfTrigger') = 1
|
||||
THEN 'INSTEAD OF' ELSE 'AFTER'
|
||||
END trigger_type,
|
||||
'' trigger_comment
|
||||
FROM sysobjects sys1
|
||||
JOIN sysobjects sys2 ON sys1.parent_obj = sys2.id
|
||||
JOIN syscomments c ON sys1.id = c.id
|
||||
WHERE sys1.xtype = 'TR'
|
||||
AND sys1.name = ". $db->quote($trigger, 'text');
|
||||
|
||||
$types = array(
|
||||
'trigger_name' => 'text',
|
||||
'table_name' => 'text',
|
||||
'trigger_body' => 'text',
|
||||
'trigger_type' => 'text',
|
||||
'trigger_event' => 'text',
|
||||
'trigger_comment' => 'text',
|
||||
'trigger_enabled' => 'boolean',
|
||||
'is_encripted' => 'boolean',
|
||||
);
|
||||
|
||||
$def = $db->queryRow($query, $types, MDB2_FETCHMODE_ASSOC);
|
||||
if (MDB2::isError($def)) {
|
||||
return $def;
|
||||
}
|
||||
$trg_body = $db->queryCol('EXEC sp_helptext '. $db->quote($trigger, 'text'), 'text');
|
||||
if (!MDB2::isError($trg_body)) {
|
||||
$def['trigger_body'] = implode(' ', $trg_body);
|
||||
}
|
||||
return $def;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ tableInfo()
|
||||
|
||||
/**
|
||||
* Returns information about a table or a result set
|
||||
*
|
||||
* NOTE: only supports 'table' and 'flags' if <var>$result</var>
|
||||
* is a table name.
|
||||
*
|
||||
* @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 a valid tableInfo mode
|
||||
*
|
||||
* @return array an associative array with the information requested.
|
||||
* A MDB2_Error object on failure.
|
||||
*
|
||||
* @see MDB2_Driver_Common::tableInfo()
|
||||
*/
|
||||
function tableInfo($result, $mode = null)
|
||||
{
|
||||
if (is_string($result)) {
|
||||
return parent::tableInfo($result, $mode);
|
||||
}
|
||||
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$resource = MDB2::isResultCommon($result) ? $result->getResource() : $result;
|
||||
if (!is_resource($resource)) {
|
||||
return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
|
||||
'Could not generate result resource', __FUNCTION__);
|
||||
}
|
||||
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
if ($db->options['field_case'] == CASE_LOWER) {
|
||||
$case_func = 'strtolower';
|
||||
} else {
|
||||
$case_func = 'strtoupper';
|
||||
}
|
||||
} else {
|
||||
$case_func = 'strval';
|
||||
}
|
||||
|
||||
$count = @mssql_num_fields($resource);
|
||||
$res = array();
|
||||
|
||||
if ($mode) {
|
||||
$res['num_fields'] = $count;
|
||||
}
|
||||
|
||||
$db->loadModule('Datatype', null, true);
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
$res[$i] = array(
|
||||
'table' => '',
|
||||
'name' => $case_func(@mssql_field_name($resource, $i)),
|
||||
'type' => @mssql_field_type($resource, $i),
|
||||
'length' => @mssql_field_length($resource, $i),
|
||||
'flags' => '',
|
||||
);
|
||||
$mdb2type_info = $db->datatype->mapNativeDatatype($res[$i]);
|
||||
if (MDB2::isError($mdb2type_info)) {
|
||||
return $mdb2type_info;
|
||||
}
|
||||
$res[$i]['mdb2type'] = $mdb2type_info[0][0];
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _mssql_field_flags()
|
||||
|
||||
/**
|
||||
* Get a column's flags
|
||||
*
|
||||
* Supports "not_null", "primary_key",
|
||||
* "auto_increment" (mssql identity), "timestamp" (mssql timestamp),
|
||||
* "unique_key" (mssql unique index, unique check or primary_key) and
|
||||
* "multiple_key" (multikey index)
|
||||
*
|
||||
* mssql timestamp is NOT similar to the mysql timestamp so this is maybe
|
||||
* not useful at all - is the behaviour of mysql_field_flags that primary
|
||||
* keys are alway unique? is the interpretation of multiple_key correct?
|
||||
*
|
||||
* @param string $table the table name
|
||||
* @param string $column the field name
|
||||
*
|
||||
* @return string the flags
|
||||
*
|
||||
* @access protected
|
||||
* @author Joern Barthel <j_barthel@web.de>
|
||||
*/
|
||||
function _mssql_field_flags($table, $column)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
static $tableName = null;
|
||||
static $flags = array();
|
||||
|
||||
if ($table != $tableName) {
|
||||
|
||||
$flags = array();
|
||||
$tableName = $table;
|
||||
|
||||
// get unique and primary keys
|
||||
$res = $db->queryAll("EXEC SP_HELPINDEX[$table]", null, MDB2_FETCHMODE_ASSOC);
|
||||
|
||||
foreach ($res as $val) {
|
||||
$val = array_change_key_case($val, CASE_LOWER);
|
||||
$keys = explode(', ', $val['index_keys']);
|
||||
|
||||
if (sizeof($keys) > 1) {
|
||||
foreach ($keys as $key) {
|
||||
$this->_add_flag($flags[$key], 'multiple_key');
|
||||
}
|
||||
}
|
||||
|
||||
if (strpos($val['index_description'], 'primary key')) {
|
||||
foreach ($keys as $key) {
|
||||
$this->_add_flag($flags[$key], 'primary_key');
|
||||
}
|
||||
} elseif (strpos($val['index_description'], 'unique')) {
|
||||
foreach ($keys as $key) {
|
||||
$this->_add_flag($flags[$key], 'unique_key');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get auto_increment, not_null and timestamp
|
||||
$res = $db->queryAll("EXEC SP_COLUMNS[$table]", null, MDB2_FETCHMODE_ASSOC);
|
||||
|
||||
foreach ($res as $val) {
|
||||
$val = array_change_key_case($val, CASE_LOWER);
|
||||
if ($val['nullable'] == '0') {
|
||||
$this->_add_flag($flags[$val['column_name']], 'not_null');
|
||||
}
|
||||
if (strpos($val['type_name'], 'identity')) {
|
||||
$this->_add_flag($flags[$val['column_name']], 'auto_increment');
|
||||
}
|
||||
if (strpos($val['type_name'], 'timestamp')) {
|
||||
$this->_add_flag($flags[$val['column_name']], 'timestamp');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($flags[$column])) {
|
||||
return(implode(' ', $flags[$column]));
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _add_flag()
|
||||
|
||||
/**
|
||||
* Adds a string to the flags array if the flag is not yet in there
|
||||
* - if there is no flag present the array is created
|
||||
*
|
||||
* @param array &$array the reference to the flag-array
|
||||
* @param string $value the flag value
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @access protected
|
||||
* @author Joern Barthel <j_barthel@web.de>
|
||||
*/
|
||||
function _add_flag(&$array, $value)
|
||||
{
|
||||
if (!is_array($array)) {
|
||||
$array = array($value);
|
||||
} elseif (!in_array($value, $array)) {
|
||||
array_push($array, $value);
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
}
|
||||
?>
|
610
extlib/MDB2/Driver/Reverse/mysqli.php
Normal file
610
extlib/MDB2/Driver/Reverse/mysqli.php
Normal file
@ -0,0 +1,610 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 and 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Copyright (c) 1998-2007 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Author: Lukas Smith <smith@pooteeweet.org> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
|
||||
require_once 'MDB2/Driver/Reverse/Common.php';
|
||||
|
||||
/**
|
||||
* MDB2 MySQLi driver for the schema reverse engineering module
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lukas Smith <smith@pooteeweet.org>
|
||||
* @author Lorenzo Alberton <l.alberton@quipo.it>
|
||||
*/
|
||||
class MDB2_Driver_Reverse_mysqli extends MDB2_Driver_Reverse_Common
|
||||
{
|
||||
/**
|
||||
* Array for converting MYSQLI_*_FLAG constants to text values
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $flags = array(
|
||||
MYSQLI_NOT_NULL_FLAG => 'not_null',
|
||||
MYSQLI_PRI_KEY_FLAG => 'primary_key',
|
||||
MYSQLI_UNIQUE_KEY_FLAG => 'unique_key',
|
||||
MYSQLI_MULTIPLE_KEY_FLAG => 'multiple_key',
|
||||
MYSQLI_BLOB_FLAG => 'blob',
|
||||
MYSQLI_UNSIGNED_FLAG => 'unsigned',
|
||||
MYSQLI_ZEROFILL_FLAG => 'zerofill',
|
||||
MYSQLI_AUTO_INCREMENT_FLAG => 'auto_increment',
|
||||
MYSQLI_TIMESTAMP_FLAG => 'timestamp',
|
||||
MYSQLI_SET_FLAG => 'set',
|
||||
// MYSQLI_NUM_FLAG => 'numeric', // unnecessary
|
||||
// MYSQLI_PART_KEY_FLAG => 'multiple_key', // duplicatvie
|
||||
MYSQLI_GROUP_FLAG => 'group_by'
|
||||
);
|
||||
|
||||
/**
|
||||
* Array for converting MYSQLI_TYPE_* constants to text values
|
||||
* @var array
|
||||
* @access public
|
||||
*/
|
||||
var $types = array(
|
||||
MYSQLI_TYPE_DECIMAL => 'decimal',
|
||||
246 => 'decimal',
|
||||
MYSQLI_TYPE_TINY => 'tinyint',
|
||||
MYSQLI_TYPE_SHORT => 'int',
|
||||
MYSQLI_TYPE_LONG => 'int',
|
||||
MYSQLI_TYPE_FLOAT => 'float',
|
||||
MYSQLI_TYPE_DOUBLE => 'double',
|
||||
// MYSQLI_TYPE_NULL => 'DEFAULT NULL', // let flags handle it
|
||||
MYSQLI_TYPE_TIMESTAMP => 'timestamp',
|
||||
MYSQLI_TYPE_LONGLONG => 'bigint',
|
||||
MYSQLI_TYPE_INT24 => 'mediumint',
|
||||
MYSQLI_TYPE_DATE => 'date',
|
||||
MYSQLI_TYPE_TIME => 'time',
|
||||
MYSQLI_TYPE_DATETIME => 'datetime',
|
||||
MYSQLI_TYPE_YEAR => 'year',
|
||||
MYSQLI_TYPE_NEWDATE => 'date',
|
||||
MYSQLI_TYPE_ENUM => 'enum',
|
||||
MYSQLI_TYPE_SET => 'set',
|
||||
MYSQLI_TYPE_TINY_BLOB => 'tinyblob',
|
||||
MYSQLI_TYPE_MEDIUM_BLOB => 'mediumblob',
|
||||
MYSQLI_TYPE_LONG_BLOB => 'longblob',
|
||||
MYSQLI_TYPE_BLOB => 'blob',
|
||||
MYSQLI_TYPE_VAR_STRING => 'varchar',
|
||||
MYSQLI_TYPE_STRING => 'char',
|
||||
MYSQLI_TYPE_GEOMETRY => 'geometry',
|
||||
);
|
||||
|
||||
// {{{ getTableFieldDefinition()
|
||||
|
||||
/**
|
||||
* Get the structure of a field into an array
|
||||
*
|
||||
* @param string $table_name name of table that should be used in method
|
||||
* @param string $field_name name of field that should be used in method
|
||||
* @return mixed data array on success, a MDB2 error on failure
|
||||
* @access public
|
||||
*/
|
||||
function getTableFieldDefinition($table_name, $field_name)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$result = $db->loadModule('Datatype', null, true);
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
list($schema, $table) = $this->splitTableSchema($table_name);
|
||||
|
||||
$table = $db->quoteIdentifier($table, true);
|
||||
$query = "SHOW FULL COLUMNS FROM $table LIKE ".$db->quote($field_name);
|
||||
$columns = $db->queryAll($query, null, MDB2_FETCHMODE_ASSOC);
|
||||
if (MDB2::isError($columns)) {
|
||||
return $columns;
|
||||
}
|
||||
foreach ($columns as $column) {
|
||||
$column = array_change_key_case($column, CASE_LOWER);
|
||||
$column['name'] = $column['field'];
|
||||
unset($column['field']);
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
if ($db->options['field_case'] == CASE_LOWER) {
|
||||
$column['name'] = strtolower($column['name']);
|
||||
} else {
|
||||
$column['name'] = strtoupper($column['name']);
|
||||
}
|
||||
} else {
|
||||
$column = array_change_key_case($column, $db->options['field_case']);
|
||||
}
|
||||
if ($field_name == $column['name']) {
|
||||
$mapped_datatype = $db->datatype->mapNativeDatatype($column);
|
||||
if (MDB2::isError($mapped_datatype)) {
|
||||
return $mapped_datatype;
|
||||
}
|
||||
list($types, $length, $unsigned, $fixed) = $mapped_datatype;
|
||||
$notnull = false;
|
||||
if (empty($column['null']) || $column['null'] !== 'YES') {
|
||||
$notnull = true;
|
||||
}
|
||||
$default = false;
|
||||
if (array_key_exists('default', $column)) {
|
||||
$default = $column['default'];
|
||||
if ((null === $default) && $notnull) {
|
||||
$default = '';
|
||||
}
|
||||
}
|
||||
$definition[0] = array(
|
||||
'notnull' => $notnull,
|
||||
'nativetype' => preg_replace('/^([a-z]+)[^a-z].*/i', '\\1', $column['type'])
|
||||
);
|
||||
$autoincrement = false;
|
||||
if (!empty($column['extra'])) {
|
||||
if ($column['extra'] == 'auto_increment') {
|
||||
$autoincrement = true;
|
||||
} else {
|
||||
$definition[0]['extra'] = $column['extra'];
|
||||
}
|
||||
}
|
||||
$collate = null;
|
||||
if (!empty($column['collation'])) {
|
||||
$collate = $column['collation'];
|
||||
$charset = preg_replace('/(.+?)(_.+)?/', '$1', $collate);
|
||||
}
|
||||
|
||||
if (null !== $length) {
|
||||
$definition[0]['length'] = $length;
|
||||
}
|
||||
if (null !== $unsigned) {
|
||||
$definition[0]['unsigned'] = $unsigned;
|
||||
}
|
||||
if (null !== $fixed) {
|
||||
$definition[0]['fixed'] = $fixed;
|
||||
}
|
||||
if ($default !== false) {
|
||||
$definition[0]['default'] = $default;
|
||||
}
|
||||
if ($autoincrement !== false) {
|
||||
$definition[0]['autoincrement'] = $autoincrement;
|
||||
}
|
||||
if (null !== $collate) {
|
||||
$definition[0]['collate'] = $collate;
|
||||
$definition[0]['charset'] = $charset;
|
||||
}
|
||||
foreach ($types as $key => $type) {
|
||||
$definition[$key] = $definition[0];
|
||||
if ($type == 'clob' || $type == 'blob') {
|
||||
unset($definition[$key]['default']);
|
||||
} elseif ($type == 'timestamp' && $notnull && empty($definition[$key]['default'])) {
|
||||
$definition[$key]['default'] = '0000-00-00 00:00:00';
|
||||
}
|
||||
$definition[$key]['type'] = $type;
|
||||
$definition[$key]['mdb2type'] = $type;
|
||||
}
|
||||
return $definition;
|
||||
}
|
||||
}
|
||||
|
||||
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
'it was not specified an existing table column', __FUNCTION__);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ getTableIndexDefinition()
|
||||
|
||||
/**
|
||||
* Get the structure of an index into an array
|
||||
*
|
||||
* @param string $table_name name of table that should be used in method
|
||||
* @param string $index_name name of index that should be used in method
|
||||
* @return mixed data array on success, a MDB2 error on failure
|
||||
* @access public
|
||||
*/
|
||||
function getTableIndexDefinition($table_name, $index_name)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
list($schema, $table) = $this->splitTableSchema($table_name);
|
||||
|
||||
$table = $db->quoteIdentifier($table, true);
|
||||
$query = "SHOW INDEX FROM $table /*!50002 WHERE Key_name = %s */";
|
||||
$index_name_mdb2 = $db->getIndexName($index_name);
|
||||
$result = $db->queryRow(sprintf($query, $db->quote($index_name_mdb2)));
|
||||
if (!MDB2::isError($result) && (null !== $result)) {
|
||||
// apply 'idxname_format' only if the query succeeded, otherwise
|
||||
// fallback to the given $index_name, without transformation
|
||||
$index_name = $index_name_mdb2;
|
||||
}
|
||||
$result = $db->query(sprintf($query, $db->quote($index_name)));
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
$colpos = 1;
|
||||
$definition = array();
|
||||
while (is_array($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))) {
|
||||
$row = array_change_key_case($row, CASE_LOWER);
|
||||
$key_name = $row['key_name'];
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
if ($db->options['field_case'] == CASE_LOWER) {
|
||||
$key_name = strtolower($key_name);
|
||||
} else {
|
||||
$key_name = strtoupper($key_name);
|
||||
}
|
||||
}
|
||||
if ($index_name == $key_name) {
|
||||
if (!$row['non_unique']) {
|
||||
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
$index_name . ' is not an existing table index', __FUNCTION__);
|
||||
}
|
||||
$column_name = $row['column_name'];
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
if ($db->options['field_case'] == CASE_LOWER) {
|
||||
$column_name = strtolower($column_name);
|
||||
} else {
|
||||
$column_name = strtoupper($column_name);
|
||||
}
|
||||
}
|
||||
$definition['fields'][$column_name] = array(
|
||||
'position' => $colpos++
|
||||
);
|
||||
if (!empty($row['collation'])) {
|
||||
$definition['fields'][$column_name]['sorting'] = ($row['collation'] == 'A'
|
||||
? 'ascending' : 'descending');
|
||||
}
|
||||
}
|
||||
}
|
||||
$result->free();
|
||||
if (empty($definition['fields'])) {
|
||||
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
$index_name . ' is not an existing table index', __FUNCTION__);
|
||||
}
|
||||
return $definition;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ getTableConstraintDefinition()
|
||||
|
||||
/**
|
||||
* Get the structure of a constraint into an array
|
||||
*
|
||||
* @param string $table_name name of table that should be used in method
|
||||
* @param string $constraint_name name of constraint that should be used in method
|
||||
* @return mixed data array on success, a MDB2 error on failure
|
||||
* @access public
|
||||
*/
|
||||
function getTableConstraintDefinition($table_name, $constraint_name)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
list($schema, $table) = $this->splitTableSchema($table_name);
|
||||
$constraint_name_original = $constraint_name;
|
||||
|
||||
$table = $db->quoteIdentifier($table, true);
|
||||
$query = "SHOW INDEX FROM $table /*!50002 WHERE Key_name = %s */";
|
||||
if (strtolower($constraint_name) != 'primary') {
|
||||
$constraint_name_mdb2 = $db->getIndexName($constraint_name);
|
||||
$result = $db->queryRow(sprintf($query, $db->quote($constraint_name_mdb2)));
|
||||
if (!MDB2::isError($result) && (null !== $result)) {
|
||||
// apply 'idxname_format' only if the query succeeded, otherwise
|
||||
// fallback to the given $index_name, without transformation
|
||||
$constraint_name = $constraint_name_mdb2;
|
||||
}
|
||||
}
|
||||
$result = $db->query(sprintf($query, $db->quote($constraint_name)));
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
$colpos = 1;
|
||||
//default values, eventually overridden
|
||||
$definition = array(
|
||||
'primary' => false,
|
||||
'unique' => false,
|
||||
'foreign' => false,
|
||||
'check' => false,
|
||||
'fields' => array(),
|
||||
'references' => array(
|
||||
'table' => '',
|
||||
'fields' => array(),
|
||||
),
|
||||
'onupdate' => '',
|
||||
'ondelete' => '',
|
||||
'match' => '',
|
||||
'deferrable' => false,
|
||||
'initiallydeferred' => false,
|
||||
);
|
||||
while (is_array($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))) {
|
||||
$row = array_change_key_case($row, CASE_LOWER);
|
||||
$key_name = $row['key_name'];
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
if ($db->options['field_case'] == CASE_LOWER) {
|
||||
$key_name = strtolower($key_name);
|
||||
} else {
|
||||
$key_name = strtoupper($key_name);
|
||||
}
|
||||
}
|
||||
if ($constraint_name == $key_name) {
|
||||
if ($row['non_unique']) {
|
||||
//FOREIGN KEY?
|
||||
return $this->_getTableFKConstraintDefinition($table, $constraint_name_original, $definition);
|
||||
}
|
||||
if ($row['key_name'] == 'PRIMARY') {
|
||||
$definition['primary'] = true;
|
||||
} elseif (!$row['non_unique']) {
|
||||
$definition['unique'] = true;
|
||||
}
|
||||
$column_name = $row['column_name'];
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
if ($db->options['field_case'] == CASE_LOWER) {
|
||||
$column_name = strtolower($column_name);
|
||||
} else {
|
||||
$column_name = strtoupper($column_name);
|
||||
}
|
||||
}
|
||||
$definition['fields'][$column_name] = array(
|
||||
'position' => $colpos++
|
||||
);
|
||||
if (!empty($row['collation'])) {
|
||||
$definition['fields'][$column_name]['sorting'] = ($row['collation'] == 'A'
|
||||
? 'ascending' : 'descending');
|
||||
}
|
||||
}
|
||||
}
|
||||
$result->free();
|
||||
if (empty($definition['fields'])) {
|
||||
return $this->_getTableFKConstraintDefinition($table, $constraint_name_original, $definition);
|
||||
}
|
||||
return $definition;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _getTableFKConstraintDefinition()
|
||||
|
||||
/**
|
||||
* Get the FK definition from the CREATE TABLE statement
|
||||
*
|
||||
* @param string $table table name
|
||||
* @param string $constraint_name constraint name
|
||||
* @param array $definition default values for constraint definition
|
||||
*
|
||||
* @return array|PEAR_Error
|
||||
* @access private
|
||||
*/
|
||||
function _getTableFKConstraintDefinition($table, $constraint_name, $definition)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
//Use INFORMATION_SCHEMA instead?
|
||||
//SELECT *
|
||||
// FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS
|
||||
// WHERE CONSTRAINT_SCHEMA = '$dbname'
|
||||
// AND TABLE_NAME = '$table'
|
||||
// AND CONSTRAINT_NAME = '$constraint_name';
|
||||
$query = 'SHOW CREATE TABLE '. $db->escape($table);
|
||||
$constraint = $db->queryOne($query, 'text', 1);
|
||||
if (!MDB2::isError($constraint) && !empty($constraint)) {
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
if ($db->options['field_case'] == CASE_LOWER) {
|
||||
$constraint = strtolower($constraint);
|
||||
} else {
|
||||
$constraint = strtoupper($constraint);
|
||||
}
|
||||
}
|
||||
$constraint_name_original = $constraint_name;
|
||||
$constraint_name = $db->getIndexName($constraint_name);
|
||||
$pattern = '/\bCONSTRAINT\s+'.$constraint_name.'\s+FOREIGN KEY\s+\(([^\)]+)\) \bREFERENCES\b ([^\s]+) \(([^\)]+)\)(?: ON DELETE ([^\s]+))?(?: ON UPDATE ([^\s]+))?/i';
|
||||
if (!preg_match($pattern, str_replace('`', '', $constraint), $matches)) {
|
||||
//fallback to original constraint name
|
||||
$pattern = '/\bCONSTRAINT\s+'.$constraint_name_original.'\s+FOREIGN KEY\s+\(([^\)]+)\) \bREFERENCES\b ([^\s]+) \(([^\)]+)\)(?: ON DELETE ([^\s]+))?(?: ON UPDATE ([^\s]+))?/i';
|
||||
}
|
||||
if (preg_match($pattern, str_replace('`', '', $constraint), $matches)) {
|
||||
$definition['foreign'] = true;
|
||||
$column_names = explode(',', $matches[1]);
|
||||
$referenced_cols = explode(',', $matches[3]);
|
||||
$definition['references'] = array(
|
||||
'table' => $matches[2],
|
||||
'fields' => array(),
|
||||
);
|
||||
$colpos = 1;
|
||||
foreach ($column_names as $column_name) {
|
||||
$definition['fields'][trim($column_name)] = array(
|
||||
'position' => $colpos++
|
||||
);
|
||||
}
|
||||
$colpos = 1;
|
||||
foreach ($referenced_cols as $column_name) {
|
||||
$definition['references']['fields'][trim($column_name)] = array(
|
||||
'position' => $colpos++
|
||||
);
|
||||
}
|
||||
$definition['ondelete'] = empty($matches[4]) ? 'RESTRICT' : strtoupper($matches[4]);
|
||||
$definition['onupdate'] = empty($matches[5]) ? 'RESTRICT' : strtoupper($matches[5]);
|
||||
$definition['match'] = 'SIMPLE';
|
||||
return $definition;
|
||||
}
|
||||
}
|
||||
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
$constraint_name . ' is not an existing table constraint', __FUNCTION__);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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
|
||||
* @access public
|
||||
*/
|
||||
function getTriggerDefinition($trigger)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$query = 'SELECT trigger_name,
|
||||
event_object_table AS table_name,
|
||||
action_statement AS trigger_body,
|
||||
action_timing AS trigger_type,
|
||||
event_manipulation AS trigger_event
|
||||
FROM information_schema.triggers
|
||||
WHERE trigger_name = '. $db->quote($trigger, 'text');
|
||||
$types = array(
|
||||
'trigger_name' => 'text',
|
||||
'table_name' => 'text',
|
||||
'trigger_body' => 'text',
|
||||
'trigger_type' => 'text',
|
||||
'trigger_event' => 'text',
|
||||
);
|
||||
$def = $db->queryRow($query, $types, MDB2_FETCHMODE_ASSOC);
|
||||
if (MDB2::isError($def)) {
|
||||
return $def;
|
||||
}
|
||||
$def['trigger_comment'] = '';
|
||||
$def['trigger_enabled'] = true;
|
||||
return $def;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ tableInfo()
|
||||
|
||||
/**
|
||||
* Returns information about a table or a result set
|
||||
*
|
||||
* @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 a valid tableInfo mode
|
||||
*
|
||||
* @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)
|
||||
{
|
||||
if (is_string($result)) {
|
||||
return parent::tableInfo($result, $mode);
|
||||
}
|
||||
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$resource = MDB2::isResultCommon($result) ? $result->getResource() : $result;
|
||||
if (!is_object($resource)) {
|
||||
return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
|
||||
'Could not generate result resource', __FUNCTION__);
|
||||
}
|
||||
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
if ($db->options['field_case'] == CASE_LOWER) {
|
||||
$case_func = 'strtolower';
|
||||
} else {
|
||||
$case_func = 'strtoupper';
|
||||
}
|
||||
} else {
|
||||
$case_func = 'strval';
|
||||
}
|
||||
|
||||
$count = @mysqli_num_fields($resource);
|
||||
$res = array();
|
||||
if ($mode) {
|
||||
$res['num_fields'] = $count;
|
||||
}
|
||||
|
||||
$db->loadModule('Datatype', null, true);
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
$tmp = @mysqli_fetch_field($resource);
|
||||
|
||||
$flags = '';
|
||||
foreach ($this->flags as $const => $means) {
|
||||
if ($tmp->flags & $const) {
|
||||
$flags.= $means . ' ';
|
||||
}
|
||||
}
|
||||
if ($tmp->def) {
|
||||
$flags.= 'default_' . rawurlencode($tmp->def);
|
||||
}
|
||||
$flags = trim($flags);
|
||||
|
||||
$res[$i] = array(
|
||||
'table' => $case_func($tmp->table),
|
||||
'name' => $case_func($tmp->name),
|
||||
'type' => isset($this->types[$tmp->type])
|
||||
? $this->types[$tmp->type] : 'unknown',
|
||||
// http://bugs.php.net/?id=36579
|
||||
'length' => $tmp->length,
|
||||
'flags' => $flags,
|
||||
);
|
||||
$mdb2type_info = $db->datatype->mapNativeDatatype($res[$i]);
|
||||
if (MDB2::isError($mdb2type_info)) {
|
||||
return $mdb2type_info;
|
||||
}
|
||||
$res[$i]['mdb2type'] = $mdb2type_info[0][0];
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
}
|
||||
?>
|
621
extlib/MDB2/Driver/Reverse/oci8.php
Normal file
621
extlib/MDB2/Driver/Reverse/oci8.php
Normal file
@ -0,0 +1,621 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 and 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox, |
|
||||
// | Stig. S. Bakken, Lukas Smith, Frank M. Kromann, Lorenzo Alberton |
|
||||
// | 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Authors: Lukas Smith <smith@pooteeweet.org> |
|
||||
// | Lorenzo Alberton <l.alberton@quipo.it> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
|
||||
require_once 'MDB2/Driver/Reverse/Common.php';
|
||||
|
||||
/**
|
||||
* MDB2 Oracle driver for the schema reverse engineering module
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lukas Smith <smith@dybnet.de>
|
||||
*/
|
||||
class MDB2_Driver_Reverse_oci8 extends MDB2_Driver_Reverse_Common
|
||||
{
|
||||
// {{{ getTableFieldDefinition()
|
||||
|
||||
/**
|
||||
* Get the structure of a field into an array
|
||||
*
|
||||
* @param string $table_name name of table that should be used in method
|
||||
* @param string $field_name name of field that should be used in method
|
||||
* @return mixed data array on success, a MDB2 error on failure
|
||||
* @access public
|
||||
*/
|
||||
function getTableFieldDefinition($table_name, $field_name)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$result = $db->loadModule('Datatype', null, true);
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
list($owner, $table) = $this->splitTableSchema($table_name);
|
||||
if (empty($owner)) {
|
||||
$owner = $db->dsn['username'];
|
||||
}
|
||||
|
||||
$query = 'SELECT column_name name,
|
||||
data_type "type",
|
||||
nullable,
|
||||
data_default "default",
|
||||
COALESCE(data_precision, data_length) "length",
|
||||
data_scale "scale"
|
||||
FROM all_tab_columns
|
||||
WHERE (table_name=? OR table_name=?)
|
||||
AND (owner=? OR owner=?)
|
||||
AND (column_name=? OR column_name=?)
|
||||
ORDER BY column_id';
|
||||
$stmt = $db->prepare($query);
|
||||
if (MDB2::isError($stmt)) {
|
||||
return $stmt;
|
||||
}
|
||||
$args = array(
|
||||
$table,
|
||||
strtoupper($table),
|
||||
$owner,
|
||||
strtoupper($owner),
|
||||
$field_name,
|
||||
strtoupper($field_name)
|
||||
);
|
||||
$result = $stmt->execute($args);
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
$column = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
|
||||
if (MDB2::isError($column)) {
|
||||
return $column;
|
||||
}
|
||||
$stmt->free();
|
||||
$result->free();
|
||||
|
||||
if (empty($column)) {
|
||||
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
$field_name . ' is not a column in table ' . $table_name, __FUNCTION__);
|
||||
}
|
||||
|
||||
$column = array_change_key_case($column, CASE_LOWER);
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
if ($db->options['field_case'] == CASE_LOWER) {
|
||||
$column['name'] = strtolower($column['name']);
|
||||
} else {
|
||||
$column['name'] = strtoupper($column['name']);
|
||||
}
|
||||
}
|
||||
$mapped_datatype = $db->datatype->mapNativeDatatype($column);
|
||||
if (MDB2::isError($mapped_datatype)) {
|
||||
return $mapped_datatype;
|
||||
}
|
||||
list($types, $length, $unsigned, $fixed) = $mapped_datatype;
|
||||
$notnull = false;
|
||||
if (!empty($column['nullable']) && $column['nullable'] == 'N') {
|
||||
$notnull = true;
|
||||
}
|
||||
$default = false;
|
||||
if (array_key_exists('default', $column)) {
|
||||
$default = $column['default'];
|
||||
if ($default === 'NULL') {
|
||||
$default = null;
|
||||
}
|
||||
if ((null === $default) && $notnull) {
|
||||
$default = '';
|
||||
}
|
||||
}
|
||||
|
||||
$definition[0] = array('notnull' => $notnull, 'nativetype' => $column['type']);
|
||||
if (null !== $length) {
|
||||
$definition[0]['length'] = $length;
|
||||
}
|
||||
if (null !== $unsigned) {
|
||||
$definition[0]['unsigned'] = $unsigned;
|
||||
}
|
||||
if (null !== $fixed) {
|
||||
$definition[0]['fixed'] = $fixed;
|
||||
}
|
||||
if ($default !== false) {
|
||||
$definition[0]['default'] = $default;
|
||||
}
|
||||
foreach ($types as $key => $type) {
|
||||
$definition[$key] = $definition[0];
|
||||
if ($type == 'clob' || $type == 'blob') {
|
||||
unset($definition[$key]['default']);
|
||||
}
|
||||
$definition[$key]['type'] = $type;
|
||||
$definition[$key]['mdb2type'] = $type;
|
||||
}
|
||||
if ($type == 'integer') {
|
||||
$query= "SELECT trigger_body
|
||||
FROM all_triggers
|
||||
WHERE table_name=?
|
||||
AND triggering_event='INSERT'
|
||||
AND trigger_type='BEFORE EACH ROW'";
|
||||
// ^^ pretty reasonable mimic for "auto_increment" in oracle?
|
||||
$stmt = $db->prepare($query);
|
||||
if (MDB2::isError($stmt)) {
|
||||
return $stmt;
|
||||
}
|
||||
$result = $stmt->execute(strtoupper($table));
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
while ($triggerstr = $result->fetchOne()) {
|
||||
if (preg_match('/.*SELECT\W+(.+)\.nextval +into +\:NEW\.'.$field_name.' +FROM +dual/im', $triggerstr, $matches)) {
|
||||
$definition[0]['autoincrement'] = $matches[1];
|
||||
}
|
||||
}
|
||||
$stmt->free();
|
||||
$result->free();
|
||||
}
|
||||
return $definition;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ getTableIndexDefinition()
|
||||
|
||||
/**
|
||||
* Get the structure of an index into an array
|
||||
*
|
||||
* @param string $table_name name of table that should be used in method
|
||||
* @param string $index_name name of index that should be used in method
|
||||
* @return mixed data array on success, a MDB2 error on failure
|
||||
* @access public
|
||||
*/
|
||||
function getTableIndexDefinition($table_name, $index_name)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
list($owner, $table) = $this->splitTableSchema($table_name);
|
||||
if (empty($owner)) {
|
||||
$owner = $db->dsn['username'];
|
||||
}
|
||||
|
||||
$query = "SELECT aic.column_name,
|
||||
aic.column_position,
|
||||
aic.descend,
|
||||
aic.table_owner,
|
||||
alc.constraint_type
|
||||
FROM all_ind_columns aic
|
||||
LEFT JOIN all_constraints alc
|
||||
ON aic.index_name = alc.constraint_name
|
||||
AND aic.table_name = alc.table_name
|
||||
AND aic.table_owner = alc.owner
|
||||
WHERE (aic.table_name=? OR aic.table_name=?)
|
||||
AND (aic.index_name=? OR aic.index_name=?)
|
||||
AND (aic.table_owner=? OR aic.table_owner=?)
|
||||
ORDER BY column_position";
|
||||
$stmt = $db->prepare($query);
|
||||
if (MDB2::isError($stmt)) {
|
||||
return $stmt;
|
||||
}
|
||||
$indexnames = array_unique(array($db->getIndexName($index_name), $index_name));
|
||||
$i = 0;
|
||||
$row = null;
|
||||
while ((null === $row) && array_key_exists($i, $indexnames)) {
|
||||
$args = array(
|
||||
$table,
|
||||
strtoupper($table),
|
||||
$indexnames[$i],
|
||||
strtoupper($indexnames[$i]),
|
||||
$owner,
|
||||
strtoupper($owner)
|
||||
);
|
||||
$result = $stmt->execute($args);
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
$row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
|
||||
if (MDB2::isError($row)) {
|
||||
return $row;
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
if (null === $row) {
|
||||
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
$index_name. ' is not an index on table '. $table_name, __FUNCTION__);
|
||||
}
|
||||
if ($row['constraint_type'] == 'U' || $row['constraint_type'] == 'P') {
|
||||
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
$index_name. ' is a constraint, not an index on table '. $table_name, __FUNCTION__);
|
||||
}
|
||||
|
||||
$definition = array();
|
||||
while (null !== $row) {
|
||||
$row = array_change_key_case($row, CASE_LOWER);
|
||||
$column_name = $row['column_name'];
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
if ($db->options['field_case'] == CASE_LOWER) {
|
||||
$column_name = strtolower($column_name);
|
||||
} else {
|
||||
$column_name = strtoupper($column_name);
|
||||
}
|
||||
}
|
||||
$definition['fields'][$column_name] = array(
|
||||
'position' => (int)$row['column_position'],
|
||||
);
|
||||
if (!empty($row['descend'])) {
|
||||
$definition['fields'][$column_name]['sorting'] =
|
||||
($row['descend'] == 'ASC' ? 'ascending' : 'descending');
|
||||
}
|
||||
$row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
|
||||
}
|
||||
$result->free();
|
||||
if (empty($definition['fields'])) {
|
||||
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
$index_name. ' is not an index on table '. $table_name, __FUNCTION__);
|
||||
}
|
||||
return $definition;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ getTableConstraintDefinition()
|
||||
|
||||
/**
|
||||
* Get the structure of a constraint into an array
|
||||
*
|
||||
* @param string $table_name name of table that should be used in method
|
||||
* @param string $constraint_name name of constraint that should be used in method
|
||||
* @return mixed data array on success, a MDB2 error on failure
|
||||
* @access public
|
||||
*/
|
||||
function getTableConstraintDefinition($table_name, $constraint_name)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
list($owner, $table) = $this->splitTableSchema($table_name);
|
||||
if (empty($owner)) {
|
||||
$owner = $db->dsn['username'];
|
||||
}
|
||||
|
||||
$query = 'SELECT alc.constraint_name,
|
||||
CASE alc.constraint_type WHEN \'P\' THEN 1 ELSE 0 END "primary",
|
||||
CASE alc.constraint_type WHEN \'R\' THEN 1 ELSE 0 END "foreign",
|
||||
CASE alc.constraint_type WHEN \'U\' THEN 1 ELSE 0 END "unique",
|
||||
CASE alc.constraint_type WHEN \'C\' THEN 1 ELSE 0 END "check",
|
||||
alc.DELETE_RULE "ondelete",
|
||||
\'NO ACTION\' "onupdate",
|
||||
\'SIMPLE\' "match",
|
||||
CASE alc.deferrable WHEN \'NOT DEFERRABLE\' THEN 0 ELSE 1 END "deferrable",
|
||||
CASE alc.deferred WHEN \'IMMEDIATE\' THEN 0 ELSE 1 END "initiallydeferred",
|
||||
alc.search_condition,
|
||||
alc.table_name,
|
||||
cols.column_name,
|
||||
cols.position,
|
||||
r_alc.table_name "references_table",
|
||||
r_cols.column_name "references_field",
|
||||
r_cols.position "references_field_position"
|
||||
FROM all_cons_columns cols
|
||||
LEFT JOIN all_constraints alc
|
||||
ON alc.constraint_name = cols.constraint_name
|
||||
AND alc.owner = cols.owner
|
||||
LEFT JOIN all_constraints r_alc
|
||||
ON alc.r_constraint_name = r_alc.constraint_name
|
||||
AND alc.r_owner = r_alc.owner
|
||||
LEFT JOIN all_cons_columns r_cols
|
||||
ON r_alc.constraint_name = r_cols.constraint_name
|
||||
AND r_alc.owner = r_cols.owner
|
||||
AND cols.position = r_cols.position
|
||||
WHERE (alc.constraint_name=? OR alc.constraint_name=?)
|
||||
AND alc.constraint_name = cols.constraint_name
|
||||
AND (alc.owner=? OR alc.owner=?)';
|
||||
$tablenames = array();
|
||||
if (!empty($table)) {
|
||||
$query.= ' AND (alc.table_name=? OR alc.table_name=?)';
|
||||
$tablenames = array($table, strtoupper($table));
|
||||
}
|
||||
$stmt = $db->prepare($query);
|
||||
if (MDB2::isError($stmt)) {
|
||||
return $stmt;
|
||||
}
|
||||
|
||||
$constraintnames = array_unique(array($db->getIndexName($constraint_name), $constraint_name));
|
||||
$c = 0;
|
||||
$row = null;
|
||||
while ((null === $row) && array_key_exists($c, $constraintnames)) {
|
||||
$args = array(
|
||||
$constraintnames[$c],
|
||||
strtoupper($constraintnames[$c]),
|
||||
$owner,
|
||||
strtoupper($owner)
|
||||
);
|
||||
if (!empty($table)) {
|
||||
$args = array_merge($args, $tablenames);
|
||||
}
|
||||
$result = $stmt->execute($args);
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
$row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
|
||||
if (MDB2::isError($row)) {
|
||||
return $row;
|
||||
}
|
||||
$c++;
|
||||
}
|
||||
|
||||
$definition = array(
|
||||
'primary' => (boolean)$row['primary'],
|
||||
'unique' => (boolean)$row['unique'],
|
||||
'foreign' => (boolean)$row['foreign'],
|
||||
'check' => (boolean)$row['check'],
|
||||
'deferrable' => (boolean)$row['deferrable'],
|
||||
'initiallydeferred' => (boolean)$row['initiallydeferred'],
|
||||
'ondelete' => $row['ondelete'],
|
||||
'onupdate' => $row['onupdate'],
|
||||
'match' => $row['match'],
|
||||
);
|
||||
|
||||
if ($definition['check']) {
|
||||
// pattern match constraint for check constraint values into enum-style output:
|
||||
$enumregex = '/'.$row['column_name'].' in \((.+?)\)/i';
|
||||
if (preg_match($enumregex, $row['search_condition'], $rangestr)) {
|
||||
$definition['fields'][$column_name] = array();
|
||||
$allowed = explode(',', $rangestr[1]);
|
||||
foreach ($allowed as $val) {
|
||||
$val = trim($val);
|
||||
$val = preg_replace('/^\'/', '', $val);
|
||||
$val = preg_replace('/\'$/', '', $val);
|
||||
array_push($definition['fields'][$column_name], $val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (null !== $row) {
|
||||
$row = array_change_key_case($row, CASE_LOWER);
|
||||
$column_name = $row['column_name'];
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
if ($db->options['field_case'] == CASE_LOWER) {
|
||||
$column_name = strtolower($column_name);
|
||||
} else {
|
||||
$column_name = strtoupper($column_name);
|
||||
}
|
||||
}
|
||||
$definition['fields'][$column_name] = array(
|
||||
'position' => (int)$row['position']
|
||||
);
|
||||
if ($row['foreign']) {
|
||||
$ref_column_name = $row['references_field'];
|
||||
$ref_table_name = $row['references_table'];
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
if ($db->options['field_case'] == CASE_LOWER) {
|
||||
$ref_column_name = strtolower($ref_column_name);
|
||||
$ref_table_name = strtolower($ref_table_name);
|
||||
} else {
|
||||
$ref_column_name = strtoupper($ref_column_name);
|
||||
$ref_table_name = strtoupper($ref_table_name);
|
||||
}
|
||||
}
|
||||
$definition['references']['table'] = $ref_table_name;
|
||||
$definition['references']['fields'][$ref_column_name] = array(
|
||||
'position' => (int)$row['references_field_position']
|
||||
);
|
||||
}
|
||||
$lastrow = $row;
|
||||
$row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
|
||||
}
|
||||
$result->free();
|
||||
if (empty($definition['fields'])) {
|
||||
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
$constraint_name . ' is not a constraint on table '. $table_name, __FUNCTION__);
|
||||
}
|
||||
|
||||
return $definition;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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
|
||||
* @access public
|
||||
*/
|
||||
function getSequenceDefinition($sequence)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$sequence_name = $db->getSequenceName($sequence);
|
||||
$query = 'SELECT last_number FROM user_sequences';
|
||||
$query.= ' WHERE sequence_name='.$db->quote($sequence_name, 'text');
|
||||
$query.= ' OR sequence_name='.$db->quote(strtoupper($sequence_name), 'text');
|
||||
$start = $db->queryOne($query, 'integer');
|
||||
if (MDB2::isError($start)) {
|
||||
return $start;
|
||||
}
|
||||
$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
|
||||
* @access public
|
||||
*/
|
||||
function getTriggerDefinition($trigger)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$query = 'SELECT trigger_name,
|
||||
table_name,
|
||||
trigger_body,
|
||||
trigger_type,
|
||||
triggering_event trigger_event,
|
||||
description trigger_comment,
|
||||
1 trigger_enabled,
|
||||
when_clause
|
||||
FROM user_triggers
|
||||
WHERE trigger_name = \''. strtoupper($trigger).'\'';
|
||||
$types = array(
|
||||
'trigger_name' => 'text',
|
||||
'table_name' => 'text',
|
||||
'trigger_body' => 'text',
|
||||
'trigger_type' => 'text',
|
||||
'trigger_event' => 'text',
|
||||
'trigger_comment' => 'text',
|
||||
'trigger_enabled' => 'boolean',
|
||||
'when_clause' => 'text',
|
||||
);
|
||||
$result = $db->queryRow($query, $types, MDB2_FETCHMODE_ASSOC);
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
if (!empty($result['trigger_type'])) {
|
||||
//$result['trigger_type'] = array_shift(explode(' ', $result['trigger_type']));
|
||||
$result['trigger_type'] = preg_replace('/(\S+).*/', '\\1', $result['trigger_type']);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ tableInfo()
|
||||
|
||||
/**
|
||||
* Returns information about a table or a result set
|
||||
*
|
||||
* NOTE: only supports 'table' and 'flags' if <var>$result</var>
|
||||
* is a table name.
|
||||
*
|
||||
* NOTE: flags won't contain index information.
|
||||
*
|
||||
* @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 a valid tableInfo mode
|
||||
*
|
||||
* @return array an associative array with the information requested.
|
||||
* A MDB2_Error object on failure.
|
||||
*
|
||||
* @see MDB2_Driver_Common::tableInfo()
|
||||
*/
|
||||
function tableInfo($result, $mode = null)
|
||||
{
|
||||
if (is_string($result)) {
|
||||
return parent::tableInfo($result, $mode);
|
||||
}
|
||||
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$resource = MDB2::isResultCommon($result) ? $result->getResource() : $result;
|
||||
if (!is_resource($resource)) {
|
||||
return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
|
||||
'Could not generate result resource', __FUNCTION__);
|
||||
}
|
||||
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
if ($db->options['field_case'] == CASE_LOWER) {
|
||||
$case_func = 'strtolower';
|
||||
} else {
|
||||
$case_func = 'strtoupper';
|
||||
}
|
||||
} else {
|
||||
$case_func = 'strval';
|
||||
}
|
||||
|
||||
$count = @OCINumCols($resource);
|
||||
$res = array();
|
||||
|
||||
if ($mode) {
|
||||
$res['num_fields'] = $count;
|
||||
}
|
||||
|
||||
$db->loadModule('Datatype', null, true);
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
$column = array(
|
||||
'table' => '',
|
||||
'name' => $case_func(@OCIColumnName($resource, $i+1)),
|
||||
'type' => @OCIColumnType($resource, $i+1),
|
||||
'length' => @OCIColumnSize($resource, $i+1),
|
||||
'flags' => '',
|
||||
);
|
||||
$res[$i] = $column;
|
||||
$res[$i]['mdb2type'] = $db->datatype->mapNativeDatatype($res[$i]);
|
||||
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;
|
||||
}
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
}
|
||||
?>
|
631
extlib/MDB2/Driver/Reverse/odbc.php
Normal file
631
extlib/MDB2/Driver/Reverse/odbc.php
Normal file
@ -0,0 +1,631 @@
|
||||
<?php
|
||||
|
||||
|
||||
require_once 'MDB2/Driver/Reverse/Common.php';
|
||||
|
||||
/**
|
||||
* MDB2 MSSQL driver for the schema reverse engineering module
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lukas Smith <smith@dybnet.de>
|
||||
* @author Lorenzo Alberton <l.alberton@quipo.it>
|
||||
*/
|
||||
class MDB2_Driver_Reverse_odbc extends MDB2_Driver_Reverse_Common
|
||||
{
|
||||
// {{{ getTableFieldDefinition()
|
||||
|
||||
/**
|
||||
* Get the structure of a field into an array
|
||||
*
|
||||
* @param string $table_name name of table that should be used in method
|
||||
* @param string $field_name name of field that should be used in method
|
||||
* @return mixed data array on success, a MDB2 error on failure
|
||||
* @access public
|
||||
*/
|
||||
function getTableFieldDefinition($table_name, $field_name)
|
||||
{
|
||||
$db =& $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$result = $db->loadModule('Datatype', null, true);
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
list($schema, $table) = $this->splitTableSchema($table_name);
|
||||
|
||||
$table = $db->quoteIdentifier($table, true);
|
||||
$fldname = $db->quoteIdentifier($field_name, true);
|
||||
|
||||
$res = odbc_columns($db->connection,"%","%",$table);
|
||||
$column = array();
|
||||
while($data = odbc_fetch_array($res)) {
|
||||
|
||||
if(strcasecmp($field_name,$data['COLUMN_NAME'])) {
|
||||
$column['table_name'] = $data['TABLE_NAME'];
|
||||
$column['name'] = $data['COLUMN_NAME'];
|
||||
$column['type'] = $data['TYPE_NAME'];
|
||||
if($data['IS_NULLABLE'] == "YES") {
|
||||
$column['is_nullable'] = 1;
|
||||
} else {
|
||||
$column['is_nullable'] = 0;
|
||||
}
|
||||
$column['column_default'] = $data['COLUMN_DEF'];
|
||||
$column['length'] = $data['COLUMNZ_SIZE'];
|
||||
$column['numeric_precision'] = $data['NUM_PREC_RADIX'];
|
||||
$column['numeric_scale'] = $data['DECIMAL_DIGITS'];
|
||||
$column['collation_name'] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
$query = "SELECT t.table_name,
|
||||
c.column_name 'name',
|
||||
c.data_type 'type',
|
||||
CASE c.is_nullable WHEN 'YES' THEN 1 ELSE 0 END AS 'is_nullable',
|
||||
c.column_default,
|
||||
c.character_maximum_length 'length',
|
||||
c.numeric_precision,
|
||||
c.numeric_scale,
|
||||
c.character_set_name,
|
||||
c.collation_name
|
||||
FROM INFORMATION_SCHEMA.TABLES t,
|
||||
INFORMATION_SCHEMA.COLUMNS c
|
||||
WHERE t.table_name = c.table_name
|
||||
AND t.table_name = '$table'
|
||||
AND c.column_name = '$fldname'";
|
||||
if (!empty($schema)) {
|
||||
$query .= " AND t.table_schema = '" .$db->quoteIdentifier($schema, true) ."'";
|
||||
}
|
||||
$query .= ' ORDER BY t.table_name';
|
||||
$column = $db->queryRow($query, null, MDB2_FETCHMODE_ASSOC);
|
||||
if (MDB2::isError($column)) {
|
||||
return $column;
|
||||
}
|
||||
*/
|
||||
if (empty($column)) {
|
||||
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
'it was not specified an existing table column', __FUNCTION__);
|
||||
}
|
||||
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
if ($db->options['field_case'] == CASE_LOWER) {
|
||||
$column['name'] = strtolower($column['name']);
|
||||
} else {
|
||||
$column['name'] = strtoupper($column['name']);
|
||||
}
|
||||
} else {
|
||||
$column = array_change_key_case($column, $db->options['field_case']);
|
||||
}
|
||||
$mapped_datatype = $db->datatype->mapNativeDatatype($column);
|
||||
if (MDB2::isError($mapped_datatype)) {
|
||||
return $mapped_datatype;
|
||||
}
|
||||
list($types, $length, $unsigned, $fixed) = $mapped_datatype;
|
||||
$notnull = true;
|
||||
if ($column['is_nullable']) {
|
||||
$notnull = false;
|
||||
}
|
||||
$default = false;
|
||||
if (array_key_exists('column_default', $column)) {
|
||||
$default = $column['column_default'];
|
||||
if (is_null($default) && $notnull) {
|
||||
$default = '';
|
||||
} elseif (strlen($default) > 4
|
||||
&& substr($default, 0, 1) == '('
|
||||
&& substr($default, -1, 1) == ')'
|
||||
) {
|
||||
//mssql wraps the default value in parentheses: "((1234))", "(NULL)"
|
||||
$default = trim($default, '()');
|
||||
if ($default == 'NULL') {
|
||||
$default = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
$definition[0] = array(
|
||||
'notnull' => $notnull,
|
||||
'nativetype' => preg_replace('/^([a-z]+)[^a-z].*/i', '\\1', $column['type'])
|
||||
);
|
||||
if (!is_null($length)) {
|
||||
$definition[0]['length'] = $length;
|
||||
}
|
||||
if (!is_null($unsigned)) {
|
||||
$definition[0]['unsigned'] = $unsigned;
|
||||
}
|
||||
if (!is_null($fixed)) {
|
||||
$definition[0]['fixed'] = $fixed;
|
||||
}
|
||||
if ($default !== false) {
|
||||
$definition[0]['default'] = $default;
|
||||
}
|
||||
foreach ($types as $key => $type) {
|
||||
$definition[$key] = $definition[0];
|
||||
if ($type == 'clob' || $type == 'blob') {
|
||||
unset($definition[$key]['default']);
|
||||
}
|
||||
$definition[$key]['type'] = $type;
|
||||
$definition[$key]['mdb2type'] = $type;
|
||||
}
|
||||
return $definition;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ getTableIndexDefinition()
|
||||
|
||||
/**
|
||||
* Get the structure of an index into an array
|
||||
*
|
||||
* @param string $table_name name of table that should be used in method
|
||||
* @param string $index_name name of index that should be used in method
|
||||
* @return mixed data array on success, a MDB2 error on failure
|
||||
* @access public
|
||||
*/
|
||||
function getTableIndexDefinition($table_name, $index_name)
|
||||
{
|
||||
$db =& $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
list($schema, $table) = $this->splitTableSchema($table_name);
|
||||
|
||||
$table = $db->quoteIdentifier($table, true);
|
||||
//$idxname = $db->quoteIdentifier($index_name, true);
|
||||
|
||||
$query = "SELECT OBJECT_NAME(i.id) tablename,
|
||||
i.name indexname,
|
||||
c.name field_name,
|
||||
CASE INDEXKEY_PROPERTY(i.id, i.indid, ik.keyno, 'IsDescending')
|
||||
WHEN 1 THEN 'DESC' ELSE 'ASC'
|
||||
END 'collation',
|
||||
ik.keyno 'position'
|
||||
FROM sysindexes i
|
||||
JOIN sysindexkeys ik ON ik.id = i.id AND ik.indid = i.indid
|
||||
JOIN syscolumns c ON c.id = ik.id AND c.colid = ik.colid
|
||||
WHERE OBJECT_NAME(i.id) = '$table'
|
||||
AND i.name = '%s'
|
||||
AND NOT EXISTS (
|
||||
SELECT *
|
||||
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE k
|
||||
WHERE k.table_name = OBJECT_NAME(i.id)
|
||||
AND k.constraint_name = i.name";
|
||||
if (!empty($schema)) {
|
||||
$query .= " AND k.table_schema = '" .$db->quoteIdentifier($schema, true) ."'";
|
||||
}
|
||||
$query .= ')
|
||||
ORDER BY tablename, indexname, ik.keyno';
|
||||
|
||||
$index_name_mdb2 = $db->getIndexName($index_name);
|
||||
$result = $db->queryRow(sprintf($query, $index_name_mdb2));
|
||||
if (!MDB2::isError($result) && !is_null($result)) {
|
||||
// apply 'idxname_format' only if the query succeeded, otherwise
|
||||
// fallback to the given $index_name, without transformation
|
||||
$index_name = $index_name_mdb2;
|
||||
}
|
||||
$result = $db->query(sprintf($query, $index_name));
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$definition = array();
|
||||
while (is_array($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))) {
|
||||
$column_name = $row['field_name'];
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
if ($db->options['field_case'] == CASE_LOWER) {
|
||||
$column_name = strtolower($column_name);
|
||||
} else {
|
||||
$column_name = strtoupper($column_name);
|
||||
}
|
||||
}
|
||||
$definition['fields'][$column_name] = array(
|
||||
'position' => (int)$row['position'],
|
||||
);
|
||||
if (!empty($row['collation'])) {
|
||||
$definition['fields'][$column_name]['sorting'] = ($row['collation'] == 'ASC'
|
||||
? 'ascending' : 'descending');
|
||||
}
|
||||
}
|
||||
$result->free();
|
||||
if (empty($definition['fields'])) {
|
||||
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
'it was not specified an existing table index', __FUNCTION__);
|
||||
}
|
||||
return $definition;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ getTableConstraintDefinition()
|
||||
|
||||
/**
|
||||
* Get the structure of a constraint into an array
|
||||
*
|
||||
* @param string $table_name name of table that should be used in method
|
||||
* @param string $constraint_name name of constraint that should be used in method
|
||||
* @return mixed data array on success, a MDB2 error on failure
|
||||
* @access public
|
||||
*/
|
||||
function getTableConstraintDefinition($table_name, $constraint_name)
|
||||
{
|
||||
$db =& $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
list($schema, $table) = $this->splitTableSchema($table_name);
|
||||
|
||||
$table = $db->quoteIdentifier($table, true);
|
||||
$query = "SELECT k.table_name,
|
||||
k.column_name field_name,
|
||||
CASE c.constraint_type WHEN 'PRIMARY KEY' THEN 1 ELSE 0 END 'primary',
|
||||
CASE c.constraint_type WHEN 'UNIQUE' THEN 1 ELSE 0 END 'unique',
|
||||
CASE c.constraint_type WHEN 'FOREIGN KEY' THEN 1 ELSE 0 END 'foreign',
|
||||
CASE c.constraint_type WHEN 'CHECK' THEN 1 ELSE 0 END 'check',
|
||||
CASE c.is_deferrable WHEN 'NO' THEN 0 ELSE 1 END 'deferrable',
|
||||
CASE c.initially_deferred WHEN 'NO' THEN 0 ELSE 1 END 'initiallydeferred',
|
||||
rc.match_option 'match',
|
||||
rc.update_rule 'onupdate',
|
||||
rc.delete_rule 'ondelete',
|
||||
kcu.table_name 'references_table',
|
||||
kcu.column_name 'references_field',
|
||||
k.ordinal_position 'field_position'
|
||||
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE k
|
||||
LEFT JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS c
|
||||
ON k.table_name = c.table_name
|
||||
AND k.table_schema = c.table_schema
|
||||
AND k.table_catalog = c.table_catalog
|
||||
AND k.constraint_catalog = c.constraint_catalog
|
||||
AND k.constraint_name = c.constraint_name
|
||||
LEFT JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc
|
||||
ON rc.constraint_schema = c.constraint_schema
|
||||
AND rc.constraint_catalog = c.constraint_catalog
|
||||
AND rc.constraint_name = c.constraint_name
|
||||
LEFT JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu
|
||||
ON rc.unique_constraint_schema = kcu.constraint_schema
|
||||
AND rc.unique_constraint_catalog = kcu.constraint_catalog
|
||||
AND rc.unique_constraint_name = kcu.constraint_name
|
||||
AND k.ordinal_position = kcu.ordinal_position
|
||||
WHERE k.constraint_catalog = DB_NAME()
|
||||
AND k.table_name = '$table'
|
||||
AND k.constraint_name = '%s'";
|
||||
if (!empty($schema)) {
|
||||
$query .= " AND k.table_schema = '" .$db->quoteIdentifier($schema, true) ."'";
|
||||
}
|
||||
$query .= ' ORDER BY k.constraint_name,
|
||||
k.ordinal_position';
|
||||
|
||||
$constraint_name_mdb2 = $db->getIndexName($constraint_name);
|
||||
$result = $db->queryRow(sprintf($query, $constraint_name_mdb2));
|
||||
if (!MDB2::isError($result) && !is_null($result)) {
|
||||
// apply 'idxname_format' only if the query succeeded, otherwise
|
||||
// fallback to the given $index_name, without transformation
|
||||
$constraint_name = $constraint_name_mdb2;
|
||||
}
|
||||
$result = $db->query(sprintf($query, $constraint_name));
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$definition = array(
|
||||
'fields' => array()
|
||||
);
|
||||
while (is_array($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))) {
|
||||
$row = array_change_key_case($row, CASE_LOWER);
|
||||
$column_name = $row['field_name'];
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
if ($db->options['field_case'] == CASE_LOWER) {
|
||||
$column_name = strtolower($column_name);
|
||||
} else {
|
||||
$column_name = strtoupper($column_name);
|
||||
}
|
||||
}
|
||||
$definition['fields'][$column_name] = array(
|
||||
'position' => (int)$row['field_position']
|
||||
);
|
||||
if ($row['foreign']) {
|
||||
$ref_column_name = $row['references_field'];
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
if ($db->options['field_case'] == CASE_LOWER) {
|
||||
$ref_column_name = strtolower($ref_column_name);
|
||||
} else {
|
||||
$ref_column_name = strtoupper($ref_column_name);
|
||||
}
|
||||
}
|
||||
$definition['references']['table'] = $row['references_table'];
|
||||
$definition['references']['fields'][$ref_column_name] = array(
|
||||
'position' => (int)$row['field_position']
|
||||
);
|
||||
}
|
||||
//collation?!?
|
||||
/*
|
||||
if (!empty($row['collation'])) {
|
||||
$definition['fields'][$column_name]['sorting'] = ($row['collation'] == 'ASC'
|
||||
? 'ascending' : 'descending');
|
||||
}
|
||||
*/
|
||||
$lastrow = $row;
|
||||
// otherwise $row is no longer usable on exit from loop
|
||||
}
|
||||
$result->free();
|
||||
if (empty($definition['fields'])) {
|
||||
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
$constraint_name . ' is not an existing table constraint', __FUNCTION__);
|
||||
}
|
||||
|
||||
$definition['primary'] = (boolean)$lastrow['primary'];
|
||||
$definition['unique'] = (boolean)$lastrow['unique'];
|
||||
$definition['foreign'] = (boolean)$lastrow['foreign'];
|
||||
$definition['check'] = (boolean)$lastrow['check'];
|
||||
$definition['deferrable'] = (boolean)$lastrow['deferrable'];
|
||||
$definition['initiallydeferred'] = (boolean)$lastrow['initiallydeferred'];
|
||||
$definition['onupdate'] = $lastrow['onupdate'];
|
||||
$definition['ondelete'] = $lastrow['ondelete'];
|
||||
$definition['match'] = $lastrow['match'];
|
||||
|
||||
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
|
||||
* @access public
|
||||
*/
|
||||
function getTriggerDefinition($trigger)
|
||||
{
|
||||
$db =& $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$query = "SELECT sys1.name trigger_name,
|
||||
sys2.name table_name,
|
||||
c.text trigger_body,
|
||||
c.encrypted is_encripted,
|
||||
CASE
|
||||
WHEN OBJECTPROPERTY(sys1.id, 'ExecIsTriggerDisabled') = 1
|
||||
THEN 0 ELSE 1
|
||||
END trigger_enabled,
|
||||
CASE
|
||||
WHEN OBJECTPROPERTY(sys1.id, 'ExecIsInsertTrigger') = 1
|
||||
THEN 'INSERT'
|
||||
WHEN OBJECTPROPERTY(sys1.id, 'ExecIsUpdateTrigger') = 1
|
||||
THEN 'UPDATE'
|
||||
WHEN OBJECTPROPERTY(sys1.id, 'ExecIsDeleteTrigger') = 1
|
||||
THEN 'DELETE'
|
||||
END trigger_event,
|
||||
CASE WHEN OBJECTPROPERTY(sys1.id, 'ExecIsInsteadOfTrigger') = 1
|
||||
THEN 'INSTEAD OF' ELSE 'AFTER'
|
||||
END trigger_type,
|
||||
'' trigger_comment
|
||||
FROM sysobjects sys1
|
||||
JOIN sysobjects sys2 ON sys1.parent_obj = sys2.id
|
||||
JOIN syscomments c ON sys1.id = c.id
|
||||
WHERE sys1.xtype = 'TR'
|
||||
AND sys1.name = ". $db->quote($trigger, 'text');
|
||||
|
||||
$types = array(
|
||||
'trigger_name' => 'text',
|
||||
'table_name' => 'text',
|
||||
'trigger_body' => 'text',
|
||||
'trigger_type' => 'text',
|
||||
'trigger_event' => 'text',
|
||||
'trigger_comment' => 'text',
|
||||
'trigger_enabled' => 'boolean',
|
||||
'is_encripted' => 'boolean',
|
||||
);
|
||||
|
||||
$def = $db->queryRow($query, $types, MDB2_FETCHMODE_ASSOC);
|
||||
if (MDB2::isError($def)) {
|
||||
return $def;
|
||||
}
|
||||
$trg_body = $db->queryCol('EXEC sp_helptext '. $db->quote($trigger, 'text'), 'text');
|
||||
if (!MDB2::isError($trg_body)) {
|
||||
$def['trigger_body'] = implode(' ', $trg_body);
|
||||
}
|
||||
return $def;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ tableInfo()
|
||||
|
||||
/**
|
||||
* Returns information about a table or a result set
|
||||
*
|
||||
* NOTE: only supports 'table' and 'flags' if <var>$result</var>
|
||||
* is a table name.
|
||||
*
|
||||
* @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 a valid tableInfo mode
|
||||
*
|
||||
* @return array an associative array with the information requested.
|
||||
* A MDB2_Error object on failure.
|
||||
*
|
||||
* @see MDB2_Driver_Common::tableInfo()
|
||||
*/
|
||||
function tableInfo($result, $mode = null)
|
||||
{
|
||||
if (is_string($result)) {
|
||||
return parent::tableInfo($result, $mode);
|
||||
}
|
||||
|
||||
$db =& $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$resource = MDB2::isResultCommon($result) ? $result->getResource() : $result;
|
||||
if (!is_resource($resource)) {
|
||||
return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
|
||||
'Could not generate result resource', __FUNCTION__);
|
||||
}
|
||||
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
if ($db->options['field_case'] == CASE_LOWER) {
|
||||
$case_func = 'strtolower';
|
||||
} else {
|
||||
$case_func = 'strtoupper';
|
||||
}
|
||||
} else {
|
||||
$case_func = 'strval';
|
||||
}
|
||||
|
||||
$count = @mssql_num_fields($resource);
|
||||
$res = array();
|
||||
|
||||
if ($mode) {
|
||||
$res['num_fields'] = $count;
|
||||
}
|
||||
|
||||
$db->loadModule('Datatype', null, true);
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
$res[$i] = array(
|
||||
'table' => '',
|
||||
'name' => $case_func(@mssql_field_name($resource, $i)),
|
||||
'type' => @mssql_field_type($resource, $i),
|
||||
'length' => @mssql_field_length($resource, $i),
|
||||
'flags' => '',
|
||||
);
|
||||
$mdb2type_info = $db->datatype->mapNativeDatatype($res[$i]);
|
||||
if (MDB2::isError($mdb2type_info)) {
|
||||
return $mdb2type_info;
|
||||
}
|
||||
$res[$i]['mdb2type'] = $mdb2type_info[0][0];
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _mssql_field_flags()
|
||||
|
||||
/**
|
||||
* Get a column's flags
|
||||
*
|
||||
* Supports "not_null", "primary_key",
|
||||
* "auto_increment" (mssql identity), "timestamp" (mssql timestamp),
|
||||
* "unique_key" (mssql unique index, unique check or primary_key) and
|
||||
* "multiple_key" (multikey index)
|
||||
*
|
||||
* mssql timestamp is NOT similar to the mysql timestamp so this is maybe
|
||||
* not useful at all - is the behaviour of mysql_field_flags that primary
|
||||
* keys are alway unique? is the interpretation of multiple_key correct?
|
||||
*
|
||||
* @param string $table the table name
|
||||
* @param string $column the field name
|
||||
*
|
||||
* @return string the flags
|
||||
*
|
||||
* @access protected
|
||||
* @author Joern Barthel <j_barthel@web.de>
|
||||
*/
|
||||
function _mssql_field_flags($table, $column)
|
||||
{
|
||||
$db =& $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
static $tableName = null;
|
||||
static $flags = array();
|
||||
|
||||
if ($table != $tableName) {
|
||||
|
||||
$flags = array();
|
||||
$tableName = $table;
|
||||
|
||||
// get unique and primary keys
|
||||
$res = $db->queryAll("EXEC SP_HELPINDEX[$table]", null, MDB2_FETCHMODE_ASSOC);
|
||||
|
||||
foreach ($res as $val) {
|
||||
$val = array_change_key_case($val, CASE_LOWER);
|
||||
$keys = explode(', ', $val['index_keys']);
|
||||
|
||||
if (sizeof($keys) > 1) {
|
||||
foreach ($keys as $key) {
|
||||
$this->_add_flag($flags[$key], 'multiple_key');
|
||||
}
|
||||
}
|
||||
|
||||
if (strpos($val['index_description'], 'primary key')) {
|
||||
foreach ($keys as $key) {
|
||||
$this->_add_flag($flags[$key], 'primary_key');
|
||||
}
|
||||
} elseif (strpos($val['index_description'], 'unique')) {
|
||||
foreach ($keys as $key) {
|
||||
$this->_add_flag($flags[$key], 'unique_key');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get auto_increment, not_null and timestamp
|
||||
$res = $db->queryAll("EXEC SP_COLUMNS[$table]", null, MDB2_FETCHMODE_ASSOC);
|
||||
|
||||
foreach ($res as $val) {
|
||||
$val = array_change_key_case($val, CASE_LOWER);
|
||||
if ($val['nullable'] == '0') {
|
||||
$this->_add_flag($flags[$val['column_name']], 'not_null');
|
||||
}
|
||||
if (strpos($val['type_name'], 'identity')) {
|
||||
$this->_add_flag($flags[$val['column_name']], 'auto_increment');
|
||||
}
|
||||
if (strpos($val['type_name'], 'timestamp')) {
|
||||
$this->_add_flag($flags[$val['column_name']], 'timestamp');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($flags[$column])) {
|
||||
return(implode(' ', $flags[$column]));
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _add_flag()
|
||||
|
||||
/**
|
||||
* Adds a string to the flags array if the flag is not yet in there
|
||||
* - if there is no flag present the array is created
|
||||
*
|
||||
* @param array &$array the reference to the flag-array
|
||||
* @param string $value the flag value
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @access protected
|
||||
* @author Joern Barthel <j_barthel@web.de>
|
||||
*/
|
||||
function _add_flag(&$array, $value)
|
||||
{
|
||||
if (!is_array($array)) {
|
||||
$array = array($value);
|
||||
} elseif (!in_array($value, $array)) {
|
||||
array_push($array, $value);
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
}
|
||||
?>
|
574
extlib/MDB2/Driver/Reverse/pgsql.php
Normal file
574
extlib/MDB2/Driver/Reverse/pgsql.php
Normal file
@ -0,0 +1,574 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 and 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Copyright (c) 1998-2008 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Authors: Paul Cooper <pgc@ucecom.com> |
|
||||
// | Lorenzo Alberton <l.alberton@quipo.it> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id$
|
||||
|
||||
require_once 'MDB2/Driver/Reverse/Common.php';
|
||||
|
||||
/**
|
||||
* MDB2 PostGreSQL driver for the schema reverse engineering module
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Paul Cooper <pgc@ucecom.com>
|
||||
* @author Lorenzo Alberton <l.alberton@quipo.it>
|
||||
*/
|
||||
class MDB2_Driver_Reverse_pgsql extends MDB2_Driver_Reverse_Common
|
||||
{
|
||||
// {{{ getTableFieldDefinition()
|
||||
|
||||
/**
|
||||
* Get the structure of a field into an array
|
||||
*
|
||||
* @param string $table_name name of table that should be used in method
|
||||
* @param string $field_name name of field that should be used in method
|
||||
* @return mixed data array on success, a MDB2 error on failure
|
||||
* @access public
|
||||
*/
|
||||
function getTableFieldDefinition($table_name, $field_name)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$result = $db->loadModule('Datatype', null, true);
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
list($schema, $table) = $this->splitTableSchema($table_name);
|
||||
|
||||
$query = "SELECT a.attname AS name,
|
||||
t.typname AS type,
|
||||
CASE a.attlen
|
||||
WHEN -1 THEN
|
||||
CASE t.typname
|
||||
WHEN 'numeric' THEN (a.atttypmod / 65536)
|
||||
WHEN 'decimal' THEN (a.atttypmod / 65536)
|
||||
WHEN 'money' THEN (a.atttypmod / 65536)
|
||||
ELSE CASE a.atttypmod
|
||||
WHEN -1 THEN NULL
|
||||
ELSE a.atttypmod - 4
|
||||
END
|
||||
END
|
||||
ELSE a.attlen
|
||||
END AS length,
|
||||
CASE t.typname
|
||||
WHEN 'numeric' THEN (a.atttypmod % 65536) - 4
|
||||
WHEN 'decimal' THEN (a.atttypmod % 65536) - 4
|
||||
WHEN 'money' THEN (a.atttypmod % 65536) - 4
|
||||
ELSE 0
|
||||
END AS scale,
|
||||
a.attnotnull,
|
||||
a.atttypmod,
|
||||
a.atthasdef,
|
||||
(SELECT substring(pg_get_expr(d.adbin, d.adrelid) for 128)
|
||||
FROM pg_attrdef d
|
||||
WHERE d.adrelid = a.attrelid
|
||||
AND d.adnum = a.attnum
|
||||
AND a.atthasdef
|
||||
) as default
|
||||
FROM pg_attribute a,
|
||||
pg_class c,
|
||||
pg_type t
|
||||
WHERE c.relname = ".$db->quote($table, 'text')."
|
||||
AND a.atttypid = t.oid
|
||||
AND c.oid = a.attrelid
|
||||
AND NOT a.attisdropped
|
||||
AND a.attnum > 0
|
||||
AND a.attname = ".$db->quote($field_name, 'text')."
|
||||
ORDER BY a.attnum";
|
||||
$column = $db->queryRow($query, null, MDB2_FETCHMODE_ASSOC);
|
||||
if (MDB2::isError($column)) {
|
||||
return $column;
|
||||
}
|
||||
|
||||
if (empty($column)) {
|
||||
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
'it was not specified an existing table column', __FUNCTION__);
|
||||
}
|
||||
|
||||
$column = array_change_key_case($column, CASE_LOWER);
|
||||
$mapped_datatype = $db->datatype->mapNativeDatatype($column);
|
||||
if (MDB2::isError($mapped_datatype)) {
|
||||
return $mapped_datatype;
|
||||
}
|
||||
list($types, $length, $unsigned, $fixed) = $mapped_datatype;
|
||||
$notnull = false;
|
||||
if (!empty($column['attnotnull']) && $column['attnotnull'] == 't') {
|
||||
$notnull = true;
|
||||
}
|
||||
$default = null;
|
||||
if ($column['atthasdef'] === 't'
|
||||
&& strpos($column['default'], 'NULL') !== 0
|
||||
&& !preg_match("/nextval\('([^']+)'/", $column['default'])
|
||||
) {
|
||||
$pattern = '/^\'(.*)\'::[\w ]+$/i';
|
||||
$default = $column['default'];#substr($column['adsrc'], 1, -1);
|
||||
if ((null === $default) && $notnull) {
|
||||
$default = '';
|
||||
} elseif (!empty($default) && preg_match($pattern, $default)) {
|
||||
//remove data type cast
|
||||
$default = preg_replace ($pattern, '\\1', $default);
|
||||
}
|
||||
}
|
||||
$autoincrement = false;
|
||||
if (preg_match("/nextval\('([^']+)'/", $column['default'], $nextvals)) {
|
||||
$autoincrement = true;
|
||||
}
|
||||
$definition[0] = array('notnull' => $notnull, 'nativetype' => $column['type']);
|
||||
if (null !== $length) {
|
||||
$definition[0]['length'] = $length;
|
||||
}
|
||||
if (null !== $unsigned) {
|
||||
$definition[0]['unsigned'] = $unsigned;
|
||||
}
|
||||
if (null !== $fixed) {
|
||||
$definition[0]['fixed'] = $fixed;
|
||||
}
|
||||
if ($default !== false) {
|
||||
$definition[0]['default'] = $default;
|
||||
}
|
||||
if ($autoincrement !== false) {
|
||||
$definition[0]['autoincrement'] = $autoincrement;
|
||||
}
|
||||
foreach ($types as $key => $type) {
|
||||
$definition[$key] = $definition[0];
|
||||
if ($type == 'clob' || $type == 'blob') {
|
||||
unset($definition[$key]['default']);
|
||||
}
|
||||
$definition[$key]['type'] = $type;
|
||||
$definition[$key]['mdb2type'] = $type;
|
||||
}
|
||||
return $definition;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ getTableIndexDefinition()
|
||||
|
||||
/**
|
||||
* Get the structure of an index into an array
|
||||
*
|
||||
* @param string $table_name name of table that should be used in method
|
||||
* @param string $index_name name of index that should be used in method
|
||||
* @return mixed data array on success, a MDB2 error on failure
|
||||
* @access public
|
||||
*/
|
||||
function getTableIndexDefinition($table_name, $index_name)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
list($schema, $table) = $this->splitTableSchema($table_name);
|
||||
|
||||
$query = 'SELECT relname, indkey FROM pg_index, pg_class';
|
||||
$query.= ' WHERE pg_class.oid = pg_index.indexrelid';
|
||||
$query.= " AND indisunique != 't' AND indisprimary != 't'";
|
||||
$query.= ' AND pg_class.relname = %s';
|
||||
$index_name_mdb2 = $db->getIndexName($index_name);
|
||||
$row = $db->queryRow(sprintf($query, $db->quote($index_name_mdb2, 'text')), null, MDB2_FETCHMODE_ASSOC);
|
||||
if (MDB2::isError($row) || empty($row)) {
|
||||
// fallback to the given $index_name, without transformation
|
||||
$row = $db->queryRow(sprintf($query, $db->quote($index_name, 'text')), null, MDB2_FETCHMODE_ASSOC);
|
||||
}
|
||||
if (MDB2::isError($row)) {
|
||||
return $row;
|
||||
}
|
||||
|
||||
if (empty($row)) {
|
||||
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
'it was not specified an existing table index', __FUNCTION__);
|
||||
}
|
||||
|
||||
$row = array_change_key_case($row, CASE_LOWER);
|
||||
|
||||
$db->loadModule('Manager', null, true);
|
||||
$columns = $db->manager->listTableFields($table_name);
|
||||
|
||||
$definition = array();
|
||||
|
||||
$index_column_numbers = explode(' ', $row['indkey']);
|
||||
|
||||
$colpos = 1;
|
||||
foreach ($index_column_numbers as $number) {
|
||||
$definition['fields'][$columns[($number - 1)]] = array(
|
||||
'position' => $colpos++,
|
||||
'sorting' => 'ascending',
|
||||
);
|
||||
}
|
||||
return $definition;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ getTableConstraintDefinition()
|
||||
|
||||
/**
|
||||
* Get the structure of a constraint into an array
|
||||
*
|
||||
* @param string $table_name name of table that should be used in method
|
||||
* @param string $constraint_name name of constraint that should be used in method
|
||||
* @return mixed data array on success, a MDB2 error on failure
|
||||
* @access public
|
||||
*/
|
||||
function getTableConstraintDefinition($table_name, $constraint_name)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
list($schema, $table) = $this->splitTableSchema($table_name);
|
||||
|
||||
$query = "SELECT c.oid,
|
||||
c.conname AS constraint_name,
|
||||
CASE WHEN c.contype = 'c' THEN 1 ELSE 0 END AS \"check\",
|
||||
CASE WHEN c.contype = 'f' THEN 1 ELSE 0 END AS \"foreign\",
|
||||
CASE WHEN c.contype = 'p' THEN 1 ELSE 0 END AS \"primary\",
|
||||
CASE WHEN c.contype = 'u' THEN 1 ELSE 0 END AS \"unique\",
|
||||
CASE WHEN c.condeferrable = 'f' THEN 0 ELSE 1 END AS deferrable,
|
||||
CASE WHEN c.condeferred = 'f' THEN 0 ELSE 1 END AS initiallydeferred,
|
||||
--array_to_string(c.conkey, ' ') AS constraint_key,
|
||||
t.relname AS table_name,
|
||||
t2.relname AS references_table,
|
||||
CASE confupdtype
|
||||
WHEN 'a' THEN 'NO ACTION'
|
||||
WHEN 'r' THEN 'RESTRICT'
|
||||
WHEN 'c' THEN 'CASCADE'
|
||||
WHEN 'n' THEN 'SET NULL'
|
||||
WHEN 'd' THEN 'SET DEFAULT'
|
||||
END AS onupdate,
|
||||
CASE confdeltype
|
||||
WHEN 'a' THEN 'NO ACTION'
|
||||
WHEN 'r' THEN 'RESTRICT'
|
||||
WHEN 'c' THEN 'CASCADE'
|
||||
WHEN 'n' THEN 'SET NULL'
|
||||
WHEN 'd' THEN 'SET DEFAULT'
|
||||
END AS ondelete,
|
||||
CASE confmatchtype
|
||||
WHEN 'u' THEN 'UNSPECIFIED'
|
||||
WHEN 'f' THEN 'FULL'
|
||||
WHEN 'p' THEN 'PARTIAL'
|
||||
END AS match,
|
||||
--array_to_string(c.confkey, ' ') AS fk_constraint_key,
|
||||
consrc
|
||||
FROM pg_constraint c
|
||||
LEFT JOIN pg_class t ON c.conrelid = t.oid
|
||||
LEFT JOIN pg_class t2 ON c.confrelid = t2.oid
|
||||
WHERE c.conname = %s
|
||||
AND t.relname = " . $db->quote($table, 'text');
|
||||
$constraint_name_mdb2 = $db->getIndexName($constraint_name);
|
||||
$row = $db->queryRow(sprintf($query, $db->quote($constraint_name_mdb2, 'text')), null, MDB2_FETCHMODE_ASSOC);
|
||||
if (MDB2::isError($row) || empty($row)) {
|
||||
// fallback to the given $index_name, without transformation
|
||||
$constraint_name_mdb2 = $constraint_name;
|
||||
$row = $db->queryRow(sprintf($query, $db->quote($constraint_name_mdb2, 'text')), null, MDB2_FETCHMODE_ASSOC);
|
||||
}
|
||||
if (MDB2::isError($row)) {
|
||||
return $row;
|
||||
}
|
||||
$uniqueIndex = false;
|
||||
if (empty($row)) {
|
||||
// We might be looking for a UNIQUE index that was not created
|
||||
// as a constraint but should be treated as such.
|
||||
$query = 'SELECT relname AS constraint_name,
|
||||
indkey,
|
||||
0 AS "check",
|
||||
0 AS "foreign",
|
||||
0 AS "primary",
|
||||
1 AS "unique",
|
||||
0 AS deferrable,
|
||||
0 AS initiallydeferred,
|
||||
NULL AS references_table,
|
||||
NULL AS onupdate,
|
||||
NULL AS ondelete,
|
||||
NULL AS match
|
||||
FROM pg_index, pg_class
|
||||
WHERE pg_class.oid = pg_index.indexrelid
|
||||
AND indisunique = \'t\'
|
||||
AND pg_class.relname = %s';
|
||||
$constraint_name_mdb2 = $db->getIndexName($constraint_name);
|
||||
$row = $db->queryRow(sprintf($query, $db->quote($constraint_name_mdb2, 'text')), null, MDB2_FETCHMODE_ASSOC);
|
||||
if (MDB2::isError($row) || empty($row)) {
|
||||
// fallback to the given $index_name, without transformation
|
||||
$constraint_name_mdb2 = $constraint_name;
|
||||
$row = $db->queryRow(sprintf($query, $db->quote($constraint_name_mdb2, 'text')), null, MDB2_FETCHMODE_ASSOC);
|
||||
}
|
||||
if (MDB2::isError($row)) {
|
||||
return $row;
|
||||
}
|
||||
if (empty($row)) {
|
||||
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
$constraint_name . ' is not an existing table constraint', __FUNCTION__);
|
||||
}
|
||||
$uniqueIndex = true;
|
||||
}
|
||||
|
||||
$row = array_change_key_case($row, CASE_LOWER);
|
||||
|
||||
$definition = array(
|
||||
'primary' => (boolean)$row['primary'],
|
||||
'unique' => (boolean)$row['unique'],
|
||||
'foreign' => (boolean)$row['foreign'],
|
||||
'check' => (boolean)$row['check'],
|
||||
'fields' => array(),
|
||||
'references' => array(
|
||||
'table' => $row['references_table'],
|
||||
'fields' => array(),
|
||||
),
|
||||
'deferrable' => (boolean)$row['deferrable'],
|
||||
'initiallydeferred' => (boolean)$row['initiallydeferred'],
|
||||
'onupdate' => $row['onupdate'],
|
||||
'ondelete' => $row['ondelete'],
|
||||
'match' => $row['match'],
|
||||
);
|
||||
|
||||
if ($uniqueIndex) {
|
||||
$db->loadModule('Manager', null, true);
|
||||
$columns = $db->manager->listTableFields($table_name);
|
||||
$index_column_numbers = explode(' ', $row['indkey']);
|
||||
$colpos = 1;
|
||||
foreach ($index_column_numbers as $number) {
|
||||
$definition['fields'][$columns[($number - 1)]] = array(
|
||||
'position' => $colpos++,
|
||||
'sorting' => 'ascending',
|
||||
);
|
||||
}
|
||||
return $definition;
|
||||
}
|
||||
|
||||
$query = 'SELECT a.attname
|
||||
FROM pg_constraint c
|
||||
LEFT JOIN pg_class t ON c.conrelid = t.oid
|
||||
LEFT JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = ANY(c.conkey)
|
||||
WHERE c.conname = %s
|
||||
AND t.relname = ' . $db->quote($table, 'text');
|
||||
$fields = $db->queryCol(sprintf($query, $db->quote($constraint_name_mdb2, 'text')), null);
|
||||
if (MDB2::isError($fields)) {
|
||||
return $fields;
|
||||
}
|
||||
$colpos = 1;
|
||||
foreach ($fields as $field) {
|
||||
$definition['fields'][$field] = array(
|
||||
'position' => $colpos++,
|
||||
'sorting' => 'ascending',
|
||||
);
|
||||
}
|
||||
|
||||
if ($definition['foreign']) {
|
||||
$query = 'SELECT a.attname
|
||||
FROM pg_constraint c
|
||||
LEFT JOIN pg_class t ON c.confrelid = t.oid
|
||||
LEFT JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = ANY(c.confkey)
|
||||
WHERE c.conname = %s
|
||||
AND t.relname = ' . $db->quote($definition['references']['table'], 'text');
|
||||
$foreign_fields = $db->queryCol(sprintf($query, $db->quote($constraint_name_mdb2, 'text')), null);
|
||||
if (MDB2::isError($foreign_fields)) {
|
||||
return $foreign_fields;
|
||||
}
|
||||
$colpos = 1;
|
||||
foreach ($foreign_fields as $foreign_field) {
|
||||
$definition['references']['fields'][$foreign_field] = array(
|
||||
'position' => $colpos++,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ($definition['check']) {
|
||||
$check_def = $db->queryOne("SELECT pg_get_constraintdef(" . $row['oid'] . ", 't')");
|
||||
// ...
|
||||
}
|
||||
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
|
||||
* @access public
|
||||
*
|
||||
* @TODO: add support for plsql functions and functions with args
|
||||
*/
|
||||
function getTriggerDefinition($trigger)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$query = "SELECT trg.tgname AS trigger_name,
|
||||
tbl.relname AS table_name,
|
||||
CASE
|
||||
WHEN p.proname IS NOT NULL THEN 'EXECUTE PROCEDURE ' || p.proname || '();'
|
||||
ELSE ''
|
||||
END AS trigger_body,
|
||||
CASE trg.tgtype & cast(2 as int2)
|
||||
WHEN 0 THEN 'AFTER'
|
||||
ELSE 'BEFORE'
|
||||
END AS trigger_type,
|
||||
CASE trg.tgtype & cast(28 as int2)
|
||||
WHEN 16 THEN 'UPDATE'
|
||||
WHEN 8 THEN 'DELETE'
|
||||
WHEN 4 THEN 'INSERT'
|
||||
WHEN 20 THEN 'INSERT, UPDATE'
|
||||
WHEN 28 THEN 'INSERT, UPDATE, DELETE'
|
||||
WHEN 24 THEN 'UPDATE, DELETE'
|
||||
WHEN 12 THEN 'INSERT, DELETE'
|
||||
END AS trigger_event,
|
||||
CASE trg.tgenabled
|
||||
WHEN 'O' THEN 't'
|
||||
ELSE trg.tgenabled
|
||||
END AS trigger_enabled,
|
||||
obj_description(trg.oid, 'pg_trigger') AS trigger_comment
|
||||
FROM pg_trigger trg,
|
||||
pg_class tbl,
|
||||
pg_proc p
|
||||
WHERE trg.tgrelid = tbl.oid
|
||||
AND trg.tgfoid = p.oid
|
||||
AND trg.tgname = ". $db->quote($trigger, 'text');
|
||||
$types = array(
|
||||
'trigger_name' => 'text',
|
||||
'table_name' => 'text',
|
||||
'trigger_body' => 'text',
|
||||
'trigger_type' => 'text',
|
||||
'trigger_event' => 'text',
|
||||
'trigger_comment' => 'text',
|
||||
'trigger_enabled' => 'boolean',
|
||||
);
|
||||
return $db->queryRow($query, $types, MDB2_FETCHMODE_ASSOC);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ tableInfo()
|
||||
|
||||
/**
|
||||
* Returns information about a table or a result set
|
||||
*
|
||||
* NOTE: only supports 'table' and 'flags' if <var>$result</var>
|
||||
* is a table name.
|
||||
*
|
||||
* @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 a valid tableInfo mode
|
||||
*
|
||||
* @return array an associative array with the information requested.
|
||||
* A MDB2_Error object on failure.
|
||||
*
|
||||
* @see MDB2_Driver_Common::tableInfo()
|
||||
*/
|
||||
function tableInfo($result, $mode = null)
|
||||
{
|
||||
if (is_string($result)) {
|
||||
return parent::tableInfo($result, $mode);
|
||||
}
|
||||
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$resource = MDB2::isResultCommon($result) ? $result->getResource() : $result;
|
||||
if (!is_resource($resource)) {
|
||||
return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
|
||||
'Could not generate result resource', __FUNCTION__);
|
||||
}
|
||||
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
if ($db->options['field_case'] == CASE_LOWER) {
|
||||
$case_func = 'strtolower';
|
||||
} else {
|
||||
$case_func = 'strtoupper';
|
||||
}
|
||||
} else {
|
||||
$case_func = 'strval';
|
||||
}
|
||||
|
||||
$count = @pg_num_fields($resource);
|
||||
$res = array();
|
||||
|
||||
if ($mode) {
|
||||
$res['num_fields'] = $count;
|
||||
}
|
||||
|
||||
$db->loadModule('Datatype', null, true);
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
$res[$i] = array(
|
||||
'table' => function_exists('pg_field_table') ? @pg_field_table($resource, $i) : '',
|
||||
'name' => $case_func(@pg_field_name($resource, $i)),
|
||||
'type' => @pg_field_type($resource, $i),
|
||||
'length' => @pg_field_size($resource, $i),
|
||||
'flags' => '',
|
||||
);
|
||||
$mdb2type_info = $db->datatype->mapNativeDatatype($res[$i]);
|
||||
if (MDB2::isError($mdb2type_info)) {
|
||||
return $mdb2type_info;
|
||||
}
|
||||
$res[$i]['mdb2type'] = $mdb2type_info[0][0];
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
}
|
||||
?>
|
611
extlib/MDB2/Driver/Reverse/sqlite.php
Normal file
611
extlib/MDB2/Driver/Reverse/sqlite.php
Normal file
@ -0,0 +1,611 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 and 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox, |
|
||||
// | Stig. S. Bakken, Lukas Smith, Lorenzo Alberton |
|
||||
// | 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Authors: Lukas Smith <smith@pooteeweet.org> |
|
||||
// | Lorenzo Alberton <l.alberton@quipo.it> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
|
||||
require_once 'MDB2/Driver/Reverse/Common.php';
|
||||
|
||||
/**
|
||||
* MDB2 SQlite driver for the schema reverse engineering module
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lukas Smith <smith@pooteeweet.org>
|
||||
*/
|
||||
class MDB2_Driver_Reverse_sqlite extends MDB2_Driver_Reverse_Common
|
||||
{
|
||||
/**
|
||||
* Remove SQL comments from the field definition
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
function _removeComments($sql) {
|
||||
$lines = explode("\n", $sql);
|
||||
foreach ($lines as $k => $line) {
|
||||
$pieces = explode('--', $line);
|
||||
if (count($pieces) > 1 && (substr_count($pieces[0], '\'') % 2) == 0) {
|
||||
$lines[$k] = substr($line, 0, strpos($line, '--'));
|
||||
}
|
||||
}
|
||||
return implode("\n", $lines);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function _getTableColumns($sql)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
$start_pos = strpos($sql, '(');
|
||||
$end_pos = strrpos($sql, ')');
|
||||
$column_def = substr($sql, $start_pos+1, $end_pos-$start_pos-1);
|
||||
// replace the decimal length-places-separator with a colon
|
||||
$column_def = preg_replace('/(\d),(\d)/', '\1:\2', $column_def);
|
||||
$column_def = $this->_removeComments($column_def);
|
||||
$column_sql = explode(',', $column_def);
|
||||
$columns = array();
|
||||
$count = count($column_sql);
|
||||
if ($count == 0) {
|
||||
return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
|
||||
'unexpected empty table column definition list', __FUNCTION__);
|
||||
}
|
||||
$regexp = '/^\s*([^\s]+) +(CHAR|VARCHAR|VARCHAR2|TEXT|BOOLEAN|SMALLINT|INT|INTEGER|DECIMAL|TINYINT|BIGINT|DOUBLE|FLOAT|DATETIME|DATE|TIME|LONGTEXT|LONGBLOB)( ?\(([1-9][0-9]*)(:([1-9][0-9]*))?\))?( NULL| NOT NULL)?( UNSIGNED)?( NULL| NOT NULL)?( PRIMARY KEY)?( DEFAULT (\'[^\']*\'|[^ ]+))?( NULL| NOT NULL)?( PRIMARY KEY)?(\s*\-\-.*)?$/i';
|
||||
$regexp2 = '/^\s*([^ ]+) +(PRIMARY|UNIQUE|CHECK)$/i';
|
||||
for ($i=0, $j=0; $i<$count; ++$i) {
|
||||
if (!preg_match($regexp, trim($column_sql[$i]), $matches)) {
|
||||
if (!preg_match($regexp2, trim($column_sql[$i]))) {
|
||||
continue;
|
||||
}
|
||||
return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
|
||||
'unexpected table column SQL definition: "'.$column_sql[$i].'"', __FUNCTION__);
|
||||
}
|
||||
$columns[$j]['name'] = trim($matches[1], implode('', $db->identifier_quoting));
|
||||
$columns[$j]['type'] = strtolower($matches[2]);
|
||||
if (isset($matches[4]) && strlen($matches[4])) {
|
||||
$columns[$j]['length'] = $matches[4];
|
||||
}
|
||||
if (isset($matches[6]) && strlen($matches[6])) {
|
||||
$columns[$j]['decimal'] = $matches[6];
|
||||
}
|
||||
if (isset($matches[8]) && strlen($matches[8])) {
|
||||
$columns[$j]['unsigned'] = true;
|
||||
}
|
||||
if (isset($matches[9]) && strlen($matches[9])) {
|
||||
$columns[$j]['autoincrement'] = true;
|
||||
}
|
||||
if (isset($matches[12]) && strlen($matches[12])) {
|
||||
$default = $matches[12];
|
||||
if (strlen($default) && $default[0]=="'") {
|
||||
$default = str_replace("''", "'", substr($default, 1, strlen($default)-2));
|
||||
}
|
||||
if ($default === 'NULL') {
|
||||
$default = null;
|
||||
}
|
||||
$columns[$j]['default'] = $default;
|
||||
} else {
|
||||
$columns[$j]['default'] = null;
|
||||
}
|
||||
if (isset($matches[7]) && strlen($matches[7])) {
|
||||
$columns[$j]['notnull'] = ($matches[7] === ' NOT NULL');
|
||||
} else if (isset($matches[9]) && strlen($matches[9])) {
|
||||
$columns[$j]['notnull'] = ($matches[9] === ' NOT NULL');
|
||||
} else if (isset($matches[13]) && strlen($matches[13])) {
|
||||
$columns[$j]['notnull'] = ($matches[13] === ' NOT NULL');
|
||||
}
|
||||
++$j;
|
||||
}
|
||||
return $columns;
|
||||
}
|
||||
|
||||
// {{{ getTableFieldDefinition()
|
||||
|
||||
/**
|
||||
* Get the stucture of a field into an array
|
||||
*
|
||||
* @param string $table_name name of table that should be used in method
|
||||
* @param string $field_name 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 (some of) these indices:
|
||||
* [notnull] [nativetype] [length] [fixed] [default] [type] [mdb2type]
|
||||
* @access public
|
||||
*/
|
||||
function getTableFieldDefinition($table_name, $field_name)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
list($schema, $table) = $this->splitTableSchema($table_name);
|
||||
|
||||
$result = $db->loadModule('Datatype', null, true);
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
$query = "SELECT sql FROM sqlite_master WHERE type='table' AND ";
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
$query.= 'LOWER(name)='.$db->quote(strtolower($table), 'text');
|
||||
} else {
|
||||
$query.= 'name='.$db->quote($table, 'text');
|
||||
}
|
||||
$sql = $db->queryOne($query);
|
||||
if (MDB2::isError($sql)) {
|
||||
return $sql;
|
||||
}
|
||||
$columns = $this->_getTableColumns($sql);
|
||||
foreach ($columns as $column) {
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
if ($db->options['field_case'] == CASE_LOWER) {
|
||||
$column['name'] = strtolower($column['name']);
|
||||
} else {
|
||||
$column['name'] = strtoupper($column['name']);
|
||||
}
|
||||
} else {
|
||||
$column = array_change_key_case($column, $db->options['field_case']);
|
||||
}
|
||||
if ($field_name == $column['name']) {
|
||||
$mapped_datatype = $db->datatype->mapNativeDatatype($column);
|
||||
if (MDB2::isError($mapped_datatype)) {
|
||||
return $mapped_datatype;
|
||||
}
|
||||
list($types, $length, $unsigned, $fixed) = $mapped_datatype;
|
||||
$notnull = false;
|
||||
if (!empty($column['notnull'])) {
|
||||
$notnull = $column['notnull'];
|
||||
}
|
||||
$default = false;
|
||||
if (array_key_exists('default', $column)) {
|
||||
$default = $column['default'];
|
||||
if ((null === $default) && $notnull) {
|
||||
$default = '';
|
||||
}
|
||||
}
|
||||
$autoincrement = false;
|
||||
if (!empty($column['autoincrement'])) {
|
||||
$autoincrement = true;
|
||||
}
|
||||
|
||||
$definition[0] = array(
|
||||
'notnull' => $notnull,
|
||||
'nativetype' => preg_replace('/^([a-z]+)[^a-z].*/i', '\\1', $column['type'])
|
||||
);
|
||||
if (null !== $length) {
|
||||
$definition[0]['length'] = $length;
|
||||
}
|
||||
if (null !== $unsigned) {
|
||||
$definition[0]['unsigned'] = $unsigned;
|
||||
}
|
||||
if (null !== $fixed) {
|
||||
$definition[0]['fixed'] = $fixed;
|
||||
}
|
||||
if ($default !== false) {
|
||||
$definition[0]['default'] = $default;
|
||||
}
|
||||
if ($autoincrement !== false) {
|
||||
$definition[0]['autoincrement'] = $autoincrement;
|
||||
}
|
||||
foreach ($types as $key => $type) {
|
||||
$definition[$key] = $definition[0];
|
||||
if ($type == 'clob' || $type == 'blob') {
|
||||
unset($definition[$key]['default']);
|
||||
}
|
||||
$definition[$key]['type'] = $type;
|
||||
$definition[$key]['mdb2type'] = $type;
|
||||
}
|
||||
return $definition;
|
||||
}
|
||||
}
|
||||
|
||||
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
'it was not specified an existing table column', __FUNCTION__);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ getTableIndexDefinition()
|
||||
|
||||
/**
|
||||
* Get the stucture of an index into an array
|
||||
*
|
||||
* @param string $table_name name of table that should be used in method
|
||||
* @param string $index_name name of index that should be used in method
|
||||
* @return mixed data array on success, a MDB2 error on failure
|
||||
* @access public
|
||||
*/
|
||||
function getTableIndexDefinition($table_name, $index_name)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
list($schema, $table) = $this->splitTableSchema($table_name);
|
||||
|
||||
$query = "SELECT sql FROM sqlite_master WHERE type='index' AND ";
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
$query.= 'LOWER(name)=%s AND LOWER(tbl_name)=' . $db->quote(strtolower($table), 'text');
|
||||
} else {
|
||||
$query.= 'name=%s AND tbl_name=' . $db->quote($table, 'text');
|
||||
}
|
||||
$query.= ' AND sql NOT NULL ORDER BY name';
|
||||
$index_name_mdb2 = $db->getIndexName($index_name);
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
$qry = sprintf($query, $db->quote(strtolower($index_name_mdb2), 'text'));
|
||||
} else {
|
||||
$qry = sprintf($query, $db->quote($index_name_mdb2, 'text'));
|
||||
}
|
||||
$sql = $db->queryOne($qry, 'text');
|
||||
if (MDB2::isError($sql) || empty($sql)) {
|
||||
// fallback to the given $index_name, without transformation
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
$qry = sprintf($query, $db->quote(strtolower($index_name), 'text'));
|
||||
} else {
|
||||
$qry = sprintf($query, $db->quote($index_name, 'text'));
|
||||
}
|
||||
$sql = $db->queryOne($qry, 'text');
|
||||
}
|
||||
if (MDB2::isError($sql)) {
|
||||
return $sql;
|
||||
}
|
||||
if (!$sql) {
|
||||
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
'it was not specified an existing table index', __FUNCTION__);
|
||||
}
|
||||
|
||||
$sql = strtolower($sql);
|
||||
$start_pos = strpos($sql, '(');
|
||||
$end_pos = strrpos($sql, ')');
|
||||
$column_names = substr($sql, $start_pos+1, $end_pos-$start_pos-1);
|
||||
$column_names = explode(',', $column_names);
|
||||
|
||||
if (preg_match("/^create unique/", $sql)) {
|
||||
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
'it was not specified an existing table index', __FUNCTION__);
|
||||
}
|
||||
|
||||
$definition = array();
|
||||
$count = count($column_names);
|
||||
for ($i=0; $i<$count; ++$i) {
|
||||
$column_name = strtok($column_names[$i], ' ');
|
||||
$collation = strtok(' ');
|
||||
$definition['fields'][$column_name] = array(
|
||||
'position' => $i+1
|
||||
);
|
||||
if (!empty($collation)) {
|
||||
$definition['fields'][$column_name]['sorting'] =
|
||||
($collation=='ASC' ? 'ascending' : 'descending');
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($definition['fields'])) {
|
||||
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
'it was not specified an existing table index', __FUNCTION__);
|
||||
}
|
||||
return $definition;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ getTableConstraintDefinition()
|
||||
|
||||
/**
|
||||
* Get the stucture of a constraint into an array
|
||||
*
|
||||
* @param string $table_name name of table that should be used in method
|
||||
* @param string $constraint_name name of constraint that should be used in method
|
||||
* @return mixed data array on success, a MDB2 error on failure
|
||||
* @access public
|
||||
*/
|
||||
function getTableConstraintDefinition($table_name, $constraint_name)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
list($schema, $table) = $this->splitTableSchema($table_name);
|
||||
|
||||
$query = "SELECT sql FROM sqlite_master WHERE type='index' AND ";
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
$query.= 'LOWER(name)=%s AND LOWER(tbl_name)=' . $db->quote(strtolower($table), 'text');
|
||||
} else {
|
||||
$query.= 'name=%s AND tbl_name=' . $db->quote($table, 'text');
|
||||
}
|
||||
$query.= ' AND sql NOT NULL ORDER BY name';
|
||||
$constraint_name_mdb2 = $db->getIndexName($constraint_name);
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
$qry = sprintf($query, $db->quote(strtolower($constraint_name_mdb2), 'text'));
|
||||
} else {
|
||||
$qry = sprintf($query, $db->quote($constraint_name_mdb2, 'text'));
|
||||
}
|
||||
$sql = $db->queryOne($qry, 'text');
|
||||
if (MDB2::isError($sql) || empty($sql)) {
|
||||
// fallback to the given $index_name, without transformation
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
$qry = sprintf($query, $db->quote(strtolower($constraint_name), 'text'));
|
||||
} else {
|
||||
$qry = sprintf($query, $db->quote($constraint_name, 'text'));
|
||||
}
|
||||
$sql = $db->queryOne($qry, 'text');
|
||||
}
|
||||
if (MDB2::isError($sql)) {
|
||||
return $sql;
|
||||
}
|
||||
//default values, eventually overridden
|
||||
$definition = array(
|
||||
'primary' => false,
|
||||
'unique' => false,
|
||||
'foreign' => false,
|
||||
'check' => false,
|
||||
'fields' => array(),
|
||||
'references' => array(
|
||||
'table' => '',
|
||||
'fields' => array(),
|
||||
),
|
||||
'onupdate' => '',
|
||||
'ondelete' => '',
|
||||
'match' => '',
|
||||
'deferrable' => false,
|
||||
'initiallydeferred' => false,
|
||||
);
|
||||
if (!$sql) {
|
||||
$query = "SELECT sql FROM sqlite_master WHERE type='table' AND ";
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
$query.= 'LOWER(name)='.$db->quote(strtolower($table), 'text');
|
||||
} else {
|
||||
$query.= 'name='.$db->quote($table, 'text');
|
||||
}
|
||||
$query.= " AND sql NOT NULL ORDER BY name";
|
||||
$sql = $db->queryOne($query, 'text');
|
||||
if (MDB2::isError($sql)) {
|
||||
return $sql;
|
||||
}
|
||||
if ($constraint_name == 'primary') {
|
||||
// search in table definition for PRIMARY KEYs
|
||||
if (preg_match("/\bPRIMARY\s+KEY\b\s*\(([^)]+)/i", $sql, $tmp)) {
|
||||
$definition['primary'] = true;
|
||||
$definition['fields'] = array();
|
||||
$column_names = explode(',', $tmp[1]);
|
||||
$colpos = 1;
|
||||
foreach ($column_names as $column_name) {
|
||||
$definition['fields'][trim($column_name)] = array(
|
||||
'position' => $colpos++
|
||||
);
|
||||
}
|
||||
return $definition;
|
||||
}
|
||||
if (preg_match("/\"([^\"]+)\"[^\,\"]+\bPRIMARY\s+KEY\b[^\,\)]*/i", $sql, $tmp)) {
|
||||
$definition['primary'] = true;
|
||||
$definition['fields'] = array();
|
||||
$column_names = explode(',', $tmp[1]);
|
||||
$colpos = 1;
|
||||
foreach ($column_names as $column_name) {
|
||||
$definition['fields'][trim($column_name)] = array(
|
||||
'position' => $colpos++
|
||||
);
|
||||
}
|
||||
return $definition;
|
||||
}
|
||||
} else {
|
||||
// search in table definition for FOREIGN KEYs
|
||||
$pattern = "/\bCONSTRAINT\b\s+%s\s+
|
||||
\bFOREIGN\s+KEY\b\s*\(([^\)]+)\)\s*
|
||||
\bREFERENCES\b\s+([^\s]+)\s*\(([^\)]+)\)\s*
|
||||
(?:\bMATCH\s*([^\s]+))?\s*
|
||||
(?:\bON\s+UPDATE\s+([^\s,\)]+))?\s*
|
||||
(?:\bON\s+DELETE\s+([^\s,\)]+))?\s*
|
||||
/imsx";
|
||||
$found_fk = false;
|
||||
if (preg_match(sprintf($pattern, $constraint_name_mdb2), $sql, $tmp)) {
|
||||
$found_fk = true;
|
||||
} elseif (preg_match(sprintf($pattern, $constraint_name), $sql, $tmp)) {
|
||||
$found_fk = true;
|
||||
}
|
||||
if ($found_fk) {
|
||||
$definition['foreign'] = true;
|
||||
$definition['match'] = 'SIMPLE';
|
||||
$definition['onupdate'] = 'NO ACTION';
|
||||
$definition['ondelete'] = 'NO ACTION';
|
||||
$definition['references']['table'] = $tmp[2];
|
||||
$column_names = explode(',', $tmp[1]);
|
||||
$colpos = 1;
|
||||
foreach ($column_names as $column_name) {
|
||||
$definition['fields'][trim($column_name)] = array(
|
||||
'position' => $colpos++
|
||||
);
|
||||
}
|
||||
$referenced_cols = explode(',', $tmp[3]);
|
||||
$colpos = 1;
|
||||
foreach ($referenced_cols as $column_name) {
|
||||
$definition['references']['fields'][trim($column_name)] = array(
|
||||
'position' => $colpos++
|
||||
);
|
||||
}
|
||||
if (isset($tmp[4])) {
|
||||
$definition['match'] = $tmp[4];
|
||||
}
|
||||
if (isset($tmp[5])) {
|
||||
$definition['onupdate'] = $tmp[5];
|
||||
}
|
||||
if (isset($tmp[6])) {
|
||||
$definition['ondelete'] = $tmp[6];
|
||||
}
|
||||
return $definition;
|
||||
}
|
||||
}
|
||||
$sql = false;
|
||||
}
|
||||
if (!$sql) {
|
||||
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
$constraint_name . ' is not an existing table constraint', __FUNCTION__);
|
||||
}
|
||||
|
||||
$sql = strtolower($sql);
|
||||
$start_pos = strpos($sql, '(');
|
||||
$end_pos = strrpos($sql, ')');
|
||||
$column_names = substr($sql, $start_pos+1, $end_pos-$start_pos-1);
|
||||
$column_names = explode(',', $column_names);
|
||||
|
||||
if (!preg_match("/^create unique/", $sql)) {
|
||||
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
$constraint_name . ' is not an existing table constraint', __FUNCTION__);
|
||||
}
|
||||
|
||||
$definition['unique'] = true;
|
||||
$count = count($column_names);
|
||||
for ($i=0; $i<$count; ++$i) {
|
||||
$column_name = strtok($column_names[$i]," ");
|
||||
$collation = strtok(" ");
|
||||
$definition['fields'][$column_name] = array(
|
||||
'position' => $i+1
|
||||
);
|
||||
if (!empty($collation)) {
|
||||
$definition['fields'][$column_name]['sorting'] =
|
||||
($collation=='ASC' ? 'ascending' : 'descending');
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($definition['fields'])) {
|
||||
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
$constraint_name . ' is not an existing table constraint', __FUNCTION__);
|
||||
}
|
||||
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
|
||||
* @access public
|
||||
*/
|
||||
function getTriggerDefinition($trigger)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$query = "SELECT name as trigger_name,
|
||||
tbl_name AS table_name,
|
||||
sql AS trigger_body,
|
||||
NULL AS trigger_type,
|
||||
NULL AS trigger_event,
|
||||
NULL AS trigger_comment,
|
||||
1 AS trigger_enabled
|
||||
FROM sqlite_master
|
||||
WHERE type='trigger'";
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
$query.= ' AND LOWER(name)='.$db->quote(strtolower($trigger), 'text');
|
||||
} else {
|
||||
$query.= ' AND name='.$db->quote($trigger, 'text');
|
||||
}
|
||||
$types = array(
|
||||
'trigger_name' => 'text',
|
||||
'table_name' => 'text',
|
||||
'trigger_body' => 'text',
|
||||
'trigger_type' => 'text',
|
||||
'trigger_event' => 'text',
|
||||
'trigger_comment' => 'text',
|
||||
'trigger_enabled' => 'boolean',
|
||||
);
|
||||
$def = $db->queryRow($query, $types, MDB2_FETCHMODE_ASSOC);
|
||||
if (MDB2::isError($def)) {
|
||||
return $def;
|
||||
}
|
||||
if (empty($def)) {
|
||||
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
'it was not specified an existing trigger', __FUNCTION__);
|
||||
}
|
||||
if (preg_match("/^create\s+(?:temp|temporary)?trigger\s+(?:if\s+not\s+exists\s+)?.*(before|after)?\s+(insert|update|delete)/Uims", $def['trigger_body'], $tmp)) {
|
||||
$def['trigger_type'] = strtoupper($tmp[1]);
|
||||
$def['trigger_event'] = strtoupper($tmp[2]);
|
||||
}
|
||||
return $def;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ tableInfo()
|
||||
|
||||
/**
|
||||
* Returns information about a table
|
||||
*
|
||||
* @param string $result a string containing the name of a table
|
||||
* @param int $mode a valid tableInfo mode
|
||||
*
|
||||
* @return array an associative array with the information requested.
|
||||
* A MDB2_Error object on failure.
|
||||
*
|
||||
* @see MDB2_Driver_Common::tableInfo()
|
||||
* @since Method available since Release 1.7.0
|
||||
*/
|
||||
function tableInfo($result, $mode = null)
|
||||
{
|
||||
if (is_string($result)) {
|
||||
return parent::tableInfo($result, $mode);
|
||||
}
|
||||
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
return $db->raiseError(MDB2_ERROR_NOT_CAPABLE, null, null,
|
||||
'This DBMS can not obtain tableInfo from result sets', __FUNCTION__);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
611
extlib/MDB2/Driver/Reverse/sqlite3.php
Normal file
611
extlib/MDB2/Driver/Reverse/sqlite3.php
Normal file
@ -0,0 +1,611 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 - 7 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox, |
|
||||
// | Stig. S. Bakken, Lukas Smith, Lorenzo Alberton |
|
||||
// | 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Authors: Lukas Smith <smith@pooteeweet.org> |
|
||||
// | Lorenzo Alberton <l.alberton@quipo.it> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
|
||||
require_once 'MDB2/Driver/Reverse/Common.php';
|
||||
|
||||
/**
|
||||
* MDB2 SQlite driver for the schema reverse engineering module
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lorenzo Alberton <l.alberton@quipo.it>
|
||||
*/
|
||||
class MDB2_Driver_Reverse_sqlite3 extends MDB2_Driver_Reverse_Common
|
||||
{
|
||||
/**
|
||||
* Remove SQL comments from the field definition
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
function _removeComments($sql) {
|
||||
$lines = explode("\n", $sql);
|
||||
foreach ($lines as $k => $line) {
|
||||
$pieces = explode('--', $line);
|
||||
if (count($pieces) > 1 && (substr_count($pieces[0], '\'') % 2) == 0) {
|
||||
$lines[$k] = substr($line, 0, strpos($line, '--'));
|
||||
}
|
||||
}
|
||||
return implode("\n", $lines);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function _getTableColumns($sql)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
$start_pos = strpos($sql, '(');
|
||||
$end_pos = strrpos($sql, ')');
|
||||
$column_def = substr($sql, $start_pos+1, $end_pos-$start_pos-1);
|
||||
// replace the decimal length-places-separator with a colon
|
||||
$column_def = preg_replace('/(\d),(\d)/', '\1:\2', $column_def);
|
||||
$column_def = $this->_removeComments($column_def);
|
||||
$column_sql = explode(',', $column_def);
|
||||
$columns = array();
|
||||
$count = count($column_sql);
|
||||
if ($count == 0) {
|
||||
return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
|
||||
'unexpected empty table column definition list', __FUNCTION__);
|
||||
}
|
||||
$regexp = '/^\s*([^\s]+) +(CHAR|VARCHAR|VARCHAR2|TEXT|BOOLEAN|SMALLINT|INT|INTEGER|DECIMAL|TINYINT|BIGINT|DOUBLE|FLOAT|DATETIME|DATE|TIME|LONGTEXT|LONGBLOB)( ?\(([1-9][0-9]*)(:([1-9][0-9]*))?\))?( NULL| NOT NULL)?( UNSIGNED)?( NULL| NOT NULL)?( PRIMARY KEY)?( DEFAULT (\'[^\']*\'|[^ ]+))?( NULL| NOT NULL)?( PRIMARY KEY)?(\s*\-\-.*)?$/i';
|
||||
$regexp2 = '/^\s*([^ ]+) +(PRIMARY|UNIQUE|CHECK)$/i';
|
||||
for ($i=0, $j=0; $i<$count; ++$i) {
|
||||
if (!preg_match($regexp, trim($column_sql[$i]), $matches)) {
|
||||
if (!preg_match($regexp2, trim($column_sql[$i]))) {
|
||||
continue;
|
||||
}
|
||||
return $db->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
|
||||
'unexpected table column SQL definition: "'.$column_sql[$i].'"', __FUNCTION__);
|
||||
}
|
||||
$columns[$j]['name'] = trim($matches[1], implode('', $db->identifier_quoting));
|
||||
$columns[$j]['type'] = strtolower($matches[2]);
|
||||
if (isset($matches[4]) && strlen($matches[4])) {
|
||||
$columns[$j]['length'] = $matches[4];
|
||||
}
|
||||
if (isset($matches[6]) && strlen($matches[6])) {
|
||||
$columns[$j]['decimal'] = $matches[6];
|
||||
}
|
||||
if (isset($matches[8]) && strlen($matches[8])) {
|
||||
$columns[$j]['unsigned'] = true;
|
||||
}
|
||||
if (isset($matches[9]) && strlen($matches[9])) {
|
||||
$columns[$j]['autoincrement'] = true;
|
||||
}
|
||||
if (isset($matches[12]) && strlen($matches[12])) {
|
||||
$default = $matches[12];
|
||||
if (strlen($default) && $default[0]=="'") {
|
||||
$default = str_replace("''", "'", substr($default, 1, strlen($default)-2));
|
||||
}
|
||||
if ($default === 'NULL') {
|
||||
$default = null;
|
||||
}
|
||||
$columns[$j]['default'] = $default;
|
||||
} else {
|
||||
$columns[$j]['default'] = null;
|
||||
}
|
||||
if (isset($matches[7]) && strlen($matches[7])) {
|
||||
$columns[$j]['notnull'] = ($matches[7] === ' NOT NULL');
|
||||
} else if (isset($matches[9]) && strlen($matches[9])) {
|
||||
$columns[$j]['notnull'] = ($matches[9] === ' NOT NULL');
|
||||
} else if (isset($matches[13]) && strlen($matches[13])) {
|
||||
$columns[$j]['notnull'] = ($matches[13] === ' NOT NULL');
|
||||
}
|
||||
++$j;
|
||||
}
|
||||
return $columns;
|
||||
}
|
||||
|
||||
// {{{ getTableFieldDefinition()
|
||||
|
||||
/**
|
||||
* Get the stucture of a field into an array
|
||||
*
|
||||
* @param string $table_name name of table that should be used in method
|
||||
* @param string $field_name 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 (some of) these indices:
|
||||
* [notnull] [nativetype] [length] [fixed] [default] [type] [mdb2type]
|
||||
* @access public
|
||||
*/
|
||||
function getTableFieldDefinition($table_name, $field_name)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
list($schema, $table) = $this->splitTableSchema($table_name);
|
||||
|
||||
$result = $db->loadModule('Datatype', null, true);
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
$query = "SELECT sql FROM sqlite_master WHERE type='table' AND ";
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
$query.= 'LOWER(name)='.$db->quote(strtolower($table), 'text');
|
||||
} else {
|
||||
$query.= 'name='.$db->quote($table, 'text');
|
||||
}
|
||||
$sql = $db->queryOne($query);
|
||||
if (MDB2::isError($sql)) {
|
||||
return $sql;
|
||||
}
|
||||
$columns = $this->_getTableColumns($sql);
|
||||
foreach ($columns as $column) {
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
if ($db->options['field_case'] == CASE_LOWER) {
|
||||
$column['name'] = strtolower($column['name']);
|
||||
} else {
|
||||
$column['name'] = strtoupper($column['name']);
|
||||
}
|
||||
} else {
|
||||
$column = array_change_key_case($column, $db->options['field_case']);
|
||||
}
|
||||
if ($field_name == $column['name']) {
|
||||
$mapped_datatype = $db->datatype->mapNativeDatatype($column);
|
||||
if (MDB2::isError($mapped_datatype)) {
|
||||
return $mapped_datatype;
|
||||
}
|
||||
list($types, $length, $unsigned, $fixed) = $mapped_datatype;
|
||||
$notnull = false;
|
||||
if (!empty($column['notnull'])) {
|
||||
$notnull = $column['notnull'];
|
||||
}
|
||||
$default = false;
|
||||
if (array_key_exists('default', $column)) {
|
||||
$default = $column['default'];
|
||||
if ((null === $default) && $notnull) {
|
||||
$default = '';
|
||||
}
|
||||
}
|
||||
$autoincrement = false;
|
||||
if (!empty($column['autoincrement'])) {
|
||||
$autoincrement = true;
|
||||
}
|
||||
|
||||
$definition[0] = array(
|
||||
'notnull' => $notnull,
|
||||
'nativetype' => preg_replace('/^([a-z]+)[^a-z].*/i', '\\1', $column['type'])
|
||||
);
|
||||
if (null !== $length) {
|
||||
$definition[0]['length'] = $length;
|
||||
}
|
||||
if (null !== $unsigned) {
|
||||
$definition[0]['unsigned'] = $unsigned;
|
||||
}
|
||||
if (null !== $fixed) {
|
||||
$definition[0]['fixed'] = $fixed;
|
||||
}
|
||||
if ($default !== false) {
|
||||
$definition[0]['default'] = $default;
|
||||
}
|
||||
if ($autoincrement !== false) {
|
||||
$definition[0]['autoincrement'] = $autoincrement;
|
||||
}
|
||||
foreach ($types as $key => $type) {
|
||||
$definition[$key] = $definition[0];
|
||||
if ($type == 'clob' || $type == 'blob') {
|
||||
unset($definition[$key]['default']);
|
||||
}
|
||||
$definition[$key]['type'] = $type;
|
||||
$definition[$key]['mdb2type'] = $type;
|
||||
}
|
||||
return $definition;
|
||||
}
|
||||
}
|
||||
|
||||
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
'it was not specified an existing table column', __FUNCTION__);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ getTableIndexDefinition()
|
||||
|
||||
/**
|
||||
* Get the stucture of an index into an array
|
||||
*
|
||||
* @param string $table_name name of table that should be used in method
|
||||
* @param string $index_name name of index that should be used in method
|
||||
* @return mixed data array on success, a MDB2 error on failure
|
||||
* @access public
|
||||
*/
|
||||
function getTableIndexDefinition($table_name, $index_name)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
list($schema, $table) = $this->splitTableSchema($table_name);
|
||||
|
||||
$query = "SELECT sql FROM sqlite_master WHERE type='index' AND ";
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
$query.= 'LOWER(name)=%s AND LOWER(tbl_name)=' . $db->quote(strtolower($table), 'text');
|
||||
} else {
|
||||
$query.= 'name=%s AND tbl_name=' . $db->quote($table, 'text');
|
||||
}
|
||||
$query.= ' AND sql NOT NULL ORDER BY name';
|
||||
$index_name_mdb2 = $db->getIndexName($index_name);
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
$qry = sprintf($query, $db->quote(strtolower($index_name_mdb2), 'text'));
|
||||
} else {
|
||||
$qry = sprintf($query, $db->quote($index_name_mdb2, 'text'));
|
||||
}
|
||||
$sql = $db->queryOne($qry, 'text');
|
||||
if (MDB2::isError($sql) || empty($sql)) {
|
||||
// fallback to the given $index_name, without transformation
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
$qry = sprintf($query, $db->quote(strtolower($index_name), 'text'));
|
||||
} else {
|
||||
$qry = sprintf($query, $db->quote($index_name, 'text'));
|
||||
}
|
||||
$sql = $db->queryOne($qry, 'text');
|
||||
}
|
||||
if (MDB2::isError($sql)) {
|
||||
return $sql;
|
||||
}
|
||||
if (!$sql) {
|
||||
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
'it was not specified an existing table index', __FUNCTION__);
|
||||
}
|
||||
|
||||
$sql = strtolower($sql);
|
||||
$start_pos = strpos($sql, '(');
|
||||
$end_pos = strrpos($sql, ')');
|
||||
$column_names = substr($sql, $start_pos+1, $end_pos-$start_pos-1);
|
||||
$column_names = explode(',', $column_names);
|
||||
|
||||
if (preg_match("/^create unique/", $sql)) {
|
||||
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
'it was not specified an existing table index', __FUNCTION__);
|
||||
}
|
||||
|
||||
$definition = array();
|
||||
$count = count($column_names);
|
||||
for ($i=0; $i<$count; ++$i) {
|
||||
$column_name = strtok($column_names[$i], ' ');
|
||||
$collation = strtok(' ');
|
||||
$definition['fields'][$column_name] = array(
|
||||
'position' => $i+1
|
||||
);
|
||||
if (!empty($collation)) {
|
||||
$definition['fields'][$column_name]['sorting'] =
|
||||
($collation=='ASC' ? 'ascending' : 'descending');
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($definition['fields'])) {
|
||||
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
'it was not specified an existing table index', __FUNCTION__);
|
||||
}
|
||||
return $definition;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ getTableConstraintDefinition()
|
||||
|
||||
/**
|
||||
* Get the stucture of a constraint into an array
|
||||
*
|
||||
* @param string $table_name name of table that should be used in method
|
||||
* @param string $constraint_name name of constraint that should be used in method
|
||||
* @return mixed data array on success, a MDB2 error on failure
|
||||
* @access public
|
||||
*/
|
||||
function getTableConstraintDefinition($table_name, $constraint_name)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
list($schema, $table) = $this->splitTableSchema($table_name);
|
||||
|
||||
$query = "SELECT sql FROM sqlite_master WHERE type='index' AND ";
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
$query.= 'LOWER(name)=%s AND LOWER(tbl_name)=' . $db->quote(strtolower($table), 'text');
|
||||
} else {
|
||||
$query.= 'name=%s AND tbl_name=' . $db->quote($table, 'text');
|
||||
}
|
||||
$query.= ' AND sql NOT NULL ORDER BY name';
|
||||
$constraint_name_mdb2 = $db->getIndexName($constraint_name);
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
$qry = sprintf($query, $db->quote(strtolower($constraint_name_mdb2), 'text'));
|
||||
} else {
|
||||
$qry = sprintf($query, $db->quote($constraint_name_mdb2, 'text'));
|
||||
}
|
||||
$sql = $db->queryOne($qry, 'text');
|
||||
if (MDB2::isError($sql) || empty($sql)) {
|
||||
// fallback to the given $index_name, without transformation
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
$qry = sprintf($query, $db->quote(strtolower($constraint_name), 'text'));
|
||||
} else {
|
||||
$qry = sprintf($query, $db->quote($constraint_name, 'text'));
|
||||
}
|
||||
$sql = $db->queryOne($qry, 'text');
|
||||
}
|
||||
if (MDB2::isError($sql)) {
|
||||
return $sql;
|
||||
}
|
||||
//default values, eventually overridden
|
||||
$definition = array(
|
||||
'primary' => false,
|
||||
'unique' => false,
|
||||
'foreign' => false,
|
||||
'check' => false,
|
||||
'fields' => array(),
|
||||
'references' => array(
|
||||
'table' => '',
|
||||
'fields' => array(),
|
||||
),
|
||||
'onupdate' => '',
|
||||
'ondelete' => '',
|
||||
'match' => '',
|
||||
'deferrable' => false,
|
||||
'initiallydeferred' => false,
|
||||
);
|
||||
if (!$sql) {
|
||||
$query = "SELECT sql FROM sqlite_master WHERE type='table' AND ";
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
$query.= 'LOWER(name)='.$db->quote(strtolower($table), 'text');
|
||||
} else {
|
||||
$query.= 'name='.$db->quote($table, 'text');
|
||||
}
|
||||
$query.= " AND sql NOT NULL ORDER BY name";
|
||||
$sql = $db->queryOne($query, 'text');
|
||||
if (MDB2::isError($sql)) {
|
||||
return $sql;
|
||||
}
|
||||
if ($constraint_name == 'primary') {
|
||||
// search in table definition for PRIMARY KEYs
|
||||
if (preg_match("/\bPRIMARY\s+KEY\b\s*\(([^)]+)/i", $sql, $tmp)) {
|
||||
$definition['primary'] = true;
|
||||
$definition['fields'] = array();
|
||||
$column_names = explode(',', $tmp[1]);
|
||||
$colpos = 1;
|
||||
foreach ($column_names as $column_name) {
|
||||
$definition['fields'][trim($column_name)] = array(
|
||||
'position' => $colpos++
|
||||
);
|
||||
}
|
||||
return $definition;
|
||||
}
|
||||
if (preg_match("/\"([^\"]+)\"[^\,\"]+\bPRIMARY\s+KEY\b[^\,\)]*/i", $sql, $tmp)) {
|
||||
$definition['primary'] = true;
|
||||
$definition['fields'] = array();
|
||||
$column_names = explode(',', $tmp[1]);
|
||||
$colpos = 1;
|
||||
foreach ($column_names as $column_name) {
|
||||
$definition['fields'][trim($column_name)] = array(
|
||||
'position' => $colpos++
|
||||
);
|
||||
}
|
||||
return $definition;
|
||||
}
|
||||
} else {
|
||||
// search in table definition for FOREIGN KEYs
|
||||
$pattern = "/\bCONSTRAINT\b\s+%s\s+
|
||||
\bFOREIGN\s+KEY\b\s*\(([^\)]+)\)\s*
|
||||
\bREFERENCES\b\s+([^\s]+)\s*\(([^\)]+)\)\s*
|
||||
(?:\bMATCH\s*([^\s]+))?\s*
|
||||
(?:\bON\s+UPDATE\s+([^\s,\)]+))?\s*
|
||||
(?:\bON\s+DELETE\s+([^\s,\)]+))?\s*
|
||||
/imsx";
|
||||
$found_fk = false;
|
||||
if (preg_match(sprintf($pattern, $constraint_name_mdb2), $sql, $tmp)) {
|
||||
$found_fk = true;
|
||||
} elseif (preg_match(sprintf($pattern, $constraint_name), $sql, $tmp)) {
|
||||
$found_fk = true;
|
||||
}
|
||||
if ($found_fk) {
|
||||
$definition['foreign'] = true;
|
||||
$definition['match'] = 'SIMPLE';
|
||||
$definition['onupdate'] = 'NO ACTION';
|
||||
$definition['ondelete'] = 'NO ACTION';
|
||||
$definition['references']['table'] = $tmp[2];
|
||||
$column_names = explode(',', $tmp[1]);
|
||||
$colpos = 1;
|
||||
foreach ($column_names as $column_name) {
|
||||
$definition['fields'][trim($column_name)] = array(
|
||||
'position' => $colpos++
|
||||
);
|
||||
}
|
||||
$referenced_cols = explode(',', $tmp[3]);
|
||||
$colpos = 1;
|
||||
foreach ($referenced_cols as $column_name) {
|
||||
$definition['references']['fields'][trim($column_name)] = array(
|
||||
'position' => $colpos++
|
||||
);
|
||||
}
|
||||
if (isset($tmp[4])) {
|
||||
$definition['match'] = $tmp[4];
|
||||
}
|
||||
if (isset($tmp[5])) {
|
||||
$definition['onupdate'] = $tmp[5];
|
||||
}
|
||||
if (isset($tmp[6])) {
|
||||
$definition['ondelete'] = $tmp[6];
|
||||
}
|
||||
return $definition;
|
||||
}
|
||||
}
|
||||
$sql = false;
|
||||
}
|
||||
if (!$sql) {
|
||||
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
$constraint_name . ' is not an existing table constraint', __FUNCTION__);
|
||||
}
|
||||
|
||||
$sql = strtolower($sql);
|
||||
$start_pos = strpos($sql, '(');
|
||||
$end_pos = strrpos($sql, ')');
|
||||
$column_names = substr($sql, $start_pos+1, $end_pos-$start_pos-1);
|
||||
$column_names = explode(',', $column_names);
|
||||
|
||||
if (!preg_match("/^create unique/", $sql)) {
|
||||
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
$constraint_name . ' is not an existing table constraint', __FUNCTION__);
|
||||
}
|
||||
|
||||
$definition['unique'] = true;
|
||||
$count = count($column_names);
|
||||
for ($i=0; $i<$count; ++$i) {
|
||||
$column_name = strtok($column_names[$i]," ");
|
||||
$collation = strtok(" ");
|
||||
$definition['fields'][$column_name] = array(
|
||||
'position' => $i+1
|
||||
);
|
||||
if (!empty($collation)) {
|
||||
$definition['fields'][$column_name]['sorting'] =
|
||||
($collation=='ASC' ? 'ascending' : 'descending');
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($definition['fields'])) {
|
||||
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
$constraint_name . ' is not an existing table constraint', __FUNCTION__);
|
||||
}
|
||||
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
|
||||
* @access public
|
||||
*/
|
||||
function getTriggerDefinition($trigger)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$query = "SELECT name as trigger_name,
|
||||
tbl_name AS table_name,
|
||||
sql AS trigger_body,
|
||||
NULL AS trigger_type,
|
||||
NULL AS trigger_event,
|
||||
NULL AS trigger_comment,
|
||||
1 AS trigger_enabled
|
||||
FROM sqlite_master
|
||||
WHERE type='trigger'";
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
$query.= ' AND LOWER(name)='.$db->quote(strtolower($trigger), 'text');
|
||||
} else {
|
||||
$query.= ' AND name='.$db->quote($trigger, 'text');
|
||||
}
|
||||
$types = array(
|
||||
'trigger_name' => 'text',
|
||||
'table_name' => 'text',
|
||||
'trigger_body' => 'text',
|
||||
'trigger_type' => 'text',
|
||||
'trigger_event' => 'text',
|
||||
'trigger_comment' => 'text',
|
||||
'trigger_enabled' => 'boolean',
|
||||
);
|
||||
$def = $db->queryRow($query, $types, MDB2_FETCHMODE_ASSOC);
|
||||
if (MDB2::isError($def)) {
|
||||
return $def;
|
||||
}
|
||||
if (empty($def)) {
|
||||
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
'it was not specified an existing trigger', __FUNCTION__);
|
||||
}
|
||||
if (preg_match("/^create\s+(?:temp|temporary)?trigger\s+(?:if\s+not\s+exists\s+)?.*(before|after)?\s+(insert|update|delete)/Uims", $def['trigger_body'], $tmp)) {
|
||||
$def['trigger_type'] = strtoupper($tmp[1]);
|
||||
$def['trigger_event'] = strtoupper($tmp[2]);
|
||||
}
|
||||
return $def;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ tableInfo()
|
||||
|
||||
/**
|
||||
* Returns information about a table
|
||||
*
|
||||
* @param string $result a string containing the name of a table
|
||||
* @param int $mode a valid tableInfo mode
|
||||
*
|
||||
* @return array an associative array with the information requested.
|
||||
* A MDB2_Error object on failure.
|
||||
*
|
||||
* @see MDB2_Driver_Common::tableInfo()
|
||||
* @since Method available since Release 1.7.0
|
||||
*/
|
||||
function tableInfo($result, $mode = null)
|
||||
{
|
||||
if (is_string($result)) {
|
||||
return parent::tableInfo($result, $mode);
|
||||
}
|
||||
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
return $db->raiseError(MDB2_ERROR_NOT_CAPABLE, null, null,
|
||||
'This DBMS can not obtain tableInfo from result sets', __FUNCTION__);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
653
extlib/MDB2/Driver/Reverse/sqlsrv.php
Normal file
653
extlib/MDB2/Driver/Reverse/sqlsrv.php
Normal file
@ -0,0 +1,653 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 and 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Copyright (c) 1998-2007 Manuel Lemos, Tomas V.V.Cox, |
|
||||
// | Stig. S. Bakken, Lukas Smith, Frank M. Kromann, Lorenzo Alberton |
|
||||
// | 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Authors: Lukas Smith <smith@pooteeweet.org> |
|
||||
// | Lorenzo Alberton <l.alberton@quipo.it> |
|
||||
// +----------------------------------------------------------------------+
|
||||
|
||||
require_once 'MDB2/Driver/Reverse/Common.php';
|
||||
|
||||
/**
|
||||
* MDB2 MSSQL driver for the schema reverse engineering module
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lukas Smith <smith@dybnet.de>
|
||||
* @author Lorenzo Alberton <l.alberton@quipo.it>
|
||||
*/
|
||||
class MDB2_Driver_Reverse_sqlsrv extends MDB2_Driver_Reverse_Common
|
||||
{
|
||||
// {{{ getTableFieldDefinition()
|
||||
|
||||
/**
|
||||
* Get the structure of a field into an array
|
||||
*
|
||||
* @param string $table_name name of table that should be used in method
|
||||
* @param string $field_name name of field that should be used in method
|
||||
* @return mixed data array on success, a MDB2 error on failure
|
||||
* @access public
|
||||
*/
|
||||
function getTableFieldDefinition($table_name, $field_name)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$result = $db->loadModule('Datatype', null, true);
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
list($schema, $table) = $this->splitTableSchema($table_name);
|
||||
|
||||
$table = $db->quoteIdentifier($table, true);
|
||||
$fldname = $db->quoteIdentifier($field_name, true);
|
||||
|
||||
$query = "SELECT t.table_name,
|
||||
c.column_name 'name',
|
||||
c.data_type 'type',
|
||||
CASE c.is_nullable WHEN 'YES' THEN 1 ELSE 0 END AS 'is_nullable',
|
||||
c.column_default,
|
||||
c.character_maximum_length 'length',
|
||||
c.numeric_precision,
|
||||
c.numeric_scale,
|
||||
c.character_set_name,
|
||||
c.collation_name
|
||||
FROM INFORMATION_SCHEMA.TABLES t,
|
||||
INFORMATION_SCHEMA.COLUMNS c
|
||||
WHERE t.table_name = c.table_name
|
||||
AND t.table_name = '$table'
|
||||
AND c.column_name = '$fldname'";
|
||||
if (!empty($schema)) {
|
||||
$query .= " AND t.table_schema = '" .$db->quoteIdentifier($schema, true) ."'";
|
||||
}
|
||||
$query .= ' ORDER BY t.table_name';
|
||||
$column = $db->queryRow($query, null, MDB2_FETCHMODE_ASSOC);
|
||||
if (MDB2::isError($column)) {
|
||||
return $column;
|
||||
}
|
||||
if (empty($column)) {
|
||||
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
'it was not specified an existing table column', __FUNCTION__);
|
||||
}
|
||||
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
if ($db->options['field_case'] == CASE_LOWER) {
|
||||
$column['name'] = strtolower($column['name']);
|
||||
} else {
|
||||
$column['name'] = strtoupper($column['name']);
|
||||
}
|
||||
} else {
|
||||
$column = array_change_key_case($column, $db->options['field_case']);
|
||||
}
|
||||
$mapped_datatype = $db->datatype->mapNativeDatatype($column);
|
||||
if (MDB2::isError($mapped_datatype)) {
|
||||
return $mapped_datatype;
|
||||
}
|
||||
list($types, $length, $unsigned, $fixed) = $mapped_datatype;
|
||||
$notnull = true;
|
||||
if ($column['is_nullable']) {
|
||||
$notnull = false;
|
||||
}
|
||||
$default = false;
|
||||
if (array_key_exists('column_default', $column)) {
|
||||
$default = $column['column_default'];
|
||||
if ((null === $default) && $notnull) {
|
||||
$default = '';
|
||||
} elseif (strlen($default) > 4
|
||||
&& substr($default, 0, 1) == '('
|
||||
&& substr($default, -1, 1) == ')'
|
||||
) {
|
||||
//mssql wraps the default value in parentheses: "((1234))", "(NULL)"
|
||||
$default = trim($default, '()');
|
||||
if ($default == 'NULL') {
|
||||
$default = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
$definition[0] = array(
|
||||
'notnull' => $notnull,
|
||||
'nativetype' => preg_replace('/^([a-z]+)[^a-z].*/i', '\\1', $column['type'])
|
||||
);
|
||||
if (null !== $length) {
|
||||
$definition[0]['length'] = $length;
|
||||
}
|
||||
if (null !== $unsigned) {
|
||||
$definition[0]['unsigned'] = $unsigned;
|
||||
}
|
||||
if (null !== $fixed) {
|
||||
$definition[0]['fixed'] = $fixed;
|
||||
}
|
||||
if ($default !== false) {
|
||||
$definition[0]['default'] = $default;
|
||||
}
|
||||
foreach ($types as $key => $type) {
|
||||
$definition[$key] = $definition[0];
|
||||
if ($type == 'clob' || $type == 'blob') {
|
||||
unset($definition[$key]['default']);
|
||||
}
|
||||
$definition[$key]['type'] = $type;
|
||||
$definition[$key]['mdb2type'] = $type;
|
||||
}
|
||||
return $definition;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ getTableIndexDefinition()
|
||||
|
||||
/**
|
||||
* Get the structure of an index into an array
|
||||
*
|
||||
* @param string $table_name name of table that should be used in method
|
||||
* @param string $index_name name of index that should be used in method
|
||||
* @return mixed data array on success, a MDB2 error on failure
|
||||
* @access public
|
||||
*/
|
||||
function getTableIndexDefinition($table_name, $index_name)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
list($schema, $table) = $this->splitTableSchema($table_name);
|
||||
|
||||
$table = $db->quoteIdentifier($table, true);
|
||||
//$idxname = $db->quoteIdentifier($index_name, true);
|
||||
|
||||
$query = "SELECT OBJECT_NAME(i.id) tablename,
|
||||
i.name indexname,
|
||||
c.name field_name,
|
||||
CASE INDEXKEY_PROPERTY(i.id, i.indid, ik.keyno, 'IsDescending')
|
||||
WHEN 1 THEN 'DESC' ELSE 'ASC'
|
||||
END 'collation',
|
||||
ik.keyno 'position'
|
||||
FROM sysindexes i
|
||||
JOIN sysindexkeys ik ON ik.id = i.id AND ik.indid = i.indid
|
||||
JOIN syscolumns c ON c.id = ik.id AND c.colid = ik.colid
|
||||
WHERE OBJECT_NAME(i.id) = '$table'
|
||||
AND i.name = '%s'
|
||||
AND NOT EXISTS (
|
||||
SELECT *
|
||||
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE k
|
||||
WHERE k.table_name = OBJECT_NAME(i.id)
|
||||
AND k.constraint_name = i.name";
|
||||
if (!empty($schema)) {
|
||||
$query .= " AND k.table_schema = '" .$db->quoteIdentifier($schema, true) ."'";
|
||||
}
|
||||
$query .= ')
|
||||
ORDER BY tablename, indexname, ik.keyno';
|
||||
|
||||
$index_name_mdb2 = $db->getIndexName($index_name);
|
||||
$result = $db->queryRow(sprintf($query, $index_name_mdb2));
|
||||
if (!MDB2::isError($result) && (null !== $result)) {
|
||||
// apply 'idxname_format' only if the query succeeded, otherwise
|
||||
// fallback to the given $index_name, without transformation
|
||||
$index_name = $index_name_mdb2;
|
||||
}
|
||||
$result = $db->query(sprintf($query, $index_name));
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$definition = array();
|
||||
while (is_array($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))) {
|
||||
$column_name = $row['field_name'];
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
if ($db->options['field_case'] == CASE_LOWER) {
|
||||
$column_name = strtolower($column_name);
|
||||
} else {
|
||||
$column_name = strtoupper($column_name);
|
||||
}
|
||||
}
|
||||
$definition['fields'][$column_name] = array(
|
||||
'position' => (int)$row['position'],
|
||||
);
|
||||
if (!empty($row['collation'])) {
|
||||
$definition['fields'][$column_name]['sorting'] = ($row['collation'] == 'ASC'
|
||||
? 'ascending' : 'descending');
|
||||
}
|
||||
}
|
||||
$result->free();
|
||||
if (empty($definition['fields'])) {
|
||||
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
'it was not specified an existing table index', __FUNCTION__);
|
||||
}
|
||||
return $definition;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ getTableConstraintDefinition()
|
||||
|
||||
/**
|
||||
* Get the structure of a constraint into an array
|
||||
*
|
||||
* @param string $table_name name of table that should be used in method
|
||||
* @param string $constraint_name name of constraint that should be used in method
|
||||
* @return mixed data array on success, a MDB2 error on failure
|
||||
* @access public
|
||||
*/
|
||||
function getTableConstraintDefinition($table_name, $constraint_name)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
list($schema, $table) = $this->splitTableSchema($table_name);
|
||||
|
||||
$table = $db->quoteIdentifier($table, true);
|
||||
$query = "SELECT k.table_name,
|
||||
k.column_name field_name,
|
||||
CASE c.constraint_type WHEN 'PRIMARY KEY' THEN 1 ELSE 0 END 'primary',
|
||||
CASE c.constraint_type WHEN 'UNIQUE' THEN 1 ELSE 0 END 'unique',
|
||||
CASE c.constraint_type WHEN 'FOREIGN KEY' THEN 1 ELSE 0 END 'foreign',
|
||||
CASE c.constraint_type WHEN 'CHECK' THEN 1 ELSE 0 END 'check',
|
||||
CASE c.is_deferrable WHEN 'NO' THEN 0 ELSE 1 END 'deferrable',
|
||||
CASE c.initially_deferred WHEN 'NO' THEN 0 ELSE 1 END 'initiallydeferred',
|
||||
rc.match_option 'match',
|
||||
rc.update_rule 'onupdate',
|
||||
rc.delete_rule 'ondelete',
|
||||
kcu.table_name 'references_table',
|
||||
kcu.column_name 'references_field',
|
||||
k.ordinal_position 'field_position'
|
||||
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE k
|
||||
LEFT JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS c
|
||||
ON k.table_name = c.table_name
|
||||
AND k.table_schema = c.table_schema
|
||||
AND k.table_catalog = c.table_catalog
|
||||
AND k.constraint_catalog = c.constraint_catalog
|
||||
AND k.constraint_name = c.constraint_name
|
||||
LEFT JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc
|
||||
ON rc.constraint_schema = c.constraint_schema
|
||||
AND rc.constraint_catalog = c.constraint_catalog
|
||||
AND rc.constraint_name = c.constraint_name
|
||||
LEFT JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu
|
||||
ON rc.unique_constraint_schema = kcu.constraint_schema
|
||||
AND rc.unique_constraint_catalog = kcu.constraint_catalog
|
||||
AND rc.unique_constraint_name = kcu.constraint_name
|
||||
AND k.ordinal_position = kcu.ordinal_position
|
||||
WHERE k.constraint_catalog = DB_NAME()
|
||||
AND k.table_name = '$table'
|
||||
AND k.constraint_name = '%s'";
|
||||
if (!empty($schema)) {
|
||||
$query .= " AND k.table_schema = '" .$db->quoteIdentifier($schema, true) ."'";
|
||||
}
|
||||
$query .= ' ORDER BY k.constraint_name,
|
||||
k.ordinal_position';
|
||||
|
||||
$constraint_name_mdb2 = $db->getIndexName($constraint_name);
|
||||
$result = $db->queryRow(sprintf($query, $constraint_name_mdb2));
|
||||
if (!MDB2::isError($result) && (null !== $result)) {
|
||||
// apply 'idxname_format' only if the query succeeded, otherwise
|
||||
// fallback to the given $index_name, without transformation
|
||||
$constraint_name = $constraint_name_mdb2;
|
||||
}
|
||||
$result = $db->query(sprintf($query, $constraint_name));
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$definition = array(
|
||||
'fields' => array()
|
||||
);
|
||||
while (is_array($row = $result->fetchRow(MDB2_FETCHMODE_ASSOC))) {
|
||||
$row = array_change_key_case($row, CASE_LOWER);
|
||||
$column_name = $row['field_name'];
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
if ($db->options['field_case'] == CASE_LOWER) {
|
||||
$column_name = strtolower($column_name);
|
||||
} else {
|
||||
$column_name = strtoupper($column_name);
|
||||
}
|
||||
}
|
||||
$definition['fields'][$column_name] = array(
|
||||
'position' => (int)$row['field_position']
|
||||
);
|
||||
if ($row['foreign']) {
|
||||
$ref_column_name = $row['references_field'];
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
if ($db->options['field_case'] == CASE_LOWER) {
|
||||
$ref_column_name = strtolower($ref_column_name);
|
||||
} else {
|
||||
$ref_column_name = strtoupper($ref_column_name);
|
||||
}
|
||||
}
|
||||
$definition['references']['table'] = $row['references_table'];
|
||||
$definition['references']['fields'][$ref_column_name] = array(
|
||||
'position' => (int)$row['field_position']
|
||||
);
|
||||
}
|
||||
//collation?!?
|
||||
/*
|
||||
if (!empty($row['collation'])) {
|
||||
$definition['fields'][$column_name]['sorting'] = ($row['collation'] == 'ASC'
|
||||
? 'ascending' : 'descending');
|
||||
}
|
||||
*/
|
||||
$lastrow = $row;
|
||||
// otherwise $row is no longer usable on exit from loop
|
||||
}
|
||||
$result->free();
|
||||
if (empty($definition['fields'])) {
|
||||
return $db->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
$constraint_name . ' is not an existing table constraint', __FUNCTION__);
|
||||
}
|
||||
|
||||
$definition['primary'] = (boolean)$lastrow['primary'];
|
||||
$definition['unique'] = (boolean)$lastrow['unique'];
|
||||
$definition['foreign'] = (boolean)$lastrow['foreign'];
|
||||
$definition['check'] = (boolean)$lastrow['check'];
|
||||
$definition['deferrable'] = (boolean)$lastrow['deferrable'];
|
||||
$definition['initiallydeferred'] = (boolean)$lastrow['initiallydeferred'];
|
||||
$definition['onupdate'] = $lastrow['onupdate'];
|
||||
$definition['ondelete'] = $lastrow['ondelete'];
|
||||
$definition['match'] = $lastrow['match'];
|
||||
|
||||
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
|
||||
* @access public
|
||||
*/
|
||||
function getTriggerDefinition($trigger)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$query = "SELECT sys1.name trigger_name,
|
||||
sys2.name table_name,
|
||||
c.text trigger_body,
|
||||
c.encrypted is_encripted,
|
||||
CASE
|
||||
WHEN OBJECTPROPERTY(sys1.id, 'ExecIsTriggerDisabled') = 1
|
||||
THEN 0 ELSE 1
|
||||
END trigger_enabled,
|
||||
CASE
|
||||
WHEN OBJECTPROPERTY(sys1.id, 'ExecIsInsertTrigger') = 1
|
||||
THEN 'INSERT'
|
||||
WHEN OBJECTPROPERTY(sys1.id, 'ExecIsUpdateTrigger') = 1
|
||||
THEN 'UPDATE'
|
||||
WHEN OBJECTPROPERTY(sys1.id, 'ExecIsDeleteTrigger') = 1
|
||||
THEN 'DELETE'
|
||||
END trigger_event,
|
||||
CASE WHEN OBJECTPROPERTY(sys1.id, 'ExecIsInsteadOfTrigger') = 1
|
||||
THEN 'INSTEAD OF' ELSE 'AFTER'
|
||||
END trigger_type,
|
||||
'' trigger_comment
|
||||
FROM sysobjects sys1
|
||||
JOIN sysobjects sys2 ON sys1.parent_obj = sys2.id
|
||||
JOIN syscomments c ON sys1.id = c.id
|
||||
WHERE sys1.xtype = 'TR'
|
||||
AND sys1.name = ". $db->quote($trigger, 'text');
|
||||
|
||||
$types = array(
|
||||
'trigger_name' => 'text',
|
||||
'table_name' => 'text',
|
||||
'trigger_body' => 'text',
|
||||
'trigger_type' => 'text',
|
||||
'trigger_event' => 'text',
|
||||
'trigger_comment' => 'text',
|
||||
'trigger_enabled' => 'boolean',
|
||||
'is_encripted' => 'boolean',
|
||||
);
|
||||
|
||||
$def = $db->queryRow($query, $types, MDB2_FETCHMODE_ASSOC);
|
||||
if (MDB2::isError($def)) {
|
||||
return $def;
|
||||
}
|
||||
$trg_body = $db->queryCol('EXEC sp_helptext '. $db->quote($trigger, 'text'), 'text');
|
||||
if (!MDB2::isError($trg_body)) {
|
||||
$def['trigger_body'] = implode(' ', $trg_body);
|
||||
}
|
||||
return $def;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ tableInfo()
|
||||
|
||||
/**
|
||||
* Returns information about a table or a result set
|
||||
*
|
||||
* NOTE: only supports 'table' and 'flags' if <var>$result</var>
|
||||
* is a table name.
|
||||
*
|
||||
* @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 a valid tableInfo mode
|
||||
*
|
||||
* @return array an associative array with the information requested.
|
||||
* A MDB2_Error object on failure.
|
||||
*
|
||||
* @see MDB2_Driver_Common::tableInfo()
|
||||
*/
|
||||
function tableInfo($result, $mode = null)
|
||||
{
|
||||
if (is_string($result)) {
|
||||
return parent::tableInfo($result, $mode);
|
||||
}
|
||||
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$resource = MDB2::isResultCommon($result) ? $result->getResource() : $result;
|
||||
if (!is_resource($resource)) {
|
||||
return $db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
|
||||
'Could not generate result resource', __FUNCTION__);
|
||||
}
|
||||
|
||||
if ($db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
if ($db->options['field_case'] == CASE_LOWER) {
|
||||
$case_func = 'strtolower';
|
||||
} else {
|
||||
$case_func = 'strtoupper';
|
||||
}
|
||||
} else {
|
||||
$case_func = 'strval';
|
||||
}
|
||||
|
||||
$meta = @sqlsrv_field_metadata($resource);
|
||||
$count = count($meta);
|
||||
$res = array();
|
||||
|
||||
if ($mode) {
|
||||
$res['num_fields'] = $count;
|
||||
}
|
||||
|
||||
$db->loadModule('Datatype', null, true);
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
$res[$i] = array(
|
||||
'table' => '',
|
||||
'name' => $case_func($meta[$i]['Name']),
|
||||
'type' => $meta[$i]['Type'],
|
||||
'length' => $meta[$i]['Size'],
|
||||
'numeric_precision' => $meta[$i]['Precision'],
|
||||
'numeric_scale' => $meta[$i]['Scale'],
|
||||
'flags' => ''
|
||||
);
|
||||
$mdb2type_info = $db->datatype->mapNativeDatatype($res[$i]);
|
||||
if (MDB2::isError($mdb2type_info)) {
|
||||
return $mdb2type_info;
|
||||
}
|
||||
$res[$i]['mdb2type'] = $mdb2type_info[0][0];
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _mssql_field_flags()
|
||||
|
||||
/**
|
||||
* Get a column's flags
|
||||
*
|
||||
* Supports "not_null", "primary_key",
|
||||
* "auto_increment" (mssql identity), "timestamp" (mssql timestamp),
|
||||
* "unique_key" (mssql unique index, unique check or primary_key) and
|
||||
* "multiple_key" (multikey index)
|
||||
*
|
||||
* mssql timestamp is NOT similar to the mysql timestamp so this is maybe
|
||||
* not useful at all - is the behaviour of mysql_field_flags that primary
|
||||
* keys are alway unique? is the interpretation of multiple_key correct?
|
||||
*
|
||||
* @param string $table the table name
|
||||
* @param string $column the field name
|
||||
*
|
||||
* @return string the flags
|
||||
*
|
||||
* @access protected
|
||||
* @author Joern Barthel <j_barthel@web.de>
|
||||
*/
|
||||
function _mssql_field_flags($table, $column)
|
||||
{
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
static $tableName = null;
|
||||
static $flags = array();
|
||||
|
||||
if ($table != $tableName) {
|
||||
|
||||
$flags = array();
|
||||
$tableName = $table;
|
||||
|
||||
// get unique and primary keys
|
||||
$res = $db->queryAll("EXEC SP_HELPINDEX[$table]", null, MDB2_FETCHMODE_ASSOC);
|
||||
|
||||
foreach ($res as $val) {
|
||||
$val = array_change_key_case($val, CASE_LOWER);
|
||||
$keys = explode(', ', $val['index_keys']);
|
||||
|
||||
if (sizeof($keys) > 1) {
|
||||
foreach ($keys as $key) {
|
||||
$this->_add_flag($flags[$key], 'multiple_key');
|
||||
}
|
||||
}
|
||||
|
||||
if (strpos($val['index_description'], 'primary key')) {
|
||||
foreach ($keys as $key) {
|
||||
$this->_add_flag($flags[$key], 'primary_key');
|
||||
}
|
||||
} elseif (strpos($val['index_description'], 'unique')) {
|
||||
foreach ($keys as $key) {
|
||||
$this->_add_flag($flags[$key], 'unique_key');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get auto_increment, not_null and timestamp
|
||||
$res = $db->queryAll("EXEC SP_COLUMNS[$table]", null, MDB2_FETCHMODE_ASSOC);
|
||||
|
||||
foreach ($res as $val) {
|
||||
$val = array_change_key_case($val, CASE_LOWER);
|
||||
if ($val['nullable'] == '0') {
|
||||
$this->_add_flag($flags[$val['column_name']], 'not_null');
|
||||
}
|
||||
if (strpos($val['type_name'], 'identity')) {
|
||||
$this->_add_flag($flags[$val['column_name']], 'auto_increment');
|
||||
}
|
||||
if (strpos($val['type_name'], 'timestamp')) {
|
||||
$this->_add_flag($flags[$val['column_name']], 'timestamp');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($flags[$column])) {
|
||||
return(implode(' ', $flags[$column]));
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _add_flag()
|
||||
|
||||
/**
|
||||
* Adds a string to the flags array if the flag is not yet in there
|
||||
* - if there is no flag present the array is created
|
||||
*
|
||||
* @param array &$array the reference to the flag-array
|
||||
* @param string $value the flag value
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @access protected
|
||||
* @author Joern Barthel <j_barthel@web.de>
|
||||
*/
|
||||
function _add_flag(&$array, $value)
|
||||
{
|
||||
if (!is_array($array)) {
|
||||
$array = array($value);
|
||||
} elseif (!in_array($value, $array)) {
|
||||
array_push($array, $value);
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
}
|
||||
?>
|
914
extlib/MDB2/Driver/fbsql.php
Normal file
914
extlib/MDB2/Driver/fbsql.php
Normal file
@ -0,0 +1,914 @@
|
||||
<?php
|
||||
// vim: set et ts=4 sw=4 fdm=marker:
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 and 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Copyright (c) 1998-2006 Manuel Lemos, Tomas V.V.Cox, |
|
||||
// | Stig. S. Bakken, Lukas Smith, Frank M. Kromann |
|
||||
// | 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Author: Lukas Smith <smith@pooteeweet.org> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
|
||||
/**
|
||||
* MDB2 FrontBase driver
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lukas Smith <smith@pooteeweet.org>
|
||||
* @author Frank M. Kromann <frank@kromann.info>
|
||||
*/
|
||||
class MDB2_Driver_fbsql extends MDB2_Driver_Common
|
||||
{
|
||||
// {{{ properties
|
||||
var $string_quoting = array('start' => "'", 'end' => "'", 'escape' => "'", 'escape_pattern' => false);
|
||||
|
||||
var $identifier_quoting = array('start' => '"', 'end' => '"', 'escape' => '"');
|
||||
// }}}
|
||||
// {{{ constructor
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->phptype = 'fbsql';
|
||||
$this->dbsyntax = 'fbsql';
|
||||
|
||||
$this->supported['sequences'] = 'emulated';
|
||||
$this->supported['indexes'] = true;
|
||||
$this->supported['affected_rows'] = true;
|
||||
$this->supported['transactions'] = true;
|
||||
$this->supported['savepoints'] = false;
|
||||
$this->supported['summary_functions'] = true;
|
||||
$this->supported['order_by_text'] = true;
|
||||
$this->supported['current_id'] = 'emulated';
|
||||
$this->supported['limit_queries'] = 'emulated';
|
||||
$this->supported['LOBs'] = true;
|
||||
$this->supported['replace'] ='emulated';
|
||||
$this->supported['sub_selects'] = true;
|
||||
$this->supported['auto_increment'] = false; // not implemented
|
||||
$this->supported['primary_key'] = true;
|
||||
$this->supported['result_introspection'] = true;
|
||||
$this->supported['prepared_statements'] = 'emulated';
|
||||
$this->supported['identifier_quoting'] = true;
|
||||
$this->supported['pattern_escaping'] = false;
|
||||
$this->supported['new_link'] = false;
|
||||
|
||||
$this->options['DBA_username'] = false;
|
||||
$this->options['DBA_password'] = false;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ errorInfo()
|
||||
|
||||
/**
|
||||
* This method is used to collect information about an error
|
||||
*
|
||||
* @param integer $error
|
||||
* @return array
|
||||
* @access public
|
||||
*/
|
||||
function errorInfo($error = null)
|
||||
{
|
||||
if ($this->connection) {
|
||||
$native_code = @fbsql_errno($this->connection);
|
||||
$native_msg = @fbsql_error($this->connection);
|
||||
} else {
|
||||
$native_code = @fbsql_errno();
|
||||
$native_msg = @fbsql_error();
|
||||
}
|
||||
if (null === $error) {
|
||||
static $ecode_map;
|
||||
if (empty($ecode_map)) {
|
||||
$ecode_map = array(
|
||||
22 => MDB2_ERROR_SYNTAX,
|
||||
85 => MDB2_ERROR_ALREADY_EXISTS,
|
||||
108 => MDB2_ERROR_SYNTAX,
|
||||
116 => MDB2_ERROR_NOSUCHTABLE,
|
||||
124 => MDB2_ERROR_VALUE_COUNT_ON_ROW,
|
||||
215 => MDB2_ERROR_NOSUCHFIELD,
|
||||
217 => MDB2_ERROR_INVALID_NUMBER,
|
||||
226 => MDB2_ERROR_NOSUCHFIELD,
|
||||
231 => MDB2_ERROR_INVALID,
|
||||
239 => MDB2_ERROR_TRUNCATED,
|
||||
251 => MDB2_ERROR_SYNTAX,
|
||||
266 => MDB2_ERROR_NOT_FOUND,
|
||||
357 => MDB2_ERROR_CONSTRAINT_NOT_NULL,
|
||||
358 => MDB2_ERROR_CONSTRAINT,
|
||||
360 => MDB2_ERROR_CONSTRAINT,
|
||||
361 => MDB2_ERROR_CONSTRAINT,
|
||||
);
|
||||
}
|
||||
if (isset($ecode_map[$native_code])) {
|
||||
$error = $ecode_map[$native_code];
|
||||
}
|
||||
}
|
||||
return array($error, $native_code, $native_msg);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ beginTransaction()
|
||||
|
||||
/**
|
||||
* 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/savepoint', __FUNCTION__, array('is_manip' => true, 'savepoint' => $savepoint));
|
||||
if (null !== $savepoint) {
|
||||
return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
|
||||
'savepoints are not supported', __FUNCTION__);
|
||||
}
|
||||
if ($this->in_transaction) {
|
||||
return MDB2_OK; //nothing to do
|
||||
}
|
||||
if (!$this->destructor_registered && $this->opened_persistent) {
|
||||
$this->destructor_registered = true;
|
||||
register_shutdown_function('MDB2_closeOpenTransactions');
|
||||
}
|
||||
$result =& $this->_doQuery('SET COMMIT FALSE;', true);
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
$this->in_transaction = true;
|
||||
return MDB2_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ commit()
|
||||
|
||||
/**
|
||||
* 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));
|
||||
if (!$this->in_transaction) {
|
||||
return $this->raiseError(MDB2_ERROR_INVALID, null, null,
|
||||
'commit/release savepoint cannot be done changes are auto committed', __FUNCTION__);
|
||||
}
|
||||
if (null !== $savepoint) {
|
||||
return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
|
||||
'savepoints are not supported', __FUNCTION__);
|
||||
}
|
||||
|
||||
$result =& $this->_doQuery('COMMIT;', true);
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
$result =& $this->_doQuery('SET COMMIT TRUE;', true);
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
$this->in_transaction = false;
|
||||
return MDB2_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{
|
||||
|
||||
/**
|
||||
* 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));
|
||||
if (!$this->in_transaction) {
|
||||
return $this->raiseError(MDB2_ERROR_INVALID, null, null,
|
||||
'rollback cannot be done changes are auto committed', __FUNCTION__);
|
||||
}
|
||||
if (null !== $savepoint) {
|
||||
return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
|
||||
'savepoints are not supported', __FUNCTION__);
|
||||
}
|
||||
|
||||
$result =& $this->_doQuery('ROLLBACK;', true);
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
$result =& $this->_doQuery('SET COMMIT TRUE;', true);
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
$this->in_transaction = false;
|
||||
return MDB2_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _doConnect()
|
||||
|
||||
/**
|
||||
* do the grunt work of the connect
|
||||
*
|
||||
* @return connection on success or MDB2 Error Object on failure
|
||||
* @access protected
|
||||
*/
|
||||
function _doConnect($username, $password, $persistent = false)
|
||||
{
|
||||
if (!extension_loaded($this->phptype)) {
|
||||
return $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
'extension '.$this->phptype.' is not compiled into PHP', __FUNCTION__);
|
||||
}
|
||||
|
||||
$params = array(
|
||||
$this->dsn['hostspec'] ? $this->dsn['hostspec'] : 'localhost',
|
||||
$username ? $username : null,
|
||||
$password ? $password : null,
|
||||
);
|
||||
|
||||
$connect_function = $persistent ? 'fbsql_pconnect' : 'fbsql_connect';
|
||||
|
||||
$connection = @call_user_func_array($connect_function, $params);
|
||||
if ($connection <= 0) {
|
||||
return $this->raiseError(MDB2_ERROR_CONNECT_FAILED, null, null,
|
||||
'unable to establish a connection', __FUNCTION__);
|
||||
}
|
||||
|
||||
if (!empty($this->dsn['charset'])) {
|
||||
$result = $this->setCharset($this->dsn['charset'], $connection);
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
return $connection;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ connect()
|
||||
|
||||
/**
|
||||
* Connect to the database
|
||||
*
|
||||
* @return true on success, MDB2 Error Object on failure
|
||||
**/
|
||||
function connect()
|
||||
{
|
||||
if (is_resource($this->connection)) {
|
||||
//if (count(array_diff($this->connected_dsn, $this->dsn)) == 0
|
||||
if (MDB2::areEquals($this->connected_dsn, $this->dsn)
|
||||
&& $this->opened_persistent == $this->options['persistent']
|
||||
) {
|
||||
return MDB2_OK;
|
||||
}
|
||||
$this->disconnect(false);
|
||||
}
|
||||
|
||||
$connection = $this->_doConnect($this->dsn['username'],
|
||||
$this->dsn['password'],
|
||||
$this->options['persistent']);
|
||||
if (MDB2::isError($connection)) {
|
||||
return $connection;
|
||||
}
|
||||
|
||||
$this->connection = $connection;
|
||||
$this->connected_dsn = $this->dsn;
|
||||
$this->connected_database_name = '';
|
||||
$this->opened_persistent = $this->options['persistent'];
|
||||
$this->dbsyntax = $this->dsn['dbsyntax'] ? $this->dsn['dbsyntax'] : $this->phptype;
|
||||
|
||||
if ($this->database_name) {
|
||||
if ($this->database_name != $this->connected_database_name) {
|
||||
if (!@fbsql_select_db($this->database_name, $connection)) {
|
||||
$err = $this->raiseError(null, null, null,
|
||||
'Could not select the database: '.$this->database_name, __FUNCTION__);
|
||||
return $err;
|
||||
}
|
||||
$this->connected_database_name = $this->database_name;
|
||||
}
|
||||
}
|
||||
|
||||
return MDB2_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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)
|
||||
{
|
||||
$connection = $this->_doConnect($this->dsn['username'],
|
||||
$this->dsn['password'],
|
||||
$this->options['persistent']);
|
||||
if (MDB2::isError($connection)) {
|
||||
return $connection;
|
||||
}
|
||||
|
||||
$result = @fbsql_select_db($name, $connection);
|
||||
@fbsql_close($connection);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ disconnect()
|
||||
|
||||
/**
|
||||
* Log out and disconnect from the database.
|
||||
*
|
||||
* @param boolean $force 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)
|
||||
{
|
||||
if (is_resource($this->connection)) {
|
||||
if ($this->in_transaction) {
|
||||
$dsn = $this->dsn;
|
||||
$database_name = $this->database_name;
|
||||
$persistent = $this->options['persistent'];
|
||||
$this->dsn = $this->connected_dsn;
|
||||
$this->database_name = $this->connected_database_name;
|
||||
$this->options['persistent'] = $this->opened_persistent;
|
||||
$this->rollback();
|
||||
$this->dsn = $dsn;
|
||||
$this->database_name = $database_name;
|
||||
$this->options['persistent'] = $persistent;
|
||||
}
|
||||
|
||||
if (!$this->opened_persistent || $force) {
|
||||
@fbsql_close($this->connection);
|
||||
}
|
||||
}
|
||||
return parent::disconnect($force);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ standaloneQuery()
|
||||
|
||||
/**
|
||||
* execute a query as DBA
|
||||
*
|
||||
* @param string $query the SQL query
|
||||
* @param mixed $types array that contains the types of the columns in
|
||||
* the result set
|
||||
* @param boolean $is_manip 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)
|
||||
{
|
||||
$user = $this->options['DBA_username']? $this->options['DBA_username'] : $this->dsn['username'];
|
||||
$pass = $this->options['DBA_password']? $this->options['DBA_password'] : $this->dsn['password'];
|
||||
$connection = $this->_doConnect($user, $pass, $this->options['persistent']);
|
||||
if (MDB2::isError($connection)) {
|
||||
return $connection;
|
||||
}
|
||||
|
||||
$offset = $this->offset;
|
||||
$limit = $this->limit;
|
||||
$this->offset = $this->limit = 0;
|
||||
$query = $this->_modifyQuery($query, $is_manip, $limit, $offset);
|
||||
|
||||
$result =& $this->_doQuery($query, $is_manip, $connection, $this->database_name);
|
||||
if (!MDB2::isError($result)) {
|
||||
$result = $this->_affectedRows($connection, $result);
|
||||
}
|
||||
|
||||
@fbsql_close($connection);
|
||||
return $result;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _doQuery()
|
||||
|
||||
/**
|
||||
* Execute a query
|
||||
* @param string $query query
|
||||
* @param boolean $is_manip if the query is a manipulation query
|
||||
* @param resource $connection
|
||||
* @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 (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
$query = $result;
|
||||
}
|
||||
if ($this->options['disable_query']) {
|
||||
$result = $is_manip ? 0 : null;
|
||||
return $result;
|
||||
}
|
||||
|
||||
if (null === $connection) {
|
||||
$connection = $this->getConnection();
|
||||
if (MDB2::isError($connection)) {
|
||||
return $connection;
|
||||
}
|
||||
}
|
||||
if (null === $database_name) {
|
||||
$database_name = $this->database_name;
|
||||
}
|
||||
|
||||
if ($database_name) {
|
||||
if ($database_name != $this->connected_database_name) {
|
||||
if (!@fbsql_select_db($database_name, $connection)) {
|
||||
$err = $this->raiseError(null, null, null,
|
||||
'Could not select the database: '.$database_name, __FUNCTION__);
|
||||
return $err;
|
||||
}
|
||||
$this->connected_database_name = $database_name;
|
||||
}
|
||||
}
|
||||
|
||||
$result = @fbsql_query($query, $connection);
|
||||
if (!$result) {
|
||||
$err =& $this->raiseError(null, null, null,
|
||||
'Could not execute statement', __FUNCTION__);
|
||||
return $err;
|
||||
}
|
||||
|
||||
$this->debug($query, 'query', array('is_manip' => $is_manip, 'when' => 'post', 'result' => $result));
|
||||
return $result;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _affectedRows()
|
||||
|
||||
/**
|
||||
* Returns the number of rows affected
|
||||
*
|
||||
* @param resource $result
|
||||
* @param resource $connection
|
||||
* @return mixed MDB2 Error Object or the number of rows affected
|
||||
* @access private
|
||||
*/
|
||||
function _affectedRows($connection, $result = null)
|
||||
{
|
||||
if (null === $connection) {
|
||||
$connection = $this->getConnection();
|
||||
if (MDB2::isError($connection)) {
|
||||
return $connection;
|
||||
}
|
||||
}
|
||||
return @fbsql_affected_rows($connection);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _modifyQuery()
|
||||
|
||||
/**
|
||||
* Changes a query string for various DBMS specific reasons
|
||||
*
|
||||
* @param string $query query to modify
|
||||
* @param boolean $is_manip if it is a DML query
|
||||
* @param integer $limit limit the number of rows
|
||||
* @param integer $offset start reading from given offset
|
||||
* @return string modified query
|
||||
* @access protected
|
||||
*/
|
||||
function _modifyQuery($query, $is_manip, $limit, $offset)
|
||||
{
|
||||
if ($limit > 0) {
|
||||
if ($is_manip) {
|
||||
return preg_replace('/^([\s(])*SELECT(?!\s*TOP\s*\()/i',
|
||||
"\\1SELECT TOP($limit)", $query);
|
||||
} else {
|
||||
return preg_replace('/([\s(])*SELECT(?!\s*TOP\s*\()/i',
|
||||
"\\1SELECT TOP($offset,$limit)", $query);
|
||||
}
|
||||
}
|
||||
// Add ; to the end of the query. This is required by FrontBase
|
||||
return $query.';';
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ nextID()
|
||||
|
||||
/**
|
||||
* Returns the next free id of a sequence
|
||||
*
|
||||
* @param string $seq_name name of the sequence
|
||||
* @param boolean $ondemand when true the sequence is
|
||||
* automatic created, if it
|
||||
* not exists
|
||||
*
|
||||
* @return mixed MDB2 Error Object or id
|
||||
* @access public
|
||||
*/
|
||||
function nextID($seq_name, $ondemand = true)
|
||||
{
|
||||
$sequence_name = $this->quoteIdentifier($this->getSequenceName($seq_name), true);
|
||||
$seqcol_name = $this->quoteIdentifier($this->options['seqcol_name'], true);
|
||||
$query = "INSERT INTO $sequence_name ($seqcol_name) VALUES (NULL);";
|
||||
$this->pushErrorHandling(PEAR_ERROR_RETURN);
|
||||
$this->expectError(MDB2_ERROR_NOSUCHTABLE);
|
||||
$result =& $this->_doQuery($query, true);
|
||||
$this->popExpect();
|
||||
$this->popErrorHandling();
|
||||
if (MDB2::isError($result)) {
|
||||
if ($ondemand && $result->getCode() == MDB2_ERROR_NOSUCHTABLE) {
|
||||
$this->loadModule('Manager', null, true);
|
||||
$result = $this->manager->createSequence($seq_name);
|
||||
if (MDB2::isError($result)) {
|
||||
return $this->raiseError($result, null, null,
|
||||
'on demand sequence '.$seq_name.' could not be created', __FUNCTION__);
|
||||
} else {
|
||||
return $this->nextID($seq_name, false);
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
$value = $this->lastInsertID();
|
||||
if (is_numeric($value)) {
|
||||
$query = "DELETE FROM $sequence_name WHERE $seqcol_name < $value";
|
||||
$result =& $this->_doQuery($query, true);
|
||||
if (MDB2::isError($result)) {
|
||||
$this->warnings[] = 'nextID: could not delete previous sequence table values from '.$seq_name;
|
||||
}
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ lastInsertID()
|
||||
|
||||
/**
|
||||
* Returns the autoincrement ID if supported or $id or fetches the current
|
||||
* ID in a sequence called: $table.(empty($field) ? '' : '_'.$field)
|
||||
*
|
||||
* @param string $table name of the table into which a new row was inserted
|
||||
* @param string $field 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)
|
||||
{
|
||||
$connection = $this->getConnection();
|
||||
if (MDB2::isError($connection)) {
|
||||
return $connection;
|
||||
}
|
||||
$value = @fbsql_insert_id($connection);
|
||||
if (!$value) {
|
||||
return $this->raiseError(null, null, null,
|
||||
'Could not get last insert ID', __FUNCTION__);
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ currID()
|
||||
|
||||
/**
|
||||
* Returns the current id of a sequence
|
||||
*
|
||||
* @param string $seq_name name of the sequence
|
||||
* @return mixed MDB2 Error Object or id
|
||||
* @access public
|
||||
*/
|
||||
function currID($seq_name)
|
||||
{
|
||||
$sequence_name = $this->quoteIdentifier($this->getSequenceName($seq_name), true);
|
||||
$seqcol_name = $this->quoteIdentifier($this->options['seqcol_name'], true);
|
||||
$query = "SELECT MAX($seqcol_name) FROM $sequence_name";
|
||||
return $this->queryOne($query, 'integer');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* MDB2 FrontbaseSQL result driver
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lukas Smith <smith@pooteeweet.org>
|
||||
*/
|
||||
class MDB2_Result_fbsql extends MDB2_Result_Common
|
||||
{
|
||||
// }}}
|
||||
// {{{ fetchRow()
|
||||
|
||||
/**
|
||||
* Fetch a row and insert the data into an existing array.
|
||||
*
|
||||
* @param int $fetchmode how the array data should be indexed
|
||||
* @param int $rownum 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)
|
||||
{
|
||||
if (null !== $rownum) {
|
||||
$seek = $this->seek($rownum);
|
||||
if (MDB2::isError($seek)) {
|
||||
return $seek;
|
||||
}
|
||||
}
|
||||
if ($fetchmode == MDB2_FETCHMODE_DEFAULT) {
|
||||
$fetchmode = $this->db->fetchmode;
|
||||
}
|
||||
if ( $fetchmode == MDB2_FETCHMODE_ASSOC
|
||||
|| $fetchmode == MDB2_FETCHMODE_OBJECT
|
||||
) {
|
||||
$row = @fbsql_fetch_assoc($this->result);
|
||||
if (is_array($row)
|
||||
&& $this->db->options['portability'] & MDB2_PORTABILITY_FIX_CASE
|
||||
) {
|
||||
$row = array_change_key_case($row, $this->db->options['field_case']);
|
||||
}
|
||||
} else {
|
||||
$row = @fbsql_fetch_row($this->result);
|
||||
}
|
||||
if (!$row) {
|
||||
if (false === $this->result) {
|
||||
$err =& $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
|
||||
'resultset has already been freed', __FUNCTION__);
|
||||
return $err;
|
||||
}
|
||||
$null = null;
|
||||
return $null;
|
||||
}
|
||||
$mode = $this->db->options['portability'] & MDB2_PORTABILITY_EMPTY_TO_NULL;
|
||||
if ($mode) {
|
||||
$this->db->_fixResultArrayValues($row, $mode);
|
||||
}
|
||||
if (($fetchmode != MDB2_FETCHMODE_ASSOC) && !empty($this->types)) {
|
||||
$row = $this->db->datatype->convertResultRow($this->types, $row, $rtrim);
|
||||
} elseif (($fetchmode == MDB2_FETCHMODE_ASSOC) && !empty($this->types_assoc)) {
|
||||
$row = $this->db->datatype->convertResultRow($this->types_assoc, $row, $rtrim);
|
||||
}
|
||||
if (!empty($this->values)) {
|
||||
$this->_assignBindColumns($row);
|
||||
}
|
||||
if ($fetchmode === MDB2_FETCHMODE_OBJECT) {
|
||||
$object_class = $this->db->options['fetch_class'];
|
||||
if ($object_class == 'stdClass') {
|
||||
$row = (object) $row;
|
||||
} else {
|
||||
$row = new $object_class($row);
|
||||
}
|
||||
}
|
||||
++$this->rownum;
|
||||
return $row;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _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()
|
||||
{
|
||||
$columns = array();
|
||||
$numcols = $this->numCols();
|
||||
if (MDB2::isError($numcols)) {
|
||||
return $numcols;
|
||||
}
|
||||
for ($column = 0; $column < $numcols; $column++) {
|
||||
$column_name = @fbsql_field_name($this->result, $column);
|
||||
$columns[$column_name] = $column;
|
||||
}
|
||||
if ($this->db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
$columns = array_change_key_case($columns, $this->db->options['field_case']);
|
||||
}
|
||||
return $columns;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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()
|
||||
{
|
||||
$cols = @fbsql_num_fields($this->result);
|
||||
if (null === $cols) {
|
||||
if (false === $this->result) {
|
||||
return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
|
||||
'resultset has already been freed', __FUNCTION__);
|
||||
}
|
||||
if (null === $this->result) {
|
||||
return count($this->types);
|
||||
}
|
||||
return $this->db->raiseError(null, null, null,
|
||||
'Could not get column count', __FUNCTION__);
|
||||
}
|
||||
return $cols;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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()
|
||||
{
|
||||
if (false === $this->result) {
|
||||
return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
|
||||
'resultset has already been freed', __FUNCTION__);
|
||||
}
|
||||
if (null === $this->result) {
|
||||
return false;
|
||||
}
|
||||
return @fbsql_next_result($this->result);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ free()
|
||||
|
||||
/**
|
||||
* Free the internal resources associated with result.
|
||||
*
|
||||
* @return boolean true on success, false if result is invalid
|
||||
* @access public
|
||||
*/
|
||||
function free()
|
||||
{
|
||||
if (is_resource($this->result) && $this->db->connection) {
|
||||
$free = @fbsql_free_result($this->result);
|
||||
if (false === $free) {
|
||||
return $this->db->raiseError(null, null, null,
|
||||
'Could not free result', __FUNCTION__);
|
||||
}
|
||||
}
|
||||
$this->result = false;
|
||||
return MDB2_OK;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* MDB2 FrontbaseSQL buffered result driver
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lukas Smith <smith@pooteeweet.org>
|
||||
*/
|
||||
|
||||
class MDB2_BufferedResult_fbsql extends MDB2_Result_fbsql
|
||||
{
|
||||
// }}}
|
||||
// {{{ seek()
|
||||
|
||||
/**
|
||||
* Seek to a specific row in a result set
|
||||
*
|
||||
* @param int $rownum 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)
|
||||
{
|
||||
if ($this->rownum != ($rownum - 1) && !@fbsql_data_seek($this->result, $rownum)) {
|
||||
if (false === $this->result) {
|
||||
return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
|
||||
'resultset has already been freed', __FUNCTION__);
|
||||
}
|
||||
if (null === $this->result) {
|
||||
return MDB2_OK;
|
||||
}
|
||||
return $this->db->raiseError(MDB2_ERROR_INVALID, null, null,
|
||||
'tried to seek to an invalid row number ('.$rownum.')', __FUNCTION__);
|
||||
}
|
||||
$this->rownum = $rownum - 1;
|
||||
return MDB2_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ valid()
|
||||
|
||||
/**
|
||||
* Check if the end of the result set has been reached
|
||||
*
|
||||
* @return mixed true or false on sucess, a MDB2 error on failure
|
||||
* @access public
|
||||
*/
|
||||
function valid()
|
||||
{
|
||||
$numrows = $this->numRows();
|
||||
if (MDB2::isError($numrows)) {
|
||||
return $numrows;
|
||||
}
|
||||
return $this->rownum < ($numrows - 1);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ numRows()
|
||||
|
||||
/**
|
||||
* Returns the number of rows in a result object
|
||||
*
|
||||
* @return mixed MDB2 Error Object or the number of rows
|
||||
* @access public
|
||||
*/
|
||||
function numRows()
|
||||
{
|
||||
$rows = @fbsql_num_rows($this->result);
|
||||
if (null === $rows) {
|
||||
if (false === $this->result) {
|
||||
return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
|
||||
'resultset has already been freed', __FUNCTION__);
|
||||
}
|
||||
if (null === $this->result) {
|
||||
return 0;
|
||||
}
|
||||
return $this->db->raiseError(null, null, null,
|
||||
'Could not get row count', __FUNCTION__);
|
||||
}
|
||||
return $rows;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* MDB2 FrontbaseSQL statement driver
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lukas Smith <smith@pooteeweet.org>
|
||||
*/
|
||||
|
||||
class MDB2_Statement_fbsql extends MDB2_Statement_Common
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
?>
|
1575
extlib/MDB2/Driver/ibase.php
Normal file
1575
extlib/MDB2/Driver/ibase.php
Normal file
File diff suppressed because it is too large
Load Diff
1182
extlib/MDB2/Driver/mssql.php
Normal file
1182
extlib/MDB2/Driver/mssql.php
Normal file
File diff suppressed because it is too large
Load Diff
1906
extlib/MDB2/Driver/mysqli.php
Normal file
1906
extlib/MDB2/Driver/mysqli.php
Normal file
File diff suppressed because it is too large
Load Diff
1667
extlib/MDB2/Driver/oci8.php
Normal file
1667
extlib/MDB2/Driver/oci8.php
Normal file
File diff suppressed because it is too large
Load Diff
1142
extlib/MDB2/Driver/odbc.php
Normal file
1142
extlib/MDB2/Driver/odbc.php
Normal file
File diff suppressed because it is too large
Load Diff
1584
extlib/MDB2/Driver/pgsql.php
Normal file
1584
extlib/MDB2/Driver/pgsql.php
Normal file
File diff suppressed because it is too large
Load Diff
824
extlib/MDB2/Driver/querysim.php
Normal file
824
extlib/MDB2/Driver/querysim.php
Normal file
@ -0,0 +1,824 @@
|
||||
<?php
|
||||
// vim: set et ts=4 sw=4 fdm=marker:
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 and 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Original QuerySim Concept & ColdFusion Author: Hal Helms |
|
||||
// | <hal.helms@teamallaire.com> |
|
||||
// | Bert Dawson <bdawson@redbanner.com> |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Original PHP Author: Alan Richmond <arichmond@bigfoot.com> |
|
||||
// | David Huyck <b@bombusbee.com> |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Special note concerning code documentation: |
|
||||
// | QuerySim was originally created for use during development of |
|
||||
// | applications built using the Fusebox framework. (www.fusebox.org) |
|
||||
// | Fusebox uses an XML style of documentation called Fusedoc. (Which |
|
||||
// | is admittedly not well suited to documenting classes and functions. |
|
||||
// | This short-coming is being addressed by the Fusebox community.) PEAR |
|
||||
// | uses a Javadoc style of documentation called PHPDoc. (www.phpdoc.de) |
|
||||
// | Since this class extension spans two groups of users, it is asked |
|
||||
// | that the members of each respect the documentation standard of the |
|
||||
// | other. So it is a further requirement that both documentation |
|
||||
// | standards be included and maintained. If assistance is required |
|
||||
// | please contact Alan Richmond. |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
|
||||
/*
|
||||
<fusedoc fuse="querysim.php" language="PHP">
|
||||
<responsibilities>
|
||||
I take information and turn it into a recordset that can be accessed
|
||||
through the PEAR MDB2 API. Based on Hal Helms' QuerySim.cfm ColdFusion
|
||||
custom tag available at halhelms.com.
|
||||
</responsibilities>
|
||||
<properties>
|
||||
<property name="API" value="PEAR MDB2" />
|
||||
<property name="version" value="0.2.1" />
|
||||
<property name="status" value="beta" />
|
||||
<history author="Hal Helms" email="hal.helms@teamallaire.com" type="Create" />
|
||||
<history author="Bert Dawson" email="bdawson@redbanner.com" type="Update">
|
||||
Extensive revision that is backwardly compatible but eliminates the
|
||||
need for a separate .sim file.
|
||||
</history>
|
||||
<history author="Alan Richmond" email="arichmond@bigfoot.com" type="Create" date="10-July-2002">
|
||||
Rewrote in PHP as an extention to the PEAR DB API.
|
||||
Functions supported:
|
||||
connect, disconnect, query, fetchRow, freeResult,
|
||||
numCols, numRows, getSpecialQuery
|
||||
David Huyck (bombusbee.com) added ability to escape special
|
||||
characters (i.e., delimiters) using a '\'.
|
||||
Extended PEAR DB options[] for adding incoming parameters. Added
|
||||
options: columnDelim, dataDelim, eolDelim
|
||||
</history>
|
||||
<history author="David Huyck" email="b@bombusbee.com" type="Update" date="19-July-2002">
|
||||
Added the ability to set the QuerySim options at runtime.
|
||||
Default options are:
|
||||
'columnDelim' => ',', // Commas split the column names
|
||||
'dataDelim' => '|', // Pipes split the data fields
|
||||
'eolDelim' => chr(13).chr(10) // Carriage returns split the
|
||||
// lines of data
|
||||
Affected functions are:
|
||||
DB_querysim(): set the default options when the
|
||||
constructor method is called
|
||||
_parseQuerySim($query): altered the parsing of lines, column
|
||||
names, and data fields
|
||||
_empty2null: altered the way this function is called
|
||||
to simplify calling it
|
||||
</history>
|
||||
<history author="Alan Richmond" email="arichmond@bigfoot.com" type="Update" date="24-July-2002">
|
||||
Added error catching for malformed QuerySim text.
|
||||
Bug fix _empty2null(): altered version was returning unmodified
|
||||
lineData.
|
||||
Cleanup:
|
||||
PEAR compliant formatting, finished PHPDocs and added 'out' to
|
||||
Fusedoc 'io'.
|
||||
Broke up _parseQuerySim() into _buildResult() and _parseOnDelim()
|
||||
to containerize duplicate parse code.
|
||||
</history>
|
||||
<history author="David Huyck" email="b@bombusbee.com" type="Update" date="25-July-2002">
|
||||
Edited the _buildResult() and _parseOnDelim() functions to improve
|
||||
reliability of special character escaping.
|
||||
Re-introduced a custom setOption() method to throw an error when a
|
||||
person tries to set one of the delimiters to '\'.
|
||||
</history>
|
||||
<history author="Alan Richmond" email="arichmond@bigfoot.com" type="Update" date="27-July-2002">
|
||||
Added '/' delimiter param to preg_quote() in _empty2null() and
|
||||
_parseOnDelim() so '/' can be used as a delimiter.
|
||||
Added error check for columnDelim == eolDelim or dataDelim == eolDelim.
|
||||
Renamed some variables for consistancy.
|
||||
</history>
|
||||
<history author="Alan Richmond" email="arichmond@bigfoot.com" type="Update" date="30-July-2002">
|
||||
Removed protected function _empty2null(). Turns out preg_split()
|
||||
deals with empty elemants by making them zero length strings, just
|
||||
what they ended up being anyway. This should speed things up a little.
|
||||
Affected functions:
|
||||
_parseOnDelim() perform trim on line here, instead of in
|
||||
_empty2null().
|
||||
_buildResult() remove call to _empty2null().
|
||||
_empty2null() removed function.
|
||||
</history>
|
||||
<history author="Alan Richmond" email="arichmond@bigfoot.com" type="Update" date="1-Jan-2003">
|
||||
Ported to PEAR MDB2.
|
||||
Methods supported:
|
||||
connect, query, getColumnNames, numCols, valid, fetch,
|
||||
numRows, free, fetchRow, nextResult, setLimit
|
||||
(inherited).
|
||||
</history>
|
||||
<history
|
||||
Removed array_change_key_case() work around for <4.2.0 in
|
||||
getColumnNames(), found it already done in MDB2/Common.php.
|
||||
</history>
|
||||
<history author="Alan Richmond" email="arichmond@bigfoot.com" type="Update" date="3-Feb-2003">
|
||||
Changed default eolDelim to a *nix file eol, since we're trimming
|
||||
the result anyway, it makes no difference for Windows. Now only
|
||||
Mac file eols should need to be set (and other kinds of chars).
|
||||
</history>
|
||||
<note author="Alan Richmond">
|
||||
Got WAY too long. See querysim_readme.txt for instructions and some
|
||||
examples.
|
||||
io section only documents elements of DB_result that DB_querysim uses,
|
||||
adds or changes; see MDB2 and MDB2_Driver_Common for more info.
|
||||
io section uses some elements that are not Fusedoc 2.0 compliant:
|
||||
object and resource.
|
||||
</note>
|
||||
</properties>
|
||||
<io>
|
||||
<in>
|
||||
<file path="MDB2/Common.php" action="require_once" />
|
||||
</in>
|
||||
<out>
|
||||
<object name="MDB2_querysim" extends="MDB2_Driver_Common" instantiatedby="MDB2::connect()">
|
||||
<resource type="file" name="connection" oncondition="source is external file" scope="class" />
|
||||
<string name="phptype" default="querysim" />
|
||||
<string name="dbsyntax" default="querysim" />
|
||||
<array name="supported" comments="most of these don't actually do anything, they are enabled to simulate the option being available if checked">
|
||||
<boolean name="sequences" default="true" />
|
||||
<boolean name="indexes" default="true" />
|
||||
<boolean name="affected_rows" default="true" />
|
||||
<boolean name="summary_functions" default="true" />
|
||||
<boolean name="order_by_text" default="true" />
|
||||
<boolean name="current_id" default="true" />
|
||||
<boolean name="limit_querys" default="true" comments="this one is functional" />
|
||||
<boolean name="LOBs" default="true" />
|
||||
<boolean name="replace" default="true" />
|
||||
<boolean name="sub_selects" default="true" />
|
||||
<boolean name="transactions" default="true" />
|
||||
</array>
|
||||
<string name="last_query" comments="last value passed in with query()" />
|
||||
<array name="options" comments="these can be changed at run time">
|
||||
<string name="columnDelim" default="," />
|
||||
<string name="dataDelim" default="|" />
|
||||
<string name="eolDelim" default="chr(13).chr(10)" />
|
||||
</array>
|
||||
</object>
|
||||
<array name="result" comments="the simulated record set returned by ::query()">
|
||||
<array comments="columns">
|
||||
<string comments="column name" />
|
||||
</array>
|
||||
<array comments="data">
|
||||
<array comments="row">
|
||||
<string comments="data element" />
|
||||
</array>
|
||||
</array>
|
||||
</array>
|
||||
</out>
|
||||
</io>
|
||||
</fusedoc>
|
||||
*/
|
||||
|
||||
/**
|
||||
* MDB2 QuerySim driver
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Alan Richmond <arichmond@bigfoot.com>
|
||||
*/
|
||||
class MDB2_Driver_querysim extends MDB2_Driver_Common
|
||||
{
|
||||
// }}}
|
||||
// {{{ constructor
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->phptype = 'querysim';
|
||||
$this->dbsyntax = 'querysim';
|
||||
|
||||
// Most of these are dummies to simulate availability if checked
|
||||
$this->supported['sequences'] = false;
|
||||
$this->supported['indexes'] = false;
|
||||
$this->supported['affected_rows'] = false;
|
||||
$this->supported['summary_functions'] = false;
|
||||
$this->supported['order_by_text'] = false;
|
||||
$this->supported['current_id'] = false;
|
||||
$this->supported['limit_queries'] = true;// this one is real
|
||||
$this->supported['LOBs'] = true;
|
||||
$this->supported['replace'] = false;
|
||||
$this->supported['sub_selects'] = false;
|
||||
$this->supported['transactions'] = false;
|
||||
$this->supported['savepoints'] = false;
|
||||
$this->supported['auto_increment'] = false;
|
||||
$this->supported['primary_key'] = false;
|
||||
$this->supported['result_introspection'] = false; // not implemented
|
||||
$this->supported['prepared_statements'] = false;
|
||||
$this->supported['identifier_quoting'] = false;
|
||||
$this->supported['pattern_escaping'] = false;
|
||||
$this->supported['new_link'] = false;
|
||||
|
||||
$this->options['columnDelim'] = ',';
|
||||
$this->options['dataDelim'] = '|';
|
||||
$this->options['eolDelim'] = "\n";
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ connect()
|
||||
|
||||
/**
|
||||
* Open a file or simulate a successful database connect
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @return mixed MDB2_OK string on success, a MDB2 error object on failure
|
||||
*/
|
||||
function connect()
|
||||
{
|
||||
if (is_resource($this->connection)) {
|
||||
if ($this->connected_database_name == $this->database_name
|
||||
&& ($this->opened_persistent == $this->options['persistent'])
|
||||
) {
|
||||
return MDB2_OK;
|
||||
}
|
||||
if ($this->connected_database_name) {
|
||||
$this->_close($this->connection);
|
||||
}
|
||||
$this->disconnect();
|
||||
}
|
||||
|
||||
$connection = 1;// sim connect
|
||||
// if external, check file...
|
||||
if ($this->database_name) {
|
||||
$file = $this->database_name;
|
||||
if (!file_exists($file)) {
|
||||
return $this->raiseError(MDB2_ERROR_NOT_FOUND, null, null,
|
||||
'file not found', __FUNCTION__);
|
||||
}
|
||||
if (!is_file($file)) {
|
||||
return $this->raiseError(MDB2_ERROR_INVALID, null, null,
|
||||
'not a file', __FUNCTION__);
|
||||
}
|
||||
if (!is_readable($file)) {
|
||||
return $this->raiseError(MDB2_ERROR_ACCESS_VIOLATION, null, null,
|
||||
'could not open file - check permissions', __FUNCTION__);
|
||||
}
|
||||
// ...and open if persistent
|
||||
if ($this->options['persistent']) {
|
||||
$connection = @fopen($file, 'r');
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($this->dsn['charset'])) {
|
||||
$result = $this->setCharset($this->dsn['charset'], $connection);
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
$this->connection = $connection;
|
||||
$this->connected_database_name = $this->database_name;
|
||||
$this->opened_persistent = $this->options['persistent'];
|
||||
$this->dbsyntax = $this->dsn['dbsyntax'] ? $this->dsn['dbsyntax'] : $this->phptype;
|
||||
|
||||
return MDB2_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ disconnect()
|
||||
|
||||
/**
|
||||
* Log out and disconnect from the database.
|
||||
*
|
||||
* @param boolean $force 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)
|
||||
{
|
||||
if (is_resource($this->connection)) {
|
||||
if ($this->opened_persistent) {
|
||||
@fclose($this->connection);
|
||||
}
|
||||
}
|
||||
return parent::disconnect($force);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _doQuery()
|
||||
|
||||
/**
|
||||
* Execute a query
|
||||
* @param string $query query
|
||||
* @param boolean $is_manip if the query is a manipulation query
|
||||
* @param resource $connection
|
||||
* @param string $database_name
|
||||
* @return result or error object
|
||||
* @access protected
|
||||
*/
|
||||
function &_doQuery($query, $is_manip = false, $connection = null, $database_name = null)
|
||||
{
|
||||
if ($this->database_name) {
|
||||
$query = $this->_readFile();
|
||||
}
|
||||
$this->last_query = $query;
|
||||
$result = $this->debug($query, 'query', array('is_manip' => $is_manip, 'when' => 'pre'));
|
||||
if ($result) {
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
$query = $result;
|
||||
}
|
||||
if ($is_manip) {
|
||||
$err =& $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
|
||||
'Manipulation statements are not supported', __FUNCTION__);
|
||||
return $err;
|
||||
}
|
||||
if ($this->options['disable_query']) {
|
||||
$result = $is_manip ? 0 : null;
|
||||
return $result;
|
||||
}
|
||||
|
||||
$result = $this->_buildResult($query);
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
if ($this->next_limit > 0) {
|
||||
$result[1] = array_slice($result[1], $this->next_offset, $this->next_limit);
|
||||
}
|
||||
|
||||
$this->debug($query, 'query', array('is_manip' => $is_manip, 'when' => 'post', 'result' => $result));
|
||||
return $result;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _modifyQuery()
|
||||
|
||||
/**
|
||||
* Changes a query string for various DBMS specific reasons
|
||||
*
|
||||
* @param string $query query to modify
|
||||
* @param boolean $is_manip if it is a DML query
|
||||
* @param integer $limit limit the number of rows
|
||||
* @param integer $offset start reading from given offset
|
||||
* @return string modified query
|
||||
* @access protected
|
||||
*/
|
||||
function _modifyQuery($query, $is_manip, $limit, $offset)
|
||||
{
|
||||
$this->next_limit = $limit;
|
||||
$this->next_offset = $offset;
|
||||
return $query;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _readFile()
|
||||
|
||||
/**
|
||||
* Read an external file
|
||||
*
|
||||
* @param string filepath/filename
|
||||
*
|
||||
* @access protected
|
||||
*
|
||||
* @return string the contents of a file
|
||||
*/
|
||||
function _readFile()
|
||||
{
|
||||
$buffer = '';
|
||||
if ($this->opened_persistent) {
|
||||
$connection = $this->getConnection();
|
||||
if (MDB2::isError($connection)) {
|
||||
return $connection;
|
||||
}
|
||||
while (!feof($connection)) {
|
||||
$buffer.= fgets($connection, 1024);
|
||||
}
|
||||
rewind($connection);
|
||||
} else {
|
||||
$connection = @fopen($this->connected_database_name, 'r');
|
||||
while (!feof($connection)) {
|
||||
$buffer.= fgets($connection, 1024);
|
||||
}
|
||||
@fclose($connection);
|
||||
}
|
||||
return $buffer;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _buildResult()
|
||||
|
||||
/**
|
||||
* Convert QuerySim text into an array
|
||||
*
|
||||
* @param string Text of simulated query
|
||||
*
|
||||
* @access protected
|
||||
*
|
||||
* @return multi-dimensional array containing the column names and data
|
||||
* from the QuerySim
|
||||
*/
|
||||
function _buildResult($query)
|
||||
{
|
||||
$eolDelim = $this->options['eolDelim'];
|
||||
$columnDelim = $this->options['columnDelim'];
|
||||
$dataDelim = $this->options['dataDelim'];
|
||||
|
||||
$columnNames = array();
|
||||
$data = array();
|
||||
|
||||
if ($columnDelim == $eolDelim) {
|
||||
return $this->raiseError(MDB2_ERROR_INVALID, null, null,
|
||||
'columnDelim and eolDelim must be different', __FUNCTION__);
|
||||
} elseif ($dataDelim == $eolDelim){
|
||||
return $this->raiseError(MDB2_ERROR_INVALID, null, null,
|
||||
'dataDelim and eolDelim must be different', __FUNCTION__);
|
||||
}
|
||||
|
||||
$query = trim($query);
|
||||
//tokenize escaped slashes
|
||||
$query = str_replace('\\\\', '[$double-slash$]', $query);
|
||||
|
||||
if (!strlen($query)) {
|
||||
return $this->raiseError(MDB2_ERROR_SYNTAX, null, null,
|
||||
'empty querysim text', __FUNCTION__);
|
||||
}
|
||||
$lineData = $this->_parseOnDelim($query, $eolDelim);
|
||||
//kill the empty last row created by final eol char if it exists
|
||||
if (!strlen(trim($lineData[count($lineData) - 1]))) {
|
||||
unset($lineData[count($lineData) - 1]);
|
||||
}
|
||||
//populate columnNames array
|
||||
$thisLine = each($lineData);
|
||||
$columnNames = $this->_parseOnDelim($thisLine[1], $columnDelim);
|
||||
if ((in_array('', $columnNames)) || (in_array('NULL', $columnNames))) {
|
||||
return $this->raiseError(MDB2_ERROR_SYNTAX, null, null,
|
||||
'all column names must be defined', __FUNCTION__);
|
||||
}
|
||||
//replace double-slash tokens with single-slash
|
||||
$columnNames = str_replace('[$double-slash$]', '\\', $columnNames);
|
||||
$columnCount = count($columnNames);
|
||||
$rowNum = 0;
|
||||
//loop through data lines
|
||||
if (count($lineData) > 1) {
|
||||
while ($thisLine = each($lineData)) {
|
||||
$thisData = $this->_parseOnDelim($thisLine[1], $dataDelim);
|
||||
$thisDataCount = count($thisData);
|
||||
if ($thisDataCount != $columnCount) {
|
||||
$fileLineNo = $rowNum + 2;
|
||||
return $this->raiseError(MDB2_ERROR_SYNTAX, null, null,
|
||||
"number of data elements ($thisDataCount) in line $fileLineNo not equal to number of defined columns ($columnCount)", __FUNCTION__);
|
||||
}
|
||||
//loop through data elements in data line
|
||||
foreach ($thisData as $thisElement) {
|
||||
if (strtoupper($thisElement) == 'NULL'){
|
||||
$thisElement = '';
|
||||
}
|
||||
//replace double-slash tokens with single-slash
|
||||
$data[$rowNum][] = str_replace('[$double-slash$]', '\\', $thisElement);
|
||||
}//end foreach
|
||||
++$rowNum;
|
||||
}//end while
|
||||
}//end if
|
||||
return array($columnNames, $data);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _parseOnDelim()
|
||||
|
||||
/**
|
||||
* Split QuerySim string into an array on a delimiter
|
||||
*
|
||||
* @param string $thisLine Text of simulated query
|
||||
* @param string $delim The delimiter to split on
|
||||
*
|
||||
* @access protected
|
||||
*
|
||||
* @return array containing parsed string
|
||||
*/
|
||||
function _parseOnDelim($thisLine, $delim)
|
||||
{
|
||||
$delimQuoted = preg_quote($delim, '/');
|
||||
$thisLine = trim($thisLine);
|
||||
|
||||
$parsed = preg_split('/(?<!\\\\)' .$delimQuoted. '/', $thisLine);
|
||||
//replaces escaped delimiters
|
||||
$parsed = preg_replace('/\\\\' .$delimQuoted. '/', $delim, $parsed);
|
||||
if ($delim != $this->options['eolDelim']) {
|
||||
//replaces escape chars
|
||||
$parsed = preg_replace('/\\\\/', '', $parsed);
|
||||
}
|
||||
return $parsed;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ &exec()
|
||||
|
||||
/**
|
||||
* Execute a manipulation query to the database and return any the affected rows
|
||||
*
|
||||
* @param string $query the SQL query
|
||||
* @return mixed affected rows on success, a MDB2 error on failure
|
||||
* @access public
|
||||
*/
|
||||
function &exec($query)
|
||||
{
|
||||
return $this->raiseError(MDB2_ERROR_UNSUPPORTED, null, null,
|
||||
'Querysim only supports reading data', __FUNCTION__);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ getServerVersion()
|
||||
|
||||
/**
|
||||
* return version information about the server
|
||||
*
|
||||
* @param bool $native determines if the raw version string should be returned
|
||||
* @return mixed array/string with version information or MDB2 error object
|
||||
* @access public
|
||||
*/
|
||||
function getServerVersion($native = false)
|
||||
{
|
||||
$server_info = '@package_version@';
|
||||
// cache server_info
|
||||
$this->connected_server_info = $server_info;
|
||||
if (!$native) {
|
||||
$tmp = explode('.', $server_info, 3);
|
||||
if (!isset($tmp[2]) || !preg_match('/(\d+)(.*)/', $tmp[2], $tmp2)) {
|
||||
$tmp2[0] = isset($tmp[2]) ? $tmp[2] : null;
|
||||
$tmp2[1] = null;
|
||||
}
|
||||
$server_info = array(
|
||||
'major' => isset($tmp[0]) ? $tmp[0] : null,
|
||||
'minor' => isset($tmp[1]) ? $tmp[1] : null,
|
||||
'patch' => isset($tmp2[0]) ? $tmp2[0] : null,
|
||||
'extra' => isset($tmp2[1]) ? $tmp2[1] : null,
|
||||
'native' => $server_info,
|
||||
);
|
||||
}
|
||||
return $server_info;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* MDB2 QuerySim result driver
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Alan Richmond <arichmond@bigfoot.com>
|
||||
*/
|
||||
class MDB2_Result_querysim extends MDB2_Result_Common
|
||||
{
|
||||
// }}}
|
||||
// {{{ fetchRow()
|
||||
|
||||
/**
|
||||
* Fetch a row and insert the data into an existing array.
|
||||
*
|
||||
* @param int $fetchmode how the array data should be indexed
|
||||
* @param int $rownum 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)
|
||||
{
|
||||
if (false === $this->result) {
|
||||
$err =& $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
|
||||
'resultset has already been freed', __FUNCTION__);
|
||||
return $err;
|
||||
}
|
||||
if (null === $this->result) {
|
||||
return null;
|
||||
}
|
||||
if (null !== $rownum) {
|
||||
$seek = $this->seek($rownum);
|
||||
if (MDB2::isError($seek)) {
|
||||
return $seek;
|
||||
}
|
||||
}
|
||||
$target_rownum = $this->rownum + 1;
|
||||
if ($fetchmode == MDB2_FETCHMODE_DEFAULT) {
|
||||
$fetchmode = $this->db->fetchmode;
|
||||
}
|
||||
if (!isset($this->result[1][$target_rownum])) {
|
||||
$null = null;
|
||||
return $null;
|
||||
}
|
||||
$row = $this->result[1][$target_rownum];
|
||||
// make row associative
|
||||
if ( $fetchmode == MDB2_FETCHMODE_ASSOC
|
||||
|| $fetchmode == MDB2_FETCHMODE_OBJECT
|
||||
) {
|
||||
$column_names = $this->getColumnNames();
|
||||
foreach ($column_names as $name => $i) {
|
||||
$column_names[$name] = $row[$i];
|
||||
}
|
||||
$row = $column_names;
|
||||
}
|
||||
$mode = $this->db->options['portability'] & MDB2_PORTABILITY_EMPTY_TO_NULL;
|
||||
$rtrim = false;
|
||||
if ($this->db->options['portability'] & MDB2_PORTABILITY_RTRIM) {
|
||||
if (empty($this->types)) {
|
||||
$mode += MDB2_PORTABILITY_RTRIM;
|
||||
} else {
|
||||
$rtrim = true;
|
||||
}
|
||||
}
|
||||
if ($mode) {
|
||||
$this->db->_fixResultArrayValues($row, $mode);
|
||||
}
|
||||
if ( ( $fetchmode != MDB2_FETCHMODE_ASSOC
|
||||
&& $fetchmode != MDB2_FETCHMODE_OBJECT)
|
||||
&& !empty($this->types)
|
||||
) {
|
||||
$row = $this->db->datatype->convertResultRow($this->types, $row, $rtrim);
|
||||
} elseif (($fetchmode == MDB2_FETCHMODE_ASSOC
|
||||
|| $detchmode == MDB2_FETCHMODE_OBJECT)
|
||||
&& !empty($this->types_assoc)
|
||||
) {
|
||||
$row = $this->db->datatype->convertResultRow($this->types_assoc, $row, $rtrim);
|
||||
}
|
||||
if (!empty($this->values)) {
|
||||
$this->_assignBindColumns($row);
|
||||
}
|
||||
if ($fetchmode === MDB2_FETCHMODE_OBJECT) {
|
||||
$object_class = $this->db->options['fetch_class'];
|
||||
if ($object_class == 'stdClass') {
|
||||
$row = (object) $row;
|
||||
} else {
|
||||
$row = new $object_class($row);
|
||||
}
|
||||
}
|
||||
++$this->rownum;
|
||||
return $row;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _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()
|
||||
{
|
||||
if (false === $this->result) {
|
||||
return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
|
||||
'resultset has already been freed', __FUNCTION__);
|
||||
}
|
||||
if (null === $this->result) {
|
||||
return array();
|
||||
}
|
||||
$columns = array_flip($this->result[0]);
|
||||
if ($this->db->options['portability'] & MDB2_PORTABILITY_FIX_CASE) {
|
||||
$columns = array_change_key_case($columns, $this->db->options['field_case']);
|
||||
}
|
||||
return $columns;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ numCols()
|
||||
|
||||
/**
|
||||
* Count the number of columns returned by the DBMS in a query result.
|
||||
*
|
||||
* @access public
|
||||
* @return mixed integer value with the number of columns, a MDB2 error
|
||||
* on failure
|
||||
*/
|
||||
function numCols()
|
||||
{
|
||||
if (false === $this->result) {
|
||||
return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
|
||||
'resultset has already been freed', __FUNCTION__);
|
||||
}
|
||||
if (null === $this->result) {
|
||||
return count($this->types);
|
||||
}
|
||||
$cols = count($this->result[0]);
|
||||
return $cols;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* MDB2 QuerySim buffered result driver
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Alan Richmond <arichmond@bigfoot.com>
|
||||
*/
|
||||
class MDB2_BufferedResult_querysim extends MDB2_Result_querysim
|
||||
{
|
||||
// }}}
|
||||
// {{{ seek()
|
||||
|
||||
/**
|
||||
* Seek to a specific row in a result set
|
||||
*
|
||||
* @param int $rownum 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)
|
||||
{
|
||||
if (false === $this->result) {
|
||||
return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
|
||||
'resultset has already been freed', __FUNCTION__);
|
||||
}
|
||||
$this->rownum = $rownum - 1;
|
||||
return MDB2_OK;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ valid()
|
||||
|
||||
/**
|
||||
* Check if the end of the result set has been reached
|
||||
*
|
||||
* @return mixed true or false on sucess, a MDB2 error on failure
|
||||
* @access public
|
||||
*/
|
||||
function valid()
|
||||
{
|
||||
$numrows = $this->numRows();
|
||||
if (MDB2::isError($numrows)) {
|
||||
return $numrows;
|
||||
}
|
||||
return $this->rownum < ($numrows - 1);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ numRows()
|
||||
|
||||
/**
|
||||
* Returns the number of rows in a result object
|
||||
*
|
||||
* @return mixed MDB2 Error Object or the number of rows
|
||||
* @access public
|
||||
*/
|
||||
function numRows()
|
||||
{
|
||||
if (false === $this->result) {
|
||||
return $this->db->raiseError(MDB2_ERROR_NEED_MORE_DATA, null, null,
|
||||
'resultset has already been freed', __FUNCTION__);
|
||||
}
|
||||
if (null === $this->result) {
|
||||
return 0;
|
||||
}
|
||||
$rows = count($this->result[1]);
|
||||
return $rows;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* MDB2 QuerySim statement driver
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Alan Richmond <arichmond@bigfoot.com>
|
||||
*/
|
||||
class MDB2_Statement_querysim extends MDB2_Statement_Common
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
?>
|
1104
extlib/MDB2/Driver/sqlite.php
Normal file
1104
extlib/MDB2/Driver/sqlite.php
Normal file
File diff suppressed because it is too large
Load Diff
1112
extlib/MDB2/Driver/sqlite3.php
Normal file
1112
extlib/MDB2/Driver/sqlite3.php
Normal file
File diff suppressed because it is too large
Load Diff
1174
extlib/MDB2/Driver/sqlsrv.php
Normal file
1174
extlib/MDB2/Driver/sqlsrv.php
Normal file
File diff suppressed because it is too large
Load Diff
723
extlib/MDB2/Extended.php
Normal file
723
extlib/MDB2/Extended.php
Normal file
@ -0,0 +1,723 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP versions 4 and 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Author: Lukas Smith <smith@pooteeweet.org> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id$
|
||||
|
||||
/**
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lukas Smith <smith@pooteeweet.org>
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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 <smith@pooteeweet.org>
|
||||
*/
|
||||
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 (MDB2::isError($query)) {
|
||||
return $query;
|
||||
}
|
||||
$db = $this->getDBInstance();
|
||||
if (MDB2::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 (MDB2::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 (MDB2::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 (MDB2::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 ((false !== $where) && (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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
$result = $db->setLimit($limit, $offset);
|
||||
if (MDB2::isError($result)) {
|
||||
return $result;
|
||||
}
|
||||
return $db->query($query, $types, $result_class, $result_wrap_class);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ 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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
settype($params, 'array');
|
||||
if (empty($params)) {
|
||||
return $db->exec($query);
|
||||
}
|
||||
|
||||
$stmt = $db->prepare($query, $param_types, MDB2_PREPARE_MANIP);
|
||||
if (MDB2::isError($stmt)) {
|
||||
return $stmt;
|
||||
}
|
||||
|
||||
$result = $stmt->execute($params);
|
||||
if (MDB2::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 (MDB2::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 (MDB2::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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
settype($params, 'array');
|
||||
if (empty($params)) {
|
||||
return $db->queryRow($query, $types, $fetchmode);
|
||||
}
|
||||
|
||||
$stmt = $db->prepare($query, $param_types, $types);
|
||||
if (MDB2::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 (MDB2::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 (MDB2::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 (MDB2::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 (MDB2::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:
|
||||
* <pre>
|
||||
* ID TEXT DATE
|
||||
* --------------------------------
|
||||
* 1 'one' 944679408
|
||||
* 2 'two' 944679408
|
||||
* 3 'three' 944679408
|
||||
* </pre>
|
||||
* Then the call getAssoc('SELECT id,text FROM mytable') returns:
|
||||
* <pre>
|
||||
* array(
|
||||
* '1' => 'one',
|
||||
* '2' => 'two',
|
||||
* '3' => 'three',
|
||||
* )
|
||||
* </pre>
|
||||
* ...while the call getAssoc('SELECT id,text,date FROM mytable') returns:
|
||||
* <pre>
|
||||
* array(
|
||||
* '1' => array('one', '944679408'),
|
||||
* '2' => array('two', '944679408'),
|
||||
* '3' => array('three', '944679408')
|
||||
* )
|
||||
* </pre>
|
||||
*
|
||||
* If the more than one row occurs with the same value in the
|
||||
* first column, the last row overwrites all previous ones by
|
||||
* default. Use the $group parameter if you don't want to
|
||||
* overwrite like this. Example:
|
||||
* <pre>
|
||||
* getAssoc('SELECT category,id,name FROM mytable', 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')
|
||||
* )
|
||||
* )
|
||||
* </pre>
|
||||
*
|
||||
* 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 (MDB2::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 (MDB2::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)
|
||||
{
|
||||
if (MDB2::isError($stmt)) {
|
||||
return $stmt;
|
||||
}
|
||||
for ($i = 0, $j = count($params); $i < $j; $i++) {
|
||||
$result = $stmt->execute($params[$i]);
|
||||
if (MDB2::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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
if ($db->supports('auto_increment') !== true) {
|
||||
$seq = $table.(empty($field) ? '' : '_'.$field);
|
||||
$id = $db->nextID($seq, $ondemand);
|
||||
if (!$quote || MDB2::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 (MDB2::isError($db)) {
|
||||
return $db;
|
||||
}
|
||||
|
||||
if ($db->supports('auto_increment') !== true) {
|
||||
return $id;
|
||||
}
|
||||
return $db->lastInsertID($table, $field);
|
||||
}
|
||||
|
||||
// }}}
|
||||
}
|
||||
?>
|
262
extlib/MDB2/Iterator.php
Normal file
262
extlib/MDB2/Iterator.php
Normal file
@ -0,0 +1,262 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP version 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Author: Lukas Smith <smith@pooteeweet.org> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id$
|
||||
|
||||
/**
|
||||
* PHP5 Iterator
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lukas Smith <smith@pooteeweet.org>
|
||||
*/
|
||||
class MDB2_Iterator implements Iterator
|
||||
{
|
||||
protected $fetchmode;
|
||||
/**
|
||||
* @var MDB2_Result_Common
|
||||
*/
|
||||
protected $result;
|
||||
protected $row;
|
||||
|
||||
// {{{ constructor
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct(MDB2_Result_Common $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 (null === $this->row) {
|
||||
$row = $this->result->fetchRow($this->fetchmode);
|
||||
if (MDB2::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 <smith@pooteeweet.org>
|
||||
*/
|
||||
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);
|
||||
}
|
||||
// }}}
|
||||
}
|
||||
|
||||
?>
|
264
extlib/MDB2/LOB.php
Normal file
264
extlib/MDB2/LOB.php
Normal file
@ -0,0 +1,264 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP version 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | 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. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Author: Lukas Smith <smith@pooteeweet.org> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id$
|
||||
|
||||
/**
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lukas Smith <smith@pooteeweet.org>
|
||||
*/
|
||||
|
||||
require_once 'MDB2.php';
|
||||
|
||||
/**
|
||||
* MDB2_LOB: user land stream wrapper implementation for LOB support
|
||||
*
|
||||
* @package MDB2
|
||||
* @category Database
|
||||
* @author Lukas Smith <smith@pooteeweet.org>
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
?>
|
@ -220,8 +220,8 @@ class MysqlSchema extends Schema
|
||||
*/
|
||||
public function fetchMetaInfo($table, $infoTable, $orderBy = null)
|
||||
{
|
||||
$schema = $this->conn->dsn['database'];
|
||||
return $this->fetchQueryData(sprintf(
|
||||
$schema = $this->conn->getDatabase();
|
||||
$info = $this->fetchQueryData(sprintf(
|
||||
<<<'END'
|
||||
SELECT * FROM INFORMATION_SCHEMA.%1$s
|
||||
WHERE TABLE_SCHEMA = '%2$s' AND TABLE_NAME = '%3$s'%4$s;
|
||||
@ -231,6 +231,10 @@ class MysqlSchema extends Schema
|
||||
$table,
|
||||
($orderBy ? " ORDER BY {$orderBy}" : '')
|
||||
));
|
||||
|
||||
return array_map(function (array $cols): array {
|
||||
return array_change_key_case($cols, CASE_UPPER);
|
||||
}, $info);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -242,7 +246,7 @@ class MysqlSchema extends Schema
|
||||
*/
|
||||
private function fetchKeyInfo(string $table): array
|
||||
{
|
||||
$schema = $this->conn->dsn['database'];
|
||||
$schema = $this->conn->getDatabase();
|
||||
$data = $this->fetchQueryData(
|
||||
<<<EOT
|
||||
SELECT INDEX_NAME AS `key_name`,
|
||||
@ -290,7 +294,7 @@ class MysqlSchema extends Schema
|
||||
*/
|
||||
private function fetchForeignKeyInfo(string $table): array
|
||||
{
|
||||
$schema = $this->conn->dsn['database'];
|
||||
$schema = $this->conn->getDatabase();
|
||||
$data = $this->fetchQueryData(
|
||||
<<<END
|
||||
SELECT CONSTRAINT_NAME AS `key_name`,
|
||||
|
@ -193,8 +193,8 @@ class PgsqlSchema extends Schema
|
||||
*/
|
||||
public function fetchMetaInfo($table, $infoTable, $orderBy = null)
|
||||
{
|
||||
$catalog = $this->conn->dsn['database'];
|
||||
return $this->fetchQueryData(sprintf(
|
||||
$catalog = $this->conn->getDatabase();
|
||||
$info = $this->fetchQueryData(sprintf(
|
||||
<<<'END'
|
||||
SELECT * FROM information_schema.%1$s
|
||||
WHERE table_catalog = '%2$s' AND table_name = '%3$s'%4$s;
|
||||
@ -204,6 +204,10 @@ class PgsqlSchema extends Schema
|
||||
$table,
|
||||
($orderBy ? " ORDER BY {$orderBy}" : '')
|
||||
));
|
||||
|
||||
return array_map(function (array $cols): array {
|
||||
return array_change_key_case($cols, CASE_LOWER);
|
||||
}, $info);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -72,7 +72,7 @@ class Schema
|
||||
if (is_null($conn)) {
|
||||
$key = 'default';
|
||||
} else {
|
||||
$key = md5(serialize($conn->dsn));
|
||||
$key = hash('md5', $conn->getDSN('string'));
|
||||
}
|
||||
|
||||
if (is_null($dbtype)) {
|
||||
@ -343,7 +343,7 @@ class Schema
|
||||
{
|
||||
global $_PEAR;
|
||||
|
||||
$res = $this->conn->query('DROP TABLE ' . $this->quoteIdentifier($name));
|
||||
$res = $this->conn->exec('DROP TABLE ' . $this->quoteIdentifier($name));
|
||||
|
||||
if ($_PEAR->isError($res)) {
|
||||
PEAR_ErrorToPEAR_Exception($res);
|
||||
@ -372,7 +372,7 @@ class Schema
|
||||
{
|
||||
global $_PEAR;
|
||||
|
||||
$qry = [];
|
||||
$statements = [];
|
||||
|
||||
if (!is_array($columnNames)) {
|
||||
$columnNames = [$columnNames];
|
||||
@ -382,14 +382,20 @@ class Schema
|
||||
$name = "{$table}_" . implode("_", $columnNames) . "_idx";
|
||||
}
|
||||
|
||||
$this->appendCreateIndex($qry, $table, $name, $columnNames);
|
||||
$this->appendCreateIndex($statements, $table, $name, $columnNames);
|
||||
|
||||
$res = $this->conn->query(implode('; ', $qry));
|
||||
$this->conn->beginTransaction();
|
||||
|
||||
foreach ($statements as $sql) {
|
||||
$res = $this->conn->exec($sql);
|
||||
|
||||
if ($_PEAR->isError($res)) {
|
||||
$this->conn->rollback();
|
||||
PEAR_ErrorToPEAR_Exception($res);
|
||||
}
|
||||
}
|
||||
|
||||
$this->conn->commit();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -409,12 +415,18 @@ class Schema
|
||||
$statements = [];
|
||||
$this->appendDropIndex($statements, $table, $name);
|
||||
|
||||
$res = $this->conn->query(implode(";\n", $statements));
|
||||
$this->conn->beginTransaction();
|
||||
|
||||
foreach ($statements as $sql) {
|
||||
$res = $this->conn->exec($sql);
|
||||
|
||||
if ($_PEAR->isError($res)) {
|
||||
$this->conn->rollback();
|
||||
PEAR_ErrorToPEAR_Exception($res);
|
||||
}
|
||||
}
|
||||
|
||||
$this->conn->commit();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -435,7 +447,7 @@ class Schema
|
||||
$sql = 'ALTER TABLE ' . $this->quoteIdentifier($table) .
|
||||
' ADD COLUMN ' . $this->columnSql($name, $columndef);
|
||||
|
||||
$res = $this->conn->query($sql);
|
||||
$res = $this->conn->exec($sql);
|
||||
|
||||
if ($_PEAR->isError($res)) {
|
||||
PEAR_ErrorToPEAR_Exception($res);
|
||||
@ -463,7 +475,7 @@ class Schema
|
||||
$sql = 'ALTER TABLE ' . $this->quoteIdentifier($table) .
|
||||
' MODIFY COLUMN ' . $this->columnSql($name, $columndef);
|
||||
|
||||
$res = $this->conn->query($sql);
|
||||
$res = $this->conn->exec($sql);
|
||||
|
||||
if ($_PEAR->isError($res)) {
|
||||
PEAR_ErrorToPEAR_Exception($res);
|
||||
@ -490,7 +502,7 @@ class Schema
|
||||
$sql = 'ALTER TABLE ' . $this->quoteIdentifier($table) .
|
||||
' DROP COLUMN ' . $columnName;
|
||||
|
||||
$res = $this->conn->query($sql);
|
||||
$res = $this->conn->exec($sql);
|
||||
|
||||
if ($_PEAR->isError($res)) {
|
||||
PEAR_ErrorToPEAR_Exception($res);
|
||||
@ -532,19 +544,24 @@ class Schema
|
||||
{
|
||||
global $_PEAR;
|
||||
|
||||
$ok = true;
|
||||
$this->conn->beginTransaction();
|
||||
|
||||
foreach ($statements as $sql) {
|
||||
if (defined('DEBUG_INSTALLER')) {
|
||||
echo "<code>" . htmlspecialchars($sql) . "</code><br/>\n";
|
||||
}
|
||||
$res = $this->conn->query($sql);
|
||||
|
||||
$res = $this->conn->exec($sql);
|
||||
|
||||
if ($_PEAR->isError($res)) {
|
||||
$this->conn->rollback();
|
||||
common_debug('PEAR exception on query: ' . $sql);
|
||||
PEAR_ErrorToPEAR_Exception($res);
|
||||
}
|
||||
}
|
||||
return $ok;
|
||||
|
||||
$this->conn->commit();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -849,7 +866,11 @@ class Schema
|
||||
|
||||
public function quoteValue($val)
|
||||
{
|
||||
return $this->conn->quoteSmart($val);
|
||||
// MDB2_Driver_Common::quote changes empty strings to "NULL".
|
||||
if ($val === '') {
|
||||
return '';
|
||||
}
|
||||
return $this->conn->quote($val);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1190,7 +1211,7 @@ class Schema
|
||||
* @return array of arrays
|
||||
* @throws PEAR_Exception
|
||||
*/
|
||||
protected function fetchQueryData($sql)
|
||||
protected function fetchQueryData(string $sql): array
|
||||
{
|
||||
global $_PEAR;
|
||||
|
||||
@ -1200,8 +1221,7 @@ class Schema
|
||||
}
|
||||
|
||||
$out = [];
|
||||
$row = [];
|
||||
while ($res->fetchInto($row, DB_FETCHMODE_ASSOC)) {
|
||||
while (!empty($row = $res->fetchRow(MDB2_FETCHMODE_ASSOC))) {
|
||||
$out[] = $row;
|
||||
}
|
||||
$res->free();
|
||||
|
@ -72,8 +72,7 @@ $default =
|
||||
'require_prefix' => 'classes/',
|
||||
'class_prefix' => '',
|
||||
'mirror' => null,
|
||||
'utf8' => true,
|
||||
'db_driver' => 'DB', # XXX: JanRain libs only work with DB
|
||||
'db_driver' => 'MDB2',
|
||||
'disable_null_strings' => true, // 'NULL' can be harmful
|
||||
'quote_identifiers' => true,
|
||||
'type' => 'mysql',
|
||||
|
@ -95,11 +95,9 @@ global $_PEAR;
|
||||
$_PEAR = new PEAR;
|
||||
$_PEAR->setErrorHandling(PEAR_ERROR_CALLBACK, 'PEAR_ErrorToPEAR_Exception');
|
||||
|
||||
require_once 'DB.php';
|
||||
require_once 'MDB2.php';
|
||||
require_once 'DB/DataObject.php';
|
||||
require_once 'DB/DataObject/Cast.php'; # for dates
|
||||
global $_DB;
|
||||
$_DB = new DB;
|
||||
require_once 'DB/DataObject/Cast.php'; // for dates
|
||||
|
||||
require_once INSTALLDIR . '/lib/util/language.php';
|
||||
|
||||
@ -130,12 +128,13 @@ function GNUsocial_class_autoload($cls)
|
||||
$lib_path = INSTALLDIR . '/lib/';
|
||||
$lib_dirs = array_map(function ($dir) {
|
||||
return '/lib/' . $dir . '/';
|
||||
},
|
||||
array_filter(scandir($lib_path),
|
||||
}, array_filter(
|
||||
scandir($lib_path),
|
||||
function ($dir) use ($lib_path) {
|
||||
// Filter out files and both hidden and implicit folders
|
||||
return $dir[0] != '.' && is_dir($lib_path . $dir);
|
||||
}));
|
||||
// Filter out files and both hidden and implicit directories.
|
||||
return $dir[0] !== '.' && is_dir($lib_path . $dir);
|
||||
}
|
||||
));
|
||||
|
||||
$found = false;
|
||||
foreach (array_merge(['/classes/'], $lib_dirs) as $dir) {
|
||||
|
@ -66,12 +66,12 @@ abstract class Installer
|
||||
'mysql' => [
|
||||
'name' => 'MariaDB 10.3+',
|
||||
'check_module' => 'mysqli',
|
||||
'scheme' => 'mysqli', // DSN prefix for PEAR::DB
|
||||
'scheme' => 'mysqli', // DSN prefix for MDB2
|
||||
],
|
||||
'pgsql' => [
|
||||
'name' => 'PostgreSQL 11+',
|
||||
'check_module' => 'pgsql',
|
||||
'scheme' => 'pgsql', // DSN prefix for PEAR::DB
|
||||
'scheme' => 'pgsql', // DSN prefix for MDB2
|
||||
]
|
||||
];
|
||||
|
||||
@ -283,64 +283,45 @@ abstract class Installer
|
||||
*/
|
||||
public function setupDatabase()
|
||||
{
|
||||
if ($this->db) {
|
||||
throw new Exception("Bad order of operations: DB already set up.");
|
||||
if (!empty($this->db)) {
|
||||
throw new Exception('Bad order of operations: DB already set up.');
|
||||
}
|
||||
$this->updateStatus("Starting installation...");
|
||||
$this->updateStatus('Starting installation...');
|
||||
|
||||
if (empty($this->password)) {
|
||||
$auth = '';
|
||||
} else {
|
||||
$auth = ":$this->password";
|
||||
if (!empty($this->password)) {
|
||||
$auth .= ":{$this->password}";
|
||||
}
|
||||
$scheme = self::$dbModules[$this->dbtype]['scheme'];
|
||||
$dsn = "{$scheme}://{$this->username}{$auth}@{$this->host}/{$this->database}";
|
||||
|
||||
$this->updateStatus("Checking database...");
|
||||
$this->updateStatus('Checking database...');
|
||||
$conn = $this->connectDatabase($dsn);
|
||||
|
||||
if (!$conn instanceof DB_common) {
|
||||
// Is not the right instance
|
||||
throw new Exception('Cannot connect to database: ' . $conn->getMessage());
|
||||
}
|
||||
$charset = ($this->dbtype !== 'mysql') ? 'UTF8' : 'utf8mb4';
|
||||
$server_charset = $this->getDatabaseCharset($conn, $this->dbtype);
|
||||
|
||||
switch ($this->dbtype) {
|
||||
case 'pgsql':
|
||||
// ensure the timezone is UTC
|
||||
$conn->query("SET TIME ZONE INTERVAL '+00:00' HOUR TO MINUTE");
|
||||
// ensure the database encoding is UTF8
|
||||
$conn->query("SET NAMES 'UTF8'");
|
||||
$server_encoding = $conn->getRow('SHOW server_encoding')[0];
|
||||
if ($server_encoding !== 'UTF8') {
|
||||
// Ensure the database server character set is UTF-8.
|
||||
$conn->exec("SET NAMES '{$charset}'");
|
||||
|
||||
if ($server_charset !== $charset) {
|
||||
$this->updateStatus(
|
||||
'GNU social requires the UTF8 character encoding. Yours is ' .
|
||||
htmlentities($server_encoding)
|
||||
'GNU social requires the "' . $charset . '" character set. '
|
||||
. 'Yours is ' . htmlentities($server_charset)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 'mysql':
|
||||
// ensure the timezone is UTC
|
||||
$conn->query("SET time_zone = '+0:00'");
|
||||
// ensure the database encoding is utf8mb4
|
||||
$conn->query("SET NAMES 'utf8mb4'");
|
||||
$server_encoding = $conn->getRow("SHOW VARIABLES LIKE 'character_set_server'")[1];
|
||||
if ($server_encoding !== 'utf8mb4') {
|
||||
$this->updateStatus(
|
||||
'GNU social requires the utf8mb4 character encoding. Yours is ' .
|
||||
htmlentities($server_encoding)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$this->updateStatus('Unknown DB type selected: ' . $this->dbtype);
|
||||
return false;
|
||||
|
||||
// Ensure the timezone is UTC.
|
||||
if ($this->dbtype !== 'mysql') {
|
||||
$conn->exec("SET TIME ZONE INTERVAL '+00:00' HOUR TO MINUTE");
|
||||
} else {
|
||||
$conn->exec("SET time_zone = '+0:00'");
|
||||
}
|
||||
|
||||
$res = $this->updateStatus("Creating database tables...");
|
||||
$res = $this->updateStatus('Creating database tables...');
|
||||
if (!$this->createCoreTables($conn)) {
|
||||
$this->updateStatus("Error creating tables.", true);
|
||||
$this->updateStatus('Error creating tables.', true);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -365,21 +346,67 @@ abstract class Installer
|
||||
* Open a connection to the database.
|
||||
*
|
||||
* @param string $dsn
|
||||
* @return DB|DB_Error
|
||||
* @return MDB2_Driver_Common
|
||||
* @throws Exception
|
||||
*/
|
||||
public function connectDatabase(string $dsn)
|
||||
protected function connectDatabase(string $dsn)
|
||||
{
|
||||
global $_DB;
|
||||
return $_DB->connect($dsn);
|
||||
$conn = MDB2::connect($dsn);
|
||||
if (MDB2::isError($conn)) {
|
||||
throw new Exception(
|
||||
'Cannot connect to database: ' . $conn->getMessage()
|
||||
);
|
||||
}
|
||||
return $conn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the database server character set.
|
||||
*
|
||||
* @param MDB2_Driver_Common $conn
|
||||
* @param string $dbtype
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function getDatabaseCharset($conn, string $dbtype): string
|
||||
{
|
||||
$database = $conn->getDatabase();
|
||||
|
||||
switch ($dbtype) {
|
||||
case 'pgsql':
|
||||
$res = $conn->query('SHOW server_encoding');
|
||||
|
||||
if (MDB2::isError($res)) {
|
||||
throw new Exception($res->getMessage());
|
||||
}
|
||||
$ret = $res->fetchOne();
|
||||
break;
|
||||
case 'mysql':
|
||||
$res = $conn->query(
|
||||
"SHOW SESSION VARIABLES LIKE 'character_set_server'"
|
||||
);
|
||||
if (MDB2::isError($res)) {
|
||||
throw new Exception($res->getMessage());
|
||||
}
|
||||
[, $ret] = $res->fetchRow(MDB2_FETCHMODE_ORDERED);
|
||||
break;
|
||||
default:
|
||||
throw new Exception('Unknown DB type selected.');
|
||||
}
|
||||
|
||||
if (MDB2::isError($ret)) {
|
||||
throw new Exception($ret->getMessage());
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create core tables on the given database connection.
|
||||
*
|
||||
* @param DB_common $conn
|
||||
* @param MDB2_Driver_Common $conn
|
||||
* @return bool
|
||||
*/
|
||||
public function createCoreTables(DB_common $conn): bool
|
||||
public function createCoreTables($conn): bool
|
||||
{
|
||||
$schema = Schema::get($conn, $this->dbtype);
|
||||
$tableDefs = $this->getCoreSchema();
|
||||
@ -520,11 +547,11 @@ abstract class Installer
|
||||
* Install schema into the database
|
||||
*
|
||||
* @param string $filename location of database schema file
|
||||
* @param DB_common $conn connection to database
|
||||
* @param MDB2_Driver_Common $conn connection to database
|
||||
*
|
||||
* @return bool - indicating success or failure
|
||||
*/
|
||||
public function runDbScript(string $filename, DB_common $conn): bool
|
||||
public function runDbScript(string $filename, $conn): bool
|
||||
{
|
||||
$sql = trim(file_get_contents(INSTALLDIR . '/db/' . $filename));
|
||||
$stmts = explode(';', $sql);
|
||||
|
204
plugins/OpenID/lib/openiddbconn.php
Normal file
204
plugins/OpenID/lib/openiddbconn.php
Normal file
@ -0,0 +1,204 @@
|
||||
<?php
|
||||
// This file is part of GNU social - https://www.gnu.org/software/social
|
||||
//
|
||||
// GNU social is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// GNU social is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with GNU social. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* @package GNUsocial
|
||||
* @author Alexei Sorokin <sor.alexei@meowr.ru>
|
||||
* @copyright 2020 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
|
||||
*/
|
||||
|
||||
defined('GNUSOCIAL') || die();
|
||||
|
||||
require_once 'Auth/OpenID/DatabaseConnection.php';
|
||||
|
||||
/**
|
||||
* A DB abstraction error for OpenID's Auth_OpenID_SQLStore
|
||||
*
|
||||
* @package GNUsocial
|
||||
* @author Alexei Sorokin <sor.alexei@meowr.ru>
|
||||
* @copyright 2020 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
|
||||
*/
|
||||
class SQLStore_DB_Connection extends Auth_OpenID_DatabaseConnection
|
||||
{
|
||||
private $conn = null;
|
||||
private $autocommit = true;
|
||||
|
||||
/**
|
||||
* @param string|array $dsn
|
||||
* @param array $options
|
||||
*/
|
||||
public function __construct($dsn, array $options = [])
|
||||
{
|
||||
if (!is_array($dsn)) {
|
||||
$dsn = MDB2::parseDSN($dsn);
|
||||
}
|
||||
$dsn['new_link'] = true;
|
||||
|
||||
// To create a new Database connection is an absolute must, because
|
||||
// php-openid code delays its transactions commitment.
|
||||
// Is a must because our Internal Session Handler uses the database
|
||||
// and depends on immediate commitment.
|
||||
$this->conn = MDB2::connect($dsn, $options);
|
||||
|
||||
if (MDB2::isError($this->conn)) {
|
||||
throw new ServerException($this->conn->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
$this->conn->disconnect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets auto-commit mode on this database connection.
|
||||
*
|
||||
* @param bool $mode
|
||||
*/
|
||||
public function autoCommit($mode)
|
||||
{
|
||||
$this->autocommit = $mode;
|
||||
if ($mode && $this->conn->inTransaction()) {
|
||||
$this->commit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run an SQL query with the specified parameters, if any.
|
||||
*
|
||||
* @param string $sql
|
||||
* @param array $params
|
||||
* @param bool $is_manip
|
||||
* @return mixed
|
||||
*/
|
||||
private function _query(string $sql, array $params = [], bool $is_manip)
|
||||
{
|
||||
$stmt_type = $is_manip ? MDB2_PREPARE_MANIP : MDB2_PREPARE_RESULT;
|
||||
if ($is_manip && !$this->autocommit) {
|
||||
$this->begin();
|
||||
}
|
||||
|
||||
$split = preg_split(
|
||||
'/((?<!\\\)[&?!]|\'!\')/',
|
||||
$sql,
|
||||
-1,
|
||||
PREG_SPLIT_DELIM_CAPTURE
|
||||
);
|
||||
$sql = '';
|
||||
// '!' has no meaning in MDB2, but MDB2 can detect types like BLOB.
|
||||
$i = 0;
|
||||
foreach ($split as $part) {
|
||||
if (!in_array($part, ['?', '!', "'!'"])) {
|
||||
$sql .= preg_replace('/\\\([!])/', '\\1', $part);
|
||||
} else {
|
||||
++$i;
|
||||
$sql .= '?';
|
||||
}
|
||||
}
|
||||
|
||||
$stmt = $this->conn->prepare($sql, null, $stmt_type);
|
||||
if (MDB2::isError($stmt)) {
|
||||
// php-openid actually expects PEAR_Error.
|
||||
return $res;
|
||||
}
|
||||
if (count($params) > 0) {
|
||||
$stmt->bindValueArray($params);
|
||||
}
|
||||
$res = $stmt->execute();
|
||||
if (MDB2::isError($res)) {
|
||||
return $res;
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run an SQL query with the specified parameters, if any.
|
||||
*
|
||||
* @param string $sql
|
||||
* @param array $params
|
||||
* @return mixed
|
||||
*/
|
||||
public function query($sql, $params = [])
|
||||
{
|
||||
return $this->_query($sql, $params, true);
|
||||
}
|
||||
|
||||
public function begin()
|
||||
{
|
||||
$this->conn->beginTransaction();
|
||||
}
|
||||
|
||||
public function commit()
|
||||
{
|
||||
$this->conn->commit();
|
||||
}
|
||||
|
||||
public function rollback()
|
||||
{
|
||||
$this->conn->rollback();
|
||||
}
|
||||
|
||||
/**
|
||||
* Run an SQL query and return the first column of the first row of the
|
||||
* result set, if any.
|
||||
*
|
||||
* @param string $sql
|
||||
* @param array $params
|
||||
* @return string|PEAR_Error
|
||||
*/
|
||||
public function getOne($sql, $params = [])
|
||||
{
|
||||
$res = $this->_query($sql, $params, false);
|
||||
if (MDB2::isError($res)) {
|
||||
return $res;
|
||||
}
|
||||
return $res->fetchOne() ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Run an SQL query and return the first row of the result set, if any.
|
||||
*
|
||||
* @param string $sql
|
||||
* @param array $params
|
||||
* @return array|PEAR_Error
|
||||
*/
|
||||
public function getRow($sql, $params = [])
|
||||
{
|
||||
$res = $this->_query($sql, $params, false);
|
||||
if (MDB2::isError($res)) {
|
||||
return $res;
|
||||
}
|
||||
return $res->fetchRow(MDB2_FETCHMODE_ASSOC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run an SQL query with the specified parameters, if any.
|
||||
*
|
||||
* @param string $sql
|
||||
* @param array $params
|
||||
* @return array|PEAR_Error
|
||||
*/
|
||||
public function getAll($sql, $params = [])
|
||||
{
|
||||
$res = $this->_query($sql, $params, false);
|
||||
if (MDB2::isError($res)) {
|
||||
return $res;
|
||||
}
|
||||
return $res->fetchAll(MDB2_FETCHMODE_ASSOC);
|
||||
}
|
||||
}
|
@ -21,11 +21,12 @@
|
||||
|
||||
defined('GNUSOCIAL') || die();
|
||||
|
||||
require_once('Auth/OpenID.php');
|
||||
require_once('Auth/OpenID/Consumer.php');
|
||||
require_once('Auth/OpenID/Server.php');
|
||||
require_once('Auth/OpenID/SReg.php');
|
||||
require_once('Auth/OpenID/MySQLStore.php');
|
||||
require_once __DIR__ . '/lib/openiddbconn.php';
|
||||
|
||||
require_once 'Auth/OpenID.php';
|
||||
require_once 'Auth/OpenID/Consumer.php';
|
||||
require_once 'Auth/OpenID/Server.php';
|
||||
require_once 'Auth/OpenID/SReg.php';
|
||||
|
||||
// About one year cookie expiry
|
||||
|
||||
@ -34,31 +35,24 @@ define('OPENID_COOKIE_KEY', 'lastusedopenid');
|
||||
|
||||
function oid_store()
|
||||
{
|
||||
global $_PEAR;
|
||||
static $store = null;
|
||||
|
||||
if (is_null($store)) {
|
||||
// To create a new Database connection is an absolute must
|
||||
// because database is in transaction (auto-commit = false)
|
||||
// mode during OpenID operation
|
||||
// Is a must because our Internal Session Handler uses database
|
||||
// and depends on auto-commit = true
|
||||
$dsn = common_config('db', 'database');
|
||||
$options = PEAR::getStaticProperty('DB', 'options');
|
||||
$options = $_PEAR->getStaticProperty('MDB2', 'options');
|
||||
|
||||
if (!is_array($options)) {
|
||||
$options = [];
|
||||
}
|
||||
$db = DB::connect($dsn, $options);
|
||||
|
||||
if ((new PEAR)->isError($db)) {
|
||||
throw new ServerException($db->getMessage());
|
||||
}
|
||||
$dbconn = new SQLStore_DB_Connection($dsn, $options);
|
||||
|
||||
switch (common_config('db', 'type')) {
|
||||
case 'pgsql':
|
||||
$store = new Auth_OpenID_PostgreSQLStore($db);
|
||||
$store = new Auth_OpenID_PostgreSQLStore($dbconn);
|
||||
break;
|
||||
case 'mysql':
|
||||
$store = new Auth_OpenID_MySQLStore($db);
|
||||
$store = new Auth_OpenID_MySQLStore($dbconn);
|
||||
break;
|
||||
default:
|
||||
throw new ServerException('Unknown DB type selected.');
|
||||
@ -247,8 +241,12 @@ function oid_authenticate($openid_url, $returnto, $immediate=false)
|
||||
} else {
|
||||
// Generate form markup and render it.
|
||||
$form_id = 'openid_message';
|
||||
$form_html = $auth_request->formMarkup($trust_root, $process_url,
|
||||
$immediate, array('id' => $form_id));
|
||||
$form_html = $auth_request->formMarkup(
|
||||
$trust_root,
|
||||
$process_url,
|
||||
$immediate,
|
||||
['id' => $form_id]
|
||||
);
|
||||
|
||||
// XXX: This is cheap, but things choke if we don't escape ampersands
|
||||
// in the HTML attributes
|
||||
|
@ -121,7 +121,7 @@ function handleError($error)
|
||||
}
|
||||
}
|
||||
if ($error instanceof DB_DataObject_Error
|
||||
|| $error instanceof DB_Error
|
||||
|| $error instanceof MDB2_Error
|
||||
|| ($error instanceof PEAR_Exception && $error->getCode() == -24)
|
||||
) {
|
||||
//If we run into a DB error, assume we can't connect to the DB at all
|
||||
|
Loading…
Reference in New Issue
Block a user