MediaWiki
REL1_21
|
00001 <?php 00031 class DatabaseMysql extends DatabaseBase { 00032 00036 function getType() { 00037 return 'mysql'; 00038 } 00039 00044 protected function doQuery( $sql ) { 00045 if( $this->bufferResults() ) { 00046 $ret = mysql_query( $sql, $this->mConn ); 00047 } else { 00048 $ret = mysql_unbuffered_query( $sql, $this->mConn ); 00049 } 00050 return $ret; 00051 } 00052 00061 function open( $server, $user, $password, $dbName ) { 00062 global $wgAllDBsAreLocalhost, $wgDBmysql5, $wgSQLMode; 00063 wfProfileIn( __METHOD__ ); 00064 00065 # Load mysql.so if we don't have it 00066 wfDl( 'mysql' ); 00067 00068 # Fail now 00069 # Otherwise we get a suppressed fatal error, which is very hard to track down 00070 if ( !function_exists( 'mysql_connect' ) ) { 00071 throw new DBConnectionError( $this, "MySQL functions missing, have you compiled PHP with the --with-mysql option?\n" ); 00072 } 00073 00074 # Debugging hack -- fake cluster 00075 if ( $wgAllDBsAreLocalhost ) { 00076 $realServer = 'localhost'; 00077 } else { 00078 $realServer = $server; 00079 } 00080 $this->close(); 00081 $this->mServer = $server; 00082 $this->mUser = $user; 00083 $this->mPassword = $password; 00084 $this->mDBname = $dbName; 00085 00086 $connFlags = 0; 00087 if ( $this->mFlags & DBO_SSL ) { 00088 $connFlags |= MYSQL_CLIENT_SSL; 00089 } 00090 if ( $this->mFlags & DBO_COMPRESS ) { 00091 $connFlags |= MYSQL_CLIENT_COMPRESS; 00092 } 00093 00094 wfProfileIn( "dbconnect-$server" ); 00095 00096 # The kernel's default SYN retransmission period is far too slow for us, 00097 # so we use a short timeout plus a manual retry. Retrying means that a small 00098 # but finite rate of SYN packet loss won't cause user-visible errors. 00099 $this->mConn = false; 00100 if ( ini_get( 'mysql.connect_timeout' ) <= 3 ) { 00101 $numAttempts = 2; 00102 } else { 00103 $numAttempts = 1; 00104 } 00105 $this->installErrorHandler(); 00106 for ( $i = 0; $i < $numAttempts && !$this->mConn; $i++ ) { 00107 if ( $i > 1 ) { 00108 usleep( 1000 ); 00109 } 00110 if ( $this->mFlags & DBO_PERSISTENT ) { 00111 $this->mConn = mysql_pconnect( $realServer, $user, $password, $connFlags ); 00112 } else { 00113 # Create a new connection... 00114 $this->mConn = mysql_connect( $realServer, $user, $password, true, $connFlags ); 00115 } 00116 #if ( $this->mConn === false ) { 00117 #$iplus = $i + 1; 00118 #wfLogDBError("Connect loop error $iplus of $max ($server): " . mysql_errno() . " - " . mysql_error()."\n"); 00119 #} 00120 } 00121 $error = $this->restoreErrorHandler(); 00122 00123 wfProfileOut( "dbconnect-$server" ); 00124 00125 # Always log connection errors 00126 if ( !$this->mConn ) { 00127 if ( !$error ) { 00128 $error = $this->lastError(); 00129 } 00130 wfLogDBError( "Error connecting to {$this->mServer}: $error\n" ); 00131 wfDebug( "DB connection error\n" . 00132 "Server: $server, User: $user, Password: " . 00133 substr( $password, 0, 3 ) . "..., error: " . $error . "\n" ); 00134 00135 wfProfileOut( __METHOD__ ); 00136 return $this->reportConnectionError( $error ); 00137 } 00138 00139 if ( $dbName != '' ) { 00140 wfSuppressWarnings(); 00141 $success = mysql_select_db( $dbName, $this->mConn ); 00142 wfRestoreWarnings(); 00143 if ( !$success ) { 00144 wfLogDBError( "Error selecting database $dbName on server {$this->mServer}\n" ); 00145 wfDebug( "Error selecting database $dbName on server {$this->mServer} " . 00146 "from client host " . wfHostname() . "\n" ); 00147 00148 wfProfileOut( __METHOD__ ); 00149 return $this->reportConnectionError( "Error selecting database $dbName" ); 00150 } 00151 } 00152 00153 // Tell the server we're communicating with it in UTF-8. 00154 // This may engage various charset conversions. 00155 if( $wgDBmysql5 ) { 00156 $this->query( 'SET NAMES utf8', __METHOD__ ); 00157 } else { 00158 $this->query( 'SET NAMES binary', __METHOD__ ); 00159 } 00160 // Set SQL mode, default is turning them all off, can be overridden or skipped with null 00161 if ( is_string( $wgSQLMode ) ) { 00162 $mode = $this->addQuotes( $wgSQLMode ); 00163 $this->query( "SET sql_mode = $mode", __METHOD__ ); 00164 } 00165 00166 $this->mOpened = true; 00167 wfProfileOut( __METHOD__ ); 00168 return true; 00169 } 00170 00174 protected function closeConnection() { 00175 return mysql_close( $this->mConn ); 00176 } 00177 00182 function freeResult( $res ) { 00183 if ( $res instanceof ResultWrapper ) { 00184 $res = $res->result; 00185 } 00186 wfSuppressWarnings(); 00187 $ok = mysql_free_result( $res ); 00188 wfRestoreWarnings(); 00189 if ( !$ok ) { 00190 throw new DBUnexpectedError( $this, "Unable to free MySQL result" ); 00191 } 00192 } 00193 00199 function fetchObject( $res ) { 00200 if ( $res instanceof ResultWrapper ) { 00201 $res = $res->result; 00202 } 00203 wfSuppressWarnings(); 00204 $row = mysql_fetch_object( $res ); 00205 wfRestoreWarnings(); 00206 00207 $errno = $this->lastErrno(); 00208 // Unfortunately, mysql_fetch_object does not reset the last errno. 00209 // Only check for CR_SERVER_LOST and CR_UNKNOWN_ERROR, as 00210 // these are the only errors mysql_fetch_object can cause. 00211 // See http://dev.mysql.com/doc/refman/5.0/en/mysql-fetch-row.html. 00212 if( $errno == 2000 || $errno == 2013 ) { 00213 throw new DBUnexpectedError( $this, 'Error in fetchObject(): ' . htmlspecialchars( $this->lastError() ) ); 00214 } 00215 return $row; 00216 } 00217 00223 function fetchRow( $res ) { 00224 if ( $res instanceof ResultWrapper ) { 00225 $res = $res->result; 00226 } 00227 wfSuppressWarnings(); 00228 $row = mysql_fetch_array( $res ); 00229 wfRestoreWarnings(); 00230 00231 $errno = $this->lastErrno(); 00232 // Unfortunately, mysql_fetch_array does not reset the last errno. 00233 // Only check for CR_SERVER_LOST and CR_UNKNOWN_ERROR, as 00234 // these are the only errors mysql_fetch_object can cause. 00235 // See http://dev.mysql.com/doc/refman/5.0/en/mysql-fetch-row.html. 00236 if( $errno == 2000 || $errno == 2013 ) { 00237 throw new DBUnexpectedError( $this, 'Error in fetchRow(): ' . htmlspecialchars( $this->lastError() ) ); 00238 } 00239 return $row; 00240 } 00241 00247 function numRows( $res ) { 00248 if ( $res instanceof ResultWrapper ) { 00249 $res = $res->result; 00250 } 00251 wfSuppressWarnings(); 00252 $n = mysql_num_rows( $res ); 00253 wfRestoreWarnings(); 00254 // Unfortunately, mysql_num_rows does not reset the last errno. 00255 // We are not checking for any errors here, since 00256 // these are no errors mysql_num_rows can cause. 00257 // See http://dev.mysql.com/doc/refman/5.0/en/mysql-fetch-row.html. 00258 // See https://bugzilla.wikimedia.org/42430 00259 return $n; 00260 } 00261 00266 function numFields( $res ) { 00267 if ( $res instanceof ResultWrapper ) { 00268 $res = $res->result; 00269 } 00270 return mysql_num_fields( $res ); 00271 } 00272 00278 function fieldName( $res, $n ) { 00279 if ( $res instanceof ResultWrapper ) { 00280 $res = $res->result; 00281 } 00282 return mysql_field_name( $res, $n ); 00283 } 00284 00288 function insertId() { 00289 return mysql_insert_id( $this->mConn ); 00290 } 00291 00297 function dataSeek( $res, $row ) { 00298 if ( $res instanceof ResultWrapper ) { 00299 $res = $res->result; 00300 } 00301 return mysql_data_seek( $res, $row ); 00302 } 00303 00307 function lastErrno() { 00308 if ( $this->mConn ) { 00309 return mysql_errno( $this->mConn ); 00310 } else { 00311 return mysql_errno(); 00312 } 00313 } 00314 00318 function lastError() { 00319 if ( $this->mConn ) { 00320 # Even if it's non-zero, it can still be invalid 00321 wfSuppressWarnings(); 00322 $error = mysql_error( $this->mConn ); 00323 if ( !$error ) { 00324 $error = mysql_error(); 00325 } 00326 wfRestoreWarnings(); 00327 } else { 00328 $error = mysql_error(); 00329 } 00330 if( $error ) { 00331 $error .= ' (' . $this->mServer . ')'; 00332 } 00333 return $error; 00334 } 00335 00339 function affectedRows() { 00340 return mysql_affected_rows( $this->mConn ); 00341 } 00342 00350 function replace( $table, $uniqueIndexes, $rows, $fname = 'DatabaseMysql::replace' ) { 00351 return $this->nativeReplace( $table, $rows, $fname ); 00352 } 00353 00366 public function estimateRowCount( $table, $vars = '*', $conds = '', $fname = 'DatabaseMysql::estimateRowCount', $options = array() ) { 00367 $options['EXPLAIN'] = true; 00368 $res = $this->select( $table, $vars, $conds, $fname, $options ); 00369 if ( $res === false ) { 00370 return false; 00371 } 00372 if ( !$this->numRows( $res ) ) { 00373 return 0; 00374 } 00375 00376 $rows = 1; 00377 foreach ( $res as $plan ) { 00378 $rows *= $plan->rows > 0 ? $plan->rows : 1; // avoid resetting to zero 00379 } 00380 return $rows; 00381 } 00382 00388 function fieldInfo( $table, $field ) { 00389 $table = $this->tableName( $table ); 00390 $res = $this->query( "SELECT * FROM $table LIMIT 1", __METHOD__, true ); 00391 if ( !$res ) { 00392 return false; 00393 } 00394 $n = mysql_num_fields( $res->result ); 00395 for( $i = 0; $i < $n; $i++ ) { 00396 $meta = mysql_fetch_field( $res->result, $i ); 00397 if( $field == $meta->name ) { 00398 return new MySQLField( $meta ); 00399 } 00400 } 00401 return false; 00402 } 00403 00413 function indexInfo( $table, $index, $fname = 'DatabaseMysql::indexInfo' ) { 00414 # SHOW INDEX works in MySQL 3.23.58, but SHOW INDEXES does not. 00415 # SHOW INDEX should work for 3.x and up: 00416 # http://dev.mysql.com/doc/mysql/en/SHOW_INDEX.html 00417 $table = $this->tableName( $table ); 00418 $index = $this->indexName( $index ); 00419 00420 $sql = 'SHOW INDEX FROM ' . $table; 00421 $res = $this->query( $sql, $fname ); 00422 00423 if ( !$res ) { 00424 return null; 00425 } 00426 00427 $result = array(); 00428 00429 foreach ( $res as $row ) { 00430 if ( $row->Key_name == $index ) { 00431 $result[] = $row; 00432 } 00433 } 00434 return empty( $result ) ? false : $result; 00435 } 00436 00441 function selectDB( $db ) { 00442 $this->mDBname = $db; 00443 return mysql_select_db( $db, $this->mConn ); 00444 } 00445 00451 function strencode( $s ) { 00452 $sQuoted = mysql_real_escape_string( $s, $this->mConn ); 00453 00454 if( $sQuoted === false ) { 00455 $this->ping(); 00456 $sQuoted = mysql_real_escape_string( $s, $this->mConn ); 00457 } 00458 return $sQuoted; 00459 } 00460 00468 public function addIdentifierQuotes( $s ) { 00469 return "`" . $this->strencode( $s ) . "`"; 00470 } 00471 00476 public function isQuotedIdentifier( $name ) { 00477 return strlen( $name ) && $name[0] == '`' && substr( $name, -1, 1 ) == '`'; 00478 } 00479 00483 function ping() { 00484 $ping = mysql_ping( $this->mConn ); 00485 if ( $ping ) { 00486 return true; 00487 } 00488 00489 mysql_close( $this->mConn ); 00490 $this->mOpened = false; 00491 $this->mConn = false; 00492 $this->open( $this->mServer, $this->mUser, $this->mPassword, $this->mDBname ); 00493 return true; 00494 } 00495 00503 function getLag() { 00504 if ( !is_null( $this->mFakeSlaveLag ) ) { 00505 wfDebug( "getLag: fake slave lagged {$this->mFakeSlaveLag} seconds\n" ); 00506 return $this->mFakeSlaveLag; 00507 } 00508 00509 return $this->getLagFromSlaveStatus(); 00510 } 00511 00515 function getLagFromSlaveStatus() { 00516 $res = $this->query( 'SHOW SLAVE STATUS', __METHOD__ ); 00517 if ( !$res ) { 00518 return false; 00519 } 00520 $row = $res->fetchObject(); 00521 if ( !$row ) { 00522 return false; 00523 } 00524 if ( strval( $row->Seconds_Behind_Master ) === '' ) { 00525 return false; 00526 } else { 00527 return intval( $row->Seconds_Behind_Master ); 00528 } 00529 } 00530 00536 function getLagFromProcesslist() { 00537 wfDeprecated( __METHOD__, '1.19' ); 00538 $res = $this->query( 'SHOW PROCESSLIST', __METHOD__ ); 00539 if( !$res ) { 00540 return false; 00541 } 00542 # Find slave SQL thread 00543 foreach( $res as $row ) { 00544 /* This should work for most situations - when default db 00545 * for thread is not specified, it had no events executed, 00546 * and therefore it doesn't know yet how lagged it is. 00547 * 00548 * Relay log I/O thread does not select databases. 00549 */ 00550 if ( $row->User == 'system user' && 00551 $row->State != 'Waiting for master to send event' && 00552 $row->State != 'Connecting to master' && 00553 $row->State != 'Queueing master event to the relay log' && 00554 $row->State != 'Waiting for master update' && 00555 $row->State != 'Requesting binlog dump' && 00556 $row->State != 'Waiting to reconnect after a failed master event read' && 00557 $row->State != 'Reconnecting after a failed master event read' && 00558 $row->State != 'Registering slave on master' 00559 ) { 00560 # This is it, return the time (except -ve) 00561 if ( $row->Time > 0x7fffffff ) { 00562 return false; 00563 } else { 00564 return $row->Time; 00565 } 00566 } 00567 } 00568 return false; 00569 } 00570 00578 function masterPosWait( DBMasterPos $pos, $timeout ) { 00579 $fname = 'DatabaseBase::masterPosWait'; 00580 wfProfileIn( $fname ); 00581 00582 # Commit any open transactions 00583 if ( $this->mTrxLevel ) { 00584 $this->commit( __METHOD__ ); 00585 } 00586 00587 if ( !is_null( $this->mFakeSlaveLag ) ) { 00588 $status = parent::masterPosWait( $pos, $timeout ); 00589 wfProfileOut( $fname ); 00590 return $status; 00591 } 00592 00593 # Call doQuery() directly, to avoid opening a transaction if DBO_TRX is set 00594 $encFile = $this->addQuotes( $pos->file ); 00595 $encPos = intval( $pos->pos ); 00596 $sql = "SELECT MASTER_POS_WAIT($encFile, $encPos, $timeout)"; 00597 $res = $this->doQuery( $sql ); 00598 00599 if ( $res && $row = $this->fetchRow( $res ) ) { 00600 wfProfileOut( $fname ); 00601 return $row[0]; 00602 } 00603 wfProfileOut( $fname ); 00604 return false; 00605 } 00606 00612 function getSlavePos() { 00613 if ( !is_null( $this->mFakeSlaveLag ) ) { 00614 return parent::getSlavePos(); 00615 } 00616 00617 $res = $this->query( 'SHOW SLAVE STATUS', 'DatabaseBase::getSlavePos' ); 00618 $row = $this->fetchObject( $res ); 00619 00620 if ( $row ) { 00621 $pos = isset( $row->Exec_master_log_pos ) ? $row->Exec_master_log_pos : $row->Exec_Master_Log_Pos; 00622 return new MySQLMasterPos( $row->Relay_Master_Log_File, $pos ); 00623 } else { 00624 return false; 00625 } 00626 } 00627 00633 function getMasterPos() { 00634 if ( $this->mFakeMaster ) { 00635 return parent::getMasterPos(); 00636 } 00637 00638 $res = $this->query( 'SHOW MASTER STATUS', 'DatabaseBase::getMasterPos' ); 00639 $row = $this->fetchObject( $res ); 00640 00641 if ( $row ) { 00642 return new MySQLMasterPos( $row->File, $row->Position ); 00643 } else { 00644 return false; 00645 } 00646 } 00647 00651 function getServerVersion() { 00652 return mysql_get_server_info( $this->mConn ); 00653 } 00654 00659 function useIndexClause( $index ) { 00660 return "FORCE INDEX (" . $this->indexName( $index ) . ")"; 00661 } 00662 00666 function lowPriorityOption() { 00667 return 'LOW_PRIORITY'; 00668 } 00669 00673 public static function getSoftwareLink() { 00674 return '[http://www.mysql.com/ MySQL]'; 00675 } 00676 00680 public function setSessionOptions( array $options ) { 00681 if ( isset( $options['connTimeout'] ) ) { 00682 $timeout = (int)$options['connTimeout']; 00683 $this->query( "SET net_read_timeout=$timeout" ); 00684 $this->query( "SET net_write_timeout=$timeout" ); 00685 } 00686 } 00687 00688 public function streamStatementEnd( &$sql, &$newLine ) { 00689 if ( strtoupper( substr( $newLine, 0, 9 ) ) == 'DELIMITER' ) { 00690 preg_match( '/^DELIMITER\s+(\S+)/', $newLine, $m ); 00691 $this->delimiter = $m[1]; 00692 $newLine = ''; 00693 } 00694 return parent::streamStatementEnd( $sql, $newLine ); 00695 } 00696 00705 public function lockIsFree( $lockName, $method ) { 00706 $lockName = $this->addQuotes( $lockName ); 00707 $result = $this->query( "SELECT IS_FREE_LOCK($lockName) AS lockstatus", $method ); 00708 $row = $this->fetchObject( $result ); 00709 return ( $row->lockstatus == 1 ); 00710 } 00711 00718 public function lock( $lockName, $method, $timeout = 5 ) { 00719 $lockName = $this->addQuotes( $lockName ); 00720 $result = $this->query( "SELECT GET_LOCK($lockName, $timeout) AS lockstatus", $method ); 00721 $row = $this->fetchObject( $result ); 00722 00723 if( $row->lockstatus == 1 ) { 00724 return true; 00725 } else { 00726 wfDebug( __METHOD__ . " failed to acquire lock\n" ); 00727 return false; 00728 } 00729 } 00730 00737 public function unlock( $lockName, $method ) { 00738 $lockName = $this->addQuotes( $lockName ); 00739 $result = $this->query( "SELECT RELEASE_LOCK($lockName) as lockstatus", $method ); 00740 $row = $this->fetchObject( $result ); 00741 return ( $row->lockstatus == 1 ); 00742 } 00743 00751 public function lockTables( $read, $write, $method, $lowPriority = true ) { 00752 $items = array(); 00753 00754 foreach( $write as $table ) { 00755 $tbl = $this->tableName( $table ) . 00756 ( $lowPriority ? ' LOW_PRIORITY' : '' ) . 00757 ' WRITE'; 00758 $items[] = $tbl; 00759 } 00760 foreach( $read as $table ) { 00761 $items[] = $this->tableName( $table ) . ' READ'; 00762 } 00763 $sql = "LOCK TABLES " . implode( ',', $items ); 00764 $this->query( $sql, $method ); 00765 return true; 00766 } 00767 00772 public function unlockTables( $method ) { 00773 $this->query( "UNLOCK TABLES", $method ); 00774 return true; 00775 } 00776 00783 public function getSearchEngine() { 00784 return 'SearchMySQL'; 00785 } 00786 00791 public function setBigSelects( $value = true ) { 00792 if ( $value === 'default' ) { 00793 if ( $this->mDefaultBigSelects === null ) { 00794 # Function hasn't been called before so it must already be set to the default 00795 return; 00796 } else { 00797 $value = $this->mDefaultBigSelects; 00798 } 00799 } elseif ( $this->mDefaultBigSelects === null ) { 00800 $this->mDefaultBigSelects = (bool)$this->selectField( false, '@@sql_big_selects' ); 00801 } 00802 $encValue = $value ? '1' : '0'; 00803 $this->query( "SET sql_big_selects=$encValue", __METHOD__ ); 00804 } 00805 00817 function deleteJoin( $delTable, $joinTable, $delVar, $joinVar, $conds, $fname = 'DatabaseBase::deleteJoin' ) { 00818 if ( !$conds ) { 00819 throw new DBUnexpectedError( $this, 'DatabaseBase::deleteJoin() called with empty $conds' ); 00820 } 00821 00822 $delTable = $this->tableName( $delTable ); 00823 $joinTable = $this->tableName( $joinTable ); 00824 $sql = "DELETE $delTable FROM $delTable, $joinTable WHERE $delVar=$joinVar "; 00825 00826 if ( $conds != '*' ) { 00827 $sql .= ' AND ' . $this->makeList( $conds, LIST_AND ); 00828 } 00829 00830 return $this->query( $sql, $fname ); 00831 } 00832 00838 function getServerUptime() { 00839 $vars = $this->getMysqlStatus( 'Uptime' ); 00840 return (int)$vars['Uptime']; 00841 } 00842 00848 function wasDeadlock() { 00849 return $this->lastErrno() == 1213; 00850 } 00851 00857 function wasLockTimeout() { 00858 return $this->lastErrno() == 1205; 00859 } 00860 00867 function wasErrorReissuable() { 00868 return $this->lastErrno() == 2013 || $this->lastErrno() == 2006; 00869 } 00870 00876 function wasReadOnlyError() { 00877 return $this->lastErrno() == 1223 || 00878 ( $this->lastErrno() == 1290 && strpos( $this->lastError(), '--read-only' ) !== false ); 00879 } 00880 00887 function duplicateTableStructure( $oldName, $newName, $temporary = false, $fname = 'DatabaseMysql::duplicateTableStructure' ) { 00888 $tmp = $temporary ? 'TEMPORARY ' : ''; 00889 $newName = $this->addIdentifierQuotes( $newName ); 00890 $oldName = $this->addIdentifierQuotes( $oldName ); 00891 $query = "CREATE $tmp TABLE $newName (LIKE $oldName)"; 00892 $this->query( $query, $fname ); 00893 } 00894 00902 function listTables( $prefix = null, $fname = 'DatabaseMysql::listTables' ) { 00903 $result = $this->query( "SHOW TABLES", $fname); 00904 00905 $endArray = array(); 00906 00907 foreach( $result as $table ) { 00908 $vars = get_object_vars( $table ); 00909 $table = array_pop( $vars ); 00910 00911 if( !$prefix || strpos( $table, $prefix ) === 0 ) { 00912 $endArray[] = $table; 00913 } 00914 } 00915 00916 return $endArray; 00917 } 00918 00924 public function dropTable( $tableName, $fName = 'DatabaseMysql::dropTable' ) { 00925 if( !$this->tableExists( $tableName, $fName ) ) { 00926 return false; 00927 } 00928 return $this->query( "DROP TABLE IF EXISTS " . $this->tableName( $tableName ), $fName ); 00929 } 00930 00934 protected function getDefaultSchemaVars() { 00935 $vars = parent::getDefaultSchemaVars(); 00936 $vars['wgDBTableOptions'] = str_replace( 'TYPE', 'ENGINE', $GLOBALS['wgDBTableOptions'] ); 00937 $vars['wgDBTableOptions'] = str_replace( 'CHARSET=mysql4', 'CHARSET=binary', $vars['wgDBTableOptions'] ); 00938 return $vars; 00939 } 00940 00947 function getMysqlStatus( $which = "%" ) { 00948 $res = $this->query( "SHOW STATUS LIKE '{$which}'" ); 00949 $status = array(); 00950 00951 foreach ( $res as $row ) { 00952 $status[$row->Variable_name] = $row->Value; 00953 } 00954 00955 return $status; 00956 } 00957 00958 } 00959 00964 class MySQLField implements Field { 00965 private $name, $tablename, $default, $max_length, $nullable, 00966 $is_pk, $is_unique, $is_multiple, $is_key, $type; 00967 00968 function __construct ( $info ) { 00969 $this->name = $info->name; 00970 $this->tablename = $info->table; 00971 $this->default = $info->def; 00972 $this->max_length = $info->max_length; 00973 $this->nullable = !$info->not_null; 00974 $this->is_pk = $info->primary_key; 00975 $this->is_unique = $info->unique_key; 00976 $this->is_multiple = $info->multiple_key; 00977 $this->is_key = ( $this->is_pk || $this->is_unique || $this->is_multiple ); 00978 $this->type = $info->type; 00979 } 00980 00984 function name() { 00985 return $this->name; 00986 } 00987 00991 function tableName() { 00992 return $this->tableName; 00993 } 00994 00998 function type() { 00999 return $this->type; 01000 } 01001 01005 function isNullable() { 01006 return $this->nullable; 01007 } 01008 01009 function defaultValue() { 01010 return $this->default; 01011 } 01012 01016 function isKey() { 01017 return $this->is_key; 01018 } 01019 01023 function isMultipleKey() { 01024 return $this->is_multiple; 01025 } 01026 } 01027 01028 class MySQLMasterPos implements DBMasterPos { 01029 var $file, $pos; 01030 01031 function __construct( $file, $pos ) { 01032 $this->file = $file; 01033 $this->pos = $pos; 01034 } 01035 01036 function __toString() { 01037 return "{$this->file}/{$this->pos}"; 01038 } 01039 }