<?php
require_once($INC . "/log.inc.php");
require_once($INC . "/prof.inc.php");
if (!function_exists("pg_connect"))
die("FATAL: php PostgreSQL is not installed!");
$rg_sql_conn = array();
$rg_sql_error = "";
/*
* Set error string
*/
function rg_sql_set_error($str)
{
global $rg_sql_error;
$rg_sql_error = $str;
rg_log($str);
}
function rg_sql_error()
{
global $rg_sql_error;
return $rg_sql_error;
}
/*
* Set application name to be able to identify the scripts
*/
$rg_sql_app = "rg-unk";
function rg_sql_app($name)
{
global $rg_sql_app;
$rg_sql_app = $name;
}
/*
* Connect to database
*/
function rg_sql_open_nodelay($h)
{
global $php_errormsg;
global $rg_sql_debug;
global $rg_sql_conn;
rg_prof_start("sql_open_nodelay");
$ret = FALSE;
while (1) {
if (!isset($rg_sql_conn[$h])) {
rg_internal_error("Handler $h not present!");
break;
}
if (isset($rg_sql_conn[$h]['db'])) {
$ret = $rg_sql_conn[$h]['db'];
break;
}
putenv('PGAPPNAME=' . $rg_sql_conn[$h]['app']);
$str = $rg_sql_conn[$h]['str'];
if ($rg_sql_debug > 0)
rg_log("DB: opening [$str]...");
rg_prof_set(array("db_conn" => 1));
$_s = microtime(TRUE);
$tries = 0;
while (1) {
$db = @pg_pconnect($str);
if ($db !== FALSE) {
// reconnect if needed
$x = @pg_ping($db);
if ($x === TRUE)
break;
}
if ($tries == 0)
rg_log('Cannot connect to db. Keep trying...');
$tries++;
if ($tries > 30) {
$db = FALSE;
break;
}
}
$diff = intval((microtime(TRUE) - $_s) * 1000);
rg_prof_set(array("db_c_ms" => $diff));
if ($db === FALSE) {
$err = 'cannot connect to database';
rg_sql_set_error($err);
rg_internal_error($err);
rg_prof_set(array('db_conn_errors' => 1));
break;
}
$rg_sql_conn[$h]['db'] = $db;
$ret = $db;
break;
}
rg_prof_end("sql_open_nodelay");
return $ret;
}
/*
* Prepare to connect to database (delayed connection).
* Returns a special handler.
*/
function rg_sql_open($str)
{
global $rg_sql_conn;
global $rg_sql_app;
$free_index = count($rg_sql_conn);
$rg_sql_conn[$free_index] = array();
$rg_sql_conn[$free_index]['str'] = $str;
$rg_sql_conn[$free_index]['app'] = $rg_sql_app;
//rg_log("Delay connection to [$str], index $free_index.");
return $free_index;
}
/*
* Escaping
*/
function rg_sql_escape($h, $str)
{
$db = rg_sql_open_nodelay($h);
if ($db === FALSE)
return FALSE;
return pg_escape_string($db, $str);
}
/*
* Helper for sql_query and sql_query_params
*/
function rg_sql_query0($db, $sql, $res, $_s)
{
global $rg_sql_debug;
while (1) {
if ($res === FALSE) {
$err = "$sql: " . @pg_last_error($db);
rg_sql_set_error($err);
rg_internal_error($err);
rg_prof_set(array('qerrors' => 1));
// reconnect if needed
@pg_ping($db);
break;
}
$diff = sprintf("%u", (microtime(TRUE) - $_s) * 1000);
$rows = rg_sql_num_rows($res);
if ($rows == 0)
$arows = rg_sql_affected_rows($res);
else
$arows = 0;
if ($rg_sql_debug > 0)
rg_log("DB: Took " . $diff . "ms, $rows row(s), $arows affected");
rg_prof_set(array("q" => 1,
"rows" => $rows,
"arows" => $arows,
"q_ms" => $diff));
break;
}
return $res;
}
/*
* Do a query
*/
function rg_sql_query($h, $sql)
{
global $rg_sql_debug;
if ($rg_sql_debug > 0)
rg_log_enter("sql_query: sql=$sql");
$ret = FALSE;
while (1) {
$db = rg_sql_open_nodelay($h);
if ($db === FALSE)
break;
$_s = microtime(TRUE);
$res = @pg_query($db, $sql);
$ret = rg_sql_query0($db, $sql, $res, $_s);
break;
}
if ($rg_sql_debug > 0)
rg_log_exit();
return $ret;
}
/*
* Queries using params
* @params - array of fields -> values
* Examples: $params = array("id" => "1", "name" = "bau")
* $sql = "UPDATE x SET name = @@name@@ WHERE id = @@id@@ AND @@name@@ = @@name@@"
* $sql2 = "UPDATE x SET name = $1 WHERE id = $2 AND name = $1"
*/
function rg_sql_query_params($h, $sql, $params)
{
global $rg_sql_debug;
if ($rg_sql_debug > 0)
rg_log_enter("query_params: running [$sql] with [" . rg_array2string($params) . "]");
$ret = FALSE;
while (1) {
$db = rg_sql_open_nodelay($h);
if ($db === FALSE)
break;
// Transforms @params into $x system
$params2 = array();
$i = 1;
foreach ($params as $k => $v) {
$what = '@@' . $k . '@@';
$value = '$' . $i;
$sql = str_replace($what, $value, $sql, $count);
//rg_log("rg_sql_query_params: k=[$k] value=$value count=$count");
if ($count > 0) {
$params2[] = $v;
$i++;
}
}
//rg_log("new sql: $sql");
//rg_log("params2: " . rg_array2string($params2));
$_s = microtime(TRUE);
$res = @pg_query_params($db, $sql, $params2);
$ret = rg_sql_query0($db, $sql, $res, $_s);
break;
}
if ($rg_sql_debug > 0)
rg_log_exit();
return $ret;
}
/*
* Close database
*/
function rg_sql_close($h)
{
// TODO: why should I connect before close?!
$db = rg_sql_open_nodelay($h);
if ($db === FALSE)
return FALSE;
return pg_close($db);
}
/*
* Free results
*/
function rg_sql_free_result($res)
{
if (!is_resource($res)) {
rg_internal_error("res is not resource!");
return;
}
pg_free_result($res);
}
/*
* Returns a row as an associated array
*/
function rg_sql_fetch_array($res)
{
if (!is_resource($res)) {
rg_internal_error("res is not resource!");
return FALSE;
}
return pg_fetch_assoc($res);
}
function rg_sql_last_id($h)
{
$sql = "SELECT lastval() AS id";
$res = rg_sql_query($h, $sql);
if ($res === FALSE)
return FALSE;
$row = rg_sql_fetch_array($res);
rg_sql_free_result($res);
return $row['id'];
}
function rg_sql_num_rows($res)
{
if (!is_resource($res)) {
rg_internal_error("res is not resource!");
return FALSE;
}
return pg_num_rows($res);
}
function rg_sql_affected_rows($res)
{
if (!is_resource($res)) {
rg_internal_error("res is not resource!");
return FALSE;
}
return pg_affected_rows($res);
}
function rg_sql_begin($h)
{
$res = rg_sql_query($h, "BEGIN");
if ($res === FALSE)
return FALSE;
rg_sql_free_result($res);
return TRUE;
}
function rg_sql_commit($h)
{
$res = rg_sql_query($h, "COMMIT");
if ($res === FALSE)
return FALSE;
rg_sql_free_result($res);
return TRUE;
}
function rg_sql_rollback($h)
{
$res = rg_sql_query($h, "ROLLBACK");
if ($res === FALSE)
return FALSE;
rg_sql_free_result($res);
return TRUE;
}
/*
* Test if a table exists
* Returns FALSE on error, 0 if does not exists, 1 if exists
*/
function rg_sql_rel_exists($db, $rel)
{
$sql = "SELECT 1 FROM pg_class"
. " WHERE relname = '" . $rel . "'";
$res = rg_sql_query($db, $sql);
if ($res === FALSE)
return FALSE;
$rows = rg_sql_num_rows($res);
rg_sql_free_result($res);
return $rows;
}
/*
* Returns the fileds names of a table
*/
function rg_sql_fields($db, $table)
{
$params = array('table' => $table);
$sql = 'SELECT column_name FROM information_schema.columns'
. ' WHERE table_name = @@table@@';
$res = rg_sql_query_params($db, $sql, $params);
if ($res === FALSE)
return FALSE;
$ret = array();
while (($row = rg_sql_fetch_array($res))) {
$f = $row['column_name'];
$ret[$f] = 1;
}
rg_sql_free_result($res);
return $ret;
}
?>