2005-07-04 01:07:14 +00:00
|
|
|
<?php
|
2005-08-21 06:49:02 +00:00
|
|
|
/* SVN FILE: $Id$ */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Short description for file.
|
2006-01-12 02:10:47 +00:00
|
|
|
*
|
2005-08-21 06:49:02 +00:00
|
|
|
* Long description for file
|
|
|
|
*
|
|
|
|
* PHP versions 4 and 5
|
|
|
|
*
|
|
|
|
* CakePHP : Rapid Development Framework <http://www.cakephp.org/>
|
2006-01-12 02:10:47 +00:00
|
|
|
* Copyright (c) 2005, Cake Software Foundation, Inc.
|
2005-12-23 21:57:26 +00:00
|
|
|
* 1785 E. Sahara Avenue, Suite 490-204
|
|
|
|
* Las Vegas, Nevada 89104
|
2005-08-21 06:49:02 +00:00
|
|
|
*
|
2005-12-23 21:57:26 +00:00
|
|
|
* Licensed under The MIT License
|
|
|
|
* Redistributions of files must retain the above copyright notice.
|
2005-08-21 06:49:02 +00:00
|
|
|
*
|
2006-01-12 02:10:47 +00:00
|
|
|
* @filesource
|
2005-12-23 21:57:26 +00:00
|
|
|
* @copyright Copyright (c) 2005, Cake Software Foundation, Inc.
|
|
|
|
* @link http://www.cakefoundation.org/projects/info/cakephp CakePHP Project
|
2005-08-21 06:49:02 +00:00
|
|
|
* @package cake
|
2005-10-09 01:56:21 +00:00
|
|
|
* @subpackage cake.cake.libs.model.dbo
|
2005-08-21 06:49:02 +00:00
|
|
|
* @since CakePHP v 0.2.9
|
|
|
|
* @version $Revision$
|
|
|
|
* @modifiedby $LastChangedBy$
|
|
|
|
* @lastmodified $Date$
|
|
|
|
* @license http://www.opensource.org/licenses/mit-license.php The MIT License
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Enter description here...
|
|
|
|
*
|
|
|
|
*/
|
2006-01-12 02:10:47 +00:00
|
|
|
if(!class_exists('Object'))
|
|
|
|
{
|
|
|
|
uses('object');
|
|
|
|
}
|
2005-06-23 13:59:02 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Purpose: DBO/ADO
|
2006-01-12 02:10:47 +00:00
|
|
|
*
|
|
|
|
* Description:
|
2005-08-21 06:49:02 +00:00
|
|
|
* A SQL functions wrapper. Provides ability to get results as arrays
|
2005-06-23 13:59:02 +00:00
|
|
|
* and query logging (with execution time).
|
|
|
|
*
|
|
|
|
* Example usage:
|
|
|
|
*
|
|
|
|
* <code>
|
|
|
|
* require_once('dbo_mysql.php'); // or 'dbo_postgres.php'
|
|
|
|
*
|
|
|
|
* // create and connect the object
|
|
|
|
* $db = new DBO_MySQL(array( // or 'DBO_Postgres'
|
|
|
|
* 'host'=>'localhost',
|
|
|
|
* 'login'=>'username',
|
|
|
|
* 'password'=>'password',
|
|
|
|
* 'database'=>'database'));
|
|
|
|
*
|
|
|
|
* // read the whole query result array (of rows)
|
|
|
|
* $all_rows = $db->all("SELECT a,b,c FROM table");
|
|
|
|
*
|
|
|
|
* // read the first row with debugging on
|
|
|
|
* $first_row_only = $db->one("SELECT a,b,c FROM table WHERE a=1", TRUE);
|
|
|
|
*
|
|
|
|
* // emulate the usual way of reading query results
|
2006-01-12 02:10:47 +00:00
|
|
|
* if ($db->query("SELECT a,b,c FROM table"))
|
2005-12-27 03:33:44 +00:00
|
|
|
* {
|
2006-01-12 02:10:47 +00:00
|
|
|
* while ( $row = $db->farr() )
|
2005-12-27 03:33:44 +00:00
|
|
|
* {
|
|
|
|
* print $row['a'].$row['b'].$row['c'];
|
|
|
|
* }
|
2005-06-23 13:59:02 +00:00
|
|
|
* }
|
|
|
|
*
|
|
|
|
* // show a log of all queries, sorted by execution time
|
|
|
|
* $db->showLog(TRUE);
|
|
|
|
* </code>
|
|
|
|
*
|
2005-08-21 06:49:02 +00:00
|
|
|
* @package cake
|
2005-10-09 01:56:21 +00:00
|
|
|
* @subpackage cake.cake.libs.model.dbo
|
2005-08-21 06:49:02 +00:00
|
|
|
* @since CakePHP v 0.2.9
|
2005-06-23 13:59:02 +00:00
|
|
|
*/
|
|
|
|
class DBO extends Object
|
|
|
|
{
|
|
|
|
|
2005-07-10 05:08:19 +00:00
|
|
|
/**
|
|
|
|
* Are we connected to the database?
|
|
|
|
*
|
|
|
|
* @var boolean
|
|
|
|
* @access public
|
|
|
|
*/
|
|
|
|
var $connected=FALSE;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Connection configuration.
|
|
|
|
*
|
|
|
|
* @var array
|
|
|
|
* @access public
|
|
|
|
*/
|
|
|
|
var $config=FALSE;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Enter description here...
|
|
|
|
*
|
|
|
|
* @var boolean
|
|
|
|
* @access public
|
|
|
|
*/
|
|
|
|
var $debug=FALSE;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Enter description here...
|
|
|
|
*
|
|
|
|
* @var boolean
|
|
|
|
* @access public
|
|
|
|
*/
|
|
|
|
var $fullDebug=FALSE;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Enter description here...
|
|
|
|
*
|
|
|
|
* @var unknown_type
|
|
|
|
* @access public
|
|
|
|
*/
|
|
|
|
var $error=NULL;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* String to hold how many rows were affected by the last SQL operation.
|
|
|
|
*
|
|
|
|
* @var unknown_type
|
|
|
|
* @access public
|
|
|
|
*/
|
|
|
|
var $affected=NULL;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Number of rows in current resultset
|
|
|
|
*
|
|
|
|
* @var int
|
|
|
|
* @access public
|
|
|
|
*/
|
|
|
|
var $numRows=NULL;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Time the last query took
|
|
|
|
*
|
|
|
|
* @var unknown_type
|
|
|
|
* @access public
|
|
|
|
*/
|
|
|
|
var $took=NULL;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Enter description here...
|
|
|
|
*
|
|
|
|
* @var unknown_type
|
|
|
|
* @access private
|
|
|
|
*/
|
|
|
|
var $_conn=NULL;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Enter description here...
|
|
|
|
*
|
|
|
|
* @var unknown_type
|
|
|
|
* @access private
|
|
|
|
*/
|
|
|
|
var $_result=NULL;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Queries count.
|
|
|
|
*
|
|
|
|
* @var unknown_type
|
|
|
|
* @access private
|
|
|
|
*/
|
|
|
|
var $_queriesCnt=0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Total duration of all queries.
|
|
|
|
*
|
|
|
|
* @var unknown_type
|
|
|
|
* @access private
|
|
|
|
*/
|
|
|
|
var $_queriesTime=NULL;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Enter description here...
|
|
|
|
*
|
|
|
|
* @var unknown_type
|
|
|
|
* @access private
|
|
|
|
*/
|
|
|
|
var $_queriesLog=array();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Maximum number of items in query log, to prevent query log taking over
|
2006-01-12 02:10:47 +00:00
|
|
|
* too much memory on large amounts of queries -- I we've had problems at
|
2005-07-10 05:08:19 +00:00
|
|
|
* >6000 queries on one system.
|
|
|
|
*
|
|
|
|
* @var int Maximum number of queries in the queries log.
|
|
|
|
* @access private
|
|
|
|
*/
|
|
|
|
var $_queriesLogMax=200;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2006-01-12 02:10:47 +00:00
|
|
|
* Constructor. Sets the level of debug for dbo (fullDebug or debug).
|
2005-07-10 05:08:19 +00:00
|
|
|
*
|
|
|
|
* @param array $config
|
|
|
|
* @return unknown
|
|
|
|
*/
|
|
|
|
function __construct($config=NULL)
|
|
|
|
{
|
|
|
|
$this->debug = DEBUG > 0;
|
|
|
|
$this->fullDebug = DEBUG > 1;
|
|
|
|
parent::__construct();
|
|
|
|
return $this->connect($config);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Destructor. Closes connection to the database.
|
|
|
|
*
|
|
|
|
*/
|
2005-12-24 07:56:48 +00:00
|
|
|
function __destruct()
|
2005-07-10 05:08:19 +00:00
|
|
|
{
|
|
|
|
$this->close();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a string with a USE [databasename] SQL statement.
|
|
|
|
*
|
|
|
|
* @param string $db_name Name of database to use
|
|
|
|
* @return unknown Result of the query
|
|
|
|
*/
|
|
|
|
function useDb($db_name)
|
|
|
|
{
|
|
|
|
return $this->query("USE {$db_name}");
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Disconnects database, kills the connection and says the connection is closed, and if DEBUG is turned on, the log for this object is shown.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
function close ()
|
|
|
|
{
|
|
|
|
if ($this->fullDebug) $this->showLog();
|
|
|
|
$this->disconnect();
|
|
|
|
$this->_conn = NULL;
|
|
|
|
$this->connected = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Prepares a value, or an array of values for database queries by quoting and escaping them.
|
|
|
|
*
|
|
|
|
* @param mixed $data A value or an array of values to prepare.
|
|
|
|
* @return mixed Prepared value or array of values.
|
|
|
|
*/
|
|
|
|
function prepare ($data)
|
|
|
|
{
|
|
|
|
if (is_array($data))
|
|
|
|
{
|
|
|
|
$out = null;
|
|
|
|
foreach ($data as $key=>$item)
|
|
|
|
{
|
|
|
|
$out[$key] = $this->prepareValue($item);
|
|
|
|
}
|
|
|
|
return $out;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return $this->prepareValue($data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function tables()
|
|
|
|
{
|
|
|
|
return array_map('strtolower', $this->tablesList());
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Executes given SQL statement.
|
|
|
|
*
|
|
|
|
* @param string $sql SQL statement
|
|
|
|
* @return unknown
|
|
|
|
*/
|
|
|
|
function rawQuery ($sql)
|
|
|
|
{
|
|
|
|
$this->took = $this->error = $this->numRows = false;
|
|
|
|
return $this->execute($sql);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2006-01-12 02:10:47 +00:00
|
|
|
* Queries the database with given SQL statement, and obtains some metadata about the result
|
|
|
|
* (rows affected, timing, any errors, number of rows in resultset). The query is also logged.
|
2005-07-10 05:08:19 +00:00
|
|
|
* If DEBUG is set, the log is shown all the time, else it is only shown on errors.
|
|
|
|
*
|
|
|
|
* @param string $sql
|
|
|
|
* @return unknown
|
|
|
|
*/
|
|
|
|
function query($sql)
|
|
|
|
{
|
|
|
|
$t = getMicrotime();
|
|
|
|
$this->_result = $this->execute($sql);
|
|
|
|
$this->affected = $this->lastAffected();
|
|
|
|
$this->took = round((getMicrotime()-$t)*1000, 0);
|
|
|
|
$this->error = $this->lastError();
|
|
|
|
$this->numRows = $this->lastNumRows($this->_result);
|
|
|
|
$this->logQuery($sql);
|
|
|
|
if (($this->debug && $this->error) || ($this->fullDebug))
|
|
|
|
$this->showQuery($sql);
|
|
|
|
|
|
|
|
return $this->error? false: $this->_result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a single row of results from the _last_ SQL query.
|
|
|
|
*
|
|
|
|
* @param resource $res
|
|
|
|
* @return array A single row of results
|
|
|
|
*/
|
|
|
|
function farr ($assoc=false)
|
|
|
|
{
|
|
|
|
if ($assoc === false)
|
|
|
|
{
|
|
|
|
return $this->fetchRow();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return $this->fetchRow($assoc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a single row of results for a _given_ SQL query.
|
|
|
|
*
|
|
|
|
* @param string $sql SQL statement
|
|
|
|
* @return array A single row of results
|
|
|
|
*/
|
|
|
|
function one ($sql)
|
|
|
|
{
|
|
|
|
return $this->query($sql)? $this->farr(): false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2006-01-12 02:10:47 +00:00
|
|
|
* Returns an array of all result rows for a given SQL query.
|
2005-07-10 05:08:19 +00:00
|
|
|
* Returns false if no rows matched.
|
|
|
|
*
|
|
|
|
* @param string $sql SQL statement
|
|
|
|
* @return array Array of resultset rows, or false if no rows matched
|
|
|
|
*/
|
|
|
|
function all ($sql)
|
|
|
|
{
|
|
|
|
if($this->query($sql))
|
|
|
|
{
|
|
|
|
$out=array();
|
|
|
|
while ($item = $this->farr(null, true))
|
|
|
|
{
|
|
|
|
$out[] = $item;
|
|
|
|
}
|
|
|
|
return $out;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a single field of the first of query results for a given SQL query, or false if empty.
|
|
|
|
*
|
|
|
|
* @param string $name Name of the field
|
|
|
|
* @param string $sql SQL query
|
|
|
|
* @return unknown
|
|
|
|
*/
|
|
|
|
function field ($name, $sql)
|
|
|
|
{
|
|
|
|
$data = $this->one($sql);
|
|
|
|
return empty($data[$name])? false: $data[$name];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks if the specified table contains any record matching specified SQL
|
|
|
|
*
|
|
|
|
* @param string $table Name of table to look in
|
|
|
|
* @param string $sql SQL WHERE clause (condition only, not the "WHERE" part)
|
|
|
|
* @return boolean True if the table has a matching record, else false
|
|
|
|
*/
|
|
|
|
function hasAny($table, $sql)
|
|
|
|
{
|
|
|
|
$out = $this->one("SELECT COUNT(*) AS count FROM {$table}".($sql? " WHERE {$sql}":""));
|
2005-07-10 07:49:30 +00:00
|
|
|
return is_array($out)? $out[0]['count']: false;
|
2005-07-10 05:08:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks if it's connected to the database
|
|
|
|
*
|
|
|
|
* @return boolean True if the database is connected, else false
|
|
|
|
*/
|
|
|
|
function isConnected()
|
|
|
|
{
|
|
|
|
return $this->connected;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Outputs the contents of the log.
|
|
|
|
*
|
|
|
|
* @param boolean $sorted
|
|
|
|
*/
|
|
|
|
function showLog($sorted=false)
|
|
|
|
{
|
|
|
|
$log = $sorted?
|
|
|
|
sortByKey($this->_queriesLog, 'took', 'desc', SORT_NUMERIC):
|
|
|
|
$this->_queriesLog;
|
|
|
|
|
|
|
|
print("<table border=1>\n<tr><th colspan=7>{$this->_queriesCnt} queries took {$this->_queriesTime} ms</th></tr>\n");
|
|
|
|
print("<tr><td>Nr</td><td>Query</td><td>Error</td><td>Affected</td><td>Num. rows</td><td>Took (ms)</td></tr>\n");
|
|
|
|
|
|
|
|
foreach($log AS $k=>$i)
|
|
|
|
{
|
|
|
|
print("<tr><td>".($k+1)."</td><td>{$i['query']}</td><td>{$i['error']}</td><td align='right'>{$i['affected']}</td><td align='right'>{$i['numRows']}</td><td align='right'>{$i['took']}</td></tr>\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
print("</table>\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Log given SQL query.
|
|
|
|
*
|
|
|
|
* @param string $sql SQL statement
|
|
|
|
*/
|
|
|
|
function logQuery($sql)
|
|
|
|
{
|
|
|
|
$this->_queriesCnt++;
|
|
|
|
$this->_queriesTime += $this->took;
|
|
|
|
|
|
|
|
$this->_queriesLog[] = array(
|
|
|
|
'query'=>$sql,
|
|
|
|
'error'=>$this->error,
|
|
|
|
'affected'=>$this->affected,
|
|
|
|
'numRows'=>$this->numRows,
|
|
|
|
'took'=>$this->took
|
|
|
|
);
|
|
|
|
|
|
|
|
if (count($this->_queriesLog) > $this->_queriesLogMax)
|
|
|
|
{
|
|
|
|
array_pop($this->_queriesLog);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($this->error)
|
|
|
|
return false; // shouldn't we be logging errors somehow?
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2006-01-12 02:10:47 +00:00
|
|
|
* Output information about an SQL query. The SQL statement, number of rows in resultset,
|
2005-07-10 05:08:19 +00:00
|
|
|
* and execution time in microseconds. If the query fails, and error is output instead.
|
|
|
|
*
|
|
|
|
* @param string $sql
|
|
|
|
*/
|
|
|
|
function showQuery($sql)
|
|
|
|
{
|
|
|
|
$error = $this->error;
|
|
|
|
|
|
|
|
if (strlen($sql)>200 && !$this->fullDebug)
|
|
|
|
{
|
|
|
|
$sql = substr($sql, 0, 200) .'[...]';
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($this->debug || $error)
|
|
|
|
{
|
|
|
|
print("<p style=\"text-align:left\"><b>Query:</b> {$sql} <small>[Aff:{$this->affected} Num:{$this->numRows} Took:{$this->took}ms]</small>");
|
|
|
|
if($error)
|
|
|
|
{
|
|
|
|
print("<br /><span style=\"color:Red;text-align:left\"><b>ERROR:</b> {$this->error}</span>");
|
|
|
|
}
|
|
|
|
print('</p>');
|
|
|
|
}
|
|
|
|
}
|
2005-06-23 13:59:02 +00:00
|
|
|
}
|
|
|
|
|
2005-05-15 21:41:38 +00:00
|
|
|
?>
|