diff --git a/CHANGELOG b/CHANGELOG index 7d4c81c42..beb28238d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,9 @@ CHANGELOG RoundCube Webmail --------------------------- +2008/05/12 (alec) +- Updated PEAR::DB package to version 1.7.13 + 2008/05/10 (alec) - Make password input fields of type password in installer (#1484886) diff --git a/program/lib/DB.php b/program/lib/DB.php index e2beecaf2..f76913367 100644 --- a/program/lib/DB.php +++ b/program/lib/DB.php @@ -18,7 +18,7 @@ * @author Stig Bakken * @author Tomas V.V.Cox * @author Daniel Convissor - * @copyright 1997-2005 The PHP Group + * @copyright 1997-2007 The PHP Group * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version CVS: $Id$ * @link http://pear.php.net/package/DB @@ -424,9 +424,9 @@ define('DB_PORTABILITY_ALL', 63); * @author Stig Bakken * @author Tomas V.V.Cox * @author Daniel Convissor - * @copyright 1997-2005 The PHP Group + * @copyright 1997-2007 The PHP Group * @license http://www.php.net/license/3_0.txt PHP License 3.0 - * @version Release: @package_version@ + * @version Release: 1.7.13 * @link http://pear.php.net/package/DB */ class DB @@ -467,7 +467,7 @@ class DB return $tmp; } - @$obj =& new $classname; + @$obj = new $classname; foreach ($options as $option => $value) { $test = $obj->setOption($option, $value); @@ -544,7 +544,7 @@ class DB return $tmp; } - @$obj =& new $classname; + @$obj = new $classname; foreach ($options as $option => $value) { $test = $obj->setOption($option, $value); @@ -555,7 +555,11 @@ class DB $err = $obj->connect($dsninfo, $obj->getOption('persistent')); if (DB::isError($err)) { - $err->addUserInfo($dsn); + if (is_array($dsn)) { + $err->addUserInfo(DB::getDSNString($dsn, true)); + } else { + $err->addUserInfo($dsn); + } return $err; } @@ -572,7 +576,7 @@ class DB */ function apiVersion() { - return '@package_version@'; + return '1.7.13'; } // }}} @@ -625,7 +629,7 @@ class DB { $manips = 'INSERT|UPDATE|DELETE|REPLACE|' . 'CREATE|DROP|' - . 'LOAD DATA|SELECT .* INTO|COPY|' + . 'LOAD DATA|SELECT .* INTO .* FROM|COPY|' . 'ALTER|GRANT|REVOKE|' . 'LOCK|UNLOCK'; if (preg_match('/^\s*"?(' . $manips . ')\s+/i', $query)) { @@ -808,13 +812,11 @@ class DB // process the different protocol options $parsed['protocol'] = (!empty($proto)) ? $proto : 'tcp'; $proto_opts = rawurldecode($proto_opts); + if (strpos($proto_opts, ':') !== false) { + list($proto_opts, $parsed['port']) = explode(':', $proto_opts); + } if ($parsed['protocol'] == 'tcp') { - if (strpos($proto_opts, ':') !== false) { - list($parsed['hostspec'], - $parsed['port']) = explode(':', $proto_opts); - } else { - $parsed['hostspec'] = $proto_opts; - } + $parsed['hostspec'] = $proto_opts; } elseif ($parsed['protocol'] == 'unix') { $parsed['socket'] = $proto_opts; } @@ -847,6 +849,82 @@ class DB return $parsed; } + // }}} + // {{{ getDSNString() + + /** + * Returns the given DSN in a string format suitable for output. + * + * @param array|string the DSN to parse and format + * @param boolean true to hide the password, false to include it + * @return string + */ + function getDSNString($dsn, $hidePassword) { + /* Calling parseDSN will ensure that we have all the array elements + * defined, and means that we deal with strings and array in the same + * manner. */ + $dsnArray = DB::parseDSN($dsn); + + if ($hidePassword) { + $dsnArray['password'] = 'PASSWORD'; + } + + /* Protocol is special-cased, as using the default "tcp" along with an + * Oracle TNS connection string fails. */ + if (is_string($dsn) && strpos($dsn, 'tcp') === false && $dsnArray['protocol'] == 'tcp') { + $dsnArray['protocol'] = false; + } + + // Now we just have to construct the actual string. This is ugly. + $dsnString = $dsnArray['phptype']; + if ($dsnArray['dbsyntax']) { + $dsnString .= '('.$dsnArray['dbsyntax'].')'; + } + $dsnString .= '://' + .$dsnArray['username'] + .':' + .$dsnArray['password'] + .'@' + .$dsnArray['protocol']; + if ($dsnArray['socket']) { + $dsnString .= '('.$dsnArray['socket'].')'; + } + if ($dsnArray['protocol'] && $dsnArray['hostspec']) { + $dsnString .= '+'; + } + $dsnString .= $dsnArray['hostspec']; + if ($dsnArray['port']) { + $dsnString .= ':'.$dsnArray['port']; + } + $dsnString .= '/'.$dsnArray['database']; + + /* Option handling. Unfortunately, parseDSN simply places options into + * the top-level array, so we'll first get rid of the fields defined by + * DB and see what's left. */ + unset($dsnArray['phptype'], + $dsnArray['dbsyntax'], + $dsnArray['username'], + $dsnArray['password'], + $dsnArray['protocol'], + $dsnArray['socket'], + $dsnArray['hostspec'], + $dsnArray['port'], + $dsnArray['database'] + ); + if (count($dsnArray) > 0) { + $dsnString .= '?'; + $i = 0; + foreach ($dsnArray as $key => $value) { + if (++$i > 1) { + $dsnString .= '&'; + } + $dsnString .= $key.'='.$value; + } + } + + return $dsnString; + } + // }}} } @@ -860,9 +938,9 @@ class DB * @category Database * @package DB * @author Stig Bakken - * @copyright 1997-2005 The PHP Group + * @copyright 1997-2007 The PHP Group * @license http://www.php.net/license/3_0.txt PHP License 3.0 - * @version Release: @package_version@ + * @version Release: 1.7.13 * @link http://pear.php.net/package/DB */ class DB_Error extends PEAR_Error @@ -907,9 +985,9 @@ class DB_Error extends PEAR_Error * @category Database * @package DB * @author Stig Bakken - * @copyright 1997-2005 The PHP Group + * @copyright 1997-2007 The PHP Group * @license http://www.php.net/license/3_0.txt PHP License 3.0 - * @version Release: @package_version@ + * @version Release: 1.7.13 * @link http://pear.php.net/package/DB */ class DB_result @@ -1089,7 +1167,7 @@ class DB_result $fetchmode = DB_FETCHMODE_ASSOC; $object_class = $this->fetchmode_object_class; } - if ($this->limit_from !== null) { + if (is_null($rownum) && $this->limit_from !== null) { if ($this->row_counter === null) { $this->row_counter = $this->limit_from; // Skip rows @@ -1121,7 +1199,7 @@ class DB_result if ($object_class == 'stdClass') { $arr = (object) $arr; } else { - $arr = &new $object_class($arr); + $arr = new $object_class($arr); } } return $arr; @@ -1171,7 +1249,7 @@ class DB_result $fetchmode = DB_FETCHMODE_ASSOC; $object_class = $this->fetchmode_object_class; } - if ($this->limit_from !== null) { + if (is_null($rownum) && $this->limit_from !== null) { if ($this->row_counter === null) { $this->row_counter = $this->limit_from; // Skip rows @@ -1253,10 +1331,33 @@ class DB_result while ($res->fetchInto($tmp, DB_FETCHMODE_ORDERED)) { $i++; } - return $i; + $count = $i; } else { - return $this->dbh->numRows($this->result); + $count = $this->dbh->numRows($this->result); } + + /* fbsql is checked for here because limit queries are implemented + * using a TOP() function, which results in fbsql_num_rows still + * returning the total number of rows that would have been returned, + * rather than the real number. As a result, we'll just do the limit + * calculations for fbsql in the same way as a database with emulated + * limits. Unfortunately, we can't just do this in DB_fbsql::numRows() + * because that only gets the result resource, rather than the full + * DB_Result object. */ + if (($this->dbh->features['limit'] === 'emulate' + && $this->limit_from !== null) + || $this->dbh->phptype == 'fbsql') { + $limit_count = is_null($this->limit_count) ? $count : $this->limit_count; + if ($count < $this->limit_from) { + $count = 0; + } elseif ($count < ($this->limit_from + $limit_count)) { + $count -= $this->limit_from; + } else { + $count = $limit_count; + } + } + + return $count; } // }}} @@ -1349,9 +1450,9 @@ class DB_result * @category Database * @package DB * @author Stig Bakken - * @copyright 1997-2005 The PHP Group + * @copyright 1997-2007 The PHP Group * @license http://www.php.net/license/3_0.txt PHP License 3.0 - * @version Release: @package_version@ + * @version Release: 1.7.13 * @link http://pear.php.net/package/DB * @see DB_common::setFetchMode() */ diff --git a/program/lib/DB/common.php b/program/lib/DB/common.php index 7988e7194..f54dedcbc 100644 --- a/program/lib/DB/common.php +++ b/program/lib/DB/common.php @@ -18,7 +18,7 @@ * @author Stig Bakken * @author Tomas V.V. Cox * @author Daniel Convissor - * @copyright 1997-2005 The PHP Group + * @copyright 1997-2007 The PHP Group * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version CVS: $Id$ * @link http://pear.php.net/package/DB @@ -40,9 +40,9 @@ require_once 'PEAR.php'; * @author Stig Bakken * @author Tomas V.V. Cox * @author Daniel Convissor - * @copyright 1997-2005 The PHP Group + * @copyright 1997-2007 The PHP Group * @license http://www.php.net/license/3_0.txt PHP License 3.0 - * @version Release: @package_version@ + * @version Release: 1.7.13 * @link http://pear.php.net/package/DB */ class DB_common extends PEAR @@ -121,6 +121,21 @@ class DB_common extends PEAR */ var $prepared_queries = array(); + /** + * Flag indicating that the last query was a manipulation query. + * @access protected + * @var boolean + */ + var $_last_query_manip = false; + + /** + * Flag indicating that the next query must be a manipulation + * query. + * @access protected + * @var boolean + */ + var $_next_query_manip = false; + // }}} // {{{ DB_common @@ -424,17 +439,56 @@ class DB_common extends PEAR */ function quoteSmart($in) { - if (is_int($in) || is_double($in)) { + if (is_int($in)) { return $in; + } elseif (is_float($in)) { + return $this->quoteFloat($in); } elseif (is_bool($in)) { - return $in ? 1 : 0; + return $this->quoteBoolean($in); } elseif (is_null($in)) { return 'NULL'; } else { + if ($this->dbsyntax == 'access' + && preg_match('/^#.+#$/', $in)) + { + return $this->escapeSimple($in); + } return "'" . $this->escapeSimple($in) . "'"; } } + // }}} + // {{{ quoteBoolean() + + /** + * Formats a boolean value for use within a query in a locale-independent + * manner. + * + * @param boolean the boolean value to be quoted. + * @return string the quoted string. + * @see DB_common::quoteSmart() + * @since Method available since release 1.7.8. + */ + function quoteBoolean($boolean) { + return $boolean ? '1' : '0'; + } + + // }}} + // {{{ quoteFloat() + + /** + * Formats a float value for use within a query in a locale-independent + * manner. + * + * @param float the float value to be quoted. + * @return string the quoted string. + * @see DB_common::quoteSmart() + * @since Method available since release 1.7.8. + */ + function quoteFloat($float) { + return "'".$this->escapeSimple(str_replace(',', '.', strval(floatval($float))))."'"; + } + // }}} // {{{ escapeSimple() @@ -837,7 +891,7 @@ class DB_common extends PEAR if (DB::isError($sth)) { return $sth; } - $ret =& $this->execute($sth, array_values($fields_values)); + $ret = $this->execute($sth, array_values($fields_values)); $this->freePrepared($sth); return $ret; @@ -931,7 +985,7 @@ class DB_common extends PEAR * "'it''s good'", * 'filename.txt' * ); - * $res =& $db->execute($sth, $data); + * $res = $db->execute($sth, $data); * * * @param resource $stmt a DB statement resource returned from prepare() @@ -960,7 +1014,7 @@ class DB_common extends PEAR if ($result === DB_OK || DB::isError($result)) { return $result; } else { - $tmp =& new DB_result($this, $result); + $tmp = new DB_result($this, $result); return $tmp; } } @@ -1041,7 +1095,7 @@ class DB_common extends PEAR function executeMultiple($stmt, $data) { foreach ($data as $value) { - $res =& $this->execute($stmt, $value); + $res = $this->execute($stmt, $value); if (DB::isError($res)) { return $res; } @@ -1154,7 +1208,7 @@ class DB_common extends PEAR if (DB::isError($sth)) { return $sth; } - $ret =& $this->execute($sth, $params); + $ret = $this->execute($sth, $params); $this->freePrepared($sth, false); return $ret; } else { @@ -1163,7 +1217,7 @@ class DB_common extends PEAR if ($result === DB_OK || DB::isError($result)) { return $result; } else { - $tmp =& new DB_result($this, $result); + $tmp = new DB_result($this, $result); return $tmp; } } @@ -1194,7 +1248,7 @@ class DB_common extends PEAR if (DB::isError($query)){ return $query; } - $result =& $this->query($query, $params); + $result = $this->query($query, $params); if (is_a($result, 'DB_result')) { $result->setOption('limit_from', $from); $result->setOption('limit_count', $count); @@ -1229,10 +1283,10 @@ class DB_common extends PEAR if (DB::isError($sth)) { return $sth; } - $res =& $this->execute($sth, $params); + $res = $this->execute($sth, $params); $this->freePrepared($sth); } else { - $res =& $this->query($query); + $res = $this->query($query); } if (DB::isError($res)) { @@ -1293,10 +1347,10 @@ class DB_common extends PEAR if (DB::isError($sth)) { return $sth; } - $res =& $this->execute($sth, $params); + $res = $this->execute($sth, $params); $this->freePrepared($sth); } else { - $res =& $this->query($query); + $res = $this->query($query); } if (DB::isError($res)) { @@ -1344,10 +1398,10 @@ class DB_common extends PEAR return $sth; } - $res =& $this->execute($sth, $params); + $res = $this->execute($sth, $params); $this->freePrepared($sth); } else { - $res =& $this->query($query); + $res = $this->query($query); } if (DB::isError($res)) { @@ -1360,7 +1414,7 @@ class DB_common extends PEAR $ret = array(); } else { if (!array_key_exists($col, $row)) { - $ret =& $this->raiseError(DB_ERROR_NOSUCHFIELD); + $ret = $this->raiseError(DB_ERROR_NOSUCHFIELD); } else { $ret = array($row[$col]); while (is_array($row = $res->fetchRow($fetchmode))) { @@ -1476,10 +1530,10 @@ class DB_common extends PEAR return $sth; } - $res =& $this->execute($sth, $params); + $res = $this->execute($sth, $params); $this->freePrepared($sth); } else { - $res =& $this->query($query); + $res = $this->query($query); } if (DB::isError($res)) { @@ -1491,7 +1545,7 @@ class DB_common extends PEAR $cols = $res->numCols(); if ($cols < 2) { - $tmp =& $this->raiseError(DB_ERROR_TRUNCATED); + $tmp = $this->raiseError(DB_ERROR_TRUNCATED); return $tmp; } @@ -1603,10 +1657,10 @@ class DB_common extends PEAR return $sth; } - $res =& $this->execute($sth, $params); + $res = $this->execute($sth, $params); $this->freePrepared($sth); } else { - $res =& $this->query($query); + $res = $this->query($query); } if ($res === DB_OK || DB::isError($res)) { @@ -1627,7 +1681,7 @@ class DB_common extends PEAR $res->free(); if (DB::isError($row)) { - $tmp =& $this->raiseError($row); + $tmp = $this->raiseError($row); return $tmp; } return $results; @@ -2102,6 +2156,52 @@ class DB_common extends PEAR return $this->raiseError(DB_ERROR_UNSUPPORTED); } + // }}} + // {{{ nextQueryIsManip() + + /** + * Sets (or unsets) a flag indicating that the next query will be a + * manipulation query, regardless of the usual DB::isManip() heuristics. + * + * @param boolean true to set the flag overriding the isManip() behaviour, + * false to clear it and fall back onto isManip() + * + * @return void + * + * @access public + */ + function nextQueryIsManip($manip) + { + $this->_next_query_manip = $manip; + } + + // }}} + // {{{ _checkManip() + + /** + * Checks if the given query is a manipulation query. This also takes into + * account the _next_query_manip flag and sets the _last_query_manip flag + * (and resets _next_query_manip) according to the result. + * + * @param string The query to check. + * + * @return boolean true if the query is a manipulation query, false + * otherwise + * + * @access protected + */ + function _checkManip($query) + { + if ($this->_next_query_manip || DB::isManip($query)) { + $this->_last_query_manip = true; + } else { + $this->_last_query_manip = false; + } + $this->_next_query_manip = false; + return $this->_last_query_manip; + $manip = $this->_next_query_manip; + } + // }}} // {{{ _rtrimArrayValues() diff --git a/program/lib/DB/dbase.php b/program/lib/DB/dbase.php index 6026f15ce..25455ccda 100644 --- a/program/lib/DB/dbase.php +++ b/program/lib/DB/dbase.php @@ -18,7 +18,7 @@ * @package DB * @author Tomas V.V. Cox * @author Daniel Convissor - * @copyright 1997-2005 The PHP Group + * @copyright 1997-2007 The PHP Group * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version CVS: $Id$ * @link http://pear.php.net/package/DB @@ -39,9 +39,9 @@ require_once 'DB/common.php'; * @package DB * @author Tomas V.V. Cox * @author Daniel Convissor - * @copyright 1997-2005 The PHP Group + * @copyright 1997-2007 The PHP Group * @license http://www.php.net/license/3_0.txt PHP License 3.0 - * @version Release: @package_version@ + * @version Release: 1.7.13 * @link http://pear.php.net/package/DB */ class DB_dbase extends DB_common @@ -188,7 +188,7 @@ class DB_dbase extends DB_common * 'portability' => DB_PORTABILITY_ALL, * ); * - * $db =& DB::connect($dsn, $options); + * $db = DB::connect($dsn, $options); * if (PEAR::isError($db)) { * die($db->getMessage()); * } @@ -214,7 +214,7 @@ class DB_dbase extends DB_common * 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); + @ini_set('track_errors', 1); $php_errormsg = ''; if (!file_exists($dsn['database'])) { @@ -273,7 +273,7 @@ class DB_dbase extends DB_common { // emulate result resources $this->res_row[(int)$this->result] = 0; - $tmp =& new DB_result($this, $this->result++); + $tmp = new DB_result($this, $this->result++); return $tmp; } @@ -325,6 +325,26 @@ class DB_dbase extends DB_common return DB_OK; } + // }}} + // {{{ freeResult() + + /** + * Deletes the result set and frees the memory occupied by the result set. + * + * This method is a no-op for dbase, as there aren't result resources in + * the same sense as most other database backends. + * + * @param resource $result PHP's query result resource + * + * @return bool TRUE on success, FALSE if $result is invalid + * + * @see DB_result::free() + */ + function freeResult($result) + { + return true; + } + // }}} // {{{ numCols() @@ -368,41 +388,21 @@ class DB_dbase extends DB_common } // }}} - // {{{ quoteSmart() + // {{{ quoteBoolean() /** - * 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 NULL - * + boolean = T if true or - * F if false. Use the Logical - * 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 + * Formats a boolean value for use within a query in a locale-independent + * manner. * + * @param boolean the boolean value to be quoted. + * @return string the quoted string. * @see DB_common::quoteSmart() - * @since Method available since Release 1.6.0 + * @since Method available since release 1.7.8. */ - 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) . "'"; - } + function quoteBoolean($boolean) { + return $boolean ? 'T' : 'F'; } - + // }}} // {{{ tableInfo() diff --git a/program/lib/DB/fbsql.php b/program/lib/DB/fbsql.php index b25868dc1..8ebcccd0c 100644 --- a/program/lib/DB/fbsql.php +++ b/program/lib/DB/fbsql.php @@ -18,7 +18,7 @@ * @package DB * @author Frank M. Kromann * @author Daniel Convissor - * @copyright 1997-2005 The PHP Group + * @copyright 1997-2007 The PHP Group * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version CVS: $Id$ * @link http://pear.php.net/package/DB @@ -39,9 +39,9 @@ require_once 'DB/common.php'; * @package DB * @author Frank M. Kromann * @author Daniel Convissor - * @copyright 1997-2005 The PHP Group + * @copyright 1997-2007 The PHP Group * @license http://www.php.net/license/3_0.txt PHP License 3.0 - * @version Release: @package_version@ + * @version Release: 1.7.13 * @link http://pear.php.net/package/DB * @since Class functional since Release 1.7.0 */ @@ -171,10 +171,10 @@ class DB_fbsql extends DB_common $this->connection = @call_user_func_array($connect_function, $params); } else { - ini_set('track_errors', 1); + @ini_set('track_errors', 1); $this->connection = @call_user_func_array($connect_function, $params); - ini_set('track_errors', $ini); + @ini_set('track_errors', $ini); } if (!$this->connection) { @@ -229,7 +229,7 @@ class DB_fbsql extends DB_common } // Determine which queries that should return data, and which // should return an error code only. - if (DB::isManip($query)) { + if ($this->_checkManip($query)) { return DB_OK; } return $result; @@ -320,7 +320,7 @@ class DB_fbsql extends DB_common */ function freeResult($result) { - return @fbsql_free_result($result); + return is_resource($result) ? fbsql_free_result($result) : false; } // }}} @@ -353,7 +353,7 @@ class DB_fbsql extends DB_common */ function commit() { - @fbsql_commit(); + @fbsql_commit($this->connection); } // }}} @@ -366,7 +366,7 @@ class DB_fbsql extends DB_common */ function rollback() { - @fbsql_rollback(); + @fbsql_rollback($this->connection); } // }}} @@ -431,7 +431,7 @@ class DB_fbsql extends DB_common */ function affectedRows() { - if (DB::isManip($this->last_query)) { + if ($this->_last_query_manip) { $result = @fbsql_affected_rows($this->connection); } else { $result = 0; @@ -543,7 +543,7 @@ class DB_fbsql extends DB_common */ function modifyLimitQuery($query, $from, $count, $params = array()) { - if (DB::isManip($query)) { + if (DB::isManip($query) || $this->_next_query_manip) { return preg_replace('/^([\s(])*SELECT/i', "\\1SELECT TOP($count)", $query); } else { @@ -553,38 +553,37 @@ class DB_fbsql extends DB_common } // }}} - // {{{ quoteSmart() + // {{{ quoteBoolean() /** - * 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 NULL - * + boolean = string TRUE or FALSE - * + 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 + * Formats a boolean value for use within a query in a locale-independent + * manner. * + * @param boolean the boolean value to be quoted. + * @return string the quoted string. * @see DB_common::quoteSmart() - * @since Method available since Release 1.6.0 + * @since Method available since release 1.7.8. */ - 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) . "'"; - } + function quoteBoolean($boolean) { + return $boolean ? 'TRUE' : 'FALSE'; } + + // }}} + // {{{ quoteFloat() + /** + * Formats a float value for use within a query in a locale-independent + * manner. + * + * @param float the float value to be quoted. + * @return string the quoted string. + * @see DB_common::quoteSmart() + * @since Method available since release 1.7.8. + */ + function quoteFloat($float) { + return $this->escapeSimple(str_replace(',', '.', strval(floatval($float)))); + } + // }}} // {{{ fbsqlRaiseError() diff --git a/program/lib/DB/ibase.php b/program/lib/DB/ibase.php index b5e2386a0..913fbf3eb 100644 --- a/program/lib/DB/ibase.php +++ b/program/lib/DB/ibase.php @@ -21,7 +21,7 @@ * @package DB * @author Sterling Hughes * @author Daniel Convissor - * @copyright 1997-2005 The PHP Group + * @copyright 1997-2007 The PHP Group * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version CVS: $Id$ * @link http://pear.php.net/package/DB @@ -47,9 +47,9 @@ require_once 'DB/common.php'; * @package DB * @author Sterling Hughes * @author Daniel Convissor - * @copyright 1997-2005 The PHP Group + * @copyright 1997-2007 The PHP Group * @license http://www.php.net/license/3_0.txt PHP License 3.0 - * @version Release: @package_version@ + * @version Release: 1.7.13 * @link http://pear.php.net/package/DB * @since Class became stable in Release 1.7.0 */ @@ -123,6 +123,7 @@ class DB_ibase extends DB_common -625 => DB_ERROR_CONSTRAINT_NOT_NULL, -803 => DB_ERROR_CONSTRAINT, -804 => DB_ERROR_VALUE_COUNT_ON_ROW, + // -902 => // Covers too many errors, need to use regex on msg -904 => DB_ERROR_CONNECT_FAILED, -922 => DB_ERROR_NOSUCHDB, -923 => DB_ERROR_CONNECT_FAILED, @@ -275,7 +276,7 @@ class DB_ibase extends DB_common */ function simpleQuery($query) { - $ismanip = DB::isManip($query); + $ismanip = $this->_checkManip($query); $this->last_query = $query; $query = $this->modifyQuery($query); $result = @ibase_query($this->connection, $query); @@ -412,7 +413,7 @@ class DB_ibase extends DB_common */ function freeResult($result) { - return @ibase_free_result($result); + return is_resource($result) ? ibase_free_result($result) : false; } // }}} @@ -420,8 +421,7 @@ class DB_ibase extends DB_common function freeQuery($query) { - @ibase_free_query($query); - return true; + return is_resource($query) ? ibase_free_query($query) : false; } // }}} @@ -521,8 +521,14 @@ class DB_ibase extends DB_common $this->last_query = $query; $newquery = $this->modifyQuery($newquery); $stmt = @ibase_prepare($this->connection, $newquery); - $this->prepare_types[(int)$stmt] = $types; - $this->manip_query[(int)$stmt] = DB::isManip($query); + + if ($stmt === false) { + $stmt = $this->ibaseRaiseError(); + } else { + $this->prepare_types[(int)$stmt] = $types; + $this->manip_query[(int)$stmt] = DB::isManip($query); + } + return $stmt; } @@ -547,9 +553,9 @@ class DB_ibase extends DB_common $data = (array)$data; $this->last_parameters = $data; - $types =& $this->prepare_types[(int)$stmt]; + $types = $this->prepare_types[(int)$stmt]; if (count($types) != count($data)) { - $tmp =& $this->raiseError(DB_ERROR_MISMATCH); + $tmp = $this->raiseError(DB_ERROR_MISMATCH); return $tmp; } @@ -568,7 +574,7 @@ class DB_ibase extends DB_common } elseif ($types[$i] == DB_PARAM_OPAQUE) { $fp = @fopen($data[$key], 'rb'); if (!$fp) { - $tmp =& $this->raiseError(DB_ERROR_ACCESS_VIOLATION); + $tmp = $this->raiseError(DB_ERROR_ACCESS_VIOLATION); return $tmp; } $data[$key] = fread($fp, filesize($data[$key])); @@ -581,7 +587,7 @@ class DB_ibase extends DB_common $res = call_user_func_array('ibase_execute', $data); if (!$res) { - $tmp =& $this->ibaseRaiseError(); + $tmp = $this->ibaseRaiseError(); return $tmp; } /* XXX need this? @@ -589,10 +595,13 @@ class DB_ibase extends DB_common @ibase_commit($this->connection); }*/ $this->last_stmt = $stmt; - if ($this->manip_query[(int)$stmt]) { + if ($this->manip_query[(int)$stmt] || $this->_next_query_manip) { + $this->_last_query_manip = true; + $this->_next_query_manip = false; $tmp = DB_OK; } else { - $tmp =& new DB_result($this, $res); + $this->_last_query_manip = false; + $tmp = new DB_result($this, $res); } return $tmp; } @@ -698,7 +707,7 @@ class DB_ibase extends DB_common $repeat = 0; do { $this->pushErrorHandling(PEAR_ERROR_RETURN); - $result =& $this->query("SELECT GEN_ID(${sqn}, 1) " + $result = $this->query("SELECT GEN_ID(${sqn}, 1) " . 'FROM RDB$GENERATORS ' . "WHERE RDB\$GENERATOR_NAME='${sqn}'"); $this->popErrorHandling(); @@ -856,7 +865,7 @@ class DB_ibase extends DB_common if ($errno === null) { $errno = $this->errorCode($this->errorNative()); } - $tmp =& $this->raiseError($errno, null, null, null, @ibase_errmsg()); + $tmp = $this->raiseError($errno, null, null, null, @ibase_errmsg()); return $tmp; } @@ -925,6 +934,8 @@ class DB_ibase extends DB_common => DB_ERROR_ACCESS_VIOLATION, '/arithmetic exception, numeric overflow, or string truncation/i' => DB_ERROR_INVALID, + '/feature is not supported/i' + => DB_ERROR_NOT_CAPABLE, ); } diff --git a/program/lib/DB/ifx.php b/program/lib/DB/ifx.php index 22575c746..f08cf6667 100644 --- a/program/lib/DB/ifx.php +++ b/program/lib/DB/ifx.php @@ -18,7 +18,7 @@ * @package DB * @author Tomas V.V.Cox * @author Daniel Convissor - * @copyright 1997-2005 The PHP Group + * @copyright 1997-2007 The PHP Group * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version CVS: $Id$ * @link http://pear.php.net/package/DB @@ -46,9 +46,9 @@ require_once 'DB/common.php'; * @package DB * @author Tomas V.V.Cox * @author Daniel Convissor - * @copyright 1997-2005 The PHP Group + * @copyright 1997-2007 The PHP Group * @license http://www.php.net/license/3_0.txt PHP License 3.0 - * @version Release: @package_version@ + * @version Release: 1.7.13 * @link http://pear.php.net/package/DB */ class DB_ifx extends DB_common @@ -101,6 +101,7 @@ class DB_ifx extends DB_common '-236' => DB_ERROR_VALUE_COUNT_ON_ROW, '-239' => DB_ERROR_CONSTRAINT, '-253' => DB_ERROR_SYNTAX, + '-268' => DB_ERROR_CONSTRAINT, '-292' => DB_ERROR_CONSTRAINT_NOT_NULL, '-310' => DB_ERROR_ALREADY_EXISTS, '-316' => DB_ERROR_ALREADY_EXISTS, @@ -113,6 +114,7 @@ class DB_ifx extends DB_common '-691' => DB_ERROR_CONSTRAINT, '-692' => DB_ERROR_CONSTRAINT, '-703' => DB_ERROR_CONSTRAINT_NOT_NULL, + '-1202' => DB_ERROR_DIVZERO, '-1204' => DB_ERROR_INVALID_DATE, '-1205' => DB_ERROR_INVALID_DATE, '-1206' => DB_ERROR_INVALID_DATE, @@ -243,10 +245,10 @@ class DB_ifx extends DB_common */ function simpleQuery($query) { - $ismanip = DB::isManip($query); + $ismanip = $this->_checkManip($query); $this->last_query = $query; $this->affected = null; - if (preg_match('/(SELECT)/i', $query)) { //TESTME: Use !DB::isManip()? + if (preg_match('/(SELECT|EXECUTE)/i', $query)) { //TESTME: Use !DB::isManip()? // the scroll is needed for fetching absolute row numbers // in a select query result $result = @ifx_query($query, $this->connection, IFX_SCROLL); @@ -268,7 +270,7 @@ class DB_ifx extends DB_common $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)) { + if (preg_match('/(SELECT|EXECUTE)/i', $query)) { return $result; } // XXX Testme: free results inside a transaction @@ -309,7 +311,7 @@ class DB_ifx extends DB_common */ function affectedRows() { - if (DB::isManip($this->last_query)) { + if ($this->_last_query_manip) { return $this->affected; } else { return 0; @@ -420,7 +422,7 @@ class DB_ifx extends DB_common */ function freeResult($result) { - return @ifx_free_result($result); + return is_resource($result) ? ifx_free_result($result) : false; } // }}} diff --git a/program/lib/DB/msql.php b/program/lib/DB/msql.php index 81ca8553b..e39683397 100644 --- a/program/lib/DB/msql.php +++ b/program/lib/DB/msql.php @@ -21,7 +21,7 @@ * @category Database * @package DB * @author Daniel Convissor - * @copyright 1997-2005 The PHP Group + * @copyright 1997-2007 The PHP Group * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version CVS: $Id$ * @link http://pear.php.net/package/DB @@ -45,9 +45,9 @@ require_once 'DB/common.php'; * @category Database * @package DB * @author Daniel Convissor - * @copyright 1997-2005 The PHP Group + * @copyright 1997-2007 The PHP Group * @license http://www.php.net/license/3_0.txt PHP License 3.0 - * @version Release: @package_version@ + * @version Release: 1.7.13 * @link http://pear.php.net/package/DB * @since Class not functional until Release 1.7.0 */ @@ -153,7 +153,7 @@ class DB_msql extends DB_common * 'portability' => DB_PORTABILITY_ALL, * ); * - * $db =& DB::connect($dsn, $options); + * $db = DB::connect($dsn, $options); * if (PEAR::isError($db)) { * die($db->getMessage()); * } @@ -190,10 +190,10 @@ class DB_msql extends DB_common $this->connection = @call_user_func_array($connect_function, $params); } else { - ini_set('track_errors', 1); + @ini_set('track_errors', 1); $this->connection = @call_user_func_array($connect_function, $params); - ini_set('track_errors', $ini); + @ini_set('track_errors', $ini); } if (!$this->connection) { @@ -251,7 +251,7 @@ class DB_msql extends DB_common } // Determine which queries that should return data, and which // should return an error code only. - if (DB::isManip($query)) { + if ($this->_checkManip($query)) { $this->_result = $result; return DB_OK; } else { @@ -350,7 +350,7 @@ class DB_msql extends DB_common */ function freeResult($result) { - return @msql_free_result($result); + return is_resource($result) ? msql_free_result($result) : false; } // }}} @@ -443,7 +443,7 @@ class DB_msql extends DB_common $repeat = false; do { $this->pushErrorHandling(PEAR_ERROR_RETURN); - $result =& $this->query("SELECT _seq FROM ${seqname}"); + $result = $this->query("SELECT _seq FROM ${seqname}"); $this->popErrorHandling(); if ($ondemand && DB::isError($result) && $result->getCode() == DB_ERROR_NOSUCHTABLE) { @@ -530,6 +530,22 @@ class DB_msql extends DB_common return $this->raiseError(DB_ERROR_UNSUPPORTED); } + // }}} + // {{{ quoteFloat() + + /** + * Formats a float value for use within a query in a locale-independent + * manner. + * + * @param float the float value to be quoted. + * @return string the quoted string. + * @see DB_common::quoteSmart() + * @since Method available since release 1.7.8. + */ + function quoteFloat($float) { + return $this->escapeSimple(str_replace(',', '.', strval(floatval($float)))); + } + // }}} // {{{ escapeSimple() @@ -598,6 +614,11 @@ class DB_msql extends DB_common function errorCode($errormsg) { static $error_regexps; + + // PHP 5.2+ prepends the function name to $php_errormsg, so we need + // this hack to work around it, per bug #9599. + $errormsg = preg_replace('/^msql[a-z_]+\(\): /', '', $errormsg); + if (!isset($error_regexps)) { $error_regexps = array( '/^Access to database denied/i' diff --git a/program/lib/DB/mssql.php b/program/lib/DB/mssql.php index a84db89f6..8452f08b1 100644 --- a/program/lib/DB/mssql.php +++ b/program/lib/DB/mssql.php @@ -18,7 +18,7 @@ * @package DB * @author Sterling Hughes * @author Daniel Convissor - * @copyright 1997-2005 The PHP Group + * @copyright 1997-2007 The PHP Group * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version CVS: $Id$ * @link http://pear.php.net/package/DB @@ -35,13 +35,21 @@ require_once 'DB/common.php'; * * These methods overload the ones declared in DB_common. * + * DB's mssql driver is only for Microsfoft SQL Server databases. + * + * If you're connecting to a Sybase database, you MUST specify "sybase" + * as the "phptype" in the DSN. + * + * This class only works correctly if you have compiled PHP using + * --with-mssql=[dir_to_FreeTDS]. + * * @category Database * @package DB * @author Sterling Hughes * @author Daniel Convissor - * @copyright 1997-2005 The PHP Group + * @copyright 1997-2007 The PHP Group * @license http://www.php.net/license/3_0.txt PHP License 3.0 - * @version Release: @package_version@ + * @version Release: 1.7.13 * @link http://pear.php.net/package/DB */ class DB_mssql extends DB_common @@ -89,19 +97,40 @@ class DB_mssql extends DB_common */ // XXX Add here error codes ie: 'S100E' => DB_ERROR_SYNTAX var $errorcode_map = array( + 102 => DB_ERROR_SYNTAX, 110 => DB_ERROR_VALUE_COUNT_ON_ROW, 155 => DB_ERROR_NOSUCHFIELD, + 156 => DB_ERROR_SYNTAX, 170 => DB_ERROR_SYNTAX, 207 => DB_ERROR_NOSUCHFIELD, 208 => DB_ERROR_NOSUCHTABLE, 245 => DB_ERROR_INVALID_NUMBER, + 319 => DB_ERROR_SYNTAX, + 321 => DB_ERROR_NOSUCHFIELD, + 325 => DB_ERROR_SYNTAX, + 336 => DB_ERROR_SYNTAX, 515 => DB_ERROR_CONSTRAINT_NOT_NULL, 547 => DB_ERROR_CONSTRAINT, + 1018 => DB_ERROR_SYNTAX, + 1035 => DB_ERROR_SYNTAX, 1913 => DB_ERROR_ALREADY_EXISTS, + 2209 => DB_ERROR_SYNTAX, + 2223 => DB_ERROR_SYNTAX, + 2248 => DB_ERROR_SYNTAX, + 2256 => DB_ERROR_SYNTAX, + 2257 => DB_ERROR_SYNTAX, 2627 => DB_ERROR_CONSTRAINT, 2714 => DB_ERROR_ALREADY_EXISTS, + 3607 => DB_ERROR_DIVZERO, 3701 => DB_ERROR_NOSUCHTABLE, + 7630 => DB_ERROR_SYNTAX, 8134 => DB_ERROR_DIVZERO, + 9303 => DB_ERROR_SYNTAX, + 9317 => DB_ERROR_SYNTAX, + 9318 => DB_ERROR_SYNTAX, + 9331 => DB_ERROR_SYNTAX, + 9332 => DB_ERROR_SYNTAX, + 15253 => DB_ERROR_SYNTAX, ); /** @@ -244,7 +273,7 @@ class DB_mssql extends DB_common */ function simpleQuery($query) { - $ismanip = DB::isManip($query); + $ismanip = $this->_checkManip($query); $this->last_query = $query; if (!@mssql_select_db($this->_db, $this->connection)) { return $this->mssqlRaiseError(DB_ERROR_NODBSELECTED); @@ -316,7 +345,7 @@ class DB_mssql extends DB_common } } if ($fetchmode & DB_FETCHMODE_ASSOC) { - $arr = @mssql_fetch_array($result, MSSQL_ASSOC); + $arr = @mssql_fetch_assoc($result); if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) { $arr = array_change_key_case($arr, CASE_LOWER); } @@ -353,7 +382,7 @@ class DB_mssql extends DB_common */ function freeResult($result) { - return @mssql_free_result($result); + return is_resource($result) ? mssql_free_result($result) : false; } // }}} @@ -483,7 +512,7 @@ class DB_mssql extends DB_common */ function affectedRows() { - if (DB::isManip($this->last_query)) { + if ($this->_last_query_manip) { $res = @mssql_query('select @@rowcount', $this->connection); if (!$res) { return $this->mssqlRaiseError(); @@ -537,7 +566,15 @@ class DB_mssql extends DB_common return $this->raiseError($result); } } elseif (!DB::isError($result)) { - $result =& $this->query("SELECT @@IDENTITY FROM $seqname"); + $result = $this->query("SELECT IDENT_CURRENT('$seqname')"); + if (DB::isError($result)) { + /* Fallback code for MS SQL Server 7.0, which doesn't have + * IDENT_CURRENT. This is *not* safe for concurrent + * requests, and really, if you're using it, you're in a + * world of hurt. Nevertheless, it's here to ensure BC. See + * bug #181 for the gory details.*/ + $result = $this->query("SELECT @@IDENTITY FROM $seqname"); + } $repeat = 0; } else { $repeat = false; @@ -745,16 +782,22 @@ class DB_mssql extends DB_common } for ($i = 0; $i < $count; $i++) { + if ($got_string) { + $flags = $this->_mssql_field_flags($result, + @mssql_field_name($id, $i)); + if (DB::isError($flags)) { + return $flags; + } + } else { + $flags = ''; + } + $res[$i] = array( 'table' => $got_string ? $case_func($result) : '', 'name' => $case_func(@mssql_field_name($id, $i)), 'type' => @mssql_field_type($id, $i), 'len' => @mssql_field_length($id, $i), - // We only support flags for table - 'flags' => $got_string - ? $this->_mssql_field_flags($result, - @mssql_field_name($id, $i)) - : '', + 'flags' => $flags, ); if ($mode & DB_TABLEINFO_ORDER) { $res['order'][$res[$i]['name']] = $i; @@ -805,7 +848,10 @@ class DB_mssql extends DB_common $tableName = $table; // get unique and primary keys - $res = $this->getAll("EXEC SP_HELPINDEX[$table]", DB_FETCHMODE_ASSOC); + $res = $this->getAll("EXEC SP_HELPINDEX $table", DB_FETCHMODE_ASSOC); + if (DB::isError($res)) { + return $res; + } foreach ($res as $val) { $keys = explode(', ', $val['index_keys']); @@ -828,7 +874,10 @@ class DB_mssql extends DB_common } // get auto_increment, not_null and timestamp - $res = $this->getAll("EXEC SP_COLUMNS[$table]", DB_FETCHMODE_ASSOC); + $res = $this->getAll("EXEC SP_COLUMNS $table", DB_FETCHMODE_ASSOC); + if (DB::isError($res)) { + return $res; + } foreach ($res as $val) { $val = array_change_key_case($val, CASE_LOWER); diff --git a/program/lib/DB/mysql.php b/program/lib/DB/mysql.php index 5b737b606..91572e14a 100644 --- a/program/lib/DB/mysql.php +++ b/program/lib/DB/mysql.php @@ -18,7 +18,7 @@ * @package DB * @author Stig Bakken * @author Daniel Convissor - * @copyright 1997-2005 The PHP Group + * @copyright 1997-2007 The PHP Group * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version CVS: $Id$ * @link http://pear.php.net/package/DB @@ -39,9 +39,9 @@ require_once 'DB/common.php'; * @package DB * @author Stig Bakken * @author Daniel Convissor - * @copyright 1997-2005 The PHP Group + * @copyright 1997-2007 The PHP Group * @license http://www.php.net/license/3_0.txt PHP License 3.0 - * @version Release: @package_version@ + * @version Release: 1.7.13 * @link http://pear.php.net/package/DB */ class DB_mysql extends DB_common @@ -111,6 +111,9 @@ class DB_mysql extends DB_common 1146 => DB_ERROR_NOSUCHTABLE, 1216 => DB_ERROR_CONSTRAINT, 1217 => DB_ERROR_CONSTRAINT, + 1356 => DB_ERROR_DIVZERO, + 1451 => DB_ERROR_CONSTRAINT, + 1452 => DB_ERROR_CONSTRAINT, ); /** @@ -236,10 +239,10 @@ class DB_mysql extends DB_common $this->connection = @call_user_func_array($connect_function, $params); } else { - ini_set('track_errors', 1); + @ini_set('track_errors', 1); $this->connection = @call_user_func_array($connect_function, $params); - ini_set('track_errors', $ini); + @ini_set('track_errors', $ini); } if (!$this->connection) { @@ -297,7 +300,7 @@ class DB_mysql extends DB_common */ function simpleQuery($query) { - $ismanip = DB::isManip($query); + $ismanip = $this->_checkManip($query); $this->last_query = $query; $query = $this->modifyQuery($query); if ($this->_db) { @@ -419,7 +422,7 @@ class DB_mysql extends DB_common */ function freeResult($result) { - return @mysql_free_result($result); + return is_resource($result) ? mysql_free_result($result) : false; } // }}} @@ -555,7 +558,7 @@ class DB_mysql extends DB_common */ function affectedRows() { - if (DB::isManip($this->last_query)) { + if ($this->_last_query_manip) { return @mysql_affected_rows($this->connection); } else { return 0; @@ -752,9 +755,10 @@ class DB_mysql extends DB_common /** * Quotes a string so it can be safely used as a table or column name + * (WARNING: using names that require this is a REALLY BAD IDEA) * - * MySQL can't handle the backtick character (`) in - * table or column names. + * WARNING: Older versions of MySQL can't handle the backtick + * character (`) in table or column names. * * @param string $str identifier name to be quoted * @@ -765,7 +769,7 @@ class DB_mysql extends DB_common */ function quoteIdentifier($str) { - return '`' . $str . '`'; + return '`' . str_replace('`', '``', $str) . '`'; } // }}} @@ -852,7 +856,7 @@ class DB_mysql extends DB_common */ function modifyLimitQuery($query, $from, $count, $params = array()) { - if (DB::isManip($query)) { + if (DB::isManip($query) || $this->_next_query_manip) { return $query . " LIMIT $count"; } else { return $query . " LIMIT $from, $count"; @@ -928,12 +932,19 @@ class DB_mysql extends DB_common function tableInfo($result, $mode = null) { if (is_string($result)) { + // Fix for bug #11580. + if ($this->_db) { + if (!@mysql_select_db($this->_db, $this->connection)) { + return $this->mysqlRaiseError(DB_ERROR_NODBSELECTED); + } + } + /* * Probably received a table name. * Create a result resource identifier. */ - $id = @mysql_list_fields($this->dsn['database'], - $result, $this->connection); + $id = @mysql_query("SELECT * FROM $result LIMIT 0", + $this->connection); $got_string = true; } elseif (isset($result->result)) { /* diff --git a/program/lib/DB/mysqli.php b/program/lib/DB/mysqli.php index bf742e27f..6cf912573 100644 --- a/program/lib/DB/mysqli.php +++ b/program/lib/DB/mysqli.php @@ -17,7 +17,7 @@ * @category Database * @package DB * @author Daniel Convissor - * @copyright 1997-2005 The PHP Group + * @copyright 1997-2007 The PHP Group * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version CVS: $Id$ * @link http://pear.php.net/package/DB @@ -41,9 +41,9 @@ require_once 'DB/common.php'; * @category Database * @package DB * @author Daniel Convissor - * @copyright 1997-2005 The PHP Group + * @copyright 1997-2007 The PHP Group * @license http://www.php.net/license/3_0.txt PHP License 3.0 - * @version Release: @package_version@ + * @version Release: 1.7.13 * @link http://pear.php.net/package/DB * @since Class functional since Release 1.6.3 */ @@ -114,6 +114,9 @@ class DB_mysqli extends DB_common 1146 => DB_ERROR_NOSUCHTABLE, 1216 => DB_ERROR_CONSTRAINT, 1217 => DB_ERROR_CONSTRAINT, + 1356 => DB_ERROR_DIVZERO, + 1451 => DB_ERROR_CONSTRAINT, + 1452 => DB_ERROR_CONSTRAINT, ); /** @@ -210,6 +213,10 @@ class DB_mysqli extends DB_common MYSQLI_TYPE_VAR_STRING => 'varchar', MYSQLI_TYPE_STRING => 'char', MYSQLI_TYPE_GEOMETRY => 'geometry', + /* These constants are conditionally compiled in ext/mysqli, so we'll + * define them by number rather than constant. */ + 16 => 'bit', + 246 => 'decimal', ); @@ -264,7 +271,7 @@ class DB_mysqli extends DB_common * 'ssl' => true, * ); * - * $db =& DB::connect($dsn, $options); + * $db = DB::connect($dsn, $options); * if (PEAR::isError($db)) { * die($db->getMessage()); * } @@ -287,10 +294,10 @@ class DB_mysqli extends DB_common } $ini = ini_get('track_errors'); - ini_set('track_errors', 1); + @ini_set('track_errors', 1); $php_errormsg = ''; - if ($this->getOption('ssl') === true) { + if (((int) $this->getOption('ssl')) === 1) { $init = mysqli_init(); mysqli_ssl_set( $init, @@ -322,7 +329,7 @@ class DB_mysqli extends DB_common ); } - ini_set('track_errors', $ini); + @ini_set('track_errors', $ini); if (!$this->connection) { if (($err = @mysqli_connect_error()) != '') { @@ -372,7 +379,7 @@ class DB_mysqli extends DB_common */ function simpleQuery($query) { - $ismanip = DB::isManip($query); + $ismanip = $this->_checkManip($query); $this->last_query = $query; $query = $this->modifyQuery($query); if ($this->_db) { @@ -490,7 +497,7 @@ class DB_mysqli extends DB_common */ function freeResult($result) { - return @mysqli_free_result($result); + return is_resource($result) ? mysqli_free_result($result) : false; } // }}} @@ -626,7 +633,7 @@ class DB_mysqli extends DB_common */ function affectedRows() { - if (DB::isManip($this->last_query)) { + if ($this->_last_query_manip) { return @mysqli_affected_rows($this->connection); } else { return 0; @@ -823,9 +830,10 @@ class DB_mysqli extends DB_common /** * Quotes a string so it can be safely used as a table or column name + * (WARNING: using names that require this is a REALLY BAD IDEA) * - * MySQL can't handle the backtick character (`) in - * table or column names. + * WARNING: Older versions of MySQL can't handle the backtick + * character (`) in table or column names. * * @param string $str identifier name to be quoted * @@ -836,7 +844,7 @@ class DB_mysqli extends DB_common */ function quoteIdentifier($str) { - return '`' . $str . '`'; + return '`' . str_replace('`', '``', $str) . '`'; } // }}} @@ -878,7 +886,7 @@ class DB_mysqli extends DB_common */ function modifyLimitQuery($query, $from, $count, $params = array()) { - if (DB::isManip($query)) { + if (DB::isManip($query) || $this->_next_query_manip) { return $query . " LIMIT $count"; } else { return $query . " LIMIT $from, $count"; @@ -954,6 +962,13 @@ class DB_mysqli extends DB_common function tableInfo($result, $mode = null) { if (is_string($result)) { + // Fix for bug #11580. + if ($this->_db) { + if (!@mysqli_select_db($this->connection, $this->_db)) { + return $this->mysqliRaiseError(DB_ERROR_NODBSELECTED); + } + } + /* * Probably received a table name. * Create a result resource identifier. @@ -1015,7 +1030,8 @@ class DB_mysqli extends DB_common 'type' => isset($this->mysqli_types[$tmp->type]) ? $this->mysqli_types[$tmp->type] : 'unknown', - 'len' => $tmp->max_length, + // http://bugs.php.net/?id=36579 + 'len' => $tmp->length, 'flags' => $flags, ); diff --git a/program/lib/DB/oci8.php b/program/lib/DB/oci8.php index c610a04e8..f2f8e3d4c 100644 --- a/program/lib/DB/oci8.php +++ b/program/lib/DB/oci8.php @@ -18,7 +18,7 @@ * @package DB * @author James L. Pine * @author Daniel Convissor - * @copyright 1997-2005 The PHP Group + * @copyright 1997-2007 The PHP Group * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version CVS: $Id$ * @link http://pear.php.net/package/DB @@ -45,9 +45,9 @@ require_once 'DB/common.php'; * @package DB * @author James L. Pine * @author Daniel Convissor - * @copyright 1997-2005 The PHP Group + * @copyright 1997-2007 The PHP Group * @license http://www.php.net/license/3_0.txt PHP License 3.0 - * @version Release: @package_version@ + * @version Release: 1.7.13 * @link http://pear.php.net/package/DB */ class DB_oci8 extends DB_common @@ -94,24 +94,25 @@ class DB_oci8 extends DB_common * @var array */ var $errorcode_map = array( - 1 => DB_ERROR_CONSTRAINT, - 900 => DB_ERROR_SYNTAX, - 904 => DB_ERROR_NOSUCHFIELD, - 913 => DB_ERROR_VALUE_COUNT_ON_ROW, - 921 => DB_ERROR_SYNTAX, - 923 => DB_ERROR_SYNTAX, - 942 => DB_ERROR_NOSUCHTABLE, - 955 => DB_ERROR_ALREADY_EXISTS, - 1400 => DB_ERROR_CONSTRAINT_NOT_NULL, - 1401 => DB_ERROR_INVALID, - 1407 => DB_ERROR_CONSTRAINT_NOT_NULL, - 1418 => DB_ERROR_NOT_FOUND, - 1476 => DB_ERROR_DIVZERO, - 1722 => DB_ERROR_INVALID_NUMBER, - 2289 => DB_ERROR_NOSUCHTABLE, - 2291 => DB_ERROR_CONSTRAINT, - 2292 => DB_ERROR_CONSTRAINT, - 2449 => DB_ERROR_CONSTRAINT, + 1 => DB_ERROR_CONSTRAINT, + 900 => DB_ERROR_SYNTAX, + 904 => DB_ERROR_NOSUCHFIELD, + 913 => DB_ERROR_VALUE_COUNT_ON_ROW, + 921 => DB_ERROR_SYNTAX, + 923 => DB_ERROR_SYNTAX, + 942 => DB_ERROR_NOSUCHTABLE, + 955 => DB_ERROR_ALREADY_EXISTS, + 1400 => DB_ERROR_CONSTRAINT_NOT_NULL, + 1401 => DB_ERROR_INVALID, + 1407 => DB_ERROR_CONSTRAINT_NOT_NULL, + 1418 => DB_ERROR_NOT_FOUND, + 1476 => DB_ERROR_DIVZERO, + 1722 => DB_ERROR_INVALID_NUMBER, + 2289 => DB_ERROR_NOSUCHTABLE, + 2291 => DB_ERROR_CONSTRAINT, + 2292 => DB_ERROR_CONSTRAINT, + 2449 => DB_ERROR_CONSTRAINT, + 12899 => DB_ERROR_INVALID, ); /** @@ -160,6 +161,13 @@ class DB_oci8 extends DB_common */ var $manip_query = array(); + /** + * Store of prepared SQL queries. + * @var array + * @access private + */ + var $_prepared_queries = array(); + // }}} // {{{ constructor @@ -216,6 +224,13 @@ class DB_oci8 extends DB_common $this->dbsyntax = $dsn['dbsyntax']; } + // Backwards compatibility with DB < 1.7.0 + if (empty($dsn['database']) && !empty($dsn['hostspec'])) { + $db = $dsn['hostspec']; + } else { + $db = $dsn['database']; + } + if (function_exists('oci_connect')) { if (isset($dsn['new_link']) && ($dsn['new_link'] == 'true' || $dsn['new_link'] === true)) @@ -225,12 +240,8 @@ class DB_oci8 extends DB_common $connect_function = $persistent ? 'oci_pconnect' : 'oci_connect'; } - - // Backwards compatibility with DB < 1.7.0 - if (empty($dsn['database']) && !empty($dsn['hostspec'])) { - $db = $dsn['hostspec']; - } else { - $db = $dsn['database']; + if (isset($this->dsn['port']) && $this->dsn['port']) { + $db = '//'.$db.':'.$this->dsn['port']; } $char = empty($dsn['charset']) ? null : $dsn['charset']; @@ -248,10 +259,10 @@ class DB_oci8 extends DB_common } } else { $connect_function = $persistent ? 'OCIPLogon' : 'OCILogon'; - if ($dsn['hostspec']) { + if ($db) { $this->connection = @$connect_function($dsn['username'], $dsn['password'], - $dsn['hostspec']); + $db); } elseif ($dsn['username'] || $dsn['password']) { $this->connection = @$connect_function($dsn['username'], $dsn['password']); @@ -322,7 +333,7 @@ class DB_oci8 extends DB_common return $this->oci8RaiseError($result); } $this->last_stmt = $result; - if (DB::isManip($query)) { + if ($this->_checkManip($query)) { return DB_OK; } else { @ocisetprefetch($result, $this->options['result_buffering']); @@ -415,7 +426,7 @@ class DB_oci8 extends DB_common */ function freeResult($result) { - return @OCIFreeStatement($result); + return is_resource($result) ? OCIFreeStatement($result) : false; } /** @@ -476,20 +487,18 @@ class DB_oci8 extends DB_common $save_query = $this->last_query; $save_stmt = $this->last_stmt; - if (count($this->_data)) { - $smt = $this->prepare('SELECT COUNT(*) FROM ('.$this->last_query.')'); - $count = $this->execute($smt, $this->_data); - } else { - $count =& $this->query($countquery); - } + $count = $this->query($countquery); + // Restore the last query and statement. + $this->last_query = $save_query; + $this->last_stmt = $save_stmt; + if (DB::isError($count) || DB::isError($row = $count->fetchRow(DB_FETCHMODE_ORDERED))) { - $this->last_query = $save_query; - $this->last_stmt = $save_stmt; return $this->raiseError(DB_ERROR_NOT_CAPABLE); } + return $row[0]; } return $this->raiseError(DB_ERROR_NOT_CAPABLE); @@ -590,6 +599,7 @@ class DB_oci8 extends DB_common } $this->prepare_types[(int)$stmt] = $types; $this->manip_query[(int)$stmt] = DB::isManip($query); + $this->_prepared_queries[(int)$stmt] = $newquery; return $stmt; } @@ -620,11 +630,12 @@ class DB_oci8 extends DB_common { $data = (array)$data; $this->last_parameters = $data; + $this->last_query = $this->_prepared_queries[(int)$stmt]; $this->_data = $data; - $types =& $this->prepare_types[(int)$stmt]; + $types = $this->prepare_types[(int)$stmt]; if (count($types) != count($data)) { - $tmp =& $this->raiseError(DB_ERROR_MISMATCH); + $tmp = $this->raiseError(DB_ERROR_MISMATCH); return $tmp; } @@ -643,16 +654,23 @@ class DB_oci8 extends DB_common } elseif ($types[$i] == DB_PARAM_OPAQUE) { $fp = @fopen($data[$key], 'rb'); if (!$fp) { - $tmp =& $this->raiseError(DB_ERROR_ACCESS_VIOLATION); + $tmp = $this->raiseError(DB_ERROR_ACCESS_VIOLATION); return $tmp; } $data[$key] = fread($fp, filesize($data[$key])); fclose($fp); + } elseif ($types[$i] == DB_PARAM_SCALAR) { + // Floats have to be converted to a locale-neutral + // representation. + if (is_float($data[$key])) { + $data[$key] = $this->quoteFloat($data[$key]); + } } if (!@OCIBindByName($stmt, ':bind' . $i, $data[$key], -1)) { $tmp = $this->oci8RaiseError($stmt); return $tmp; } + $this->last_query = str_replace(':bind'.$i, $this->quoteSmart($data[$key]), $this->last_query); $i++; } if ($this->autocommit) { @@ -665,11 +683,14 @@ class DB_oci8 extends DB_common return $tmp; } $this->last_stmt = $stmt; - if ($this->manip_query[(int)$stmt]) { + if ($this->manip_query[(int)$stmt] || $this->_next_query_manip) { + $this->_last_query_manip = true; + $this->_next_query_manip = false; $tmp = DB_OK; } else { + $this->_last_query_manip = false; @ocisetprefetch($stmt, $this->options['result_buffering']); - $tmp =& new DB_result($this, $stmt); + $tmp = new DB_result($this, $stmt); } return $tmp; } @@ -797,7 +818,7 @@ class DB_oci8 extends DB_common if (count($params)) { $result = $this->prepare("SELECT * FROM ($query) " . 'WHERE NULL = NULL'); - $tmp =& $this->execute($result, $params); + $tmp = $this->execute($result, $params); } else { $q_fields = "SELECT * FROM ($query) WHERE NULL = NULL"; @@ -857,7 +878,7 @@ class DB_oci8 extends DB_common $repeat = 0; do { $this->expectError(DB_ERROR_NOSUCHTABLE); - $result =& $this->query("SELECT ${seqname}.nextval FROM dual"); + $result = $this->query("SELECT ${seqname}.nextval FROM dual"); $this->popExpect(); if ($ondemand && DB::isError($result) && $result->getCode() == DB_ERROR_NOSUCHTABLE) { @@ -1015,7 +1036,7 @@ class DB_oci8 extends DB_common if (!@OCIExecute($stmt, OCI_DEFAULT)) { return $this->oci8RaiseError($stmt); } - + $i = 0; while (@OCIFetch($stmt)) { $res[$i] = array( @@ -1098,12 +1119,30 @@ class DB_oci8 extends DB_common return 'SELECT table_name FROM user_tables'; case 'synonyms': return 'SELECT synonym_name FROM user_synonyms'; + case 'views': + return 'SELECT view_name FROM user_views'; default: return null; } } // }}} + // {{{ quoteFloat() + + /** + * Formats a float value for use within a query in a locale-independent + * manner. + * + * @param float the float value to be quoted. + * @return string the quoted string. + * @see DB_common::quoteSmart() + * @since Method available since release 1.7.8. + */ + function quoteFloat($float) { + return $this->escapeSimple(str_replace(',', '.', strval(floatval($float)))); + } + + // }}} } diff --git a/program/lib/DB/odbc.php b/program/lib/DB/odbc.php index c920d7a63..350ec85bd 100644 --- a/program/lib/DB/odbc.php +++ b/program/lib/DB/odbc.php @@ -18,7 +18,7 @@ * @package DB * @author Stig Bakken * @author Daniel Convissor - * @copyright 1997-2005 The PHP Group + * @copyright 1997-2007 The PHP Group * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version CVS: $Id$ * @link http://pear.php.net/package/DB @@ -42,9 +42,9 @@ require_once 'DB/common.php'; * @package DB * @author Stig Bakken * @author Daniel Convissor - * @copyright 1997-2005 The PHP Group + * @copyright 1997-2007 The PHP Group * @license http://www.php.net/license/3_0.txt PHP License 3.0 - * @version Release: @package_version@ + * @version Release: 1.7.13 * @link http://pear.php.net/package/DB */ class DB_odbc extends DB_common @@ -266,7 +266,7 @@ class DB_odbc extends DB_common } // Determine which queries that should return data, and which // should return an error code only. - if (DB::isManip($query)) { + if ($this->_checkManip($query)) { $this->affected = $result; // For affectedRows() return DB_OK; } @@ -367,7 +367,7 @@ class DB_odbc extends DB_common */ function freeResult($result) { - return @odbc_free_result($result); + return is_resource($result) ? odbc_free_result($result) : false; } // }}} diff --git a/program/lib/DB/pgsql.php b/program/lib/DB/pgsql.php index ae229afa1..fc3762a65 100644 --- a/program/lib/DB/pgsql.php +++ b/program/lib/DB/pgsql.php @@ -19,7 +19,7 @@ * @author Rui Hirokawa * @author Stig Bakken * @author Daniel Convissor - * @copyright 1997-2005 The PHP Group + * @copyright 1997-2007 The PHP Group * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version CVS: $Id$ * @link http://pear.php.net/package/DB @@ -41,9 +41,9 @@ require_once 'DB/common.php'; * @author Rui Hirokawa * @author Stig Bakken * @author Daniel Convissor - * @copyright 1997-2005 The PHP Group + * @copyright 1997-2007 The PHP Group * @license http://www.php.net/license/3_0.txt PHP License 3.0 - * @version Release: @package_version@ + * @version Release: 1.7.13 * @link http://pear.php.net/package/DB */ class DB_pgsql extends DB_common @@ -193,7 +193,7 @@ class DB_pgsql extends DB_common * 'portability' => DB_PORTABILITY_ALL, * ); * - * $db =& DB::connect($dsn, $options); + * $db = DB::connect($dsn, $options); * if (PEAR::isError($db)) { * die($db->getMessage()); * } @@ -277,10 +277,10 @@ class DB_pgsql extends DB_common $this->connection = @call_user_func_array($connect_function, $params); } else { - ini_set('track_errors', 1); + @ini_set('track_errors', 1); $this->connection = @call_user_func_array($connect_function, $params); - ini_set('track_errors', $ini); + @ini_set('track_errors', $ini); } if (!$this->connection) { @@ -320,7 +320,7 @@ class DB_pgsql extends DB_common */ function simpleQuery($query) { - $ismanip = DB::isManip($query); + $ismanip = $this->_checkManip($query); $this->last_query = $query; $query = $this->modifyQuery($query); if (!$this->autocommit && $ismanip) { @@ -336,19 +336,26 @@ class DB_pgsql extends DB_common if (!$result) { return $this->pgsqlRaiseError(); } - // Determine which queries that should return data, and which - // should return an error code only. + + /* + * Determine whether queries produce affected rows, result or nothing. + * + * This logic was introduced in version 1.1 of the file by ssb, + * though the regex has been modified slightly since then. + * + * PostgreSQL commands: + * ABORT, ALTER, BEGIN, CLOSE, CLUSTER, COMMIT, COPY, + * CREATE, DECLARE, DELETE, DROP TABLE, EXPLAIN, FETCH, + * GRANT, INSERT, LISTEN, LOAD, LOCK, MOVE, NOTIFY, RESET, + * REVOKE, ROLLBACK, SELECT, SELECT INTO, SET, SHOW, + * UNLISTEN, UPDATE, VACUUM + */ if ($ismanip) { $this->affected = @pg_affected_rows($result); return DB_OK; - } elseif (preg_match('/^\s*\(*\s*(SELECT|EXPLAIN|SHOW)\s/si', $query)) { - /* PostgreSQL commands: - ABORT, ALTER, BEGIN, CLOSE, CLUSTER, COMMIT, COPY, - CREATE, DECLARE, DELETE, DROP TABLE, EXPLAIN, FETCH, - GRANT, INSERT, LISTEN, LOAD, LOCK, MOVE, NOTIFY, RESET, - REVOKE, ROLLBACK, SELECT, SELECT INTO, SET, SHOW, - UNLISTEN, UPDATE, VACUUM - */ + } elseif (preg_match('/^\s*\(*\s*(SELECT|EXPLAIN|FETCH|SHOW)\s/si', + $query)) + { $this->row[(int)$result] = 0; // reset the row counter. $numrows = $this->numRows($result); if (is_object($numrows)) { @@ -471,38 +478,21 @@ class DB_pgsql extends DB_common } // }}} - // {{{ quoteSmart() + // {{{ quoteBoolean() /** - * 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 NULL - * + boolean = string TRUE or FALSE - * + integer or double = the unquoted number - * + other (including strings and numeric strings) = - * the data escaped according to MySQL's settings - * then encapsulated between single quotes + * Formats a boolean value for use within a query in a locale-independent + * manner. * + * @param boolean the boolean value to be quoted. + * @return string the quoted string. * @see DB_common::quoteSmart() - * @since Method available since Release 1.6.0 + * @since Method available since release 1.7.8. */ - 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) . "'"; - } + function quoteBoolean($boolean) { + return $boolean ? 'TRUE' : 'FALSE'; } - + // }}} // {{{ escapeSimple() @@ -512,9 +502,6 @@ class DB_pgsql extends DB_common * {@internal PostgreSQL treats a backslash as an escape character, * so they are escaped as well. * - * Not using pg_escape_string() yet because it requires PostgreSQL - * to be at version 7.2 or greater.}} - * * @param string $str the string to be escaped * * @return string the escaped string @@ -524,7 +511,21 @@ class DB_pgsql extends DB_common */ function escapeSimple($str) { - return str_replace("'", "''", str_replace('\\', '\\\\', $str)); + if (function_exists('pg_escape_string')) { + /* This fixes an undocumented BC break in PHP 5.2.0 which changed + * the prototype of pg_escape_string. I'm not thrilled about having + * to sniff the PHP version, quite frankly, but it's the only way + * to deal with the problem. Revision 1.331.2.13.2.10 on + * php-src/ext/pgsql/pgsql.c (PHP_5_2 branch) is to blame, for the + * record. */ + if (version_compare(PHP_VERSION, '5.2.0', '>=')) { + return pg_escape_string($this->connection, $str); + } else { + return pg_escape_string($str); + } + } else { + return str_replace("'", "''", str_replace('\\', '\\\\', $str)); + } } // }}} @@ -675,7 +676,7 @@ class DB_pgsql extends DB_common $repeat = false; do { $this->pushErrorHandling(PEAR_ERROR_RETURN); - $result =& $this->query("SELECT NEXTVAL('${seqname}')"); + $result = $this->query("SELECT NEXTVAL('${seqname}')"); $this->popErrorHandling(); if ($ondemand && DB::isError($result) && $result->getCode() == DB_ERROR_NOSUCHTABLE) { @@ -779,6 +780,10 @@ class DB_pgsql extends DB_common function pgsqlRaiseError($errno = null) { $native = $this->errorNative(); + if (!$native) { + $native = 'Database connection has been lost.'; + $errno = DB_ERROR_CONNECT_FAILED; + } if ($errno === null) { $errno = $this->errorCode($native); } @@ -815,12 +820,12 @@ class DB_pgsql extends DB_common static $error_regexps; if (!isset($error_regexps)) { $error_regexps = array( + '/column .* (of relation .*)?does not exist/i' + => DB_ERROR_NOSUCHFIELD, '/(relation|sequence|table).*does not exist|class .* not found/i' => DB_ERROR_NOSUCHTABLE, '/index .* does not exist/' => DB_ERROR_NOT_FOUND, - '/column .* does not exist/i' - => DB_ERROR_NOSUCHFIELD, '/relation .* already exists/i' => DB_ERROR_ALREADY_EXISTS, '/(divide|division) by zero$/i' @@ -976,22 +981,33 @@ class DB_pgsql extends DB_common { $field_name = @pg_fieldname($resource, $num_field); + // Check if there's a schema in $table_name and update things + // accordingly. + $from = 'pg_attribute f, pg_class tab, pg_type typ'; + if (strpos($table_name, '.') !== false) { + $from .= ', pg_namespace nsp'; + list($schema, $table) = explode('.', $table_name); + $tableWhere = "tab.relname = '$table' AND tab.relnamespace = nsp.oid AND nsp.nspname = '$schema'"; + } else { + $tableWhere = "tab.relname = '$table_name'"; + } + $result = @pg_exec($this->connection, "SELECT f.attnotnull, f.atthasdef - FROM pg_attribute f, pg_class tab, pg_type typ + FROM $from WHERE tab.relname = typ.typname AND typ.typrelid = f.attrelid AND f.attname = '$field_name' - AND tab.relname = '$table_name'"); + AND $tableWhere"); if (@pg_numrows($result) > 0) { $row = @pg_fetch_row($result, 0); $flags = ($row[0] == 't') ? 'not_null ' : ''; if ($row[1] == 't') { $result = @pg_exec($this->connection, "SELECT a.adsrc - FROM pg_attribute f, pg_class tab, pg_type typ, pg_attrdef a + FROM $from, pg_attrdef a WHERE tab.relname = typ.typname AND typ.typrelid = f.attrelid AND f.attrelid = a.adrelid AND f.attname = '$field_name' - AND tab.relname = '$table_name' AND f.attnum = a.adnum"); + AND $tableWhere AND f.attnum = a.adnum"); $row = @pg_fetch_row($result, 0); $num = preg_replace("/'(.*)'::\w+/", "\\1", $row[0]); $flags .= 'default_' . rawurlencode($num) . ' '; @@ -1000,12 +1016,12 @@ class DB_pgsql extends DB_common $flags = ''; } $result = @pg_exec($this->connection, "SELECT i.indisunique, i.indisprimary, i.indkey - FROM pg_attribute f, pg_class tab, pg_type typ, pg_index i + FROM $from, pg_index i WHERE tab.relname = typ.typname AND typ.typrelid = f.attrelid AND f.attrelid = i.indrelid AND f.attname = '$field_name' - AND tab.relname = '$table_name'"); + AND $tableWhere"); $count = @pg_numrows($result); for ($i = 0; $i < $count ; $i++) { @@ -1066,6 +1082,9 @@ class DB_pgsql extends DB_common . ' FROM pg_catalog.pg_tables' . ' WHERE schemaname NOT IN' . " ('pg_catalog', 'information_schema', 'pg_toast')"; + case 'schema.views': + return "SELECT schemaname || '.' || viewname from pg_views WHERE schemaname" + . " NOT IN ('information_schema', 'pg_catalog')"; case 'views': // Table cols: viewname | viewowner | definition return 'SELECT viewname from pg_views WHERE schemaname' diff --git a/program/lib/DB/sqlite.php b/program/lib/DB/sqlite.php index 42f599e5d..63fd68bac 100644 --- a/program/lib/DB/sqlite.php +++ b/program/lib/DB/sqlite.php @@ -19,7 +19,7 @@ * @author Urs Gehrig * @author Mika Tuupola * @author Daniel Convissor - * @copyright 1997-2005 The PHP Group + * @copyright 1997-2007 The PHP Group * @license http://www.php.net/license/3_0.txt PHP License 3.0 3.0 * @version CVS: $Id$ * @link http://pear.php.net/package/DB @@ -45,9 +45,9 @@ require_once 'DB/common.php'; * @author Urs Gehrig * @author Mika Tuupola * @author Daniel Convissor - * @copyright 1997-2005 The PHP Group + * @copyright 1997-2007 The PHP Group * @license http://www.php.net/license/3_0.txt PHP License 3.0 3.0 - * @version Release: @package_version@ + * @version Release: 1.7.13 * @link http://pear.php.net/package/DB */ class DB_sqlite extends DB_common @@ -182,7 +182,7 @@ class DB_sqlite extends DB_common * 'portability' => DB_PORTABILITY_ALL, * ); * - * $db =& DB::connect($dsn, $options); + * $db = DB::connect($dsn, $options); * if (PEAR::isError($db)) { * die($db->getMessage()); * } @@ -204,7 +204,11 @@ class DB_sqlite extends DB_common $this->dbsyntax = $dsn['dbsyntax']; } - if ($dsn['database']) { + if (!$dsn['database']) { + return $this->sqliteRaiseError(DB_ERROR_ACCESS_VIOLATION); + } + + if ($dsn['database'] !== ':memory:') { if (!file_exists($dsn['database'])) { if (!touch($dsn['database'])) { return $this->sqliteRaiseError(DB_ERROR_NOT_FOUND); @@ -229,14 +233,12 @@ class DB_sqlite extends DB_common 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); + @ini_set('track_errors', 1); $php_errormsg = ''; if (!$this->connection = @$connect_function($dsn['database'])) { @@ -280,7 +282,7 @@ class DB_sqlite extends DB_common */ function simpleQuery($query) { - $ismanip = DB::isManip($query); + $ismanip = $this->_checkManip($query); $this->last_query = $query; $query = $this->modifyQuery($query); @@ -357,6 +359,16 @@ class DB_sqlite extends DB_common if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) { $arr = array_change_key_case($arr, CASE_LOWER); } + + /* Remove extraneous " characters from the fields in the result. + * Fixes bug #11716. */ + if (is_array($arr) && count($arr) > 0) { + $strippedArr = array(); + foreach ($arr as $field => $value) { + $strippedArr[trim($field, '"')] = $value; + } + $arr = $strippedArr; + } } else { $arr = @sqlite_fetch_array($result, SQLITE_NUM); } @@ -727,6 +739,11 @@ class DB_sqlite extends DB_common function errorCode($errormsg) { static $error_regexps; + + // PHP 5.2+ prepends the function name to $php_errormsg, so we need + // this hack to work around it, per bug #9599. + $errormsg = preg_replace('/^sqlite[a-z_]+\(\): /', '', $errormsg); + if (!isset($error_regexps)) { $error_regexps = array( '/^no such table:/' => DB_ERROR_NOSUCHTABLE, diff --git a/program/lib/DB/storage.php b/program/lib/DB/storage.php index 17bffd155..67318a910 100644 --- a/program/lib/DB/storage.php +++ b/program/lib/DB/storage.php @@ -16,7 +16,7 @@ * @category Database * @package DB * @author Stig Bakken - * @copyright 1997-2005 The PHP Group + * @copyright 1997-2007 The PHP Group * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version CVS: $Id$ * @link http://pear.php.net/package/DB @@ -36,9 +36,9 @@ require_once 'DB.php'; * @category Database * @package DB * @author Stig Bakken - * @copyright 1997-2005 The PHP Group + * @copyright 1997-2007 The PHP Group * @license http://www.php.net/license/3_0.txt PHP License 3.0 - * @version Release: @package_version@ + * @version Release: 1.7.13 * @link http://pear.php.net/package/DB */ class DB_storage extends PEAR @@ -293,7 +293,7 @@ class DB_storage extends PEAR function &create($table, &$data) { $classname = strtolower(get_class($this)); - $obj =& new $classname($table); + $obj = new $classname($table); foreach ($data as $name => $value) { $obj->_properties[$name] = true; $obj->$name = &$value; @@ -445,6 +445,8 @@ class DB_storage extends PEAR */ function store() { + $params = array(); + $vars = array(); foreach ($this->_changes as $name => $foo) { $params[] = &$this->$name; $vars[] = $name . ' = ?'; diff --git a/program/lib/DB/sybase.php b/program/lib/DB/sybase.php index 893178213..3172701cb 100644 --- a/program/lib/DB/sybase.php +++ b/program/lib/DB/sybase.php @@ -19,7 +19,7 @@ * @author Sterling Hughes * @author Antônio Carlos Venâncio Júnior * @author Daniel Convissor - * @copyright 1997-2005 The PHP Group + * @copyright 1997-2007 The PHP Group * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version CVS: $Id$ * @link http://pear.php.net/package/DB @@ -44,9 +44,9 @@ require_once 'DB/common.php'; * @author Sterling Hughes * @author Antônio Carlos Venâncio Júnior * @author Daniel Convissor - * @copyright 1997-2005 The PHP Group + * @copyright 1997-2007 The PHP Group * @license http://www.php.net/license/3_0.txt PHP License 3.0 - * @version Release: @package_version@ + * @version Release: 1.7.13 * @link http://pear.php.net/package/DB */ class DB_sybase extends DB_common @@ -248,9 +248,9 @@ class DB_sybase extends DB_common */ function simpleQuery($query) { - $ismanip = DB::isManip($query); + $ismanip = $this->_checkManip($query); $this->last_query = $query; - if (!@sybase_select_db($this->_db, $this->connection)) { + if ($this->_db && !@sybase_select_db($this->_db, $this->connection)) { return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED); } $query = $this->modifyQuery($query); @@ -370,7 +370,7 @@ class DB_sybase extends DB_common */ function freeResult($result) { - return @sybase_free_result($result); + return is_resource($result) ? sybase_free_result($result) : false; } // }}} @@ -435,7 +435,7 @@ class DB_sybase extends DB_common */ function affectedRows() { - if (DB::isManip($this->last_query)) { + if ($this->_last_query_manip) { $result = @sybase_affected_rows($this->connection); } else { $result = 0; @@ -462,7 +462,7 @@ class DB_sybase extends DB_common function nextId($seq_name, $ondemand = true) { $seqname = $this->getSequenceName($seq_name); - if (!@sybase_select_db($this->_db, $this->connection)) { + if ($this->_db && !@sybase_select_db($this->_db, $this->connection)) { return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED); } $repeat = 0; @@ -479,7 +479,7 @@ class DB_sybase extends DB_common return $this->raiseError($result); } } elseif (!DB::isError($result)) { - $result =& $this->query("SELECT @@IDENTITY FROM $seqname"); + $result = $this->query("SELECT @@IDENTITY FROM $seqname"); $repeat = 0; } else { $repeat = false; @@ -528,6 +528,22 @@ class DB_sybase extends DB_common return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name)); } + // }}} + // {{{ quoteFloat() + + /** + * Formats a float value for use within a query in a locale-independent + * manner. + * + * @param float the float value to be quoted. + * @return string the quoted string. + * @see DB_common::quoteSmart() + * @since Method available since release 1.7.8. + */ + function quoteFloat($float) { + return $this->escapeSimple(str_replace(',', '.', strval(floatval($float)))); + } + // }}} // {{{ autoCommit() @@ -558,7 +574,7 @@ class DB_sybase extends DB_common function commit() { if ($this->transaction_opcount > 0) { - if (!@sybase_select_db($this->_db, $this->connection)) { + if ($this->_db && !@sybase_select_db($this->_db, $this->connection)) { return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED); } $result = @sybase_query('COMMIT', $this->connection); @@ -581,7 +597,7 @@ class DB_sybase extends DB_common function rollback() { if ($this->transaction_opcount > 0) { - if (!@sybase_select_db($this->_db, $this->connection)) { + if ($this->_db && !@sybase_select_db($this->_db, $this->connection)) { return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED); } $result = @sybase_query('ROLLBACK', $this->connection); @@ -642,6 +658,11 @@ class DB_sybase extends DB_common function errorCode($errormsg) { static $error_regexps; + + // PHP 5.2+ prepends the function name to $php_errormsg, so we need + // this hack to work around it, per bug #9599. + $errormsg = preg_replace('/^sybase[a-z_]+\(\): /', '', $errormsg); + if (!isset($error_regexps)) { $error_regexps = array( '/Incorrect syntax near/' @@ -674,6 +695,8 @@ class DB_sybase extends DB_common => DB_ERROR_ALREADY_EXISTS, '/^There are fewer columns in the INSERT statement than values specified/i' => DB_ERROR_VALUE_COUNT_ON_ROW, + '/Divide by zero/i' + => DB_ERROR_DIVZERO, ); } @@ -714,7 +737,7 @@ class DB_sybase extends DB_common * Probably received a table name. * Create a result resource identifier. */ - if (!@sybase_select_db($this->_db, $this->connection)) { + if ($this->_db && !@sybase_select_db($this->_db, $this->connection)) { return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED); } $id = @sybase_query("SELECT * FROM $result WHERE 1=0", @@ -811,14 +834,24 @@ class DB_sybase extends DB_common $flags = array(); $tableName = $table; - // get unique/primary keys - $res = $this->getAll("sp_helpindex $table", DB_FETCHMODE_ASSOC); + /* We're running sp_helpindex directly because it doesn't exist in + * older versions of ASE -- unfortunately, we can't just use + * DB::isError() because the user may be using callback error + * handling. */ + $res = @sybase_query("sp_helpindex $table", $this->connection); - if (!isset($res[0]['index_description'])) { + if ($res === false || $res === true) { + // Fake a valid response for BC reasons. return ''; } - foreach ($res as $val) { + while (($val = sybase_fetch_assoc($res)) !== false) { + if (!isset($val['index_keys'])) { + /* No useful information returned. Break and be done with + * it, which preserves the pre-1.7.9 behaviour. */ + break; + } + $keys = explode(', ', trim($val['index_keys'])); if (sizeof($keys) > 1) { @@ -834,6 +867,8 @@ class DB_sybase extends DB_common } } + sybase_free_result($res); + } if (array_key_exists($column, $flags)) {