xaizek / rocketgit (License: AGPLv3+) (since 2018-12-09)
Light and fast Git hosting solution suitable to serve both as a hub or as a personal code storage with its tickets, pull requests, API and much more.
<root> / inc / sql.inc.php (8854a3d1a216c661476153452ffb737cbc11032a) (6,404B) (mode 100644) [raw]
<?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;
		}

		$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 = 30;
		while ($tries > 0) {
			$db = pg_pconnect($str);
			if ($db === FALSE) {
				rg_log("Cannot connect to db. Sleep 1 second and try again.");
				sleep(1);
				$tries--;
				continue;
			}
			break;
		}
		$diff = sprintf("%u", (microtime(TRUE) - $_s) * 1000);
		rg_prof_set(array("db_c_ms" => $diff));
		if ($db === FALSE) {
			rg_sql_set_error('cannot connect to database');
			rg_prof_set(array('db_conn_errors' => 1));
			break;
		}

		rg_log("Connect OK to database.");
		$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
		. " application_name=" . $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) {
			rg_sql_set_error("$sql: " . @pg_last_error($db));
			rg_prof_set(array("qerrors" => 1));
			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)
{
	$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_table_exists($db, $table)
{
	$sql = "SELECT 1 FROM pg_class"
		. " WHERE relname = '" . $table . "'";
	$res = rg_sql_query($db, $sql);
	if ($res === FALSE)
		return FALSE;

	$rows = rg_sql_num_rows($res);
	rg_sql_free_result($res);

	return $rows;
}

?>
Hints

Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/rocketgit

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/rocketgit

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master