Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: [MySQLi] add config to use MYSQLI_OPT_INT_AND_FLOAT_NATIVE #7265

Merged
merged 14 commits into from
Feb 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 18 additions & 17 deletions app/Config/Database.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,23 +25,24 @@ class Database extends Config
* The default database connection.
*/
public array $default = [
'DSN' => '',
'hostname' => 'localhost',
'username' => '',
'password' => '',
'database' => '',
'DBDriver' => 'MySQLi',
'DBPrefix' => '',
'pConnect' => false,
'DBDebug' => true,
'charset' => 'utf8',
'DBCollat' => 'utf8_general_ci',
'swapPre' => '',
'encrypt' => false,
'compress' => false,
'strictOn' => false,
'failover' => [],
'port' => 3306,
'DSN' => '',
'hostname' => 'localhost',
'username' => '',
'password' => '',
'database' => '',
'DBDriver' => 'MySQLi',
'DBPrefix' => '',
'pConnect' => false,
'DBDebug' => true,
'charset' => 'utf8',
'DBCollat' => 'utf8_general_ci',
'swapPre' => '',
'encrypt' => false,
'compress' => false,
'strictOn' => false,
'failover' => [],
'port' => 3306,
'numberNative' => false,
];

/**
Expand Down
11 changes: 11 additions & 0 deletions system/Database/MySQLi/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@ class Connection extends BaseConnection
*/
public $resultMode = MYSQLI_STORE_RESULT;

/**
* Use MYSQLI_OPT_INT_AND_FLOAT_NATIVE
*
* @var bool
*/
public $numberNative = false;

/**
* Connect to the database.
*
Expand Down Expand Up @@ -99,6 +106,10 @@ public function connect(bool $persistent = false)

$this->mysqli->options(MYSQLI_OPT_CONNECT_TIMEOUT, 10);

if ($this->numberNative === true) {
$this->mysqli->options(MYSQLI_OPT_INT_AND_FLOAT_NATIVE, 1);
}

if (isset($this->strictOn)) {
if ($this->strictOn) {
$this->mysqli->options(
Expand Down
102 changes: 102 additions & 0 deletions tests/system/Database/Live/MySQLi/NumberNativeTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<?php

/**
* This file is part of CodeIgniter 4 framework.
*
* (c) CodeIgniter Foundation <[email protected]>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/

namespace CodeIgniter\Database\Live\MySQLi;

use CodeIgniter\Test\CIUnitTestCase;
use CodeIgniter\Test\DatabaseTestTrait;
use Config\Database;
use Tests\Support\Database\Seeds\CITestSeeder;

/**
* @group DatabaseLive
*
* @internal
*/
final class NumberNativeTest extends CIUnitTestCase
{
use DatabaseTestTrait;

private $tests;
protected $refresh = true;
protected $seed = CITestSeeder::class;

protected function setUp(): void
{
parent::setUp();

$config = config('Database');

$this->tests = $config->tests;
}

public function testEnableNumberNative()
{
$this->tests['numberNative'] = true;

$db1 = Database::connect($this->tests);

kenjis marked this conversation as resolved.
Show resolved Hide resolved
if ($db1->DBDriver !== 'MySQLi') {
$this->markTestSkipped('Only MySQLi can complete this test.');
}

$this->assertTrue($db1->numberNative);
}

public function testDisableNumberNative()
{
$this->tests['numberNative'] = false;

$db1 = Database::connect($this->tests);

if ($db1->DBDriver !== 'MySQLi') {
$this->markTestSkipped('Only MySQLi can complete this test.');
}

$this->assertFalse($db1->numberNative);
}

public function testQueryDataAfterEnableNumberNative()
{
$this->tests['numberNative'] = true;

$db1 = Database::connect($this->tests);

if ($db1->DBDriver !== 'MySQLi') {
$this->markTestSkipped('Only MySQLi can complete this test.');
}

$data = $db1->table('db_type_test')
->get()
->getRow();

$this->assertIsFloat($data->type_float);
$this->assertIsInt($data->type_integer);
}

public function testQueryDataAfterDisableNumberNative()
{
$this->tests['numberNative'] = false;

$db1 = Database::connect($this->tests);

if ($db1->DBDriver !== 'MySQLi') {
$this->markTestSkipped('Only MySQLi can complete this test.');
}

$data = $db1->table('db_type_test')
->get()
->getRow();

$this->assertIsString($data->type_float);
$this->assertIsString($data->type_integer);
}
}
3 changes: 3 additions & 0 deletions user_guide_src/source/changelogs/v4.4.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ Forge
Others
------

- **MySQLi:** Added the ``numberNative`` attribute to the Database Config to keep the variable type obtained after SQL Query consistent with the type set in the database.
See :ref:`Database Configuration <database-configuration-explanation-of-values>`.

Model
=====

Expand Down
89 changes: 46 additions & 43 deletions user_guide_src/source/database/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -104,53 +104,56 @@ default group's configuration settings. The values should be name following this
database.default.password = '';
database.default.database = 'ci4';

.. _database-configuration-explanation-of-values:

**********************
Explanation of Values:
**********************

=============== ===========================================================================================================
Name Config Description
=============== ===========================================================================================================
**dsn** The DSN connect string (an all-in-one configuration sequence).
**hostname** The hostname of your database server. Often this is 'localhost'.
**username** The username used to connect to the database. (``SQLite3`` does not use this.)
**password** The password used to connect to the database. (``SQLite3`` does not use this.)
**database** The name of the database you want to connect to.

