<?php
/*
**	$Id$
**
**	ITools - the Internet Tools Library
**
**	Copyright (C) 1995-2003 by the ITools Authors.
**	This program is free software; you can redistribute it and/or
**	modify it under the terms of either the GNU General Public License
**	or the GNU Lesser General Public License, as published by the Free
**	Software Foundation. See http://www.gnu.org/licenses/ for details.
**
**	it_db.class - Generic Database class, currently using mysql.
**
**	This tries to be as efficient as possible by maintaining
**	persistent database connections.
*/


/**
 * Functions to handle SQL databases
 * @see it_db_table, it_db_record
 */
class it_db
{
	/* public */
	var	$host;			/* Database host */
	var	$host_update='';	/* Optional database host for updates */
	var	$name;			/* Name of database */
	var	$numtables;		/* Number of tables in databasee or 0 if not known */
	var	$tablenames = array();	/* Array(0..$numtables) of table names */

	/* private */
	var	$link;			/* MySQL Link Identifier */
	var	$username;		/* MySQL username (if $updatehost) */
	var	$password;		/* MySQL password (if $updatehost) */

/**
 * Constructor: connect to MySQL server and select database
 * @param $databasename name of the database to select or empty for default
 * @param $username username to connect with
 * @param $password password to connect with
 * @param $host Optional name of the host to connect to
 * @param $host_update Optional name of the host for updates (writes)
 */
function it_db($databasename, $username, $password, $host='localhost', $host_update='')
{
	if (empty($databasename))
		$databasename = strtr(ereg_replace('^www.', '', strtolower(ereg_replace(':.*$', '', getenv('HTTP_HOST')))), '.', '_');

	if ($this->link = @mysql_connect($host, $username, $password, true))
	{
		if (mysql_select_db($databasename, $this->link))
		{
			$this->host = $host;
			$this->name = $databasename;
		}
		else
			internal_error("Can't select database \"$databasename\" on host \"$host\".");
	}
	else
		internal_error("Can't connect to database server \"$host\" as user \"$username\".");

	if ($host_update)
	{
		$this->host_update = $host_update;
		$this->username = $username;
		$this->password = $password;
	}
}


/**
 * Perform an SQL query.
 * @see ::safe_sql_query, mysql_query
 * @param $sql SQL query
 * @return SQL handle or false in case of failure
 */
function sql_query($sql)
{
	debug("it_db::sql_query($sql) on {$this->host}", 5);

	/*
	** If we have a special update host, and an update operation is to be
	** performed, we switch to this host. And we stay forever and ever and ever...
	*/
	if ($this->host_update && eregi('^(UPDATE|INSERT|REPLACE|DELETE|ALTER) ', $sql))
	{
		/*debug('it_db::sql_query(): switching to update host "'.$this->host_update.'"', 3); */
		if ($this->link = @mysql_connect($this->host_update, $this->username, $this->password, true))
		{
			if (mysql_select_db($this->name, $this->link))
				$this->host = $this->host_update;
			else
				internal_error('Error selecting update database "'.$this->name.'" on host "'.$this->host_update.'".');

			$this->host_update='';
		}
		else
			internal_error('Error connecting to update database server "'.$this->host_update.'" as user "'.$this->username.'".');
	}
	
	return mysql_query($sql, $this->link);
}


/**
 * Perform an SQL query. If the query fails, issue an error message
 * and terminate program execution. No matching rows does not mean failure.
 * @see ::sql_query, mysql_query
 * @param $sql SQL query
 * @return SQL handle
 */
function safe_sql_query($sql)
{
	/* debug("it_db::safe_sql_query($sql)", 4); */
	if ($result = $this->sql_query($sql))
		return $result;
	else
	{
		if ($this->errno() == 1062)	/* Duplicate entry */
			return 0;

		fail('SQL-Query db "'.$this->name.'" host "'.$this->host."\" failed: \"$sql\":<br>".$this->error().' ('.$this->errno().')');
	}
}


/**
 * Free resources used by SQL handle
 * @see mysql_free_result
 * @param $handle SQL handle
 * @return 
 */
function free($handle)
{
	return mysql_free_result($handle);
}


/**
 * Fetch a row as an array
 * @see mysql_fetch_array
 * @param $handle SQL handle
 * @return numeric & associative array with contents of table row
 */
function fetch_array($handle)
{
	return mysql_fetch_array($handle);
}


/**
 * Fetch a row as an associative array
 * @see mysql_fetch_array
 * @param $handle SQL handle
 * @return associative array with contents of table row
 */
function fetch_assoc($handle)
{
	return mysql_fetch_assoc($handle);
}


/**
 * Return number of rows of a query
 * @see mysql_num_rows
 * @param $handle SQL handle
 * @return number of rows the query returned
 */
function num_rows($handle)
{
	return mysql_num_rows($handle);
}


/**
 * Return number of found rows of a limited query that had SQL_COUNT_FOUND_ROWS set
 * @return number of rows the query would have returned without LIMIT
 */
function found_rows()
{
	list($count) = mysql_fetch_row($this->safe_sql_query('SELECT FOUND_ROWS()'));
	return intval($count);
}


/* Internal: get information about tables */
function _get_table_info()
{
	if ($this->numtables > 0) /* Already done! */
		return;

	if(($tables = mysql_list_tables($this->name,$this->link)) >= 0)
	{
		$this->numtables = mysql_numrows($tables);
		for ($i=0; $i < $this->numtables; ++$i)
		{
			$name = mysql_tablename($tables, $i);
			$this->tablenames[$i] = $name;
		}
	}
	else internal_error("mysql_list_tables($this->name,$this->link) failed.");
}


/**
 * Return a list of all table names of this database
 * @return array with tablenames of this Database
 */
function table_names()
{
	$this->_get_table_info();
	return $this->tablenames;
}


/**
 * Return number of tables in this database
 */
function num_tables()
{
	$this->_get_table_info();
	return $this->numtables;
}


/**
 * Return last error number
 * @see ::sql_query, ::safe_sql_query, mysql_errno
 * @return last mySQL error number
 */
function errno()
{
	return mysql_errno($this->link);
}


/**
 * Return last error string
 * @see ::sql_query, ::safe_sql_query, mysql_error
 * @return last mySQL error message
 */
function error()
{
	return mysql_error($this->link);
}

} /* End class it_db */
?>