* null value => default value handling
authorJure Kajzer <freakolowsky@users.mediawiki.org>
Mon, 25 Oct 2010 10:56:07 +0000 (10:56 +0000)
committerJure Kajzer <freakolowsky@users.mediawiki.org>
Mon, 25 Oct 2010 10:56:07 +0000 (10:56 +0000)
* duplicateTable call fix
* some internal calls to query replaced with doQuery
* added update method overload

includes/db/DatabaseOracle.php

index dd7294e..5789d11 100644 (file)
@@ -54,6 +54,7 @@ class ORAResult {
                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'], '', __METHOD__ );
+                       $this->free();
                        return;
                }
 
@@ -185,10 +186,10 @@ class DatabaseOracle extends DatabaseBase {
        var $mFieldInfoCache = array();
 
        function __construct( $server = false, $user = false, $password = false, $dbName = false,
-               $flags = 0, $tablePrefix = 'get from global' )
+               $failFunction = false, $flags = 0, $tablePrefix = 'get from global' )
        {
                $tablePrefix = $tablePrefix == 'get from global' ? $tablePrefix : strtoupper( $tablePrefix );
-               parent::__construct( $server, $user, $password, $dbName, $flags, $tablePrefix );
+               parent::__construct( $server, $user, $password, $dbName, $failFunction, $flags, $tablePrefix );
                wfRunHooks( 'DatabaseOraclePostInit', array( &$this ) );
        }
 
@@ -218,12 +219,14 @@ class DatabaseOracle extends DatabaseBase {
                return true;
        }
 
