diff --git a/classes/context/Context.class.php b/classes/context/Context.class.php
index 342bebcc9..36fe76e25 100644
--- a/classes/context/Context.class.php
+++ b/classes/context/Context.class.php
@@ -401,13 +401,6 @@ class Context
function close()
{
session_write_close();
-
- // DB close
- $oDB = DB::getInstance();
- if(is_object($oDB) && method_exists($oDB, 'close'))
- {
- $oDB->close();
- }
}
/**
diff --git a/classes/db/DB.class.php b/classes/db/DB.class.php
index aca61aa7f..f2167a03b 100644
--- a/classes/db/DB.class.php
+++ b/classes/db/DB.class.php
@@ -57,7 +57,8 @@ class DB
* @var array
*/
var $priority_dbms = array(
- 'mysqli' => 5,
+ 'mysqli' => 6,
+ 'mysqli_innodb' => 5,
'mysql' => 4,
'mysql_innodb' => 3,
'cubrid' => 2,
@@ -468,7 +469,8 @@ class DB
{
$log['result'] = 'Success';
}
- $GLOBALS['__db_queries__'][] = $log;
+
+ $this->setQueryLog($log);
// if __LOG_SLOW_QUERY__ if defined, check elapsed time and leave query log
if(__LOG_SLOW_QUERY__ > 0 && $elapsed_time > __LOG_SLOW_QUERY__)
@@ -486,6 +488,16 @@ class DB
}
}
+ /**
+ * set query debug log
+ * @param array $log values set query debug
+ * @return void
+ */
+ function setQueryLog($log)
+ {
+ $GLOBALS['__db_queries__'][] = $log;
+ }
+
/**
* set error
* @param int $errno error code
@@ -1089,6 +1101,7 @@ class DB
$connection = &$this->slave_db[$indx];
}
+ $this->commit();
$this->_close($connection["resource"]);
$connection["is_connected"] = FALSE;
@@ -1313,6 +1326,9 @@ class DB
// Save connection info for db logs
$this->connection = ucfirst($type) . ' ' . $connection["db_hostname"];
+ // regist $this->close callback
+ register_shutdown_function(array($this, "close"));
+
$this->_afterConnect($result);
}
diff --git a/classes/db/DBMysql_innodb.class.php b/classes/db/DBMysql_innodb.class.php
index 5a03950f5..affa59aab 100644
--- a/classes/db/DBMysql_innodb.class.php
+++ b/classes/db/DBMysql_innodb.class.php
@@ -43,7 +43,6 @@ class DBMysql_innodb extends DBMysql
*/
function _close($connection)
{
- $this->_query("commit", $connection);
@mysql_close($connection);
}
diff --git a/classes/db/DBMysqli_innodb.class.php b/classes/db/DBMysqli_innodb.class.php
new file mode 100644
index 000000000..9f5ee5671
--- /dev/null
+++ b/classes/db/DBMysqli_innodb.class.php
@@ -0,0 +1,583 @@
+ */
+
+require_once('DBMysql.class.php');
+
+/**
+ * Class to use MySQLi innoDB DBMS as mysqli_*
+ * mysql innodb handling class
+ *
+ * Does not use prepared statements, since mysql driver does not support them
+ *
+ * @author NAVER (developers@xpressengine.com)
+ * @package /classes/db
+ * @version 0.1
+ */
+class DBMysqli_innodb extends DBMysql
+{
+
+ /**
+ * Constructor
+ * @return void
+ */
+ function DBMysqli_innodb()
+ {
+ $this->_setDBInfo();
+ $this->_connect();
+ }
+
+ /**
+ * Create an instance of this class
+ * @return DBMysqli_innodb return DBMysqli_innodb object instance
+ */
+ function create()
+ {
+ return new DBMysqli_innodb;
+ }
+
+ /**
+ * DB Connect
+ * this method is private
+ * @param array $connection connection's value is db_hostname, db_port, db_database, db_userid, db_password
+ * @return resource
+ */
+ function __connect($connection)
+ {
+ // Attempt to connect
+ if($connection["db_port"])
+ {
+ $result = @mysqli_connect($connection["db_hostname"]
+ , $connection["db_userid"]
+ , $connection["db_password"]
+ , $connection["db_database"]
+ , $connection["db_port"]);
+ }
+ else
+ {
+ $result = @mysqli_connect($connection["db_hostname"]
+ , $connection["db_userid"]
+ , $connection["db_password"]
+ , $connection["db_database"]);
+ }
+ $error = mysqli_connect_errno();
+ if($error)
+ {
+ $this->setError($error, mysqli_connect_error());
+ return;
+ }
+ mysqli_set_charset($result, 'utf8');
+ return $result;
+ }
+
+ /**
+ * DB disconnection
+ * this method is private
+ * @param resource $connection
+ * @return void
+ */
+ function _close($connection)
+ {
+ mysqli_close($connection);
+ }
+
+ /**
+ * DB transaction start
+ * this method is private
+ * @return boolean
+ */
+ function _begin($transactionLevel)
+ {
+ $connection = $this->_getConnection('master');
+
+ if(!$transactionLevel)
+ {
+ $this->_query("begin");
+ }
+ else
+ {
+ $this->_query("SAVEPOINT SP" . $transactionLevel, $connection);
+ }
+ return true;
+ }
+
+ /**
+ * DB transaction rollback
+ * this method is private
+ * @return boolean
+ */
+ function _rollback($transactionLevel)
+ {
+ $connection = $this->_getConnection('master');
+
+ $point = $transactionLevel - 1;
+
+ if($point)
+ {
+ $this->_query("ROLLBACK TO SP" . $point, $connection);
+ }
+ else
+ {
+ mysqli_rollback($connection);
+ $this->setQueryLog( array("query"=>"rollback") );
+ }
+ return true;
+ }
+
+ /**
+ * DB transaction commit
+ * this method is private
+ * @return boolean
+ */
+ function _commit()
+ {
+ $connection = $this->_getConnection('master');
+ mysqli_commit($connection);
+ $this->setQueryLog( array("query"=>"commit") );
+ return true;
+ }
+
+
+
+ /**
+ * Handles quatation of the string variables from the query
+ * @param string $string
+ * @return string
+ */
+ function addQuotes($string)
+ {
+ if(version_compare(PHP_VERSION, "5.9.0", "<") && get_magic_quotes_gpc())
+ {
+ $string = stripslashes(str_replace("\\", "\\\\", $string));
+ }
+ if(!is_numeric($string))
+ {
+ $connection = $this->_getConnection('master');
+ $string = mysqli_escape_string($connection, $string);
+ }
+ return $string;
+ }
+
+ /**
+ * Execute the query
+ * this method is private
+ * @param string $query
+ * @param resource $connection
+ * @return resource
+ */
+ function __query($query, $connection)
+ {
+ if($this->use_prepared_statements == 'Y')
+ {
+ // 1. Prepare query
+ $stmt = mysqli_prepare($connection, $query);
+ if($stmt)
+ {
+ $types = '';
+ $params = array();
+ $this->_prepareQueryParameters($types, $params);
+
+ if(!empty($params))
+ {
+ $args[0] = $stmt;
+ $args[1] = $types;
+
+ $i = 2;
+ foreach($params as $key => $param)
+ {
+ $copy[$key] = $param;
+ $args[$i++] = &$copy[$key];
+ }
+
+ // 2. Bind parameters
+ $status = call_user_func_array('mysqli_stmt_bind_param', $args);
+ if(!$status)
+ {
+ $this->setError(-1, "Invalid arguments: $query" . mysqli_error($connection) . PHP_EOL . print_r($args, true));
+ }
+ }
+
+ // 3. Execute query
+ $status = mysqli_stmt_execute($stmt);
+
+ if(!$status)
+ {
+ $this->setError(-1, "Prepared statement failed: $query" . mysqli_error($connection) . PHP_EOL . print_r($args, true));
+ }
+
+ // Return stmt for other processing - like retrieving resultset (_fetch)
+ return $stmt;
+ // mysqli_stmt_close($stmt);
+ }
+ }
+ // Run the query statement
+ $result = mysqli_query($connection, $query);
+ // Error Check
+ $error = mysqli_error($connection);
+ if($error)
+ {
+ $this->setError(mysqli_errno($connection), $error);
+ }
+ // Return result
+ return $result;
+ }
+
+ /**
+ * Before execute query, prepare statement
+ * this method is private
+ * @param string $types
+ * @param array $params
+ * @return void
+ */
+ function _prepareQueryParameters(&$types, &$params)
+ {
+ $types = '';
+ $params = array();
+ if(!$this->param)
+ {
+ return;
+ }
+
+ foreach($this->param as $k => $o)
+ {
+ $value = $o->getUnescapedValue();
+ $type = $o->getType();
+
+ // Skip column names -> this should be concatenated to query string
+ if($o->isColumnName())
+ {
+ continue;
+ }
+
+ switch($type)
+ {
+ case 'number' :
+ $type = 'i';
+ break;
+ case 'varchar' :
+ $type = 's';
+ break;
+ default:
+ $type = 's';
+ }
+
+ if(is_array($value))
+ {
+ foreach($value as $v)
+ {
+ $params[] = $v;
+ $types .= $type;
+ }
+ }
+ else
+ {
+ $params[] = $value;
+ $types .= $type;
+ }
+ }
+ }
+
+ /**
+ * Fetch the result
+ * @param resource $result
+ * @param int|NULL $arrayIndexEndValue
+ * @return array
+ */
+ function _fetch($result, $arrayIndexEndValue = NULL)
+ {
+ if($this->use_prepared_statements != 'Y')
+ {
+ return parent::_fetch($result, $arrayIndexEndValue);
+ }
+ $output = array();
+ if(!$this->isConnected() || $this->isError() || !$result)
+ {
+ return $output;
+ }
+
+ // Prepared stements: bind result variable and fetch data
+ $stmt = $result;
+ $meta = mysqli_stmt_result_metadata($stmt);
+ $fields = mysqli_fetch_fields($meta);
+
+ /**
+ * Mysqli has a bug that causes LONGTEXT columns not to get loaded
+ * Unless store_result is called before
+ * MYSQLI_TYPE for longtext is 252
+ */
+ $longtext_exists = false;
+ foreach($fields as $field)
+ {
+ if(isset($resultArray[$field->name])) // When joined tables are used and the same column name appears twice, we should add it separately, otherwise bind_result fails
+ {
+ $field->name = 'repeat_' . $field->name;
+ }
+
+ // Array passed needs to contain references, not values
+ $row[$field->name] = "";
+ $resultArray[$field->name] = &$row[$field->name];
+
+ if($field->type == 252)
+ {
+ $longtext_exists = true;
+ }
+ }
+ $resultArray = array_merge(array($stmt), $resultArray);
+
+ if($longtext_exists)
+ {
+ mysqli_stmt_store_result($stmt);
+ }
+
+ call_user_func_array('mysqli_stmt_bind_result', $resultArray);
+
+ $rows = array();
+ while(mysqli_stmt_fetch($stmt))
+ {
+ $resultObject = new stdClass();
+
+ foreach($resultArray as $key => $value)
+ {
+ if($key === 0)
+ {
+ continue; // Skip stmt object
+ }
+ if(strpos($key, 'repeat_'))
+ {
+ $key = substr($key, 6);
+ }
+ $resultObject->$key = $value;
+ }
+
+ $rows[] = $resultObject;
+ }
+
+ mysqli_stmt_close($stmt);
+
+ if($arrayIndexEndValue)
+ {
+ foreach($rows as $row)
+ {
+ $output[$arrayIndexEndValue--] = $row;
+ }
+ }
+ else
+ {
+ $output = $rows;
+ }
+
+ if(count($output) == 1)
+ {
+ if(isset($arrayIndexEndValue))
+ {
+ return $output;
+ }
+ else
+ {
+ return $output[0];
+ }
+ }
+
+ return $output;
+ }
+
+ /**
+ * Handles insertAct
+ * @param Object $queryObject
+ * @param boolean $with_values
+ * @return resource
+ */
+ function _executeInsertAct($queryObject, $with_values = false)
+ {
+ if($this->use_prepared_statements != 'Y')
+ {
+ return parent::_executeInsertAct($queryObject);
+ }
+ $this->param = $queryObject->getArguments();
+ $result = parent::_executeInsertAct($queryObject, $with_values);
+ unset($this->param);
+ return $result;
+ }
+
+ /**
+ * Handles updateAct
+ * @param Object $queryObject
+ * @param boolean $with_values
+ * @return resource
+ */
+ function _executeUpdateAct($queryObject, $with_values = false)
+ {
+ if($this->use_prepared_statements != 'Y')
+ {
+ return parent::_executeUpdateAct($queryObject);
+ }
+ $this->param = $queryObject->getArguments();
+ $result = parent::_executeUpdateAct($queryObject, $with_values);
+ unset($this->param);
+ return $result;
+ }
+
+ /**
+ * Handles deleteAct
+ * @param Object $queryObject
+ * @param boolean $with_values
+ * @return resource
+ */
+ function _executeDeleteAct($queryObject, $with_values = false)
+ {
+ if($this->use_prepared_statements != 'Y')
+ {
+ return parent::_executeDeleteAct($queryObject);
+ }
+ $this->param = $queryObject->getArguments();
+ $result = parent::_executeDeleteAct($queryObject, $with_values);
+ unset($this->param);
+ return $result;
+ }
+
+ /**
+ * Handle selectAct
+ * In order to get a list of pages easily when selecting \n
+ * it supports a method as navigation
+ * @param Object $queryObject
+ * @param resource $connection
+ * @param boolean $with_values
+ * @return Object
+ */
+ function _executeSelectAct($queryObject, $connection = null, $with_values = false)
+ {
+ if($this->use_prepared_statements != 'Y')
+ {
+ return parent::_executeSelectAct($queryObject, $connection);
+ }
+ $this->param = $queryObject->getArguments();
+ $result = parent::_executeSelectAct($queryObject, $connection, $with_values);
+ unset($this->param);
+ return $result;
+ }
+
+ /**
+ * Get the ID generated in the last query
+ * Return next sequence from sequence table
+ * This method use only mysql
+ * @return int
+ */
+ function db_insert_id()
+ {
+ $connection = $this->_getConnection('master');
+ return mysqli_insert_id($connection);
+ }
+
+ /**
+ * Fetch a result row as an object
+ * @param resource $result
+ * @return object
+ */
+ function db_fetch_object(&$result)
+ {
+ return mysqli_fetch_object($result);
+ }
+
+ /**
+ * Free result memory
+ * @param resource $result
+ * @return boolean Returns TRUE on success or FALSE on failure.
+ */
+ function db_free_result(&$result)
+ {
+ return mysqli_free_result($result);
+ }
+
+ /**
+ * Create table by using the schema xml
+ *
+ * type : number, varchar, tinytext, text, bigtext, char, date, \n
+ * opt : notnull, default, size\n
+ * index : primary key, index, unique\n
+ * @param string $xml_doc xml schema contents
+ * @return void|object
+ */
+ function _createTable($xml_doc)
+ {
+ // xml parsing
+ $oXml = new XmlParser();
+ $xml_obj = $oXml->parse($xml_doc);
+ // Create a table schema
+ $table_name = $xml_obj->table->attrs->name;
+ if($this->isTableExists($table_name))
+ {
+ return;
+ }
+ $table_name = $this->prefix . $table_name;
+
+ if(!is_array($xml_obj->table->column))
+ {
+ $columns[] = $xml_obj->table->column;
+ }
+ else
+ {
+ $columns = $xml_obj->table->column;
+ }
+
+ foreach($columns as $column)
+ {
+ $name = $column->attrs->name;
+ $type = $column->attrs->type;
+ $size = $column->attrs->size;
+ $notnull = $column->attrs->notnull;
+ $primary_key = $column->attrs->primary_key;
+ $index = $column->attrs->index;
+ $unique = $column->attrs->unique;
+ $default = $column->attrs->default;
+ $auto_increment = $column->attrs->auto_increment;
+
+ $column_schema[] = sprintf('`%s` %s%s %s %s %s', $name, $this->column_type[$type], $size ? '(' . $size . ')' : '', isset($default) ? "default '" . $default . "'" : '', $notnull ? 'not null' : '', $auto_increment ? 'auto_increment' : '');
+
+ if($primary_key)
+ {
+ $primary_list[] = $name;
+ }
+ else if($unique)
+ {
+ $unique_list[$unique][] = $name;
+ }
+ else if($index)
+ {
+ $index_list[$index][] = $name;
+ }
+ }
+
+ if(count($primary_list))
+ {
+ $column_schema[] = sprintf("primary key (%s)", '`' . implode($primary_list, '`,`') . '`');
+ }
+
+ if(count($unique_list))
+ {
+ foreach($unique_list as $key => $val)
+ {
+ $column_schema[] = sprintf("unique %s (%s)", $key, '`' . implode($val, '`,`') . '`');
+ }
+ }
+
+ if(count($index_list))
+ {
+ foreach($index_list as $key => $val)
+ {
+ $column_schema[] = sprintf("index %s (%s)", $key, '`' . implode($val, '`,`') . '`');
+ }
+ }
+
+ $schema = sprintf('create table `%s` (%s%s) %s;', $this->addQuotes($table_name), "\n", implode($column_schema, ",\n"), "ENGINE = INNODB CHARACTER SET utf8 COLLATE utf8_general_ci");
+
+ $output = $this->_query($schema);
+ if(!$output)
+ {
+ return false;
+ }
+ }
+}
+
+DBMysqli_innodb::$isSupported = function_exists('mysqli_connect');
+
+/* End of file DBMysqli.class.php */
+/* Location: ./classes/db/DBMysqli.class.php */
diff --git a/modules/install/lang/lang.xml b/modules/install/lang/lang.xml
index a62f01978..0ac55bdf2 100644
--- a/modules/install/lang/lang.xml
+++ b/modules/install/lang/lang.xml
@@ -354,6 +354,19 @@
İşlemler, veritabanı dosyası myisam 'da oluşturulduğu zaman işlenmeyecektir.]]>
mysql*() để sử dụng MySql Database.
Giao dịch được vô hiệu hóa bởi File Database được tạo ra bởi myisam.]]>
+ -
+ innodb는 트랜잭션을 사용할 수 있습니다.]]>
+ Transactions will be processed with innodb]]>
+ 「innodb」ではトランザクションの処理が行えます。]]>
+ innodb可以使用transaction。]]>
+ innodb可以使用 transaction。]]>
+ La transaction sera validé pour innodb]]>
+ Транзакция включена для innodb]]>
+ La transacción es hablilitado para innodb]]>
+ İşlemler, innodb ile işlenecektir]]>
+ innodb để sử dụng MySql Database.
Giao dịch được kích hoạt cho innodb]]>
+
+
-
DB 파일은 myisam으로 생성되기에 트랜잭션이 이루어지지 않습니다.]]>
Transactions will not be processed since DB file is created in myisam]]>
diff --git a/modules/install/tpl/form.mysqli_innodb.html b/modules/install/tpl/form.mysqli_innodb.html
new file mode 100644
index 000000000..358e962f5
--- /dev/null
+++ b/modules/install/tpl/form.mysqli_innodb.html
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
{$XE_VALIDATOR_MESSAGE}
+
+
+
+
+