Index: trunk/phase3/includes/db/DatabaseOracle.php |
— | — | @@ -54,6 +54,7 @@ |
55 | 55 | if ( ( $this->nrows = oci_fetch_all( $stmt, $this->rows, 0, - 1, OCI_FETCHSTATEMENT_BY_ROW | OCI_NUM ) ) === false ) { |
56 | 56 | $e = oci_error( $stmt ); |
57 | 57 | $db->reportQueryError( $e['message'], $e['code'], '', __METHOD__ ); |
| 58 | + $this->free(); |
58 | 59 | return; |
59 | 60 | } |
60 | 61 | |
— | — | @@ -185,10 +186,10 @@ |
186 | 187 | var $mFieldInfoCache = array(); |
187 | 188 | |
188 | 189 | function __construct( $server = false, $user = false, $password = false, $dbName = false, |
189 | | - $flags = 0, $tablePrefix = 'get from global' ) |
| 190 | + $failFunction = false, $flags = 0, $tablePrefix = 'get from global' ) |
190 | 191 | { |
191 | 192 | $tablePrefix = $tablePrefix == 'get from global' ? $tablePrefix : strtoupper( $tablePrefix ); |
192 | | - parent::__construct( $server, $user, $password, $dbName, $flags, $tablePrefix ); |
| 193 | + parent::__construct( $server, $user, $password, $dbName, $failFunction, $flags, $tablePrefix ); |
193 | 194 | wfRunHooks( 'DatabaseOraclePostInit', array( &$this ) ); |
194 | 195 | } |
195 | 196 | |
— | — | @@ -218,12 +219,14 @@ |
219 | 220 | return true; |
220 | 221 | } |
221 | 222 | |
222 | | - static function newFromParams( $server, $user, $password, $dbName, $flags = 0, $tablePrefix ) { |
223 | | - return new DatabaseOracle( $server, $user, $password, $dbName, $flags, $tablePrefix ); |
| 223 | + static function newFromParams( $server, $user, $password, $dbName, $failFunction = false, $flags = 0, $tablePrefix ) |
| 224 | + { |
| 225 | + return new DatabaseOracle( $server, $user, $password, $dbName, $failFunction, $flags, $tablePrefix ); |
224 | 226 | } |
225 | 227 | |
226 | 228 | /** |
227 | 229 | * Usually aborts on failure |
| 230 | + * If the failFunction is set to a non-zero integer, returns success |
228 | 231 | */ |
229 | 232 | function open( $server, $user, $password, $dbName ) { |
230 | 233 | if ( !function_exists( 'oci_connect' ) ) { |
— | — | @@ -471,6 +474,36 @@ |
472 | 475 | return $retVal; |
473 | 476 | } |
474 | 477 | |
| 478 | + private function fieldBindStatement ( $table, $col, &$val, $includeCol = false ) { |
| 479 | + $col_info = $this->fieldInfoMulti( $table, $col ); |
| 480 | + $col_type = $col_info != false ? $col_info->type() : 'CONSTANT'; |
| 481 | + |
| 482 | + $bind = ''; |
| 483 | + if ( is_numeric( $col ) ) { |
| 484 | + $bind = $val; |
| 485 | + $val = null; |
| 486 | + return $bind; |
| 487 | + } else if ( $includeCol ) { |
| 488 | + $bind = "$col = "; |
| 489 | + } |
| 490 | + |
| 491 | + if ( $val == '' && $val !== 0 && $col_type != 'BLOB' && $col_type != 'CLOB' ) { |
| 492 | + $val = null; |
| 493 | + } |
| 494 | + |
| 495 | + if ( $val === null ) { |
| 496 | + if ( $col_info != false && $col_info->nullable() == 0 && $col_info->defaultValue() != null ) { |
| 497 | + $bind .= 'DEFAULT'; |
| 498 | + } else { |
| 499 | + $bind .= 'NULL'; |
| 500 | + } |
| 501 | + } else { |
| 502 | + $bind .= ':' . $col; |
| 503 | + } |
| 504 | + |
| 505 | + return $bind; |
| 506 | + } |
| 507 | + |
475 | 508 | private function insertOneRow( $table, $row, $fname ) { |
476 | 509 | global $wgContLang; |
477 | 510 | |
— | — | @@ -481,18 +514,22 @@ |
482 | 515 | |
483 | 516 | // for each value, append ":key" |
484 | 517 | $first = true; |
485 | | - foreach ( $row as $col => $val ) { |
486 | | - if ( $first ) { |
487 | | - $sql .= $val !== null ? ':' . $col : 'NULL'; |
| 518 | + foreach ( $row as $col => &$val ) { |
| 519 | + if ( !$first ) { |
| 520 | + $sql .= ', '; |
488 | 521 | } else { |
489 | | - $sql .= $val !== null ? ', :' . $col : ', NULL'; |
| 522 | + $first = false; |
490 | 523 | } |
491 | | - |
492 | | - $first = false; |
| 524 | + |
| 525 | + $sql .= $this->fieldBindStatement( $table, $col, $val ); |
493 | 526 | } |
494 | 527 | $sql .= ')'; |
495 | 528 | |
496 | | - $stmt = oci_parse( $this->mConn, $sql ); |
| 529 | + if ( ( $this->mLastResult = $stmt = oci_parse( $this->mConn, $sql ) ) === false ) { |
| 530 | + $e = oci_error( $this->mConn ); |
| 531 | + $this->reportQueryError( $e['message'], $e['code'], $sql, __METHOD__ ); |
| 532 | + return false; |
| 533 | + } |
497 | 534 | foreach ( $row as $col => &$val ) { |
498 | 535 | $col_info = $this->fieldInfoMulti( $table, $col ); |
499 | 536 | $col_type = $col_info != false ? $col_info->type() : 'CONSTANT'; |
— | — | @@ -510,7 +547,8 @@ |
511 | 548 | |
512 | 549 | $val = ( $wgContLang != null ) ? $wgContLang->checkTitleEncoding( $val ) : $val; |
513 | 550 | if ( oci_bind_by_name( $stmt, ":$col", $val ) === false ) { |
514 | | - $this->reportQueryError( $this->lastErrno(), $this->lastError(), $sql, __METHOD__ ); |
| 551 | + $e = oci_error( $stmt ); |
| 552 | + $this->reportQueryError( $e['message'], $e['code'], $sql, __METHOD__ ); |
515 | 553 | return false; |
516 | 554 | } |
517 | 555 | } else { |
— | — | @@ -519,8 +557,8 @@ |
520 | 558 | throw new DBUnexpectedError( $this, "Cannot create LOB descriptor: " . $e['message'] ); |
521 | 559 | } |
522 | 560 | |
523 | | - if ( $col_type == 'BLOB' ) { // is_object($val)) { |
524 | | - $lob[$col]->writeTemporary( $val ); // ->getData()); |
| 561 | + if ( $col_type == 'BLOB' ) { |
| 562 | + $lob[$col]->writeTemporary( $val ); |
525 | 563 | oci_bind_by_name( $stmt, ":$col", $lob[$col], - 1, SQLT_BLOB ); |
526 | 564 | } else { |
527 | 565 | $lob[$col]->writeTemporary( $val ); |
— | — | @@ -533,7 +571,6 @@ |
534 | 572 | |
535 | 573 | if ( oci_execute( $stmt, OCI_DEFAULT ) === false ) { |
536 | 574 | $e = oci_error( $stmt ); |
537 | | - |
538 | 575 | if ( !$this->ignore_DUP_VAL_ON_INDEX || $e['code'] != '1' ) { |
539 | 576 | $this->reportQueryError( $e['message'], $e['code'], $sql, __METHOD__ ); |
540 | 577 | return false; |
— | — | @@ -657,7 +694,7 @@ |
658 | 695 | if ( isset( $database ) ) { |
659 | 696 | $database = ( $database[0] == '"' ? $database : "\"{$database}\"" ); |
660 | 697 | } |
661 | | - $table = ( $table[0] == '"' ? $table : "\"{$prefix}{$table}\"" ); |
| 698 | + $table = ( $table[0] == '"') ? $table : "\"{$prefix}{$table}\"" ; |
662 | 699 | |
663 | 700 | $tableName = ( isset( $database ) ? "{$database}.{$table}" : "{$table}" ); |
664 | 701 | |
— | — | @@ -679,7 +716,7 @@ |
680 | 717 | */ |
681 | 718 | private function getSequenceData( $table ) { |
682 | 719 | if ( $this->sequenceData == null ) { |
683 | | - $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'" ); |
| 720 | + $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\'' ); |
684 | 721 | |
685 | 722 | while ( ( $row = $result->fetchRow() ) !== false ) { |
686 | 723 | $this->sequenceData[$this->tableName( $row[1] )] = array( |
— | — | @@ -789,28 +826,17 @@ |
790 | 827 | } |
791 | 828 | |
792 | 829 | function duplicateTableStructure( $oldName, $newName, $temporary = false, $fname = 'DatabaseOracle::duplicateTableStructure' ) { |
| 830 | + global $wgDBprefix; |
| 831 | + |
793 | 832 | $temporary = $temporary ? 'TRUE' : 'FALSE'; |
794 | | - $oldName = trim( strtoupper( $oldName ), '"'); |
795 | | - $oldParts = explode( '_', $oldName ); |
796 | 833 | |
797 | 834 | $newName = trim( strtoupper( $newName ), '"'); |
798 | | - $newParts = explode( '_', $newName ); |
| 835 | + $oldName = trim( strtoupper( $oldName ), '"'); |
799 | 836 | |
800 | | - $oldPrefix = ''; |
801 | | - $newPrefix = ''; |
802 | | - for ( $i = count( $oldParts ) - 1; $i >= 0; $i-- ) { |
803 | | - if ( $oldParts[$i] != $newParts[$i] ) { |
804 | | - $oldPrefix = implode( '_', $oldParts ) . '_'; |
805 | | - $newPrefix = implode( '_', $newParts ) . '_'; |
806 | | - break; |
807 | | - } |
808 | | - unset( $oldParts[$i] ); |
809 | | - unset( $newParts[$i] ); |
810 | | - } |
| 837 | + $tabName = substr( $newName, strlen( $wgDBprefix ) ); |
| 838 | + $oldPrefix = substr( $oldName, 0, strlen( $oldName ) - strlen( $tabName ) ); |
811 | 839 | |
812 | | - $tabName = substr( $oldName, strlen( $oldPrefix ) ); |
813 | | - |
814 | | - return $this->query( 'BEGIN DUPLICATE_TABLE(\'' . $tabName . '\', \'' . $oldPrefix . '\', \''.$newPrefix.'\', ' . $temporary . '); END;', $fname ); |
| 840 | + return $this->doQuery( 'BEGIN DUPLICATE_TABLE(\'' . $tabName . '\', \'' . $oldPrefix . '\', \'' . strtoupper( $wgDBprefix ) . '\', ' . $temporary . '); END;' ); |
815 | 841 | } |
816 | 842 | |
817 | 843 | function timestamp( $ts = 0 ) { |
— | — | @@ -917,12 +943,14 @@ |
918 | 944 | } else { |
919 | 945 | $this->mFieldInfoCache["$table.$field"] = false; |
920 | 946 | } |
| 947 | + $fieldInfoTemp = null; |
921 | 948 | } else { |
922 | 949 | $fieldInfoTemp = new ORAField( $res->fetchRow() ); |
923 | 950 | $table = $fieldInfoTemp->tableName(); |
924 | 951 | $this->mFieldInfoCache["$table.$field"] = $fieldInfoTemp; |
925 | | - return $fieldInfoTemp; |
926 | 952 | } |
| 953 | + $res->free(); |
| 954 | + return $fieldInfoTemp; |
927 | 955 | } |
928 | 956 | |
929 | 957 | function fieldInfo( $table, $field ) { |
— | — | @@ -1000,7 +1028,7 @@ |
1001 | 1029 | } |
1002 | 1030 | |
1003 | 1031 | $cmd = $this->replaceVars( $cmd ); |
1004 | | - $res = $this->query( $cmd, __METHOD__ ); |
| 1032 | + $res = $this->doQuery( $cmd ); |
1005 | 1033 | if ( $resultCallback ) { |
1006 | 1034 | call_user_func( $resultCallback, $res, $this ); |
1007 | 1035 | } |
— | — | @@ -1094,7 +1122,7 @@ |
1095 | 1123 | $conds2[$col] = $val; |
1096 | 1124 | } |
1097 | 1125 | } |
1098 | | - |
| 1126 | + |
1099 | 1127 | return parent::selectRow( $table, $vars, $conds2, $fname, $options, $join_conds ); |
1100 | 1128 | } |
1101 | 1129 | |
— | — | @@ -1170,6 +1198,98 @@ |
1171 | 1199 | } |
1172 | 1200 | } |
1173 | 1201 | |
| 1202 | + function update( $table, $values, $conds, $fname = 'DatabaseOracle::update', $options = array() ) { |
| 1203 | + $table = $this->tableName( $table ); |
| 1204 | + $opts = $this->makeUpdateOptions( $options ); |
| 1205 | + $sql = "UPDATE $opts $table SET "; |
| 1206 | + |
| 1207 | + $first = true; |
| 1208 | + foreach ( $values as $col => &$val ) { |
| 1209 | + $sqlSet = $this->fieldBindStatement( $table, $col, $val, true ); |
| 1210 | + |
| 1211 | + if ( !$first ) { |
| 1212 | + $sqlSet = ', ' . $sqlSet; |
| 1213 | + } else { |
| 1214 | + $first = false; |
| 1215 | + } |
| 1216 | + $sql .= $sqlSet; |
| 1217 | + } |
| 1218 | + |
| 1219 | + if ( $conds != '*' ) { |
| 1220 | + $sql .= ' WHERE ' . $this->makeList( $conds, LIST_AND ); |
| 1221 | + } |
| 1222 | + |
| 1223 | + if ( ( $this->mLastResult = $stmt = oci_parse( $this->mConn, $sql ) ) === false ) { |
| 1224 | + $e = oci_error( $this->mConn ); |
| 1225 | + $this->reportQueryError( $e['message'], $e['code'], $sql, __METHOD__ ); |
| 1226 | + return false; |
| 1227 | + } |
| 1228 | + foreach ( $values as $col => &$val ) { |
| 1229 | + $col_info = $this->fieldInfoMulti( $table, $col ); |
| 1230 | + $col_type = $col_info != false ? $col_info->type() : 'CONSTANT'; |
| 1231 | + |
| 1232 | + if ( $val === null ) { |
| 1233 | + // do nothing ... null was inserted in statement creation |
| 1234 | + } elseif ( $col_type != 'BLOB' && $col_type != 'CLOB' ) { |
| 1235 | + if ( is_object( $val ) ) { |
| 1236 | + $val = $val->getData(); |
| 1237 | + } |
| 1238 | + |
| 1239 | + if ( preg_match( '/^timestamp.*/i', $col_type ) == 1 && strtolower( $val ) == 'infinity' ) { |
| 1240 | + $val = '31-12-2030 12:00:00.000000'; |
| 1241 | + } |
| 1242 | + |
| 1243 | + $val = ( $wgContLang != null ) ? $wgContLang->checkTitleEncoding( $val ) : $val; |
| 1244 | + if ( oci_bind_by_name( $stmt, ":$col", $val ) === false ) { |
| 1245 | + $e = oci_error( $stmt ); |
| 1246 | + $this->reportQueryError( $e['message'], $e['code'], $sql, __METHOD__ ); |
| 1247 | + return false; |
| 1248 | + } |
| 1249 | + } else { |
| 1250 | + if ( ( $lob[$col] = oci_new_descriptor( $this->mConn, OCI_D_LOB ) ) === false ) { |
| 1251 | + $e = oci_error( $stmt ); |
| 1252 | + throw new DBUnexpectedError( $this, "Cannot create LOB descriptor: " . $e['message'] ); |
| 1253 | + } |
| 1254 | + |
| 1255 | + if ( $col_type == 'BLOB' ) { |
| 1256 | + $lob[$col]->writeTemporary( $val ); |
| 1257 | + oci_bind_by_name( $stmt, ":$col", $lob[$col], - 1, SQLT_BLOB ); |
| 1258 | + } else { |
| 1259 | + $lob[$col]->writeTemporary( $val ); |
| 1260 | + oci_bind_by_name( $stmt, ":$col", $lob[$col], - 1, OCI_B_CLOB ); |
| 1261 | + } |
| 1262 | + } |
| 1263 | + } |
| 1264 | + |
| 1265 | + wfSuppressWarnings(); |
| 1266 | + |
| 1267 | + if ( oci_execute( $stmt, OCI_DEFAULT ) === false ) { |
| 1268 | + $e = oci_error( $stmt ); |
| 1269 | + if ( !$this->ignore_DUP_VAL_ON_INDEX || $e['code'] != '1' ) { |
| 1270 | + $this->reportQueryError( $e['message'], $e['code'], $sql, __METHOD__ ); |
| 1271 | + return false; |
| 1272 | + } else { |
| 1273 | + $this->mAffectedRows = oci_num_rows( $stmt ); |
| 1274 | + } |
| 1275 | + } else { |
| 1276 | + $this->mAffectedRows = oci_num_rows( $stmt ); |
| 1277 | + } |
| 1278 | + |
| 1279 | + wfRestoreWarnings(); |
| 1280 | + |
| 1281 | + if ( isset( $lob ) ) { |
| 1282 | + foreach ( $lob as $lob_v ) { |
| 1283 | + $lob_v->free(); |
| 1284 | + } |
| 1285 | + } |
| 1286 | + |
| 1287 | + if ( !$this->mTrxLevel ) { |
| 1288 | + oci_commit( $this->mConn ); |
| 1289 | + } |
| 1290 | + |
| 1291 | + oci_free_statement( $stmt ); |
| 1292 | + } |
| 1293 | + |
1174 | 1294 | function bitNot( $field ) { |
1175 | 1295 | // expecting bit-fields smaller than 4bytes |
1176 | 1296 | return 'BITNOT(' . $field . ')'; |