Permalink
Browse files

Switches MySQLDatabase to use the MySQLi class rather than the mysql_…

…* functions.
  • Loading branch information...
1 parent 0cdf52c commit 6bf3f7ded400c925dd66df2c2612c095d447c7b0 @simonwelsh simonwelsh committed Oct 29, 2011
Showing with 82 additions and 55 deletions.
  1. +82 −55 model/MySQLDatabase.php
View
@@ -28,7 +28,7 @@ class MySQLDatabase extends SS_Database {
private static $connection_charset = null;
- private $supportsTransactions=false;
+ private $supportsTransactions = true;
/**
* Sets the character set for the MySQL database connection.
@@ -54,22 +54,22 @@ public static function set_connection_charset($charset = 'utf8') {
* - timezone: (optional) The timezone offset. For example: +12:00, "Pacific/Auckland", or "SYSTEM"
*/
public function __construct($parameters) {
- $this->dbConn = mysql_connect($parameters['server'], $parameters['username'], $parameters['password'], true);
+ $this->dbConn = new MySQLi($parameters['server'], $parameters['username'], $parameters['password']);
+
+ if($this->dbConn->connect_error) {
+ $this->databaseError("Couldn't connect to MySQL database | " . $this->dbConn->connect_error);
+ }
+
+ $this->query("SET sql_mode = 'ANSI'");
if(self::$connection_charset) {
- $this->query("SET CHARACTER SET '" . self::$connection_charset . "'");
- $this->query("SET NAMES '" . self::$connection_charset . "'");
+ $this->dbConn->set_charset(self::$connection_charset);
}
- $this->active = mysql_select_db($parameters['database'], $this->dbConn);
+ $this->active = $this->dbConn->select_db($parameters['database']);
$this->database = $parameters['database'];
- if(!$this->dbConn) {
- $this->databaseError("Couldn't connect to MySQL database");
- }
-
if(isset($parameters['timezone'])) $this->query(sprintf("SET SESSION time_zone = '%s'", $parameters['timezone']));
- $this->query("SET sql_mode = 'ANSI'");
}
/**
@@ -84,15 +84,15 @@ public function getConnect($parameters) {
* @return boolean
*/
public function supportsCollations() {
- return $this->getVersion() >= 4.1;
+ return true;
}
/**
* Get the version of MySQL.
* @return string
*/
public function getVersion() {
- return mysql_get_server_info($this->dbConn);
+ return $this->dbConn->server_info;
}
/**
@@ -113,35 +113,33 @@ public function query($sql, $errorLevel = E_USER_ERROR) {
$starttime = microtime(true);
}
- $handle = mysql_query($sql, $this->dbConn);
+ $handle = $this->dbConn->query($sql);
if(isset($_REQUEST['showqueries'])) {
$endtime = round(microtime(true) - $starttime,4);
Debug::message("\n$sql\n{$endtime}ms\n", false);
}
- if(!$handle && $errorLevel) $this->databaseError("Couldn't run query: $sql | " . mysql_error($this->dbConn), $errorLevel);
+ if(!$handle && $errorLevel) $this->databaseError("Couldn't run query: $sql | " . $this->dbConn->error, $errorLevel);
return new MySQLQuery($this, $handle);
}
public function getGeneratedID($table) {
- return mysql_insert_id($this->dbConn);
+ return $this->dbConn->insert_id;
}
public function isActive() {
return $this->active ? true : false;
}
public function createDatabase() {
- $this->query("CREATE DATABASE `$this->database`");
- $this->query("USE `$this->database`");
+ $this->query("CREATE DATABASE \"$this->database\"");
+ $this->query("USE \"$this->database\"");
$this->tableList = $this->fieldList = $this->indexList = null;
- if(mysql_select_db($this->database, $this->dbConn)) {
- $this->active = true;
- return true;
- }
+ $this->active = $this->dbConn->select_db($this->database);
+ return $this->active;
}
/**
@@ -173,10 +171,12 @@ public function currentDatabase() {
*/
public function selectDatabase($dbname) {
$this->database = $dbname;
+ $this->tableList = $this->fieldList = $this->indexList = null;
+ $this->active = false;
if($this->databaseExists($this->database)) {
- if(mysql_select_db($this->database, $this->dbConn)) $this->active = true;
+ $this->active = $this->dbConn->select_db($this->database);
}
- $this->tableList = $this->fieldList = $this->indexList = null;
+ return $this->active;
}
/**
@@ -206,9 +206,15 @@ public function allDatabaseNames() {
*/
public function createTable($table, $fields = null, $indexes = null, $options = null, $advancedOptions = null) {
$fieldSchemas = $indexSchemas = "";
-
- $addOptions = empty($options[get_class($this)]) ? "ENGINE=MyISAM" : $options[get_class($this)];
-
+
+ if(!empty($options[get_class($this)])) {
+ $addOptions = $options[get_class($this)];
+ } elseif(!empty($options[get_parent_class($this)])) {
+ $addOptions = $options[get_parent_class($this)];
+ } else {
+ $addOptions = "ENGINE=InnoDB";
+ }
+
if(!isset($fields['ID'])) $fields['ID'] = "int(11) not null auto_increment";
if($fields) foreach($fields as $k => $v) $fieldSchemas .= "\"$k\" $v,\n";
if($indexes) foreach($indexes as $k => $v) $indexSchemas .= $this->getIndexSqlDefinition($k, $v) . ",\n";
@@ -221,7 +227,7 @@ public function createTable($table, $fields = null, $indexes = null, $options =
$indexSchemas
primary key (ID)
) {$addOptions}");
-
+
return $table;
}
@@ -235,6 +241,13 @@ public function createTable($table, $fields = null, $indexes = null, $options =
* @param $alteredOptions
*/
public function alterTable($tableName, $newFields = null, $newIndexes = null, $alteredFields = null, $alteredIndexes = null, $alteredOptions = null, $advancedOptions = null) {
+ if($this->isView($tableName)) {
+ DB::alteration_message(
+ sprintf("Table %s not changed as it is a view", $tableName),
+ "changed"
+ );
+ return;
+ }
$fieldSchemas = $indexSchemas = "";
$alterList = array();
@@ -257,7 +270,12 @@ public function alterTable($tableName, $newFields = null, $newIndexes = null, $a
);
}
}
-
+
+ public function isView($tableName) {
+ $info = $this->query("SHOW /*!50002 FULL*/ TABLES LIKE '$tableName'")->record();
+ return $info && strtoupper($info['Table_type']) == 'VIEW';
+ }
+
public function renameTable($oldTableName, $newTableName) {
$this->query("ALTER TABLE \"$oldTableName\" RENAME \"$newTableName\"");
}
@@ -513,7 +531,7 @@ public function tableList() {
* @return int
*/
public function affectedRows() {
- return mysql_affected_rows($this->dbConn);
+ return $this->dbConn->affected_rows;
}
function databaseError($msg, $errorLevel = E_USER_ERROR) {
@@ -575,7 +593,8 @@ public function decimal($values){
$defaultValue = '';
if(isset($values['default']) && is_numeric($values['default'])) {
- $defaultValue = ' default ' . $values['default'];
+ $decs = strpos($precision, ',') !== false ? (int)substr($precision, strpos($precision, ',')+1) : 0;
+ $defaultValue = ' default ' . number_format($values['default'], $decs, '.', '');
}
return 'decimal(' . $precision . ') not null' . $defaultValue;
@@ -877,7 +896,7 @@ function dbDataType($type){
* This will return text which has been escaped in a database-friendly manner.
*/
function addslashes($value){
- return mysql_real_escape_string($value, $this->dbConn);
+ return $this->dbConn->real_escape_string($value);
}
/*
@@ -931,30 +950,43 @@ public function supportsExtensions($extensions=Array('partitions', 'tablespaces'
* See http://developer.postgresql.org/pgdocs/postgres/sql-set-transaction.html for details on transaction isolation options
*/
public function transactionStart($transaction_mode=false, $session_characteristics=false){
- //Transactions not set up for MySQL yet
+ // This sets the isolation level for the NEXT transaction, not the current one.
+ if($transaction_mode) {
+ $this->query('SET TRANSACTION ' . $transaction_mode . ';');
+ }
+
+ $this->query('START TRANSACTION;');
+
+ if($session_characteristics) {
+ $this->query('SET SESSION TRANSACTION ' . $session_characteristics . ';');
+ }
}
/*
* Create a savepoint that you can jump back to if you encounter problems
*/
public function transactionSavepoint($savepoint){
- //Transactions not set up for MySQL yet
+ $this->query("SAVEPOINT $savepoint;");
}
/*
* Rollback or revert to a savepoint if your queries encounter problems
* If you encounter a problem at any point during a transaction, you may
* need to rollback that particular query, or return to a savepoint
*/
- public function transactionRollback($savepoint=false){
- //Transactions not set up for MySQL yet
+ public function transactionRollback($savepoint = false){
+ if($savepoint) {
+ $this->query('ROLLBACK TO ' . $savepoint . ';');
+ } else {
+ $this->query('ROLLBACK');
+ }
}
/*
* Commit everything inside this transaction so far
*/
- public function transactionEnd(){
- //Transactions not set up for MySQL yet
+ public function transactionEnd($chain = false){
+ $this->query('COMMIT AND ' . ($chain ? '' : 'NO ') . 'CHAIN;');
}
/**
@@ -1098,35 +1130,30 @@ public function __construct(MySQLDatabase $database, $handle) {
}
public function __destruct() {
- if(is_resource($this->handle)) mysql_free_result($this->handle);
+ if(is_object($this->handle)) $this->handle->free();
}
-
+
public function seek($row) {
- return is_resource($this->handle) ? mysql_data_seek($this->handle, $row) : false;
+ if(is_object($this->handle)) return $this->handle->data_seek($row);
}
-
+
public function numRecords() {
- return is_resource($this->handle) ? mysql_num_rows($this->handle) : false;
+ if(is_object($this->handle)) return $this->handle->num_rows;
}
-
+
public function nextRecord() {
- // Coalesce rather than replace common fields.
- if(is_resource($this->handle) && $data = mysql_fetch_row($this->handle)) {
- foreach($data as $columnIdx => $value) {
- $columnName = mysql_field_name($this->handle, $columnIdx);
- // $value || !$ouput[$columnName] means that the *last* occurring value is shown
- // !$ouput[$columnName] means that the *first* occurring value is shown
- if(isset($value) || !isset($output[$columnName])) {
- $output[$columnName] = $value;
+ if(is_object($this->handle) && $data = $this->handle->fetch_row()) {
+ $output = array();
+ $this->handle->field_seek(0);
+ while($field = $this->handle->fetch_field()) {
+ $columnName = $field->name;
+ if(isset($data[$this->handle->current_field-1]) || !isset($output[$columnName])) {
+ $output[$columnName] = $data[$this->handle->current_field-1];
}
}
return $output;
} else {
return false;
}
}
-
-
}
-
-?>

2 comments on commit 6bf3f7d

Owner

chillu replied Oct 29, 2011

@sminnee @simonwelsh Awesome you've got that in, yay for using less deprecated APIs in SilverStripe :) This should also be tagged "API CHANGE". But more importantly: Let's try to document these relatively high impact changes at the time of commit, rather than release. Thats why we have /docs in source control now. So in a new /docs/en/changelog/alpha/3.0.0-alpha1.md file, write down an upgrading guide.

For example, what the "create table" changes mean for existing and new users and existing databases. What happens when you upgrade from 2.4 with an existing database, and then create a new subclass - will the new table(s) be in InnoDB, and everything else in MyISAM, hence potentially breaking any usage of MySQL FULLTEXT searches?

We should also create a script for migrating all tables to InnoDB, and explain why and when its a good idea (or point to a tech article that does it).

Contributor

powtac replied Jan 24, 2017

👍

Please sign in to comment.