r71634 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r71633‎ | r71634 | r71635 >
Date:17:45, 25 August 2010
Author:reedy
Status:reverted (Comments)
Tags:
Comment:
Move insertOnDupeUpdate (and rename to insertOrUpdate) to DatabaseMysql. Add todo/fixme in insertOrUpdate in DatabaseBase

Add some braces
Modified paths:
  • /trunk/phase3/includes/db/Database.php (modified) (history)
  • /trunk/phase3/includes/db/DatabaseMysql.php (modified) (history)

Diff [purge]

Index: trunk/phase3/includes/db/DatabaseMysql.php
@@ -253,8 +253,9 @@
254254 public function estimateRowCount( $table, $vars='*', $conds='', $fname = 'Database::estimateRowCount', $options = array() ) {
255255 $options['EXPLAIN'] = true;
256256 $res = $this->select( $table, $vars, $conds, $fname, $options );
257 - if ( $res === false )
 257+ if ( $res === false ) {
258258 return false;
 259+ }
259260 if ( !$this->numRows( $res ) ) {
260261 return 0;
261262 }
@@ -350,6 +351,66 @@
351352 return false;
352353 }
353354
 355+ /**
 356+ * INSERT ... ON DUPE UPDATE wrapper, inserts an array into a table, optionally updating if
 357+ * duplicate primary key found
 358+ *
 359+ * $a may be a single associative array, or an array of these with numeric keys, for
 360+ * multi-row insert.
 361+ *
 362+ * Usually aborts on failure
 363+ * If errors are explicitly ignored, returns success
 364+ *
 365+ * @param $table String: table name (prefix auto-added)
 366+ * @param $a Array: Array of rows to insert
 367+ * @param $fname String: Calling function name (use __METHOD__) for logs/profiling
 368+ * @param $options Mixed: Associative array of options
 369+ * @param $onDupeUpdate Array: Associative array of fields to update on duplicate
 370+ *
 371+ * @return bool
 372+ */
 373+ function insertOrUpdate( $table, $a, $fname = 'DatabaseBase::insertOnDupeUpdate', $options = array(), $onDupeUpdate = array() ) {
 374+ # No rows to insert, easy just return now
 375+ if ( !count( $a ) ) {
 376+ return true;
 377+ }
 378+
 379+ $table = $this->tableName( $table );
 380+ if ( !is_array( $options ) ) {
 381+ $options = array( $options );
 382+ }
 383+ if ( isset( $a[0] ) && is_array( $a[0] ) ) {
 384+ $multi = true;
 385+ $keys = array_keys( $a[0] );
 386+ } else {
 387+ $multi = false;
 388+ $keys = array_keys( $a );
 389+ }
 390+
 391+ $sql = 'INSERT ' . implode( ' ', $options ) .
 392+ " INTO $table (" . implode( ',', $keys ) . ') VALUES ';
 393+
 394+ if ( $multi ) {
 395+ $first = true;
 396+ foreach ( $a as $row ) {
 397+ if ( $first ) {
 398+ $first = false;
 399+ } else {
 400+ $sql .= ',';
 401+ }
 402+ $sql .= '(' . $this->makeList( $row ) . ')';
 403+ }
 404+ } else {
 405+ $sql .= '(' . $this->makeList( $a ) . ')';
 406+ }
 407+
 408+ if ( count( $onDupeUpdate ) ) {
 409+ $sql .= ' ON DUPLICATE KEY UPDATE ' . $this->makeList( $onDupeUpdate );
 410+ }
 411+
 412+ return (bool)$this->query( $sql, $fname );
 413+ }
 414+