-       static function newFromParams( $server, $user, $password, $dbName, $flags = 0, $tablePrefix ) {
-               return new DatabaseOracle( $server, $user, $password, $dbName, $flags, $tablePrefix );
+       static function newFromParams( $server, $user, $password, $dbName, $failFunction = false, $flags = 0, $tablePrefix )
+       {
+               return new DatabaseOracle( $server, $user, $password, $dbName, $failFunction, $flags, $tablePrefix );
        }
 
        /**
         * Usually aborts on failure
+        * If the failFunction is set to a non-zero integer, returns success
         */
        function open( $server, $user, $password, $dbName ) {
                if ( !function_exists( 'oci_connect' ) ) {
@@ -471,6 +474,36 @@ class DatabaseOracle extends DatabaseBase {
                return $retVal;
        }
 
+       private function fieldBindStatement ( $table, $col, &$val, $includeCol = false ) {
+               $col_info = $this->fieldInfoMulti( $table, $col );
+               $col_type = $col_info != false ? $col_info->type() : 'CONSTANT';
+               
+               $bind = '';
+               if ( is_numeric( $col ) ) {
+                       $bind = $val;
+                       $val = null;
+                       return $bind; 
+               } else if ( $includeCol ) {
+                       $bind = "$col = ";
+               }
+               
+               if ( $val == '' && $val !== 0 && $col_type != 'BLOB' && $col_type != 'CLOB' ) {
+                       $val = null;
+               }
+
+               if ( $val === null ) {
+                       if ( $col_info != false && $col_info->nullable() == 0 && $col_info->defaultValue() != null ) {
+                               $bind .= 'DEFAULT';
+                       } else {
+                               $bind .= 'NULL';
+                       }
+               } else {
+                       $bind .= ':' . $col;
+               }
+               
+               return $bind;
+       }
+
        private function insertOneRow( $table, $row, $fname ) {
                global $wgContLang;
 
@@ -481,18 +514,22 @@ class DatabaseOracle extends DatabaseBase {
 
                // for each value, append ":key"
                $first = true;
-               foreach ( $row as $col => $val ) {
-                       if ( $first ) {
-                               $sql .= $val !== null ? ':' . $col : 'NULL';
+               foreach ( $row as $col => &$val ) {
+                       if ( !$first ) {
+                               $sql .= ', ';
                        } else {
-                               $sql .= $val !== null ? ', :' . $col : ', NULL';
+                               $first = false;
                        }
-
-                       $first = false;
+                       
+                       $sql .= $this->fieldBindStatement( $table, $col, $val );
                }
                $sql .= ')';
 
-               $stmt = oci_parse( $this->mConn, $sql );
+               if ( ( $this->mLastResult = $stmt = oci_parse( $this->mConn, $sql ) ) === false ) {
+                       $e = oci_error( $this->mConn );
+                       $this->reportQueryError( $e['message'], $e['code'], $sql, __METHOD__ );
+                       return false;
+               }
                foreach ( $row as $col => &$val ) {
                        $col_info = $this->fieldInfoMulti( $table, $col );
                        $col_type = $col_info != false ? $col_info->type() : 'CONSTANT';
@@ -510,7 +547,8 @@ class DatabaseOracle extends DatabaseBase {
 
                                $val = ( $wgContLang != null ) ? $wgContLang->checkTitleEncoding( $val ) : $val;
                                if ( oci_bind_by_name( $stmt, ":$col", $val ) === false ) {
-                                       $this->reportQueryError( $this->lastErrno(), $this->lastError(), $sql, __METHOD__ );
+                                       $e = oci_error( $stmt );
+                                       $this->reportQueryError( $e['message'], $e['code'], $sql, __METHOD__ );
                                        return false;
                                }
                        } else {
@@ -519,8 +557,8 @@ class DatabaseOracle extends DatabaseBase {
                                        throw new DBUnexpectedError( $this, "Cannot create LOB descriptor: " . $e['message'] );
                                }
 
-                               if ( $col_type == 'BLOB' ) { // is_object($val)) {
-                                       $lob[$col]->writeTemporary( $val ); // ->getData());
+                               if ( $col_type == 'BLOB' ) {
+                                       $lob[$col]->writeTemporary( $val );
                                        oci_bind_by_name( $stmt, ":$col", $lob[$col], - 1, SQLT_BLOB );
                                } else {
                                        $lob[$col]->writeTemporary( $val );
@@ -533,7 +571,6 @@ class DatabaseOracle extends DatabaseBase {
 
                if ( oci_execute( $stmt, OCI_DEFAULT ) === false ) {
                        $e = oci_error( $stmt );
-
                        if ( !$this->ignore_DUP_VAL_ON_INDEX || $e['code'] != '1' ) {
                                $this->reportQueryError( $e['message'], $e['code'], $sql, __METHOD__ );
                                return false;
@@ -657,7 +694,7 @@ class DatabaseOracle extends DatabaseBase {
                if ( isset( $database ) ) {
                        $database = ( $database[0] == '"' ? $database : "\"{$database}\"" );
                }
-               $table = ( $table[0] == '"' ? $table : "\"{$prefix}{$table}\"" );
+               $table = ( $table[0] == '"') ? $table : "\"{$prefix}{$table}\"" ;
 
                $tableName = ( isset( $database ) ? "{$database}.{$table}" : "{$table}" );
 
@@ -679,7 +716,7 @@ class DatabaseOracle extends DatabaseBase {
         */
        private 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'" );
+                       $result = $this->doQuery( '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(
@@ -789,28 +826,17 @@ class DatabaseOracle extends DatabaseBase {
        }
 
        function duplicateTableStructure( $oldName, $newName, $temporary = false, $fname = 'DatabaseOracle::duplicateTableStructure' ) {
+               global $wgDBprefix;
+               
                $temporary = $temporary ? 'TRUE' : 'FALSE';
-               $oldName = trim( strtoupper( $oldName ), '"');
-               $oldParts = explode( '_', $oldName );
 
                $newName = trim( strtoupper( $newName ), '"');
-               $newParts = explode( '_', $newName );
-
-               $oldPrefix = '';
-               $newPrefix = '';
-               for ( $i = count( $oldParts ) - 1; $i >= 0; $i-- ) {
-                       if ( $oldParts[$i] != $newParts[$i] ) {
-                               $oldPrefix = implode( '_', $oldParts ) . '_';
-                               $newPrefix = implode( '_', $newParts ) . '_';
-                               break;
-                       }
-                       unset( $oldParts[$i] );
-                       unset( $newParts[$i] );
-               }
+               $oldName = trim( strtoupper( $oldName ), '"');
 
-               $tabName = substr( $oldName, strlen( $oldPrefix ) );
+               $tabName = substr( $newName, strlen( $wgDBprefix ) );
+               $oldPrefix = substr( $oldName, 0, strlen( $oldName ) - strlen( $tabName ) );
 
-               return $this->query( 'BEGIN DUPLICATE_TABLE(\'' . $tabName . '\', \'' . $oldPrefix . '\', \''.$newPrefix.'\', ' . $temporary . '); END;', $fname );
+               return $this->doQuery( 'BEGIN DUPLICATE_TABLE(\'' . $tabName . '\', \'' . $oldPrefix . '\', \'' . strtoupper( $wgDBprefix ) . '\', ' . $temporary . '); END;' );
        }
 
        function timestamp( $ts = 0 ) {
@@ -917,12 +943,14 @@ class DatabaseOracle extends DatabaseBase {
                        } else {
                                $this->mFieldInfoCache["$table.$field"] = false;
                        }
+                       $fieldInfoTemp = null;
                } else {
                        $fieldInfoTemp = new ORAField( $res->fetchRow() );
                        $table = $fieldInfoTemp->tableName();
                        $this->mFieldInfoCache["$table.$field"] = $fieldInfoTemp;
-                       return $fieldInfoTemp;
                }
+               $res->free();
+               return $fieldInfoTemp;
        }
 
        function fieldInfo( $table, $field ) {
@@ -1000,7 +1028,7 @@ class DatabaseOracle extends DatabaseBase {
                                        }
 
                                        $cmd = $this->replaceVars( $cmd );
-                                       $res = $this->query( $cmd, __METHOD__ );
+                                       $res = $this->doQuery( $cmd );
                                        if ( $resultCallback ) {
                                                call_user_func( $resultCallback, $res, $this );
                                        }
@@ -1094,7 +1122,7 @@ class DatabaseOracle extends DatabaseBase {
                                $conds2[$col] = $val;
                        }
                }
-
+               
                return parent::selectRow( $table, $vars, $conds2, $fname, $options, $join_conds );
        }
 
@@ -1170,6 +1198,98 @@ class DatabaseOracle extends DatabaseBase {
                }
        }
 
+       function update( $table, $values, $conds, $fname = 'DatabaseOracle::update', $options = array() ) {
+               $table = $this->tableName( $table );
+               $opts = $this->makeUpdateOptions( $options );
+               $sql = "UPDATE $opts $table SET ";
+               
+               $first = true;
+               foreach ( $values as $col => &$val ) {
+                       $sqlSet = $this->fieldBindStatement( $table, $col, $val, true );
+                       
+                       if ( !$first ) {
+                               $sqlSet = ', ' . $sqlSet;
+                       } else {
+                               $first = false;
+                       }
+                       $sql .= $sqlSet;
+               }
+
+               if ( $conds != '*' ) {
+                       $sql .= ' WHERE ' . $this->makeList( $conds, LIST_AND );
+               }
+
+               if ( ( $this->mLastResult = $stmt = oci_parse( $this->mConn, $sql ) ) === false ) {
+                       $e = oci_error( $this->mConn );
+                       $this->reportQueryError( $e['message'], $e['code'], $sql, __METHOD__ );
+                       return false;
+               }
+               foreach ( $values as $col => &$val ) {
+                       $col_info = $this->fieldInfoMulti( $table, $col );
+                       $col_type = $col_info != false ? $col_info->type() : 'CONSTANT';
+
+                       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';
+                               }
+
+                               $val = ( $wgContLang != null ) ? $wgContLang->checkTitleEncoding( $val ) : $val;
+                               if ( oci_bind_by_name( $stmt, ":$col", $val ) === false ) {
+                                       $e = oci_error( $stmt );
+                                       $this->reportQueryError( $e['message'], $e['code'], $sql, __METHOD__ );
+                                       return false;
+                               }
+                       } else {
+                               if ( ( $lob[$col] = oci_new_descriptor( $this->mConn, OCI_D_LOB ) ) === false ) {
+                                       $e = oci_error( $stmt );
+                                       throw new DBUnexpectedError( $this, "Cannot create LOB descriptor: " . $e['message'] );
+                               }
+
+                               if ( $col_type == 'BLOB' ) { 
+                                       $lob[$col]->writeTemporary( $val ); 
+                                       oci_bind_by_name( $stmt, ":$col", $lob[$col], - 1, SQLT_BLOB );
+                               } else {
+                                       $lob[$col]->writeTemporary( $val );
+                                       oci_bind_by_name( $stmt, ":$col", $lob[$col], - 1, OCI_B_CLOB );
+                               }
+                       }
+               }
+
+               wfSuppressWarnings();
+
+               if ( oci_execute( $stmt, OCI_DEFAULT ) === false ) {
+                       $e = oci_error( $stmt );
+                       if ( !$this->ignore_DUP_VAL_ON_INDEX || $e['code'] != '1' ) {
+                               $this->reportQueryError( $e['message'], $e['code'], $sql, __METHOD__ );
+                               return false;
+                       } else {
+                               $this->mAffectedRows = oci_num_rows( $stmt );
+                       }
+               } else {
+                       $this->mAffectedRows = oci_num_rows( $stmt );
+               }
+
+               wfRestoreWarnings();
+
+               if ( isset( $lob ) ) {
+                       foreach ( $lob as $lob_v ) {
+                               $lob_v->free();
+                       }
+               }
+
+               if ( !$this->mTrxLevel ) {
+                       oci_commit( $this->mConn );
+               }
+
+               oci_free_statement( $stmt );
+       }
+
        function bitNot( $field ) {
                // expecting bit-fields smaller than 4bytes
                return 'BITNOT(' . $field . ')';