Index: /trunk/htdocs2/GreenZone/Utils/OCIDB.php
===================================================================
--- /trunk/htdocs2/GreenZone/Utils/OCIDB.php	(revision 440)
+++ /trunk/htdocs2/GreenZone/Utils/OCIDB.php	(revision 440)
@@ -0,0 +1,77 @@
+<?php
+
+/// Written by David Smith
+/// for CSIRO ATNF (c) 2008
+///
+/// This class inherits from the SQLDatabase class and changes some of the basic
+/// functions for interfacing to the database.
+
+
+
+require_once GREEN_ZONE_DIR . 'Utils/SQLDatabase.php';
+
+
+
+class OCIDBException extends SQLDBException
+{
+};
+
+class OCIDB extends SQLDatabase
+{
+  // PUBLIC
+      
+  public function __construct()
+  {
+    parent::__construct();
+  }
+  
+  public function __destruct()
+  {
+    parent::__destruct();
+  }
+  
+  // PRIVATE
+  
+  /// Connect to the database using the details given, throw an exception if we
+  /// failed.
+
+  private function priv_Connect( $target_user, $target_password, $target_dsn )
+  {
+    $conn = oci_connect( $target_user, $target_password, $target_dsn );
+    if( $conn !== false )
+      $this->link = $conn;
+    else
+      throw new OCIDBException( 'Failed to connect to OCI database', 'OCIDB::connect' );
+  }
+  
+  /// Perform the query given and store the results in $this->last_dataset.
+
+  private function priv_DoQuery( $sql )
+  {
+    if( $this->connection == null )
+      throw new OCIDBException( 'Attempt to perform query without connection', 'OCIDB::DoQuery' );
+    
+    $query = oci_parse( $this->link, sql );
+    
+    $res = oci_execute( $query, OCI_DEFAULT );
+    if( $res !== false )
+    {
+      $this->last_dataset = Array();
+      $this->last_dataset_index = 0;
+      $this->last_query = $sql;
+      while( ( $next_row = oci_fetch_array( $query, OCI_RETURN_NULLS ) ) !== false )
+        $this->last_dataset[] = $next_row;
+    }
+  }
+  
+  /// Throw an exception, this function isn't implemented for oci yet.There is probably
+  /// a function for it, but I haven't looked into it as we won't be inserting anything
+  /// into an oci database in this project.
+
+  private function priv_GetInsertID()
+  {
+    throw new OCIDBException( 'Not implemented', 'OCIDB::priv_GetInsertID' );
+  }
+};
+
+?>
Index: /trunk/htdocs2/GreenZone/Utils/SQLDatabase.php
===================================================================
--- /trunk/htdocs2/GreenZone/Utils/SQLDatabase.php	(revision 440)
+++ /trunk/htdocs2/GreenZone/Utils/SQLDatabase.php	(revision 440)
@@ -0,0 +1,292 @@
+<?php
+
+
+
+/// Written by David Smith
+/// FOR ATNF CSIRO (c) 2008
+///
+/// This file is a base interface for different types of database.
+/// If pdo_oci worked, we would simply have one pdo database class,
+/// however it doesn't, so this class defines the common interface
+/// shared by mysql and oci databases.
+
+
+
+class SQLDBException extends GZ_Exception
+{}
+
+
+
+class SQLDatabase
+{
+  // PUBLIC
+
+  public function __construct()
+  {
+    $this->link = null;
+    $this->last_query = null;
+    $this->last_result = null;
+    $this->last_dataset = Array();
+    $this->debug = 0;
+  }
+  
+  public function __destruct() { $this->priv_Disconnect(); }
+  
+  // MAIN INTERFACE - override the private versions of these functions.
+  
+  public function Connect( $db_user, $db_password, $db_dsn ) { $this->priv_Connect( $db_user, $db_password, $db_dsn ); }
+  public function EnsureConnected() { $this->priv_EnsureConnected(); }
+  public function EnsureNumRows( $comparison, $num ) { $this->priv_EnsureNumRows( $comparison, $num ); }
+  public function FetchNumRows() { return $this->priv_FetchNumRows(); }
+  public function FetchRowAsArray() { return $this->priv_FetchRowAsArray(); }
+  public function DoQuery( $sql ) { $this->priv_DoQuery( $sql ); }
+  public function GetLastResult() { return $this->last_dataset; }
+  public function GetInsertID() { return $this->GetInsertID(); }
+  public function SelectByFields( $table_name, $field_specs ) { $this->priv_SelectByFields( $table_name, $field_specs ); }
+  public function SetFieldsByFields( $table_name, $set_fields, $match_fields )
+    { $this->priv_SetFieldsByFields( $table_name, $set_fields, $match_fields );
+  public function InsertWithFields( $table_name, $field_specs ) { $this->priv_InsertWithFields( $table_name, $field_specs ); }
+  public function InsertTupleUsingAssoc( $table_name, $tuple ) { $this->priv_InsertTupleUsingAssoc( $table_name, $tuple ); }
+
+  public function Debug() { $this->debug = 1; }
+  public function EndDebug() { $this->debug = 0; }
+  
+  // PRIVATE
+      
+  private $link;
+  private $last_result;
+  private $last_query;
+  private $debug;
+  private $last_dataset;
+  private $last_dataset_index;
+  
+  
+  
+  /// This function simply throws an error, because it should be overriden by the specific
+  /// database class we are using.
+  
+  private function priv_Connect( $db_user, $db_password, $db_dsn )
+  {
+    throw new SQLDBException( 'Bad Call, derived class should always override this function', 'SQLDatabase::priv_Connect' );
+  }
+  
+  /// Simply throw an exception if we are not connected to the database.
+
+  private function priv_EnsureConnected()
+  {
+    if( !$this->link )
+      throw new SQLDBException( 'Not connected to database', 'SQLDB::EnsureConnected', DISCONNECTED );
+  }
+  
+  
+  
+  /// Checks that the correct number of rows have been returned.
+
+  private function priv_EnsureNumRows( $comparison, $num )
+  {
+    $this->EnsureConnected();
+
+    $num_rows = count( $this->last_dataset );
+
+    if( $comparison != 'equals' && $comparison != 'lessthan' && $comparison != 'greaterthan' )
+      throw new SQLDBException( 'Unknown comparison ' . $comparison, 'SQLDB::EnsureNumRows', INVALID_PARAM );
+
+    if( $comparison == 'equals' && $num != $num_rows )
+      throw new SQLDBException( 'num rows failed equality' . $this->last_query, 'SQLDB::EnsureNumRows', OUT_OF_RANGE );
+    else if( $comparison == 'lessthan' && $num_rows >= $num )
+      throw new SQLDBException( 'num rows failed < comparison' . $this->last_query, 'SQLDB::EnsureNumRows', OUT_OF_RANGE );
+    else if( $comparison == 'greaterthan' && $num_rows <= $num )
+      throw new SQLDBException( 'num rows failed > comparison' . $this->last_query, 'SQLDB::EnsureNumRows', OUT_OF_RANGE );
+  }
+  
+  
+  /// Fetch the number of rows returned by the last query
+  
+  private function priv_FetchNumRows()
+  {
+    if( $this->last_dataset == null )
+      return 0;
+    
+    return count( $this->last_dataset );
+  }
+  
+  
+  /// Fetch the next row as an array
+  
+  function priv_FetchRowAsArray()
+  {
+    if( $this->last_dataset_index >= $this->FetchNumRows() )
+      throw new SQLDBException( 'fetching row out of range', 'SQLDB::FetchRowAsArray', OUT_OF_RANGE );
+
+    return $this->last_dataset[ $this->last_dataset_index ++ ];
+  }
+  
+  
+  /// Get the id of the row just inserted
+  /// TODO write a neutral version of this.
+  
+  function priv_GetInsertID()
+  {
+//     $this->EnsureConnected();
+// 
+//     if( ( $id = mysql_insert_id( $this->link ) ) === false )
+//       throw new SQLDBException( 'Unable to retreive insert id', 'SQLDB::EnsureConnected', FAILED_CALL );
+// 
+//     return $id;
+  }
+  
+  
+  
+  /// Build and execute a select query given the tablename and an array
+  /// of field => value parameters.
+  
+  private function priv_SelectByFields( $table_name, $field_specs )
+  {
+    $select_sql = ' SELECT * FROM ' . $table_name . ' WHERE ';
+
+    $first = true;
+    foreach( $field_specs as $next_field => $next_value )
+    {
+      if( !$first )
+        $select_sql .= ' AND ';
+      $select_sql .= $next_field . ' = ';
+      if( !is_numeric( $next_value ) )
+        $select_sql .= '\'';
+
+      $select_sql .= $next_value;
+
+      if( !is_numeric( $next_value ) )
+        $select_sql .= '\'';
+
+      $first = false;
+    }
+
+    if( $this->debug )
+      echo $select_sql . ' <br> ';
+
+    $this->DoQuery( $select_sql );
+
+    return $this->GetLastResult();
+  }
+  
+  
+  /// Build and execute an update query given the table name, the fields to select by
+  /// and the fields to change.
+
+  private function priv_SetFieldsByFields( $table_name, $set_fields, $match_fields )
+  {
+    if( count( $set_fields ) < 2 || count( $match_fields ) < 2 )
+      throw( new SQLDBException( 'SetFieldsByFields: Need atleast 2 args to set fields and 2 to match fields.', 
+             'SQLDB::SetFieldsByFields', OUT_OF_RANGE ) );
+
+    $update_sql = ' UPDATE ' . $table_name . ' SET ';
+
+    for( $i = 0; $i < count( $set_fields ); $i += 2 )
+    {
+      if( 0 != $i )
+        $update_sql .= ', ';
+
+      $update_sql .= $set_fields[$i] . ' = ';
+      if( !is_numeric( $set_fields[$i+1] ) )
+        $update_sql .= '\'';
+
+      $update_sql .= $set_fields[$i+1];
+      if( !is_numeric( $set_fields[$i+1] ) )
+        $update_sql .= '\'';
+    }
+
+    $update_sql .= ' WHERE ';
+
+    for( $i = 0; $i < count( $match_fields ); $i += 2 )
+    {
+      if( $i != 0 )
+        $update_sql .= ' AND ';
+      $update_sql .= $match_fields[$i] . ' = ';
+
+      if( !is_numeric( $match_fields[$i+1] ) )
+        $update_sql .= '\'';
+
+      $update_sql .= $match_fields[$i+1];
+
+      if( !is_numeric( $match_fields[$i+1] ) )
+        $update_sql .= '\'';
+    }
+
+    if( $this->debug )
+      echo $update_sql;
+
+    $this->DoQuery( $update_sql );
+  }
+  
+  /// Build and execute an insert query given the table name and the fields we want to set.
+  /// The field_specs are not an associative array, every second item is a fieldname every
+  /// other item is a value. I don't know why I keep this function, the associative version
+  /// is better.
+  
+  private function priv_InsertWithFields( $table_name, $field_specs )
+  {
+    $insert_sql = ' INSERT INTO ' . $table_name . ' ( ';
+
+    for( $i = 0; $i < count( $field_specs ); $i += 2 )
+    {
+      if( $i != 0 )
+        $insert_sql .= ', ';
+
+      $insert_sql .= $field_specs[$i];
+    }
+
+    $insert_sql .= ' ) VALUES ( ';
+
+    for( $i = 1; $i < count( $field_specs ); $i += 2 )
+    {
+      if( $i != 1 )
+        $insert_sql .= ', ';
+
+      $insert_sql .= '\'' . $field_specs[$i] . '\'';
+    }
+    $insert_sql .= ' ) ';
+
+    if( $this->debug )
+      echo $insert_sql . '<br>';
+
+    $this->DoQuery( $insert_sql );
+  }
+
+  /// Build and execute an insert query using the associative array of field=>values
+  
+  private function priv_InsertTupleUsingAssoc( $table_name, $tuple )
+  {
+    $insert_sql = ' INSERT INTO ' . $table_name . ' ( ';
+
+    $num_fields = count( $tuple );
+    $ind = 1;
+    foreach( $tuple as $next_name => $next_value )
+    {
+      $insert_sql .= $next_name . ' ';
+      if( $ind < $num_fields )
+        $insert_sql .= ', ';
+      $ind ++;
+    }
+    $insert_sql .= ' ) VALUES ( ';
+
+    $ind = 1;
+    foreach( $tuple as $next_name => $next_value )
+    {
+      if( is_string( $next_value ) || $next_value == null )
+        $insert_sql .= '"' . $next_value . '" ';
+      else
+        $insert_sql .= $next_value;
+      if( $ind < $num_fields )
+        $insert_sql .= ', ';
+      $ind ++;
+    }
+    $insert_sql .= ' ) ';
+
+    if( $this->debug )
+      echo $insert_sql . '<br>';
+
+    $this->DoQuery( $insert_sql );
+  }
+};
+
+?>
