<?php
/* Load functions for preferred database.
*
* Written by: Chris Studholme
* Copyright: GPL (http://www.fsf.org/copyleft/gpl.html)
* $Id: db.php,v 1.17 2003/04/18 23:52:02 cstudhol Exp $
*/
/* Base class for database reset sets. This class and db_connection form
* the bases of the database abstraction layer.
*/
class db_resultset {
// array types
var $NUM=1;
var $ASSOC=2;
var $BOTH=3;
// number of rows in result set
function num_rows() {
die("db_resultset->num_rows() not implemented!");
}
// number of fields in result set
function num_fields() {
die("db_resultset->num_fields() not implemented!");
}
// last error message related to this resultset
function last_error() {
die("db_resultset->last_error() not implemented!");
}
// close resultset and free memory
function close() {
}
// return field name
function field_name($index) {
die("db_resultset->field_name() not implemented!");
}
// fetch a specific row and column from the result set
function result($row,$field) {
die("db_resultset->result() not implemented!");
}
// reset to the first row in the result set
function reset() {
die("db_resultset->reset() not implemented!");
}
// return the next row as an array or false if there are no more rows
function fetch_array($result_type=false) {
die("db_resultset->fetch_array() not implemented!");
}
// return the next row as an array or false if there are no more rows
function fetch_assoc() {
return $this->fetch_array($this->ASSOC);
}
// return the next row as an array or false if there are no more rows
function fetch_row() {
return $this->fetch_array($this->NUM);
}
/* Function to return entire table as an array.
* If $key is a column name, the array will be associative with that
* column as key.
* If $value is a column name, only that column will be stored in array.
* If $multi is true, each element of the array will be a non-associative
* array or rows.
*/
function fetch_table($key=false,$value=false,$multi=false) {
$result = array();
while ($arr=$this->fetch_assoc()) {
$v = $value ? $arr[$value] : $arr;
if (!$key)
$result[] = $v;
else if (!$multi)
$result[$arr[$key]] = $v;
else
$result[$arr[$key]][] = $v;
}
return $result;
}
}
/* Reset set for table represented as an array.
*/
class db_resultset_cache extends db_resultset {
var $table; // simple array of associative arrays
var $row; // current row
// constructor: new resultset
function db_resultset_cache($table) {
if (is_string($table))
$this->table = unserialize($table);
else
$this->table = $table;
$this->row = 0;
}
// number of rows in result set
function num_rows() {
return count($this->table);
}
// number of fields in result set
function num_fields() {
return count($this->table[0]);
}
// last error message related to this resultset
function last_error() {
return false;
}
// return field name
function field_name($index) {
reset($this->table[0]);
$i=0;
while (list($field,$data)=each($this->table[0])) {
if ($index==$i)
return $field;
++$i;
}
return false;
}
// fetch a specific row and column from the result set
function result($row,$field) {
if (0<=$row && $row<count($this->table))
return $table[$row][$field];
return false;
}
// reset to the first row in the result set
function reset() {
$this->row=0;
}
// return the next row as an array or false if there are no more rows
function fetch_array($result_type=false) {
if ($this->row>=count($this->table))
return false;
switch ($result_type) {
case $this->ASSOC:
$result = $this->table[$this->row];
break;
case $this->BOTH:
$result = $this->table[$this->row];
default: // $this->NUM
reset($this->table[$this->row]);
$i=0;
while (list($field,$data)=each($this->table[$this->row]))
$result[$i++] = $data;
}
++$this->row;
return $result;
}
}
/* Base class for database connections. This class and db_resultset form
* the bases of the database abstraction layer.
*/
class db_connection {
var $queries = false;
var $error_function = false; // prototype: error_function(object,query);
// create connection to database
function connect($connection_string) {
die("db_connection->connect() not implemented!");
}
// create persistent connection
function pconnect($connection_string) {
die("db_connection->pconnect() not implemented!");
}
// close the connection
function close() {
die("db_connection->close() not implemented!");
}
// get last error message from connection
function last_error() {
die("db_connection->last_error() not implemented!");
}
// return database name
function name() {
die("db_connection->name() not implemented!");
}
// execute a database query
// returns a db_result_set object
function query($query,$return_error=false) {
die("db_connection->query() not implemented!");
}
function query_cache($query,$return_error=false) {
global $db_enable_caching;
if (!$db_enable_caching)
return $this->query($query,$return_error);
// check for query in cache
$h = md5($query);
$q = "SELECT * FROM cache WHERE hash='".$h."'";
$result = $this->query($q,$return_error);
if ($result && $arr=$result->fetch_assoc()) {
// query is in cache
return new db_resultset_cache($arr["data"]);
}
// query not in cache, execute and add to cache
$result = $this->query($query,$return_error);
$table = $result->fetch_table();
$result->reset();
$data = $this->quote_string(serialize($table));
$query = $this->sql_insert("cache",
array("hash"=>$this->quote_string($h),
"data"=>$data,
"date_create"=>$this->date_now()));
@$this->query($query,true); // we don't care if this fails
return $result;
}
function clear_cache() {
$query = $this->sql_delete("cache",false);
$this->query($query);
}
// start tracking queries
function track_queries() {
$this->queries = array();
}
// get array of all queries executed on connection thus far
// returns false if queries are not being tracked
function get_queries() {
return $this->queries;
}
// set error function to call when database query fails
function set_error_function($error_function) {
$this->error_function = $error_function;
}
/**** transactions ****/
function transaction_begin() {
return true;
}
function transaction_commit() {
return true;
}
function transaction_rollback() {
return false;
}
/**** simple SQL queries ****/
// SQL INSERT query
function sql_insert($table,$fields) {
reset($fields);
list($columns,$values)=each($fields);
while (list($column,$value)=each($fields)) {
$columns.=",".$column;
$values.=",".$value;
}
return "INSERT INTO ".$table." (".$columns.") VALUES (".$values.")";
}
// SQL UPDATE query
function sql_update($table,$fields,$where) {
reset($fields);
list($column,$value)=each($fields);
$sets = $column."=".$value;
while (list($column,$value)=each($fields))
$sets .= ", ".$column."=".$value;
return "UPDATE ".$table." SET ".$sets." WHERE ".$where;
}
// SQL DELETE query
function sql_delete($table,$where) {
return "DELETE FROM ".$table.($where?" WHERE ".$where:"");
}
/**** SQL feature set ****/
// returns an associative array of features
function sql_features() {
return array("except"=>true, // supports EXCEPT
"subselect_from"=>true, // supports subquery in FROM
"subselect_select"=>true, // supports subquery in SELECT
"subselect_where"=>true, // supports subquery in WHERE
"date_format"=>"YYYY-MM-DD", // format for inputing dates
);
}
/**** methods to help create queries ****/
// sql representing current date/time
function date_now() {
return "now()";
}
// return appropriate date string from UNIX timestamp
// if $quote is true, valid dates are quoted, non-valid dates are returned
// as null,
// if $quote is false, valid dates are not-quoted, non-valid dates are
// returned as false
function date($timestamp,$quote=true) {
if (is_numeric($timestamp))
return date($quote?"'Y-m-d'":"Y-m-d",(int)$timestamp);
return $quote ? "null" : false;
}
// return appropriate date/time string from UNIX timestamp
// if $quote is true, valid dates are quoted, non-valid dates are returned
// as null,
// if $quote is false, valid dates are not-quoted, non-valid dates are
// returned as false
function datetime($timestamp,$quote=true) {
if (is_numeric($timestamp))
return date($quote?"'Y-m-d H:i:s'":"Y-m-d H:i:s",(int)$timestamp);
return $quote ? "null" : false;
}
// $bit should be a number with only one bit set
function bit_set($field,$bit) {
return "(".$field."%".($bit<<1).">=".$bit.")";
}
// $bit should be a number with only one bit set
function bit_unset($field,$bit) {
return "(".$field."%".($bit<<1)."<".$bit.")";
}
/* Quote string for use in an SQL query. If $output_null is true then
* an empty string will be returned as "null" (unquoted of course).
*/
function quote_string($str,$output_null=false) {
$str = strval($str);
if ($output_null&&!$str)
return "null";
return "'".addslashes($str)."'";
}
}
/* Function to report database error:
* - format_error is called to display error
* - any outstanding transaction is rolled back
* - end_body() is called
* - script terminates
*/
function db_error_function(&$conn,$query) {
$strings = get_strings();
format_error($strings["err_db_query"],$strings["err_db_query_long"]);
//echo "Query: ".$query;
$conn->transaction_rollback();
end_body(false);
exit();
}
// database specific classes
require("include/db_".$db_type.".php");
// backwards compatibility:
// returns false if table does not exist
function db_fieldlist(&$conn,$table) {
@$dbresult = $conn->query("SELECT * FROM ".$table." WHERE false",true);
if (!$dbresult)
return false;
$result = array();
for ($i=0; $i<$dbresult->num_fields(); ++$i)
$result[] = $dbresult->field_name($i);
return $result;
}
// read config table
if ($conn) {
@$result = $conn->query("SELECT key,value FROM config",true);
if ($result) {
$new_config = $result->fetch_table("key","value");
$config = array_merge($config,$new_config);
}
else if (!$db_conn_error)
die ("Failed to read 'config' table."); //STRING
}
?>