Fix for bug 13004, in which the Postgres full-text search has too many results,
[lhc/web/wiklou.git] / includes / DatabaseOracle.php
index 7f3601b..3848548 100644 (file)
@@ -2,8 +2,8 @@
 
 /**
  * This is the Oracle database abstraction layer.
+ * @addtogroup Database
  */
-
 class ORABlob {
        var $mData;
 
@@ -14,12 +14,13 @@ class ORABlob {
        function getData() {
                return $this->mData;
        }
-};
+}
 
-/*
+/**
  * The oci8 extension is fairly weak and doesn't support oci_num_rows, among 
  * other things.  We use a wrapper class to handle that and other 
  * Oracle-specific bits, like converting column names back to lowercase.
+ * @addtogroup Database
  */
 class ORAResult {
        private $rows;
@@ -32,7 +33,7 @@ class ORAResult {
                $this->db =& $db;
                if (($this->nrows = oci_fetch_all($stmt, $this->rows, 0, -1, OCI_FETCHSTATEMENT_BY_ROW | OCI_NUM)) === false) {
                        $e = oci_error($stmt);
-                       $db->reportQueryError('', $e['message'], $e['code']);
+                       $db->reportQueryError($e['message'], $e['code'], '', __FUNCTION__);
                        return;
                }
 
@@ -83,8 +84,11 @@ class ORAResult {
                }
                return $ret;
        }
-};
+}
 
+/**
+ * @addtogroup Database
+ */
 class DatabaseOracle extends Database {
        var $mInsertId = NULL;
        var $mLastResult = NULL;
@@ -104,22 +108,29 @@ class DatabaseOracle extends Database {
                }
                $this->mOut =& $wgOut;
                $this->mFailFunction = $failFunction;
-               $this->mCascadingDeletes = true;
-               $this->mCleanupTriggers = true;
-               $this->mStrictIPs = true;
                $this->mFlags = $flags;
                $this->open( $server, $user, $password, $dbName);
 
        }
 
+       function cascadingDeletes() {
+               return true;
+       }
+       function cleanupTriggers() {
+               return true;
+       }
+       function strictIPs() {
+               return true;
+       }
        function realTimestamps() {
                return true;
        }
-
        function implicitGroupby() {
                return false;
        }
-
+       function implicitOrderby() {
+               return false;
+       }
        function searchableIPs() {
                return true;
        }
