00001 <?php
00016 class BlankObject {
00017 }
00018
00023 class IBM_DB2Field {
00024 private $name, $tablename, $type, $nullable, $max_length;
00025
00033 static function fromText($db, $table, $field) {
00034 global $wgDBmwschema;
00035
00036 $q = <<<END
00037 SELECT
00038 lcase(coltype) AS typname,
00039 nulls AS attnotnull, length AS attlen
00040 FROM sysibm.syscolumns
00041 WHERE tbcreator=%s AND tbname=%s AND name=%s;
00042 END;
00043 $res = $db->query(sprintf($q,
00044 $db->addQuotes($wgDBmwschema),
00045 $db->addQuotes($table),
00046 $db->addQuotes($field)));
00047 $row = $db->fetchObject($res);
00048 if (!$row)
00049 return null;
00050 $n = new IBM_DB2Field;
00051 $n->type = $row->typname;
00052 $n->nullable = ($row->attnotnull == 'N');
00053 $n->name = $field;
00054 $n->tablename = $table;
00055 $n->max_length = $row->attlen;
00056 return $n;
00057 }
00062 function name() { return $this->name; }
00067 function tableName() { return $this->tablename; }
00072 function type() { return $this->type; }
00077 function nullable() { return $this->nullable; }
00082 function maxLength() { return $this->max_length; }
00083 }
00084
00089 class IBM_DB2Blob {
00090 private $mData;
00091
00092 function __construct($data) {
00093 $this->mData = $data;
00094 }
00095
00096 function getData() {
00097 return $this->mData;
00098 }
00099 }
00100
00105 class DatabaseIbm_db2 extends Database {
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00125 protected $mPort = NULL;
00127 protected $mCataloged = NULL;
00129 protected $mSchema = NULL;
00131 protected $mSchemaSet = false;
00133 protected $mLastResult = NULL;
00135 protected $mAffectedRows = NULL;
00137 protected $mNumRows = NULL;
00138
00139
00140 const CATALOGED = "cataloged";
00141 const UNCATALOGED = "uncataloged";
00142 const USE_GLOBAL = "get from global";
00143
00145 protected $mInsertId = NULL;
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305 ######################################
00306 # Getters and Setters
00307 ######################################
00308
00312 function cascadingDeletes() {
00313 return true;
00314 }
00315
00319 function cleanupTriggers() {
00320 return true;
00321 }
00322
00327 function strictIPs() {
00328 return true;
00329 }
00330
00334 function realTimestamps() {
00335 return true;
00336 }
00337
00341 function implicitGroupby() {
00342 return false;
00343 }
00344
00349 function implicitOrderby() {
00350 return false;
00351 }
00352
00357 function searchableIPs() {
00358 return true;
00359 }
00360
00364 function functionalIndexes() {
00365 return true;
00366 }
00367
00371 function getWikiID() {
00372 if( $this->mSchema ) {
00373 return "{$this->mDBname}-{$this->mSchema}";
00374 } else {
00375 return $this->mDBname;
00376 }
00377 }
00378
00379
00380 ######################################
00381 # Setup
00382 ######################################
00383
00384
00394 public function DatabaseIbm_db2($server = false, $user = false, $password = false,
00395 $dbName = false, $failFunction = false, $flags = 0,
00396 $schema = self::USE_GLOBAL )
00397 {
00398
00399 global $wgOut, $wgDBmwschema;
00400 # Can't get a reference if it hasn't been set yet
00401 if ( !isset( $wgOut ) ) {
00402 $wgOut = NULL;
00403 }
00404 $this->mOut =& $wgOut;
00405 $this->mFailFunction = $failFunction;
00406 $this->mFlags = DBO_TRX | $flags;
00407
00408 if ( $schema == self::USE_GLOBAL ) {
00409 $this->mSchema = $wgDBmwschema;
00410 }
00411 else {
00412 $this->mSchema = $schema;
00413 }
00414
00415 $this->open( $server, $user, $password, $dbName);
00416 }
00417
00427 public function open( $server, $user, $password, $dbName )
00428 {
00429
00430 global $wgDBport_db2, $wgDBcataloged;
00431 wfProfileIn( __METHOD__ );
00432
00433
00434 if (!@extension_loaded('ibm_db2')) {
00435 @dl('ibm_db2.so');
00436 }
00437
00438 if ( !function_exists( 'db2_connect' ) ) {
00439 $error = "DB2 functions missing, have you enabled the ibm_db2 extension for PHP?\n";
00440 wfDebug($error);
00441 $this->reportConnectionError($error);
00442 }
00443
00444 if (!strlen($user)) {
00445 return null;
00446 }
00447
00448
00449 $this->close();
00450
00451 $this->mServer = $server;
00452 $this->mPort = $port = $wgDBport_db2;
00453 $this->mUser = $user;
00454 $this->mPassword = $password;
00455 $this->mDBname = $dbName;
00456 $this->mCataloged = $cataloged = $wgDBcataloged;
00457
00458 if ( $cataloged == self::CATALOGED ) {
00459 $this->openCataloged($dbName, $user, $password);
00460 }
00461 elseif ( $cataloged == self::UNCATALOGED ) {
00462 $this->openUncataloged($dbName, $user, $password, $server, $port);
00463 }
00464
00465
00466
00467
00468 db2_autocommit($this->mConn, DB2_AUTOCOMMIT_ON);
00469
00470 if ( $this->mConn == false ) {
00471 wfDebug( "DB connection error\n" );
00472 wfDebug( "Server: $server, Database: $dbName, User: $user, Password: " . substr( $password, 0, 3 ) . "...\n" );
00473 wfDebug( $this->lastError()."\n" );
00474 return null;
00475 }
00476
00477 $this->mOpened = true;
00478 $this->applySchema();
00479
00480 wfProfileOut( __METHOD__ );
00481 return $this->mConn;
00482 }
00483
00487 protected function openCataloged( $dbName, $user, $password )
00488 {
00489 @$this->mConn = db2_connect($dbName, $user, $password);
00490 }
00491
00495 protected function openUncataloged( $dbName, $user, $password, $server, $port )
00496 {
00497 $str = "DRIVER={IBM DB2 ODBC DRIVER};";
00498 $str .= "DATABASE=$dbName;";
00499 $str .= "HOSTNAME=$server;";
00500 if ($port) $str .= "PORT=$port;";
00501 $str .= "PROTOCOL=TCPIP;";
00502 $str .= "UID=$user;";
00503 $str .= "PWD=$password;";
00504
00505 @$this->mConn = db2_connect($str, $user, $password);
00506 }
00507
00512 public function close() {
00513 $this->mOpened = false;
00514 if ( $this->mConn ) {
00515 if ($this->trxLevel() > 0) {
00516 $this->commit();
00517 }
00518 return db2_close( $this->mConn );
00519 }
00520 else {
00521 return true;
00522 }
00523 }
00524
00536 static function newFromParams( $server, $user, $password, $dbName, $failFunction = false, $flags = 0)
00537 {
00538 return new DatabaseIbm_db2( $server, $user, $password, $dbName, $failFunction, $flags );
00539 }
00540
00545 public function lastError() {
00546 if ($this->lastError2()) {
00547 $this->rollback();
00548 return true;
00549 }
00550 return false;
00551 }
00552
00553 private function lastError2() {
00554 $connerr = db2_conn_errormsg();
00555 if ($connerr) return $connerr;
00556 $stmterr = db2_stmt_errormsg();
00557 if ($stmterr) return $stmterr;
00558 if ($this->mConn) return "No open connection.";
00559 if ($this->mOpened) return "No open connection allegedly.";
00560
00561 return false;
00562 }
00563
00569 public function lastErrno() {
00570 $connerr = db2_conn_error();
00571 if ($connerr) return $connerr;
00572 $stmterr = db2_stmt_error();
00573 if ($stmterr) return $stmterr;
00574 return 0;
00575 }
00576
00581 public function isOpen() { return $this->mOpened; }
00582
00589
00590 public function doQuery( $sql ) {
00591
00592
00593 $this->applySchema();
00594
00595 $ret = db2_exec( $this->mConn, $sql );
00596 if( !$ret ) {
00597 print "<br><pre>";
00598 print $sql;
00599 print "</pre><br>";
00600 $error = db2_stmt_errormsg();
00601 throw new DBUnexpectedError($this, 'SQL error: ' . htmlspecialchars( $error ) );
00602 }
00603 $this->mLastResult = $ret;
00604 $this->mAffectedRows = NULL;
00605 return $ret;
00606 }
00607
00611 public function getServerVersion() {
00612 $info = db2_server_info( $this->mConn );
00613 return $info->DBMS_VER;
00614 }
00615
00620 public function tableExists( $table ) {
00621 $schema = $this->mSchema;
00622 $sql = <<< EOF
00623 SELECT COUNT(*) FROM SYSIBM.SYSTABLES ST
00624 WHERE ST.NAME = '$table' AND ST.CREATOR = '$schema'
00625 EOF;
00626 $res = $this->query( $sql );
00627 if (!$res) return false;
00628
00629
00630 @$row = $this->fetchRow($res);
00631 $count = $row[0];
00632 if ($count == '1' or $count == 1) {
00633 return true;
00634 }
00635
00636 return false;
00637 }
00638
00648 public function fetchObject( $res ) {
00649 if ( $res instanceof ResultWrapper ) {
00650 $res = $res->result;
00651 }
00652 @$row = db2_fetch_object( $res );
00653 if( $this->lastErrno() ) {
00654 throw new DBUnexpectedError( $this, 'Error in fetchObject(): ' . htmlspecialchars( $this->lastError() ) );
00655 }
00656
00657 if ($row)
00658 {
00659 $row2 = new BlankObject();
00660 foreach ($row as $key => $value)
00661 {
00662 $keyu = strtolower($key);
00663 $row2->$keyu = $value;
00664 }
00665 $row = $row2;
00666 }
00667 return $row;
00668 }
00669
00678 public function fetchRow( $res ) {
00679 if ( $res instanceof ResultWrapper ) {
00680 $res = $res->result;
00681 }
00682 @$row = db2_fetch_array( $res );
00683 if ( $this->lastErrno() ) {
00684 throw new DBUnexpectedError( $this, 'Error in fetchRow(): ' . htmlspecialchars( $this->lastError() ) );
00685 }
00686 return $row;
00687 }
00688
00692 public function initial_setup() {
00693
00694 }
00695
00699 public function setup_database() {
00700
00701
00702
00703 try {
00704
00705
00706
00707 $this->applySchema();
00708 $this->begin();
00709
00710 $res = dbsource( "../maintenance/ibm_db2/tables.sql", $this);
00711 $res = null;
00712
00713
00714
00715
00716
00717 $this->commit();
00718 }
00719 catch (MWException $mwe)
00720 {
00721 print "<br><pre>$mwe</pre><br>";
00722 }
00723 }
00724
00731 public function addQuotes( $s ) {
00732
00733 if ( is_null( $s ) ) {
00734 return "NULL";
00735 } else if ($s instanceof Blob) {
00736 return "'".$s->fetch($s)."'";
00737 }
00738 $s = $this->strencode($s);
00739 if ( is_numeric($s) ) {
00740 return $s;
00741 }
00742 else {
00743 return "'$s'";
00744 }
00745 }
00746
00753 public function addQuotesSmart( $table, $field, $s ) {
00754 if ( is_null( $s ) ) {
00755 return "NULL";
00756 } else if ($s instanceof Blob) {
00757 return "'".$s->fetch($s)."'";
00758 }
00759 $s = $this->strencode($s);
00760 if ( is_numeric($s) ) {
00761
00762
00763 $res = $this->doQuery("SELECT $field FROM $table FETCH FIRST 1 ROWS ONLY");
00764 $type = db2_field_type($res, strtoupper($field));
00765 if ( $this->is_numeric_type( $type ) ) {
00766
00767 return $s;
00768 }
00769 else {
00770 wfDebug("DB2: Numeric in non-numeric: '$s' in $type $field in $table\n");
00771 return "'$s'";
00772 }
00773 }
00774 else {
00775 return "'$s'";
00776 }
00777 }
00778
00784 public function is_numeric_type( $type ) {
00785 switch (strtoupper($type)) {
00786 case 'SMALLINT':
00787 case 'INTEGER':
00788 case 'INT':
00789 case 'BIGINT':
00790 case 'DECIMAL':
00791 case 'REAL':
00792 case 'DOUBLE':
00793 case 'DECFLOAT':
00794 return true;
00795 }
00796 return false;
00797 }
00798
00804 public function strencode( $s ) {
00805
00806
00807
00808 $s = db2_escape_string($s);
00809
00810 $s = utf8_encode($s);
00811
00812 $from = array("\\\\", "\\'", '\\n', '\\t', '\\"', '\\r');
00813 $to = array("\\", "''", "\n", "\t", '"', "\r");
00814 $s = str_replace($from, $to, $s);
00815 return $s;
00816 }
00817
00821 protected function applySchema() {
00822 if ( !($this->mSchemaSet) ) {
00823 $this->mSchemaSet = true;
00824 $this->begin();
00825 $this->doQuery("SET SCHEMA = $this->mSchema");
00826 $this->commit();
00827 }
00828 }
00829
00833 public function begin() {
00834
00835 db2_autocommit($this->mConn, DB2_AUTOCOMMIT_OFF);
00836 $this->mTrxLevel = 1;
00837 }
00838
00843 public function commit() {
00844 db2_commit($this->mConn);
00845
00846 db2_autocommit($this->mConn, DB2_AUTOCOMMIT_ON);
00847 $this->mTrxLevel = 0;
00848 }
00849
00853 public function rollback() {
00854 db2_rollback($this->mConn);
00855
00856
00857 db2_autocommit($this->mConn, DB2_AUTOCOMMIT_ON);
00858 $this->mTrxLevel = 0;
00859 }
00860
00870 public function makeList( $a, $mode = LIST_COMMA ) {
00871 wfDebug("DB2::makeList()\n");
00872 if ( !is_array( $a ) ) {
00873 throw new DBUnexpectedError( $this, 'Database::makeList called with incorrect parameters' );
00874 }
00875
00876 $first = true;
00877 $list = '';
00878 foreach ( $a as $field => $value ) {
00879 if ( !$first ) {
00880 if ( $mode == LIST_AND ) {
00881 $list .= ' AND ';
00882 } elseif($mode == LIST_OR) {
00883 $list .= ' OR ';
00884 } else {
00885 $list .= ',';
00886 }
00887 } else {
00888 $first = false;
00889 }
00890 if ( ($mode == LIST_AND || $mode == LIST_OR) && is_numeric( $field ) ) {
00891 $list .= "($value)";
00892 } elseif ( ($mode == LIST_SET) && is_numeric( $field ) ) {
00893 $list .= "$value";
00894 } elseif ( ($mode == LIST_AND || $mode == LIST_OR) && is_array($value) ) {
00895 if( count( $value ) == 0 ) {
00896 throw new MWException( __METHOD__.': empty input' );
00897 } elseif( count( $value ) == 1 ) {
00898
00899
00900
00901 $value = array_values( $value );
00902 $list .= $field." = ".$this->addQuotes( $value[0] );
00903 } else {
00904 $list .= $field." IN (".$this->makeList($value).") ";
00905 }
00906 } elseif( is_null($value) ) {
00907 if ( $mode == LIST_AND || $mode == LIST_OR ) {
00908 $list .= "$field IS ";
00909 } elseif ( $mode == LIST_SET ) {
00910 $list .= "$field = ";
00911 }
00912 $list .= 'NULL';
00913 } else {
00914 if ( $mode == LIST_AND || $mode == LIST_OR || $mode == LIST_SET ) {
00915 $list .= "$field = ";
00916 }
00917 if ( $mode == LIST_NAMES ) {
00918 $list .= $value;
00919 }
00920
00921
00922 else if ( is_numeric($value) ) {
00923 $list .= $value;
00924 }
00925 else {
00926 $list .= $this->addQuotes( $value );
00927 }
00928 }
00929 }
00930 return $list;
00931 }
00932
00946 public function makeListSmart( $table, $a, $mode = LIST_COMMA ) {
00947 if ( !is_array( $a ) ) {
00948 throw new DBUnexpectedError( $this, 'Database::makeList called with incorrect parameters' );
00949 }
00950
00951 $first = true;
00952 $list = '';
00953 foreach ( $a as $field => $value ) {
00954 if ( !$first ) {
00955 if ( $mode == LIST_AND ) {
00956 $list .= ' AND ';
00957 } elseif($mode == LIST_OR) {
00958 $list .= ' OR ';
00959 } else {
00960 $list .= ',';
00961 }
00962 } else {
00963 $first = false;
00964 }
00965 if ( ($mode == LIST_AND || $mode == LIST_OR) && is_numeric( $field ) ) {
00966 $list .= "($value)";
00967 } elseif ( ($mode == LIST_SET) && is_numeric( $field ) ) {
00968 $list .= "$value";
00969 } elseif ( ($mode == LIST_AND || $mode == LIST_OR) && is_array($value) ) {
00970 if( count( $value ) == 0 ) {
00971 throw new MWException( __METHOD__.': empty input' );
00972 } elseif( count( $value ) == 1 ) {
00973
00974
00975
00976 $value = array_values( $value );
00977 $list .= $field." = ".$this->addQuotes( $value[0] );
00978 } else {
00979 $list .= $field." IN (".$this->makeList($value).") ";
00980 }
00981 } elseif( is_null($value) ) {
00982 if ( $mode == LIST_AND || $mode == LIST_OR ) {
00983 $list .= "$field IS ";
00984 } elseif ( $mode == LIST_SET ) {
00985 $list .= "$field = ";
00986 }
00987 $list .= 'NULL';
00988 } else {
00989 if ( $mode == LIST_AND || $mode == LIST_OR || $mode == LIST_SET ) {
00990 $list .= "$field = ";
00991 }
00992 if ( $mode == LIST_NAMES ) {
00993 $list .= $value;
00994 }
00995 else {
00996 $list .= $this->addQuotesSmart( $table, $field, $value );
00997 }
00998 }
00999 }
01000 return $list;
01001 }
01002
01010 public function limitResult($sql, $limit, $offset=false) {
01011 if( !is_numeric($limit) ) {
01012 throw new DBUnexpectedError( $this, "Invalid non-numeric limit passed to limitResult()\n" );
01013 }
01014 if( $offset ) {
01015 wfDebug("Offset parameter not supported in limitResult()\n");
01016 }
01017
01018
01019 return "$sql FETCH FIRST $limit ROWS ONLY ";
01020 }
01021
01027 public function tableName( $name ) {
01028 # Replace reserved words with better ones
01029 switch( $name ) {
01030 case 'user':
01031 return 'mwuser';
01032 case 'text':
01033 return 'pagecontent';
01034 default:
01035 return $name;
01036 }
01037 }
01038
01044 public function timestamp( $ts=0 ) {
01045
01046 return wfTimestamp(TS_DB2,$ts);
01047 }
01048
01054 public function nextSequenceValue( $seqName ) {
01055 $safeseq = preg_replace( "/'/", "''", $seqName );
01056 $res = $this->query( "VALUES NEXTVAL FOR $safeseq" );
01057 $row = $this->fetchRow( $res );
01058 $this->mInsertId = $row[0];
01059 $this->freeResult( $res );
01060 return $this->mInsertId;
01061 }
01062
01067 public function insertId() {
01068 return $this->mInsertId;
01069 }
01070
01084 public function insert( $table, $args, $fname = 'DatabaseIbm_db2::insert', $options = array() ) {
01085 wfDebug("DB2::insert($table)\n");
01086 if ( !count( $args ) ) {
01087 return true;
01088 }
01089
01090 $table = $this->tableName( $table );
01091
01092 if ( !is_array( $options ) )
01093 $options = array( $options );
01094
01095 if ( isset( $args[0] ) && is_array( $args[0] ) ) {
01096 }
01097 else {
01098 $args = array($args);
01099 }
01100 $keys = array_keys( $args[0] );
01101
01102
01103 $ignore = in_array( 'IGNORE', $options ) ? 'mw' : '';
01104
01105
01106 $oldautocommit = db2_autocommit($this->mConn);
01107
01108
01109 $didbegin = 0;
01110 if (! $this->mTrxLevel) {
01111 $this->begin();
01112 $didbegin = 1;
01113 }
01114 if ( $ignore ) {
01115 $olde = error_reporting( 0 );
01116
01117
01118 $numrowsinserted = 0;
01119 }
01120
01121 $sql = "INSERT INTO $table (" . implode( ',', $keys ) . ') VALUES ';
01122
01123 if ( !$ignore ) {
01124 $first = true;
01125 foreach ( $args as $row ) {
01126 if ( $first ) {
01127 $first = false;
01128 } else {
01129 $sql .= ',';
01130 }
01131 $sql .= '(' . $this->makeListSmart( $table, $row ) . ')';
01132 }
01133 $res = (bool)$this->query( $sql, $fname, $ignore );
01134 }
01135 else {
01136 $res = true;
01137 $origsql = $sql;
01138 foreach ( $args as $row ) {
01139 $tempsql = $origsql;
01140 $tempsql .= '(' . $this->makeListSmart( $table, $row ) . ')';
01141
01142 if ( $ignore ) {
01143 db2_exec($this->mConn, "SAVEPOINT $ignore");
01144 }
01145
01146 $tempres = (bool)$this->query( $tempsql, $fname, $ignore );
01147
01148 if ( $ignore ) {
01149 $bar = db2_stmt_error();
01150 if ($bar != false) {
01151 db2_exec( $this->mConn, "ROLLBACK TO SAVEPOINT $ignore" );
01152 }
01153 else {
01154 db2_exec( $this->mConn, "RELEASE SAVEPOINT $ignore" );
01155 $numrowsinserted++;
01156 }
01157 }
01158
01159
01160
01161 if (! $tempres)
01162 $res = false;
01163 }
01164 }
01165
01166 if ($didbegin) {
01167 $this->commit();
01168 }
01169
01170 else if ($oldautocommit)
01171 {
01172 $this->commit();
01173 }
01174
01175 if ( $ignore ) {
01176 $olde = error_reporting( $olde );
01177
01178 $this->mAffectedRows = $numrowsinserted;
01179
01180
01181 return true;
01182 }
01183
01184 return $res;
01185 }
01186
01199 function update( $table, $values, $conds, $fname = 'Database::update', $options = array() ) {
01200 $table = $this->tableName( $table );
01201 $opts = $this->makeUpdateOptions( $options );
01202 $sql = "UPDATE $opts $table SET " . $this->makeListSmart( $table, $values, LIST_SET );
01203 if ( $conds != '*' ) {
01204 $sql .= " WHERE " . $this->makeListSmart( $table, $conds, LIST_AND );
01205 }
01206 return $this->query( $sql, $fname );
01207 }
01208
01214 function delete( $table, $conds, $fname = 'Database::delete' ) {
01215 if ( !$conds ) {
01216 throw new DBUnexpectedError( $this, 'Database::delete() called with no conditions' );
01217 }
01218 $table = $this->tableName( $table );
01219 $sql = "DELETE FROM $table";
01220 if ( $conds != '*' ) {
01221 $sql .= ' WHERE ' . $this->makeListSmart( $table, $conds, LIST_AND );
01222 }
01223 return $this->query( $sql, $fname );
01224 }
01225
01230 public function affectedRows() {
01231 if ( !is_null( $this->mAffectedRows ) ) {
01232
01233 return $this->mAffectedRows;
01234 }
01235 if( empty( $this->mLastResult ) )
01236 return 0;
01237 return db2_num_rows( $this->mLastResult );
01238 }
01239
01245 public function useIndexClause( $index ) {
01246 return "";
01247 }
01248
01257 function replace( $table, $uniqueIndexes, $rows, $fname = 'DatabaseIbm_db2::replace' ) {
01258 $table = $this->tableName( $table );
01259
01260 if (count($rows)==0) {
01261 return;
01262 }
01263
01264 # Single row case
01265 if ( !is_array( reset( $rows ) ) ) {
01266 $rows = array( $rows );
01267 }
01268
01269 foreach( $rows as $row ) {
01270 # Delete rows which collide
01271 if ( $uniqueIndexes ) {
01272 $sql = "DELETE FROM $table WHERE ";
01273 $first = true;
01274 foreach ( $uniqueIndexes as $index ) {
01275 if ( $first ) {
01276 $first = false;
01277 $sql .= "(";
01278 } else {
01279 $sql .= ') OR (';
01280 }
01281 if ( is_array( $index ) ) {
01282 $first2 = true;
01283 foreach ( $index as $col ) {
01284 if ( $first2 ) {
01285 $first2 = false;
01286 } else {
01287 $sql .= ' AND ';
01288 }
01289 $sql .= $col.'=' . $this->addQuotes( $row[$col] );
01290 }
01291 } else {
01292 $sql .= $index.'=' . $this->addQuotes( $row[$index] );
01293 }
01294 }
01295 $sql .= ')';
01296 $this->query( $sql, $fname );
01297 }
01298
01299 # Now insert the row
01300 $sql = "INSERT INTO $table (" . $this->makeList( array_keys( $row ), LIST_NAMES ) .') VALUES (' .
01301 $this->makeList( $row, LIST_COMMA ) . ')';
01302 $this->query( $sql, $fname );
01303 }
01304 }
01305
01312 public function numRows( $res ) {
01313 if ( $res instanceof ResultWrapper ) {
01314 $res = $res->result;
01315 }
01316 if ( $this->mNumRows ) {
01317 return $this->mNumRows;
01318 }
01319 else {
01320 return 0;
01321 }
01322 }
01323
01330 public function dataSeek( $res, $row ) {
01331 if ( $res instanceof ResultWrapper ) {
01332 $res = $res->result;
01333 }
01334 return db2_fetch_row( $res, $row );
01335 }
01336
01337 ###
01338 # Fix notices in Block.php
01339 ###
01340
01346 public function freeResult( $res ) {
01347 if ( $res instanceof ResultWrapper ) {
01348 $res = $res->result;
01349 }
01350 if ( !@db2_free_result( $res ) ) {
01351 throw new DBUnexpectedError($this, "Unable to free DB2 result\n" );
01352 }
01353 }
01354
01360 public function numFields( $res ) {
01361 if ( $res instanceof ResultWrapper ) {
01362 $res = $res->result;
01363 }
01364 return db2_num_fields( $res );
01365 }
01366
01373 public function fieldName( $res, $n ) {
01374 if ( $res instanceof ResultWrapper ) {
01375 $res = $res->result;
01376 }
01377 return db2_field_name( $res, $n );
01378 }
01379
01393 public function select( $table, $vars, $conds='', $fname = 'DatabaseIbm_db2::select', $options = array(), $join_conds = array() )
01394 {
01395 $res = parent::select( $table, $vars, $conds, $fname, $options, $join_conds );
01396
01397
01398 if ( isset( $options['LIMIT'] ) ) {
01399 if ( isset ($options['OFFSET'] ) ) {
01400 $limit = $options['LIMIT'];
01401 $offset = $options['OFFSET'];
01402 }
01403 }
01404
01405
01406
01407
01408
01409
01410
01411 $vars2 = array('count(*) as num_rows');
01412
01413 $options2 = array();
01414 if ( isset( $options['LIMIT'] ) ) $options2['LIMIT'] = $options['LIMIT'];
01415
01416 if ( isset( $options['GROUP BY'] ) ) return $res;
01417
01418 $res2 = parent::select( $table, $vars2, $conds, $fname, $options2, $join_conds );
01419 $obj = $this->fetchObject($res2);
01420 $this->mNumRows = $obj->num_rows;
01421
01422 wfDebug("DatabaseIbm_db2::select: There are $this->mNumRows rows.\n");
01423
01424 return $res;
01425 }
01426
01437 function makeSelectOptions( $options ) {
01438 $preLimitTail = $postLimitTail = '';
01439 $startOpts = '';
01440
01441 $noKeyOptions = array();
01442 foreach ( $options as $key => $option ) {
01443 if ( is_numeric( $key ) ) {
01444 $noKeyOptions[$option] = true;
01445 }
01446 }
01447
01448 if ( isset( $options['GROUP BY'] ) ) $preLimitTail .= " GROUP BY {$options['GROUP BY']}";
01449 if ( isset( $options['HAVING'] ) ) $preLimitTail .= " HAVING {$options['HAVING']}";
01450 if ( isset( $options['ORDER BY'] ) ) $preLimitTail .= " ORDER BY {$options['ORDER BY']}";
01451
01452 if ( isset( $noKeyOptions['DISTINCT'] ) || isset( $noKeyOptions['DISTINCTROW'] ) ) $startOpts .= 'DISTINCT';
01453
01454 return array( $startOpts, '', $preLimitTail, $postLimitTail );
01455 }
01456
01461 public function getSoftwareLink() {
01462 return "[http://www.ibm.com/software/data/db2/express/?s_cmp=ECDDWW01&s_tact=MediaWiki IBM DB2]";
01463 }
01464
01470 public function selectDB( $db ) {
01471 return true;
01472 }
01473
01483 public function conditional( $cond, $trueVal, $falseVal ) {
01484 return " (CASE WHEN $cond THEN $trueVal ELSE $falseVal END) ";
01485 }
01486
01487 ###
01488 # Fix search crash
01489 ###
01490
01496 public function getSearchEngine() {
01497 return "SearchIBM_DB2";
01498 }
01499
01500 ###
01501 # Tuesday the 14th of October, 2008
01502 ###
01503
01507 public function wasDeadlock() {
01508
01509 $err = $this->lastErrno();
01510 switch($err) {
01511 case '40001':
01512 case '57011':
01513 case '57033':
01514 wfDebug("In a deadlock because of SQLSTATE $err");
01515 return true;
01516 }
01517 return false;
01518 }
01519
01525 public function ping() {
01526
01527
01528 $this->close();
01529 if ($this->mCataloged == NULL) {
01530 return false;
01531 }
01532 else if ($this->mCataloged) {
01533 $this->mConn = $this->openCataloged($this->mDBName, $this->mUser, $this->mPassword);
01534 }
01535 else if (!$this->mCataloged) {
01536 $this->mConn = $this->openUncataloged($this->mDBName, $this->mUser, $this->mPassword, $this->mServer, $this->mPort);
01537 }
01538 return false;
01539 }
01540 ######################################
01541 # Unimplemented and not applicable
01542 ######################################
01543
01548 public function getStatus( $which ) { wfDebug('Not implemented for DB2: getStatus()'); return ''; }
01553 public function setTimeout( $timeout ) { wfDebug('Not implemented for DB2: setTimeout()'); }
01559 public function lock( $lockName, $method ) { wfDebug('Not implemented for DB2: lock()'); return true; }
01565 public function unlock( $lockName, $method ) { wfDebug('Not implemented for DB2: unlock()'); return true; }
01570 public function setFakeSlaveLag( $lag ) { wfDebug('Not implemented for DB2: setFakeSlaveLag()'); }
01575 public function setFakeMaster( $enabled ) { wfDebug('Not implemented for DB2: setFakeMaster()'); }
01581 public function limitResultForUpdate($sql, $num) { return $sql; }
01587 public function lowPriorityOption() { return ''; }
01588
01589 ######################################
01590 # Reflection
01591 ######################################
01592
01599 public function fieldExists( $table, $field, $fname = 'DatabaseIbm_db2::fieldExists' ) {
01600 $table = $this->tableName( $table );
01601 $schema = $this->mSchema;
01602 $etable = preg_replace("/'/", "''", $table);
01603 $eschema = preg_replace("/'/", "''", $schema);
01604 $ecol = preg_replace("/'/", "''", $field);
01605 $sql = <<<SQL
01606 SELECT 1 as fieldexists
01607 FROM sysibm.syscolumns sc
01608 WHERE sc.name='$ecol' AND sc.tbname='$etable' AND sc.tbcreator='$eschema'
01609 SQL;
01610 $res = $this->query( $sql, $fname );
01611 $count = $res ? $this->numRows($res) : 0;
01612 if ($res)
01613 $this->freeResult( $res );
01614 return $count;
01615 }
01616
01625 public function indexInfo( $table, $index, $fname = 'DatabaseIbm_db2::indexExists' ) {
01626 $table = $this->tableName( $table );
01627 $sql = <<<SQL
01628 SELECT name as indexname
01629 FROM sysibm.sysindexes si
01630 WHERE si.name='$index' AND si.tbname='$table' AND sc.tbcreator='$this->mSchema'
01631 SQL;
01632 $res = $this->query( $sql, $fname );
01633 if ( !$res ) {
01634 return NULL;
01635 }
01636 $row = $this->fetchObject( $res );
01637 if ($row != NULL) return $row;
01638 else return false;
01639 }
01640
01647 public function fieldInfo( $table, $field ) {
01648 return IBM_DB2Field::fromText($this, $table, $field);
01649 }
01650
01657 public function fieldType( $res, $index ) {
01658 if ( $res instanceof ResultWrapper ) {
01659 $res = $res->result;
01660 }
01661 return db2_field_type( $res, $index );
01662 }
01663
01671 public function indexUnique ($table, $index, $fname = 'Database::indexUnique' ) {
01672 $table = $this->tableName( $table );
01673 $sql = <<<SQL
01674 SELECT si.name as indexname
01675 FROM sysibm.sysindexes si
01676 WHERE si.name='$index' AND si.tbname='$table' AND sc.tbcreator='$this->mSchema'
01677 AND si.uniquerule IN ('U', 'P')
01678 SQL;
01679 $res = $this->query( $sql, $fname );
01680 if ( !$res ) {
01681 return null;
01682 }
01683 if ($this->fetchObject( $res )) {
01684 return true;
01685 }
01686 return false;
01687
01688 }
01689
01696 public function textFieldSize( $table, $field ) {
01697 $table = $this->tableName( $table );
01698 $sql = <<<SQL
01699 SELECT length as size
01700 FROM sysibm.syscolumns sc
01701 WHERE sc.name='$field' AND sc.tbname='$table' AND sc.tbcreator='$this->mSchema'
01702 SQL;
01703 $res = $this->query($sql);
01704 $row = $this->fetchObject($res);
01705 $size = $row->size;
01706 $this->freeResult( $res );
01707 return $size;
01708 }
01709
01719 public function deleteJoin( $delTable, $joinTable, $delVar, $joinVar, $conds, $fname = "DatabaseIbm_db2::deleteJoin" ) {
01720 if ( !$conds ) {
01721 throw new DBUnexpectedError($this, 'Database::deleteJoin() called with empty $conds' );
01722 }
01723
01724 $delTable = $this->tableName( $delTable );
01725 $joinTable = $this->tableName( $joinTable );
01726 $sql = "DELETE FROM $delTable WHERE $delVar IN (SELECT $joinVar FROM $joinTable ";
01727 if ( $conds != '*' ) {
01728 $sql .= 'WHERE ' . $this->makeList( $conds, LIST_AND );
01729 }
01730 $sql .= ')';
01731
01732 $this->query( $sql, $fname );
01733 }
01734
01746 public function estimateRowCount( $table, $vars='*', $conds='', $fname = 'Database::estimateRowCount', $options = array() ) {
01747 $rows = 0;
01748 $res = $this->select ($table, 'COUNT(*) as mwrowcount', $conds, $fname, $options );
01749 if ($res) {
01750 $row = $this->fetchRow($res);
01751 $rows = (isset($row['mwrowcount'])) ? $row['mwrowcount'] : 0;
01752 }
01753 $this->freeResult($res);
01754 return $rows;
01755 }
01756
01762 public function encodeBlob($b) {
01763 return new IBM_DB2Blob($b);
01764 }
01765
01771 public function decodeBlob($b) {
01772 return $b->getData();
01773 }
01774
01780 public function buildConcat( $stringList ) {
01781
01782
01783 return implode( ' || ', $stringList );
01784 }
01785
01791 public function extractUnixEpoch( $column ) {
01792
01793
01794 }
01795 }
01796 ?>