Fixed some Oracle-specific installer and Strict Standards issues
[lhc/web/wiklou.git] / includes / db / DatabaseOracle.php
index c2df310..f1d90ac 100644 (file)
@@ -33,7 +33,21 @@ class ORAResult {
        private $nrows;
 
        private $unique;
-
+       private function array_unique_md($array_in) {  
+               $array_out = array();
+               $array_hashes = array();
+
+               foreach($array_in as $key => $item) {  
+                       $hash = md5(serialize($item));  
+                       if (!isset($array_hashes[$hash])) {  
+                               $array_hashes[$hash] = $hash;  
+                               $array_out[] = $item;
+                       }  
+               }  
+               
+               return $array_out;  
+       }
+       
        function __construct(&$db, $stmt, $unique = false) {
                $this->db =& $db;
 
@@ -44,7 +58,7 @@ class ORAResult {
                }
 
                if ($unique) {
-                       $this->rows = array_unique($this->rows);
+                       $this->rows = $this->array_unique_md($this->rows);
                        $this->nrows = count($this->rows);
                }
 
@@ -162,6 +176,7 @@ class DatabaseOracle extends DatabaseBase {
        var $mAffectedRows;
 
        var $ignore_DUP_VAL_ON_INDEX = false;
+       var $sequenceData = null;
 
        function DatabaseOracle($server = false, $user = false, $password = false, $dbName = false,
                $failFunction = false, $flags = 0, $tablePrefix = 'get from global' )
@@ -193,8 +208,7 @@ class DatabaseOracle extends DatabaseBase {
                return true;
        }
 
-       static function newFromParams( $server = false, $user = false, $password = false, $dbName = false,
-               $failFunction = false, $flags = 0)
+       static function newFromParams( $server, $user, $password, $dbName, $failFunction = false, $flags = 0 )
        {
                return new DatabaseOracle( $server, $user, $password, $dbName, $failFunction, $flags );
        }
@@ -274,7 +288,9 @@ class DatabaseOracle extends DatabaseBase {
                $union_unique = (preg_match('/\/\* UNION_UNIQUE \*\/ /', $sql) != 0);
                //EXPLAIN syntax in Oracle is EXPLAIN PLAN FOR and it return nothing
                //you have to select data from plan table after explain
+               $olderr = error_reporting(E_ERROR);
                $explain_id = date('dmYHis');
+               error_reporting($olderr);
                $sql = preg_replace('/^EXPLAIN /', 'EXPLAIN PLAN SET STATEMENT_ID = \''.$explain_id.'\' FOR', $sql, 1, $explain_count);
                        
                
@@ -431,33 +447,30 @@ class DatabaseOracle extends DatabaseBase {
                $first = true;
                foreach ($row as $col => $val) {
                        if ($first)
-                               $sql .= ':'.$col;
+                               $sql .= $val !== NULL ? ':'.$col : 'NULL';
                        else
-                               $sql.= ', :'.$col;
+                               $sql .= $val !== NULL ? ', :'.$col : ', NULL';
                        
                        $first = false;
                }
                $sql .= ')';
 
-               $stmt = oci_parse($this->mConn, $sql);
-               foreach ($row as $col => $val) {
-                       if (!is_object($val)) {
-                               if (oci_bind_by_name($stmt, ":$col", $row[$col]) === false)
-                                       $this->reportQueryError($this->lastErrno(), $this->lastError(), $sql, __METHOD__);
-                       }
-               }
                
                $stmt = oci_parse($this->mConn, $sql);
-               foreach ($row as $col => $val) {
+               foreach ($row as $col => &$val) {
                        $col_type=$this->fieldInfo($this->tableName($table), $col)->type();
-                       if ($col_type != 'BLOB' && $col_type != 'CLOB') {
+                       
+                       if ($val === NULL) {
+                               // do nothing ... null was inserted in statement creation
+                       } elseif ($col_type != 'BLOB' && $col_type != 'CLOB') {
                                if (is_object($val))
                                        $val = $val->getData();
-                               
+                       
                                if (preg_match('/^timestamp.*/i', $col_type) == 1 && strtolower($val) == 'infinity') 
                                        $val = '31-12-2030 12:00:00.000000';
                                
-                               if (oci_bind_by_name($stmt, ":$col", $wgLang->checkTitleEncoding($val)) === false)
+                               $val = $wgLang->checkTitleEncoding($val);
+                               if (oci_bind_by_name($stmt, ":$col", $val) === false)
                                        $this->reportQueryError($this->lastErrno(), $this->lastError(), $sql, __METHOD__);
                        } else {
                                if (($lob[$col] = oci_new_descriptor($this->mConn, OCI_D_LOB)) === false) {
@@ -474,7 +487,7 @@ class DatabaseOracle extends DatabaseBase {
                                }
                        }
                }
-               
+
                $olderr = error_reporting(E_ERROR);
                if (oci_execute($stmt, OCI_DEFAULT) === false) {
                        $e = oci_error($stmt);
@@ -512,6 +525,16 @@ class DatabaseOracle extends DatabaseBase {
                } else {
                        $srcTable = $this->tableName( $srcTable );
                }
+               
+               if (($sequenceData = $this->getSequenceData($destTable)) !== false &&
+                               !isset($varMap[$sequenceData['column']]))
+                       $varMap[$sequenceData['column']] = 'GET_SEQUENCE_VALUE(\''.$sequenceData['sequence'].'\')';
+               
+               // count-alias subselect fields to avoid abigious definition errors
+               $i=0;
+               foreach($varMap as $key=>&$val)
+                       $val=$val.' field'.($i++);
+               
                $sql = "INSERT INTO $destTable (" . implode( ',', array_keys( $varMap ) ) . ')' .
                        " SELECT $startOpts " . implode( ',', $varMap ) .
                        " FROM $srcTable $useIndex ";
@@ -519,12 +542,12 @@ class DatabaseOracle extends DatabaseBase {
                        $sql .= ' WHERE ' . $this->makeList( $conds, LIST_AND );
                }
                $sql .= " $tailOpts";
-
+               
                if (in_array('IGNORE', $insertOptions)) 
                        $this->ignore_DUP_VAL_ON_INDEX = true;
-
+               
                $retval = $this->query( $sql, $fname );
-
+               
                if (in_array('IGNORE', $insertOptions))
                        $this->ignore_DUP_VAL_ON_INDEX = false;
                
@@ -590,11 +613,19 @@ class DatabaseOracle extends DatabaseBase {
        }
 
        /**
-        * Oracle does not have a "USE INDEX" clause, so return an empty string
+        * Return sequence_name if table has a sequence
         */
-       function useIndexClause($index) {
-               return '';
+       function getSequenceData($table) {
+               if ($this->sequenceData == NULL) {
+                       $result = $this->query("SELECT lower(us.sequence_name), lower(utc.table_name), lower(utc.column_name) from user_sequences us, user_tab_columns utc where us.sequence_name = utc.table_name||'_'||utc.column_name||'_SEQ'");
+                       
+                       while(($row = $result->fetchRow()) !== false)
+                               $this->sequenceData[$this->tableName($row[1])] = array('sequence' => $row[0], 'column' => $row[2]);
+               }
+               
+               return (isset($this->sequenceData[$table])) ? $this->sequenceData[$table] : false;
        }
+       
 
        # REPLACE query wrapper
        # Oracle simulates this with a DELETE followed by INSERT
@@ -687,35 +718,18 @@ class DatabaseOracle extends DatabaseBase {
                return $size;
        }
 
-       function lowPriorityOption() {
-               return '';
-       }
-
-       function limitResult($sql, $limit, $offset) {
+       function limitResult( $sql, $limit, $offset=false ) {
                if ($offset === false)
                        $offset = 0;
                return "SELECT * FROM ($sql) WHERE rownum >= (1 + $offset) AND rownum < (1 + $limit + $offset)";
        }
 
 
-       function unionQueries($sqls, $all = false) {
+       function unionQueries($sqls, $all) {
                $glue = ' UNION ALL ';
                return 'SELECT * '.($all?'':'/* UNION_UNIQUE */ ').'FROM ('.implode( $glue, $sqls ).')' ;
        }
 
-       /**
-        * Returns an SQL expression for a simple conditional.
-        * Uses CASE on Oracle
-        *
-        * @param $cond String: SQL expression which will result in a boolean value
-        * @param $trueVal String: SQL expression to return if true
-        * @param $falseVal String: SQL expression to return if false
-        * @return String: SQL fragment
-        */
-       function conditional( $cond, $trueVal, $falseVal ) {
-               return " (CASE WHEN $cond THEN $trueVal ELSE $falseVal END) ";
-       }
-
        function wasDeadlock() {
                return $this->lastErrno() == 'OCI-00060';
        }
@@ -785,7 +799,7 @@ class DatabaseOracle extends DatabaseBase {
         * Query whether a given column exists in the mediawiki schema
         * based on prebuilt table to simulate MySQL field info and keep query speed minimal
         */
-       function fieldExists( $table, $field ) {
+       function fieldExists( $table, $field, $fname = 'DatabaseOracle::fieldExists' ) {
                if (!isset($this->fieldInfo_stmt))
                        $this->fieldInfo_stmt = oci_parse($this->mConn, 'SELECT * FROM wiki_field_info_full WHERE table_name = upper(:tab) and column_name = UPPER(:col)');
 
@@ -805,7 +819,8 @@ class DatabaseOracle extends DatabaseBase {
                if (!isset($this->fieldInfo_stmt))
                        $this->fieldInfo_stmt = oci_parse($this->mConn, 'SELECT * FROM wiki_field_info_full WHERE table_name = upper(:tab) and column_name = UPPER(:col)');
 
-               oci_bind_by_name($this->fieldInfo_stmt, ':tab', trim($table, '"'));
+               $table = trim($table, '"');
+               oci_bind_by_name($this->fieldInfo_stmt, ':tab', $table);
                oci_bind_by_name($this->fieldInfo_stmt, ':col', $field);
 
                if (oci_execute($this->fieldInfo_stmt, OCI_DEFAULT) === false) {
@@ -905,7 +920,7 @@ class DatabaseOracle extends DatabaseBase {
                global $wgVersion, $wgDBmwschema, $wgDBts2schema, $wgDBport, $wgDBuser;
                
                echo "<li>Creating DB objects</li>\n";
-               $res = dbsource( "../maintenance/ora/tables.sql", $this);
+               $res = $this->sourceFile( "../maintenance/ora/tables.sql" );
                
                // Avoid the non-standard "REPLACE INTO" syntax
                echo "<li>Populating table interwiki</li>\n";
@@ -950,11 +965,6 @@ class DatabaseOracle extends DatabaseBase {
                return $s;
        }
 
-       /* For now, does nothing */
-       function selectDB( $db ) {
-               return true;
-       }
-
        function selectRow( $table, $vars, $conds, $fname = 'DatabaseOracle::selectRow', $options = array(), $join_conds = array() ) {
                if (is_array($table)) 
                        foreach ($table as $tab)
@@ -1001,39 +1011,19 @@ class DatabaseOracle extends DatabaseBase {
                return array( $startOpts, $useIndex, $preLimitTail, $postLimitTail );
        }
 
-       /* redundand ... will remove after confirming bitwise operations functionality
-       public function makeList( $a, $mode = LIST_COMMA ) {
-               if ( !is_array( $a ) ) {
-                       throw new DBUnexpectedError( $this, 'DatabaseOracle::makeList called with incorrect parameters' );
-               }
-               $a2 = array();
-               foreach ($a as $key => $value) {
-                       if (strpos($key, ' & ') !== FALSE)
-                               $a2[preg_replace('/(.*)\s&\s(.*)/', 'BITAND($1, $2)', $key)] = $value;
-                       elseif (strpos($key, ' | ') !== FALSE)
-                               $a2[preg_replace('/(.*)\s|\s(.*)/', 'BITOR($1, $2)', $key)] = $value;
-                       elseif (!is_array($value)) {
-                               if (strpos($value, ' = ') !== FALSE) {
-                                       if (strpos($value, ' & ') !== FALSE)
-                                               $a2[$key] = preg_replace('/(.*)\s&\s(.*?)\s=\s(.*)/', 'BITAND($1, $2) = $3', $value);
-                                       elseif (strpos($value, ' | ') !== FALSE)
-                                               $a2[$key] = preg_replace('/(.*)\s|\s(.*?)\s=\s(.*)/', 'BITOR($1, $2) = $3', $value);
-                                       else $a2[$key] = $value;
-                               } 
-                               elseif (strpos($value, ' & ') !== FALSE)
-                                       $a2[$key] = preg_replace('/(.*)\s&\s(.*)/', 'BITAND($1, $2)', $value);
-                               elseif (strpos($value, ' | ') !== FALSE)
-                                       $a2[$key] = preg_replace('/(.*)\s|\s(.*)/', 'BITOR($1, $2)', $value);
-                               else
-                                       $a2[$key] = $value;
-                       }
+       public function delete( $table, $conds, $fname = 'DatabaseOracle::delete' ) {
+
+               $conds2 = array();
+               foreach($conds as $col=>$val) {
+                       $col_type=$this->fieldInfo($this->tableName($table), $col)->type();
+                       if ($col_type == 'CLOB')
+                               $conds2['TO_CHAR('.$col.')'] = $val;
                        else
-                               $a2[$key] = $value;
+                               $conds2[$col] = $val;
                }
 
-               return parent::makeList($a2, $mode);
+               return parent::delete( $table, $conds2, $fname );
        }
-       */
 
        function bitNot($field) {
                //expecting bit-fields smaller than 4bytes
@@ -1048,15 +1038,6 @@ class DatabaseOracle extends DatabaseBase {
                return 'BITOR('.$fieldLeft.', '.$fieldRight.')';
        }
 
-       public function setTimeout( $timeout ) {
-               // @todo fixme no-op
-       }
-
-       function ping() {
-               wfDebug( "Function ping() not written for DatabaseOracle.php yet");
-               return true;
-       }
-
        /**
         * How lagged is this slave?
         *
@@ -1098,21 +1079,7 @@ class DatabaseOracle extends DatabaseBase {
                return parent::replaceVars($ins);
        }
 
-       /** 
-        * No-op lock functions
-        */
-       public function lock( $lockName, $method ) {
-               return true;
-       }
-       public function unlock( $lockName, $method ) {
-               return true;
-       }
-       
        public function getSearchEngine() {
                return "SearchOracle";
        }
-
-       /** No-op */
-       public function setBigSelects( $value = true ) {}
-
 } // end DatabaseOracle class