@@ -135,11 +146,12 @@ class DatabaseOracle extends Database {
         * If the failFunction is set to a non-zero integer, returns success
         */
        function open( $server, $user, $password, $dbName ) {
-               # Test for Postgres support, to avoid suppressed fatal error
                if ( !function_exists( 'oci_connect' ) ) {
                        throw new DBConnectionError( $this, "Oracle functions missing, have you compiled PHP with the --with-oci8 option?\n (Note: if you recently installed PHP, you may need to restart your webserver and database)\n" );
                }
 
+               # Needed for proper UTF-8 functionality
+               putenv("NLS_LANG=AMERICAN_AMERICA.AL32UTF8");
 
                $this->close();
                $this->mServer = $server;
@@ -184,10 +196,18 @@ class DatabaseOracle extends Database {
 
        function doQuery($sql) {
                wfDebug("SQL: [$sql]\n");
-               $this->mLastResult = $stmt = oci_parse($this->mConn, $sql);
+               if (!mb_check_encoding($sql)) {
+                       throw new MWException("SQL encoding is invalid");
+               }
+
+               if (($this->mLastResult = $stmt = oci_parse($this->mConn, $sql)) === false) {
+                       $e = oci_error($this->mConn);
+                       $this->reportQueryError($e['message'], $e['code'], $sql, __FUNCTION__);
+               }
+               
                if (oci_execute($stmt, $this->execFlags()) == false) {
                        $e = oci_error($stmt);
-                       $this->reportQueryError($sql, $e['message'], $e['code']);
+                       $this->reportQueryError($e['message'], $e['code'], $sql, __FUNCTION__);
                }
                if (oci_statement_type($stmt) == "SELECT")
                        return new ORAResult($this, $stmt);
@@ -272,8 +292,8 @@ class DatabaseOracle extends Database {
                if (!is_array($options))
                        $options = array($options);
 
-               if (in_array('IGNORE', $options))
-                       $oldIgnore = $this->ignoreErrors(true);
+               #if (in_array('IGNORE', $options))
+               #       $oldIgnore = $this->ignoreErrors(true);
 
                # IGNORE is performed using single-row inserts, ignoring errors in each
                # FIXME: need some way to distiguish between key collision and other types of error
@@ -287,8 +307,8 @@ class DatabaseOracle extends Database {
                //$this->ignoreErrors($oldIgnore);
                $retVal = true;
 
-               if (in_array('IGNORE', $options))
-                       $this->ignoreErrors($oldIgnore);
+               //if (in_array('IGNORE', $options))
+               //      $this->ignoreErrors($oldIgnore);
 
                return $retVal;
        }
@@ -300,10 +320,14 @@ class DatabaseOracle extends Database {
 
                // for each value, append ":key"
                $first = true;
+               $returning = '';
                foreach ($row as $col => $val) {
-                       if (is_object($val))
+                       if (is_object($val)) {
                                $what = "EMPTY_BLOB()";
-                       else
+                               assert($returning === '');
+                               $returning = " RETURNING $col INTO :bval";
+                               $blobcol = $col;
+                       } else
                                $what = ":$col";
 
                        if ($first)
@@ -312,7 +336,7 @@ class DatabaseOracle extends Database {
                                $sql.= ", $what";
                        $first = false;
                }
-               $sql .= ")";
+               $sql .= ") $returning";
 
                $stmt = oci_parse($this->mConn, $sql);
                foreach ($row as $col => $val) {
@@ -322,10 +346,25 @@ class DatabaseOracle extends Database {
                        }
                }
 
-               if (oci_execute($stmt, $this->execFlags()) === false) {
+               if (($bval = oci_new_descriptor($this->mConn, OCI_D_LOB)) === false) {
+                       $e = oci_error($stmt);
+                       throw new DBUnexpectedError($this, "Cannot create LOB descriptor: " . $e['message']);
+               }
+
+               if (strlen($returning))
+                       oci_bind_by_name($stmt, ":bval", $bval, -1, SQLT_BLOB);
+
+               if (oci_execute($stmt, OCI_DEFAULT) === false) {
                        $e = oci_error($stmt);
                        $this->reportQueryError($e['message'], $e['code'], $sql, __METHOD__);
                }
+               if (strlen($returning)) {
+                       $bval->save($row[$blobcol]->getData());
+                       $bval->free();
+               }
+               if (!$this->mTrxLevel)
+                       oci_commit($this->mConn);
+
                oci_free_statement($stmt);
        }
        
@@ -353,7 +392,7 @@ class DatabaseOracle extends Database {
        }
 
        /**
-        * ORacle does not have a "USE INDEX" clause, so return an empty string
+        * Oracle does not have a "USE INDEX" clause, so return an empty string
         */
        function useIndexClause($index) {
                return '';
@@ -491,15 +530,18 @@ class DatabaseOracle extends Database {
        }
 
        function reportQueryError($error, $errno, $sql, $fname, $tempIgnore = false) {
-               # Ignore errors during error handling to avoid infinite recursion
+               # Ignore errors during error handling to avoid infinite 
+               # recursion
                $ignore = $this->ignoreErrors(true);
                ++$this->mErrorCount;
 
                if ($ignore || $tempIgnore) {
+echo "error ignored! query = [$sql]\n";
                        wfDebug("SQL ERROR (ignored): $error\n");
                        $this->ignoreErrors( $ignore );
                }
                else {
+echo "error!\n";
                        $message = "A database error has occurred\n" .
                                "Query: $sql\n" .
                                "Function: $fname\n" .
@@ -574,6 +616,8 @@ class DatabaseOracle extends Database {
        }
 
        function addQuotes( $s ) {
+       global  $wgLang;
+               $s = $wgLang->checkTitleEncoding($s);
                return "'" . $this->strencode($s) . "'";
        }
 
@@ -597,7 +641,7 @@ class DatabaseOracle extends Database {
         * @return array
         */
        function makeSelectOptions( $options ) {
-               $tailOpts = '';
+               $preLimitTail = $postLimitTail = '';
                $startOpts = '';
 
                $noKeyOptions = array();
@@ -607,8 +651,8 @@ class DatabaseOracle extends Database {
                        }
                }
 
-               if ( isset( $options['GROUP BY'] ) ) $tailOpts .= " GROUP BY {$options['GROUP BY']}";
-               if ( isset( $options['ORDER BY'] ) ) $tailOpts .= " ORDER BY {$options['ORDER BY']}";
+               if ( isset( $options['GROUP BY'] ) ) $preLimitTail .= " GROUP BY {$options['GROUP BY']}";
+               if ( isset( $options['ORDER BY'] ) ) $preLimitTail .= " ORDER BY {$options['ORDER BY']}";
                
                if (isset($options['LIMIT'])) {
                //      $tailOpts .= $this->limitResult('', $options['LIMIT'],
@@ -616,9 +660,9 @@ class DatabaseOracle extends Database {
                //              : false);
                }
 
-               if ( isset( $noKeyOptions['FOR UPDATE'] ) ) $tailOpts .= ' FOR UPDATE';
-               if ( isset( $noKeyOptions['LOCK IN SHARE MODE'] ) ) $tailOpts .= ' LOCK IN SHARE MODE';
-               if ( isset( $noKeyOptions['DISTINCT'] ) && isset( $noKeyOptions['DISTINCTROW'] ) ) $startOpts .= 'DISTINCT';
+               #if ( isset( $noKeyOptions['FOR UPDATE'] ) ) $tailOpts .= ' FOR UPDATE';
+               #if ( isset( $noKeyOptions['LOCK IN SHARE MODE'] ) ) $tailOpts .= ' LOCK IN SHARE MODE';
+               if ( isset( $noKeyOptions['DISTINCT'] ) || isset( $noKeyOptions['DISTINCTROW'] ) ) $startOpts .= 'DISTINCT';
 
                if ( isset( $options['USE INDEX'] ) && ! is_array( $options['USE INDEX'] ) ) {
                        $useIndex = $this->useIndexClause( $options['USE INDEX'] );
@@ -626,19 +670,28 @@ class DatabaseOracle extends Database {
                        $useIndex = '';
                }
                
-               return array( $startOpts, $useIndex, $tailOpts );
+               return array( $startOpts, $useIndex, $preLimitTail, $postLimitTail );
        }
 
        public function setTimeout( $timeout ) {
-               /// @fixme no-op
+               // @todo fixme no-op
        }
 
        function ping() {
-               wfDebug( "Function ping() not written for DatabasePostgres.php yet");
+               wfDebug( "Function ping() not written for DatabaseOracle.php yet");
                return true;
        }
 
+       /**
+        * How lagged is this slave?
+        *
+        * @return int
+        */
+       public function getLag() {
+               # Not implemented for Oracle
+               return 0;
+       }
 
 } // end DatabaseOracle class
 
-?>
+