diff -urpN drupal-6.x-dev-200705302348/includes/database.oracle.inc drupal-6.x-dev/includes/database.oracle.inc
--- drupal-6.x-dev-200705302348/includes/database.oracle.inc	1970-01-01 08:00:00.000000000 +0800
+++ drupal-6.x-dev/includes/database.oracle.inc	2007-05-31 01:26:05.000000000 +0800
@@ -0,0 +1,1933 @@
+<?php
+// $ID$
+
+/**
+ * @file
+ * Database interface code for Oracle database servers.
+ */
+
+/**
+ * @ingroup database
+ * @{
+ */
+
+/**
+ * Report database status.
+ */
+function db_status_report($phase) {
+  $t = get_t();
+
+  $version = db_version();
+
+  $form['oracle'] = array(
+    'title' => $t('Oracle database'),
+//    'value' => ($phase == 'runtime') ? l($version, 'admin/logs/status/sql') : $version,
+    'value' => $version,
+  );
+
+  // -- checkpoint 01: no checking for Oracle server
+  //            TODO
+  //            $version : from system.install
+  //  if (version_compare($version, DRUPAL_MINIMUM_MYSQL) < 0) {
+  //    $form['oracle']['severity'] = REQUIREMENT_ERROR;
+  //    $form['oracle']['description'] = $t('Your MySQL Server is too old. Drupal requires at least MySQL %version.', array('%version' => DRUPAL_MINIMUM_MYSQL));
+  //  }
+  // -- end 01
+
+  return $form;
+}
+
+/**
+ * Returns the version of the database server currently in use.
+ *
+ * @return Database server version
+ */
+function db_version() {
+  return db_result(db_query('SELECT banner FROM sys.V_$VERSION'));
+}
+
+/**
+ * Initialize a database connection.
+ */
+function db_connect($url) {
+  	
+  // Check if Oracle support is present in PHP 4 or 5
+  if (!(function_exists('oci_connect'))) {
+    drupal_maintenance_theme();
+    drupal_set_title('PHP Oracle support not enabled');
+    print theme('maintenance_page', '<p>We were unable to use the Oracle database because the Oracle extension for PHP is not installed. Check your <code>PHP.ini</code> to see how you can enable it.</p>');
+    //create a book page about Oracle support.
+    exit;
+  }
+
+  $url = parse_url($url);
+  
+  //print_r($url);	
+  //die(); 
+  // Decode url-encoded information in the db connection string
+  $url['user'] = urldecode($url['user']);
+  $url['pass'] = urldecode($url['pass']);
+  $url['host'] = urldecode($url['host']);
+  $url['path'] = urldecode($url['path']);
+
+  // Allow for non-standard Oracle port.
+  if (isset($url['port'])) {
+     $url['host'] = $url['host'] .':'. $url['port'];
+  }
+
+  // -- checkpoint 02 : extract charset from path
+  // $db_url = 'oracle://user:pass@host/SID/charset';
+  $tmp_path = explode('/', substr($url['path'], 1));
+  $url['charset'] = $tmp_path[1];
+  $url['path'] = "/" . $tmp_path[0];
+  // -- end 02
+  $string_db = '//'.$url['host'].'/'.substr($url['path'], 1);
+  
+  //TODO: investigate for the use of charset parameter.
+  //TODO: Currently, this requires that the $url['path'] value be 
+  //      set in the TNSNAMES.ora file on the local system. Investigate
+  //      how to specify server, port and DB Instance. 
+  
+  /*
+  Re: TODO above, using a connection string like this might work
+  $db="(DESCRIPTION =
+     (ADDRESS_LIST =
+         (ADDRESS =
+           (COMMUNITY = xxx)
+           (PROTOCOL = TCP)
+           (Host = xxx)
+           (Port = xxx)
+         )
+     )
+     (CONNECT_DATA = (SID = xxx)
+     )
+   )"; 
+   */
+
+// -- checkpoint 03
+//    Add connection charset parameter
+//    use string_db instead of substr
+//    as 'Can't find listenser before
+//  $connection = @oci_connect($url['user'], $url['pass'], substr($url['path'], 1));
+  if ($url['charset']) {
+    $connection = @oci_connect($url['user'], $url['pass'], $string_db, $url['charset']);
+  } else {
+    $connection = @oci_connect($url['user'], $url['pass'], $string_db);
+  }
+// -- end 03
+  
+  if (!$connection) {
+  	
+    drupal_maintenance_theme();
+    drupal_set_title('Unable to connect to database server');
+    $error = ocierror();
+    print theme('maintenance_page', '<p>This either means that the username and password information in your <code>settings.php</code> file is incorrect or we can\'t contact the Oracle database server. This could mean your hosting provider\'s database server is down.</p>
+<p>The Oracle error was: '. theme('placeholder', $error['message']) .'.</p>
+<p>Currently, the username is '. theme('placeholder', $url['user']) .' and the database server is '. theme('placeholder', $url['host']) .'.</p>
+<ul>
+  <li>Are you sure you have the correct username and password?</li>
+  <li>Are you sure that you have typed the correct hostname?</li>
+  <li>Are you sure that the database server is running?</li>
+</ul>
+<p>For more help, see the <a href="http://drupal.org/node/258">Installation and upgrading handbook</a>. If you are unsure what these terms mean you should probably contact your hosting provider.</p>');
+    exit;
+  }  
+  
+  return $connection;
+}
+ /**
+ * Sanitize query adding "" around Oracle SQL reserved column names.
+ */
+
+function _db_reserved_words($part) {
+  $part = " " . $part . " "; //hack to get around the fact that the column name might be at the front or at the end of the string
+  $db_reserved_words = array ('access', 'comment', 'mode', 'session', 'uid', 'file');
+  foreach ($db_reserved_words as $word) {
+    $part = eregi_replace('([[:space:],\.\(<>\+-=!*])'.$word.'([[:space:],\.\)<>\+-=!*])','\\1"'.$word.'"\\2', $part);
+  }
+  return substr($part,1,-1);
+}
+
+  /**
+   *  _db_query_rewrite_select() : rewrite SELECT query quote reserved word and handle CLOB comparison
+   *  @param string query : SELECT query string
+   *  @param integer debug : debug mode ON/OFF to print message(OFF)
+   *  @return string : query string with reserved words quoted
+   */
+// Isolated function to rewrite select query
+// planned for INSERT INTO ... SELECT
+function _db_query_rewrite_select($query, $debug = 0) {
+  
+  global $active_db, $last_result, $_query_rc_result, $queries;
+
+  // Parsing SELECT query, because we need to manage CLOB and BLOBs in WHERE clause
+  // This is only for simple queries
+  // TODO: think of better $re to handle complex queries (JOINS)
+  	
+  if (strpos($query, 'JOIN') || strpos($query, 'ORDER') || strpos($query, 'GROUP') || strpos($query, 'LIKE') || !strpos($query, 'WHERE')) {
+
+    $newSQL = _db_reserved_words($query);
+    return $newSQL;
+
+  } else { 
+
+    //$re = "/select\\s*(.*)\\s*from\\s*(.*)\\s*where\\s*(.*)/si";  		
+    $re = "/\sfrom\s*(\w+)/si";
+    preg_match($re, $query, $tmpArr);		
+    $tablename = trim($tmpArr[1]);		
+    // -- checkpoint 04
+    //    for query select only constant
+    //    give it virtual table 'dual'
+    if (!$tablename) {
+      $query .= " FROM DUAL";
+    }
+    // -- end 04
+    
+    /*
+     * Determine whether or not each column is a LOB (CLOB or BLOB) and 
+     * substitute a bind variable. If the column list is not provided, 
+     * we'll need to obtain it from the DB.
+     */
+    //TODO: Augment this query with some sort of caching system, so it knows
+    //       which columns are LOBs without having to ask the DB every time.
+    $col_query = "SELECT column_name, data_type, column_id
+                FROM USER_TAB_COLUMNS
+                WHERE table_name = '" . strtoupper($tablename) . "'
+                ORDER BY column_id";
+	    
+    $col_result = oci_parse($active_db, $col_query);
+    oci_execute($col_result , OCI_DEFAULT);
+    oci_fetch_all($col_result, $ora_cols, 0, -1, OCI_ASSOC);
+	    	    	    
+    for ($i=0; $i<sizeof($ora_cols["DATA_TYPE"]); $i++) {
+      if ($ora_cols["DATA_TYPE"][$i] == 'CLOB') {
+    	$CLOB_vars[] = $ora_cols["COLUMN_NAME"][$i];
+      }
+    }
+	    
+    $newSQL = _db_reserved_words($query);
+    if (sizeof($CLOB_vars)) {
+      $CLOB_str = implode("|", $CLOB_vars);   
+      $sql = str_replace("\'", chr(0), $query);
+      $sql = str_replace("''", chr(1), $sql);
+      $pattern = "/(" . $CLOB_str . ")\s*(=|!=)\s*('.*?')/si";
+      //$pattern = "/(" . $CLOB_str . ")\s*(=|!=)\s*('(?:\\'|[^'])*')/si";
+      $containerArr = array();
+      preg_match_all($pattern, $sql, $containerArr);
+      
+      for ($j=0; $j<sizeof($containerArr[0]); $j++) {
+        $sql = str_replace($containerArr[0][$j], " dbms_lob.instr(" . $containerArr[1][$j] . ", " . $containerArr[3][$j] . ") > 0 ", $sql);
+      }
+
+      $newSQL = str_replace(chr(1), "''", $sql);
+      $newSQL = str_replace(chr(0), "\'", $newSQL);
+      $newSQL = _db_reserved_words($newSQL);
+    }
+    return $newSQL;
+
+  }
+}
+
+// -- checkpoint 24: Parsing implementation
+// -- Try to handle queries without bucket '()'
+//    JOIN:   is in FROM part,
+//            seems can be handled in it.
+//    GROUP:  not tested
+// SELECT A FROM B WHERE C ORDER BY D
+function _regexp_select_easy($query) {
+  $hasWhere = 0;
+  $hasOrder = 0;
+  $hasIn = 0;
+  $argOrder = array();
+  $regexp_select = "/^select (.*) from (.*)";
+  $i = 3;
+  if (strpos($query, " WHERE ")) {
+    $hasWhere = 1;
+    $argOrder['where'] = $i;
+    $i++;
+    $regexp_select .= " where (.*)";
+    if (strpos($query, " IN ")) {
+      $hasIn = 1;
+      $argOrder['in'] = $i;
+      $i++;
+      $regexp_select .= " in (\(.*\))";
+    }
+  }
+  if (strpos($query, " ORDER ")) {
+    $hasOrder = 1;
+    $argOrder['order'] = $i;
+    $i++;
+    $regexp_select .= " order by (.*)";
+  }
+  $regexp_select .= "/Dsi";
+  preg_match($regexp_select, $query, $matches2);
+//  drupal_set_message($regexp_select);
+
+  if (isset($matches2[1]) && $matches2[1]) {
+    $returnSQL  = "SELECT "._db_reserved_words($matches2[1]);
+    $returnSQL .= " FROM "._db_reserved_words($matches2[2]);
+    if ($hasWhere) {
+      $returnSQL .= " WHERE "._db_reserved_words($matches2[($argOrder['where'])]);
+    }
+    if ($hasIn) {
+      $returnSQL .= " IN ".$matches2[($argOrder['in'])];
+    }
+    if ($hasOrder) {
+      $returnSQL .= " ORDER BY "._db_reserved_words($matches2[($argOrder['order'])]);
+    }
+  } else {
+    // not a query, just field names
+    $returnSQL = $query;
+  }
+  return $returnSQL;
+}
+// -- end 24
+
+// -- checkpoint 23: parsing query with recursive function
+//                    break bucket until no bucket.
+//                    at the same time do complete parsing to remaining SQL segment
+function _regexp_select_recur($query) {
+  $regexp_bucket = "/\((.*)\)/Dsi";
+  preg_match($regexp_bucket, $query, $matches);
+  if (isset($matches[1]) && $matches[1]) {
+//    drupal_set_message("Matches: ".$matches[1]);
+    $return_str = _regexp_select_recur($matches[1]);
+    // replace query in bucket with some string
+    // prevent re-parsing
+    $new_query = str_replace($matches[1],"a1", $query);
+
+    $new_query = _regexp_select_easy($new_query);
+
+    // restore the query
+    $return_query = str_replace("a1", $return_str, $new_query);
+    return $return_query;
+  } else {
+    // end of recursive: no bucket found
+    $return_query = _regexp_select_easy($query);
+
+    return $return_query;
+  }
+}
+// -- end 23
+
+/**
+ * Runs a basic query in the active database.
+ *
+ * User-supplied arguments to the query should be passed in as separate
+ * parameters so that they can be properly escaped to avoid SQL injection
+ * attacks.
+ *
+ * @param $query
+ *   A string containing an SQL query.
+ * @param ...
+ *   A variable number of arguments which are substituted into the query
+ *   using printf() syntax. Instead of a variable number of query arguments,
+ *   you may also pass a single array containing the query arguments.
+ *
+ *   Valid %-modifiers are: %s, %d, %f, %b (binary data, do not enclose
+ *   in '') and %%.
+ *
+ *   NOTE: using this syntax will cast NULL and FALSE values to decimal 0,
+ *   and TRUE values to decimal 1.
+ *
+ * @return
+ *   A database query result resource, or FALSE if the query was not
+ *   executed correctly.
+ */
+function db_query($query) {
+  $args = func_get_args();
+  array_shift($args);
+  $query = db_prefix_tables($query);
+  if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax
+    $args = $args[0];
+  }
+  _db_query_callback($args, TRUE);
+  $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query);
+  return _db_query($query);
+}
+
+/**
+ * Helper function for db_query().
+ */
+function _db_query($query, $debug = 0) {
+	global $counterS;
+        $counterS++;
+        $dbug = 0;
+        global $active_db, $last_result, $_query_rc_result, $queries;
+        $CLOB_vars = array();
+
+//  drupal_set_message("_db_query(): ".$query);
+  if (variable_get('dev_query', 0)) {
+    list($usec, $sec) = explode(' ', microtime());
+    $timer = (float)$usec + (float)$sec;
+  }
+  
+  if (!isset($_query_rc_result)) {
+    $_query_rc_result = array();
+  }
+  
+  //Rewrite all INSERT/UPDATE statements to check and handle LOBs since Oracle
+  //  cannot handle them as just strings of text delimited by single quote 
+  //  marks (') once they go over 4000 charecters (common in Drupal).
+  if (eregi('^(INSERT INTO )', $query)) {
+    //Rewrite INSERT INTO statement
+    //$query = "INSERT INTO boxes (title, body, info, format) VALUES ('', '', 'a', 1)";
+    
+  	//echo "<br />------------------------------------<br />Step $counterS <br />";
+  	//echo $query . "<br />";
+    /* 
+     * Split statement into three groups - the table name, the field list 
+     * (if provided) and "VALUES" and the value list. Then, further split
+     * the column list and value/ list into arrays. 
+     */
+
+    // -- checkpoint 05 : Handle "INSERT INTO .. SELECT .. " query
+    //$query = "INSERT INTO node_data_field_cck0101
+    //          (vid, nid, field_cck0101_value)
+    //          SELECT vid, nid, field_cck0101_value 
+    //          FROM node_content_cck01";
+    // CCK: content_admin.inc
+    // TODO: do data type validation between INSERT fields and SELECT fields
+    
+    $re = "/[\s)]values\s*(\(.*\))/si";
+    preg_match($re, $query, $tmpArr);	
+    if (!isset($tmpArr[0]) || !trim($tmpArr[0])) {
+      //drupal_set_message("The INSERT query does not contain VALUES, function not yet DONE, checking is skipped");
+      $re = "/^insert into ([a-z0-9_\"]+)(?:\s*\((.*)\))? (select .*)$/Dsi";
+      preg_match($re, $query, $parts);
+
+      $tablename = _db_reserved_words($parts[1]);
+      $col_list = _db_reserved_words($parts[2]);
+      $val_list = _db_query_rewrite_select($parts[3]);
+
+      $query = "INSERT INTO " . $tablename . " (" . $col_list . ") " . $val_list;
+      $result = OCIParse($active_db, $query);
+      OCIExecute($result, OCI_DEFAULT) or die($query);
+      OCICommit($active_db);
+      return true;
+    }
+    // -- end 05
+
+    //$re = "/^insert into ([a-z0-9_\"]+)(?:\s*\((.*)\))? values \((.*)\)$/Dsi";
+    //$re = "/^insert into ([a-z0-9_\"]+)(?:\s*\((.*)\))? values\s+\((.*)\)$/Dsi";
+    // checkpoint 20 : break INSERT statement into parts
+    $re = "/^insert into ([a-zA-Z0-9_\"]+)\s+\((.*)\)\s+values\s*\((.*)\)/Dsi";
+    // -- end 20
+    
+    preg_match($re, $query, $parts);
+    if (isset($parts[3]) && count($parts[3])) {
+      // INSERT INTO tablename (column_list) VALUES (value_list)
+//    print_r($parts); echo "<br />";
+//  die();
+      $tablename = _db_reserved_words($parts[1]);
+      $col_list = _db_reserved_words($parts[2]);
+      $val_list = $parts[3];
+      $col_arr = explode(",",$col_list); //the column list is strictly delimited by ","
+      $hasColName = 1;
+    } else {
+      $re = "/^insert into ([a-zA-Z0-9_\"]+)\s+values\s*\((.*)\)/Dsi";
+      // dbug01
+//      print "OLD: ".$query."<br />";
+      preg_match($re, $query, $parts);
+      $tablename = _db_reserved_words($parts[1]);
+      $val_list = $parts[2];
+      $hasColName  = 0;
+    }
+    
+    //However, the value list is not strictly delimited by ",", use a regex to break it up
+    $re="/,(?=(?:[^']*'[^']*')*(?![^']*'))/";
+    $results=preg_split($re, trim($val_list));
+    $val_arr = preg_replace("/^\"(.*)\"$/","$1", $results);
+    
+    /*
+     * Determine whether or not each column is a LOB (CLOB or BLOB) and 
+     * substitute a bind variable. If the column list is not provided, 
+     * we'll need to obtain it from the DB.
+     */
+    //TODO: Augment this query with some sort of caching system, so it knows
+    //       which columns are LOBs without having to ask the DB every time.
+    $col_query = "select column_name, data_type, column_id
+                from USER_TAB_COLUMNS
+                where table_name = '" . strtoupper($tablename) . "'
+                order by column_id";
+    $col_result = ociparse($active_db, $col_query);
+    OCIExecute($col_result , OCI_DEFAULT);
+    ocifetchstatement($col_result, $ora_cols, 0, -1, OCI_ASSOC);
+    
+    // Check + Build $col_arr
+    if (! is_array($col_arr)) {
+      //populate $col_list
+      $col_arr = $ora_cols['COLUMN_NAME'];
+      for($i=0; $i < count($col_arr);$i++) {
+        // If column name is in lower case, it needs to have "" around it since its a reserved word
+        if ($col_arr[$i] == strtolower($col_arr[$i])){
+          $col_arr[$i] = "\"" . $col_arr[$i] . "\"";
+        }
+      }
+      array_change_key_case($col_arr, CASE_LOWER);
+    }
+    
+    //Clean $col_arr and $val_arr
+    foreach ($col_arr as $key => $value) {
+      $col_arr[$key] = trim($value);
+    }
+    foreach ($val_arr as $key => $value) {
+      $val_arr[$key] = trim($value);
+    }
+    
+    // $lob_cols[n] => [0] Column Name, [1] Value to be stored
+    $lob_cols = array();
+    
+    // Check for CLOB/BLOB
+    for($i=0; $i < count($col_arr);$i++) {
+      $query_col = trim(str_replace("\"", "", strtolower($col_arr[$i])));
+      for($j=0; $j < count($ora_cols['COLUMN_NAME']);$j++) {
+        $ora_col = trim(strtolower($ora_cols['COLUMN_NAME'][$j]));  
+        if ($query_col == $ora_col) {
+          if ($ora_cols['DATA_TYPE'][$j] == "CLOB" || $ora_cols['DATA_TYPE'][$j] == "BLOB") {
+            // Replace that value with a bind variable if the data is not ''
+            if ($val_arr[$i] != "''") {
+              $lob_cols[] = array($col_arr[$i], $val_arr[$i]);
+            } 
+            $val_arr[$i] = "EMPTY_" . $ora_cols['DATA_TYPE'][$j] . "()";
+          }
+          break;
+        }
+      }
+    }
+    //Rebuild Query
+    $newquery  = "INSERT INTO " . $tablename;
+    if ($hasColName) {
+      $newquery .= " (" . implode(",", $col_arr) . ")";
+    }
+    $newquery .= " VALUES (" .  implode(",", $val_arr) . ")";
+//    print "NEW: ".$newquery."<br />";
+
+    //Build RETURNING string
+    if (count($lob_cols) > 0) {
+      $lobcollist = null;
+      $bindvarlist = null;
+      for($i=0;$i < count($lob_cols);$i++) {
+        $lobcollist .=  "," . $lob_cols[$i][0];
+        $bindvarlist .= "," . ":" . $lob_cols[$i][0];
+      }
+      $lobcollist = substr($lobcollist,1);
+      $bindvarlist = substr($bindvarlist,1);
+      $newquery .= " RETURNING " . $lobcollist . " INTO " . $bindvarlist;
+    }
+    
+    $result = OCIParse($active_db, $newquery);
+    $clobs = array();
+    
+    //Create bind variables
+    if (count($lob_cols) > 0) {
+      for($i=0;$i < count($lob_cols);$i++) {
+        $clob = ocinewdescriptor($active_db, OCI_D_LOB);
+        ocibindbyname($result, ':' . $lob_cols[$i][0], $clob, -1, OCI_B_CLOB);
+        $clobs[] = $clob;
+      }
+    }
+    
+    OCIExecute($result, OCI_DEFAULT) or die($newquery);
+    
+    //Bind CLOB data
+    if (count($lob_cols) > 0) {
+      for($i=0;$i < count($lob_cols);$i++) {
+        $clob = $clobs[$i];
+        $data = $lob_cols[$i][1];
+        //Strip ' from the beginning and end of the string (since they'll be 
+        //  interpreted literally and not as string encapsulators)
+        if (substr($data,0,1) == "'" && substr($data,-1,1) == "'") {
+          $data = substr($data,1,-1);
+          // -- checkpoint 06 : remove duplicated quote for further steps
+          $tmp_str = str_replace("''", "'", $data);
+          $data = $tmp_str;
+          // -- end 06
+        }
+        // In order to update the table, a row must have been found in the where clause!
+        if (ocirowcount($result) > 0) {
+          $clob->save($data);
+        }
+      }
+    }
+    
+    OCICommit($active_db);
+    
+    //Free CLOBs
+    if (count($lob_cols) > 0) {
+      for($i=0;$i < count($lob_cols);$i++) {
+        $clob = $clobs[$i];
+        $clob->free();
+      }
+    }
+  
+  } // end (eregi('^(INSERT INTO )', $query))
+  else if (eregi('^(UPDATE )', $query)) {
+    //Rewrite UPDATE statement
+    
+    /* 
+     * Split statement into three groups - the table name, the field and 
+     * value list, and the WHERE clause (if provided). Then, further split
+     * the column list and value list into arrays. 
+     */
+    $re = "/update\\s*([a-z0-9_\"]+)\\s*set\\s*(.*)\\s*where\\s*(.*)/si";
+    preg_match($re, $query, $parts);
+    $tablename = _db_reserved_words($parts[1]);
+    $item_list = $parts[2];
+    $whereclause = _db_reserved_words($parts[3]);
+    
+    $re="/,(?=(?:[^']*'[^']*')*(?![^']*'))/";
+    $results=preg_split($re, trim($item_list));
+    $item_arr = preg_replace("/^\"(.*)\"$/","$1", $results);
+
+    //Split item array into column and value arrays
+    $col_arr = array();
+    $val_arr = array();
+    
+    for($i=0; $i < count($item_arr);$i++) {
+      $pos = strpos($item_arr[$i], "=");
+      $col_arr[] = trim(substr($item_arr[$i],0,$pos-1));
+      $val_arr[] = trim(substr($item_arr[$i],$pos+1));
+    }
+    
+    $col_arr = explode(",",_db_reserved_words(implode(",", $col_arr)));
+    
+    /*
+     * Determine whether or not each column is a LOB (CLOB or BLOB) and 
+     * substitute a bind variable. If the column list is not provided, 
+     * we'll need to obtain it from the DB.
+     */
+    //TODO: Augment this query with some sort of caching system, so it knows
+    //       which columns are LOBs without having to ask the DB every time.
+    $col_query = "select column_name, data_type, column_id
+                from USER_TAB_COLUMNS
+                where table_name = '" . strtoupper($tablename) . "'
+                order by column_id";
+    $col_result = OCIParse($active_db, $col_query);
+    OCIExecute($col_result , OCI_DEFAULT);
+    ocifetchstatement($col_result, $ora_cols, 0, -1, OCI_ASSOC);
+    
+    // Check + Build $col_arr
+    if (! is_array($col_arr)) {
+      //populate $col_list
+      $col_arr = $ora_cols['COLUMN_NAME'];
+      for($i=0; $i < count($col_arr);$i++) {
+        // If column name is in lower case, it needs to have "" around it since its a reserved word
+        if ($col_arr[$i] == strtolower($col_arr[$i])){
+          $col_arr[$i] = "\"" . $col_arr[$i] . "\"";
+        }
+      }
+      array_change_key_case($col_arr, CASE_LOWER);
+    }
+    
+    //Clean $col_arr and $val_arr
+    foreach ($col_arr as $key => $value) {
+      $col_arr[$key] = trim($value);
+    }
+    foreach ($val_arr as $key => $value) {
+      $val_arr[$key] = trim($value);
+    }
+    
+    //array of arrays, the items below are defined as... 
+    // $lob_cols[n] => [0] Column Name, [1] Value to be stored
+    $lob_cols = array();
+    
+    // Check for CLOB/BLOB
+    for($i=0; $i < count($col_arr);$i++) {
+      $query_col = trim(str_replace("\"", "", strtolower($col_arr[$i])));
+      for($j=0; $j < count($ora_cols['COLUMN_NAME']);$j++) {
+        $ora_col = trim(strtolower($ora_cols['COLUMN_NAME'][$j]));  
+        if ($query_col == $ora_col) {
+          if ($ora_cols['DATA_TYPE'][$j] == "CLOB" || $ora_cols['DATA_TYPE'][$j] == "BLOB") {
+            // Replace that value with a bind variable if the data is not ''
+            if ($val_arr[$i] != "''") {
+              $lob_cols[] = array($col_arr[$i], $val_arr[$i]);
+            }
+            $val_arr[$i] = "EMPTY_" . $ora_cols['DATA_TYPE'][$j] . "()";
+          }
+          break;
+        }
+      }
+    }
+    
+    //Rebuild Query
+    $newquery = "UPDATE " . $tablename . " SET ";
+    for($i=0; $i < count($col_arr); $i++) {
+      $newquery .= $col_arr[$i] . " = " . $val_arr[$i];
+      if ($i < (count($col_arr)-1)) $newquery .= ", ";
+    }
+    if ($whereclause != "") {
+      $newquery .= " where " . $whereclause;
+    }
+    
+    //Build RETURNING string
+    if (count($lob_cols) > 0) {
+      $lobcollist = null;
+      $bindvarlist = null;
+      for($i=0;$i < count($lob_cols);$i++) {
+        $lobcollist .=  "," . $lob_cols[$i][0];
+        $bindvarlist .= "," . ":" . $lob_cols[$i][0];
+      }
+      $lobcollist = substr($lobcollist,1);
+      $bindvarlist = substr($bindvarlist,1);
+      $newquery .= " RETURNING " . $lobcollist . " INTO " . $bindvarlist;
+    }
+        
+    $result = OCIParse($active_db, $newquery);
+    $clobs = array();
+    
+    //Create bind variables
+    if (count($lob_cols) > 0) {
+      for($i=0;$i < count($lob_cols);$i++) {
+        $clob = ocinewdescriptor($active_db, OCI_D_LOB);
+        ocibindbyname($result, ':' . $lob_cols[$i][0], $clob, -1, OCI_B_CLOB);
+        $clobs[] = $clob;
+      }
+    }
+    OCIExecute($result, OCI_DEFAULT) or die($newquery);
+    
+    //Bind CLOB data
+    if (count($lob_cols) > 0) {
+      for($i=0;$i < count($lob_cols);$i++) {
+        $clob = $clobs[$i];
+        $data = $lob_cols[$i][1];
+        //Strip ' from the beginning and end of the string (since they'll be 
+        //  interpreted literally and not as string encapsulators)
+        if (substr($data,0,1) == "'" && substr($data,-1,1) == "'") {
+          $data = substr($data,1,-1);
+          // -- checkpoint 07 : remove duplicated quote for further steps
+          $tmp_str = str_replace("''", "'", $data);
+          $data = $tmp_str;
+          // -- end 07
+        }
+
+        // In order to update the table, a row must have been found in the where clause!
+        if (ocirowcount($result) > 0) {
+          $clob->save($data);
+        }
+      }
+    }
+    
+    OCICommit($active_db);
+    
+    //Free CLOBs
+    if (count($lob_cols) > 0) {
+      for($i=0;$i < count($lob_cols);$i++) {
+        $clob = $clobs[$i];
+        $clob->free();
+      }
+    }
+  } // end (eregi('^(UPDATE )', $query))
+  else if (ereg('^(SELECT DISTINCT)', $query)) {
+//    drupal_set_message("DISTINCT: ".$query);
+    // Oracle cannot SELECT DISTINCT(clob_field) ... 
+    $query = str_replace("DISTINCT", "", $query);
+    $query = _db_reserved_words($query);
+    $result = OCIParse($active_db, $query);
+    OCIExecute($result, OCI_DEFAULT) or die($query);
+    //Re-execute query for when the app requests a rowcount (so it wont disturb the cursor of the real result set)
+    $result_rc = OCIParse($active_db, $query);
+    OCIExecute($result_rc, OCI_DEFAULT) or die($query);
+    // -- checkpoint 08: $_query_rc_result stores numrow number instead
+//    $_query_rc_result[$result] = $result_rc;
+    db_set_num_rows($result, $result_rc);
+  }
+  else if (ereg('^(LOCK TABLE)', $query)) {
+//    drupal_set_message("QUERY(LOCK): ". $query);
+    //Lock Table has a keyword thats in the reserved word list, we don't want it in ""s
+    //echo $query . "<br/>";
+
+    $re = "/^(lock table\s+)([a-z0-9_]+)(\\s+.*)$/si";
+    preg_match($re, $query, $parts);
+    $parts[2] = _db_reserved_words($parts[2]);
+    array_shift($parts); //shift off the entire string
+    $query = implode("",$parts);
+    $result = OCIParse($active_db, $query);
+    OCIExecute($result, OCI_DEFAULT);
+  }
+  else if (ereg('^(SELECT)', $query)) {
+    //Limit double query for row count to SELECT statements
+    //echo $query . "<br/>";
+    //$query = _db_reserved_words($query);
+    
+    	// Parsing SELECT query, because we need to manage CLOB and BLOBs in WHERE clause
+  	// This is only for simple queries
+  	// TODO: think of better $re to handle complex queries (JOINS)
+  	
+//            drupal_set_message("Unvised: ".$query);
+  	if (strpos($query, 'JOIN') || strpos($query, 'ORDER') || strpos($query, 'GROUP') || strpos($query, 'LIKE') || !strpos($query, 'WHERE')) {
+          //$query = _db_reserved_words($query);
+          $query = _regexp_select_recur($query);
+//            drupal_set_message("Revised: ".$query);
+            $result = OCIParse($active_db, $query);
+	    OCIExecute($result, OCI_DEFAULT);
+	    //Re-execute query for when the app requests a rowcount (so it wont disturb the cursor of the real result set)
+	    $result_rc = OCIParse($active_db, $query);
+	    OCIExecute($result_rc, OCI_DEFAULT);
+            // -- checkpoint 09: $_query_rc_result stores numrow number instead
+//            $_query_rc_result[$result] = $result_rc;
+            db_set_num_rows($result, $result_rc);
+            // -- end 09
+  	}
+  	else { 
+          //$re = "/select\\s*(.*)\\s*from\\s*(.*)\\s*where\\s*(.*)/si";  		
+//          print "Query1: ".$query."<br />";
+            $re = "/\sfrom\s*(\w+)/si";
+            preg_match($re, $query, $tmpArr);		
+            $tablename = trim($tmpArr[1]);		
+            // -- checkpoint 10
+            if (!$tablename) {
+              $query .= " FROM DUAL";
+            }
+//          print "Query2: ".$query."<br />";
+            // -- end 10
+
+            /*
+	     * Determine whether or not each column is a LOB (CLOB or BLOB) and 
+	     * substitute a bind variable. If the column list is not provided, 
+	     * we'll need to obtain it from the DB.
+	     */
+	    //TODO: Augment this query with some sort of caching system, so it knows
+	    //       which columns are LOBs without having to ask the DB every time.
+	    $col_query = "select column_name, data_type, column_id
+	                from USER_TAB_COLUMNS
+	                where table_name = '" . strtoupper($tablename) . "'
+	                order by column_id";
+            
+	    $col_result = oci_parse($active_db, $col_query);
+	    oci_execute($col_result , OCI_DEFAULT);
+	    oci_fetch_all($col_result, $ora_cols, 0, -1, OCI_ASSOC);
+	    	    	    
+	    for ($i=0; $i<sizeof($ora_cols["DATA_TYPE"]); $i++) {
+	    	if ($ora_cols["DATA_TYPE"][$i] == 'CLOB') {
+	    		$CLOB_vars[] = $ora_cols["COLUMN_NAME"][$i];
+	    	}
+	    }
+
+            // -- checkpoint 22: write deeper parsing for nested SELECT query
+            //$newSQL = _db_reserved_words($query);
+            $newSQL = _regexp_select_recur($query);
+            // end 22
+	    if (sizeof($CLOB_vars)) {
+		    $CLOB_str = implode("|", $CLOB_vars);   
+                    $sql = str_replace("\'", chr(0), $query);
+                    // -- checkpoint 26: replace the escaped single quote
+                    //    so no need to do in regexp
+                    $sql = str_replace("''", chr(1), $sql);
+                    // 05-15 stop here
+		    $pattern = "/(" . $CLOB_str . ")\s*(=|!=)\s*('.*?')/si";
+		    //$pattern = "/(" . $CLOB_str . ")\s*(=|!=)\s*('(?:\\'|[^'])*')/si";
+		    $containerArr = array();
+		    preg_match_all($pattern, $sql, $containerArr);
+			
+		    for ($j=0; $j<sizeof($containerArr[0]); $j++) {
+		      $sql = str_replace($containerArr[0][$j], " dbms_lob.instr(" . $containerArr[1][$j] . ", " . $containerArr[3][$j] . ") > 0 ", $sql);
+		    }
+		    $newSQL = str_replace(chr(1), "''", $sql);
+		    $newSQL = str_replace(chr(0), "\'", $newSQL);
+		    $newSQL = _db_reserved_words($newSQL);
+            }
+//            drupal_set_message("NEW: ".$newSQL);
+            $result = OCIParse($active_db, $newSQL);
+            OCIExecute($result, OCI_DEFAULT);	    	
+	    //Re-execute query for when the app requests a rowcount (so it wont disturb the cursor of the real result set)
+	    $result_rc = OCIParse($active_db, $newSQL);
+	    OCIExecute($result_rc, OCI_DEFAULT);
+            // -- checkpoint 11: $_query_rc_result stores numrow number instead
+//            $_query_rc_result[$result] = $result_rc;
+            db_set_num_rows($result, $result_rc);
+            // -- end 11
+  	}
+  }
+  else {
+    $query = _db_reserved_words($query);
+    $result = OCIParse($active_db, $query);
+    OCIExecute($result, OCI_DEFAULT) or die($query);
+  }
+  
+  $last_result = $result;
+  
+  $error = ocierror($result);
+
+  if (variable_get('dev_query', 0)) {
+    $bt = debug_backtrace();
+    $query = $bt[2]['function'] . "\n" . $query;
+    list($usec, $sec) = explode(' ', microtime());
+    $stop = (float)$usec + (float)$sec;
+    $diff = $stop - $timer;
+    $queries[] = array($query, $diff);
+  }
+
+  if ($debug) {
+    print '<p>query: '. $query .'<br />error:'. $error['message'] .'</p>';
+  }
+
+  if ($last_result !== FALSE) {
+    return $result;
+  }
+  else {
+    trigger_error(check_plain($error['message']."\nquery: ". $error['sqltext']), E_USER_WARNING);
+    return FALSE;
+  }
+}
+
+
+/*
+// For debugging purposes only
+function userErrorHandler($errno, $errmsg, $filename, $linenum, $vars)
+{
+  echo "<div style=\"border:1px solid black\">";
+  echo "ERR: ";
+  echo $errmsg . " | ";
+  echo $filename . " | ";
+  echo $errmsg . " | ";
+  echo $linenum . " | ";
+  print_r($vars);
+  echo "</div>";
+}
+*/
+
+
+/**
+ * Fetch one result row from the previous query as an object.
+ *
+ * @param $result
+ *   A database query result resource, as returned from db_query().
+ * @return
+ *   An object representing the next row of the result. The attributes of this
+ *   object are the table fields selected by the query.
+ *   
+ * NOTE: - Oracle returns table fields in uppercase, so we convert them into lowercase.
+ *       - Oracle will return the " marks around reserved column names - remove then or 
+ *         it will break other items down the line. 
+ *       - Oracle Clob are Objects, so we read their value.
+ *       - To maintain compatibility with PHP4 as well as PHP5, OCI_FETCH_OBJECT is 
+ *         not used (it does not exist in PHP4), instead OCIFETCHINTO is used.
+ */
+function db_fetch_object($result, $debug = 0) {
+  
+  if ($result) {
+    $new_obj = null;
+    //ocifetchinto($result, $arr, OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS); // To return LOBs as strings of text automatically
+    @ocifetchinto($result, $arr, OCI_ASSOC+OCI_RETURN_NULLS);
+    if ($myerr = ocierror($result)) {
+      // -- checkpoint 21: Use soft alert...
+      //print_r($myerr);
+      if ($debug)
+        drupal_set_message($myerr['message']."<br />".$myerr['sqltext']);
+    }
+    /*if ($debug) {
+      print_r($arr);
+    }*/
+    if (is_array($arr)) {
+      foreach ($arr as $key => $value) {
+        //if ($debug) print 'key:'.$key.'-value:'.$value.'<br>';
+        $lower_key = str_replace("\"","",strtolower($key));
+        
+        //Return LOB value.
+        if (is_object($value)) {
+          //TODO: use OCI-Lob->load instead ?
+          $new_obj->$lower_key = $value->load();
+          /*if ($debug) {
+            print 'name:'.$lower_key.'-value:'.$value->read($value->size()).'<br/>';
+          }*/
+        }
+        else {
+          $new_obj->$lower_key = $value;
+          ///if ($debug) print 'key:'.$lower_key.'-value:'.$value.'<br>';
+        }
+      }
+    }
+    /*if ($debug) {
+      print_r($new_obj);
+    }*/
+    return $new_obj;
+  }
+}
+
+/**
+ * Fetch one result row from the previous query as an array.
+ *
+ * @param $result
+ *   A database query result resource, as returned from db_query().
+ * @return
+ *   An associative array representing the next row of the result. The keys of
+ *   this object are the names of the table fields selected by the query, and
+ *   the values are the field values for this result row.
+ * 
+ * NOTE: - Oracle returns table fields in uppercase, so we convert them into lowercase.
+ */
+function db_fetch_array($result) {
+  if ($result) { 
+    ocifetchinto($result, $array_result, OCI_ASSOC + OCI_RETURN_NULLS + OCI_RETURN_LOBS);
+    if (is_array($array_result)) {
+      return array_change_key_case($array_result, CASE_LOWER);
+    }
+    else {
+      return FALSE;
+    }
+  }
+}
+
+/**
+ * Determine how many result rows were found by the preceding query.
+ *
+ * @param $result
+ *   A database query result resource, as returned from db_query().
+ * @return
+ *   The number of result rows.
+ * 
+ * NOTE: ocirowcount doesn't return the number of lines selected in a SELECT query. It
+ *       cannot be used here. Further, there is no way to implement this function cleanly 
+ *       with an Oracle DB. Oracle stores its query results on the server side, therefore
+ *       the client does not have to download the entire result set when the query is
+ *       executed. However, since the client can not see the entire result set, it cant 
+ *       (from within the client only) determine how many rows were selected. 
+ *
+ *       Unfortunately, the cleanest possible way I could figure out was to have two
+ *       result resources for SELECT statements, one for retrieving data and the other 
+ *       for counting rows. The alternate resource is set above in _db_query. 
+ */
+/*
+function db_num_rows($result) {
+  global $_query_rc_result;
+  $result_rc = $_query_rc_result[$result];
+  if ($result_rc) {
+    // Reset result cursor and count
+    ociexecute($result_rc, OCI_COMMIT_ON_SUCCESS);
+    ocifetchstatement($result_rc,$rows, 0, 1, OCI_FETCHSTATEMENT_BY_ROW);
+    $num_rows = count($rows);
+    return $num_rows;
+  }
+  else {
+    //Just test $result with OCIROWCOUNT (this is appropriate for INSERT/UPDATE/DELETE statements)
+    return ocirowcount($result);
+  }
+}
+ */
+
+/*  db_set_num_rows($result, $result_rc, $mode = 0)
+ *    store number of result row in global array, let db_num_rows() to query
+ *  @param $result
+ *    A database query result resource, as returned from OCIParse().
+ *    Just for array indexing
+ *  @param $result_rc
+ *    A database query result resource, returned from OCIParse()
+ *    The result resource to be counted
+ *  @param $mode
+ *    mode 0 : For SELECT statement
+ *    mode x : For INSERT/UPDATE/DELETE (not used, just placed)
+ *
+ *  NOTE: As the previous version store the entire resource into array,
+ *        in some heavy query page(?q=admin/build/menu)
+ *        it exceeds the limit of maximum cursor in Oracle.
+ *        Instead of adjusting the limit,
+ *        here just store the num_rows of each query,
+ *        instead of the resource itself
+ */
+  
+// -- checkpoint 12 : "helper" function for db_num_rows()
+function db_set_num_rows($result, $result_rc, $mode = 0) {
+  global $_query_rc_result;
+  if (!$mode) {
+    // Reset result cursor and count
+    ociexecute($result_rc, OCI_COMMIT_ON_SUCCESS);
+    // Simply use OCIFetchStatement() to get num_rows
+    $num_rows = OCIFetchStatement($result_rc, $rows);
+//    ocifetchstatement($result_rc, $rows, 0, 1, OCI_FETCHSTATEMENT_BY_ROW);
+//    $num_rows = count($rows);
+    $_query_rc_result[$result] = $num_rows;
+    return $num_rows;
+  } else {
+    //Just test $result with OCIROWCOUNT (this is appropriate for INSERT/UPDATE/DELETE statements)
+    $num_rows = ocirowcount($result_rc);
+    $_query_rc_result[$result] = $num_rows;
+    return $num_rows;
+  }
+}
+// -- end 12
+
+// -- checkpoint 13 : Re-implement num_rows counting
+function db_num_rows($result) {
+  global $_query_rc_result;
+  $num_rows = $_query_rc_result[$result];
+  if ($num_rows) {
+    //-- checkpoint :  numrow for SELECT query is already stored in global array 
+    //                instead of storing resultset
+    return $num_rows;
+  }
+  else {
+    //Just test $result with OCIROWCOUNT (this is appropriate for INSERT/UPDATE/DELETE statements)
+    return ocirowcount($result);
+  }
+}
+// -- end 13
+
+
+/**
+ * Return an individual result field from the previous query.
+ *
+ * Only use this function if exactly one field is being selected; otherwise,
+ * use db_fetch_object() or db_fetch_array().
+ *
+ * @param $result
+ *   A database query result resource, as returned from db_query().
+ * @param $row
+ *   The index of the row whose result is needed.
+ * @return
+ *   The resulting field.
+ */
+function db_result($result, $row = 0) {
+    //First we have to fetch the first row then we return the first column.
+    //TODO: validate the number of rows ? This would generate problems for
+    //      db_next_id query as we need to run query one time to get the number
+    //      of rows, and then run it a second time to get the result, so we will
+    //      "jumped" some id.
+//  while ($row = db_fetch_object($result)) {
+//    print_r($row);
+  //  }
+  // checkpoint 17: ocifetch only fetch the resource link of CLOB
+  //                Use OCIFetchInto to get content instead 
+  //ocifetch($result);
+  //  return ociresult($result, 1);
+  if (@OCIFetchInto($result, $result_row, OCI_NUM+OCI_RETURN_LOBS)) {
+    //var_dump($row);
+    return $result_row[0];
+  }
+    return False;
+}
+
+/**
+ * Determine whether the previous query caused an error.
+ */
+function db_error() {
+  $error = ocierror();
+  return $error['message'];
+}
+
+/**
+ * Return a new unique ID in the given sequence.
+ *
+ * For compatibility reasons, Drupal does not use auto-numbered fields in its
+ * database tables. Instead, this function is used to return a new unique ID
+ * of the type requested. With the Oracle DB implementation, all sequences 
+ * must be created at the time of Oracle scema creation. 
+ */
+function db_next_id($name) {
+  global $active_db;
+  // checkpoint 18: cant use db_query(),
+  //                seq num additionally +2 for each call..
+  //                not know the reason
+//  $id = db_result(db_query("SELECT %s_seq.nextval FROM DUAL", db_prefix_tables($name)));
+  // test only
+  if (strlen($name) > 26) {
+    $name = substr($name, 0, 26);
+  }
+  $name = db_prefix_tables($name);
+  // end test only
+  $result = OCIParse($active_db, "SELECT ".$name."_seq.nextval FROM DUAL");
+  OCIExecute($result, OCI_DEFAULT);
+  $id = db_result($result);
+  return $id;
+}
+
+/**
+ * Determine the number of rows changed by the preceding query.
+ */
+function db_affected_rows() {
+  global $last_result;
+  return ocirowcount($last_result);
+}
+
+/**
+ * Runs a limited-range query in the active database.
+ *
+ * Use this as a substitute for db_query() when a subset of the query is to be
+ * returned.
+ * User-supplied arguments to the query should be passed in as separate parameters
+ * so that they can be properly escaped to avoid SQL injection attacks.
+ *
+ * Note that if you need to know how many results were returned, you should do
+ * a SELECT COUNT(*) on the temporary table afterwards. db_num_rows() and
+ * db_affected_rows() do not give consistent result across different database
+ * types in this case.
+ *
+ * @param $query
+ *   A string containing an SQL query.
+ * @param ...
+ *   A variable number of arguments which are substituted into the query
+ *   using printf() syntax. The query arguments can be enclosed in one
+ *   array instead.
+ *   Valid %-modifiers are: %s, %d, %f, %b (binary data, do not enclose
+ *   in '') and %%.
+ *
+ *   NOTE: using this syntax will cast NULL and FALSE values to decimal 0,
+ *   and TRUE values to decimal 1.
+ *
+ * @param $from
+ *   The first result row to return.
+ * @param $count
+ *   The maximum number of result rows to return.
+ * @return
+ *   A database query result resource, or FALSE if the query was not executed
+ *   correctly.
+ */
+function db_query_range($query) {
+  $args = func_get_args();
+  $count = (int) array_pop($args);
+  $from = (int) array_pop($args);
+  array_shift($args);
+
+  $query = db_prefix_tables($query);
+  if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax
+    $args = $args[0];
+  }
+  _db_query_callback($args, TRUE);
+  $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query);
+  $query = 'SELECT * FROM (SELECT sub.*, rownum AS line FROM ('. $query .') sub) WHERE line BETWEEN '. ($from + 1) .' AND '. ($from + $count);
+  return _db_query($query);
+}
+
+/**
+ * Runs a SELECT query and stores its results in a temporary table.
+ *
+ * Use this as a substitute for db_query() when the results need to stored
+ * in a temporary table. Temporary tables exist for the duration of the page
+ * request.
+ * User-supplied arguments to the query should be passed in as separate parameters
+ * so that they can be properly escaped to avoid SQL injection attacks.
+ *
+ * Note that if you need to know how many results were returned, you should do
+ * a SELECT COUNT(*) on the temporary table afterwards. db_num_rows() and
+ * db_affected_rows() do not give consistent result across different database
+ * types in this case.
+ *
+ * @param $query
+ *   A string containing a normal SELECT SQL query.
+ * @param ...
+ *   A variable number of arguments which are substituted into the query
+ *   using printf() syntax. The query arguments can be enclosed in one
+ *   array instead.
+ *   Valid %-modifiers are: %s, %d, %f, %b (binary data, do not enclose
+ *   in '') and %%.
+ *
+ *   NOTE: using this syntax will cast NULL and FALSE values to decimal 0,
+ *   and TRUE values to decimal 1.
+ *
+ * @param $table
+ *   The name of the temporary table to select into. This name will not be
+ *   prefixed as there is no risk of collision.
+ * @return
+ *   A database query result resource, or FALSE if the query was not executed
+ *   correctly.
+ */
+function db_query_temporary($query) {
+  $args = func_get_args();
+  $tablename = array_pop($args);
+  array_shift($args);
+  _check_table_existance($tablename);
+  $query = preg_replace('/^SELECT/i', 'CREATE GLOBAL TEMPORARY TABLE '. $tablename .' ON COMMIT PRESERVE ROWS AS SELECT ', db_prefix_tables($query));
+  
+  if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax
+    $args = $args[0];
+  }
+  _db_query_callback($args, TRUE);
+  $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query);
+  return _db_query($query);
+}
+
+/**
+ * Returns a properly formatted Binary Large OBject value.
+ *
+ * @param $data
+ *   Data to encode.
+ * @return
+ *  Encoded data.
+ */
+function db_encode_blob($data) {
+  //No processing is needed here, since LOBs in Oracle are input via LOB->Save() and 
+  // dont need any escaping of charecters like \ or '
+  // -- checkpoint 14: Move the modification from
+  //            database.inc to here
+  //            keep database.inc original
+//  return "'" . $data . "'";
+  return "'" . db_escape_string($data) . "'";
+  // -- end 11
+}
+
+/**
+ * Returns text from a Binary Large Object value.
+ *
+ * @param $data
+ *   Data to decode.
+ * @return
+ *  Decoded data.
+ */
+function db_decode_blob($data) {
+  //No processing is needed here, since LOBs in Oracle are read via LOB->Load()
+  return $data;
+}
+
+/**
+ * Prepare user input for use in a database query, preventing SQL injection attacks.
+ */
+function db_escape_string($text) {
+  // Replace any single ' with two ' 
+  return str_replace("'", "''",$text);
+}
+
+/**
+ * Lock a table.
+ */
+function db_lock_table($table) {
+  //TODO: should we put a NOWAIT clause ?
+  db_query('LOCK TABLE {%s} IN EXCLUSIVE MODE', $table);
+}
+
+/**
+ * Unlock all locked tables.
+ */
+function db_unlock_tables() {
+  db_query('COMMIT');
+}
+
+/**
+ * Checks if table exists and if so, drops it
+ */
+function _check_table_existance($tableName) {
+	$tableName = strtoupper($tableName);
+	$sql = 'SELECT table_name FROM user_tables WHERE table_name = \'' . $tableName . '\' ';
+	$result = db_query($sql);
+	$check = db_fetch_object($result);
+	if (is_array($check) && ($check->table_name == $tableName)) {
+		$sql = 'DROP TABLE ' . $tableName;
+		_db_query($sql);
+	}
+}
+
+// -- checkpoint 15 : Oracle version
+/**
+ * Check if a table exists.
+ */
+function db_table_exists($table) {
+  return db_num_rows(db_query("SELECT table_name FROM user_tables WHERE table_name LIKE UPPER('{" . db_escape_table($table) . "}')"));
+}
+// -- end 15
+
+// -- checkpoint 19 : drupal 6 func
+/**
+ * Check if a column exists in the given table.
+ */
+function db_column_exists($table, $column) {
+  return db_num_rows(db_query("SELECT column_name FROM user_tab_cols WHERE table_name LIKE UPPER('{". db_escape_table($table) ."}') AND column_name LIKE UPPER(TRIM('$column'))"));
+}
+// -- end 19
+
+// -- checkpoint 16 : Just copy the func from MySQL
+/**
+ * Wraps the given table.field entry with a DISTINCT(). The wrapper is added to
+ * the SELECT list entry of the given query and the resulting query is returned.
+ * This function only applies the wrapper if a DISTINCT doesn't already exist in
+ * the query.
+ *
+ * @param $table Table containing the field to set as DISTINCT
+ * @param $field Field to set as DISTINCT
+ * @param $query Query to apply the wrapper to
+ * @return SQL query with the DISTINCT wrapper surrounding the given table.field.
+ */
+function db_distinct_field($table, $field, $query) {
+  $field_to_select = 'DISTINCT('. $table .'.'. $field .')';
+  // (?<!text) is a negative look-behind (no need to rewrite queries that already use DISTINCT).
+  return preg_replace('/(SELECT.*)(?:'. $table .'\.|\s)(?<!DISTINCT\()(?<!DISTINCT\('. $table .'\.)'. $field .'(.*FROM )/AUsi', '\1 '. $field_to_select .'\2', $query);
+}
+// -- end 16
+
+/**
+ * @} End of "ingroup database".
+ */
+
+/**
+ * @ingroup schemaapi
+ * @{
+ */
+
+/**
+ * array to keep column be indexed
+ * $_index_list['table_name']['index_fields'] = 1
+ */
+$_index_list = array();
+
+
+/**
+ * This maps a generic data type in combination with its data size
+ * to the engine-specific data type.
+ */
+function db_type_map() {
+  // Put :normal last so it gets preserved by array_flip.  This makes
+  // it much easier for modules (such as schema.module) to map
+  // database types back into schema types.
+  $map = array(
+    'varchar:normal'  => 'VARCHAR2',
+
+    'text:tiny'       => 'VARCHAR2(4000)',
+    'text:small'      => 'VARCHAR2(4000)',
+    'text:medium'     => 'VARCHAR2(4000)',
+    'text:big'        => 'CLOB',
+    'text:normal'     => 'VARCHAR2(4000)',
+
+    'int:tiny'        => 'INTEGER',
+    'int:small'       => 'INTEGER',
+    'int:medium'      => 'INTEGER',
+    'int:big'         => 'INTEGER',
+    'int:normal'      => 'INTEGER',
+
+    'float:tiny'      => 'FLOAT',
+    'float:small'     => 'FLOAT',
+    'float:medium'    => 'FLOAT',
+    'float:big'       => 'DOUBLE PRECISION',
+    'float:normal'    => 'FLOAT',
+
+    'numeric:normal'  => 'NUMERIC',
+
+    // -- checkpoint 03: Use CLOB instead of BLOB (cache)
+    'blob:big'        => 'CLOB',
+//    'blob:big'        => 'BLOB',
+    // -- end 03
+    'blob:normal'     => 'BLOB',
+
+    'datetime:normal' => 'TIMESTAMP',
+
+    'serial:tiny'     => 'INTEGER',
+    'serial:small'    => 'INTEGER',
+    'serial:medium'   => 'INTEGER',
+    'serial:big'      => 'INTEGER',
+    'serial:normal'   => 'INTEGER',
+  );
+  return $map;
+}
+
+/**
+ *  Generate SQL to create sequence for serial field
+ *  
+ *  @param $table
+ *    the tablename that sequence responsibile to
+ *  @param $field
+ *    the fieldname that sequence responsibile to
+ *  
+ *  sequence name:
+ *  {tablename}_fieldname_seq
+ */
+function _db_create_sequence_sql($table, $field) {
+
+  $options = " MINVALUE 1 INCREMENT BY 1 START WITH 1 NOCACHE NOORDER NOCYCLE";
+  // test only
+//  $seq_name  = "{". $table ."}_". $field."_seq";
+  // end test only
+  $seq_name  = "{". $table ."}_". $field;
+  if (strlen($seq_name) > 26) {
+    $seq_name = substr($seq_name, 0, 26);
+  }
+  $seq_name .= "_seq";
+
+  $sql  = "CREATE SEQUENCE ". $seq_name;
+  $sql .= $options;
+  return $sql;
+}
+
+/**
+ *  Generate SQL to create trigger for serial field
+ *  
+ *  @param $table
+ *    the tablename that trigger responsibile to
+ *  @param $field
+ *    the fieldname that trigger responsibile to
+ *  
+ *  sequence name:
+ *  {tablename}_fieldname_seq
+ *  trigger name:
+ *  {tablename}_fieldname_be_in
+ */
+function _db_create_trigger_sql($table, $field) {
+  // test only
+//  $trg_name = "{". $table ."}_".$field."_be_in";
+  // end test only
+  $trg_name = "{". $table ."}_".$field;
+  if (strlen($trg_name) > 24) {
+    $trg_name = substr($trg_name, 0, 24);
+  }
+  $trg_name .= "_be_in";
+
+  // test only
+//  $seq_name  = "{". $table ."}_". $field."_seq";
+  // end test only
+  $seq_name  = "{". $table ."}_". $field;
+  if (strlen($seq_name) > 26) {
+    $seq_name = substr($seq_name, 0, 26);
+  }
+  $seq_name .= "_seq";
+
+  $sql  = "CREATE OR REPLACE TRIGGER ". $trg_name ."\n";
+  $sql .= "BEFORE INSERT ON {". $table ."}\n";
+  $sql .= "FOR EACH ROW\n";
+  $sql .= "BEGIN\n";
+  $sql .= " IF :NEW.".$field." IS NULL THEN\n";
+  $sql .= "   SELECT ".$seq_name.".NEXTVAL\n";
+  $sql .= "   INTO :NEW.".$field."\n";
+  $sql .= "   FROM DUAL;\n";
+  $sql .= " END IF;\n";
+  $sql .= "END\n";
+  $sql .= ";";
+  return $sql;
+}
+
+/**
+ *  Generate SQL to create a new table from a Drupal schema definition.
+ *
+ * @param $table
+ *   A valid Drupal table definition array.
+ * @return $statements
+ *   An array of SQL statements to create the table.
+ *
+ *  $tmp_field_info['sql']      - definition of the field
+ *  $tmp_field_info['isSerial'] - indicate if is a serial type field
+ * 
+ */
+function db_create_table_sql($table) {
+
+  global $_index_list;
+  $sql_fields = array();
+  $sql_keys = array();
+  $seq_trg_SQL = array(); // SQL to create sequence and trigger
+  $returnSQL = array();
+
+  foreach ($table['fields'] as $name => $field) {
+    $tmp_field_info = _db_create_field_sql($name, _db_process_field($field));
+    $sql_fields[] = $tmp_field_info['sql'];
+    if ($tmp_field_info['isSerial']) {
+      $seq_trg_SQL[] = _db_create_sequence_sql($table['name'], $name);
+      $seq_trg_SQL[] = _db_create_trigger_sql($table['name'], $name);
+    }
+  }
+  if (isset($table['primary key']) && is_array($table['primary key'])) {
+    $sql_keys[] = 'PRIMARY KEY ('. implode(', ', $table['primary key']) .')';
+    // record indexed column
+    $_index_table_name = $table['name'];
+    $_index_keys =  str_replace(',','_',(implode(',', $table['primary key'])));
+    $_index_list[$_index_table_name][$_index_keys] = 1;
+  }
+  if (isset($table['unique keys']) && is_array($table['unique keys'])) {
+    foreach ($table['unique keys'] as $keyname => $key) {
+      $sql_keys[] = 'CONSTRAINT {'. $table['name'] .'}_'. $keyname .'_uni UNIQUE ('. implode(', ', $key) .')';
+    }
+  }
+
+  $sql  = "CREATE TABLE {". $table['name'] ."} (\n\t";
+  $sql .= implode(",\n\t", $sql_fields);
+  if (count($sql_keys) > 0) {
+    $sql .= ",\n\t";
+  }
+  $sql .= implode(",\n\t", $sql_keys);
+  $sql .= "\n)";
+  $statements[] = $sql;
+
+  if (isset($table['indexes']) && is_array($table['indexes'])) {
+    foreach ($table['indexes'] as $keyname => $key) {
+      $_index_table_name = $table['name'];
+      $_index_keys = str_replace(', ','_',(_db_create_key_sql($key)));
+      if (!isset($_index_list[$_index_table_name][$_index_keys]) || !($_index_list[$_index_table_name][$_index_keys])) {
+        $statements[] = _db_create_index_sql($table['name'], $keyname, $key);
+      }
+    }
+  }
+
+  if (count($seq_trg_SQL)) {
+    foreach ($seq_trg_SQL AS $key => $value) {
+      $statements[] = $value;
+    }
+  }
+
+  return $statements;
+}
+
+/**
+ *  Generate SQL to create index 
+ *  
+ *  @param $table
+ *    the tablename that index responsibile to
+ *  @param $name
+ *    the index name
+ *  @param $fields
+ *    the field sets that index responsibile to
+ *  
+ *  sequence name:
+ *  {tablename}_fieldname_seq
+ *  trigger name:
+ *  {tablename}_fieldname_be_in
+ */
+function _db_create_index_sql($table, $name, $fields) {
+  // test only
+  $idx_name  = "{". $table ."}_". $name;
+  if (strlen($idx_name) > 26) {
+    $idx_name = substr($idx_name, 0, 26);
+  }
+  $idx_name .= "_idx";
+  $query  = 'CREATE INDEX '. $idx_name . ' ON {'. $table .'} (';
+  // end test only
+//  $query = 'CREATE INDEX {'. $table .'}_'. $name .'_idx ON {'. $table .'} (';
+  $query .= _db_create_key_sql($fields) .')';
+  return $query;
+}
+
+/**
+ *  Implode array of fields from array 
+ *  
+ *  @param $fields
+ *    array of field for indexing
+ *  
+ */
+function _db_create_key_sql($fields) {
+  $ret = array();
+  foreach ($fields as $field) {
+    if (is_array($field)) {
+//      $ret[] = $field[0] .'('. $field[1] .')';
+      $ret[] = 'substr('. $field[0] .', 1, '. $field[1] .')';
+    }
+    else {
+      $ret[] = $field;
+    }
+  }
+  return implode(', ', $ret);
+}
+
+/**
+ * Set database-engine specific properties for a field.
+ *
+ * @param $field
+ *   A field description array, as specified in the schema documentation.
+ */
+function _db_process_field($field) {
+  if (!isset($field['size'])) {
+    $field['size'] = 'normal';
+  }
+  // Set the correct database-engine specific datatype.
+  if (!isset($field['oracle_type'])) {
+    $map = db_type_map();
+    $field['oracle_type'] = $map[$field['type'] .':'. $field['size']];
+  }
+
+  if ($field['type'] == 'serial') {
+    unset($field['not null']);
+  }
+
+  return $field;
+}
+
+/**
+ * Create an SQL string for a field to be used in table creation or alteration.
+ *
+ * Before passing a field out of a schema definition into this function it has
+ * to be processed by _db_process_field().
+ *
+ * @param $name
+ *    Name of the field.
+ * @param $spec
+ *    The field specification, as per the schema data structure format.
+ * ret: array ( isSerial : hint to tell is a serial, need create sequence and trigger
+ *              sql : field information )
+ */
+function _db_create_field_sql($name, $spec) {
+
+  $returnAry = array();
+  $returnAry['isSerial'] = 0;
+
+  $sql = $name .' '. $spec['oracle_type'];
+
+  if ($spec['type'] == 'serial') {
+    unset($spec['not null']);
+    $returnAry['isSerial'] = 1;
+  }
+  // -- checkpoint 02: no 'NOT NULL' for VARCHAR2 and CLOB in Oracle
+  if (($spec['type'] == 'text') || ($spec['type'] == 'varchar') || ($spec['type'] == 'blob')) {
+    unset($spec['not null']);
+  }
+  // -- end 02
+
+  // Lun check 04 - Oracle no UNSIGNED
+  /*
+  if (!empty($spec['unsigned'])) {
+    $sql .= ' unsigned';
+  }
+   */
+  if (isset($spec['length'])) {
+    $sql .= '('. $spec['length'] .')';
+  }
+  elseif (isset($spec['precision']) && isset($spec['scale'])) {
+    $sql .= '('. $spec['scale'] .', '. $spec['precision'] .')';
+  }
+
+  // -- checkpoint 01: DEFAULT before NOT NULL in Oracle
+  if (isset($spec['default'])) {
+    $default = is_string($spec['default']) ? "'". $spec['default'] ."'" : $spec['default'];
+    $sql .= " DEFAULT $default";
+  }
+
+  if (isset($spec['not null']) && $spec['not null']) {
+    $sql .= ' NOT NULL';
+  }
+  // -- end 01
+
+  $returnAry['sql'] = $sql;
+
+  return $returnAry;
+}
+
+/**
+ * Drop a table.
+ *
+ * @param $ret
+ *   Array to which query results will be added.
+ * @param $table
+ *   The table to be dropped.
+ */
+function db_drop_table(&$ret, $table) {
+  $ret[] = update_sql('DROP TABLE {'. $table .'} CASCADE CONSTRAINTS');
+}
+
+/**
+ * Add a new field to a table.
+ *
+ * @param $ret
+ *   Array to which query results will be added.
+ * @param $table
+ *   Name of the table to be altered.
+ * @param $field
+ *   Name of the field to be added.
+ * @param $spec
+ *   The field specification array, as taken from a schema definition
+ */
+function db_add_field(&$ret, $table, $field, $spec) {
+  $query = 'ALTER TABLE {'. $table .'} ADD ';
+  $tmp_field_info = _db_create_field_sql($field, _db_process_field($spec));
+  $query .= $tmp_field_info['sql'];
+  $ret[] = update_sql($query);
+}
+
+/**
+ * Drop a field.
+ *
+ * @param $ret
+ *   Array to which query results will be added.
+ * @param $table
+ *   The table to be altered.
+ * @param $field
+ *   The field to be dropped.
+ */
+function db_drop_field(&$ret, $table, $field) {
+  $ret[] = update_sql('ALTER TABLE {'. $table .'} DROP COLUMN '. $field);
+}
+
+/**
+ * Set the default value for a field.
+ *
+ * @param $ret
+ *   Array to which query results will be added.
+ * @param $table
+ *   The table to be altered.
+ * @param $field
+ *   The field to be altered.
+ * @param $default
+ *   Default value to be set. NULL for 'default NULL'.
+ */
+function db_field_set_default(&$ret, $table, $field, $default) {
+  if ($default == NULL) {
+    $default = 'NULL';
+  }
+  else {
+    $default = is_string($default) ? "'$default'" : $default;
+  }
+
+  $ret[] = update_sql('ALTER TABLE {'. $table .'} MODIFY ('. $field .' DEFAULT '. $default . ')');
+}
+
+/**
+ * Set a field to have no default value.
+ *
+ * @param $ret
+ *   Array to which query results will be added.
+ * @param $table
+ *   The table to be altered.
+ * @param $field
+ *   The field to be altered.
+ */
+function db_field_set_no_default(&$ret, $table, $field) {
+  $ret[] = update_sql('ALTER TABLE {'. $table .'} MODIFY ('. $field .' DEFAULT NULL'.')');
+}
+
+/**
+ * Add a primary key.
+ *
+ * @param $ret
+ *   Array to which query results will be added.
+ * @param $table
+ *   The table to be altered.
+ * @param $fields
+ *   Fields for the primary key.
+ */
+function db_add_primary_key(&$ret, $table, $fields) {
+  $name = '{'. $table .'}_pk';
+  $ret[] = update_sql('ALTER TABLE {'. $table .'} ADD CONSTRAINT ' . $name . ' PRIMARY KEY ('.
+    implode(',', $fields) .')');
+}
+
+/**
+ * Drop the primary key.
+ *
+ * @param $ret
+ *   Array to which query results will be added.
+ * @param $table
+ *   The table to be altered.
+ */
+function db_drop_primary_key(&$ret, $table) {
+  $name = '{'. $table .'}_pk';
+  $ret[] = update_sql('ALTER TABLE {'. $table .'} DROP CONSTRAINT ' . $name);
+}
+
+/**
+ * Add a unique key.
+ *
+ * @param $ret
+ *   Array to which query results will be added.
+ * @param $table
+ *   The table to be altered.
+ * @param $name
+ *   The name of the key.
+ * @param $fields
+ *   An array of field names.
+ */
+function db_add_unique_key(&$ret, $table, $name, $fields) {
+  $name = "{". $table ."}_".$name."_uni";
+  $ret[] = update_sql('ALTER TABLE {'. $table .'} ADD CONSTRAINT '. 
+    $name .' UNIQUE ('. implode(',', $fields) .')');
+}
+
+/**
+ * Drop a unique key.
+ *
+ * @param $ret
+ *   Array to which query results will be added.
+ * @param $table
+ *   The table to be altered.
+ * @param $name
+ *   The name of the key.
+ */
+function db_drop_unique_key(&$ret, $table, $name) {
+  $name = "{". $table ."}_".$name."_uni";
+  $ret[] = update_sql('ALTER TABLE {'. $table .'} DROP CONSTRAINT '. $name);
+}
+
+/**
+ * Add an index.
+ *
+ * @param $ret
+ *   Array to which query results will be added.
+ * @param $table
+ *   The table to be altered.
+ * @param $name
+ *   The name of the index.
+ * @param $fields
+ *   An array of field names.
+ */
+function db_add_index(&$ret, $table, $name, $fields) {
+  $_index_table_name = $table['name'];
+  $_index_keys = str_replace(', ','_',(_db_create_key_sql($fields)));
+  if (!isset($_index_list[$_index_table_name][$_index_keys]) || !($_index_list[$_index_table_name][$_index_keys])) {
+    $ret[] = update_sql(_db_create_index_sql($table, $name, $fields));
+  }
+}
+
+/**
+ * Drop an index.
+ *
+ * @param $ret
+ *   Array to which query results will be added.
+ * @param $table
+ *   The table to be altered.
+ * @param $name
+ *   The name of the index.
+ */
+function db_drop_index(&$ret, $table, $name) {
+  $name = '{'. $table .'}_'. $name .'_idx';
+  $ret[] = update_sql('DROP INDEX '. $name);
+}
+
+/**
+ * Change a field definition.
+ *
+ * @param $ret
+ *   Array to which query results will be added.
+ * @param $table
+ *   Name of the table.
+ * @param $field
+ *   Name of the field to change.
+ * @param $field_new
+ *   New name for the field (set to the same as $field if you don't want to change the name).
+ * @param $spec
+ *   The field specification for the new field.
+ */
+function db_change_field(&$ret, $table, $field, $field_new, $spec) {
+  if ($field == $field_new) {
+    $mid_field = $field ."_old";
+    $ret[] = update_sql("ALTER TABLE {". $table ."} RENAME COLUMN $field TO ". $mid_field);
+  } else {
+    $mid_field = $field;
+  }
+  
+  $not_null = isset($spec['not null']) ? $spec['not null'] : FALSE;
+  db_add_field($ret, $table, $field_new, $spec);
+  $ret[] = update_sql("UPDATE {". $table ."} SET $field_new = ". $mid_field);
+  if ($not_null) {
+    $ret[] = update_sql("ALTER TABLE {". $table ."} MODIFY ($field_new NOT NULL)");
+  }
+  db_drop_field($ret, $table, $mid_field);
+}
+
+/**
+ * Update a field definition to match its schema. If the field is
+ * involved in any keys or indexes, recreate them.
+ *
+ * @param $ret
+ *   Array to which query results will be added.
+ * @param $table
+ *   Name of the table.
+ * @param $field
+ *   Name of the field to update.
+ */
+function db_update_field(&$ret, $table, $field) {
+  $spec = drupal_get_schema($table);
+
+  db_change_field($ret, $table, $field, $field, $spec['fields'][$field]);
+  if (isset($spec['primary key'])) {
+    if (array_search($field, db_field_names($spec['primary key'])) !== FALSE) {
+      db_add_primary_key($ret, $table, $spec['primary key']);
+    }
+  }
+  if (isset($spec['unique keys'])) {
+    foreach ($spec['unique keys'] as $name => $fields) {
+      if (array_search($field, db_field_names($fields)) !== FALSE) {
+        db_add_unique_key($ret, $table, $fields);
+      }
+    }
+  }
+  if (isset($spec['indexes'])) {
+    foreach ($spec['indexes'] as $name => $fields) {
+      if (array_search($field, db_field_names($fields)) !== FALSE) {
+        db_add_index($ret, $table, $fields);
+      }
+    }
+  }
+}
+
+/**
+ * @} End of "ingroup schemaapi".
+ */
+
diff -urpN drupal-6.x-dev-200705302348/includes/install.inc drupal-6.x-dev/includes/install.inc
--- drupal-6.x-dev-200705302348/includes/install.inc	2007-05-21 18:56:05.000000000 +0800
+++ drupal-6.x-dev/includes/install.inc	2007-05-30 23:57:05.000000000 +0800
@@ -144,7 +144,7 @@ function drupal_detect_baseurl($file = '
 function drupal_detect_database_types() {
   $databases = array();
 
-  foreach (array('mysql', 'mysqli', 'pgsql') as $type) {
+  foreach (array('mysql', 'mysqli', 'pgsql', 'oracle') as $type) {
     if (file_exists('./includes/install.'. $type .'.inc')) {
       include_once './includes/install.'. $type .'.inc';
       $function = $type .'_is_available';
diff -urpN drupal-6.x-dev-200705302348/includes/install.oracle.inc drupal-6.x-dev/includes/install.oracle.inc
--- drupal-6.x-dev-200705302348/includes/install.oracle.inc	1970-01-01 08:00:00.000000000 +0800
+++ drupal-6.x-dev/includes/install.oracle.inc	2007-05-31 00:31:59.000000000 +0800
@@ -0,0 +1,194 @@
+<?php
+// $Id$
+
+// ORACLE specific install functions
+
+/**
+ * Check if oracle is available.
+ *
+ * @return
+ *  TRUE/FALSE
+ */
+function oracle_is_available() {
+  return function_exists('oci_connect');
+}
+
+/**
+ * Check if we can connect to Oracle.
+ *
+ * @return
+ *  TRUE/FALSE
+ */
+function drupal_test_oracle($url, &$success) {
+
+  if (!oracle_is_available()) {
+    drupal_set_message(st('PHP OCI8 support not enabled.'), 'error');
+    return FALSE;
+  }
+
+  $url = parse_url($url);
+
+  // Decode url-encoded information in the db connection string.
+  $url['user'] = urldecode($url['user']);
+  $url['pass'] = urldecode($url['pass']);
+  $url['host'] = urldecode($url['host']);
+  $url['path'] = urldecode($url['path']);
+
+  // Allow for non-standard Oracle port.
+  if (isset($url['port'])) {
+     $url['host'] = $url['host'] .':'. $url['port'];
+  }
+
+  // Setup connection string for Oracle.
+  $tmp_path = explode('/', substr($url['path'], 1));
+  $url['charset'] = $tmp_path[1];
+  $url['path'] = "/" . $tmp_path[0];
+  $conn_string = '//'.$url['host'].'/'.substr($url['path'], 1);
+
+  // Test connecting to the database.
+  if (isset($url['charset']) && $url['charset']) {
+    $connection = @oci_connect($url['user'], $url['pass'], $conn_string, $url['charset']);
+  } else {
+    $connection = @oci_connect($url['user'], $url['pass'], $conn_string);
+  }
+  if (!$connection && ($error = oci_error())) {
+    drupal_set_message(st('Failure to connect to your Oracle database server. Oracle reports the following message: %error.<ul><li>Are you sure you have the correct username and password?</li><li>Are you sure that you have typed the correct database hostname?</li><li>Are you sure that the database server is running?</li><li>Are you sure you typed the correct database name?</li></ul>For more help, see the <a href="http://drupal.org/node/258">Installation and upgrading handbook</a>. If you are unsure what these terms mean you should probably contact your hosting provider.<br />Error: '.$error, array('%error' => 'Connection failed. See log file for failure reason')), 'error');
+    return FALSE;
+  }
+
+  $success = array('CONNECT');
+
+  // Test CREATE.
+  $query = 'CREATE TABLE drupal_install_test (id integer NOT NULL)';
+  $stmt = @OCIParse($connection, $query);
+  if (!$stmt && ($error = oci_error($connection))) {
+    drupal_set_message(st('We were unable to create a test table on your Oracle database server with the command %query. Oracle reports the following message: %error.<ul><li>Are you sure the configured username has the necessary Oracle permissions to create tables in the database?</li></ul>For more help, see the <a href="http://drupal.org/node/258">Installation and upgrading handbook</a>. If you are unsure what these terms mean you should probably contact your hosting provider.', array('%query' => $query, '%error' => $error)), 'error');
+    return FALSE;
+  }
+  $result = @OCIExecute($stmt);
+  $err = FALSE;
+  $success[] = 'SELECT';
+  $success[] = 'CREATE';
+
+  // Test INSERT.
+  $query = 'INSERT INTO drupal_install_test (id) VALUES (1)';
+  $stmt = @OCIParse($connection, $query);
+  $result = @OCIExecute($stmt);
+  if ($error = oci_error($stmt)) {
+    drupal_set_message(st('We were unable to insert a value into a test table on your Oracle database server. We tried inserting a value with the command %query and Oracle reported the following error: %error.', array('%query' => $query, '%error' => $error)), 'error');
+    $err = TRUE;
+  }
+  else {
+    $success[] = 'INSERT';
+  }
+
+  // Test UPDATE.
+  $query = 'UPDATE drupal_install_test SET id = 2';
+  $stmt = @OCIParse($connection, $query);
+  $result = @OCIExecute($stmt);
+  if ($error = oci_error($stmt)) {
+    drupal_set_message(st('We were unable to update a value in a test table on your Oracle database server. We tried updating a value with the command %query and Oracle reported the following error: %error.', array('%query' => $query, '%error' => $error)), 'error');
+    $err = TRUE;
+  }
+  else {
+    $success[] = 'UPDATE';
+  }
+
+  // Test LOCK.
+  $query = 'LOCK TABLE drupal_install_test IN EXCLUSIVE MODE';
+  $stmt = @OCIParse($connection, $query);
+  $result = @OCIExecute($stmt);
+  if ($error = oci_error($stmt)) {
+    drupal_set_message(st('We were unable to lock a test table on your Oracle database server. We tried locking a table with the command %query and Oracle reported the following error: %error.', array('%query' => $query, '%error' => $error)), 'error');
+    $err = TRUE;
+  }
+  else {
+    $success[] = 'LOCK';
+  }
+ 
+  // Test UNLOCK, which is done automatically upon transaction end in Oracle
+  $query = 'COMMIT';
+  $stmt = @OCIParse($connection, $query);
+  $result = @OCIExecute($stmt);
+  if ($error = oci_error($stmt)) {
+    drupal_set_message(st('We were unable to unlock a test table on your Oracle database server. We tried unlocking a table with the command %query and Oracle reported the following error: %error.', array('%query' => $query, '%error' => $error)), 'error');
+    $err = TRUE;
+  }
+  else {
+    $success[] = 'UNLOCK';
+  }
+
+  // Test DELETE.
+  $query = 'DELETE FROM drupal_install_test';
+  $stmt = @OCIParse($connection, $query);
+  $result = @OCIExecute($stmt);
+  if ($error = oci_error($stmt)) {
+    drupal_set_message(st('We were unable to delete a value from a test table on your Oracle database server. We tried deleting a value with the command %query and Oracle reported the following error: %error.', array('%query' => $query, '%error' => $error)), 'error');
+    $err = TRUE;
+  }
+  else {
+    $success[] = 'DELETE';
+  }
+
+  // Test DROP.
+  $query = 'DROP TABLE drupal_install_test';
+  $stmt = @OCIParse($connection, $query);
+  $result = @OCIExecute($stmt);
+  if ($error = oci_error($stmt)) {
+    drupal_set_message(st('We were unable to drop a test table from your Oracle database server. We tried dropping a table with the command %query and Oracle reported the following error %error.', array('%query' => $query, '%error' => $error)), 'error');
+    $err = TRUE;
+  }
+  else {
+    $success[] = 'DROP';
+  }
+
+  // CREATE FUNCTION from_unixtime()
+  $query = "CREATE OR REPLACE FUNCTION from_unixtime(sttTime number)
+        RETURN date IS
+        BEGIN
+          RETURN to_date(19700101, 'yyyymmdd') + sttTime/24/60/60;
+        END
+        ;";
+  $stmt = @OCIParse($connection, $query);
+  $result = @OCIExecute($stmt);
+  if ($error = oci_error($stmt)) {
+    drupal_set_message(st('We were unable to drop a test table from your Oracle database server. We tried dropping a table with the command %query and Oracle reported the following error %error.', array('%query' => $query, '%error' => $error)), 'error');
+    $err = TRUE;
+  }
+
+  // CREATE FUNCTION to_unixtime()
+  $query = "CREATE OR REPLACE FUNCTION to_unixtime(oracleDate date)
+        RETURN number IS
+        BEGIN
+          RETURN (oracleDate - to_date(19700101, 'yyyymmdd'))*24*60*60;
+        END
+        ;";
+  $stmt = @OCIParse($connection, $query);
+  $result = @OCIExecute($stmt);
+  if ($error = oci_error($stmt)) {
+    drupal_set_message(st('We were unable to drop a test table from your Oracle database server. We tried dropping a table with the command %query and Oracle reported the following error %error.', array('%query' => $query, '%error' => $error)), 'error');
+    $err = TRUE;
+  }
+
+  // CREATE FUNCTION POW()
+  $query = "CREATE OR REPLACE FUNCTION POW(base_num IN number, pow_num IN number)
+        RETURN number IS
+        BEGIN
+          RETURN POWER(base_num, pow_num);
+        END
+        ;";
+  $stmt = @OCIParse($connection, $query);
+  $result = @OCIExecute($stmt);
+  if ($error = oci_error($stmt)) {
+    drupal_set_message(st('We were unable to drop a test table from your Oracle database server. We tried dropping a table with the command %query and Oracle reported the following error %error.', array('%query' => $query, '%error' => $error)), 'error');
+    $err = TRUE;
+  }
+
+  if ($err) {
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+?>