354415 function getServerVersion() {
355416 return mysql_get_server_info( $this->mConn );
356417 }
Index: trunk/phase3/includes/db/Database.php
@@ -1115,28 +1115,6 @@
11161116 * @return bool
11171117 */
11181118 function insert( $table, $a, $fname = 'DatabaseBase::insert', $options = array() ) {
1119 - return $this->insertOnDupeUpdate( $table, $a, $fname, $options );
1120 - }
1121 -
1122 - /**
1123 - * INSERT ... ON DUPE UPDATE wrapper, inserts an array into a table, optionally updating if
1124 - * duplicate primary key found
1125 - *
1126 - * $a may be a single associative array, or an array of these with numeric keys, for
1127 - * multi-row insert.
1128 - *
1129 - * Usually aborts on failure
1130 - * If errors are explicitly ignored, returns success
1131 - *
1132 - * @param $table String: table name (prefix auto-added)
1133 - * @param $a Array: Array of rows to insert
1134 - * @param $fname String: Calling function name (use __METHOD__) for logs/profiling
1135 - * @param $options Mixed: Associative array of options
1136 - * @param $onDupeUpdate Array: Associative array of fields to update on duplicate
1137 - *
1138 - * @return bool
1139 - */
1140 - function insertOnDupeUpdate( $table, $a, $fname = 'DatabaseBase::insertOnDupeUpdate', $options = array(), $onDupeUpdate = array() ) {
11411119 # No rows to insert, easy just return now
11421120 if ( !count( $a ) ) {
11431121 return true;
@@ -1170,15 +1148,35 @@
11711149 } else {
11721150 $sql .= '(' . $this->makeList( $a ) . ')';
11731151 }
1174 -
1175 - if ( count( $onDupeUpdate ) ) {
1176 - $sql .= ' ON DUPLICATE KEY UPDATE ' . $this->makeList( $onDupeUpdate );
1177 - }
1178 -
 1152+
11791153 return (bool)$this->query( $sql, $fname );
11801154 }
11811155
11821156 /**
 1157+ * INSERT ... ON DUPE UPDATE wrapper, inserts an array into a table, optionally updating if
 1158+ * duplicate primary key found
 1159+ *
 1160+ * $a may be a single associative array, or an array of these with numeric keys, for
 1161+ * multi-row insert.
 1162+ *
 1163+ * Usually aborts on failure
 1164+ * If errors are explicitly ignored, returns success
 1165+ *
 1166+ * @param $table String: table name (prefix auto-added)
 1167+ * @param $a Array: Array of rows to insert
 1168+ * @param $fname String: Calling function name (use __METHOD__) for logs/profiling
 1169+ * @param $options Mixed: Associative array of options
 1170+ * @param $onDupeUpdate Array: Associative array of fields to update on duplicate
 1171+ *
 1172+ * @return bool
 1173+ */
 1174+ function insertOrUpdate( $table, $a, $fname = 'DatabaseBase::insertOnDupeUpdate', $options = array(), $onDupeUpdate = array() ) {
 1175+ //TODO:FIXME
 1176+ //$this->select();
 1177+ //$this->replace();
 1178+ }
 1179+
 1180+ /**
11831181 * Make UPDATE options for the DatabaseBase::update function
11841182 *
11851183 * @private
@@ -1190,10 +1188,12 @@
11911189 $options = array( $options );
11921190 }
11931191 $opts = array();
1194 - if ( in_array( 'LOW_PRIORITY', $options ) )
 1192+ if ( in_array( 'LOW_PRIORITY', $options ) ) {
11951193 $opts[] = $this->lowPriorityOption();
1196 - if ( in_array( 'IGNORE', $options ) )
 1194+ }
 1195+ if ( in_array( 'IGNORE', $options ) ) {
11971196 $opts[] = 'IGNORE';
 1197+ }
11981198 return implode(' ', $opts);
11991199 }
12001200
@@ -1369,7 +1369,9 @@
13701370 # Note that we check the end so that we will still quote any use of
13711371 # use of `database`.table. But won't break things if someone wants
13721372 # to query a database table with a dot in the name.
1373 - if ( $name[0] == '`' && substr( $name, -1, 1 ) == '`' ) return $name;
 1373+ if ( $name[0] == '`' && substr( $name, -1, 1 ) == '`' ) {
 1374+ return $name;
 1375+ }
13741376
13751377 # Lets test for any bits of text that should never show up in a table
13761378 # name. Basically anything like JOIN or ON which are actually part of
@@ -1378,19 +1380,26 @@
13791381 # Note that we use a whitespace test rather than a \b test to avoid
13801382 # any remote case where a word like on may be inside of a table name
13811383 # surrounded by symbols which may be considered word breaks.
1382 - if( preg_match( '/(^|\s)(DISTINCT|JOIN|ON|AS)(\s|$)/i', $name ) !== 0 ) return $name;
 1384+ if( preg_match( '/(^|\s)(DISTINCT|JOIN|ON|AS)(\s|$)/i', $name ) !== 0 ) {
 1385+ return $name;
 1386+ }
13831387
13841388 # Split database and table into proper variables.
13851389 # We reverse the explode so that database.table and table both output
13861390 # the correct table.
13871391 $dbDetails = array_reverse( explode( '.', $name, 2 ) );
1388 - if( isset( $dbDetails[1] ) ) @list( $table, $database ) = $dbDetails;
1389 - else @list( $table ) = $dbDetails;
 1392+ if( isset( $dbDetails[1] ) ) {
 1393+ @list( $table, $database ) = $dbDetails;
 1394+ } else {
 1395+ @list( $table ) = $dbDetails;
 1396+ }
13901397 $prefix = $this->mTablePrefix; # Default prefix
13911398
13921399 # A database name has been specified in input. Quote the table name
13931400 # because we don't want any prefixes added.
1394 - if( isset($database) ) $table = ( $table[0] == '`' ? $table : "`{$table}`" );
 1401+ if( isset($database) ) {
 1402+ $table = ( $table[0] == '`' ? $table : "`{$table}`" );
 1403+ }
13951404
13961405 # Note that we use the long format because php will complain in in_array if
13971406 # the input is not an array, and will complain in is_array if it is not set.
@@ -1405,7 +1414,9 @@
14061415 }
14071416
14081417 # Quote the $database and $table and apply the prefix if not quoted.
1409 - if( isset($database) ) $database = ( $database[0] == '`' ? $database : "`{$database}`" );
 1418+ if( isset($database) ) {
 1419+ $database = ( $database[0] == '`' ? $database : "`{$database}`" );
 1420+ }
14101421 $table = ( $table[0] == '`' ? $table : "`{$prefix}{$table}`" );
14111422
14121423 # Merge our database and table into our final table name.

Follow-up revisions

RevisionCommit summaryAuthorDate
r71648Update method names per r71634reedy19:05, 25 August 2010
r71662Fill out insertOrUpdate in DatabaseBase, rather than blank stub. Followup to ...reedy21:46, 25 August 2010

Comments

#Comment by Reedy (talk | contribs)   17:46, 25 August 2010

Needs some refactoring. It causes quite a lot of duplication of insert()

#Comment by Simetrical (talk | contribs)   16:29, 27 August 2010

We still support MySQL 4.0; a number of Wikimedia slaves and masters still run it. ON DUPLICATE KEY UPDATE was only added in 4.1:

http://dev.mysql.com/doc/refman/4.1/en/insert-on-duplicate.html

You'll have to detect that case and call the parent method. Overall, though, this is going to be hard to implement consistently across DBs, so I'd really recommend just getting rid of it and using standard SQL like INSERT and UPDATE. This is a very MySQL-specific thing, and trying to make it work the same in MySQL and other DBs (or even MySQL 4.0 and later MySQL) in the face of concurrent access to the affected rows is probably a losing battle.

#Comment by Reedy (talk | contribs)   16:43, 27 August 2010

Bah. Didn't see that. Looked at the "4.x" documentation, and presumed we'd be ok.

That then means, something akin to what I did in the base implementation, adding in the FOR UPDATE?

Status & tagging log