.. note:: CodeIgniter doesn't support dots (``.``) in the database, table, and column names.
**DBDriver** The database driver name. e.g.,: ``MySQLi``, ``Postgres``, etc. The case must match the driver name.
You can set a fully qualified classname to use your custom driver.
**DBPrefix** An optional table prefix which will added to the table name when running
:doc:`Query Builder <query_builder>` queries. This permits multiple CodeIgniter
installations to share one database.
**pConnect** true/false (boolean) - Whether to use a persistent connection.
**DBDebug** true/false (boolean) - Whether to throw exceptions or not when database errors occur.
**charset** The character set used in communicating with the database.
**DBCollat** The character collation used in communicating with the database (``MySQLi`` only).
**swapPre** A default table prefix that should be swapped with ``DBPrefix``. This is useful for distributed
applications where you might run manually written queries, and need the prefix to still be
customizable by the end user.
**schema** The database schema, default value varies by driver. (Used by ``Postgres`` and ``SQLSRV``.)
**encrypt** Whether or not to use an encrypted connection.
``SQLSRV`` driver accepts true/false
``MySQLi`` driver accepts an array with the following options:
* ``ssl_key`` - Path to the private key file
* ``ssl_cert`` - Path to the public key certificate file
* ``ssl_ca`` - Path to the certificate authority file
* ``ssl_capath`` - Path to a directory containing trusted CA certificates in PEM format
* ``ssl_cipher`` - List of *allowed* ciphers to be used for the encryption, separated by colons (``:``)
* ``ssl_verify`` - true/false; Whether to verify the server certificate or not (``MySQLi`` only)
**compress** Whether or not to use client compression (``MySQLi`` only).
**strictOn** true/false (boolean) - Whether to force "Strict Mode" connections, good for ensuring strict SQL
while developing an application (``MySQLi`` only).
**port** The database port number.
**foreignKeys** true/false (boolean) - Whether or not to enable Foreign Key constraint (``SQLite3`` only).

.. important:: SQLite3 Foreign Key constraint is disabled by default.
See `SQLite documentation <https://www.sqlite.org/pragma.html#pragma_foreign_keys>`_.
To enforce Foreign Key constraint, set this config item to true.
**busyTimeout** milliseconds (int) - Sleeps for a specified amount of time when a table is locked (``SQLite3`` only).
=============== ===========================================================================================================
================ ===========================================================================================================
Name Config Description
================ ===========================================================================================================
**dsn** The DSN connect string (an all-in-one configuration sequence).
**hostname** The hostname of your database server. Often this is 'localhost'.
**username** The username used to connect to the database. (``SQLite3`` does not use this.)
**password** The password used to connect to the database. (``SQLite3`` does not use this.)
**database** The name of the database you want to connect to.

.. note:: CodeIgniter doesn't support dots (``.``) in the database, table, and column names.
**DBDriver** The database driver name. e.g.,: ``MySQLi``, ``Postgres``, etc. The case must match the driver name.
You can set a fully qualified classname to use your custom driver.
**DBPrefix** An optional table prefix which will added to the table name when running
:doc:`Query Builder <query_builder>` queries. This permits multiple CodeIgniter
installations to share one database.
**pConnect** true/false (boolean) - Whether to use a persistent connection.
**DBDebug** true/false (boolean) - Whether to throw exceptions or not when database errors occur.
**charset** The character set used in communicating with the database.
**DBCollat** The character collation used in communicating with the database (``MySQLi`` only).
**swapPre** A default table prefix that should be swapped with ``DBPrefix``. This is useful for distributed
applications where you might run manually written queries, and need the prefix to still be
customizable by the end user.
**schema** The database schema, default value varies by driver. (Used by ``Postgres`` and ``SQLSRV``.)
**encrypt** Whether or not to use an encrypted connection.
``SQLSRV`` driver accepts true/false
``MySQLi`` driver accepts an array with the following options:
* ``ssl_key`` - Path to the private key file
* ``ssl_cert`` - Path to the public key certificate file
* ``ssl_ca`` - Path to the certificate authority file
* ``ssl_capath`` - Path to a directory containing trusted CA certificates in PEM format
* ``ssl_cipher`` - List of *allowed* ciphers to be used for the encryption, separated by colons (``:``)
* ``ssl_verify`` - true/false; Whether to verify the server certificate or not (``MySQLi`` only)
**compress** Whether or not to use client compression (``MySQLi`` only).
**strictOn** true/false (boolean) - Whether to force "Strict Mode" connections, good for ensuring strict SQL
while developing an application (``MySQLi`` only).
**port** The database port number.
**foreignKeys** true/false (boolean) - Whether or not to enable Foreign Key constraint (``SQLite3`` only).

.. important:: SQLite3 Foreign Key constraint is disabled by default.
See `SQLite documentation <https://www.sqlite.org/pragma.html#pragma_foreign_keys>`_.
To enforce Foreign Key constraint, set this config item to true.
**busyTimeout** milliseconds (int) - Sleeps for a specified amount of time when a table is locked (``SQLite3`` only).
**numberNative** true/false (boolean) - Whether or not to enable MYSQLI_OPT_INT_AND_FLOAT_NATIVE (``MySQLi`` only).
================ ===========================================================================================================

.. note:: Depending on what database driver you are using (``MySQLi``, ``Postgres``,
etc.) not all values will be needed. For example, when using ``SQLite3`` you
Expand Down