|
eZ Publish
[trunk]
|
00001 <?php 00002 /** 00003 * File containing the eZMySQLDB class. 00004 * 00005 * @copyright Copyright (C) 1999-2012 eZ Systems AS. All rights reserved. 00006 * @license http://www.gnu.org/licenses/gpl-2.0.txt GNU General Public License v2 00007 * @version //autogentag// 00008 * @package lib 00009 */ 00010 00011 /** 00012 * The eZMySQLDB class provides MySQL implementation of the database interface. 00013 * 00014 * eZMySQLDB is the MySQL implementation of eZDB. 00015 * @see eZDB 00016 * @deprecated Since 4.5 in favour of {@link eZMySQLiDB} 00017 */ 00018 class eZMySQLDB extends eZDBInterface 00019 { 00020 const RELATION_FOREIGN_KEY = 5; 00021 const RELATION_FOREIGN_KEY_BIT = 32; 00022 00023 /*! 00024 Create a new eZMySQLDB object and connects to the database backend. 00025 */ 00026 function eZMySQLDB( $parameters ) 00027 { 00028 $this->eZDBInterface( $parameters ); 00029 00030 if ( !extension_loaded( 'mysql' ) ) 00031 { 00032 if ( function_exists( 'eZAppendWarningItem' ) ) 00033 { 00034 eZAppendWarningItem( array( 'error' => array( 'type' => 'ezdb', 00035 'number' => eZDBInterface::ERROR_MISSING_EXTENSION ), 00036 'text' => 'MySQL extension was not found, the DB handler will not be initialized.' ) ); 00037 $this->IsConnected = false; 00038 } 00039 eZDebug::writeWarning( 'MySQL extension was not found, the DB handler will not be initialized.', 'eZMySQLDB' ); 00040 return; 00041 } 00042 00043 eZDebug::createAccumulatorGroup( 'mysql_total', 'Mysql Total' ); 00044 00045 /// Connect to master server 00046 if ( !$this->DBWriteConnection ) 00047 { 00048 $connection = $this->connect( $this->Server, $this->DB, $this->User, $this->Password, $this->SocketPath, $this->Charset, $this->Port ); 00049 if ( $this->IsConnected ) 00050 { 00051 $this->DBWriteConnection = $connection; 00052 } 00053 } 00054 00055 // Connect to slave 00056 if ( !$this->DBConnection ) 00057 { 00058 if ( $this->UseSlaveServer === true ) 00059 { 00060 $connection = $this->connect( $this->SlaveServer, $this->SlaveDB, $this->SlaveUser, $this->SlavePassword, $this->SocketPath, $this->Charset, $this->SlavePort ); 00061 } 00062 else 00063 { 00064 $connection = $this->DBWriteConnection; 00065 } 00066 00067 if ( $connection and $this->DBWriteConnection ) 00068 { 00069 $this->DBConnection = $connection; 00070 $this->IsConnected = true; 00071 } 00072 } 00073 00074 // Initialize TempTableList 00075 $this->TempTableList = array(); 00076 } 00077 00078 /*! 00079 \private 00080 Opens a new connection to a MySQL database and returns the connection 00081 */ 00082 function connect( $server, $db, $user, $password, $socketPath, $charset = null, $port = false ) 00083 { 00084 // if a port is specified, we add it to $server, this is how mysql_(p)connect accepts a port number 00085 if ( $port ) 00086 { 00087 $server .= ':' . $port; 00088 } 00089 00090 $connection = false; 00091 00092 if ( $socketPath !== false ) 00093 { 00094 ini_set( "mysql.default_socket", $socketPath ); 00095 } 00096 00097 $oldHandling = eZDebug::setHandleType( eZDebug::HANDLE_EXCEPTION ); 00098 try { 00099 if ( $this->UsePersistentConnection == true ) 00100 { 00101 $connection = mysql_pconnect( $server, $user, $password ); 00102 } 00103 else 00104 { 00105 $connection = mysql_connect( $server, $user, $password, true ); 00106 } 00107 } catch( ErrorException $e ) {} 00108 eZDebug::setHandleType( $oldHandling ); 00109 00110 $this->setError(); 00111 $maxAttempts = $this->connectRetryCount(); 00112 $waitTime = $this->connectRetryWaitTime(); 00113 $numAttempts = 1; 00114 while ( !$connection && $numAttempts <= $maxAttempts ) 00115 { 00116 sleep( $waitTime ); 00117 $oldHandling = eZDebug::setHandleType( eZDebug::HANDLE_EXCEPTION ); 00118 eZDebug::accumulatorStart( 'mysql_connection', 'mysql_total', 'Database connection' ); 00119 try { 00120 if ( $this->UsePersistentConnection == true ) 00121 { 00122 $connection = mysql_pconnect( $this->Server, $this->User, $this->Password ); 00123 } 00124 else 00125 { 00126 $connection = mysql_connect( $this->Server, $this->User, $this->Password ); 00127 } 00128 } catch( ErrorException $e ) {} 00129 eZDebug::accumulatorStop( 'mysql_connection' ); 00130 eZDebug::setHandleType( $oldHandling ); 00131 $numAttempts++; 00132 } 00133 $this->setError(); 00134 00135 $this->IsConnected = true; 00136 00137 if ( !$connection ) 00138 { 00139 eZDebug::writeError( "Connection error: Couldn't connect to database server. Please try again later or inform the system administrator.\n{$this->ErrorMessage}", __CLASS__ ); 00140 $this->IsConnected = false; 00141 throw new eZDBNoConnectionException( $server, $this->ErrorMessage, $this->ErrorNumber ); 00142 } 00143 00144 if ( $this->IsConnected && $db != null ) 00145 { 00146 $ret = mysql_select_db( $db, $connection ); 00147 if ( !$ret ) 00148 { 00149 $this->setError( $connection ); 00150 eZDebug::writeError( "Connection error: Couldn't select the database. Please try again later or inform the system administrator.\n{$this->ErrorMessage}", __CLASS__ ); 00151 $this->IsConnected = false; 00152 } 00153 } 00154 00155 if ( $charset !== null ) 00156 { 00157 $charset = eZCharsetInfo::realCharsetCode( $charset ); 00158 } 00159 00160 if ( $this->IsConnected and $charset !== null and $this->isCharsetSupported( $charset ) ) 00161 { 00162 $query = "SET NAMES '" . eZMySQLCharset::mapTo( $charset ) . "'"; 00163 $status = mysql_query( $query, $connection ); 00164 $this->reportQuery( 'eZMySQLDB', $query, false, false, true ); 00165 if ( !$status ) 00166 { 00167 $this->setError(); 00168 eZDebug::writeWarning( "Connection warning: " . mysql_errno( $connection ) . ": " . mysql_error( $connection ), "eZMySQLDB" ); 00169 } 00170 } 00171 00172 return $connection; 00173 } 00174 00175 function databaseName() 00176 { 00177 return 'mysql'; 00178 } 00179 00180 function bindingType( ) 00181 { 00182 return eZDBInterface::BINDING_NO; 00183 } 00184 00185 function bindVariable( $value, $fieldDef = false ) 00186 { 00187 return $value; 00188 } 00189 00190 /*! 00191 Checks if the requested character set matches the one used in the database. 00192 00193 \return \c true if it matches or \c false if it differs. 00194 \param[out] $currentCharset The charset that the database uses. 00195 will only be set if the match fails. 00196 Note: This will be specific to the database. 00197 00198 \note There will be no check for databases using MySQL 4.1.0 or lower since 00199 they do not have proper character set handling. 00200 */ 00201 function checkCharset( $charset, &$currentCharset ) 00202 { 00203 // If we don't have a database yet we shouldn't check it 00204 if ( !$this->DB ) 00205 return true; 00206 00207 if ( is_array( $charset ) ) 00208 { 00209 $realCharset = array(); 00210 foreach ( $charset as $charsetItem ) 00211 $realCharset[] = eZCharsetInfo::realCharsetCode( $charsetItem ); 00212 } 00213 else 00214 $realCharset = eZCharsetInfo::realCharsetCode( $charset ); 00215 00216 return $this->checkCharsetPriv( $realCharset, $currentCharset ); 00217 } 00218 00219 /*! 00220 \private 00221 */ 00222 function checkCharsetPriv( $charset, &$currentCharset ) 00223 { 00224 $query = "SHOW CREATE DATABASE `{$this->DB}`"; 00225 $status = mysql_query( $query, $this->DBConnection ); 00226 $this->reportQuery( __CLASS__, $query, false, false ); 00227 if ( !$status ) 00228 { 00229 $this->setError(); 00230 eZDebug::writeWarning( "Connection warning: " . mysql_errno( $this->DBConnection ) . ": " . mysql_error( $this->DBConnection ), "eZMySQLDB" ); 00231 return false; 00232 } 00233 00234 $numRows = mysql_num_rows( $status ); 00235 if ( $numRows == 0 ) 00236 return false; 00237 00238 for ( $i = 0; $i < $numRows; ++$i ) 00239 { 00240 $tmpRow = mysql_fetch_array( $status, MYSQL_ASSOC ); 00241 if ( $tmpRow['Database'] == $this->DB ) 00242 { 00243 $createText = $tmpRow['Create Database']; 00244 if ( preg_match( '#DEFAULT CHARACTER SET ([a-zA-Z0-9_-]+)#', $createText, $matches ) ) 00245 { 00246 $currentCharset = $matches[1]; 00247 $currentCharset = eZCharsetInfo::realCharsetCode( $currentCharset ); 00248 // Convert charset names into something MySQL will understand 00249 $unmappedCurrentCharset = eZMySQLCharset::mapFrom( $currentCharset ); 00250 00251 if ( is_array( $charset ) ) 00252 { 00253 if ( in_array( $unmappedCurrentCharset, $charset ) ) 00254 { 00255 return $unmappedCurrentCharset; 00256 } 00257 } 00258 else if ( $unmappedCurrentCharset == $charset ) 00259 { 00260 return true; 00261 } 00262 return false; 00263 } 00264 break; 00265 } 00266 } 00267 return true; 00268 } 00269 00270 function query( $sql, $server = false ) 00271 { 00272 if ( $this->IsConnected ) 00273 { 00274 eZDebug::accumulatorStart( 'mysql_query', 'mysql_total', 'Mysql_queries' ); 00275 // The converted sql should not be output 00276 if ( $this->InputTextCodec ) 00277 { 00278 eZDebug::accumulatorStart( 'mysql_conversion', 'mysql_total', 'String conversion in mysql' ); 00279 $sql = $this->InputTextCodec->convertString( $sql ); 00280 eZDebug::accumulatorStop( 'mysql_conversion' ); 00281 } 00282 00283 if ( $this->OutputSQL ) 00284 { 00285 $this->startTimer(); 00286 } 00287 00288 $sql = trim( $sql ); 00289 00290 // Check if we need to use the master or slave server by default 00291 if ( $server === false ) 00292 { 00293 $server = strncasecmp( $sql, 'select', 6 ) === 0 && $this->TransactionCounter == 0 ? 00294 eZDBInterface::SERVER_SLAVE : eZDBInterface::SERVER_MASTER; 00295 } 00296 00297 $connection = ( $server == eZDBInterface::SERVER_SLAVE ) ? $this->DBConnection : $this->DBWriteConnection; 00298 00299 $analysisText = false; 00300 // If query analysis is enable we need to run the query 00301 // with an EXPLAIN in front of it 00302 // Then we build a human-readable table out of the result 00303 if ( $this->QueryAnalysisOutput ) 00304 { 00305 $analysisResult = mysql_query( 'EXPLAIN ' . $sql, $connection ); 00306 if ( $analysisResult ) 00307 { 00308 $numRows = mysql_num_rows( $analysisResult ); 00309 $rows = array(); 00310 if ( $numRows > 0 ) 00311 { 00312 for ( $i = 0; $i < $numRows; ++$i ) 00313 { 00314 if ( $this->InputTextCodec ) 00315 { 00316 $tmpRow = mysql_fetch_array( $analysisResult, MYSQL_ASSOC ); 00317 $convRow = array(); 00318 foreach( $tmpRow as $key => $row ) 00319 { 00320 $convRow[$key] = $this->OutputTextCodec->convertString( $row ); 00321 } 00322 $rows[$i] = $convRow; 00323 } 00324 else 00325 $rows[$i] = mysql_fetch_array( $analysisResult, MYSQL_ASSOC ); 00326 } 00327 } 00328 00329 // Figure out all columns and their maximum display size 00330 $columns = array(); 00331 foreach ( $rows as $row ) 00332 { 00333 foreach ( $row as $col => $data ) 00334 { 00335 if ( !isset( $columns[$col] ) ) 00336 $columns[$col] = array( 'name' => $col, 00337 'size' => strlen( $col ) ); 00338 $columns[$col]['size'] = max( $columns[$col]['size'], strlen( $data ) ); 00339 } 00340 } 00341 00342 $delimiterLine = array(); 00343 $colLine = array(); 00344 // Generate the column line and the vertical delimiter 00345 // The look of the table is taken from the MySQL CLI client 00346 // It looks like this: 00347 // +-------+-------+ 00348 // | col_a | col_b | 00349 // +-------+-------+ 00350 // | txt | 42 | 00351 // +-------+-------+ 00352 foreach ( $columns as $col ) 00353 { 00354 $delimiterLine[] = str_repeat( '-', $col['size'] + 2 ); 00355 $colLine[] = ' ' . str_pad( $col['name'], $col['size'], ' ', STR_PAD_RIGHT ) . ' '; 00356 } 00357 $delimiterLine = '+' . join( '+', $delimiterLine ) . "+\n"; 00358 $analysisText = $delimiterLine; 00359 $analysisText .= '|' . join( '|', $colLine ) . "|\n"; 00360 $analysisText .= $delimiterLine; 00361 00362 // Go trough all data and pad them to create the table correctly 00363 foreach ( $rows as $row ) 00364 { 00365 $rowLine = array(); 00366 foreach ( $columns as $col ) 00367 { 00368 $name = $col['name']; 00369 $size = $col['size']; 00370 $data = isset( $row[$name] ) ? $row[$name] : ''; 00371 // Align numerical values to the right (ie. pad left) 00372 $rowLine[] = ' ' . str_pad( $data, $size, ' ', 00373 is_numeric( $data ) ? STR_PAD_LEFT : STR_PAD_RIGHT ) . ' '; 00374 } 00375 $analysisText .= '|' . join( '|', $rowLine ) . "|\n"; 00376 $analysisText .= $delimiterLine; 00377 } 00378 00379 // Reduce memory usage 00380 unset( $rows, $delimiterLine, $colLine, $columns ); 00381 } 00382 } 00383 00384 $result = mysql_query( $sql, $connection ); 00385 00386 if ( $this->RecordError and !$result ) 00387 $this->setError(); 00388 00389 if ( $this->OutputSQL ) 00390 { 00391 $this->endTimer(); 00392 00393 if ($this->timeTaken() > $this->SlowSQLTimeout) 00394 { 00395 $num_rows = mysql_affected_rows( $connection ); 00396 $text = $sql; 00397 00398 // If we have some analysis text we append this to the SQL output 00399 if ( $analysisText !== false ) 00400 $text = "EXPLAIN\n" . $text . "\n\nANALYSIS:\n" . $analysisText; 00401 00402 $this->reportQuery( __CLASS__ . ( $server == eZDBInterface::SERVER_MASTER ? '[on master]' : '' ), $text, $num_rows, $this->timeTaken() ); 00403 } 00404 } 00405 eZDebug::accumulatorStop( 'mysql_query' ); 00406 if ( $result ) 00407 { 00408 return $result; 00409 } 00410 else 00411 { 00412 $errorMessage = "Query error: " . mysql_error( $connection ) . ". Query: ". $sql; 00413 eZDebug::writeError( $errorMessage, __CLASS__ ); 00414 $oldRecordError = $this->RecordError; 00415 // Turn off error handling while we unlock 00416 $this->RecordError = false; 00417 mysql_query( 'UNLOCK TABLES', $connection ); 00418 $this->RecordError = $oldRecordError; 00419 00420 $this->reportError(); 00421 00422 // This is to behave the same way as other RDBMS PHP API as PostgreSQL 00423 // functions which throws an error with a failing request. 00424 if ( $this->errorHandling == eZDB::ERROR_HANDLING_STANDARD ) 00425 { 00426 trigger_error( "mysql_query(): $errorMessage", E_USER_ERROR ); 00427 } 00428 else 00429 { 00430 throw new eZDBException( $this->ErrorMessage, $this->ErrorNumber ); 00431 } 00432 00433 return false; 00434 } 00435 } 00436 else 00437 { 00438 eZDebug::writeError( "Trying to do a query without being connected to a database!", __CLASS__ ); 00439 } 00440 00441 00442 } 00443 00444 function arrayQuery( $sql, $params = array(), $server = false ) 00445 { 00446 $retArray = array(); 00447 if ( $this->IsConnected ) 00448 { 00449 $limit = false; 00450 $offset = 0; 00451 $column = false; 00452 // check for array parameters 00453 if ( is_array( $params ) ) 00454 { 00455 if ( isset( $params["limit"] ) and is_numeric( $params["limit"] ) ) 00456 $limit = $params["limit"]; 00457 00458 if ( isset( $params["offset"] ) and is_numeric( $params["offset"] ) ) 00459 $offset = $params["offset"]; 00460 00461 if ( isset( $params["column"] ) and ( is_numeric( $params["column"] ) or is_string( $params["column"] ) ) ) 00462 $column = $params["column"]; 00463 } 00464 00465 if ( $limit !== false and is_numeric( $limit ) ) 00466 { 00467 $sql .= "\nLIMIT $offset, $limit "; 00468 } 00469 else if ( $offset !== false and is_numeric( $offset ) and $offset > 0 ) 00470 { 00471 $sql .= "\nLIMIT $offset, 18446744073709551615"; // 2^64-1 00472 } 00473 $result = $this->query( $sql, $server ); 00474 00475 if ( $result == false ) 00476 { 00477 $this->reportQuery( __CLASS__, $sql, false, false ); 00478 return false; 00479 } 00480 00481 $numRows = mysql_num_rows( $result ); 00482 if ( $numRows > 0 ) 00483 { 00484 if ( !is_string( $column ) ) 00485 { 00486 eZDebug::accumulatorStart( 'mysql_loop', 'mysql_total', 'Looping result' ); 00487 for ( $i=0; $i < $numRows; $i++ ) 00488 { 00489 if ( $this->InputTextCodec ) 00490 { 00491 $tmpRow = mysql_fetch_array( $result, MYSQL_ASSOC ); 00492 $convRow = array(); 00493 foreach( $tmpRow as $key => $row ) 00494 { 00495 eZDebug::accumulatorStart( 'mysql_conversion', 'mysql_total', 'String conversion in mysql' ); 00496 $convRow[$key] = $this->OutputTextCodec->convertString( $row ); 00497 eZDebug::accumulatorStop( 'mysql_conversion' ); 00498 } 00499 $retArray[$i + $offset] = $convRow; 00500 } 00501 else 00502 $retArray[$i + $offset] = mysql_fetch_array( $result, MYSQL_ASSOC ); 00503 } 00504 eZDebug::accumulatorStop( 'mysql_loop' ); 00505 00506 } 00507 else 00508 { 00509 eZDebug::accumulatorStart( 'mysql_loop', 'mysql_total', 'Looping result' ); 00510 for ( $i=0; $i < $numRows; $i++ ) 00511 { 00512 $tmp_row = mysql_fetch_array( $result, MYSQL_ASSOC ); 00513 if ( $this->InputTextCodec ) 00514 { 00515 eZDebug::accumulatorStart( 'mysql_conversion', 'mysql_total', 'String conversion in mysql' ); 00516 $retArray[$i + $offset] = $this->OutputTextCodec->convertString( $tmp_row[$column] ); 00517 eZDebug::accumulatorStop( 'mysql_conversion' ); 00518 } 00519 else 00520 $retArray[$i + $offset] =& $tmp_row[$column]; 00521 } 00522 eZDebug::accumulatorStop( 'mysql_loop' ); 00523 } 00524 } 00525 } 00526 return $retArray; 00527 } 00528 00529 function subString( $string, $from, $len = null ) 00530 { 00531 if ( $len == null ) 00532 { 00533 return " substring( $string from $from ) "; 00534 }else 00535 { 00536 return " substring( $string from $from for $len ) "; 00537 } 00538 } 00539 00540 function concatString( $strings = array() ) 00541 { 00542 $str = implode( "," , $strings ); 00543 return " concat( $str ) "; 00544 } 00545 00546 function md5( $str ) 00547 { 00548 return " MD5( $str ) "; 00549 } 00550 00551 function bitAnd( $arg1, $arg2 ) 00552 { 00553 return 'cast(' . $arg1 . ' & ' . $arg2 . ' AS SIGNED ) '; 00554 } 00555 00556 function bitOr( $arg1, $arg2 ) 00557 { 00558 return 'cast( ' . $arg1 . ' | ' . $arg2 . ' AS SIGNED ) '; 00559 } 00560 00561 function supportedRelationTypeMask() 00562 { 00563 return eZDBInterface::RELATION_TABLE_BIT | self::RELATION_FOREIGN_KEY_BIT; 00564 } 00565 00566 function supportedRelationTypes() 00567 { 00568 return array( self::RELATION_FOREIGN_KEY, eZDBInterface::RELATION_TABLE ); 00569 } 00570 00571 function relationCounts( $relationMask ) 00572 { 00573 if ( $relationMask & eZDBInterface::RELATION_TABLE_BIT ) 00574 return $this->relationCount(); 00575 else 00576 return 0; 00577 } 00578 00579 function relationCount( $relationType = eZDBInterface::RELATION_TABLE ) 00580 { 00581 if ( !in_array( $relationType, $this->supportedRelationTypes() ) ) 00582 { 00583 eZDebug::writeError( "Unsupported relation type '$relationType'", __METHOD__ ); 00584 return false; 00585 } 00586 $count = false; 00587 if ( $this->IsConnected ) 00588 { 00589 switch ( $relationType ) 00590 { 00591 case eZDBInterface::RELATION_TABLE: 00592 { 00593 $query = "SHOW TABLES FROM `" . $this->DB . "`"; 00594 $result = @mysql_query( $query, $this->DBConnection ); 00595 $this->reportQuery( __CLASS__, $query, false, false ); 00596 $count = mysql_num_rows( $result ); 00597 mysql_free_result( $result ); 00598 } break; 00599 00600 case self::RELATION_FOREIGN_KEY: 00601 { 00602 $count = count( $this->relationList( self::RELATION_FOREIGN_KEY ) ); 00603 } break; 00604 } 00605 } 00606 return $count; 00607 } 00608 00609 function relationList( $relationType = eZDBInterface::RELATION_TABLE ) 00610 { 00611 if ( !in_array( $relationType, $this->supportedRelationTypes() ) ) 00612 { 00613 eZDebug::writeError( "Unsupported relation type '$relationType'", __METHOD__ ); 00614 return false; 00615 } 00616 $tables = array(); 00617 if ( $this->IsConnected ) 00618 { 00619 switch ( $relationType ) 00620 { 00621 case eZDBInterface::RELATION_TABLE: 00622 { 00623 $query = "SHOW TABLES FROM `" . $this->DB . "`"; 00624 $result = @mysql_query( $query, $this->DBConnection ); 00625 $this->reportQuery( __CLASS__, $query, false, false ); 00626 $count = mysql_num_rows( $result ); 00627 for ( $i = 0; $i < $count; ++ $i ) 00628 { 00629 $table = mysql_fetch_array( $result ); 00630 $tables[] = $table[0]; 00631 } 00632 mysql_free_result( $result ); 00633 return $tables; 00634 } break; 00635 00636 case self::RELATION_FOREIGN_KEY: 00637 { 00638 /** 00639 * Ideally, we would have queried information_schema.KEY_COLUMN_USAGE 00640 * However, a known bug causes queries on this table to potentially be VERY slow (http://bugs.mysql.com/bug.php?id=19588) 00641 * 00642 * The query would look like this: 00643 * SELECT table_name AS from_table, column_name AS from_column, referenced_table_name AS to_table, 00644 * referenced_column_name AS to_column 00645 * FROM information_schema.KEY_COLUMN_USAGE 00646 * WHERE REFERENCED_TABLE_SCHEMA = '{$this->DB}' 00647 * AND REFERENCED_TABLE_NAME is not null; 00648 * 00649 * Result as of MySQL 5.1.48 / August 2010: 00650 * 00651 * +---------------+-------------+----------+-----------+ 00652 * | from_table | from_column | to_table | to_column | 00653 * +---------------+-------------+----------+-----------+ 00654 * | ezdbfile_data | name_hash | ezdbfile | name_hash | 00655 * +---------------+-------------+----------+-----------+ 00656 * 1 row in set (12.56 sec) 00657 * 00658 * The only way out right now is to parse SHOW CREATE TABLE for each table and extract CONSTRAINT lines 00659 */ 00660 00661 $foreignKeys = array(); 00662 foreach( $this->relationList( eZDBInterface::RELATION_TABLE ) as $table ) 00663 { 00664 $query = "SHOW CREATE TABLE $table"; 00665 $result = mysql_query( $query, $this->DBConnection ); 00666 $this->reportQuery( __CLASS__, $query, false, false ); 00667 if ( mysql_num_rows( $result ) === 1 ) 00668 { 00669 $row = mysql_fetch_row( $result ); 00670 if ( strpos( $row[1], "CONSTRAINT" ) !== false ) 00671 { 00672 if ( preg_match_all( '#CONSTRAINT [`"]([^`"]+)[`"] FOREIGN KEY \([`"].*[`"]\) REFERENCES [`"]([^`"]+)[`"] \([`"].*[`"]\)#', 00673 $row[1], $matches, PREG_PATTERN_ORDER ) ) 00674 { 00675 // $foreignKeys[] = array( 'table' => $table, 'keys' => $matches[1] ); 00676 foreach( $matches[1] as $fkMatch ) 00677 { 00678 $foreignKeys[] = array( 'table' => $table, 'fk' => $fkMatch ); 00679 } 00680 } 00681 } 00682 } 00683 } 00684 return $foreignKeys; 00685 } 00686 } 00687 } 00688 } 00689 00690 function eZTableList( $server = eZDBInterface::SERVER_MASTER ) 00691 { 00692 $tables = array(); 00693 if ( $this->IsConnected ) 00694 { 00695 if ( $this->UseSlaveServer && $server == eZDBInterface::SERVER_SLAVE ) 00696 { 00697 $connection = $this->DBConnection; 00698 $db = $this->SlaveDB; 00699 } 00700 else 00701 { 00702 $connection = $this->DBWriteConnection; 00703 $db = $this->DB; 00704 } 00705 00706 $query = "SHOW TABLES FROM `" . $db . "`"; 00707 $result = @mysql_query( $query, $connection ); 00708 $this->reportQuery( __CLASS__, $query, false, false ); 00709 $count = mysql_num_rows( $result ); 00710 for ( $i = 0; $i < $count; ++ $i ) 00711 { 00712 $table = mysql_fetch_array( $result ); 00713 $tableName = $table[0]; 00714 if ( substr( $tableName, 0, 2 ) == 'ez' ) 00715 { 00716 $tables[$tableName] = eZDBInterface::RELATION_TABLE; 00717 } 00718 } 00719 mysql_free_result( $result ); 00720 } 00721 return $tables; 00722 } 00723 00724 function relationMatchRegexp( $relationType ) 00725 { 00726 return "#^ez#"; 00727 } 00728 00729 function removeRelation( $relationName, $relationType ) 00730 { 00731 $relationTypeName = $this->relationName( $relationType ); 00732 if ( !$relationTypeName ) 00733 { 00734 eZDebug::writeError( "Unknown relation type '$relationType'", __METHOD__ ); 00735 return false; 00736 } 00737 00738 if ( $this->IsConnected ) 00739 { 00740 switch ( $relationType ) 00741 { 00742 case self::RELATION_FOREIGN_KEY: 00743 { 00744 $sql = "ALTER TABLE {$relationName['table']} DROP FOREIGN KEY {$relationName['fk']}"; 00745 $this->query( $sql ); 00746 return true; 00747 } break; 00748 00749 default: 00750 { 00751 $sql = "DROP $relationTypeName $relationName"; 00752 return $this->query( $sql ); 00753 } 00754 } 00755 } 00756 return false; 00757 } 00758 00759 /** 00760 * Local eZDBInterface::relationName() override to support the foreign keys type relation 00761 * @param $relationType 00762 * @return string|false 00763 */ 00764 public function relationName( $relationType ) 00765 { 00766 if ( $relationType == self::RELATION_FOREIGN_KEY ) 00767 return 'FOREIGN_KEY'; 00768 else 00769 return parent::relationName( $relationType ); 00770 } 00771 00772 00773 function lock( $table ) 00774 { 00775 if ( $this->IsConnected ) 00776 { 00777 if ( is_array( $table ) ) 00778 { 00779 $lockQuery = "LOCK TABLES"; 00780 $first = true; 00781 foreach( array_keys( $table ) as $tableKey ) 00782 { 00783 if ( $first == true ) 00784 $first = false; 00785 else 00786 $lockQuery .= ","; 00787 $lockQuery .= " " . $table[$tableKey]['table'] . " WRITE"; 00788 } 00789 $this->query( $lockQuery ); 00790 } 00791 else 00792 { 00793 $this->query( "LOCK TABLES $table WRITE" ); 00794 } 00795 } 00796 } 00797 00798 function unlock() 00799 { 00800 if ( $this->IsConnected ) 00801 { 00802 $this->query( "UNLOCK TABLES" ); 00803 } 00804 } 00805 00806 /*! 00807 The query to start the transaction. 00808 */ 00809 function beginQuery() 00810 { 00811 return $this->query("BEGIN WORK"); 00812 } 00813 00814 /*! 00815 The query to commit the transaction. 00816 */ 00817 function commitQuery() 00818 { 00819 return $this->query( "COMMIT" ); 00820 } 00821 00822 /*! 00823 The query to cancel the transaction. 00824 */ 00825 function rollbackQuery() 00826 { 00827 return mysql_query( "ROLLBACK", $this->DBWriteConnection ); 00828 } 00829 00830 function lastSerialID( $table = false, $column = false ) 00831 { 00832 if ( $this->IsConnected ) 00833 { 00834 $id = mysql_insert_id( $this->DBWriteConnection ); 00835 return $id; 00836 } 00837 else 00838 return false; 00839 } 00840 00841 function escapeString( $str ) 00842 { 00843 if ( $this->IsConnected ) 00844 { 00845 return mysql_real_escape_string( $str, $this->DBConnection ); 00846 } 00847 else 00848 { 00849 return mysql_escape_string( $str ); 00850 } 00851 } 00852 00853 function close() 00854 { 00855 if ( $this->IsConnected ) 00856 { 00857 if ( $this->UseSlaveServer === true ) 00858 mysql_close( $this->DBConnection ); 00859 mysql_close( $this->DBWriteConnection ); 00860 } 00861 } 00862 00863 function createDatabase( $dbName ) 00864 { 00865 if ( $this->IsConnected ) 00866 { 00867 $this->query( "CREATE DATABASE $dbName" ); 00868 $this->setError(); 00869 } 00870 } 00871 00872 function removeDatabase( $dbName ) 00873 { 00874 if ( $this->IsConnected ) 00875 { 00876 $this->query( "DROP DATABASE $dbName" ); 00877 $this->setError(); 00878 } 00879 } 00880 00881 /** 00882 * Sets the internal error messages & number 00883 * @param int $connection database connection handle, overrides the current one if given 00884 */ 00885 function setError( $connection = false) 00886 { 00887 if ( $this->IsConnected ) 00888 { 00889 if ( $connection === false ) 00890 $connection = $this->DBConnection; 00891 00892 if ( is_resource( $connection ) ) 00893 { 00894 $this->ErrorMessage = mysql_error( $connection ); 00895 $this->ErrorNumber = mysql_errno( $connection ); 00896 } 00897 } 00898 else 00899 { 00900 $this->ErrorMessage = mysql_error(); 00901 $this->ErrorNumber = mysql_errno(); 00902 } 00903 } 00904 00905 function availableDatabases() 00906 { 00907 $databaseArray = mysql_list_dbs( $this->DBConnection ); 00908 00909 if ( $this->errorNumber() != 0 ) 00910 { 00911 return null; 00912 } 00913 00914 $databases = array(); 00915 $i = 0; 00916 $numRows = mysql_num_rows( $databaseArray ); 00917 if ( count( $numRows ) == 0 ) 00918 { 00919 return false; 00920 } 00921 00922 while ( $i < $numRows ) 00923 { 00924 // we don't allow "mysql" or "information_schema" database to be shown anywhere 00925 $curDB = mysql_db_name( $databaseArray, $i ); 00926 if ( strcasecmp( $curDB, 'mysql' ) != 0 && strcasecmp( $curDB, 'information_schema' ) != 0 ) 00927 { 00928 $databases[] = $curDB; 00929 } 00930 ++$i; 00931 } 00932 return $databases; 00933 } 00934 00935 function databaseServerVersion() 00936 { 00937 if ( $this->IsConnected ) 00938 { 00939 $versionInfo = mysql_get_server_info(); 00940 00941 $versionArray = explode( '.', $versionInfo ); 00942 00943 return array( 'string' => $versionInfo, 00944 'values' => $versionArray ); 00945 } 00946 return false; 00947 } 00948 00949 function databaseClientVersion() 00950 { 00951 $versionInfo = mysql_get_client_info(); 00952 00953 $versionArray = explode( '.', $versionInfo ); 00954 00955 return array( 'string' => $versionInfo, 00956 'values' => $versionArray ); 00957 } 00958 00959 function isCharsetSupported( $charset ) 00960 { 00961 return true; 00962 } 00963 00964 function supportsDefaultValuesInsertion() 00965 { 00966 return false; 00967 } 00968 00969 function dropTempTable( $dropTableQuery = '', $server = self::SERVER_SLAVE ) 00970 { 00971 $dropTableQuery = str_ireplace( 'DROP TABLE', 'DROP TEMPORARY TABLE', $dropTableQuery ); 00972 parent::dropTempTable( $dropTableQuery, $server ); 00973 } 00974 00975 public $TempTableList; 00976 00977 /// \privatesection 00978 } 00979 00980 ?>