Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

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

…* functions.
  • Loading branch information...
commit 6bf3f7ded400c925dd66df2c2612c095d447c7b0 1 parent 0cdf52c
@simonwelsh simonwelsh authored
Showing with 82 additions and 55 deletions.
  1. +82 −55 model/MySQLDatabase.php
View
137 model/MySQLDatabase.php
@@ -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,7 +84,7 @@ public function getConnect($parameters) {
* @return boolean
*/
public function supportsCollations() {
- return $this->getVersion() >= 4.1;
+ return true;
}
/**
@@ -92,7 +92,7 @@ public function supportsCollations() {
* @return string
*/
public function getVersion() {
- return mysql_get_server_info($this->dbConn);
+ return $this->dbConn->server_info;
}
/**
@@ -113,19 +113,19 @@ 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() {
@@ -133,15 +133,13 @@ public function isActive() {
}
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,14 +950,23 @@ 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;");
}
/*
@@ -946,15 +974,19 @@ public function transactionSavepoint($savepoint){
* 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,26 +1130,25 @@ 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;
@@ -1125,8 +1156,4 @@ public function nextRecord() {
return false;
}
}
-
-
}
-
-?>

1 comment on commit 6bf3f7d

@chillu
Owner

@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).

Please sign in to comment.
Something went wrong with that request. Please try again.