From ef484d5fe7ae9eecff794c0e4071029e74c330fe Mon Sep 17 00:00:00 2001 From: Jure Kajzer Date: Mon, 25 Oct 2010 10:56:07 +0000 Subject: [PATCH] * null value => default value handling * duplicateTable call fix * some internal calls to query replaced with doQuery * added update method overload --- includes/db/DatabaseOracle.php | 194 ++++++++++++++++++++++++++------- 1 file changed, 157 insertions(+), 37 deletions(-) diff --git a/includes/db/DatabaseOracle.php b/includes/db/DatabaseOracle.php index dd7294e9a5..5789d11017 100644 --- a/includes/db/DatabaseOracle.php +++ b/includes/db/DatabaseOracle.php @@ -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 . ')'; -- 2.20.1