commit
78ce03491e
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,510 +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 versions 4 and 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-2005 The PHP Group |
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
||||
* @version CVS: $Id: dbase.php,v 1.39 2005/02/19 23:25:25 danielc Exp $ |
||||
* @link http://pear.php.net/package/DB |
||||
*/ |
||||
|
||||
/** |
||||
* Obtain the DB_common class so it can be extended from |
||||
*/ |
||||
require_once 'DB/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-2005 The PHP Group |
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
||||
* @version Release: @package_version@ |
||||
* @link http://pear.php.net/package/DB |
||||
*/ |
||||
class DB_dbase extends DB_common |
||||
{ |
||||
// {{{ properties |
||||
|
||||
/** |
||||
* The DB driver type (mysql, oci8, odbc, etc.) |
||||
* @var string |
||||
*/ |
||||
var $phptype = 'dbase'; |
||||
|
||||
/** |
||||
* The database syntax variant to be used (db2, access, etc.), if any |
||||
* @var string |
||||
*/ |
||||
var $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 |
||||
*/ |
||||
var $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 |
||||
*/ |
||||
var $errorcode_map = array( |
||||
); |
||||
|
||||
/** |
||||
* The raw database connection created by PHP |
||||
* @var resource |
||||
*/ |
||||
var $connection; |
||||
|
||||
/** |
||||
* The DSN information for connecting to a database |
||||
* @var array |
||||
*/ |
||||
var $dsn = array(); |
||||
|
||||
|
||||
/** |
||||
* A means of emulating result resources |
||||
* @var array |
||||
*/ |
||||
var $res_row = array(); |
||||
|
||||
/** |
||||
* The quantity of results so far |
||||
* |
||||
* For emulating result resources. |
||||
* |
||||
* @var integer |
||||
*/ |
||||
var $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 |
||||
*/ |
||||
var $types = array( |
||||
'C' => 'character', |
||||
'D' => 'date', |
||||
'L' => 'boolean', |
||||
'M' => 'memo', |
||||
'N' => 'number', |
||||
); |
||||
|
||||
|
||||
// }}} |
||||
// {{{ constructor |
||||
|
||||
/** |
||||
* This constructor calls <kbd>$this->DB_common()</kbd> |
||||
* |
||||
* @return void |
||||
*/ |
||||
function DB_dbase() |
||||
{ |
||||
$this->DB_common(); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ 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 (PEAR::isError($db)) { |
||||
* die($db->getMessage()); |
||||
* } |
||||
* </code> |
||||
* |
||||
* @param array $dsn the data source name |
||||
* @param bool $persistent should the connection be persistent? |
||||
* |
||||
* @return int DB_OK on success. A DB_Error object on failure. |
||||
*/ |
||||
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 |
||||
*/ |
||||
function disconnect() |
||||
{ |
||||
$ret = @dbase_close($this->connection); |
||||
$this->connection = null; |
||||
return $ret; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ &query() |
||||
|
||||
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() |
||||
*/ |
||||
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; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ 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 resource $result PHP's query result resource |
||||
* |
||||
* @return int the number of columns. A DB_Error object on failure. |
||||
* |
||||
* @see DB_result::numCols() |
||||
*/ |
||||
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 resource $result PHP's query result resource |
||||
* |
||||
* @return int the number of rows. A DB_Error object on failure. |
||||
* |
||||
* @see DB_result::numRows() |
||||
*/ |
||||
function numRows($foo) |
||||
{ |
||||
return @dbase_numrecords($this->connection); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ quoteSmart() |
||||
|
||||
/** |
||||
* Formats input so it can be safely used in a query |
||||
* |
||||
* @param mixed $in the data to be formatted |
||||
* |
||||
* @return mixed the formatted data. The format depends on the input's |
||||
* PHP type: |
||||
* + null = the string <samp>NULL</samp> |
||||
* + boolean = <samp>T</samp> if true or |
||||
* <samp>F</samp> if false. Use the <kbd>Logical</kbd> |
||||
* data type. |
||||
* + integer or double = the unquoted number |
||||
* + other (including strings and numeric strings) = |
||||
* the data with single quotes escaped by preceeding |
||||
* single quotes then the whole string is encapsulated |
||||
* between single quotes |
||||
* |
||||
* @see DB_common::quoteSmart() |
||||
* @since Method available since Release 1.6.0 |
||||
*/ |
||||
function quoteSmart($in) |
||||
{ |
||||
if (is_int($in) || is_double($in)) { |
||||
return $in; |
||||
} elseif (is_bool($in)) { |
||||
return $in ? 'T' : 'F'; |
||||
} elseif (is_null($in)) { |
||||
return 'NULL'; |
||||
} else { |
||||
return "'" . $this->escapeSimple($in) . "'"; |
||||
} |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ 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 an associative array with the information requested. |
||||
* A DB_Error object on failure. |
||||
* |
||||
* @see DB_common::tableInfo() |
||||
* @since Method available since Release 1.7.0 |
||||
*/ |
||||
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,770 +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 versions 4 and 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-2005 The PHP Group |
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
||||
* @version CVS: $Id: fbsql.php,v 1.82 2005/03/04 23:12:36 danielc Exp $ |
||||
* @link http://pear.php.net/package/DB |
||||
*/ |
||||
|
||||
/** |
||||
* Obtain the DB_common class so it can be extended from |
||||
*/ |
||||
require_once 'DB/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-2005 The PHP Group |
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
||||
* @version Release: @package_version@ |
||||
* @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 |
||||
*/ |
||||
var $phptype = 'fbsql'; |
||||
|
||||
/** |
||||
* The database syntax variant to be used (db2, access, etc.), if any |
||||
* @var string |
||||
*/ |
||||
var $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 |
||||
*/ |
||||
var $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 |
||||
*/ |
||||
var $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 |
||||
*/ |
||||
var $connection; |
||||
|
||||
/** |
||||
* The DSN information for connecting to a database |
||||
* @var array |
||||
*/ |
||||
var $dsn = array(); |
||||
|
||||
|
||||
// }}} |
||||
// {{{ constructor |
||||
|
||||
/** |
||||
* This constructor calls <kbd>$this->DB_common()</kbd> |
||||
* |
||||
* @return void |
||||
*/ |
||||
function DB_fbsql() |
||||
{ |
||||
$this->DB_common(); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ 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 DB_OK on success. A DB_Error object on failure. |
||||
*/ |
||||
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() |
||||
|
||||
/** |
||||
* Disconnects from the database server |
||||
* |
||||
* @return bool TRUE on success, FALSE on failure |
||||
*/ |
||||
function disconnect() |
||||
{ |
||||
$ret = @fbsql_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 |
||||
*/ |
||||
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 (DB::isManip($query)) { |
||||
return DB_OK; |
||||
} |
||||
return $result; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ nextResult() |
||||
|
||||
/** |
||||
* 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 |
||||
*/ |
||||
function nextResult($result) |
||||
{ |
||||
return @fbsql_next_result($result); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ 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() |
||||
*/ |
||||
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; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ freeResult() |
||||
|
||||
/** |
||||
* 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() |
||||
*/ |
||||
function freeResult($result) |
||||
{ |
||||
return @fbsql_free_result($result); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ autoCommit() |
||||
|
||||
/** |
||||
* 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. |
||||
*/ |
||||
function autoCommit($onoff=false) |
||||
{ |
||||
if ($onoff) { |
||||
$this->query("SET COMMIT TRUE"); |
||||
} else { |
||||
$this->query("SET COMMIT FALSE"); |
||||
} |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ commit() |
||||
|
||||
/** |
||||
* Commits the current transaction |
||||
* |
||||
* @return int DB_OK on success. A DB_Error object on failure. |
||||
*/ |
||||
function commit() |
||||
{ |
||||
@fbsql_commit(); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ rollback() |
||||
|
||||
/** |
||||
* Reverts the current transaction |
||||
* |
||||
* @return int DB_OK on success. A DB_Error object on failure. |
||||
*/ |
||||
function rollback() |
||||
{ |
||||
@fbsql_rollback(); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ 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 resource $result PHP's query result resource |
||||
* |
||||
* @return int the number of columns. A DB_Error object on failure. |
||||
* |
||||
* @see DB_result::numCols() |
||||
*/ |
||||
function numCols($result) |
||||
{ |
||||
$cols = @fbsql_num_fields($result); |
||||
if (!$cols) { |
||||
return $this->fbsqlRaiseError(); |
||||
} |
||||
return $cols; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ 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 the number of rows. A DB_Error object on failure. |
||||
* |
||||
* @see DB_result::numRows() |
||||
*/ |
||||
function numRows($result) |
||||
{ |
||||
$rows = @fbsql_num_rows($result); |
||||
if ($rows === null) { |
||||
return $this->fbsqlRaiseError(); |
||||
} |
||||
return $rows; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ affectedRows() |
||||
|
||||
/** |
||||
* 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. |
||||
*/ |
||||
function affectedRows() |
||||
{ |
||||
if (DB::isManip($this->last_query)) { |
||||
$result = @fbsql_affected_rows($this->connection); |
||||
} else { |
||||
$result = 0; |
||||
} |
||||
return $result; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ nextId() |
||||
|
||||
/** |
||||
* 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 the next id number in the sequence. |
||||
* A DB_Error object on failure. |
||||
* |
||||
* @see DB_common::nextID(), DB_common::getSequenceName(), |
||||
* DB_fbsql::createSequence(), DB_fbsql::dropSequence() |
||||
*/ |
||||
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]; |
||||
} |
||||
|
||||
/** |
||||
* 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() |
||||
*/ |
||||
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; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ dropSequence() |
||||
|
||||
/** |
||||
* 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() |
||||
*/ |
||||
function dropSequence($seq_name) |
||||
{ |
||||
return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name) |
||||
. ' RESTRICT'); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ modifyLimitQuery() |
||||
|
||||
/** |
||||
* 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 |
||||
*/ |
||||
function modifyLimitQuery($query, $from, $count, $params = array()) |
||||
{ |
||||
if (DB::isManip($query)) { |
||||
return preg_replace('/^([\s(])*SELECT/i', |
||||
"\\1SELECT TOP($count)", $query); |
||||
} else { |
||||
return preg_replace('/([\s(])*SELECT/i', |
||||
"\\1SELECT TOP($from, $count)", $query); |
||||
} |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ quoteSmart() |
||||
|
||||
/** |
||||
* Formats input so it can be safely used in a query |
||||
* |
||||
* @param mixed $in the data to be formatted |
||||
* |
||||
* @return mixed the formatted data. The format depends on the input's |
||||
* PHP type: |
||||
* + null = the string <samp>NULL</samp> |
||||
* + boolean = string <samp>TRUE</samp> or <samp>FALSE</samp> |
||||
* + integer or double = the unquoted number |
||||
* + other (including strings and numeric strings) = |
||||
* the data escaped according to FrontBase's settings |
||||
* then encapsulated between single quotes |
||||
* |
||||
* @see DB_common::quoteSmart() |
||||
* @since Method available since Release 1.6.0 |
||||
*/ |
||||
function quoteSmart($in) |
||||
{ |
||||
if (is_int($in) || is_double($in)) { |
||||
return $in; |
||||
} elseif (is_bool($in)) { |
||||
return $in ? 'TRUE' : 'FALSE'; |
||||
} elseif (is_null($in)) { |
||||
return 'NULL'; |
||||
} else { |
||||
return "'" . $this->escapeSimple($in) . "'"; |
||||
} |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ fbsqlRaiseError() |
||||
|
||||
/** |
||||
* 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() |
||||
*/ |
||||
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)); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ errorNative() |
||||
|
||||
/** |
||||
* Gets the DBMS' native error code produced by the last query |
||||
* |
||||
* @return int the DBMS' error code |
||||
*/ |
||||
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 an associative array with the information requested. |
||||
* A DB_Error object on failure. |
||||
* |
||||
* @see DB_common::tableInfo() |
||||
*/ |
||||
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() |
||||
*/ |
||||
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: |
||||
*/ |
||||
|
||||
?> |
||||
File diff suppressed because it is too large
Load Diff
@ -1,681 +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 versions 4 and 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-2005 The PHP Group |
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
||||
* @version CVS: $Id: ifx.php,v 1.70 2005/02/20 00:44:48 danielc Exp $ |
||||
* @link http://pear.php.net/package/DB |
||||
*/ |
||||
|
||||
/** |
||||
* Obtain the DB_common class so it can be extended from |
||||
*/ |
||||
require_once 'DB/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-2005 The PHP Group |
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
||||
* @version Release: @package_version@ |
||||
* @link http://pear.php.net/package/DB |
||||
*/ |
||||
class DB_ifx extends DB_common |
||||
{ |
||||
// {{{ properties |
||||
|
||||
/** |
||||
* The DB driver type (mysql, oci8, odbc, etc.) |
||||
* @var string |
||||
*/ |
||||
var $phptype = 'ifx'; |
||||
|
||||
/** |
||||
* The database syntax variant to be used (db2, access, etc.), if any |
||||
* @var string |
||||
*/ |
||||
var $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 |
||||
*/ |
||||
var $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 |
||||
*/ |
||||
var $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, |
||||
'-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, |
||||
'-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 |
||||
*/ |
||||
var $connection; |
||||
|
||||
/** |
||||
* The DSN information for connecting to a database |
||||
* @var array |
||||
*/ |
||||
var $dsn = array(); |
||||
|
||||
|
||||
/** |
||||
* Should data manipulation queries be committed automatically? |
||||
* @var bool |
||||
* @access private |
||||
*/ |
||||
var $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 |
||||
*/ |
||||
var $transaction_opcount = 0; |
||||
|
||||
/** |
||||
* The number of rows affected by a data manipulation query |
||||
* @var integer |
||||
* @access private |
||||
*/ |
||||
var $affected = 0; |
||||
|
||||
|
||||
// }}} |
||||
// {{{ constructor |
||||
|
||||
/** |
||||
* This constructor calls <kbd>$this->DB_common()</kbd> |
||||
* |
||||
* @return void |
||||
*/ |
||||
function DB_ifx() |
||||
{ |
||||
$this->DB_common(); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ 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 DB_OK on success. A DB_Error object on failure. |
||||
*/ |
||||
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() |
||||
|
||||
/** |
||||
* Disconnects from the database server |
||||
* |
||||
* @return bool TRUE on success, FALSE on failure |
||||
*/ |
||||
function disconnect() |
||||
{ |
||||
$ret = @ifx_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 |
||||
*/ |
||||
function simpleQuery($query) |
||||
{ |
||||
$ismanip = DB::isManip($query); |
||||
$this->last_query = $query; |
||||
$this->affected = null; |
||||
if (preg_match('/(SELECT)/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)/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; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ nextResult() |
||||
|
||||
/** |
||||
* 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 |
||||
*/ |
||||
function nextResult($result) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ affectedRows() |
||||
|
||||
/** |
||||
* 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. |
||||
*/ |
||||
function affectedRows() |
||||
{ |
||||
if (DB::isManip($this->last_query)) { |
||||
return $this->affected; |
||||
} else { |
||||
return 0; |
||||
} |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ 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() |
||||
*/ |
||||
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; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ 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 resource $result PHP's query result resource |
||||
* |
||||
* @return int the number of columns. A DB_Error object on failure. |
||||
* |
||||
* @see DB_result::numCols() |
||||
*/ |
||||
function numCols($result) |
||||
{ |
||||
if (!$cols = @ifx_num_fields($result)) { |
||||
return $this->ifxRaiseError(); |
||||
} |
||||
return $cols; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ freeResult() |
||||
|
||||
/** |
||||
* 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() |
||||
*/ |
||||
function freeResult($result) |
||||
{ |
||||
return @ifx_free_result($result); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ autoCommit() |
||||
|
||||
/** |
||||
* 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. |
||||
*/ |
||||
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; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ commit() |
||||
|
||||
/** |
||||
* Commits the current transaction |
||||
* |
||||
* @return int DB_OK on success. A DB_Error object on failure. |
||||
*/ |
||||
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; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ rollback() |
||||
|
||||
/** |
||||
* Reverts the current transaction |
||||
* |
||||
* @return int DB_OK on success. A DB_Error object on failure. |
||||
*/ |
||||
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; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ ifxRaiseError() |
||||
|
||||
/** |
||||
* 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() |
||||
*/ |
||||
function ifxRaiseError($errno = null) |
||||
{ |
||||
if ($errno === null) { |
||||
$errno = $this->errorCode(ifx_error()); |
||||
} |
||||
return $this->raiseError($errno, null, null, null, |
||||
$this->errorNative()); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ errorNative() |
||||
|
||||
/** |
||||
* Gets the DBMS' native error code and message produced by the last query |
||||
* |
||||
* @return string the DBMS' error code and message |
||||
*/ |
||||
function errorNative() |
||||
{ |
||||
return @ifx_error() . ' ' . @ifx_errormsg(); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ errorCode() |
||||
|
||||
/** |
||||
* 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. |
||||
*/ |
||||
function errorCode($nativecode) |
||||
{ |
||||
if (ereg('SQLCODE=(.*)]', $nativecode, $match)) { |
||||
$code = $match[1]; |
||||
if (isset($this->errorcode_map[$code])) { |
||||
return $this->errorcode_map[$code]; |
||||
} |
||||
} |
||||
return DB_ERROR; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ 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 an associative array with the information requested. |
||||
* A DB_Error object on failure. |
||||
* |
||||
* @see DB_common::tableInfo() |
||||
* @since Method available since Release 1.6.0 |
||||
*/ |
||||
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() |
||||
*/ |
||||
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,810 +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 versions 4 and 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-2005 The PHP Group |
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
||||
* @version CVS: $Id: msql.php,v 1.57 2005/02/22 07:26:46 danielc Exp $ |
||||
* @link http://pear.php.net/package/DB |
||||
*/ |
||||
|
||||
/** |
||||
* Obtain the DB_common class so it can be extended from |
||||
*/ |
||||
require_once 'DB/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-2005 The PHP Group |
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
||||
* @version Release: @package_version@ |
||||
* @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 |
||||
*/ |
||||
var $phptype = 'msql'; |
||||
|
||||
/** |
||||
* The database syntax variant to be used (db2, access, etc.), if any |
||||
* @var string |
||||
*/ |
||||
var $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 |
||||
*/ |
||||
var $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 |
||||
*/ |
||||
var $errorcode_map = array( |
||||
); |
||||
|
||||
/** |
||||
* The raw database connection created by PHP |
||||
* @var resource |
||||
*/ |
||||
var $connection; |
||||
|
||||
/** |
||||
* The DSN information for connecting to a database |
||||
* @var array |
||||
*/ |
||||
var $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 |
||||
*/ |
||||
var $_result; |
||||
|
||||
|
||||
// }}} |
||||
// {{{ constructor |
||||
|
||||
/** |
||||
* This constructor calls <kbd>$this->DB_common()</kbd> |
||||
* |
||||
* @return void |
||||
*/ |
||||
function DB_msql() |
||||
{ |
||||
$this->DB_common(); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ 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 (PEAR::isError($db)) { |
||||
* die($db->getMessage()); |
||||
* } |
||||
* </code> |
||||
* |
||||
* @param array $dsn the data source name |
||||
* @param bool $persistent should the connection be persistent? |
||||
* |
||||
* @return int DB_OK on success. A DB_Error object on failure. |
||||
*/ |
||||
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() |
||||
|
||||
/** |
||||
* Disconnects from the database server |
||||
* |
||||
* @return bool TRUE on success, FALSE on failure |
||||
*/ |
||||
function disconnect() |
||||
{ |
||||
$ret = @msql_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 |
||||
*/ |
||||
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 (DB::isManip($query)) { |
||||
$this->_result = $result; |
||||
return DB_OK; |
||||
} else { |
||||
$this->_result = false; |
||||
return $result; |
||||
} |
||||
} |
||||
|
||||
|
||||
// }}} |
||||
// {{{ nextResult() |
||||
|
||||
/** |
||||
* 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 |
||||
*/ |
||||
function nextResult($result) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ 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. |
||||
* |
||||
* 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() |
||||
*/ |
||||
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; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ freeResult() |
||||
|
||||
/** |
||||
* 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() |
||||
*/ |
||||
function freeResult($result) |
||||
{ |
||||
return @msql_free_result($result); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ 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 resource $result PHP's query result resource |
||||
* |
||||
* @return int the number of columns. A DB_Error object on failure. |
||||
* |
||||
* @see DB_result::numCols() |
||||
*/ |
||||
function numCols($result) |
||||
{ |
||||
$cols = @msql_num_fields($result); |
||||
if (!$cols) { |
||||
return $this->msqlRaiseError(); |
||||
} |
||||
return $cols; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ 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 the number of rows. A DB_Error object on failure. |
||||
* |
||||
* @see DB_result::numRows() |
||||
*/ |
||||
function numRows($result) |
||||
{ |
||||
$rows = @msql_num_rows($result); |
||||
if ($rows === false) { |
||||
return $this->msqlRaiseError(); |
||||
} |
||||
return $rows; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ affected() |
||||
|
||||
/** |
||||
* 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. |
||||
*/ |
||||
function affectedRows() |
||||
{ |
||||
if (!$this->_result) { |
||||
return 0; |
||||
} |
||||
return msql_affected_rows($this->_result); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ nextId() |
||||
|
||||
/** |
||||
* 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 the next id number in the sequence. |
||||
* A DB_Error object on failure. |
||||
* |
||||
* @see DB_common::nextID(), DB_common::getSequenceName(), |
||||
* DB_msql::createSequence(), DB_msql::dropSequence() |
||||
*/ |
||||
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]; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ createSequence() |
||||
|
||||
/** |
||||
* 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() |
||||
*/ |
||||
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; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ dropSequence() |
||||
|
||||
/** |
||||
* 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() |
||||
*/ |
||||
function dropSequence($seq_name) |
||||
{ |
||||
return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name)); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ quoteIdentifier() |
||||
|
||||
/** |
||||
* 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 |
||||
*/ |
||||
function quoteIdentifier($str) |
||||
{ |
||||
return $this->raiseError(DB_ERROR_UNSUPPORTED); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ escapeSimple() |
||||
|
||||
/** |
||||
* 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 |
||||
*/ |
||||
function escapeSimple($str) |
||||
{ |
||||
return addslashes($str); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ msqlRaiseError() |
||||
|
||||
/** |
||||
* 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() |
||||
*/ |
||||
function msqlRaiseError($errno = null) |
||||
{ |
||||
$native = $this->errorNative(); |
||||
if ($errno === null) { |
||||
$errno = $this->errorCode($native); |
||||
} |
||||
return $this->raiseError($errno, null, null, null, $native); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ errorNative() |
||||
|
||||
/** |
||||
* Gets the DBMS' native error message produced by the last query |
||||
* |
||||
* @return string the DBMS' error message |
||||
*/ |
||||
function errorNative() |
||||
{ |
||||
return @msql_error(); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ errorCode() |
||||
|
||||
/** |
||||
* 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 |
||||
*/ |
||||
function errorCode($errormsg) |
||||
{ |
||||
static $error_regexps; |
||||
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; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ 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 an associative array with the information requested. |
||||
* A DB_Error object on failure. |
||||
* |
||||
* @see DB_common::setOption() |
||||
*/ |
||||
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 the array containing the list of objects requested |
||||
* |
||||
* @access protected |
||||
* @see DB_common::getListOf() |
||||
*/ |
||||
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,914 +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 versions 4 and 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-2005 The PHP Group |
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
||||
* @version CVS: $Id: mssql.php,v 1.83 2005/03/07 18:24:51 danielc Exp $ |
||||
* @link http://pear.php.net/package/DB |
||||
*/ |
||||
|
||||
/** |
||||
* Obtain the DB_common class so it can be extended from |
||||
*/ |
||||
require_once 'DB/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. |
||||
* |
||||
* @category Database |
||||
* @package DB |
||||
* @author Sterling Hughes <sterling@php.net> |
||||
* @author Daniel Convissor <danielc@php.net> |
||||
* @copyright 1997-2005 The PHP Group |
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
||||
* @version Release: @package_version@ |
||||
* @link http://pear.php.net/package/DB |
||||
*/ |
||||
class DB_mssql extends DB_common |
||||
{ |
||||
// {{{ properties |
||||
|
||||
/** |
||||
* The DB driver type (mysql, oci8, odbc, etc.) |
||||
* @var string |
||||
*/ |
||||
var $phptype = 'mssql'; |
||||
|
||||
/** |
||||
* The database syntax variant to be used (db2, access, etc.), if any |
||||
* @var string |
||||
*/ |
||||
var $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 |
||||
*/ |
||||
var $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 |
||||
var $errorcode_map = array( |
||||
110 => DB_ERROR_VALUE_COUNT_ON_ROW, |
||||
155 => DB_ERROR_NOSUCHFIELD, |
||||
170 => DB_ERROR_SYNTAX, |
||||
207 => DB_ERROR_NOSUCHFIELD, |
||||
208 => DB_ERROR_NOSUCHTABLE, |
||||
245 => DB_ERROR_INVALID_NUMBER, |
||||
515 => DB_ERROR_CONSTRAINT_NOT_NULL, |
||||
547 => DB_ERROR_CONSTRAINT, |
||||
1913 => DB_ERROR_ALREADY_EXISTS, |
||||
2627 => DB_ERROR_CONSTRAINT, |
||||
2714 => DB_ERROR_ALREADY_EXISTS, |
||||
3701 => DB_ERROR_NOSUCHTABLE, |
||||
8134 => DB_ERROR_DIVZERO, |
||||
); |
||||
|
||||
/** |
||||
* The raw database connection created by PHP |
||||
* @var resource |
||||
*/ |
||||
var $connection; |
||||
|
||||
/** |
||||
* The DSN information for connecting to a database |
||||
* @var array |
||||
*/ |
||||
var $dsn = array(); |
||||
|
||||
|
||||
/** |
||||
* Should data manipulation queries be committed automatically? |
||||
* @var bool |
||||
* @access private |
||||
*/ |
||||
var $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 |
||||
*/ |
||||
var $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 |
||||
*/ |
||||
var $_db = null; |
||||
|
||||
|
||||
// }}} |
||||
// {{{ constructor |
||||
|
||||
/** |
||||
* This constructor calls <kbd>$this->DB_common()</kbd> |
||||
* |
||||
* @return void |
||||
*/ |
||||
function DB_mssql() |
||||
{ |
||||
$this->DB_common(); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ 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 DB_OK on success. A DB_Error object on failure. |
||||
*/ |
||||
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 |
||||
*/ |
||||
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 |
||||
*/ |
||||
function simpleQuery($query) |
||||
{ |
||||
$ismanip = DB::isManip($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() |
||||
|
||||
/** |
||||
* 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 |
||||
*/ |
||||
function nextResult($result) |
||||
{ |
||||
return @mssql_next_result($result); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ 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() |
||||
*/ |
||||
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_array($result, MSSQL_ASSOC); |
||||
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; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ freeResult() |
||||
|
||||
/** |
||||
* 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() |
||||
*/ |
||||
function freeResult($result) |
||||
{ |
||||
return @mssql_free_result($result); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ 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 resource $result PHP's query result resource |
||||
* |
||||
* @return int the number of columns. A DB_Error object on failure. |
||||
* |
||||
* @see DB_result::numCols() |
||||
*/ |
||||
function numCols($result) |
||||
{ |
||||
$cols = @mssql_num_fields($result); |
||||
if (!$cols) { |
||||
return $this->mssqlRaiseError(); |
||||
} |
||||
return $cols; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ 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 the number of rows. A DB_Error object on failure. |
||||
* |
||||
* @see DB_result::numRows() |
||||
*/ |
||||
function numRows($result) |
||||
{ |
||||
$rows = @mssql_num_rows($result); |
||||
if ($rows === false) { |
||||
return $this->mssqlRaiseError(); |
||||
} |
||||
return $rows; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ autoCommit() |
||||
|
||||
/** |
||||
* 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. |
||||
*/ |
||||
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; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ commit() |
||||
|
||||
/** |
||||
* Commits the current transaction |
||||
* |
||||
* @return int DB_OK on success. A DB_Error object on failure. |
||||
*/ |
||||
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; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ rollback() |
||||
|
||||
/** |
||||
* Reverts the current transaction |
||||
* |
||||
* @return int DB_OK on success. A DB_Error object on failure. |
||||
*/ |
||||
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; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ affectedRows() |
||||
|
||||
/** |
||||
* 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. |
||||
*/ |
||||
function affectedRows() |
||||
{ |
||||
if (DB::isManip($this->last_query)) { |
||||
$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; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ nextId() |
||||
|
||||
/** |
||||
* 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 the next id number in the sequence. |
||||
* A DB_Error object on failure. |
||||
* |
||||
* @see DB_common::nextID(), DB_common::getSequenceName(), |
||||
* DB_mssql::createSequence(), DB_mssql::dropSequence() |
||||
*/ |
||||
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 @@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]; |
||||
} |
||||
|
||||
/** |
||||
* 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() |
||||
*/ |
||||
function createSequence($seq_name) |
||||
{ |
||||
return $this->query('CREATE TABLE ' |
||||
. $this->getSequenceName($seq_name) |
||||
. ' ([id] [int] IDENTITY (1, 1) NOT NULL,' |
||||
. ' [vapor] [int] NULL)'); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ dropSequence() |
||||
|
||||
/** |
||||
* 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() |
||||
*/ |
||||
function dropSequence($seq_name) |
||||
{ |
||||
return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name)); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ quoteIdentifier() |
||||
|
||||
/** |
||||
* 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 |
||||
*/ |
||||
function quoteIdentifier($str) |
||||
{ |
||||
return '[' . str_replace(']', ']]', $str) . ']'; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ mssqlRaiseError() |
||||
|
||||
/** |
||||
* 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_mssql::errorNative(), DB_mssql::errorCode() |
||||
*/ |
||||
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"); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ errorNative() |
||||
|
||||
/** |
||||
* Gets the DBMS' native error code produced by the last query |
||||
* |
||||
* @return int the DBMS' error code |
||||
*/ |
||||
function errorNative() |
||||
{ |
||||
$res = @mssql_query('select @@ERROR as ErrorCode', $this->connection); |
||||
if (!$res) { |
||||
return DB_ERROR; |
||||
} |
||||
$row = @mssql_fetch_row($res); |
||||
return $row[0]; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ errorCode() |
||||
|
||||
/** |
||||
* 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 |
||||
* @return integer an error number from a DB error constant |
||||
* @see errorNative() |
||||
*/ |
||||
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; |
||||
} |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ 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 an associative array with the information requested. |
||||
* A DB_Error object on failure. |
||||
* |
||||
* @see DB_common::tableInfo() |
||||
*/ |
||||
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++) { |
||||
$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), |
||||
// We only support flags for table |
||||
'flags' => $got_string |
||||
? $this->_mssql_field_flags($result, |
||||
@mssql_field_name($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) { |
||||
@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 string the flags |
||||
* |
||||
* @access private |
||||
* @author Joern Barthel <j_barthel@web.de> |
||||
*/ |
||||
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); |
||||
|
||||
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); |
||||
|
||||
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> |
||||
*/ |
||||
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() |
||||
*/ |
||||
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: |
||||
*/ |
||||
|
||||
?> |
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,883 +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 versions 4 and 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-2005 The PHP Group |
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
||||
* @version CVS: $Id: odbc.php,v 1.78 2005/02/28 01:42:17 danielc Exp $ |
||||
* @link http://pear.php.net/package/DB |
||||
*/ |
||||
|
||||
/** |
||||
* Obtain the DB_common class so it can be extended from |
||||
*/ |
||||
require_once 'DB/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-2005 The PHP Group |
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
||||
* @version Release: @package_version@ |
||||
* @link http://pear.php.net/package/DB |
||||
*/ |
||||
class DB_odbc extends DB_common |
||||
{ |
||||
// {{{ properties |
||||
|
||||
/** |
||||
* The DB driver type (mysql, oci8, odbc, etc.) |
||||
* @var string |
||||
*/ |
||||
var $phptype = 'odbc'; |
||||
|
||||
/** |
||||
* The database syntax variant to be used (db2, access, etc.), if any |
||||
* @var string |
||||
*/ |
||||
var $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 |
||||
*/ |
||||
var $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 |
||||
*/ |
||||
var $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 |
||||
*/ |
||||
var $connection; |
||||
|
||||
/** |
||||
* The DSN information for connecting to a database |
||||
* @var array |
||||
*/ |
||||
var $dsn = array(); |
||||
|
||||
|
||||
/** |
||||
* The number of rows affected by a data manipulation query |
||||
* @var integer |
||||
* @access private |
||||
*/ |
||||
var $affected = 0; |
||||
|
||||
|
||||
// }}} |
||||
// {{{ constructor |
||||
|
||||
/** |
||||
* This constructor calls <kbd>$this->DB_common()</kbd> |
||||
* |
||||
* @return void |
||||
*/ |
||||
function DB_odbc() |
||||
{ |
||||
$this->DB_common(); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ 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 DB_OK on success. A DB_Error object on failure. |
||||
*/ |
||||
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() |
||||
|
||||
/** |
||||
* Disconnects from the database server |
||||
* |
||||
* @return bool TRUE on success, FALSE on failure |
||||
*/ |
||||
function disconnect() |
||||
{ |
||||
$err = @odbc_close($this->connection); |
||||
$this->connection = null; |
||||
return $err; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ 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 |
||||
*/ |
||||
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 (DB::isManip($query)) { |
||||
$this->affected = $result; // For affectedRows() |
||||
return DB_OK; |
||||
} |
||||
$this->affected = 0; |
||||
return $result; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ nextResult() |
||||
|
||||
/** |
||||
* 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 |
||||
*/ |
||||
function nextResult($result) |
||||
{ |
||||
return @odbc_next_result($result); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ 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() |
||||
*/ |
||||
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; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ freeResult() |
||||
|
||||
/** |
||||
* 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() |
||||
*/ |
||||
function freeResult($result) |
||||
{ |
||||
return @odbc_free_result($result); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ 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 resource $result PHP's query result resource |
||||
* |
||||
* @return int the number of columns. A DB_Error object on failure. |
||||
* |
||||
* @see DB_result::numCols() |
||||
*/ |
||||
function numCols($result) |
||||
{ |
||||
$cols = @odbc_num_fields($result); |
||||
if (!$cols) { |
||||
return $this->odbcRaiseError(); |
||||
} |
||||
return $cols; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ affectedRows() |
||||
|
||||
/** |
||||
* 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. |
||||
*/ |
||||
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; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ numRows() |
||||
|
||||
/** |
||||
* 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 the number of rows. A DB_Error object on failure. |
||||
* |
||||
* @see DB_result::numRows() |
||||
*/ |
||||
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; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ quoteIdentifier() |
||||
|
||||
/** |
||||
* 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 |
||||
*/ |
||||
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) . '"'; |
||||
} |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ quote() |
||||
|
||||
/** |
||||
* @deprecated Deprecated in release 1.6.0 |
||||
* @internal |
||||
*/ |
||||
function quote($str) |
||||
{ |
||||
return $this->quoteSmart($str); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ nextId() |
||||
|
||||
/** |
||||
* 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 the next id number in the sequence. |
||||
* A DB_Error object on failure. |
||||
* |
||||
* @see DB_common::nextID(), DB_common::getSequenceName(), |
||||
* DB_odbc::createSequence(), DB_odbc::dropSequence() |
||||
*/ |
||||
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]; |
||||
} |
||||
|
||||
/** |
||||
* 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() |
||||
*/ |
||||
function createSequence($seq_name) |
||||
{ |
||||
return $this->query('CREATE TABLE ' |
||||
. $this->getSequenceName($seq_name) |
||||
. ' (id integer NOT NULL,' |
||||
. ' PRIMARY KEY(id))'); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ dropSequence() |
||||
|
||||
/** |
||||
* 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() |
||||
*/ |
||||
function dropSequence($seq_name) |
||||
{ |
||||
return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name)); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ autoCommit() |
||||
|
||||
/** |
||||
* 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. |
||||
*/ |
||||
function autoCommit($onoff = false) |
||||
{ |
||||
if (!@odbc_autocommit($this->connection, $onoff)) { |
||||
return $this->odbcRaiseError(); |
||||
} |
||||
return DB_OK; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ commit() |
||||
|
||||
/** |
||||
* Commits the current transaction |
||||
* |
||||
* @return int DB_OK on success. A DB_Error object on failure. |
||||
*/ |
||||
function commit() |
||||
{ |
||||
if (!@odbc_commit($this->connection)) { |
||||
return $this->odbcRaiseError(); |
||||
} |
||||
return DB_OK; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ rollback() |
||||
|
||||
/** |
||||
* Reverts the current transaction |
||||
* |
||||
* @return int DB_OK on success. A DB_Error object on failure. |
||||
*/ |
||||
function rollback() |
||||
{ |
||||
if (!@odbc_rollback($this->connection)) { |
||||
return $this->odbcRaiseError(); |
||||
} |
||||
return DB_OK; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ odbcRaiseError() |
||||
|
||||
/** |
||||
* 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() |
||||
*/ |
||||
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()); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ errorNative() |
||||
|
||||
/** |
||||
* Gets the DBMS' native error code and message produced by the last query |
||||
* |
||||
* @return string the DBMS' error code and message |
||||
*/ |
||||
function errorNative() |
||||
{ |
||||
if (!is_resource($this->connection)) { |
||||
return @odbc_error() . ' ' . @odbc_errormsg(); |
||||
} |
||||
return @odbc_error($this->connection) . ' ' . @odbc_errormsg($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 an associative array with the information requested. |
||||
* A DB_Error object on failure. |
||||
* |
||||
* @see DB_common::tableInfo() |
||||
* @since Method available since Release 1.7.0 |
||||
*/ |
||||
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 string the list of objects requested |
||||
* |
||||
* @access protected |
||||
* @see DB_common::getListOf() |
||||
* @since Method available since Release 1.7.0 |
||||
*/ |
||||
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: |
||||
*/ |
||||
|
||||
?> |
||||
File diff suppressed because it is too large
Load Diff
@ -1,942 +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 versions 4 and 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-2005 The PHP Group |
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0 3.0 |
||||
* @version CVS: $Id: sqlite.php,v 1.109 2005/03/10 01:22:48 danielc Exp $ |
||||
* @link http://pear.php.net/package/DB |
||||
*/ |
||||
|
||||
/** |
||||
* Obtain the DB_common class so it can be extended from |
||||
*/ |
||||
require_once 'DB/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-2005 The PHP Group |
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0 3.0 |
||||
* @version Release: @package_version@ |
||||
* @link http://pear.php.net/package/DB |
||||
*/ |
||||
class DB_sqlite extends DB_common |
||||
{ |
||||
// {{{ properties |
||||
|
||||
/** |
||||
* The DB driver type (mysql, oci8, odbc, etc.) |
||||
* @var string |
||||
*/ |
||||
var $phptype = 'sqlite'; |
||||
|
||||
/** |
||||
* The database syntax variant to be used (db2, access, etc.), if any |
||||
* @var string |
||||
*/ |
||||
var $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 |
||||
*/ |
||||
var $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 |
||||
*/ |
||||
var $errorcode_map = array( |
||||
); |
||||
|
||||
/** |
||||
* The raw database connection created by PHP |
||||
* @var resource |
||||
*/ |
||||
var $connection; |
||||
|
||||
/** |
||||
* The DSN information for connecting to a database |
||||
* @var array |
||||
*/ |
||||
var $dsn = array(); |
||||
|
||||
|
||||
/** |
||||
* SQLite data types |
||||
* |
||||
* @link http://www.sqlite.org/datatypes.html |
||||
* |
||||
* @var array |
||||
*/ |
||||
var $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 |
||||
*/ |
||||
var $_lasterror = ''; |
||||
|
||||
|
||||
// }}} |
||||
// {{{ constructor |
||||
|
||||
/** |
||||
* This constructor calls <kbd>$this->DB_common()</kbd> |
||||
* |
||||
* @return void |
||||
*/ |
||||
function DB_sqlite() |
||||
{ |
||||
$this->DB_common(); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ 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 (PEAR::isError($db)) { |
||||
* die($db->getMessage()); |
||||
* } |
||||
* </code> |
||||
* |
||||
* @param array $dsn the data source name |
||||
* @param bool $persistent should the connection be persistent? |
||||
* |
||||
* @return int DB_OK on success. A DB_Error object on failure. |
||||
*/ |
||||
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']) { |
||||
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); |
||||
} |
||||
} else { |
||||
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() |
||||
|
||||
/** |
||||
* Disconnects from the database server |
||||
* |
||||
* @return bool TRUE on success, FALSE on failure |
||||
*/ |
||||
function disconnect() |
||||
{ |
||||
$ret = @sqlite_close($this->connection); |
||||
$this->connection = null; |
||||
return $ret; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ simpleQuery() |
||||
|
||||
/** |
||||
* 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 |
||||
*/ |
||||
function simpleQuery($query) |
||||
{ |
||||
$ismanip = DB::isManip($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; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ nextResult() |
||||
|
||||
/** |
||||
* 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 |
||||
*/ |
||||
function nextResult($result) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ 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() |
||||
*/ |
||||
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); |
||||
} |
||||
} 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; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ freeResult() |
||||
|
||||
/** |
||||
* 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() |
||||
*/ |
||||
function freeResult(&$result) |
||||
{ |
||||
// XXX No native free? |
||||
if (!is_resource($result)) { |
||||
return false; |
||||
} |
||||
$result = null; |
||||
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 resource $result PHP's query result resource |
||||
* |
||||
* @return int the number of columns. A DB_Error object on failure. |
||||
* |
||||
* @see DB_result::numCols() |
||||
*/ |
||||
function numCols($result) |
||||
{ |
||||
$cols = @sqlite_num_fields($result); |
||||
if (!$cols) { |
||||
return $this->sqliteRaiseError(); |
||||
} |
||||
return $cols; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ 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 the number of rows. A DB_Error object on failure. |
||||
* |
||||
* @see DB_result::numRows() |
||||
*/ |
||||
function numRows($result) |
||||
{ |
||||
$rows = @sqlite_num_rows($result); |
||||
if ($rows === null) { |
||||
return $this->sqliteRaiseError(); |
||||
} |
||||
return $rows; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ affected() |
||||
|
||||
/** |
||||
* 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. |
||||
*/ |
||||
function affectedRows() |
||||
{ |
||||
return @sqlite_changes($this->connection); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ dropSequence() |
||||
|
||||
/** |
||||
* 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() |
||||
*/ |
||||
function dropSequence($seq_name) |
||||
{ |
||||
return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name)); |
||||
} |
||||
|
||||
/** |
||||
* 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() |
||||
*/ |
||||
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); |
||||
} |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ nextId() |
||||
|
||||
/** |
||||
* 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 the next id number in the sequence. |
||||
* A DB_Error object on failure. |
||||
* |
||||
* @see DB_common::nextID(), DB_common::getSequenceName(), |
||||
* DB_sqlite::createSequence(), DB_sqlite::dropSequence() |
||||
*/ |
||||
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); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ getDbFileStats() |
||||
|
||||
/** |
||||
* 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 |
||||
*/ |
||||
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; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ escapeSimple() |
||||
|
||||
/** |
||||
* 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() |
||||
*/ |
||||
function escapeSimple($str) |
||||
{ |
||||
return @sqlite_escape_string($str); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ modifyLimitQuery() |
||||
|
||||
/** |
||||
* 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 |
||||
*/ |
||||
function modifyLimitQuery($query, $from, $count, $params = array()) |
||||
{ |
||||
return "$query LIMIT $count OFFSET $from"; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ modifyQuery() |
||||
|
||||
/** |
||||
* 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() |
||||
*/ |
||||
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; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ sqliteRaiseError() |
||||
|
||||
/** |
||||
* 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() |
||||
*/ |
||||
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); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ errorNative() |
||||
|
||||
/** |
||||
* 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 |
||||
*/ |
||||
function errorNative() |
||||
{ |
||||
return $this->_lasterror; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ errorCode() |
||||
|
||||
/** |
||||
* 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 |
||||
*/ |
||||
function errorCode($errormsg) |
||||
{ |
||||
static $error_regexps; |
||||
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, |
||||
'/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; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ 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 DB_Error object on failure. |
||||
* |
||||
* @see DB_common::tableInfo() |
||||
* @since Method available since Release 1.7.0 |
||||
*/ |
||||
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 ($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() |
||||
*/ |
||||
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,504 +0,0 @@ |
||||
<?php |
||||
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
||||
|
||||
/** |
||||
* Provides an object interface to a table row |
||||
* |
||||
* PHP versions 4 and 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-2005 The PHP Group |
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
||||
* @version CVS: $Id: storage.php,v 1.21 2005/02/02 02:54:51 danielc Exp $ |
||||
* @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-2005 The PHP Group |
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
||||
* @version Release: @package_version@ |
||||
* @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 */ |
||||
var $_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 */ |
||||
var $_keycolumn = null; |
||||
|
||||
/** DB connection handle used for all transactions */ |
||||
var $_dbh = null; |
||||
|
||||
/** an assoc with the names of database fields stored as properties |
||||
in this object */ |
||||
var $_properties = array(); |
||||
|
||||
/** an assoc with the names of the properties in this object that |
||||
have been changed since they were fetched from the database */ |
||||
var $_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. */ |
||||
var $_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 */ |
||||
var $_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 |
||||
* |
||||
*/ |
||||
function DB_storage($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() |
||||
|
||||
/** |
||||
* Utility method to build a "WHERE" clause to locate ourselves in |
||||
* the table. |
||||
* |
||||
* XXX future improvement: use rowids? |
||||
* |
||||
* @access private |
||||
*/ |
||||
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; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ 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 DB_OK on success, a DB error if not |
||||
*/ |
||||
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() |
||||
|
||||
/** |
||||
* Create a new (empty) row in the configured table for this |
||||
* object. |
||||
*/ |
||||
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); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ toString() |
||||
|
||||
/** |
||||
* Output a simple description of this DB_storage object. |
||||
* @return string object description |
||||
*/ |
||||
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". |
||||
*/ |
||||
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 $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 |
||||
*/ |
||||
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. |
||||
*/ |
||||
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 |
||||
*/ |
||||
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. |
||||
*/ |
||||
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 or a DB error |
||||
*/ |
||||
function store() |
||||
{ |
||||
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 |
||||
*/ |
||||
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,907 +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 versions 4 and 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ônio Carlos Venâncio Júnior <floripa@php.net> |
||||
* @author Daniel Convissor <danielc@php.net> |
||||
* @copyright 1997-2005 The PHP Group |
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
||||
* @version CVS: $Id: sybase.php,v 1.78 2005/02/20 00:44:48 danielc Exp $ |
||||
* @link http://pear.php.net/package/DB |
||||
*/ |
||||
|
||||
/** |
||||
* Obtain the DB_common class so it can be extended from |
||||
*/ |
||||
require_once 'DB/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ônio Carlos Venâncio Júnior <floripa@php.net> |
||||
* @author Daniel Convissor <danielc@php.net> |
||||
* @copyright 1997-2005 The PHP Group |
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0 |
||||
* @version Release: @package_version@ |
||||
* @link http://pear.php.net/package/DB |
||||
*/ |
||||
class DB_sybase extends DB_common |
||||
{ |
||||
// {{{ properties |
||||
|
||||
/** |
||||
* The DB driver type (mysql, oci8, odbc, etc.) |
||||
* @var string |
||||
*/ |
||||
var $phptype = 'sybase'; |
||||
|
||||
/** |
||||
* The database syntax variant to be used (db2, access, etc.), if any |
||||
* @var string |
||||
*/ |
||||
var $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 |
||||
*/ |
||||
var $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 |
||||
*/ |
||||
var $errorcode_map = array( |
||||
); |
||||
|
||||
/** |
||||
* The raw database connection created by PHP |
||||
* @var resource |
||||
*/ |
||||
var $connection; |
||||
|
||||
/** |
||||
* The DSN information for connecting to a database |
||||
* @var array |
||||
*/ |
||||
var $dsn = array(); |
||||
|
||||
|
||||
/** |
||||
* Should data manipulation queries be committed automatically? |
||||
* @var bool |
||||
* @access private |
||||
*/ |
||||
var $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 |
||||
*/ |
||||
var $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 |
||||
*/ |
||||
var $_db = ''; |
||||
|
||||
|
||||
// }}} |
||||
// {{{ constructor |
||||
|
||||
/** |
||||
* This constructor calls <kbd>$this->DB_common()</kbd> |
||||
* |
||||
* @return void |
||||
*/ |
||||
function DB_sybase() |
||||
{ |
||||
$this->DB_common(); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ 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 DB_OK on success. A DB_Error object on failure. |
||||
*/ |
||||
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 |
||||
*/ |
||||
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 |
||||
*/ |
||||
function simpleQuery($query) |
||||
{ |
||||
$ismanip = DB::isManip($query); |
||||
$this->last_query = $query; |
||||
if (!@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() |
||||
|
||||
/** |
||||
* 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 |
||||
*/ |
||||
function nextResult($result) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ 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() |
||||
*/ |
||||
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; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ freeResult() |
||||
|
||||
/** |
||||
* 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() |
||||
*/ |
||||
function freeResult($result) |
||||
{ |
||||
return @sybase_free_result($result); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ 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 resource $result PHP's query result resource |
||||
* |
||||
* @return int the number of columns. A DB_Error object on failure. |
||||
* |
||||
* @see DB_result::numCols() |
||||
*/ |
||||
function numCols($result) |
||||
{ |
||||
$cols = @sybase_num_fields($result); |
||||
if (!$cols) { |
||||
return $this->sybaseRaiseError(); |
||||
} |
||||
return $cols; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ 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 the number of rows. A DB_Error object on failure. |
||||
* |
||||
* @see DB_result::numRows() |
||||
*/ |
||||
function numRows($result) |
||||
{ |
||||
$rows = @sybase_num_rows($result); |
||||
if ($rows === false) { |
||||
return $this->sybaseRaiseError(); |
||||
} |
||||
return $rows; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ affectedRows() |
||||
|
||||
/** |
||||
* 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. |
||||
*/ |
||||
function affectedRows() |
||||
{ |
||||
if (DB::isManip($this->last_query)) { |
||||
$result = @sybase_affected_rows($this->connection); |
||||
} else { |
||||
$result = 0; |
||||
} |
||||
return $result; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ nextId() |
||||
|
||||
/** |
||||
* 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 the next id number in the sequence. |
||||
* A DB_Error object on failure. |
||||
* |
||||
* @see DB_common::nextID(), DB_common::getSequenceName(), |
||||
* DB_sybase::createSequence(), DB_sybase::dropSequence() |
||||
*/ |
||||
function nextId($seq_name, $ondemand = true) |
||||
{ |
||||
$seqname = $this->getSequenceName($seq_name); |
||||
if (!@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]; |
||||
} |
||||
|
||||
/** |
||||
* 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() |
||||
*/ |
||||
function createSequence($seq_name) |
||||
{ |
||||
return $this->query('CREATE TABLE ' |
||||
. $this->getSequenceName($seq_name) |
||||
. ' (id numeric(10, 0) IDENTITY NOT NULL,' |
||||
. ' vapor int NULL)'); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ dropSequence() |
||||
|
||||
/** |
||||
* 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() |
||||
*/ |
||||
function dropSequence($seq_name) |
||||
{ |
||||
return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name)); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ autoCommit() |
||||
|
||||
/** |
||||
* 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. |
||||
*/ |
||||
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; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ commit() |
||||
|
||||
/** |
||||
* Commits the current transaction |
||||
* |
||||
* @return int DB_OK on success. A DB_Error object on failure. |
||||
*/ |
||||
function commit() |
||||
{ |
||||
if ($this->transaction_opcount > 0) { |
||||
if (!@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; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ rollback() |
||||
|
||||
/** |
||||
* Reverts the current transaction |
||||
* |
||||
* @return int DB_OK on success. A DB_Error object on failure. |
||||
*/ |
||||
function rollback() |
||||
{ |
||||
if ($this->transaction_opcount > 0) { |
||||
if (!@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; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ sybaseRaiseError() |
||||
|
||||
/** |
||||
* 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() |
||||
*/ |
||||
function sybaseRaiseError($errno = null) |
||||
{ |
||||
$native = $this->errorNative(); |
||||
if ($errno === null) { |
||||
$errno = $this->errorCode($native); |
||||
} |
||||
return $this->raiseError($errno, null, null, null, $native); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ errorNative() |
||||
|
||||
/** |
||||
* Gets the DBMS' native error message produced by the last query |
||||
* |
||||
* @return string the DBMS' error message |
||||
*/ |
||||
function errorNative() |
||||
{ |
||||
return @sybase_get_last_message(); |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ errorCode() |
||||
|
||||
/** |
||||
* 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 |
||||
*/ |
||||
function errorCode($errormsg) |
||||
{ |
||||
static $error_regexps; |
||||
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, |
||||
); |
||||
} |
||||
|
||||
foreach ($error_regexps as $regexp => $code) { |
||||
if (preg_match($regexp, $errormsg)) { |
||||
return $code; |
||||
} |
||||
} |
||||
return DB_ERROR; |
||||
} |
||||
|
||||
// }}} |
||||
// {{{ 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 an associative array with the information requested. |
||||
* A DB_Error object on failure. |
||||
* |
||||
* @see DB_common::tableInfo() |
||||
* @since Method available since Release 1.6.0 |
||||
*/ |
||||
function tableInfo($result, $mode = null) |
||||
{ |
||||
if (is_string($result)) { |
||||
/* |
||||
* Probably received a table name. |
||||
* Create a result resource identifier. |
||||
*/ |
||||
if (!@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 |
||||
*/ |
||||
function _sybase_field_flags($table, $column) |
||||
{ |
||||
static $tableName = null; |
||||
static $flags = array(); |
||||
|
||||
if ($table != $tableName) { |
||||
$flags = array(); |
||||
$tableName = $table; |
||||
|
||||
// get unique/primary keys |
||||
$res = $this->getAll("sp_helpindex $table", DB_FETCHMODE_ASSOC); |
||||
|
||||
if (!isset($res[0]['index_description'])) { |
||||
return ''; |
||||
} |
||||
|
||||
foreach ($res as $val) { |
||||
$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'); |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
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 |
||||
*/ |
||||
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() |
||||
*/ |
||||
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: |
||||
*/ |
||||
|
||||
?> |
||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue