diff --git a/system/Database/Forge.php b/system/Database/Forge.php index cc41c88464d9..747ec0b0abf0 100644 --- a/system/Database/Forge.php +++ b/system/Database/Forge.php @@ -82,7 +82,7 @@ class Forge /** * List of foreign keys. * - * @var type + * @var array */ protected $foreignKeys = []; diff --git a/system/Database/MySQLi/Connection.php b/system/Database/MySQLi/Connection.php index ae095d1584ee..96c263248c21 100644 --- a/system/Database/MySQLi/Connection.php +++ b/system/Database/MySQLi/Connection.php @@ -45,14 +45,12 @@ */ class Connection extends BaseConnection implements ConnectionInterface { - /** * Database driver * * @var string */ public $DBDriver = 'MySQLi'; - /** * DELETE hack flag * @@ -63,18 +61,14 @@ class Connection extends BaseConnection implements ConnectionInterface * @var boolean */ public $deleteHack = true; - // -------------------------------------------------------------------- - /** * Identifier escape character * * @var string */ public $escapeChar = '`'; - // -------------------------------------------------------------------- - /** * MySQLi object * @@ -83,7 +77,6 @@ class Connection extends BaseConnection implements ConnectionInterface * @var \MySQLi */ public $mysqli; - //-------------------------------------------------------------------- /** @@ -121,7 +114,8 @@ public function connect($persistent = false) { if ($this->strictOn) { - $this->mysqli->options(MYSQLI_INIT_COMMAND, 'SET SESSION sql_mode = CONCAT(@@sql_mode, ",", "STRICT_ALL_TABLES")'); + $this->mysqli->options(MYSQLI_INIT_COMMAND, + 'SET SESSION sql_mode = CONCAT(@@sql_mode, ",", "STRICT_ALL_TABLES")'); } else { @@ -154,7 +148,7 @@ public function connect($persistent = false) if ($this->encrypt['ssl_verify']) { defined('MYSQLI_OPT_SSL_VERIFY_SERVER_CERT') && - $this->mysqli->options(MYSQLI_OPT_SSL_VERIFY_SERVER_CERT, true); + $this->mysqli->options(MYSQLI_OPT_SSL_VERIFY_SERVER_CERT, true); } // Apparently (when it exists), setting MYSQLI_OPT_SSL_VERIFY_SERVER_CERT // to FALSE didn't do anything, so PHP 5.6.16 introduced yet another @@ -170,12 +164,14 @@ public function connect($persistent = false) $client_flags |= MYSQLI_CLIENT_SSL; $this->mysqli->ssl_set( - $ssl['key'] ?? null, $ssl['cert'] ?? null, $ssl['ca'] ?? null, $ssl['capath'] ?? null, $ssl['cipher'] ?? null + $ssl['key'] ?? null, $ssl['cert'] ?? null, $ssl['ca'] ?? null, + $ssl['capath'] ?? null, $ssl['cipher'] ?? null ); } } - if ($this->mysqli->real_connect($hostname, $this->username, $this->password, $this->database, $port, $socket, $client_flags) + if ($this->mysqli->real_connect($hostname, $this->username, $this->password, + $this->database, $port, $socket, $client_flags) ) { // Prior to version 5.7.3, MySQL silently downgrades to an unencrypted connection if SSL setup fails @@ -191,18 +187,21 @@ public function connect($persistent = false) { throw new DatabaseException($message); } + return false; } if (! $this->mysqli->set_charset($this->charset)) { - log_message('error', "Database: Unable to set the configured connection charset ('{$this->charset}')."); + log_message('error', + "Database: Unable to set the configured connection charset ('{$this->charset}')."); $this->mysqli->close(); if ($this->db->debug) { throw new DatabaseException('Unable to set client connection character set: ' . $this->charset); } + return false; } @@ -425,7 +424,7 @@ public function _fieldData(string $table): array $query = $query->getResultObject(); $retval = []; - for ($i = 0, $c = count($query); $i < $c; $i ++) + for ($i = 0, $c = count($query); $i < $c; $i++) { $retval[$i] = new \stdClass(); $retval[$i]->name = $query[$i]->Field; @@ -433,7 +432,7 @@ public function _fieldData(string $table): array sscanf($query[$i]->Type, '%[a-z](%d)', $retval[$i]->type, $retval[$i]->max_length); $retval[$i]->default = $query[$i]->Default; - $retval[$i]->primary_key = (int) ($query[$i]->Key === 'PRI'); + $retval[$i]->primary_key = (int)($query[$i]->Key === 'PRI'); } return $retval; @@ -453,53 +452,56 @@ public function _indexData(string $table): array { $table = $this->protectIdentifiers($table, true, null, false); - if (($query = $this->query('SHOW CREATE TABLE ' . $table)) === false) + if (($query = $this->query('SHOW INDEX FROM ' . $table)) === false) { throw new DatabaseException(lang('Database.failGetIndexData')); } - if (! $row = $query->getRowArray()) + if (! $indexes = $query->getResultArray()) { return []; } - $retval = []; - foreach (explode("\n", $row['Create Table']) as $line) + $keys = []; + + foreach ($indexes as $index) { - $line = trim($line); - if (strpos($line, 'PRIMARY KEY') === 0) + if (empty($keys[$index['Key_name']])) { - $obj = new \stdClass(); - $obj->name = 'PRIMARY KEY'; - $_fields = explode(',', preg_replace('/^.*\((.+)\).*$/', '$1', $line)); - $obj->fields = array_map(function ($v) { - return trim($v, '`'); - }, $_fields); - $obj->type = 'PRIMARY'; - - $retval[] = $obj; - } - elseif (($unique = strpos($line, 'UNIQUE KEY') === 0) || strpos($line, 'KEY') === 0) - { - if (preg_match('/KEY `([^`]+)` \((.+)\)/', $line, $matches)) + $keys[$index['Key_name']] = new \stdClass(); + $keys[$index['Key_name']]->name = $index['Key_name']; + + if ($index['Key_name'] === 'PRIMARY') { - $obj = new \stdClass(); - $obj->name = $matches[1]; - $obj->fields = array_map(function ($v) { - return trim($v, '`'); - }, explode(',', $matches[2])); - $obj->type = $unique ? 'UNIQUE' : 'INDEX'; - - $retval[] = $obj; + $type = 'PRIMARY'; + } + elseif ($index['Index_type'] === 'FULLTEXT') + { + $type = 'FULLTEXT'; + } + elseif ($index['Non_unique']) + { + if ($index['Index_type'] === 'SPATIAL') + { + $type = 'SPATIAL'; + } + else + { + $type = 'INDEX'; + } } else { - throw new \LogicException(lang('Database.parseStringFail')); + $type = 'UNIQUE'; } + + $keys[$index['Key_name']]->type = $type; } + + $keys[$index['Key_name']]->fields[] = $index['Column_name']; } - return $retval; + return $keys; } //-------------------------------------------------------------------- @@ -535,10 +537,10 @@ public function _foreignKeyData(string $table): array $retval = []; foreach ($query as $row) { - $obj = new \stdClass(); - $obj->constraint_name = $row->CONSTRAINT_NAME; - $obj->table_name = $row->TABLE_NAME; - $obj->foreign_table_name = $row->REFERENCED_TABLE_NAME; + $obj = new \stdClass(); + $obj->constraint_name = $row->CONSTRAINT_NAME; + $obj->table_name = $row->TABLE_NAME; + $obj->foreign_table_name = $row->REFERENCED_TABLE_NAME; $retval[] = $obj; } @@ -611,6 +613,7 @@ protected function _transCommit(): bool if ($this->connID->commit()) { $this->connID->autocommit(true); + return true; } @@ -629,11 +632,11 @@ protected function _transRollback(): bool if ($this->connID->rollback()) { $this->connID->autocommit(true); + return true; } return false; } - //-------------------------------------------------------------------- } diff --git a/system/Database/Postgre/Connection.php b/system/Database/Postgre/Connection.php index f35271853288..5de091481665 100644 --- a/system/Database/Postgre/Connection.php +++ b/system/Database/Postgre/Connection.php @@ -365,7 +365,7 @@ public function _indexData(string $table): array $obj->type = (strpos($row->indexdef, 'CREATE UNIQUE') === 0) ? 'UNIQUE' : 'INDEX'; } - $retval[] = $obj; + $retval[$obj->name] = $obj; } return $retval; diff --git a/system/Database/SQLite3/Connection.php b/system/Database/SQLite3/Connection.php index 1e1db6fe15b5..367945d171ee 100644 --- a/system/Database/SQLite3/Connection.php +++ b/system/Database/SQLite3/Connection.php @@ -364,7 +364,7 @@ public function _indexData(string $table): array $obj->fields[] = $field->name; } - $retval[] = $obj; + $retval[$obj->name] = $obj; } return $retval; diff --git a/tests/system/Database/Live/ForgeTest.php b/tests/system/Database/Live/ForgeTest.php index d2a94ace4273..9fcfc5be8955 100644 --- a/tests/system/Database/Live/ForgeTest.php +++ b/tests/system/Database/Live/ForgeTest.php @@ -11,6 +11,10 @@ class ForgeTest extends CIDatabaseTestCase protected $refresh = true; protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; + /** + * @var \CodeIgniter\Database\Forge + */ + protected $forge; public function setUp() { @@ -180,27 +184,27 @@ public function testCompositeKey() if ($this->db->DBDriver === 'MySQLi') { - $this->assertEquals($keys[0]->name, 'PRIMARY KEY'); - $this->assertEquals($keys[0]->fields, ['id']); - $this->assertEquals($keys[0]->type, 'PRIMARY'); - $this->assertEquals($keys[2]->name, 'code_company'); - $this->assertEquals($keys[2]->fields, ['code', 'company']); - $this->assertEquals($keys[2]->type, 'INDEX'); - $this->assertEquals($keys[1]->name, 'code_active'); - $this->assertEquals($keys[1]->fields, ['code', 'active']); - $this->assertEquals($keys[1]->type, 'UNIQUE'); + $this->assertEquals($keys['PRIMARY']->name, 'PRIMARY'); + $this->assertEquals($keys['PRIMARY']->fields, ['id']); + $this->assertEquals($keys['PRIMARY']->type, 'PRIMARY'); + $this->assertEquals($keys['code_company']->name, 'code_company'); + $this->assertEquals($keys['code_company']->fields, ['code', 'company']); + $this->assertEquals($keys['code_company']->type, 'INDEX'); + $this->assertEquals($keys['code_active']->name, 'code_active'); + $this->assertEquals($keys['code_active']->fields, ['code', 'active']); + $this->assertEquals($keys['code_active']->type, 'UNIQUE'); } elseif ($this->db->DBDriver === 'Postgre') { - $this->assertEquals($keys[0]->name, 'pk_db_forge_test_1'); - $this->assertEquals($keys[0]->fields, ['id']); - $this->assertEquals($keys[0]->type, 'PRIMARY'); - $this->assertEquals($keys[1]->name, 'db_forge_test_1_code_company'); - $this->assertEquals($keys[1]->fields, ['code', 'company']); - $this->assertEquals($keys[1]->type, 'INDEX'); - $this->assertEquals($keys[2]->name, 'db_forge_test_1_code_active'); - $this->assertEquals($keys[2]->fields, ['code', 'active']); - $this->assertEquals($keys[2]->type, 'UNIQUE'); + $this->assertEquals($keys['pk_db_forge_test_1']->name, 'pk_db_forge_test_1'); + $this->assertEquals($keys['pk_db_forge_test_1']->fields, ['id']); + $this->assertEquals($keys['pk_db_forge_test_1']->type, 'PRIMARY'); + $this->assertEquals($keys['db_forge_test_1_code_company']->name, 'db_forge_test_1_code_company'); + $this->assertEquals($keys['db_forge_test_1_code_company']->fields, ['code', 'company']); + $this->assertEquals($keys['db_forge_test_1_code_company']->type, 'INDEX'); + $this->assertEquals($keys['db_forge_test_1_code_active']->name, 'db_forge_test_1_code_active'); + $this->assertEquals($keys['db_forge_test_1_code_active']->fields, ['code', 'active']); + $this->assertEquals($keys['db_forge_test_1_code_active']->type, 'UNIQUE'); } $this->forge->dropTable('forge_test_1', true);