diff --git a/.doctrine-project.json b/.doctrine-project.json index de7af7318f3..3efda43f4ff 100644 --- a/.doctrine-project.json +++ b/.doctrine-project.json @@ -6,8 +6,8 @@ "docsSlug": "doctrine-dbal", "versions": [ { - "name": "3.2", - "branchName": "3.2.x", + "name": "3.3", + "branchName": "3.3.x", "slug": "latest", "current": true, "aliases": [ @@ -15,6 +15,12 @@ "stable" ] }, + { + "name": "3.2", + "branchName": "3.2.x", + "slug": "3.2", + "maintained": false + }, { "name": "3.1", "branchName": "3.1.x", diff --git a/README.md b/README.md index 906487abd60..f160bfb0932 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ # Doctrine DBAL -| [4.0-dev][4.0] | [3.2][3.2] | [2.13][2.13] | +| [4.0-dev][4.0] | [3.3][3.3] | [2.13][2.13] | |:----------------:|:----------:|:----------:| -| [![GitHub Actions][GA 4.0 image]][GA 4.0] | [![GitHub Actions][GA 3.2 image]][GA 3.2] | [![GitHub Actions][GA 2.13 image]][GA 2.13] | -| [![AppVeyor][AppVeyor 4.0 image]][AppVeyor 4.0] | [![AppVeyor][AppVeyor 3.2 image]][AppVeyor 3.2] | [![AppVeyor][AppVeyor 2.13 image]][AppVeyor 2.13] | -| [![Code Coverage][Coverage image]][CodeCov 4.0] | [![Code Coverage][Coverage 3.2 image]][CodeCov 3.2] | [![Code Coverage][Coverage 2.13 image]][CodeCov 2.13] | -| N/A | [![Code Coverage][TypeCov 3.2 image]][TypeCov 3.2] | N/A | +| [![GitHub Actions][GA 4.0 image]][GA 4.0] | [![GitHub Actions][GA 3.3 image]][GA 3.3] | [![GitHub Actions][GA 2.13 image]][GA 2.13] | +| [![AppVeyor][AppVeyor 4.0 image]][AppVeyor 4.0] | [![AppVeyor][AppVeyor 3.3 image]][AppVeyor 3.3] | [![AppVeyor][AppVeyor 2.13 image]][AppVeyor 2.13] | +| [![Code Coverage][Coverage image]][CodeCov 4.0] | [![Code Coverage][Coverage 3.3 image]][CodeCov 3.3] | [![Code Coverage][Coverage 2.13 image]][CodeCov 2.13] | +| N/A | [![Code Coverage][TypeCov 3.3 image]][TypeCov 3.3] | N/A | Powerful ***D***ata***B***ase ***A***bstraction ***L***ayer with many features for database schema introspection and schema management. @@ -23,13 +23,15 @@ Powerful ***D***ata***B***ase ***A***bstraction ***L***ayer with many features f [GA 4.0]: https://github.com/doctrine/dbal/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A4.0.x [GA 4.0 image]: https://github.com/doctrine/dbal/workflows/Continuous%20Integration/badge.svg - [Coverage 3.2 image]: https://codecov.io/gh/doctrine/dbal/branch/3.2.x/graph/badge.svg - [3.2]: https://github.com/doctrine/dbal/tree/3.2.x - [CodeCov 3.2]: https://codecov.io/gh/doctrine/dbal/branch/3.2.x - [AppVeyor 3.2]: https://ci.appveyor.com/project/doctrine/dbal/branch/3.2.x - [AppVeyor 3.2 image]: https://ci.appveyor.com/api/projects/status/i88kitq8qpbm0vie/branch/3.2.x?svg=true - [GA 3.2]: https://github.com/doctrine/dbal/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A3.2.x - [GA 3.2 image]: https://github.com/doctrine/dbal/workflows/Continuous%20Integration/badge.svg?branch=3.2.x + [Coverage 3.3 image]: https://codecov.io/gh/doctrine/dbal/branch/3.3.x/graph/badge.svg + [3.3]: https://github.com/doctrine/dbal/tree/3.3.x + [CodeCov 3.3]: https://codecov.io/gh/doctrine/dbal/branch/3.3.x + [AppVeyor 3.3]: https://ci.appveyor.com/project/doctrine/dbal/branch/3.3.x + [AppVeyor 3.3 image]: https://ci.appveyor.com/api/projects/status/i88kitq8qpbm0vie/branch/3.3.x?svg=true + [GA 3.3]: https://github.com/doctrine/dbal/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A3.3.x + [GA 3.3 image]: https://github.com/doctrine/dbal/workflows/Continuous%20Integration/badge.svg?branch=3.3.x + [TypeCov 3.3]: https://shepherd.dev/github/doctrine/dbal + [TypeCov 3.3 image]: https://shepherd.dev/github/doctrine/dbal/coverage.svg [Coverage 2.13 image]: https://codecov.io/gh/doctrine/dbal/branch/2.13.x/graph/badge.svg [2.13]: https://github.com/doctrine/dbal/tree/2.13.x @@ -38,5 +40,3 @@ Powerful ***D***ata***B***ase ***A***bstraction ***L***ayer with many features f [AppVeyor 2.13 image]: https://ci.appveyor.com/api/projects/status/i88kitq8qpbm0vie/branch/2.13.x?svg=true [GA 2.13]: https://github.com/doctrine/dbal/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A2.13.x [GA 2.13 image]: https://github.com/doctrine/dbal/workflows/Continuous%20Integration/badge.svg?branch=2.13.x - [TypeCov 3.2]: https://shepherd.dev/github/doctrine/dbal - [TypeCov 3.2 image]: https://shepherd.dev/github/doctrine/dbal/coverage.svg diff --git a/UPGRADE.md b/UPGRADE.md index 04ac0d3ffbe..eb7b8424036 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -612,6 +612,14 @@ The following methods have been removed. | `QueryCacheProfile` | `setResultCacheDriver()` | `setResultCache()` | | `QueryCacheProfile` | `getResultCacheDriver()` | `getResultCache()` | +# Upgrade to 3.4 + +# Deprecated `AbstractPlatform::getColumnComment()` and `AbstractPlatform::getDoctrineTypeComment()` + +DBAL no longer needs column comments to ensure proper diffing. Note that both +methods should probably have been marked as internal as these comments were an +implementation detail of the DBAL. + # Upgrade to 3.3 ## Deprecated `Type::canRequireSQLConversion()`. diff --git a/docs/en/reference/architecture.rst b/docs/en/reference/architecture.rst index 8ee7f910aee..32b00a2e2c4 100644 --- a/docs/en/reference/architecture.rst +++ b/docs/en/reference/architecture.rst @@ -12,11 +12,6 @@ and a ``Doctrine\DBAL\Result`` wraps a ``Doctrine\DBAL\Driver\Result``. and ``Doctrine\DBAL\Driver\Result`` are just interfaces. These interfaces are implemented by concrete drivers. -What do the wrapper components add to the underlying driver -implementations? The enhancements include SQL logging, events and -control over the transaction isolation level in a portable manner, -among others. - Apart from the three main components, a DBAL driver should also provide an implementation of the ``Doctrine\DBAL\Driver`` interface that has two primary purposes: @@ -26,18 +21,40 @@ has two primary purposes: 2. Act as a factory of other driver-specific components like platform, schema manager and exception converter. +The driver components can be decorated using the four driver interfaces in +order to add driver-independent functionality like logging or profiling. Those +decorators are configured as a middleware. + +The wrapper components ``Connection``, ``Statement`` and ``Result`` are the +objects that the application usually interacts with directly. They wrap the +middleware stack as well as the driver at the bottom of that stack. + The DBAL is separated into several different packages that separate responsibilities of the different RDBMS layers. Drivers ------- -The drivers abstract a PHP specific database API by enforcing three +The drivers abstract a PHP specific database API by enforcing four interfaces: -- ``\Doctrine\DBAL\Driver\Connection`` -- ``\Doctrine\DBAL\Driver\Statement`` -- ``\Doctrine\DBAL\Driver\Result`` +- ``Doctrine\DBAL\Driver`` +- ``Doctrine\DBAL\Driver\Connection`` +- ``Doctrine\DBAL\Driver\Statement`` +- ``Doctrine\DBAL\Driver\Result`` + +Middlewares +----------- + +A middleware sits in the middle between the wrapper components and the driver. +By implementing the ``Doctrine\DBAL\Driver\Middleware``, it decorates the +``Driver`` component of either the actual driver or a lower middleware. If +necessary, the middleware might also decorate ``Connection``, ``Statement`` +and ``Result``. + +An example for a middleware implementation is +``Doctrine\DBAL\Logging\Middleware`` which implements logging capabilities +on top of a driver. Platforms --------- @@ -72,4 +89,3 @@ The types offer an abstraction layer for the converting and generation of types between Databases and PHP. Doctrine comes bundled with some common types but offers the ability for developers to define custom types or extend existing ones easily. - diff --git a/docs/en/reference/data-retrieval-and-manipulation.rst b/docs/en/reference/data-retrieval-and-manipulation.rst index 1490ab760b8..17a435e6249 100644 --- a/docs/en/reference/data-retrieval-and-manipulation.rst +++ b/docs/en/reference/data-retrieval-and-manipulation.rst @@ -304,7 +304,7 @@ prepare() ~~~~~~~~~ Prepare a given SQL statement and return the -``\Doctrine\DBAL\Driver\Statement`` instance: +``\Doctrine\DBAL\Statement`` instance: .. code-block:: php diff --git a/docs/en/reference/types.rst b/docs/en/reference/types.rst index 1cad37e9465..94e572760e7 100644 --- a/docs/en/reference/types.rst +++ b/docs/en/reference/types.rst @@ -526,267 +526,270 @@ The following table shows an overview of Doctrine's type abstraction. The matrix contains the mapping information for how a specific Doctrine type is mapped to the database and back to PHP. Please also notice the mapping specific footnotes for additional information. +:: -+-------------------+---------------+-----------------------------------------------------------------------------------------------+ -| Doctrine | PHP | Database vendor | -| | +--------------------------+---------+----------------------------------------------------------+ -| | | Name | Version | Type | -+===================+===============+==========================+=========+==========================================================+ -| **smallint** | ``integer`` | **MySQL** | *all* | ``SMALLINT`` ``UNSIGNED`` [10]_ ``AUTO_INCREMENT`` [11]_ | -| | +--------------------------+---------+----------------------------------------------------------+ -| | | **PostgreSQL** | *all* | ``SMALLINT`` | -| | +--------------------------+---------+----------------------------------------------------------+ -| | | **Oracle** | *all* | ``NUMBER(5)`` | -| | +--------------------------+---------+----------------------------------------------------------+ -| | | **SQL Server** | *all* | ``SMALLINT`` ``IDENTITY`` [11]_ | -| | +--------------------------+---------+----------------------------------------------------------+ -| | | **SQLite** | *all* | ``INTEGER`` [15]_ | -+-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ -| **integer** | ``integer`` | **MySQL** | *all* | ``INT`` ``UNSIGNED`` [10]_ ``AUTO_INCREMENT`` [11]_ | -| | +--------------------------+---------+----------------------------------------------------------+ -| | | **PostgreSQL** | *all* | ``INT`` [12]_ | -| | | | +----------------------------------------------------------+ -| | | | | ``SERIAL`` [11]_ | -| | +--------------------------+---------+----------------------------------------------------------+ -| | | **Oracle** | *all* | ``NUMBER(10)`` | -| | +--------------------------+---------+----------------------------------------------------------+ -| | | **SQL Server** | *all* | ``INT`` ``IDENTITY`` [11]_ | -| | +--------------------------+---------+----------------------------------------------------------+ -| | | **SQLite** | *all* | ``INTEGER`` [15]_ | -+-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ -| **bigint** | ``string`` | **MySQL** | *all* | ``BIGINT`` ``UNSIGNED`` [10]_ ``AUTO_INCREMENT`` [11]_ | -| | [8]_ +--------------------------+---------+----------------------------------------------------------+ -| | | **PostgreSQL** | *all* | ``BIGINT`` [12]_ | -| | | | +----------------------------------------------------------+ -| | | | | ``BIGSERIAL`` [11]_ | -| | +--------------------------+---------+----------------------------------------------------------+ -| | | **Oracle** | *all* | ``NUMBER(20)`` | -| | +--------------------------+---------+----------------------------------------------------------+ -| | | **SQL Server** | *all* | ``BIGINT`` ``IDENTITY`` [11]_ | -| | +--------------------------+---------+----------------------------------------------------------+ -| | | **SQLite** | *all* | ``INTEGER`` [15]_ | -+-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ -| **decimal** [7]_ | ``string`` | **MySQL** | *all* | ``NUMERIC(p, s)`` ``UNSIGNED`` [10]_ | -| | [9]_ +--------------------------+---------+----------------------------------------------------------+ -| | | **PostgreSQL** | *all* | ``NUMERIC(p, s)`` | -| | +--------------------------+ | | -| | | **Oracle** | | | -| | +--------------------------+ | | -| | | **SQL Server** | | | -| | +--------------------------+ | | -| | | **SQLite** | | | -+-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ -| **float** | ``float`` | **MySQL** | *all* | ``DOUBLE PRECISION`` ``UNSIGNED`` [10]_ | -| | +--------------------------+---------+----------------------------------------------------------+ -| | | **PostgreSQL** | *all* | ``DOUBLE PRECISION`` | -| | +--------------------------+ | | -| | | **Oracle** | | | -| | +--------------------------+ | | -| | | **SQL Server** | | | -| | +--------------------------+ | | -| | | **SQLite** | | | -+-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ -| **string** | ``string`` | **MySQL** | *all* | ``VARCHAR(n)`` [3]_ | -| [2]_ [5]_ | +--------------------------+ | | -| | | **PostgreSQL** | | | -| | +--------------------------+ +----------------------------------------------------------+ -| | | **SQLite** | | | -| | +--------------------------+---------+----------------------------------------------------------+ -| | | **Oracle** | *all* | ``VARCHAR2(n)`` [3]_ | -| | | | +----------------------------------------------------------+ -| | | | | ``CHAR(n)`` [4]_ | -| | +--------------------------+---------+----------------------------------------------------------+ -| | | **SQL Server** | *all* | ``NVARCHAR(n)`` [3]_ | -| | | | +----------------------------------------------------------+ -| | | | | ``NCHAR(n)`` [4]_ | -+-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ -| **ascii_string** | ``string`` | **SQL Server** | | ``VARCHAR(n)`` | -| | | | | ``CHAR(n)`` | -+-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ -| **text** | ``string`` | **MySQL** | *all* | ``TINYTEXT`` [16]_ | -| | | | +----------------------------------------------------------+ -| | | | | ``TEXT`` [17]_ | -| | | | +----------------------------------------------------------+ -| | | | | ``MEDIUMTEXT`` [18]_ | -| | | | +----------------------------------------------------------+ -| | | | | ``LONGTEXT`` [19]_ | -| | +--------------------------+---------+----------------------------------------------------------+ -| | | **PostgreSQL** | *all* | ``TEXT`` | -| | +--------------------------+ | | -| | | **Oracle** | *all* | ``CLOB`` | -| | +--------------------------+ | | -| | | **SQLite** | | | -| | +--------------------------+---------+----------------------------------------------------------+ -| | | **SQL Server** | *all* | ``VARCHAR(MAX)`` | -+-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ -| **guid** | ``string`` | **MySQL** | *all* | ``VARCHAR(255)`` [1]_ | -| | +--------------------------+ | | -| | | **Oracle** | | | -| | +--------------------------+ | | -| | | **SQLite** | | | -| | +--------------------------+---------+----------------------------------------------------------+ -| | | **SQL Server** | *all* | ``UNIQUEIDENTIFIER`` | -| | +--------------------------+ | | -| | | **PostgreSQL** | *all* | ``UUID`` | -+-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ -| **binary** | ``resource`` | **MySQL** | *all* | ``VARBINARY(n)`` [3]_ | -| [2]_ [6]_ | +--------------------------+ | | -| | | **SQL Server** | +----------------------------------------------------------+ -| | +--------------------------+ | ``BINARY(n)`` [4]_ | -| | | **Oracle** | *all* | ``RAW(n)`` | -| | +--------------------------+---------+----------------------------------------------------------+ -| | | **PostgreSQL** | *all* | ``BYTEA`` [15]_ | -| | +--------------------------+---------+----------------------------------------------------------+ -| | | **SQLite** | *all* | ``BLOB`` [15]_ | -+-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ -| **blob** | ``resource`` | **MySQL** | *all* | ``TINYBLOB`` [16]_ | -| | | | +----------------------------------------------------------+ -| | | | | ``BLOB`` [17]_ | -| | | | +----------------------------------------------------------+ -| | | | | ``MEDIUMBLOB`` [18]_ | -| | | | +----------------------------------------------------------+ -| | | | | ``LONGBLOB`` [19]_ | -| | +--------------------------+---------+----------------------------------------------------------+ -| | | **Oracle** | *all* | ``BLOB`` | -| | +--------------------------+ | | -| | | **SQLite** | | | -| | +--------------------------+---------+----------------------------------------------------------+ -| | | **SQL Server** | *all* | ``VARBINARY(MAX)`` | -| | +--------------------------+---------+----------------------------------------------------------+ -| | | **PostgreSQL** | *all* | ``BYTEA`` | -+-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ -| **boolean** | ``boolean`` | **MySQL** | *all* | ``TINYINT(1)`` | -| | +--------------------------+---------+----------------------------------------------------------+ -| | | **PostgreSQL** | *all* | ``BOOLEAN`` | -| | +--------------------------+ | | -| | | **SQLite** | | | -| | +--------------------------+---------+----------------------------------------------------------+ -| | | **SQL Server** | *all* | ``BIT`` | -| | +--------------------------+ | | -| | | **Oracle** | *all* | ``NUMBER(1)`` | -+-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ -| **date** | ``\DateTime`` | **MySQL** | *all* | ``DATE`` | -| | +--------------------------+ | | -| | | **PostgreSQL** | | | -| | +--------------------------+ | | -| | | **Oracle** | | | -| | +--------------------------+ | | -| | | **SQLite** | | | -| | +--------------------------+---------+ | -| | | **SQL Server** | "all" | | -+-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ -| **datetime** | ``\DateTime`` | **MySQL** | *all* | ``DATETIME`` [13]_ | -| | +--------------------------+---------+----------------------------------------------------------+ -| | | **SQL Server** | *all* | ``DATETIME`` | -| | +--------------------------+ | | -| | | **SQLite** | | | -| | +--------------------------+---------+----------------------------------------------------------+ -| | | **PostgreSQL** | *all* | ``TIMESTAMP(0) WITHOUT TIME ZONE`` | -| | +--------------------------+---------+----------------------------------------------------------+ -| | | **Oracle** | *all* | ``TIMESTAMP(0)`` | -+-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ -| **datetimetz** | ``\DateTime`` | **MySQL** | *all* | ``DATETIME`` [14]_ [15]_ | -| | +--------------------------+ | | -| | | **SQLite** | | | -| | +--------------------------+---------+ | -| | | **SQL Server** | "all" | | -| | +--------------------------+---------+----------------------------------------------------------+ -| | | **PostgreSQL** | *all* | ``TIMESTAMP(0) WITH TIME ZONE`` | -| | +--------------------------+ | | -| | | **Oracle** | | | -+-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ -| **time** | ``\DateTime`` | **MySQL** | *all* | ``TIME`` | -| | +--------------------------+ | | -| | | **SQLite** | | | -| | +--------------------------+---------+----------------------------------------------------------+ -| | | **PostgreSQL** | *all* | ``TIME(0) WITHOUT TIME ZONE`` | -| | +--------------------------+---------+----------------------------------------------------------+ -| | | **Oracle** | *all* | ``DATE`` [15]_ | -| | +--------------------------+---------+----------------------------------------------------------+ -| | | **SQL Server** | "all" | ``TIME(0)`` | -+-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ -| **array** [1]_ | ``array`` | **MySQL** | *all* | ``TINYTEXT`` [16]_ | -+-------------------+ | | +----------------------------------------------------------+ -| **simple array** | | | | ``TEXT`` [17]_ | -| [1]_ | | | +----------------------------------------------------------+ -| | | | | ``MEDIUMTEXT`` [18]_ | -| | | | +----------------------------------------------------------+ -| | | | | ``LONGTEXT`` [19]_ | -| | +--------------------------+---------+----------------------------------------------------------+ -| | | **PostgreSQL** | *all* | ``TEXT`` | -| | +--------------------------+ | | -| | | **Oracle** | *all* | ``CLOB`` | -| | +--------------------------+ | | -| | | **SQLite** | | | -| | +--------------------------+---------+----------------------------------------------------------+ -| | | **SQL Server** | *all* | ``VARCHAR(MAX)`` | -+-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ -| **json** | ``mixed`` | **MySQL** | *all* | ``JSON`` | -| | +--------------------------+---------+----------------------------------------------------------+ -| | | **PostgreSQL** | *all* | ``JSON`` [20]_ | -| | | | +----------------------------------------------------------+ -| | | | | ``JSONB`` [21]_ | -| | +--------------------------+---------+----------------------------------------------------------+ -| | | **Oracle** | *all* | ``CLOB`` [1]_ | -| | +--------------------------+ | | -| | | **SQLite** | | | -| | +--------------------------+---------+----------------------------------------------------------+ -| | | **SQL Server** | *all* | ``VARCHAR(MAX)`` [1]_ | -+-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ -| **object** [1]_ | ``object`` | **MySQL** | *all* | ``TINYTEXT`` [16]_ | -| | | | +----------------------------------------------------------+ -| | | | | ``TEXT`` [17]_ | -| | | | +----------------------------------------------------------+ -| | | | | ``MEDIUMTEXT`` [18]_ | -| | | | +----------------------------------------------------------+ -| | | | | ``LONGTEXT`` [19]_ | -| | +--------------------------+---------+----------------------------------------------------------+ -| | | **PostgreSQL** | *all* | ``TEXT`` | -| | +--------------------------+ | | -| | | **Oracle** | *all* | ``CLOB`` | -| | +--------------------------+ | | -| | | **SQLite** | | | -| | +--------------------------+---------+----------------------------------------------------------+ -| | | **SQL Server** | *all* | ``VARCHAR(MAX)`` | -+-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ - -.. [1] Requires hint in the column comment for proper reverse engineering of the appropriate - Doctrine type mapping. -.. [2] **n** is the **length** attribute set in the column definition (defaults to 255 if omitted). -.. [3] Chosen if the column definition has the **fixed** attribute set to ``false`` (default). -.. [4] Chosen if the column definition has the **fixed** attribute set to ``true``. -.. [5] Silently maps to the vendor specific ``text`` type if the given **length** attribute for - **n** exceeds the maximum length the related platform allows. If this is the case, please - see [15]_. -.. [6] Silently maps to the vendor specific ``blob`` type if the given **length** attribute for - **n** exceeds the maximum length the related platform allows. If this is the case, please - see [15]_. -.. [7] **p** is the precision and **s** the scale set in the column definition. - The precision defaults to ``10`` and the scale to ``0`` if not set. -.. [8] Returns PHP ``string`` type value instead of ``integer`` because of maximum integer value - implications on non 64bit platforms. -.. [9] Returns PHP ``string`` type value instead of ``double`` because of PHP's limitation in - preserving the exact precision when casting to ``double``. -.. [10] Used if **unsigned** attribute is set to ``true`` in the column definition (default ``false``). -.. [11] Used if **autoincrement** attribute is set to ``true`` in the column definition (default ``false``). -.. [12] Chosen if the column definition has the **autoincrement** attribute set to ``false`` (default). -.. [13] Chosen if the column definition does not contain the **version** option inside the **platformOptions** - attribute array or is set to ``false`` which marks it as a non-locking information column. -.. [14] Fallback type as the vendor does not support a native date time type with timezone information. - This means that the timezone information gets lost when storing a value. -.. [15] Cannot be safely reverse engineered to the same Doctrine type as the vendor does not have a - native distinct data type for this mapping. Using this type with this vendor can therefore - have implications on schema comparison (*online* vs *offline* schema) and PHP type safety - (data conversion from database to PHP value) because it silently falls back to its - appropriate Doctrine type. -.. [16] Chosen if the column length is less or equal to **2 ^ 8 - 1 = 255**. -.. [17] Chosen if the column length is less or equal to **2 ^ 16 - 1 = 65535**. -.. [18] Chosen if the column length is less or equal to **2 ^ 24 - 1 = 16777215**. -.. [19] Chosen if the column length is less or equal to **2 ^ 32 - 1 = 4294967295** or empty. -.. [20] Chosen if the column definition does not contain the **jsonb** option inside the **platformOptions** - attribute array or is set to ``false``. -.. [21] Chosen if the column definition contains the **jsonb** option inside the **platformOptions** - attribute array and is set to ``true``. + +-------------------+---------------+-----------------------------------------------------------------------------------------------+ + | Doctrine | PHP | Database vendor | + | | +--------------------------+---------+----------------------------------------------------------+ + | | | Name | Version | Type | + +===================+===============+==========================+=========+==========================================================+ + | **smallint** | ``integer`` | **MySQL** | *all* | ``SMALLINT`` ``UNSIGNED`` [10] ``AUTO_INCREMENT`` [11] | + | | +--------------------------+---------+----------------------------------------------------------+ + | | | **PostgreSQL** | *all* | ``SMALLINT`` | + | | +--------------------------+---------+----------------------------------------------------------+ + | | | **Oracle** | *all* | ``NUMBER(5)`` | + | | +--------------------------+---------+----------------------------------------------------------+ + | | | **SQL Server** | *all* | ``SMALLINT`` ``IDENTITY`` [11] | + | | +--------------------------+---------+----------------------------------------------------------+ + | | | **SQLite** | *all* | ``INTEGER`` [15] | + +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ + | **integer** | ``integer`` | **MySQL** | *all* | ``INT`` ``UNSIGNED`` [10] ``AUTO_INCREMENT`` [11] | + | | +--------------------------+---------+----------------------------------------------------------+ + | | | **PostgreSQL** | *all* | ``INT`` [12] | + | | | | +----------------------------------------------------------+ + | | | | | ``SERIAL`` [11] | + | | +--------------------------+---------+----------------------------------------------------------+ + | | | **Oracle** | *all* | ``NUMBER(10)`` | + | | +--------------------------+---------+----------------------------------------------------------+ + | | | **SQL Server** | *all* | ``INT`` ``IDENTITY`` [11] | + | | +--------------------------+---------+----------------------------------------------------------+ + | | | **SQLite** | *all* | ``INTEGER`` [15] | + +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ + | **bigint** | ``string`` | **MySQL** | *all* | ``BIGINT`` ``UNSIGNED`` [10] ``AUTO_INCREMENT`` [11] | + | | [8] +--------------------------+---------+----------------------------------------------------------+ + | | | **PostgreSQL** | *all* | ``BIGINT`` [12] | + | | | | +----------------------------------------------------------+ + | | | | | ``BIGSERIAL`` [11] | + | | +--------------------------+---------+----------------------------------------------------------+ + | | | **Oracle** | *all* | ``NUMBER(20)`` | + | | +--------------------------+---------+----------------------------------------------------------+ + | | | **SQL Server** | *all* | ``BIGINT`` ``IDENTITY`` [11] | + | | +--------------------------+---------+----------------------------------------------------------+ + | | | **SQLite** | *all* | ``INTEGER`` [15] | + +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ + | **decimal** [7] | ``string`` | **MySQL** | *all* | ``NUMERIC(p, s)`` ``UNSIGNED`` [10] | + | | [9] +--------------------------+---------+----------------------------------------------------------+ + | | | **PostgreSQL** | *all* | ``NUMERIC(p, s)`` | + | | +--------------------------+ | | + | | | **Oracle** | | | + | | +--------------------------+ | | + | | | **SQL Server** | | | + | | +--------------------------+ | | + | | | **SQLite** | | | + +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ + | **float** | ``float`` | **MySQL** | *all* | ``DOUBLE PRECISION`` ``UNSIGNED`` [10] | + | | +--------------------------+---------+----------------------------------------------------------+ + | | | **PostgreSQL** | *all* | ``DOUBLE PRECISION`` | + | | +--------------------------+ | | + | | | **Oracle** | | | + | | +--------------------------+ | | + | | | **SQL Server** | | | + | | +--------------------------+ | | + | | | **SQLite** | | | + +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ + | **string** | ``string`` | **MySQL** | *all* | ``VARCHAR(n)`` [3] | + | [2] [5] | +--------------------------+ | | + | | | **PostgreSQL** | | | + | | +--------------------------+ +----------------------------------------------------------+ + | | | **SQLite** | | | + | | +--------------------------+---------+----------------------------------------------------------+ + | | | **Oracle** | *all* | ``VARCHAR2(n)`` [3] | + | | | | +----------------------------------------------------------+ + | | | | | ``CHAR(n)`` [4] | + | | +--------------------------+---------+----------------------------------------------------------+ + | | | **SQL Server** | *all* | ``NVARCHAR(n)`` [3] | + | | | | +----------------------------------------------------------+ + | | | | | ``NCHAR(n)`` [4] | + +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ + | **ascii_string** | ``string`` | **SQL Server** | | ``VARCHAR(n)`` | + | | | | | ``CHAR(n)`` | + +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ + | **text** | ``string`` | **MySQL** | *all* | ``TINYTEXT`` [16] | + | | | | +----------------------------------------------------------+ + | | | | | ``TEXT`` [17] | + | | | | +----------------------------------------------------------+ + | | | | | ``MEDIUMTEXT`` [18] | + | | | | +----------------------------------------------------------+ + | | | | | ``LONGTEXT`` [19] | + | | +--------------------------+---------+----------------------------------------------------------+ + | | | **PostgreSQL** | *all* | ``TEXT`` | + | | +--------------------------+ | | + | | | **Oracle** | *all* | ``CLOB`` | + | | +--------------------------+ | | + | | | **SQLite** | | | + | | +--------------------------+---------+----------------------------------------------------------+ + | | | **SQL Server** | *all* | ``VARCHAR(MAX)`` | + +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ + | **guid** | ``string`` | **MySQL** | *all* | ``VARCHAR(255)`` [1] | + | | +--------------------------+ | | + | | | **Oracle** | | | + | | +--------------------------+ | | + | | | **SQLite** | | | + | | +--------------------------+---------+----------------------------------------------------------+ + | | | **SQL Server** | *all* | ``UNIQUEIDENTIFIER`` | + | | +--------------------------+ | | + | | | **PostgreSQL** | *all* | ``UUID`` | + +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ + | **binary** | ``resource`` | **MySQL** | *all* | ``VARBINARY(n)`` [3] | + | [2] [6] | +--------------------------+ | | + | | | **SQL Server** | +----------------------------------------------------------+ + | | +--------------------------+ | ``BINARY(n)`` [4] | + | | | **Oracle** | *all* | ``RAW(n)`` | + | | +--------------------------+---------+----------------------------------------------------------+ + | | | **PostgreSQL** | *all* | ``BYTEA`` [15] | + | | +--------------------------+---------+----------------------------------------------------------+ + | | | **SQLite** | *all* | ``BLOB`` [15] | + +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ + | **blob** | ``resource`` | **MySQL** | *all* | ``TINYBLOB`` [16] | + | | | | +----------------------------------------------------------+ + | | | | | ``BLOB`` [17] | + | | | | +----------------------------------------------------------+ + | | | | | ``MEDIUMBLOB`` [18] | + | | | | +----------------------------------------------------------+ + | | | | | ``LONGBLOB`` [19] | + | | +--------------------------+---------+----------------------------------------------------------+ + | | | **Oracle** | *all* | ``BLOB`` | + | | +--------------------------+ | | + | | | **SQLite** | | | + | | +--------------------------+---------+----------------------------------------------------------+ + | | | **SQL Server** | *all* | ``VARBINARY(MAX)`` | + | | +--------------------------+---------+----------------------------------------------------------+ + | | | **PostgreSQL** | *all* | ``BYTEA`` | + +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ + | **boolean** | ``boolean`` | **MySQL** | *all* | ``TINYINT(1)`` | + | | +--------------------------+---------+----------------------------------------------------------+ + | | | **PostgreSQL** | *all* | ``BOOLEAN`` | + | | +--------------------------+ | | + | | | **SQLite** | | | + | | +--------------------------+---------+----------------------------------------------------------+ + | | | **SQL Server** | *all* | ``BIT`` | + | | +--------------------------+ | | + | | | **Oracle** | *all* | ``NUMBER(1)`` | + +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ + | **date** | ``\DateTime`` | **MySQL** | *all* | ``DATE`` | + | | +--------------------------+ | | + | | | **PostgreSQL** | | | + | | +--------------------------+ | | + | | | **Oracle** | | | + | | +--------------------------+ | | + | | | **SQLite** | | | + | | +--------------------------+---------+ | + | | | **SQL Server** | "all" | | + +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ + | **datetime** | ``\DateTime`` | **MySQL** | *all* | ``DATETIME`` [13] | + | | +--------------------------+---------+----------------------------------------------------------+ + | | | **SQL Server** | *all* | ``DATETIME`` | + | | +--------------------------+ | | + | | | **SQLite** | | | + | | +--------------------------+---------+----------------------------------------------------------+ + | | | **PostgreSQL** | *all* | ``TIMESTAMP(0) WITHOUT TIME ZONE`` | + | | +--------------------------+---------+----------------------------------------------------------+ + | | | **Oracle** | *all* | ``TIMESTAMP(0)`` | + +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ + | **datetimetz** | ``\DateTime`` | **MySQL** | *all* | ``DATETIME`` [14] [15] | + | | +--------------------------+ | | + | | | **SQLite** | | | + | | +--------------------------+---------+ | + | | | **SQL Server** | "all" | | + | | +--------------------------+---------+----------------------------------------------------------+ + | | | **PostgreSQL** | *all* | ``TIMESTAMP(0) WITH TIME ZONE`` | + | | +--------------------------+ | | + | | | **Oracle** | | | + +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ + | **time** | ``\DateTime`` | **MySQL** | *all* | ``TIME`` | + | | +--------------------------+ | | + | | | **SQLite** | | | + | | +--------------------------+---------+----------------------------------------------------------+ + | | | **PostgreSQL** | *all* | ``TIME(0) WITHOUT TIME ZONE`` | + | | +--------------------------+---------+----------------------------------------------------------+ + | | | **Oracle** | *all* | ``DATE`` [15] | + | | +--------------------------+---------+----------------------------------------------------------+ + | | | **SQL Server** | "all" | ``TIME(0)`` | + +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ + | **array** [1] | ``array`` | **MySQL** | *all* | ``TINYTEXT`` [16] | + +-------------------+ | | +----------------------------------------------------------+ + | **simple array** | | | | ``TEXT`` [17] | + | [1] | | | +----------------------------------------------------------+ + | | | | | ``MEDIUMTEXT`` [18] | + | | | | +----------------------------------------------------------+ + | | | | | ``LONGTEXT`` [19] | + | | +--------------------------+---------+----------------------------------------------------------+ + | | | **PostgreSQL** | *all* | ``TEXT`` | + | | +--------------------------+ | | + | | | **Oracle** | *all* | ``CLOB`` | + | | +--------------------------+ | | + | | | **SQLite** | | | + | | +--------------------------+---------+----------------------------------------------------------+ + | | | **SQL Server** | *all* | ``VARCHAR(MAX)`` | + +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ + | **json** | ``mixed`` | **MySQL** | *all* | ``JSON`` | + | | +--------------------------+---------+----------------------------------------------------------+ + | | | **PostgreSQL** | *all* | ``JSON`` [20] | + | | | | +----------------------------------------------------------+ + | | | | | ``JSONB`` [21] | + | | +--------------------------+---------+----------------------------------------------------------+ + | | | **Oracle** | *all* | ``CLOB`` [1] | + | | +--------------------------+ | | + | | | **SQLite** | | | + | | +--------------------------+---------+----------------------------------------------------------+ + | | | **SQL Server** | *all* | ``VARCHAR(MAX)`` [1] | + +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ + | **object** [1] | ``object`` | **MySQL** | *all* | ``TINYTEXT`` [16] | + | | | | +----------------------------------------------------------+ + | | | | | ``TEXT`` [17] | + | | | | +----------------------------------------------------------+ + | | | | | ``MEDIUMTEXT`` [18] | + | | | | +----------------------------------------------------------+ + | | | | | ``LONGTEXT`` [19] | + | | +--------------------------+---------+----------------------------------------------------------+ + | | | **PostgreSQL** | *all* | ``TEXT`` | + | | +--------------------------+ | | + | | | **Oracle** | *all* | ``CLOB`` | + | | +--------------------------+ | | + | | | **SQLite** | | | + | | +--------------------------+---------+----------------------------------------------------------+ + | | | **SQL Server** | *all* | ``VARCHAR(MAX)`` | + +-------------------+---------------+--------------------------+---------+----------------------------------------------------------+ + +**Notes** + +* [1] Requires hint in the column comment for proper reverse engineering of the appropriate + Doctrine type mapping. +* [2] **n** is the **length** attribute set in the column definition (defaults to 255 if omitted). +* [3] Chosen if the column definition has the **fixed** attribute set to ``false`` (default). +* [4] Chosen if the column definition has the **fixed** attribute set to ``true``. +* [5] Silently maps to the vendor specific ``text`` type if the given **length** attribute for + **n** exceeds the maximum length the related platform allows. If this is the case, please + see [15] . +* [6] Silently maps to the vendor specific ``blob`` type if the given **length** attribute for + **n** exceeds the maximum length the related platform allows. If this is the case, please + see [15] . +* [7] **p** is the precision and **s** the scale set in the column definition. + The precision defaults to ``10`` and the scale to ``0`` if not set. +* [8] Returns PHP ``string`` type value instead of ``integer`` because of maximum integer value + implications on non 64bit platforms. +* [9] Returns PHP ``string`` type value instead of ``double`` because of PHP's limitation in + preserving the exact precision when casting to ``double``. +* [10] Used if **unsigned** attribute is set to ``true`` in the column definition (default ``false``). +* [11] Used if **autoincrement** attribute is set to ``true`` in the column definition (default ``false``). +* [12] Chosen if the column definition has the **autoincrement** attribute set to ``false`` (default). +* [13] Chosen if the column definition does not contain the **version** option inside the **platformOptions** + attribute array or is set to ``false`` which marks it as a non-locking information column. +* [14] Fallback type as the vendor does not support a native date time type with timezone information. + This means that the timezone information gets lost when storing a value. +* [15] Cannot be safely reverse engineered to the same Doctrine type as the vendor does not have a + native distinct data type for this mapping. Using this type with this vendor can therefore + have implications on schema comparison (*online* vs *offline* schema) and PHP type safety + (data conversion from database to PHP value) because it silently falls back to its + appropriate Doctrine type. +* [16] Chosen if the column length is less or equal to **2 ^ 8 - 1 = 255**. +* [17] Chosen if the column length is less or equal to **2 ^ 16 - 1 = 65535**. +* [18] Chosen if the column length is less or equal to **2 ^ 24 - 1 = 16777215**. +* [19] Chosen if the column length is less or equal to **2 ^ 32 - 1 = 4294967295** or empty. +* [20] Chosen if the column definition does not contain the **jsonb** option inside the **platformOptions** + attribute array or is set to ``false``. +* [21] Chosen if the column definition contains the **jsonb** option inside the **platformOptions** + attribute array and is set to ``true``. Detection of Database Types --------------------------- diff --git a/run-all.sh b/run-all.sh deleted file mode 100755 index 0397b75f994..00000000000 --- a/run-all.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -# This script is a small convenience wrapper for running the doctrine testsuite against a large bunch of databases. -# Create *.phpunit.xml files and specify database connection parameters in the section. - -for i in *.phpunit.xml; do - echo "RUNNING TESTS WITH CONFIG $i" - vendor/bin/phpunit -c "$i" "$@" -done diff --git a/src/Driver/OCI8/Statement.php b/src/Driver/OCI8/Statement.php index a3a2056abd7..9b8b675b45a 100644 --- a/src/Driver/OCI8/Statement.php +++ b/src/Driver/OCI8/Statement.php @@ -77,7 +77,7 @@ public function bindParam( } if ( - ! oci_bind_by_name( + ! @oci_bind_by_name( $this->statement, $param, $variable, diff --git a/src/Driver/PDO/Exception.php b/src/Driver/PDO/Exception.php index 49f55951d82..7036a0e43cd 100644 --- a/src/Driver/PDO/Exception.php +++ b/src/Driver/PDO/Exception.php @@ -18,6 +18,10 @@ public static function new(PDOException $exception): self { if ($exception->errorInfo !== null) { [$sqlState, $code] = $exception->errorInfo; + + if ($code === null) { + $code = 0; + } } else { $code = $exception->getCode(); $sqlState = null; diff --git a/src/Platforms/AbstractMySQLPlatform.php b/src/Platforms/AbstractMySQLPlatform.php index 9cd67c38e31..40b2a9d5e5e 100644 --- a/src/Platforms/AbstractMySQLPlatform.php +++ b/src/Platforms/AbstractMySQLPlatform.php @@ -144,15 +144,18 @@ public function getListViewsSQL(string $database): string public function getListTableForeignKeysSQL(string $table, ?string $database = null): string { + // The schema name is passed multiple times as a literal in the WHERE clause instead of using a JOIN condition + // in order to avoid performance issues on MySQL older than 8.0 and the corresponding MariaDB versions + // caused by https://bugs.mysql.com/bug.php?id=81347 return 'SELECT k.CONSTRAINT_NAME, k.COLUMN_NAME, k.REFERENCED_TABLE_NAME, ' . 'k.REFERENCED_COLUMN_NAME /*!50116 , c.UPDATE_RULE, c.DELETE_RULE */ ' . 'FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE k /*!50116 ' . 'INNER JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS c ON ' . 'c.CONSTRAINT_NAME = k.CONSTRAINT_NAME AND ' . - 'c.TABLE_NAME = k.TABLE_NAME AND ' . - 'c.CONSTRAINT_SCHEMA = k.CONSTRAINT_SCHEMA */ ' . + 'c.TABLE_NAME = k.TABLE_NAME */ ' . 'WHERE k.TABLE_NAME = ' . $this->quoteStringLiteral($table) . ' ' . - 'AND k.TABLE_SCHEMA = ' . $this->getDatabaseNameSQL($database) . ' ' . + 'AND k.TABLE_SCHEMA = ' . $this->getDatabaseNameSQL($database) . ' /*!50116 ' . + 'AND c.CONSTRAINT_SCHEMA = ' . $this->getDatabaseNameSQL($database) . ' */' . 'ORDER BY k.ORDINAL_POSITION'; } diff --git a/tests/Functional/StatementTest.php b/tests/Functional/StatementTest.php index 107fe4de49d..03f193e3a6f 100644 --- a/tests/Functional/StatementTest.php +++ b/tests/Functional/StatementTest.php @@ -4,12 +4,13 @@ namespace Doctrine\DBAL\Tests\Functional; -use Doctrine\DBAL\Driver\Exception as DriverException; +use Doctrine\DBAL\Driver; use Doctrine\DBAL\Driver\IBMDB2; use Doctrine\DBAL\Driver\Mysqli; use Doctrine\DBAL\Driver\PDO; use Doctrine\DBAL\Driver\SQLSrv; use Doctrine\DBAL\Exception; +use Doctrine\DBAL\Exception\DriverException; use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\Result; use Doctrine\DBAL\Schema\Table; @@ -23,8 +24,6 @@ use function sprintf; use function stream_get_contents; -use const PHP_VERSION_ID; - class StatementTest extends FunctionalTestCase { protected function setUp(): void @@ -248,6 +247,19 @@ public function testBindParamWithNullLength(): void self::assertEquals(1, $stmt->executeQuery()->fetchOne()); } + public function testBindInvalidNamedParameter(): void + { + if (TestUtil::isDriverOneOf('ibm_db2', 'mysqli', 'sqlsrv')) { + self::markTestSkipped('The driver does not support named statement parameters'); + } + + $platform = $this->connection->getDatabasePlatform(); + $statement = $this->connection->prepare($platform->getDummySelectSQL(':foo')); + $this->expectException(DriverException::class); + + $statement->executeQuery(['bar' => 'baz']); + } + /** * @dataProvider emptyFetchProvider */ @@ -263,7 +275,7 @@ public function testFetchFromExecutedStatementWithFreedResult(callable $fetch, m // some drivers will trigger a PHP error here which, if not suppressed, // would be converted to a PHPUnit exception prior to DBAL throwing its own one $value = @$fetch($result); - } catch (DriverException $e) { + } catch (Driver\Exception $e) { // The drivers that enforce the command sequencing internally will throw an exception $this->expectNotToPerformAssertions(); @@ -350,7 +362,7 @@ public function testExecWithRedundantParameters(): void $query = $platform->getDummySelectSQL(); $stmt = $this->connection->prepare($query); - if (PHP_VERSION_ID >= 80000 && $driver instanceof Mysqli\Driver) { + if ($driver instanceof Mysqli\Driver) { $this->expectException(Error::class); } else { // we want to make sure the exception is thrown by the DBAL code, not by PHPUnit due to a PHP-level error,