134 lines
3 KiB
PHP
134 lines
3 KiB
PHP
|
<?php
|
||
|
|
||
|
class DatabaseError extends RuntimeException { }
|
||
|
|
||
|
final class Database
|
||
|
implements PackageAware
|
||
|
{
|
||
|
|
||
|
private $connection;
|
||
|
private $package;
|
||
|
private $queries = array( );
|
||
|
|
||
|
public function setPackage( Package $package )
|
||
|
{
|
||
|
if ( $this->package !== null ) {
|
||
|
throw new Exception( 'trying to call setPackage() twice' );
|
||
|
}
|
||
|
$this->package = $package;
|
||
|
}
|
||
|
|
||
|
|
||
|
public function query( $query , $prepare = false )
|
||
|
{
|
||
|
if ( ! $this->connection ) {
|
||
|
$this->connect( );
|
||
|
}
|
||
|
if ( ! array_key_exists( $query , $this->queries )
|
||
|
|| ( $prepare && ! $this->queries[ $query ]->prepared( ) ) ) {
|
||
|
$this->queries[ $query ] = new DBQuery( $this->connection , $query , $prepare );
|
||
|
}
|
||
|
return $this->queries[ $query ];
|
||
|
}
|
||
|
|
||
|
public function commit( )
|
||
|
{
|
||
|
if ( ! $this->connection ) {
|
||
|
return;
|
||
|
}
|
||
|
if ( ! @pg_query( 'COMMIT' ) ) {
|
||
|
throw new DatabaseError( 'COMMIT: ' . pg_last_error( ) );
|
||
|
}
|
||
|
exit( 0 );
|
||
|
}
|
||
|
|
||
|
public function connect( )
|
||
|
{
|
||
|
$host = $this->package->config( 'db/host' , 'localhost' );
|
||
|
$port = $this->package->config( 'db/port' );
|
||
|
$name = $this->package->config( 'db/name' , null , true );
|
||
|
$user = $this->package->config( 'db/user' );
|
||
|
$pass = $this->package->config( 'db/password' );
|
||
|
|
||
|
$cString = array( );
|
||
|
$cString[] = "host=$host";
|
||
|
if ( $port !== null ) {
|
||
|
$cString[] = "port=$port";
|
||
|
}
|
||
|
$cString[] = "dbname=$name";
|
||
|
if ( $user !== null ) {
|
||
|
$cString[] = "user=$user";
|
||
|
}
|
||
|
if ( $pass !== null ) {
|
||
|
$cString[] = "password=$pass";
|
||
|
}
|
||
|
|
||
|
$this->connection = pg_connect( join( ' ' , $cString ) );
|
||
|
if ( ! $this->connection ) {
|
||
|
throw new DatabaseError( 'connection failed' );
|
||
|
}
|
||
|
|
||
|
if ( ! @pg_query( $this->connection , 'BEGIN TRANSACTION' ) ) {
|
||
|
throw new DatabaseError( 'BEGIN TRANSACTION: ' . pg_last_error( ) );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
final class DBQuery
|
||
|
{
|
||
|
private static $lastStatementID = 0;
|
||
|
|
||
|
private $connection;
|
||
|
private $query;
|
||
|
private $statement;
|
||
|
|
||
|
|
||
|
public function __construct( $connection , $query , $prepare = false )
|
||
|
{
|
||
|
$this->connection = $connection;
|
||
|
$this->query = $query;
|
||
|
if ( $prepare ) {
|
||
|
$this->statement = 'prep_stmt_' . ( ++ DBQuery::$lastStatementID );
|
||
|
if ( ! pg_prepare( $connection , $this->statement , $query ) ) {
|
||
|
throw new Exception( "unable to prepare statement '$query': " . pg_last_error( ) );
|
||
|
}
|
||
|
} else {
|
||
|
$this->statement = null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public function __destruct( )
|
||
|
{
|
||
|
if ( $this->statement !== null ) {
|
||
|
if ( ! pg_query( 'DEALLOCATE ' . $this->statement ) ) {
|
||
|
throw new Exception( "unable to deallocate statement: " . pg_last_error( ) );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
public function execute( )
|
||
|
{
|
||
|
$arguments = func_get_args( );
|
||
|
$result = array( );
|
||
|
|
||
|
if ( $this->statement !== null ) {
|
||
|
$pgResult = pg_execute( $this->connection , $this->statement , $arguments );
|
||
|
} else {
|
||
|
$pgResult = pg_query_params( $this->connection , $this->query , $arguments );
|
||
|
}
|
||
|
|
||
|
if ( ! $pgResult ) {
|
||
|
throw new Exception( "query \"{$this->query}\" failed: " . pg_last_error( ) );
|
||
|
}
|
||
|
|
||
|
while ( $row = pg_fetch_object( $pgResult ) ) {
|
||
|
array_push( $result , $row );
|
||
|
}
|
||
|
pg_free_result( $pgResult );
|
||
|
|
||
|
return $result;
|
||
|
}
|
||
|
}
|