README.md

October 8, 2024 ยท View on GitHub

Caution

This repository is no longer updated. To study behaviour differences, see platform matrix test in phpstan/phpstan-doctrine which has far bigger dataset.

How different PHP database drivers fetch numbers and booleans

When a native type is used and when string is returned? This repository aims to verify behaviour of PHP connectors to MySQL, PgSQL and SQLite with different configurations and PHP versions.

  • Used wrapper: doctrine/dbal
  • Tested PHP versions: 7.2 - 8.3.
  • Tested drivers: mysqli, pdo_sqlite, pdo_mysql, pdo_pgsql, pgsql (PHP >= 7.4), sqlite3 (PHP >= 7.4)
  • Used databases: mysql:8.0, postgres:13, sqlite:3

Results

  • Here is a table with results for default settings running on >= PHP 8.1:
Expressionpdo_mysql, mysqlipdo_sqlite, sqlite3pdo_pgsqlpgsql
TRUEintintboolbool
FALSEintintboolbool
col_boolintintboolbool
NOT(col_bool)intintboolbool
1 > 2intintboolbool
col_floatfloatfloatstringfloat
AVG(col_float)floatfloatstringfloat
SUM(col_float)floatfloatstringfloat
MIN(col_float)floatfloatstringfloat
MAX(col_float)floatfloatstringfloat
col_decimalstringfloatstringstring
0.1stringfloatstringstring
0.125e0floatfloatstringstring
AVG(col_decimal)stringfloatstringstring
AVG(col_int)stringfloatstringstring
AVG(col_bigint)stringfloatstringstring
SUM(col_decimal)stringfloatstringstring
MIN(col_decimal)stringfloatstringstring
MAX(col_decimal)stringfloatstringstring
1intintintint
2147483648intintintint
col_intintintintint
col_bigintintintintint
SUM(col_int)stringintintint
LENGTH('')intintintint
COUNT(*)intintintint
COUNT(1)intintintint
COUNT(col_int)intintintint
MIN(col_int)intintintint
MIN(col_bigint)intintintint
MAX(col_int)intintintint
MAX(col_bigint)intintintint
col_stringstringstringstringstring

Important notes:

  • Any tested PDO driver can force string for all values by PDO::ATTR_STRINGIFY_FETCHES: true
    • Exception is pdo_pgsql which does not stringify booleans on < PHP 8.1
  • pdo_mysql stringifies all values on < PHP 8.1
    • This can be changed by PDO::ATTR_EMULATE_PREPARES: false
  • pdo_sqlite stringifies all values on < PHP 8.1
  • mysqli stringifies all values by default when non-prepared statements are used
    • this can be changed by MYSQLI_OPT_INT_AND_FLOAT_NATIVE: false (docs)
  • Note that you cannot detect ATTR_STRINGIFY_FETCHES on PDO in any way. See bugreport
  • MySQL server treats 1.23 literals as DECIMALS, if you need FLOAT, use 1.23E0 instead (docs)
  • Stringified float/decimal numbers may include trailing zeros for some drivers, e.g. 0.000000

Full results visible in the test.

Why?

Running the tests

  • printf "UID=$(id -u)\nGID=$(id -g)" > .env
  • docker-compose up -d
  • ./test-all-php-versions.sh