pax_global_header00006660000000000000000000000064136054456600014523gustar00rootroot0000000000000052 comment=ee244eaf17c155b3ac3e6b85f5a834137eb17c32 php-doctrine-dbal-2.10.1/000077500000000000000000000000001360544566000151005ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/.appveyor.yml000066400000000000000000000140661360544566000175550ustar00rootroot00000000000000build: false platform: - x64 #matrix: # fast_finish: true # kills the build at the first failure clone_folder: C:\projects\dbal clone_depth: 2 cache: - C:\ProgramData\chocolatey\bin -> .appveyor.yml - C:\ProgramData\chocolatey\lib -> .appveyor.yml - C:\tools\php -> .appveyor.yml - C:\tools\cacert -> .appveyor.yml - C:\tools\composer -> .appveyor.yml - C:\tools\ocular -> .appveyor.yml - '%LOCALAPPDATA%\Composer\files -> composer.json' ## Build matrix for lowest and highest possible targets environment: matrix: - db: mssql driver: sqlsrv db_version: sql2008r2sp2 coverage: yes php: 7.3 - db: mssql driver: sqlsrv db_version: sql2012sp1 php: 7.3 coverage: yes - db: mssql driver: sqlsrv db_version: sql2017 coverage: no php: 7.3 - db: mssql driver: pdo_sqlsrv db_version: sql2017 php: 7.3 coverage: yes init: - SET PATH=C:\Program Files\OpenSSL;c:\tools\php;C:\tools\composer;C:\tools\ocular;%PATH% - SET COMPOSER_NO_INTERACTION=1 - SET ANSICON=121x90 (121x90) ## Install PHP and composer, and run the appropriate composer command install: - ps: | # Check if installation is cached if (!(Test-Path c:\tools\php)) { appveyor-retry cinst --params '""/InstallDir:C:\tools\php""' --ignore-checksums -y php --version 7.3.12 # install sqlite appveyor-retry cinst -y sqlite Get-ChildItem -Path c:\tools\php cd c:\tools\php # Set PHP environment items that are always needed copy php.ini-production php.ini Add-Content php.ini "`n date.timezone=UTC" Add-Content php.ini "`n extension_dir=ext" Add-Content php.ini "`n memory_limit=1G" Add-Content php.ini "`n extension=php_openssl.dll" Add-Content php.ini "`n extension=php_mbstring.dll" Add-Content php.ini "`n extension=php_fileinfo.dll" Add-Content php.ini "`n extension=php_pdo_sqlite.dll" Add-Content php.ini "`n extension=php_sqlite3.dll" Add-Content php.ini "`n extension=php_curl.dll" Add-Content php.ini "`n curl.cainfo=C:\tools\cacert\bundle.pem" # Get and install the latest stable sqlsrv DLL's $DLLVersion = (Invoke-WebRequest "https://pecl.php.net/rest/r/sqlsrv/stable.txt").Content cd c:\tools\php\ext $source = "https://windows.php.net/downloads/pecl/releases/sqlsrv/$($DLLVersion)/php_sqlsrv-$($DLLVersion)-$($env:php)-nts-vc15-x64.zip" $destination = "c:\tools\php\ext\php_sqlsrv-$($DLLVersion)-$($env:php)-nts-vc15-x64.zip" Invoke-WebRequest $source -OutFile $destination 7z x -y php_sqlsrv-$($DLLVersion)-$($env:php)-nts-vc15-x64.zip > $null $source = "https://windows.php.net/downloads/pecl/releases/pdo_sqlsrv/$($DLLVersion)/php_pdo_sqlsrv-$($DLLVersion)-$($env:php)-nts-vc15-x64.zip" $destination = "c:\tools\php\ext\php_pdo_sqlsrv-$($DLLVersion)-$($env:php)-nts-vc15-x64.zip" Invoke-WebRequest $source -OutFile $destination 7z x -y php_pdo_sqlsrv-$($DLLVersion)-$($env:php)-nts-vc15-x64.zip > $null $DLLVersion = (Invoke-WebRequest "https://pecl.php.net/rest/r/xdebug/stable.txt").Content $source = "https://xdebug.org/files/php_xdebug-$($DLLVersion)-$($env:php)-vc15-nts-x86_64.dll" $destination = "c:\tools\php\ext\php_xdebug.dll" Invoke-WebRequest $source -OutFile $destination Remove-Item c:\tools\php\* -include .zip cd c:\tools\php Add-Content php.ini "`nextension=php_sqlsrv.dll" Add-Content php.ini "`nextension=php_pdo_sqlsrv.dll" Add-Content php.ini "`nzend_extension=php_xdebug.dll" Add-Content php.ini "`n" # download Composer if (!(Test-Path C:\tools\composer)) { New-Item -path c:\tools -name composer -itemtype directory } if (!(Test-Path c:\tools\composer\composer.phar)) { appveyor-retry appveyor DownloadFile https://getcomposer.org/composer.phar -Filename C:\tools\composer\composer.phar Set-Content -path 'C:\tools\composer\composer.bat' -Value ('@php C:\tools\composer\composer.phar %*') } # download Scrutinizer's Ocular if (!(Test-Path C:\tools\ocular)) { New-Item -path c:\tools -name ocular -itemtype directory } if (!(Test-Path c:\tools\ocular\ocular.phar)) { appveyor-retry appveyor DownloadFile https://github.com/scrutinizer-ci/ocular/releases/download/1.5.2/ocular.phar -Filename C:\tools\ocular\ocular.phar Set-Content -path 'C:\tools\ocular\ocular.bat' -Value ('@php C:\tools\ocular\ocular.phar %*') } # download CA bundle if (!(Test-Path C:\tools\cacert)) { New-Item -path c:\tools\ -name cacert -itemtype directory } if (!(Test-Path c:\tools\cacert\bundle.pem)) { appveyor-retry appveyor DownloadFile https://curl.haxx.se/ca/cacert.pem -Filename C:\tools\cacert\bundle.pem } } # install composer dependencies - cd C:\projects\dbal - appveyor-retry composer self-update - appveyor-retry composer install --no-progress --prefer-dist before_test: # Selectively start the services - ps: >- if ($env:db -eq "mssql") { $instanceName = $env:db_version.ToUpper() net start "MSSQL`$$instanceName" } test_script: - ps: >- if ($env:db_version) { $env:phpunit_config = "tests\appveyor\$($env:db).$($env:db_version).$($env:driver).appveyor.xml" } else { $env:phpunit_config = "tests\appveyor\$($env:db).$($env:driver).appveyor.xml" } if ($env:coverage -eq "yes") { vendor\bin\phpunit -c $($env:phpunit_config) --coverage-clover clover.xml } else { vendor\bin\phpunit -c $($env:phpunit_config) } if ($LastExitCode -ne 0) { $host.SetShouldExit($LastExitCode) } after_test: - ps: >- if ($env:coverage -eq "yes") { appveyor-retry ocular code-coverage:upload --format=php-clover clover.xml } php-doctrine-dbal-2.10.1/.doctrine-project.json000066400000000000000000000023311360544566000213230ustar00rootroot00000000000000{ "active": true, "name": "Database Abstraction Layer", "shortName": "DBAL", "slug": "dbal", "docsSlug": "doctrine-dbal", "versions": [ { "name": "3.0", "branchName": "develop", "slug": "latest", "upcoming": true }, { "name": "2.10", "branchName": "master", "slug": "2.10", "upcoming": true }, { "name": "2.9", "branchName": "2.9", "slug": "2.9", "current": true, "aliases": [ "current", "stable" ] }, { "name": "2.8", "branchName": "2.8", "slug": "2.8", "maintained": false }, { "name": "2.7", "branchName": "2.7", "slug": "2.7", "maintained": false }, { "name": "2.6", "branchName": "2.6", "slug": "2.6", "maintained": false }, { "name": "2.5", "branchName": "2.5", "slug": "2.5", "maintained": false } ] } php-doctrine-dbal-2.10.1/.github/000077500000000000000000000000001360544566000164405ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/.github/FUNDING.yml000066400000000000000000000001631360544566000202550ustar00rootroot00000000000000patreon: phpdoctrine tidelift: packagist/doctrine%2Fdbal custom: https://www.doctrine-project.org/sponsorship.html php-doctrine-dbal-2.10.1/.github/ISSUE_TEMPLATE/000077500000000000000000000000001360544566000206235ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/.github/ISSUE_TEMPLATE/BC_Break.md000066400000000000000000000017641360544566000225450ustar00rootroot00000000000000--- name: 💥 BC Break about: Have you encountered an issue during an upgrade? 💣 --- ### BC Break Report | Q | A |------------ | ------ | BC Break | yes | Version | x.y.z #### Summary #### Previous behaviour #### Current behavior #### How to reproduce php-doctrine-dbal-2.10.1/.github/ISSUE_TEMPLATE/Bug.md000066400000000000000000000014461360544566000216670ustar00rootroot00000000000000--- name: 🐞 Bug Report about: Something is broken? 🔨 --- ### Bug Report | Q | A |------------ | ------ | BC Break | yes/no | Version | x.y.z #### Summary #### Current behaviour #### How to reproduce #### Expected behaviour php-doctrine-dbal-2.10.1/.github/ISSUE_TEMPLATE/Feature_Request.md000066400000000000000000000006131360544566000242500ustar00rootroot00000000000000--- name: 🎉 Feature Request about: You have a neat idea that should be implemented? 🎩 --- ### Feature Request | Q | A |------------ | ------ | New Feature | yes | RFC | yes/no | BC Break | yes/no #### Summary php-doctrine-dbal-2.10.1/.github/ISSUE_TEMPLATE/Support_Question.md000066400000000000000000000010331360544566000245050ustar00rootroot00000000000000--- name: ❓ Support Question about: Have a problem that you can't figure out? 🤔 --- | Q | A |------------ | ----- | Version | x.y.z ### Support Question php-doctrine-dbal-2.10.1/.github/PULL_REQUEST_TEMPLATE.md000066400000000000000000000005001360544566000222340ustar00rootroot00000000000000 | Q | A |------------- | ----------- | Type | bug/feature/improvement | BC Break | yes/no | Fixed issues | #### Summary php-doctrine-dbal-2.10.1/.gitignore000066400000000000000000000001751360544566000170730ustar00rootroot00000000000000/.phpunit.result.cache build/ logs/ reports/ dist/ download/ vendor/ /*.phpunit.xml /phpunit.xml /.phpcs-cache /phpstan.neon php-doctrine-dbal-2.10.1/.scrutinizer.yml000066400000000000000000000021671360544566000202700ustar00rootroot00000000000000build: nodes: analysis: environment: php: version: 7.2 cache: disabled: false directories: - ~/.composer/cache project_setup: override: true tests: override: - php-scrutinizer-run before_commands: - "composer install --no-dev --prefer-source -a" tools: external_code_coverage: timeout: 3600 runs: 30 # 25x Travis (jobs with COVERAGE=yes) + 3x AppVeyor (jobs with coverage=yes) + 2x ContinuousPHP filter: excluded_paths: - docs build_failure_conditions: - 'elements.rating(<= C).new.exists' # No new classes/methods with a rating of C or worse allowed - 'issues.severity(>= MAJOR).new.exists' # New issues of major or higher severity - 'project.metric_change("scrutinizer.test_coverage", < 0)' # Code Coverage decreased from previous inspection - 'patches.label("Unused Use Statements").new.exists' # No new unused imports patches allowed php-doctrine-dbal-2.10.1/.travis.yml000066400000000000000000000214031360544566000172110ustar00rootroot00000000000000language: php sudo: false dist: trusty cache: directories: - vendor - $HOME/.composer/cache before_install: - phpenv config-rm xdebug.ini || true - | if [ "x$COVERAGE" == "xyes" ]; then pecl install pcov-1.0.0 fi before_script: - if [[ "$DB" == "mysql" || "$DB" == "mysqli" || "$DB" == *"mariadb"* ]]; then mysql < tests/travis/create-mysql-schema.sql; fi; install: - travis_retry composer -n install --prefer-dist script: - | if [ "x$COVERAGE" == "xyes" ]; then ./vendor/bin/phpunit --configuration tests/travis/$DB.travis.xml --coverage-clover clover.xml else ./vendor/bin/phpunit --configuration tests/travis/$DB.travis.xml fi after_script: - | if [ "x$COVERAGE" == "xyes" ]; then travis_retry wget https://github.com/scrutinizer-ci/ocular/releases/download/1.5.2/ocular.phar travis_retry php ocular.phar code-coverage:upload --format=php-clover clover.xml fi jobs: include: - stage: Smoke Testing php: 7.3 env: DB=sqlite COVERAGE=yes - stage: Smoke Testing php: 7.3 env: PHPStan install: travis_retry composer install --prefer-dist script: vendor/bin/phpstan analyse - stage: Smoke Testing php: 7.3 env: PHP_CodeSniffer install: travis_retry composer install --prefer-dist script: vendor/bin/phpcs - stage: Test php: 7.2 env: DB=mysql.docker MYSQL_VERSION=8.0 sudo: required services: - docker before_script: - bash ./tests/travis/install-mysql-8.0.sh - stage: Test php: 7.2 env: DB=mysqli.docker MYSQL_VERSION=8.0 sudo: required services: - docker before_script: - bash ./tests/travis/install-mysql-8.0.sh - stage: Test php: 7.2 env: DB=mariadb MARIADB_VERSION=10.3 addons: mariadb: 10.3 - stage: Test php: 7.2 env: DB=mariadb.mysqli MARIADB_VERSION=10.3 addons: mariadb: 10.3 - stage: Test php: 7.2 env: DB=pgsql POSTGRESQL_VERSION=11.0 sudo: required services: - docker before_script: - bash ./tests/travis/install-postgres-11.sh - stage: Test php: 7.2 env: DB=sqlite - stage: Test php: 7.2 env: DB=sqlsrv sudo: required services: - docker before_script: - bash ./tests/travis/install-sqlsrv-dependencies.sh - bash ./tests/travis/install-mssql-sqlsrv.sh - bash ./tests/travis/install-mssql.sh - stage: Test php: 7.2 env: DB=pdo_sqlsrv sudo: required services: - docker before_script: - bash ./tests/travis/install-sqlsrv-dependencies.sh - bash ./tests/travis/install-mssql-pdo_sqlsrv.sh - bash ./tests/travis/install-mssql.sh - stage: Test php: 7.3 env: DB=mysql COVERAGE=yes - stage: Test php: 7.3 env: DB=mysql.docker MYSQL_VERSION=5.7 COVERAGE=yes sudo: required before_script: - bash ./tests/travis/install-mysql-5.7.sh - stage: Test php: 7.3 env: DB=mysql.docker MYSQL_VERSION=8.0 COVERAGE=yes sudo: required services: - docker before_script: - bash ./tests/travis/install-mysql-8.0.sh - stage: Test php: 7.3 env: DB=mysqli COVERAGE=yes - stage: Test php: 7.3 env: DB=mysqli.docker MYSQL_VERSION=5.7 COVERAGE=yes sudo: required before_script: - bash ./tests/travis/install-mysql-5.7.sh - stage: Test php: 7.3 env: DB=mysqli.docker MYSQL_VERSION=8.0 COVERAGE=yes sudo: required services: - docker before_script: - bash ./tests/travis/install-mysql-8.0.sh - stage: Test php: 7.3 env: DB=mariadb MARIADB_VERSION=10.0 COVERAGE=yes addons: mariadb: 10.0 - stage: Test php: 7.3 env: DB=mariadb MARIADB_VERSION=10.1 COVERAGE=yes addons: mariadb: 10.1 - stage: Test php: 7.3 env: DB=mariadb MARIADB_VERSION=10.2 COVERAGE=yes addons: mariadb: 10.2 - stage: Test php: 7.3 env: DB=mariadb MARIADB_VERSION=10.3 COVERAGE=yes addons: mariadb: 10.3 - stage: Test php: 7.3 env: DB=mariadb.mysqli MARIADB_VERSION=10.0 COVERAGE=yes addons: mariadb: 10.0 - stage: Test php: 7.3 env: DB=mariadb.mysqli MARIADB_VERSION=10.1 COVERAGE=yes addons: mariadb: 10.1 - stage: Test php: 7.3 env: DB=mariadb.mysqli MARIADB_VERSION=10.2 COVERAGE=yes addons: mariadb: 10.2 - stage: Test php: 7.3 env: DB=mariadb.mysqli MARIADB_VERSION=10.3 COVERAGE=yes addons: mariadb: 10.3 - stage: Test php: 7.3 env: DB=pgsql POSTGRESQL_VERSION=9.2 COVERAGE=yes services: - postgresql addons: postgresql: "9.2" - stage: Test php: 7.3 env: DB=pgsql POSTGRESQL_VERSION=9.3 COVERAGE=yes services: - postgresql addons: postgresql: "9.3" - stage: Test php: 7.3 env: DB=pgsql POSTGRESQL_VERSION=9.4 COVERAGE=yes services: - postgresql addons: postgresql: "9.4" - stage: Test php: 7.3 env: DB=pgsql POSTGRESQL_VERSION=9.5 COVERAGE=yes services: - postgresql addons: postgresql: "9.5" - stage: Test php: 7.3 env: DB=pgsql POSTGRESQL_VERSION=9.6 COVERAGE=yes services: - postgresql addons: postgresql: "9.6" - stage: Test php: 7.3 env: DB=pgsql POSTGRESQL_VERSION=10.0 COVERAGE=yes sudo: required services: - postgresql addons: postgresql: "9.6" before_script: - bash ./tests/travis/install-postgres-10.sh - stage: Test php: 7.3 env: DB=pgsql POSTGRESQL_VERSION=11.0 COVERAGE=yes sudo: required services: - docker before_script: - bash ./tests/travis/install-postgres-11.sh - stage: Test php: 7.3 env: DB=sqlsrv COVERAGE=yes sudo: required services: - docker before_script: - bash ./tests/travis/install-sqlsrv-dependencies.sh - bash ./tests/travis/install-mssql-sqlsrv.sh - bash ./tests/travis/install-mssql.sh - stage: Test php: 7.3 env: DB=pdo_sqlsrv COVERAGE=yes sudo: required services: - docker before_script: - bash ./tests/travis/install-sqlsrv-dependencies.sh - bash ./tests/travis/install-mssql-pdo_sqlsrv.sh - bash ./tests/travis/install-mssql.sh - stage: Test php: 7.3 env: DB=ibm_db2 COVERAGE=yes sudo: required services: - docker before_script: - bash ./tests/travis/install-db2.sh - bash ./tests/travis/install-db2-ibm_db2.sh - stage: Test php: 7.3 env: DB=sqlite DEPENDENCIES=low install: - travis_retry composer update --prefer-dist --prefer-lowest - stage: Test php: 7.4snapshot env: DB=mysql.docker MYSQL_VERSION=8.0 sudo: required services: - docker before_script: - bash ./tests/travis/install-mysql-8.0.sh - stage: Test php: 7.4snapshot env: DB=mysqli.docker MYSQL_VERSION=8.0 sudo: required services: - docker before_script: - bash ./tests/travis/install-mysql-8.0.sh - stage: Test php: 7.4snapshot env: DB=mariadb MARIADB_VERSION=10.3 addons: mariadb: 10.3 - stage: Test php: 7.4snapshot env: DB=mariadb.mysqli MARIADB_VERSION=10.3 addons: mariadb: 10.3 - stage: Test php: 7.4snapshot env: DB=pgsql POSTGRESQL_VERSION=11.0 sudo: required services: - docker before_script: - bash ./tests/travis/install-postgres-11.sh - stage: Test php: 7.4snapshot env: DB=sqlite - stage: Test php: 7.4snapshot env: DB=sqlsrv sudo: required services: - docker before_script: - bash ./tests/travis/install-sqlsrv-dependencies.sh - bash ./tests/travis/install-mssql-sqlsrv.sh - bash ./tests/travis/install-mssql.sh - stage: Test php: 7.4snapshot env: DB=pdo_sqlsrv sudo: required services: - docker before_script: - bash ./tests/travis/install-sqlsrv-dependencies.sh - bash ./tests/travis/install-mssql-pdo_sqlsrv.sh - bash ./tests/travis/install-mssql.sh - stage: Test if: type = cron php: 7.2 env: DB=sqlite DEPENDENCIES=dev install: - composer config minimum-stability dev - travis_retry composer update --prefer-dist allow_failures: - env: DEPENDENCIES=dev php-doctrine-dbal-2.10.1/LICENSE000066400000000000000000000020511360544566000161030ustar00rootroot00000000000000Copyright (c) 2006-2018 Doctrine Project Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. php-doctrine-dbal-2.10.1/README.md000066400000000000000000000071201360544566000163570ustar00rootroot00000000000000# Doctrine DBAL | [Master][Master] | [2.9][2.9] | [Develop][develop] | |:----------------:|:----------:|:------------------:| | [![Build status][Master image]][Master] | [![Build status][2.9 image]][2.9] | [![Build status][develop image]][develop] | | [![Build Status][ContinuousPHP image]][ContinuousPHP] | [![Build Status][ContinuousPHP 2.9 image]][ContinuousPHP] | [![Build Status][ContinuousPHP develop image]][ContinuousPHP] | | [![Code Coverage][Coverage image]][Scrutinizer Master] | [![Code Coverage][Coverage 2.9 image]][Scrutinizer 2.9] | [![Code Coverage][Coverage develop image]][Scrutinizer develop] | | [![Code Quality][Quality image]][Scrutinizer Master] | [![Code Quality][Quality 2.9 image]][Scrutinizer 2.9] | [![Code Quality][Quality develop image]][Scrutinizer develop] | | [![AppVeyor][AppVeyor master image]][AppVeyor master] | [![AppVeyor][AppVeyor 2.9 image]][AppVeyor 2.9] | [![AppVeyor][AppVeyor develop image]][AppVeyor develop] | Powerful database abstraction layer with many features for database schema introspection, schema management and PDO abstraction. ## More resources: * [Website](http://www.doctrine-project.org/projects/dbal.html) * [Documentation](http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/) * [Issue Tracker](https://github.com/doctrine/dbal/issues) [Master image]: https://img.shields.io/travis/doctrine/dbal/master.svg?style=flat-square [Coverage image]: https://img.shields.io/scrutinizer/coverage/g/doctrine/dbal/master.svg?style=flat-square [Quality image]: https://img.shields.io/scrutinizer/g/doctrine/dbal/master.svg?style=flat-square [ContinuousPHP image]: https://img.shields.io/continuousphp/git-hub/doctrine/dbal/master.svg?style=flat-square [Master]: https://travis-ci.org/doctrine/dbal [Scrutinizer Master]: https://scrutinizer-ci.com/g/doctrine/dbal/ [AppVeyor master]: https://ci.appveyor.com/project/doctrine/dbal/branch/master [AppVeyor master image]: https://ci.appveyor.com/api/projects/status/i88kitq8qpbm0vie/branch/master?svg=true [ContinuousPHP]: https://continuousphp.com/git-hub/doctrine/dbal [2.9 image]: https://img.shields.io/travis/doctrine/dbal/2.9.svg?style=flat-square [Coverage 2.9 image]: https://img.shields.io/scrutinizer/coverage/g/doctrine/dbal/2.9.svg?style=flat-square [Quality 2.9 image]: https://img.shields.io/scrutinizer/g/doctrine/dbal/2.9.svg?style=flat-square [ContinuousPHP 2.9 image]: https://img.shields.io/continuousphp/git-hub/doctrine/dbal/2.9.svg?style=flat-square [2.9]: https://github.com/doctrine/dbal/tree/2.9 [Scrutinizer 2.9]: https://scrutinizer-ci.com/g/doctrine/dbal/?branch=2.9 [AppVeyor 2.9]: https://ci.appveyor.com/project/doctrine/dbal/branch/2.9 [AppVeyor 2.9 image]: https://ci.appveyor.com/api/projects/status/i88kitq8qpbm0vie/branch/2.9?svg=true [develop]: https://github.com/doctrine/dbal/tree/develop [develop image]: https://img.shields.io/travis/doctrine/dbal/develop.svg?style=flat-square [Coverage develop image]: https://img.shields.io/scrutinizer/coverage/g/doctrine/dbal/develop.svg?style=flat-square [Quality develop image]: https://img.shields.io/scrutinizer/g/doctrine/dbal/develop.svg?style=flat-square [ContinuousPHP develop image]: https://img.shields.io/continuousphp/git-hub/doctrine/dbal/develop.svg?style=flat-square [develop]: https://github.com/doctrine/dbal/tree/develop [Scrutinizer develop]: https://scrutinizer-ci.com/g/doctrine/dbal/?branch=develop [AppVeyor develop]: https://ci.appveyor.com/project/doctrine/dbal/branch/develop [AppVeyor develop image]: https://ci.appveyor.com/api/projects/status/i88kitq8qpbm0vie/branch/develop?svg=true php-doctrine-dbal-2.10.1/SECURITY.md000066400000000000000000000012031360544566000166650ustar00rootroot00000000000000Security ======== The Doctrine library is operating very close to your database and as such needs to handle and make assumptions about SQL injection vulnerabilities. It is vital that you understand how Doctrine approaches security, because we cannot protect you from SQL injection. Please read the documentation chapter on Security in Doctrine DBAL to understand the assumptions we make. - [Latest security.rst page on Github](https://github.com/doctrine/dbal/blob/master/docs/en/reference/security.rst) - [Security Page in rendered documentation](http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/security.html) php-doctrine-dbal-2.10.1/UPGRADE.md000066400000000000000000000505001360544566000165110ustar00rootroot00000000000000# Upgrade to 2.10 ## Deprecated `Doctrine\DBAL\Event\ConnectionEventArgs` methods The usage of the `getDriver()`, `getDatabasePlatform()` and `getSchemaManager()` methods of the `ConnectionEventArgs` class has been deprecated. Obtain the underlying connection via `getConnection()` and call the corresponding methods on the connection instance. ## Deprecated `Doctrine\DBAL\Event\SchemaColumnDefinitionEventArgs` methods The usage of the `getDatabasePlatform()` method of the `SchemaColumnDefinitionEventArgs` class has been deprecated. Obtain the underlying connection via `getConnection()` and call the corresponding method on the connection instance. ## Deprecated `Doctrine\DBAL\Connection` methods The usage of the `getHost()`, `getPort()`, `getUsername()` and `getPassword()` methods of the `Connection` class has been deprecated as they leak implementation details. ## Deprecated array of statements in `addSql()` of `SchemaEventArgs`-based classes. Passing multiple SQL statements as an array to `SchemaAlterTableAddColumnEventArgs::addSql()` and the same method in other `SchemaEventArgs`-based classes is deprecated. Pass each statement as an individual argument instead. ## Deprecated calling `AbstractSchemaManager::tablesExist()` with a string argument. Instead of passing a string, pass a one-element array. ## Deprecated calling `OracleSchemaManager::createDatabase()` without an argument or by passing NULL. In order to create a database, always pass the database name. ## Deprecated unused schema manager methods. The following methods have been deprecated as unused: - `AbstractSchemaManager::_getPortableFunctionsList()`, - `AbstractSchemaManager::_getPortableFunctionDefinition()`, - `OracleSchemaManager::_getPortableFunctionDefinition()`, - `SqliteSchemaManager::_getPortableTableIndexDefinition()`. # Deprecations in `Doctrine\DBAL\Driver` - The usage of NULL to indicate empty `$username` or `$password` when calling `connect()` is deprecated. Use an empty string instead. ## Deprecated `Doctrine\DBAL\Platforms::_getAlterTableIndexForeignKeySQL()` Method `Doctrine\DBAL\Platforms::_getAlterTableIndexForeignKeySQL()` has been deprecated as no longer used. ## Deprecated `Doctrine\DBAL\Driver\OCI8\OCI8Statement::$_PARAM` Property `Doctrine\DBAL\Driver\OCI8\OCI8Statement::$_PARAM` has been deprecated as not used. ## Deprecated `Doctrine\DBAL\Driver::getName()` Relying on the name of the driver is discouraged. For referencing the driver, use its class name. ## Deprecated usage of user-provided `PDO` instance The usage of user-provided `PDO` instance is deprecated. The known use cases are: 1. **Persistent PDO connections.** DBAL 3.0 will supported establishing persistent connections, therefore, providing a pre-created persistent PDO connection will be no longer needed. 2. **Sharing `PDO` instance between DBAL and legacy components.** In order to share a PDO instance, initialize the connection in DBAL and access it using `Connection::getWrappedConnection()->getWrappedConnection()`. ## MINOR BC BREAK: Default values are no longer handled as SQL expressions They are converted to SQL literals (e.g. escaped). Clients must now specify default values in their initial form, not in the form of an SQL literal (e.g. escaped). Before: $column->setDefault('Foo\\\\Bar\\\\Baz'); After: $column->setDefault('Foo\\Bar\\Baz'); ## Deprecated `Type::*` constants The constants for built-in types have been moved from `Doctrine\DBAL\Types\Type` to a separate class `Doctrine\DBAL\Types\Types`. Some of the constants were renamed in the process: * `TARRAY`-> `ARRAY` * `DATE` -> `DATE_MUTABLE` * `DATETIME` -> `DATETIME_MUTABLE` * `DATETIMETZ` -> `DATETIMETZ_MUTABLE` * `TIME` -> `TIME_MUTABLE` ## Deprecated `SQLSrvStatement::LAST_INSERT_ID_SQL` constant The `Doctrine\DBAL\Driver\SQLSrv\SQLSrvStatement::LAST_INSERT_ID_SQL` constant has been deprecated and will be made private in 3.0. ## Deprecated `SQLParserUtils` constants The constants in `Doctrine\DBAL\SQLParserUtils` have been deprecated and will be made private in 3.0. ## Deprecated `LoggerChain::addLogger` method The `Doctrine\DBAL\Logging\LoggerChain::addLogger` method has been deprecated. Inject list of loggers via constructor instead. # Upgrade to 2.9 ## Deprecated `Statement::fetchColumn()` with an invalid index Calls to `Statement::fetchColumn()` with an invalid column index currently return `NULL`. In the future, such calls will result in a exception. ## Deprecated `Configuration::getFilterSchemaAssetsExpression()`, `::setFilterSchemaAssetsExpression()` and `AbstractSchemaManager::getFilterSchemaAssetsExpression()`. Regular expression-based filters are hard to extend by combining together. Instead, you may use callback-based filers via `::getSchemaAssetsFilter()` and `::getSchemaAssetsFilter()`. Callbacks can use regular expressions internally. ## Deprecated `Doctrine\DBAL\Types\Type::getDefaultLength()` This method was never used by DBAL internally. It is now deprecated and will be removed in DBAL 3.0. ## Deprecated `Doctrine\DBAL\Types\Type::__toString()` Relying on string representation is discouraged and will be removed in DBAL 3.0. ## Deprecated `NULL` value of `$offset` in LIMIT queries The `NULL` value of the `$offset` argument in `AbstractPlatform::(do)?ModifyLimitQuery()` methods is deprecated. If explicitly used in the method call, the absence of the offset should be indicated with a `0`. ## Deprecated dbal:import CLI command The `dbal:import` CLI command has been deprecated since it only works with PDO-based drivers by relying on a non-documented behavior of the extension, and it's impossible to make it work with other drivers. Please use other database client applications for import, e.g.: * For MySQL and MariaDB: `mysql [dbname] < data.sql`. * For PostgreSQL: `psql [dbname] < data.sql`. * For SQLite: `sqlite3 /path/to/file.db < data.sql`. # Upgrade to 2.8 ## Deprecated usage of DB-generated UUIDs The format of DB-generated UUIDs is inconsistent across supported platforms and therefore is not portable. Some of the platforms produce UUIDv1, some produce UUIDv4, some produce the values which are not even UUID. Unless UUIDs are used in stored procedures which DBAL doesn't support, there's no real benefit of DB-generated UUIDs comparing to the application-generated ones. Use a PHP library (e.g. [ramsey/uuid](https://packagist.org/packages/ramsey/uuid)) to generate UUIDs on the application side. ## Deprecated usage of binary fields whose length exceeds the platform maximum - The usage of binary fields whose length exceeds the maximum field size on a given platform is deprecated. Use binary fields of a size which fits all target platforms, or use blob explicitly instead. ## Removed dependency on doctrine/common The dependency on doctrine/common package has been removed. DBAL now depends on doctrine/cache and doctrine/event-manager instead. If you are using any other component from doctrine/common package, you will have to add an explicit dependency to your composer.json. ## Corrected exception thrown by ``Doctrine\DBAL\Platforms\SQLAnywhere16Platform::getAdvancedIndexOptionsSQL()`` This method now throws SPL ``UnexpectedValueException`` instead of accidentally throwing ``Doctrine\Common\Proxy\Exception\UnexpectedValueException``. # Upgrade to 2.7 ## Doctrine\DBAL\Platforms\AbstractPlatform::DATE_INTERVAL_UNIT_* constants deprecated ``Doctrine\DBAL\Platforms\AbstractPlatform::DATE_INTERVAL_UNIT_*`` constants were moved into ``Doctrine\DBAL\Platforms\DateIntervalUnit`` class without the ``DATE_INTERVAL_UNIT_`` prefix. ## Doctrine\DBAL\Platforms\AbstractPlatform::TRIM_* constants deprecated ``Doctrine\DBAL\Platforms\AbstractPlatform::TRIM_*`` constants were moved into ``Doctrine\DBAL\Platforms\TrimMode`` class without the ``TRIM_`` prefix. ## Doctrine\DBAL\Connection::TRANSACTION_* constants deprecated ``Doctrine\DBAL\Connection::TRANSACTION_*`` were moved into ``Doctrine\DBAL\TransactionIsolationLevel`` class without the ``TRANSACTION_`` prefix. ## DEPRECATION: direct usage of the PDO APIs in the DBAL API 1. When calling `Doctrine\DBAL\Driver\Statement` methods, instead of `PDO::PARAM_*` constants, `Doctrine\DBAL\ParameterType` constants should be used. 2. When calling `Doctrine\DBAL\Driver\ResultStatement` methods, instead of `PDO::FETCH_*` constants, `Doctrine\DBAL\FetchMode` constants should be used. 3. When configuring `Doctrine\DBAL\Portability\Connection`, instead of `PDO::CASE_*` constants, `Doctrine\DBAL\ColumnCase` constants should be used. 4. Usage of `PDO::PARAM_INPUT_OUTPUT` in `Doctrine\DBAL\Driver\Statement::bindValue()` is deprecated. 5. Usage of `PDO::FETCH_FUNC` in `Doctrine\DBAL\Driver\ResultStatement::fetch()` is deprecated. 6. Calls to `\PDOStatement` methods on a `\Doctrine\DBAL\Driver\PDOStatement` instance (e.g. `fetchObject()`) are deprecated. # Upgrade to 2.6 ## MINOR BC BREAK: `fetch()` and `fetchAll()` method signatures in `Doctrine\DBAL\Driver\ResultStatement` 1. ``Doctrine\DBAL\Driver\ResultStatement::fetch()`` now has 3 arguments instead of 1, respecting ``PDO::fetch()`` signature. Before: Doctrine\DBAL\Driver\ResultStatement::fetch($fetchMode); After: Doctrine\DBAL\Driver\ResultStatement::fetch($fetchMode, $cursorOrientation, $cursorOffset); 2. ``Doctrine\DBAL\Driver\ResultStatement::fetchAll()`` now has 3 arguments instead of 1, respecting ``PDO::fetchAll()`` signature. Before: Doctrine\DBAL\Driver\ResultStatement::fetchAll($fetchMode); After: Doctrine\DBAL\Driver\ResultStatement::fetch($fetchMode, $fetchArgument, $ctorArgs); ## MINOR BC BREAK: URL-style DSN with percentage sign in password URL-style DSNs (e.g. ``mysql://foo@bar:localhost/db``) are now assumed to be percent-encoded in order to allow certain special characters in usernames, paswords and database names. If you are using a URL-style DSN and have a username, password or database name containing a percentage sign, you need to update your DSN. If your password is, say, ``foo%foo``, it should be encoded as ``foo%25foo``. # Upgrade to 2.5.1 ## MINOR BC BREAK: Doctrine\DBAL\Schema\Table When adding indexes to ``Doctrine\DBAL\Schema\Table`` via ``addIndex()`` or ``addUniqueIndex()``, duplicate indexes are not silently ignored/dropped anymore (based on semantics, not naming!). Duplicate indexes are considered indexes that pass ``isFullfilledBy()`` or ``overrules()`` in ``Doctrine\DBAL\Schema\Index``. This is required to make the index renaming feature introduced in 2.5.0 work properly and avoid issues in the ORM schema tool / DBAL schema manager which pretends users from updating their schemas and migrate to DBAL 2.5.*. Additionally it offers more flexibility in declaring indexes for the user and potentially fixes related issues in the ORM. With this change, the responsibility to decide which index is a "duplicate" is completely deferred to the user. Please also note that adding foreign key constraints to a table via ``addForeignKeyConstraint()``, ``addUnnamedForeignKeyConstraint()`` or ``addNamedForeignKeyConstraint()`` now first checks if an appropriate index is already present and avoids adding an additional auto-generated one eventually. # Upgrade to 2.5 ## BC BREAK: time type resets date fields to UNIX epoch When mapping `time` type field to PHP's `DateTime` instance all unused date fields are reset to UNIX epoch (i.e. 1970-01-01). This might break any logic which relies on comparing `DateTime` instances with date fields set to the current date. Use `!` format prefix (see http://php.net/manual/en/datetime.createfromformat.php) for parsing time strings to prevent having different date fields when comparing user input and `DateTime` instances as mapped by Doctrine. ## BC BREAK: Doctrine\DBAL\Schema\Table The methods ``addIndex()`` and ``addUniqueIndex()`` in ``Doctrine\DBAL\Schema\Table`` have an additional, optional parameter. If you override these methods, you should add this new parameter to the declaration of your overridden methods. ## BC BREAK: Doctrine\DBAL\Connection The visibility of the property ``$_platform`` in ``Doctrine\DBAL\Connection`` was changed from protected to private. If you have subclassed ``Doctrine\DBAL\Connection`` in your application and accessed ``$_platform`` directly, you have to change the code portions to use ``getDatabasePlatform()`` instead to retrieve the underlying database platform. The reason for this change is the new automatic platform version detection feature, which lazily evaluates the appropriate platform class to use for the underlying database server version at runtime. Please also note, that calling ``getDatabasePlatform()`` now needs to establish a connection in order to evaluate the appropriate platform class if ``Doctrine\DBAL\Connection`` is not already connected. Under the following circumstances, it is not possible anymore to retrieve the platform instance from the connection object without having to do a real connect: 1. ``Doctrine\DBAL\Connection`` was instantiated without the ``platform`` connection parameter. 2. ``Doctrine\DBAL\Connection`` was instantiated without the ``serverVersion`` connection parameter. 3. The underlying driver is "version aware" and can provide different platform instances for different versions. 4. The underlying driver connection is "version aware" and can provide the database server version without having to query for it. If one of the above conditions is NOT met, there is no need for ``Doctrine\DBAL\Connection`` to do a connect when calling ``getDatabasePlatform()``. ## datetime Type uses date_create() as fallback Before 2.5 the DateTime type always required a specific format, defined in `$platform->getDateTimeFormatString()`, which could cause quite some troubles on platforms that had various microtime precision formats. Starting with 2.5 whenever the parsing of a date fails with the predefined platform format, the `date_create()` function will be used to parse the date. This could cause some troubles when your date format is weird and not parsed correctly by `date_create`, however since databases are rather strict on dates there should be no problem. ## Support for pdo_ibm driver removed The ``pdo_ibm`` driver is buggy and does not work well with Doctrine. Therefore it will no longer be supported and has been removed from the ``Doctrine\DBAL\DriverManager`` drivers map. It is highly encouraged to to use `ibm_db2` driver instead if you want to connect to an IBM DB2 database as it is much more stable and secure. If for some reason you have to utilize the ``pdo_ibm`` driver you can still use the `driverClass` connection parameter to explicitly specify the ``Doctrine\DBAL\Driver\PDOIbm\Driver`` class. However be aware that you are doing this at your own risk and it will not be guaranteed that Doctrine will work as expected. # Upgrade to 2.4 ## Doctrine\DBAL\Schema\Constraint If you have custom classes that implement the constraint interface, you have to implement an additional method ``getQuotedColumns`` now. This method is used to build proper constraint SQL for columns that need to be quoted, like keywords reserved by the specific platform used. The method has to return the same values as ``getColumns`` only that those column names that need quotation have to be returned quoted for the given platform. # Upgrade to 2.3 ## Oracle Session Init now sets Numeric Character Before 2.3 the Oracle Session Init did not care about the numeric character of the Session. This could lead to problems on non english locale systems that required a comma as a floating point seperator in Oracle. Since 2.3, using the Oracle Session Init on connection start the client session will be altered to set the numeric character to ".,": ALTER SESSION SET NLS_NUMERIC_CHARACTERS = '.,' See [DBAL-345](http://www.doctrine-project.org/jira/browse/DBAL-345) for more details. ## Doctrine\DBAL\Connection and Doctrine\DBAL\Statement The query related methods including but not limited to executeQuery, exec, query, and executeUpdate now wrap the driver exceptions such as PDOException with DBALException to add more debugging information such as the executed SQL statement, and any bound parameters. If you want to retrieve the driver specific exception, you can retrieve it by calling the ``getPrevious()`` method on DBALException. Before: catch(\PDOException $ex) { // ... } After: catch(\Doctrine\DBAL\DBALException $ex) { $pdoException = $ex->getPrevious(); // ... } ## Doctrine\DBAL\Connection#setCharsetSQL() removed This method only worked on MySQL and it is considered unsafe on MySQL to use SET NAMES UTF-8 instead of setting the charset directly on connection already. Replace this behavior with the connection charset option: Before: $conn = DriverManager::getConnection(array(..)); $conn->setCharset('UTF8'); After: $conn = DriverManager::getConnection(array('charset' => 'UTF8', ..)); ## Doctrine\DBAL\Schema\Table#renameColumn() removed Doctrine\DBAL\Schema\Table#renameColumn() was removed, because it drops and recreates the column instead. There is no fix available, because a schema diff cannot reliably detect if a column was renamed or one column was created and another one dropped. You should use explicit SQL ALTER TABLE statements to change columns names. ## Schema Filter paths The Filter Schema assets expression is not wrapped in () anymore for the regexp automatically. Before: $config->setFilterSchemaAssetsExpression('foo'); After: $config->setFilterSchemaAssetsExpression('(foo)'); ## Creating MySQL Tables now defaults to UTF-8 If you are creating a new MySQL Table through the Doctrine API, charset/collate are now set to 'utf8'/'utf8_unicode_ci' by default. Previously the MySQL server defaults were used. # Upgrade to 2.2 ## Doctrine\DBAL\Connection#insert and Doctrine\DBAL\Connection#update Both methods now accept an optional last parameter $types with binding types of the values passed. This can potentially break child classes that have overwritten one of these methods. ## Doctrine\DBAL\Connection#executeQuery Doctrine\DBAL\Connection#executeQuery() got a new last parameter "QueryCacheProfile $qcp" ## Doctrine\DBAL\Driver\Statement split The Driver statement was split into a ResultStatement and the normal statement extending from it. This separates the configuration and the retrieval API from a statement. ## MsSql Platform/SchemaManager renamed The MsSqlPlatform was renamed to SQLServerPlatform, the MsSqlSchemaManager was renamed to SQLServerSchemaManager. ## Cleanup SQLServer Platform version mess DBAL 2.1 and before were actually only compatible to SQL Server 2008, not earlier versions. Still other parts of the platform did use old features instead of newly introduced datatypes in SQL Server 2005. Starting with DBAL 2.2 you can pick the Doctrine abstraction exactly matching your SQL Server version. The PDO SqlSrv driver now uses the new `SQLServer2008Platform` as default platform. This platform uses new features of SQL Server as of version 2008. This also includes a switch in the used fields for "text" and "blob" field types to: "text" => "VARCHAR(MAX)" "blob" => "VARBINARY(MAX)" Additionally `SQLServerPlatform` in DBAL 2.1 and before used "DATE", "TIME" and "DATETIME2" for dates. This types are only available since version 2008 and the introduction of an explicit SQLServer 2008 platform makes this dependency explicit. An `SQLServer2005Platform` was also introduced to differentiate the features between versions 2003, earlier and 2005. With this change the `SQLServerPlatform` now throws an exception for using limit queries with an offset, since SQLServer 2003 and lower do not support this feature. To use the old SQL Server Platform, because you are using SQL Server 2003 and below use the following configuration code: use Doctrine\DBAL\DriverManager; use Doctrine\DBAL\Platforms\SQLServerPlatform; use Doctrine\DBAL\Platforms\SQLServer2005Platform; // You are using SQL Server 2003 or earlier $conn = DriverManager::getConnection(array( 'driver' => 'pdo_sqlsrv', 'platform' => new SQLServerPlatform() // .. additional parameters )); // You are using SQL Server 2005 $conn = DriverManager::getConnection(array( 'driver' => 'pdo_sqlsrv', 'platform' => new SQLServer2005Platform() // .. additional parameters )); // You are using SQL Server 2008 $conn = DriverManager::getConnection(array( 'driver' => 'pdo_sqlsrv', // 2008 is default platform // .. additional parameters )); php-doctrine-dbal-2.10.1/bin/000077500000000000000000000000001360544566000156505ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/bin/doctrine-dbal000077500000000000000000000001021360544566000202760ustar00rootroot00000000000000#!/usr/bin/env php 2.2,<2.4" }, "require-dev": { "alcaeus/mongo-php-adapter": "^1.1", "mongodb/mongodb": "^1.1", "phpunit/phpunit": "^5.7", "predis/predis": "~1.0" }, "suggest": { "alcaeus/mongo-php-adapter": "Required to use legacy MongoDB driver" }, "type": "library", "extra": { "branch-alias": { "dev-master": "1.7.x-dev" } }, "autoload": { "psr-4": { "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Roman Borschel", "email": "roman@code-factory.org" }, { "name": "Benjamin Eberlei", "email": "kontakt@beberlei.de" }, { "name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com" }, { "name": "Jonathan Wage", "email": "jonwage@gmail.com" }, { "name": "Johannes Schmitt", "email": "schmittjoh@gmail.com" } ], "description": "Caching library offering an object-oriented API for many cache backends", "homepage": "http://www.doctrine-project.org", "keywords": [ "cache", "caching" ], "time": "2017-08-25T07:02:50+00:00" }, { "name": "doctrine/event-manager", "version": "v1.0.0", "source": { "type": "git", "url": "https://github.com/doctrine/event-manager.git", "reference": "a520bc093a0170feeb6b14e9d83f3a14452e64b3" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/doctrine/event-manager/zipball/a520bc093a0170feeb6b14e9d83f3a14452e64b3", "reference": "a520bc093a0170feeb6b14e9d83f3a14452e64b3", "shasum": "" }, "require": { "php": "^7.1" }, "conflict": { "doctrine/common": "<2.9@dev" }, "require-dev": { "doctrine/coding-standard": "^4.0", "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { "dev-master": "1.0.x-dev" } }, "autoload": { "psr-4": { "Doctrine\\Common\\": "lib/Doctrine/Common" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Roman Borschel", "email": "roman@code-factory.org" }, { "name": "Benjamin Eberlei", "email": "kontakt@beberlei.de" }, { "name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com" }, { "name": "Jonathan Wage", "email": "jonwage@gmail.com" }, { "name": "Johannes Schmitt", "email": "schmittjoh@gmail.com" }, { "name": "Marco Pivetta", "email": "ocramius@gmail.com" } ], "description": "Doctrine Event Manager component", "homepage": "https://www.doctrine-project.org/projects/event-manager.html", "keywords": [ "event", "eventdispatcher", "eventmanager" ], "time": "2018-06-11T11:59:03+00:00" } ], "packages-dev": [ { "name": "composer/xdebug-handler", "version": "1.3.3", "source": { "type": "git", "url": "https://github.com/composer/xdebug-handler.git", "reference": "46867cbf8ca9fb8d60c506895449eb799db1184f" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/46867cbf8ca9fb8d60c506895449eb799db1184f", "reference": "46867cbf8ca9fb8d60c506895449eb799db1184f", "shasum": "" }, "require": { "php": "^5.3.2 || ^7.0", "psr/log": "^1.0" }, "require-dev": { "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5" }, "type": "library", "autoload": { "psr-4": { "Composer\\XdebugHandler\\": "src" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "John Stevenson", "email": "john-stevenson@blueyonder.co.uk" } ], "description": "Restarts a process without xdebug.", "keywords": [ "Xdebug", "performance" ], "time": "2019-05-27T17:52:04+00:00" }, { "name": "dealerdirect/phpcodesniffer-composer-installer", "version": "v0.5.0", "source": { "type": "git", "url": "https://github.com/Dealerdirect/phpcodesniffer-composer-installer.git", "reference": "e749410375ff6fb7a040a68878c656c2e610b132" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/Dealerdirect/phpcodesniffer-composer-installer/zipball/e749410375ff6fb7a040a68878c656c2e610b132", "reference": "e749410375ff6fb7a040a68878c656c2e610b132", "shasum": "" }, "require": { "composer-plugin-api": "^1.0", "php": "^5.3|^7", "squizlabs/php_codesniffer": "^2|^3" }, "require-dev": { "composer/composer": "*", "phpcompatibility/php-compatibility": "^9.0", "sensiolabs/security-checker": "^4.1.0" }, "type": "composer-plugin", "extra": { "class": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" }, "autoload": { "psr-4": { "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Franck Nijhof", "email": "franck.nijhof@dealerdirect.com", "homepage": "http://www.frenck.nl", "role": "Developer / IT Manager" } ], "description": "PHP_CodeSniffer Standards Composer Installer Plugin", "homepage": "http://www.dealerdirect.com", "keywords": [ "PHPCodeSniffer", "PHP_CodeSniffer", "code quality", "codesniffer", "composer", "installer", "phpcs", "plugin", "qa", "quality", "standard", "standards", "style guide", "stylecheck", "tests" ], "time": "2018-10-26T13:21:45+00:00" }, { "name": "doctrine/coding-standard", "version": "6.0.0", "source": { "type": "git", "url": "https://github.com/doctrine/coding-standard.git", "reference": "d33f69eb98b25aa51ffe3a909f0ec77000af4701" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/doctrine/coding-standard/zipball/d33f69eb98b25aa51ffe3a909f0ec77000af4701", "reference": "d33f69eb98b25aa51ffe3a909f0ec77000af4701", "shasum": "" }, "require": { "dealerdirect/phpcodesniffer-composer-installer": "^0.5.0", "php": "^7.1", "slevomat/coding-standard": "^5.0", "squizlabs/php_codesniffer": "^3.4.0" }, "type": "phpcodesniffer-standard", "extra": { "branch-alias": { "dev-master": "6.0.x-dev" } }, "autoload": { "psr-4": { "Doctrine\\Sniffs\\": "lib/Doctrine/Sniffs" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Benjamin Eberlei", "email": "kontakt@beberlei.de" }, { "name": "Steve Müller", "email": "st.mueller@dzh-online.de" } ], "description": "The Doctrine Coding Standard is a set of PHPCS rules applied to all Doctrine projects.", "homepage": "https://www.doctrine-project.org/projects/coding-standard.html", "keywords": [ "checks", "code", "coding", "cs", "doctrine", "rules", "sniffer", "sniffs", "standard", "style" ], "time": "2019-03-15T12:45:47+00:00" }, { "name": "doctrine/instantiator", "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", "reference": "a2c590166b2133a4633738648b6b064edae0814a" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/doctrine/instantiator/zipball/a2c590166b2133a4633738648b6b064edae0814a", "reference": "a2c590166b2133a4633738648b6b064edae0814a", "shasum": "" }, "require": { "php": "^7.1" }, "require-dev": { "doctrine/coding-standard": "^6.0", "ext-pdo": "*", "ext-phar": "*", "phpbench/phpbench": "^0.13", "phpstan/phpstan-phpunit": "^0.11", "phpstan/phpstan-shim": "^0.11", "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { "dev-master": "1.2.x-dev" } }, "autoload": { "psr-4": { "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Marco Pivetta", "email": "ocramius@gmail.com", "homepage": "http://ocramius.github.com/" } ], "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", "homepage": "https://www.doctrine-project.org/projects/instantiator.html", "keywords": [ "constructor", "instantiate" ], "time": "2019-03-17T17:37:11+00:00" }, { "name": "jean85/pretty-package-versions", "version": "1.2", "source": { "type": "git", "url": "https://github.com/Jean85/pretty-package-versions.git", "reference": "75c7effcf3f77501d0e0caa75111aff4daa0dd48" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/75c7effcf3f77501d0e0caa75111aff4daa0dd48", "reference": "75c7effcf3f77501d0e0caa75111aff4daa0dd48", "shasum": "" }, "require": { "ocramius/package-versions": "^1.2.0", "php": "^7.0" }, "require-dev": { "phpunit/phpunit": "^6.0" }, "type": "library", "extra": { "branch-alias": { "dev-master": "1.x-dev" } }, "autoload": { "psr-4": { "Jean85\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Alessandro Lai", "email": "alessandro.lai85@gmail.com" } ], "description": "A wrapper for ocramius/package-versions to get pretty versions strings", "keywords": [ "composer", "package", "release", "versions" ], "time": "2018-06-13T13:22:40+00:00" }, { "name": "jetbrains/phpstorm-stubs", "version": "v2019.1", "source": { "type": "git", "url": "https://github.com/JetBrains/phpstorm-stubs.git", "reference": "9e309771f362e979ecfb429303ad7a402c657234" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/JetBrains/phpstorm-stubs/zipball/9e309771f362e979ecfb429303ad7a402c657234", "reference": "9e309771f362e979ecfb429303ad7a402c657234", "shasum": "" }, "require-dev": { "nikic/php-parser": "v4.0.1", "php": "^7.1", "phpdocumentor/reflection-docblock": "^4.3", "phpunit/phpunit": "7.1.4" }, "type": "library", "notification-url": "https://packagist.org/downloads/", "license": [ "Apache-2.0" ], "description": "PHP runtime & extensions header files for PhpStorm", "homepage": "https://www.jetbrains.com/phpstorm", "keywords": [ "autocomplete", "code", "inference", "inspection", "jetbrains", "phpstorm", "stubs", "type" ], "time": "2019-03-25T16:59:23+00:00" }, { "name": "myclabs/deep-copy", "version": "1.9.3", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", "reference": "007c053ae6f31bba39dfa19a7726f56e9763bbea" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/007c053ae6f31bba39dfa19a7726f56e9763bbea", "reference": "007c053ae6f31bba39dfa19a7726f56e9763bbea", "shasum": "" }, "require": { "php": "^7.1" }, "replace": { "myclabs/deep-copy": "self.version" }, "require-dev": { "doctrine/collections": "^1.0", "doctrine/common": "^2.6", "phpunit/phpunit": "^7.1" }, "type": "library", "autoload": { "psr-4": { "DeepCopy\\": "src/DeepCopy/" }, "files": [ "src/DeepCopy/deep_copy.php" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "description": "Create deep copies (clones) of your objects", "keywords": [ "clone", "copy", "duplicate", "object", "object graph" ], "time": "2019-08-09T12:45:53+00:00" }, { "name": "nette/bootstrap", "version": "v3.0.0", "source": { "type": "git", "url": "https://github.com/nette/bootstrap.git", "reference": "e1075af05c211915e03e0c86542f3ba5433df4a3" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/nette/bootstrap/zipball/e1075af05c211915e03e0c86542f3ba5433df4a3", "reference": "e1075af05c211915e03e0c86542f3ba5433df4a3", "shasum": "" }, "require": { "nette/di": "^3.0", "nette/utils": "^3.0", "php": ">=7.1" }, "require-dev": { "latte/latte": "^2.2", "nette/application": "^3.0", "nette/caching": "^3.0", "nette/database": "^3.0", "nette/forms": "^3.0", "nette/http": "^3.0", "nette/mail": "^3.0", "nette/robot-loader": "^3.0", "nette/safe-stream": "^2.2", "nette/security": "^3.0", "nette/tester": "^2.0", "tracy/tracy": "^2.6" }, "suggest": { "nette/robot-loader": "to use Configurator::createRobotLoader()", "tracy/tracy": "to use Configurator::enableTracy()" }, "type": "library", "extra": { "branch-alias": { "dev-master": "3.0-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause", "GPL-2.0", "GPL-3.0" ], "authors": [ { "name": "David Grudl", "homepage": "https://davidgrudl.com" }, { "name": "Nette Community", "homepage": "https://nette.org/contributors" } ], "description": "🅱 Nette Bootstrap: the simple way to configure and bootstrap your Nette application.", "homepage": "https://nette.org", "keywords": [ "bootstrapping", "configurator", "nette" ], "time": "2019-03-26T12:59:07+00:00" }, { "name": "nette/di", "version": "v3.0.1", "source": { "type": "git", "url": "https://github.com/nette/di.git", "reference": "4aff517a1c6bb5c36fa09733d4cea089f529de6d" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/nette/di/zipball/4aff517a1c6bb5c36fa09733d4cea089f529de6d", "reference": "4aff517a1c6bb5c36fa09733d4cea089f529de6d", "shasum": "" }, "require": { "ext-tokenizer": "*", "nette/neon": "^3.0", "nette/php-generator": "^3.2.2", "nette/robot-loader": "^3.2", "nette/schema": "^1.0", "nette/utils": "^3.0", "php": ">=7.1" }, "conflict": { "nette/bootstrap": "<3.0" }, "require-dev": { "nette/tester": "^2.2", "tracy/tracy": "^2.3" }, "type": "library", "extra": { "branch-alias": { "dev-master": "3.0-dev" } }, "autoload": { "classmap": [ "src/" ], "files": [ "src/compatibility.php" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause", "GPL-2.0", "GPL-3.0" ], "authors": [ { "name": "David Grudl", "homepage": "https://davidgrudl.com" }, { "name": "Nette Community", "homepage": "https://nette.org/contributors" } ], "description": "💎 Nette Dependency Injection Container: Flexible, compiled and full-featured DIC with perfectly usable autowiring and support for all new PHP 7.1 features.", "homepage": "https://nette.org", "keywords": [ "compiled", "di", "dic", "factory", "ioc", "nette", "static" ], "time": "2019-08-07T12:11:33+00:00" }, { "name": "nette/finder", "version": "v2.5.0", "source": { "type": "git", "url": "https://github.com/nette/finder.git", "reference": "6be1b83ea68ac558aff189d640abe242e0306fe2" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/nette/finder/zipball/6be1b83ea68ac558aff189d640abe242e0306fe2", "reference": "6be1b83ea68ac558aff189d640abe242e0306fe2", "shasum": "" }, "require": { "nette/utils": "^2.4 || ~3.0.0", "php": ">=7.1" }, "conflict": { "nette/nette": "<2.2" }, "require-dev": { "nette/tester": "^2.0", "tracy/tracy": "^2.3" }, "type": "library", "extra": { "branch-alias": { "dev-master": "2.5-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause", "GPL-2.0", "GPL-3.0" ], "authors": [ { "name": "David Grudl", "homepage": "https://davidgrudl.com" }, { "name": "Nette Community", "homepage": "https://nette.org/contributors" } ], "description": "🔍 Nette Finder: find files and directories with an intuitive API.", "homepage": "https://nette.org", "keywords": [ "filesystem", "glob", "iterator", "nette" ], "time": "2019-02-28T18:13:25+00:00" }, { "name": "nette/neon", "version": "v3.0.0", "source": { "type": "git", "url": "https://github.com/nette/neon.git", "reference": "cbff32059cbdd8720deccf9e9eace6ee516f02eb" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/nette/neon/zipball/cbff32059cbdd8720deccf9e9eace6ee516f02eb", "reference": "cbff32059cbdd8720deccf9e9eace6ee516f02eb", "shasum": "" }, "require": { "ext-iconv": "*", "ext-json": "*", "php": ">=7.0" }, "require-dev": { "nette/tester": "^2.0", "tracy/tracy": "^2.3" }, "type": "library", "extra": { "branch-alias": { "dev-master": "3.0-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause", "GPL-2.0", "GPL-3.0" ], "authors": [ { "name": "David Grudl", "homepage": "https://davidgrudl.com" }, { "name": "Nette Community", "homepage": "https://nette.org/contributors" } ], "description": "🍸 Nette NEON: encodes and decodes NEON file format.", "homepage": "http://ne-on.org", "keywords": [ "export", "import", "neon", "nette", "yaml" ], "time": "2019-02-05T21:30:40+00:00" }, { "name": "nette/php-generator", "version": "v3.2.3", "source": { "type": "git", "url": "https://github.com/nette/php-generator.git", "reference": "aea6e81437bb238e5f0e5b5ce06337433908e63b" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/nette/php-generator/zipball/aea6e81437bb238e5f0e5b5ce06337433908e63b", "reference": "aea6e81437bb238e5f0e5b5ce06337433908e63b", "shasum": "" }, "require": { "nette/utils": "^2.4.2 || ~3.0.0", "php": ">=7.1" }, "require-dev": { "nette/tester": "^2.0", "tracy/tracy": "^2.3" }, "type": "library", "extra": { "branch-alias": { "dev-master": "3.2-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause", "GPL-2.0", "GPL-3.0" ], "authors": [ { "name": "David Grudl", "homepage": "https://davidgrudl.com" }, { "name": "Nette Community", "homepage": "https://nette.org/contributors" } ], "description": "🐘 Nette PHP Generator: generates neat PHP code for you. Supports new PHP 7.3 features.", "homepage": "https://nette.org", "keywords": [ "code", "nette", "php", "scaffolding" ], "time": "2019-07-05T13:01:56+00:00" }, { "name": "nette/robot-loader", "version": "v3.2.0", "source": { "type": "git", "url": "https://github.com/nette/robot-loader.git", "reference": "0712a0e39ae7956d6a94c0ab6ad41aa842544b5c" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/nette/robot-loader/zipball/0712a0e39ae7956d6a94c0ab6ad41aa842544b5c", "reference": "0712a0e39ae7956d6a94c0ab6ad41aa842544b5c", "shasum": "" }, "require": { "ext-tokenizer": "*", "nette/finder": "^2.5", "nette/utils": "^3.0", "php": ">=7.1" }, "require-dev": { "nette/tester": "^2.0", "tracy/tracy": "^2.3" }, "type": "library", "extra": { "branch-alias": { "dev-master": "3.2-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause", "GPL-2.0", "GPL-3.0" ], "authors": [ { "name": "David Grudl", "homepage": "https://davidgrudl.com" }, { "name": "Nette Community", "homepage": "https://nette.org/contributors" } ], "description": "? Nette RobotLoader: high performance and comfortable autoloader that will search and autoload classes within your application.", "homepage": "https://nette.org", "keywords": [ "autoload", "class", "interface", "nette", "trait" ], "time": "2019-03-08T21:57:24+00:00" }, { "name": "nette/schema", "version": "v1.0.0", "source": { "type": "git", "url": "https://github.com/nette/schema.git", "reference": "6241d8d4da39e825dd6cb5bfbe4242912f4d7e4d" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/nette/schema/zipball/6241d8d4da39e825dd6cb5bfbe4242912f4d7e4d", "reference": "6241d8d4da39e825dd6cb5bfbe4242912f4d7e4d", "shasum": "" }, "require": { "nette/utils": "^3.0.1", "php": ">=7.1" }, "require-dev": { "nette/tester": "^2.2", "tracy/tracy": "^2.3" }, "type": "library", "extra": { "branch-alias": { "dev-master": "1.0-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause", "GPL-2.0", "GPL-3.0" ], "authors": [ { "name": "David Grudl", "homepage": "https://davidgrudl.com" }, { "name": "Nette Community", "homepage": "https://nette.org/contributors" } ], "description": "📐 Nette Schema: validating data structures against a given Schema.", "homepage": "https://nette.org", "keywords": [ "config", "nette" ], "time": "2019-04-03T15:53:25+00:00" }, { "name": "nette/utils", "version": "v3.0.1", "source": { "type": "git", "url": "https://github.com/nette/utils.git", "reference": "bd961f49b211997202bda1d0fbc410905be370d4" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/nette/utils/zipball/bd961f49b211997202bda1d0fbc410905be370d4", "reference": "bd961f49b211997202bda1d0fbc410905be370d4", "shasum": "" }, "require": { "php": ">=7.1" }, "require-dev": { "nette/tester": "~2.0", "tracy/tracy": "^2.3" }, "suggest": { "ext-gd": "to use Image", "ext-iconv": "to use Strings::webalize() and toAscii()", "ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()", "ext-json": "to use Nette\\Utils\\Json", "ext-mbstring": "to use Strings::lower() etc...", "ext-xml": "to use Strings::length() etc. when mbstring is not available" }, "type": "library", "extra": { "branch-alias": { "dev-master": "3.0-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause", "GPL-2.0", "GPL-3.0" ], "authors": [ { "name": "David Grudl", "homepage": "https://davidgrudl.com" }, { "name": "Nette Community", "homepage": "https://nette.org/contributors" } ], "description": "🛠 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.", "homepage": "https://nette.org", "keywords": [ "array", "core", "datetime", "images", "json", "nette", "paginator", "password", "slugify", "string", "unicode", "utf-8", "utility", "validation" ], "time": "2019-03-22T01:00:30+00:00" }, { "name": "nikic/php-parser", "version": "v4.2.3", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", "reference": "e612609022e935f3d0337c1295176505b41188c8" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/e612609022e935f3d0337c1295176505b41188c8", "reference": "e612609022e935f3d0337c1295176505b41188c8", "shasum": "" }, "require": { "ext-tokenizer": "*", "php": ">=7.0" }, "require-dev": { "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0" }, "bin": [ "bin/php-parse" ], "type": "library", "extra": { "branch-alias": { "dev-master": "4.2-dev" } }, "autoload": { "psr-4": { "PhpParser\\": "lib/PhpParser" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Nikita Popov" } ], "description": "A PHP parser written in PHP", "keywords": [ "parser", "php" ], "time": "2019-08-12T20:17:41+00:00" }, { "name": "ocramius/package-versions", "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/Ocramius/PackageVersions.git", "reference": "a4d4b60d0e60da2487bd21a2c6ac089f85570dbb" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/Ocramius/PackageVersions/zipball/a4d4b60d0e60da2487bd21a2c6ac089f85570dbb", "reference": "a4d4b60d0e60da2487bd21a2c6ac089f85570dbb", "shasum": "" }, "require": { "composer-plugin-api": "^1.0.0", "php": "^7.1.0" }, "require-dev": { "composer/composer": "^1.6.3", "doctrine/coding-standard": "^5.0.1", "ext-zip": "*", "infection/infection": "^0.7.1", "phpunit/phpunit": "^7.0.0" }, "type": "composer-plugin", "extra": { "class": "PackageVersions\\Installer", "branch-alias": { "dev-master": "2.0.x-dev" } }, "autoload": { "psr-4": { "PackageVersions\\": "src/PackageVersions" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Marco Pivetta", "email": "ocramius@gmail.com" } ], "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", "time": "2019-02-21T12:16:21+00:00" }, { "name": "phar-io/manifest", "version": "1.0.3", "source": { "type": "git", "url": "https://github.com/phar-io/manifest.git", "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", "shasum": "" }, "require": { "ext-dom": "*", "ext-phar": "*", "phar-io/version": "^2.0", "php": "^5.6 || ^7.0" }, "type": "library", "extra": { "branch-alias": { "dev-master": "1.0.x-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Arne Blankerts", "email": "arne@blankerts.de", "role": "Developer" }, { "name": "Sebastian Heuer", "email": "sebastian@phpeople.de", "role": "Developer" }, { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de", "role": "Developer" } ], "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", "time": "2018-07-08T19:23:20+00:00" }, { "name": "phar-io/version", "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/phar-io/version.git", "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6", "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6", "shasum": "" }, "require": { "php": "^5.6 || ^7.0" }, "type": "library", "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Arne Blankerts", "email": "arne@blankerts.de", "role": "Developer" }, { "name": "Sebastian Heuer", "email": "sebastian@phpeople.de", "role": "Developer" }, { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de", "role": "Developer" } ], "description": "Library for handling version information and constraints", "time": "2018-07-08T19:19:57+00:00" }, { "name": "phpdocumentor/reflection-common", "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionCommon.git", "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/63a995caa1ca9e5590304cd845c15ad6d482a62a", "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a", "shasum": "" }, "require": { "php": ">=7.1" }, "require-dev": { "phpunit/phpunit": "~6" }, "type": "library", "extra": { "branch-alias": { "dev-master": "2.x-dev" } }, "autoload": { "psr-4": { "phpDocumentor\\Reflection\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Jaap van Otterdijk", "email": "opensource@ijaap.nl" } ], "description": "Common reflection classes used by phpdocumentor to reflect the code structure", "homepage": "http://www.phpdoc.org", "keywords": [ "FQSEN", "phpDocumentor", "phpdoc", "reflection", "static analysis" ], "time": "2018-08-07T13:53:10+00:00" }, { "name": "phpdocumentor/reflection-docblock", "version": "4.3.2", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", "reference": "b83ff7cfcfee7827e1e78b637a5904fe6a96698e" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/b83ff7cfcfee7827e1e78b637a5904fe6a96698e", "reference": "b83ff7cfcfee7827e1e78b637a5904fe6a96698e", "shasum": "" }, "require": { "php": "^7.0", "phpdocumentor/reflection-common": "^1.0.0 || ^2.0.0", "phpdocumentor/type-resolver": "~0.4 || ^1.0.0", "webmozart/assert": "^1.0" }, "require-dev": { "doctrine/instantiator": "^1.0.5", "mockery/mockery": "^1.0", "phpunit/phpunit": "^6.4" }, "type": "library", "extra": { "branch-alias": { "dev-master": "4.x-dev" } }, "autoload": { "psr-4": { "phpDocumentor\\Reflection\\": [ "src/" ] } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Mike van Riel", "email": "me@mikevanriel.com" } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", "time": "2019-09-12T14:27:41+00:00" }, { "name": "phpdocumentor/type-resolver", "version": "1.0.1", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/2e32a6d48972b2c1976ed5d8967145b6cec4a4a9", "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9", "shasum": "" }, "require": { "php": "^7.1", "phpdocumentor/reflection-common": "^2.0" }, "require-dev": { "ext-tokenizer": "^7.1", "mockery/mockery": "~1", "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { "dev-master": "1.x-dev" } }, "autoload": { "psr-4": { "phpDocumentor\\Reflection\\": "src" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Mike van Riel", "email": "me@mikevanriel.com" } ], "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "time": "2019-08-22T18:11:29+00:00" }, { "name": "phpspec/prophecy", "version": "1.9.0", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", "reference": "f6811d96d97bdf400077a0cc100ae56aa32b9203" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/phpspec/prophecy/zipball/f6811d96d97bdf400077a0cc100ae56aa32b9203", "reference": "f6811d96d97bdf400077a0cc100ae56aa32b9203", "shasum": "" }, "require": { "doctrine/instantiator": "^1.0.2", "php": "^5.3|^7.0", "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0", "sebastian/comparator": "^1.1|^2.0|^3.0", "sebastian/recursion-context": "^1.0|^2.0|^3.0" }, "require-dev": { "phpspec/phpspec": "^2.5|^3.2", "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1" }, "type": "library", "extra": { "branch-alias": { "dev-master": "1.8.x-dev" } }, "autoload": { "psr-4": { "Prophecy\\": "src/Prophecy" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Konstantin Kudryashov", "email": "ever.zet@gmail.com", "homepage": "http://everzet.com" }, { "name": "Marcello Duarte", "email": "marcello.duarte@gmail.com" } ], "description": "Highly opinionated mocking framework for PHP 5.3+", "homepage": "https://github.com/phpspec/prophecy", "keywords": [ "Double", "Dummy", "fake", "mock", "spy", "stub" ], "time": "2019-10-03T11:07:50+00:00" }, { "name": "phpstan/phpdoc-parser", "version": "0.3.5", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", "reference": "8c4ef2aefd9788238897b678a985e1d5c8df6db4" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/8c4ef2aefd9788238897b678a985e1d5c8df6db4", "reference": "8c4ef2aefd9788238897b678a985e1d5c8df6db4", "shasum": "" }, "require": { "php": "~7.1" }, "require-dev": { "consistence/coding-standard": "^3.5", "jakub-onderka/php-parallel-lint": "^0.9.2", "phing/phing": "^2.16.0", "phpstan/phpstan": "^0.10", "phpunit/phpunit": "^6.3", "slevomat/coding-standard": "^4.7.2", "squizlabs/php_codesniffer": "^3.3.2", "symfony/process": "^3.4 || ^4.0" }, "type": "library", "extra": { "branch-alias": { "dev-master": "0.3-dev" } }, "autoload": { "psr-4": { "PHPStan\\PhpDocParser\\": [ "src/" ] } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "description": "PHPDoc parser with support for nullable, intersection and generic types", "time": "2019-06-07T19:13:52+00:00" }, { "name": "phpstan/phpstan", "version": "0.11.15", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", "reference": "1be5b3a706db16ac472a4c40ec03cf4c810b118d" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/phpstan/phpstan/zipball/1be5b3a706db16ac472a4c40ec03cf4c810b118d", "reference": "1be5b3a706db16ac472a4c40ec03cf4c810b118d", "shasum": "" }, "require": { "composer/xdebug-handler": "^1.3.0", "jean85/pretty-package-versions": "^1.0.3", "nette/bootstrap": "^2.4 || ^3.0", "nette/di": "^2.4.7 || ^3.0", "nette/robot-loader": "^3.0.1", "nette/schema": "^1.0", "nette/utils": "^2.4.5 || ^3.0", "nikic/php-parser": "^4.2.3", "php": "~7.1", "phpstan/phpdoc-parser": "^0.3.5", "symfony/console": "~3.2 || ~4.0", "symfony/finder": "~3.2 || ~4.0" }, "conflict": { "symfony/console": "3.4.16 || 4.1.5" }, "require-dev": { "brianium/paratest": "^2.0 || ^3.0", "consistence/coding-standard": "^3.5", "dealerdirect/phpcodesniffer-composer-installer": "^0.4.4", "ext-intl": "*", "ext-mysqli": "*", "ext-simplexml": "*", "ext-soap": "*", "ext-zip": "*", "jakub-onderka/php-parallel-lint": "^1.0", "localheinz/composer-normalize": "^1.1.0", "phing/phing": "^2.16.0", "phpstan/phpstan-deprecation-rules": "^0.11", "phpstan/phpstan-php-parser": "^0.11", "phpstan/phpstan-phpunit": "^0.11", "phpstan/phpstan-strict-rules": "^0.11", "phpunit/phpunit": "^7.5.14 || ^8.0", "slevomat/coding-standard": "^4.7.2", "squizlabs/php_codesniffer": "^3.3.2" }, "bin": [ "bin/phpstan" ], "type": "library", "extra": { "branch-alias": { "dev-master": "0.11-dev" } }, "autoload": { "psr-4": { "PHPStan\\": [ "src/", "build/PHPStan" ] } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "description": "PHPStan - PHP Static Analysis Tool", "time": "2019-08-18T20:51:53+00:00" }, { "name": "phpunit/php-code-coverage", "version": "7.0.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", "reference": "aa0d179a13284c7420fc281fc32750e6cc7c9e2f" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/aa0d179a13284c7420fc281fc32750e6cc7c9e2f", "reference": "aa0d179a13284c7420fc281fc32750e6cc7c9e2f", "shasum": "" }, "require": { "ext-dom": "*", "ext-xmlwriter": "*", "php": "^7.2", "phpunit/php-file-iterator": "^2.0.2", "phpunit/php-text-template": "^1.2.1", "phpunit/php-token-stream": "^3.1.1", "sebastian/code-unit-reverse-lookup": "^1.0.1", "sebastian/environment": "^4.2.2", "sebastian/version": "^2.0.1", "theseer/tokenizer": "^1.1.3" }, "require-dev": { "phpunit/phpunit": "^8.2.2" }, "suggest": { "ext-xdebug": "^2.7.2" }, "type": "library", "extra": { "branch-alias": { "dev-master": "7.0-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de", "role": "lead" } ], "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", "homepage": "https://github.com/sebastianbergmann/php-code-coverage", "keywords": [ "coverage", "testing", "xunit" ], "time": "2019-09-17T06:24:36+00:00" }, { "name": "phpunit/php-file-iterator", "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", "reference": "050bedf145a257b1ff02746c31894800e5122946" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/050bedf145a257b1ff02746c31894800e5122946", "reference": "050bedf145a257b1ff02746c31894800e5122946", "shasum": "" }, "require": { "php": "^7.1" }, "require-dev": { "phpunit/phpunit": "^7.1" }, "type": "library", "extra": { "branch-alias": { "dev-master": "2.0.x-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de", "role": "lead" } ], "description": "FilterIterator implementation that filters files based on a list of suffixes.", "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", "keywords": [ "filesystem", "iterator" ], "time": "2018-09-13T20:33:42+00:00" }, { "name": "phpunit/php-text-template", "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-text-template.git", "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", "shasum": "" }, "require": { "php": ">=5.3.3" }, "type": "library", "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de", "role": "lead" } ], "description": "Simple template engine.", "homepage": "https://github.com/sebastianbergmann/php-text-template/", "keywords": [ "template" ], "time": "2015-06-21T13:50:34+00:00" }, { "name": "phpunit/php-timer", "version": "2.1.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", "reference": "1038454804406b0b5f5f520358e78c1c2f71501e" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/1038454804406b0b5f5f520358e78c1c2f71501e", "reference": "1038454804406b0b5f5f520358e78c1c2f71501e", "shasum": "" }, "require": { "php": "^7.1" }, "require-dev": { "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { "dev-master": "2.1-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de", "role": "lead" } ], "description": "Utility class for timing", "homepage": "https://github.com/sebastianbergmann/php-timer/", "keywords": [ "timer" ], "time": "2019-06-07T04:22:29+00:00" }, { "name": "phpunit/php-token-stream", "version": "3.1.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-token-stream.git", "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/995192df77f63a59e47f025390d2d1fdf8f425ff", "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff", "shasum": "" }, "require": { "ext-tokenizer": "*", "php": "^7.1" }, "require-dev": { "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { "dev-master": "3.1-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" } ], "description": "Wrapper around PHP's tokenizer extension.", "homepage": "https://github.com/sebastianbergmann/php-token-stream/", "keywords": [ "tokenizer" ], "time": "2019-09-17T06:23:10+00:00" }, { "name": "phpunit/phpunit", "version": "8.4.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", "reference": "366a4a0f2b971fd43b7c351d621e8dd7d7131869" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/366a4a0f2b971fd43b7c351d621e8dd7d7131869", "reference": "366a4a0f2b971fd43b7c351d621e8dd7d7131869", "shasum": "" }, "require": { "doctrine/instantiator": "^1.2.0", "ext-dom": "*", "ext-json": "*", "ext-libxml": "*", "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", "myclabs/deep-copy": "^1.9.1", "phar-io/manifest": "^1.0.3", "phar-io/version": "^2.0.1", "php": "^7.2", "phpspec/prophecy": "^1.8.1", "phpunit/php-code-coverage": "^7.0.7", "phpunit/php-file-iterator": "^2.0.2", "phpunit/php-text-template": "^1.2.1", "phpunit/php-timer": "^2.1.2", "sebastian/comparator": "^3.0.2", "sebastian/diff": "^3.0.2", "sebastian/environment": "^4.2.2", "sebastian/exporter": "^3.1.1", "sebastian/global-state": "^3.0.0", "sebastian/object-enumerator": "^3.0.3", "sebastian/resource-operations": "^2.0.1", "sebastian/type": "^1.1.3", "sebastian/version": "^2.0.1" }, "require-dev": { "ext-pdo": "*" }, "suggest": { "ext-soap": "*", "ext-xdebug": "*", "phpunit/php-invoker": "^2.0.0" }, "bin": [ "phpunit" ], "type": "library", "extra": { "branch-alias": { "dev-master": "8.4-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de", "role": "lead" } ], "description": "The PHP Unit Testing framework.", "homepage": "https://phpunit.de/", "keywords": [ "phpunit", "testing", "xunit" ], "time": "2019-10-07T12:57:41+00:00" }, { "name": "psr/log", "version": "1.1.0", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/php-fig/log/zipball/6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd", "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd", "shasum": "" }, "require": { "php": ">=5.3.0" }, "type": "library", "extra": { "branch-alias": { "dev-master": "1.0.x-dev" } }, "autoload": { "psr-4": { "Psr\\Log\\": "Psr/Log/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "PHP-FIG", "homepage": "http://www.php-fig.org/" } ], "description": "Common interface for logging libraries", "homepage": "https://github.com/php-fig/log", "keywords": [ "log", "psr", "psr-3" ], "time": "2018-11-20T15:27:04+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", "version": "1.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", "shasum": "" }, "require": { "php": "^5.6 || ^7.0" }, "require-dev": { "phpunit/phpunit": "^5.7 || ^6.0" }, "type": "library", "extra": { "branch-alias": { "dev-master": "1.0.x-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" } ], "description": "Looks up which function or method a line of code belongs to", "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", "time": "2017-03-04T06:30:41+00:00" }, { "name": "sebastian/comparator", "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/5de4fc177adf9bce8df98d8d141a7559d7ccf6da", "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da", "shasum": "" }, "require": { "php": "^7.1", "sebastian/diff": "^3.0", "sebastian/exporter": "^3.1" }, "require-dev": { "phpunit/phpunit": "^7.1" }, "type": "library", "extra": { "branch-alias": { "dev-master": "3.0-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Jeff Welch", "email": "whatthejeff@gmail.com" }, { "name": "Volker Dusch", "email": "github@wallbash.com" }, { "name": "Bernhard Schussek", "email": "bschussek@2bepublished.at" }, { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" } ], "description": "Provides the functionality to compare PHP values for equality", "homepage": "https://github.com/sebastianbergmann/comparator", "keywords": [ "comparator", "compare", "equality" ], "time": "2018-07-12T15:12:46+00:00" }, { "name": "sebastian/diff", "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/720fcc7e9b5cf384ea68d9d930d480907a0c1a29", "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29", "shasum": "" }, "require": { "php": "^7.1" }, "require-dev": { "phpunit/phpunit": "^7.5 || ^8.0", "symfony/process": "^2 || ^3.3 || ^4" }, "type": "library", "extra": { "branch-alias": { "dev-master": "3.0-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Kore Nordmann", "email": "mail@kore-nordmann.de" }, { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" } ], "description": "Diff implementation", "homepage": "https://github.com/sebastianbergmann/diff", "keywords": [ "diff", "udiff", "unidiff", "unified diff" ], "time": "2019-02-04T06:01:07+00:00" }, { "name": "sebastian/environment", "version": "4.2.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", "reference": "f2a2c8e1c97c11ace607a7a667d73d47c19fe404" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/f2a2c8e1c97c11ace607a7a667d73d47c19fe404", "reference": "f2a2c8e1c97c11ace607a7a667d73d47c19fe404", "shasum": "" }, "require": { "php": "^7.1" }, "require-dev": { "phpunit/phpunit": "^7.5" }, "suggest": { "ext-posix": "*" }, "type": "library", "extra": { "branch-alias": { "dev-master": "4.2-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" } ], "description": "Provides functionality to handle HHVM/PHP environments", "homepage": "http://www.github.com/sebastianbergmann/environment", "keywords": [ "Xdebug", "environment", "hhvm" ], "time": "2019-05-05T09:05:15+00:00" }, { "name": "sebastian/exporter", "version": "3.1.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/68609e1261d215ea5b21b7987539cbfbe156ec3e", "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e", "shasum": "" }, "require": { "php": "^7.0", "sebastian/recursion-context": "^3.0" }, "require-dev": { "ext-mbstring": "*", "phpunit/phpunit": "^6.0" }, "type": "library", "extra": { "branch-alias": { "dev-master": "3.1.x-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" }, { "name": "Jeff Welch", "email": "whatthejeff@gmail.com" }, { "name": "Volker Dusch", "email": "github@wallbash.com" }, { "name": "Adam Harvey", "email": "aharvey@php.net" }, { "name": "Bernhard Schussek", "email": "bschussek@gmail.com" } ], "description": "Provides the functionality to export PHP variables for visualization", "homepage": "http://www.github.com/sebastianbergmann/exporter", "keywords": [ "export", "exporter" ], "time": "2019-09-14T09:02:43+00:00" }, { "name": "sebastian/global-state", "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", "reference": "edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4", "reference": "edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4", "shasum": "" }, "require": { "php": "^7.2", "sebastian/object-reflector": "^1.1.1", "sebastian/recursion-context": "^3.0" }, "require-dev": { "ext-dom": "*", "phpunit/phpunit": "^8.0" }, "suggest": { "ext-uopz": "*" }, "type": "library", "extra": { "branch-alias": { "dev-master": "3.0-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" } ], "description": "Snapshotting of global state", "homepage": "http://www.github.com/sebastianbergmann/global-state", "keywords": [ "global state" ], "time": "2019-02-01T05:30:01+00:00" }, { "name": "sebastian/object-enumerator", "version": "3.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-enumerator.git", "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/7cfd9e65d11ffb5af41198476395774d4c8a84c5", "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5", "shasum": "" }, "require": { "php": "^7.0", "sebastian/object-reflector": "^1.1.1", "sebastian/recursion-context": "^3.0" }, "require-dev": { "phpunit/phpunit": "^6.0" }, "type": "library", "extra": { "branch-alias": { "dev-master": "3.0.x-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" } ], "description": "Traverses array structures and object graphs to enumerate all referenced objects", "homepage": "https://github.com/sebastianbergmann/object-enumerator/", "time": "2017-08-03T12:35:26+00:00" }, { "name": "sebastian/object-reflector", "version": "1.1.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-reflector.git", "reference": "773f97c67f28de00d397be301821b06708fca0be" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/773f97c67f28de00d397be301821b06708fca0be", "reference": "773f97c67f28de00d397be301821b06708fca0be", "shasum": "" }, "require": { "php": "^7.0" }, "require-dev": { "phpunit/phpunit": "^6.0" }, "type": "library", "extra": { "branch-alias": { "dev-master": "1.1-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" } ], "description": "Allows reflection of object attributes, including inherited and non-public ones", "homepage": "https://github.com/sebastianbergmann/object-reflector/", "time": "2017-03-29T09:07:27+00:00" }, { "name": "sebastian/recursion-context", "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", "shasum": "" }, "require": { "php": "^7.0" }, "require-dev": { "phpunit/phpunit": "^6.0" }, "type": "library", "extra": { "branch-alias": { "dev-master": "3.0.x-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Jeff Welch", "email": "whatthejeff@gmail.com" }, { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" }, { "name": "Adam Harvey", "email": "aharvey@php.net" } ], "description": "Provides functionality to recursively process PHP variables", "homepage": "http://www.github.com/sebastianbergmann/recursion-context", "time": "2017-03-03T06:23:57+00:00" }, { "name": "sebastian/resource-operations", "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/resource-operations.git", "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/4d7a795d35b889bf80a0cc04e08d77cedfa917a9", "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9", "shasum": "" }, "require": { "php": "^7.1" }, "type": "library", "extra": { "branch-alias": { "dev-master": "2.0-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" } ], "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", "time": "2018-10-04T04:07:39+00:00" }, { "name": "sebastian/type", "version": "1.1.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", "reference": "3aaaa15fa71d27650d62a948be022fe3b48541a3" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/3aaaa15fa71d27650d62a948be022fe3b48541a3", "reference": "3aaaa15fa71d27650d62a948be022fe3b48541a3", "shasum": "" }, "require": { "php": "^7.2" }, "require-dev": { "phpunit/phpunit": "^8.2" }, "type": "library", "extra": { "branch-alias": { "dev-master": "1.1-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Sebastian Bergmann", "role": "lead", "email": "sebastian@phpunit.de" } ], "description": "Collection of value objects that represent the types of the PHP type system", "homepage": "https://github.com/sebastianbergmann/type", "time": "2019-07-02T08:10:15+00:00" }, { "name": "sebastian/version", "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/version.git", "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", "shasum": "" }, "require": { "php": ">=5.6" }, "type": "library", "extra": { "branch-alias": { "dev-master": "2.0.x-dev" } }, "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de", "role": "lead" } ], "description": "Library that helps with managing the version number of Git-hosted PHP projects", "homepage": "https://github.com/sebastianbergmann/version", "time": "2016-10-03T07:35:21+00:00" }, { "name": "slevomat/coding-standard", "version": "5.0.2", "source": { "type": "git", "url": "https://github.com/slevomat/coding-standard.git", "reference": "223f02b6193fe47b7b483bfa5bf75693535482dd" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/223f02b6193fe47b7b483bfa5bf75693535482dd", "reference": "223f02b6193fe47b7b483bfa5bf75693535482dd", "shasum": "" }, "require": { "php": "^7.1", "phpstan/phpdoc-parser": "^0.3.1", "squizlabs/php_codesniffer": "^3.4.0" }, "require-dev": { "jakub-onderka/php-parallel-lint": "1.0.0", "phing/phing": "2.16.1", "phpstan/phpstan": "0.11.1", "phpstan/phpstan-phpunit": "0.11", "phpstan/phpstan-strict-rules": "0.11", "phpunit/phpunit": "8.0.0" }, "type": "phpcodesniffer-standard", "autoload": { "psr-4": { "SlevomatCodingStandard\\": "SlevomatCodingStandard" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "description": "Slevomat Coding Standard for PHP_CodeSniffer complements Consistence Coding Standard by providing sniffs with additional checks.", "time": "2019-03-12T20:26:36+00:00" }, { "name": "squizlabs/php_codesniffer", "version": "3.4.0", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", "reference": "379deb987e26c7cd103a7b387aea178baec96e48" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/379deb987e26c7cd103a7b387aea178baec96e48", "reference": "379deb987e26c7cd103a7b387aea178baec96e48", "shasum": "" }, "require": { "ext-simplexml": "*", "ext-tokenizer": "*", "ext-xmlwriter": "*", "php": ">=5.4.0" }, "require-dev": { "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" }, "bin": [ "bin/phpcs", "bin/phpcbf" ], "type": "library", "extra": { "branch-alias": { "dev-master": "3.x-dev" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Greg Sherwood", "role": "lead" } ], "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", "homepage": "http://www.squizlabs.com/php-codesniffer", "keywords": [ "phpcs", "standards" ], "time": "2018-12-19T23:57:18+00:00" }, { "name": "symfony/console", "version": "v4.2.4", "source": { "type": "git", "url": "https://github.com/symfony/console.git", "reference": "9dc2299a016497f9ee620be94524e6c0af0280a9" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/symfony/console/zipball/9dc2299a016497f9ee620be94524e6c0af0280a9", "reference": "9dc2299a016497f9ee620be94524e6c0af0280a9", "shasum": "" }, "require": { "php": "^7.1.3", "symfony/contracts": "^1.0", "symfony/polyfill-mbstring": "~1.0" }, "conflict": { "symfony/dependency-injection": "<3.4", "symfony/process": "<3.3" }, "provide": { "psr/log-implementation": "1.0" }, "require-dev": { "psr/log": "~1.0", "symfony/config": "~3.4|~4.0", "symfony/dependency-injection": "~3.4|~4.0", "symfony/event-dispatcher": "~3.4|~4.0", "symfony/lock": "~3.4|~4.0", "symfony/process": "~3.4|~4.0" }, "suggest": { "psr/log": "For using the console logger", "symfony/event-dispatcher": "", "symfony/lock": "", "symfony/process": "" }, "type": "library", "extra": { "branch-alias": { "dev-master": "4.2-dev" } }, "autoload": { "psr-4": { "Symfony\\Component\\Console\\": "" }, "exclude-from-classmap": [ "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Fabien Potencier", "email": "fabien@symfony.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], "description": "Symfony Console Component", "homepage": "https://symfony.com", "time": "2019-02-23T15:17:42+00:00" }, { "name": "symfony/contracts", "version": "v1.0.2", "source": { "type": "git", "url": "https://github.com/symfony/contracts.git", "reference": "1aa7ab2429c3d594dd70689604b5cf7421254cdf" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/symfony/contracts/zipball/1aa7ab2429c3d594dd70689604b5cf7421254cdf", "reference": "1aa7ab2429c3d594dd70689604b5cf7421254cdf", "shasum": "" }, "require": { "php": "^7.1.3" }, "require-dev": { "psr/cache": "^1.0", "psr/container": "^1.0" }, "suggest": { "psr/cache": "When using the Cache contracts", "psr/container": "When using the Service contracts", "symfony/cache-contracts-implementation": "", "symfony/service-contracts-implementation": "", "symfony/translation-contracts-implementation": "" }, "type": "library", "extra": { "branch-alias": { "dev-master": "1.0-dev" } }, "autoload": { "psr-4": { "Symfony\\Contracts\\": "" }, "exclude-from-classmap": [ "**/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Nicolas Grekas", "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], "description": "A set of abstractions extracted out of the Symfony components", "homepage": "https://symfony.com", "keywords": [ "abstractions", "contracts", "decoupling", "interfaces", "interoperability", "standards" ], "time": "2018-12-05T08:06:11+00:00" }, { "name": "symfony/debug", "version": "v4.0.6", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", "reference": "1721e4e7effb23480966690cdcdc7d2a4152d489" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/symfony/debug/zipball/1721e4e7effb23480966690cdcdc7d2a4152d489", "reference": "1721e4e7effb23480966690cdcdc7d2a4152d489", "shasum": "" }, "require": { "php": "^7.1.3", "psr/log": "~1.0" }, "conflict": { "symfony/http-kernel": "<3.4" }, "require-dev": { "symfony/http-kernel": "~3.4|~4.0" }, "type": "library", "extra": { "branch-alias": { "dev-master": "4.0-dev" } }, "autoload": { "psr-4": { "Symfony\\Component\\Debug\\": "" }, "exclude-from-classmap": [ "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Fabien Potencier", "email": "fabien@symfony.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], "description": "Symfony Debug Component", "homepage": "https://symfony.com", "time": "2018-02-28T21:50:02+00:00" }, { "name": "symfony/finder", "version": "v4.3.3", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", "reference": "9638d41e3729459860bb96f6247ccb61faaa45f2" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/symfony/finder/zipball/9638d41e3729459860bb96f6247ccb61faaa45f2", "reference": "9638d41e3729459860bb96f6247ccb61faaa45f2", "shasum": "" }, "require": { "php": "^7.1.3" }, "type": "library", "extra": { "branch-alias": { "dev-master": "4.3-dev" } }, "autoload": { "psr-4": { "Symfony\\Component\\Finder\\": "" }, "exclude-from-classmap": [ "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Fabien Potencier", "email": "fabien@symfony.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", "time": "2019-06-28T13:16:30+00:00" }, { "name": "symfony/polyfill-ctype", "version": "v1.12.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", "reference": "550ebaac289296ce228a706d0867afc34687e3f4" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/550ebaac289296ce228a706d0867afc34687e3f4", "reference": "550ebaac289296ce228a706d0867afc34687e3f4", "shasum": "" }, "require": { "php": ">=5.3.3" }, "suggest": { "ext-ctype": "For best performance" }, "type": "library", "extra": { "branch-alias": { "dev-master": "1.12-dev" } }, "autoload": { "psr-4": { "Symfony\\Polyfill\\Ctype\\": "" }, "files": [ "bootstrap.php" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Gert de Pagter", "email": "BackEndTea@gmail.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], "description": "Symfony polyfill for ctype functions", "homepage": "https://symfony.com", "keywords": [ "compatibility", "ctype", "polyfill", "portable" ], "time": "2019-08-06T08:03:45+00:00" }, { "name": "symfony/polyfill-mbstring", "version": "v1.10.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", "reference": "c79c051f5b3a46be09205c73b80b346e4153e494" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/c79c051f5b3a46be09205c73b80b346e4153e494", "reference": "c79c051f5b3a46be09205c73b80b346e4153e494", "shasum": "" }, "require": { "php": ">=5.3.3" }, "suggest": { "ext-mbstring": "For best performance" }, "type": "library", "extra": { "branch-alias": { "dev-master": "1.9-dev" } }, "autoload": { "psr-4": { "Symfony\\Polyfill\\Mbstring\\": "" }, "files": [ "bootstrap.php" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Nicolas Grekas", "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], "description": "Symfony polyfill for the Mbstring extension", "homepage": "https://symfony.com", "keywords": [ "compatibility", "mbstring", "polyfill", "portable", "shim" ], "time": "2018-09-21T13:07:52+00:00" }, { "name": "theseer/tokenizer", "version": "1.1.3", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/theseer/tokenizer/zipball/11336f6f84e16a720dae9d8e6ed5019efa85a0f9", "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9", "shasum": "" }, "require": { "ext-dom": "*", "ext-tokenizer": "*", "ext-xmlwriter": "*", "php": "^7.0" }, "type": "library", "autoload": { "classmap": [ "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Arne Blankerts", "role": "Developer", "email": "arne@blankerts.de" } ], "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "time": "2019-06-13T22:48:21+00:00" }, { "name": "webmozart/assert", "version": "1.5.0", "source": { "type": "git", "url": "https://github.com/webmozart/assert.git", "reference": "88e6d84706d09a236046d686bbea96f07b3a34f4" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/webmozart/assert/zipball/88e6d84706d09a236046d686bbea96f07b3a34f4", "reference": "88e6d84706d09a236046d686bbea96f07b3a34f4", "shasum": "" }, "require": { "php": "^5.3.3 || ^7.0", "symfony/polyfill-ctype": "^1.8" }, "require-dev": { "phpunit/phpunit": "^4.8.36 || ^7.5.13" }, "type": "library", "extra": { "branch-alias": { "dev-master": "1.3-dev" } }, "autoload": { "psr-4": { "Webmozart\\Assert\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Bernhard Schussek", "email": "bschussek@gmail.com" } ], "description": "Assertions to validate method input/output with nice error messages.", "keywords": [ "assert", "check", "validate" ], "time": "2019-08-24T08:43:50+00:00" } ], "aliases": [], "minimum-stability": "stable", "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": { "php": "^7.2", "ext-pdo": "*" }, "platform-dev": [] } php-doctrine-dbal-2.10.1/lib/000077500000000000000000000000001360544566000156465ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/lib/Doctrine/000077500000000000000000000000001360544566000174155ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/000077500000000000000000000000001360544566000201175ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Cache/000077500000000000000000000000001360544566000211225ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Cache/ArrayStatement.php000066400000000000000000000055621360544566000246060ustar00rootroot00000000000000data = $data; if (! count($data)) { return; } $this->columnCount = count($data[0]); } /** * {@inheritdoc} */ public function closeCursor() { unset($this->data); } /** * {@inheritdoc} */ public function columnCount() { return $this->columnCount; } /** * {@inheritdoc} */ public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) { if ($arg2 !== null || $arg3 !== null) { throw new InvalidArgumentException('Caching layer does not support 2nd/3rd argument to setFetchMode()'); } $this->defaultFetchMode = $fetchMode; return true; } /** * {@inheritdoc} */ public function getIterator() { $data = $this->fetchAll(); return new ArrayIterator($data); } /** * {@inheritdoc} */ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) { if (! isset($this->data[$this->num])) { return false; } $row = $this->data[$this->num++]; $fetchMode = $fetchMode ?: $this->defaultFetchMode; if ($fetchMode === FetchMode::ASSOCIATIVE) { return $row; } if ($fetchMode === FetchMode::NUMERIC) { return array_values($row); } if ($fetchMode === FetchMode::MIXED) { return array_merge($row, array_values($row)); } if ($fetchMode === FetchMode::COLUMN) { return reset($row); } throw new InvalidArgumentException('Invalid fetch-style given for fetching result.'); } /** * {@inheritdoc} */ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) { $rows = []; while ($row = $this->fetch($fetchMode)) { $rows[] = $row; } return $rows; } /** * {@inheritdoc} */ public function fetchColumn($columnIndex = 0) { $row = $this->fetch(FetchMode::NUMERIC); // TODO: verify that return false is the correct behavior return $row[$columnIndex] ?? false; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Cache/CacheException.php000066400000000000000000000007771360544566000245300ustar00rootroot00000000000000lifetime = $lifetime; $this->cacheKey = $cacheKey; $this->resultCacheDriver = $resultCache; } /** * @return Cache|null */ public function getResultCacheDriver() { return $this->resultCacheDriver; } /** * @return int */ public function getLifetime() { return $this->lifetime; } /** * @return string * * @throws CacheException */ public function getCacheKey() { if ($this->cacheKey === null) { throw CacheException::noCacheKey(); } return $this->cacheKey; } /** * Generates the real cache key from query, params, types and connection parameters. * * @param string $query * @param mixed[] $params * @param int[]|string[] $types * @param mixed[] $connectionParams * * @return string[] */ public function generateCacheKeys($query, $params, $types, array $connectionParams = []) { $realCacheKey = 'query=' . $query . '¶ms=' . serialize($params) . '&types=' . serialize($types) . '&connectionParams=' . hash('sha256', serialize($connectionParams)); // should the key be automatically generated using the inputs or is the cache key set? if ($this->cacheKey === null) { $cacheKey = sha1($realCacheKey); } else { $cacheKey = $this->cacheKey; } return [$cacheKey, $realCacheKey]; } /** * @return \Doctrine\DBAL\Cache\QueryCacheProfile */ public function setResultCacheDriver(Cache $cache) { return new QueryCacheProfile($this->lifetime, $this->cacheKey, $cache); } /** * @param string|null $cacheKey * * @return \Doctrine\DBAL\Cache\QueryCacheProfile */ public function setCacheKey($cacheKey) { return new QueryCacheProfile($this->lifetime, $cacheKey, $this->resultCacheDriver); } /** * @param int $lifetime * * @return \Doctrine\DBAL\Cache\QueryCacheProfile */ public function setLifetime($lifetime) { return new QueryCacheProfile($lifetime, $this->cacheKey, $this->resultCacheDriver); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Cache/ResultCacheStatement.php000066400000000000000000000123261360544566000257260ustar00rootroot00000000000000statement = $stmt; $this->resultCache = $resultCache; $this->cacheKey = $cacheKey; $this->realKey = $realKey; $this->lifetime = $lifetime; } /** * {@inheritdoc} */ public function closeCursor() { $this->statement->closeCursor(); if (! $this->emptied || $this->data === null) { return true; } $data = $this->resultCache->fetch($this->cacheKey); if (! $data) { $data = []; } $data[$this->realKey] = $this->data; $this->resultCache->save($this->cacheKey, $data, $this->lifetime); unset($this->data); return true; } /** * {@inheritdoc} */ public function columnCount() { return $this->statement->columnCount(); } /** * {@inheritdoc} */ public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) { $this->defaultFetchMode = $fetchMode; return true; } /** * {@inheritdoc} */ public function getIterator() { $data = $this->fetchAll(); return new ArrayIterator($data); } /** * {@inheritdoc} */ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) { if ($this->data === null) { $this->data = []; } $row = $this->statement->fetch(FetchMode::ASSOCIATIVE); if ($row) { $this->data[] = $row; $fetchMode = $fetchMode ?: $this->defaultFetchMode; if ($fetchMode === FetchMode::ASSOCIATIVE) { return $row; } if ($fetchMode === FetchMode::NUMERIC) { return array_values($row); } if ($fetchMode === FetchMode::MIXED) { return array_merge($row, array_values($row)); } if ($fetchMode === FetchMode::COLUMN) { return reset($row); } throw new InvalidArgumentException('Invalid fetch-style given for caching result.'); } $this->emptied = true; return false; } /** * {@inheritdoc} */ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) { $data = $this->statement->fetchAll($fetchMode, $fetchArgument, $ctorArgs); if ($fetchMode === FetchMode::COLUMN) { foreach ($data as $key => $value) { $data[$key] = [$value]; } } $this->data = $data; $this->emptied = true; return $this->data; } /** * {@inheritdoc} */ public function fetchColumn($columnIndex = 0) { $row = $this->fetch(FetchMode::NUMERIC); // TODO: verify that return false is the correct behavior return $row[$columnIndex] ?? false; } /** * Returns the number of rows affected by the last DELETE, INSERT, or UPDATE statement * executed by the corresponding object. * * If the last SQL statement executed by the associated Statement object was a SELECT statement, * some databases may return the number of rows returned by that statement. However, * this behaviour is not guaranteed for all databases and should not be * relied on for portable applications. * * @return int The number of rows. */ public function rowCount() { assert($this->statement instanceof Statement); return $this->statement->rowCount(); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/ColumnCase.php000066400000000000000000000007711360544566000226660ustar00rootroot00000000000000_attributes['sqlLogger'] = $logger; } /** * Gets the SQL logger that is used. * * @return SQLLogger|null */ public function getSQLLogger() { return $this->_attributes['sqlLogger'] ?? null; } /** * Gets the cache driver implementation that is used for query result caching. * * @return Cache|null */ public function getResultCacheImpl() { return $this->_attributes['resultCacheImpl'] ?? null; } /** * Sets the cache driver implementation that is used for query result caching. * * @return void */ public function setResultCacheImpl(Cache $cacheImpl) { $this->_attributes['resultCacheImpl'] = $cacheImpl; } /** * Sets the filter schema assets expression. * * Only include tables/sequences matching the filter expression regexp in * schema instances generated for the active connection when calling * {AbstractSchemaManager#createSchema()}. * * @deprecated Use Configuration::setSchemaAssetsFilter() instead * * @param string $filterExpression * * @return void */ public function setFilterSchemaAssetsExpression($filterExpression) { $this->_attributes['filterSchemaAssetsExpression'] = $filterExpression; if ($filterExpression) { $this->_attributes['filterSchemaAssetsExpressionCallable'] = $this->buildSchemaAssetsFilterFromExpression($filterExpression); } else { $this->_attributes['filterSchemaAssetsExpressionCallable'] = null; } } /** * Returns filter schema assets expression. * * @deprecated Use Configuration::getSchemaAssetsFilter() instead * * @return string|null */ public function getFilterSchemaAssetsExpression() { return $this->_attributes['filterSchemaAssetsExpression'] ?? null; } /** * @param string $filterExpression */ private function buildSchemaAssetsFilterFromExpression($filterExpression) : callable { return static function ($assetName) use ($filterExpression) { if ($assetName instanceof AbstractAsset) { $assetName = $assetName->getName(); } return preg_match($filterExpression, $assetName); }; } /** * Sets the callable to use to filter schema assets. */ public function setSchemaAssetsFilter(?callable $callable = null) : ?callable { $this->_attributes['filterSchemaAssetsExpression'] = null; return $this->_attributes['filterSchemaAssetsExpressionCallable'] = $callable; } /** * Returns the callable to use to filter schema assets. */ public function getSchemaAssetsFilter() : ?callable { return $this->_attributes['filterSchemaAssetsExpressionCallable'] ?? null; } /** * Sets the default auto-commit mode for connections. * * If a connection is in auto-commit mode, then all its SQL statements will be executed and committed as individual * transactions. Otherwise, its SQL statements are grouped into transactions that are terminated by a call to either * the method commit or the method rollback. By default, new connections are in auto-commit mode. * * @see getAutoCommit * * @param bool $autoCommit True to enable auto-commit mode; false to disable it. */ public function setAutoCommit($autoCommit) { $this->_attributes['autoCommit'] = (bool) $autoCommit; } /** * Returns the default auto-commit mode for connections. * * @see setAutoCommit * * @return bool True if auto-commit mode is enabled by default for connections, false otherwise. */ public function getAutoCommit() { return $this->_attributes['autoCommit'] ?? true; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Connection.php000066400000000000000000001430251360544566000227340ustar00rootroot00000000000000_driver = $driver; $this->params = $params; if (isset($params['pdo'])) { $this->_conn = $params['pdo']; $this->isConnected = true; unset($this->params['pdo']); } if (isset($params['platform'])) { if (! $params['platform'] instanceof Platforms\AbstractPlatform) { throw DBALException::invalidPlatformType($params['platform']); } $this->platform = $params['platform']; } // Create default config and event manager if none given if (! $config) { $config = new Configuration(); } if (! $eventManager) { $eventManager = new EventManager(); } $this->_config = $config; $this->_eventManager = $eventManager; $this->_expr = new Query\Expression\ExpressionBuilder($this); $this->autoCommit = $config->getAutoCommit(); } /** * Gets the parameters used during instantiation. * * @return mixed[] */ public function getParams() { return $this->params; } /** * Gets the name of the database this Connection is connected to. * * @return string */ public function getDatabase() { return $this->_driver->getDatabase($this); } /** * Gets the hostname of the currently connected database. * * @deprecated * * @return string|null */ public function getHost() { return $this->params['host'] ?? null; } /** * Gets the port of the currently connected database. * * @deprecated * * @return mixed */ public function getPort() { return $this->params['port'] ?? null; } /** * Gets the username used by this connection. * * @deprecated * * @return string|null */ public function getUsername() { return $this->params['user'] ?? null; } /** * Gets the password used by this connection. * * @deprecated * * @return string|null */ public function getPassword() { return $this->params['password'] ?? null; } /** * Gets the DBAL driver instance. * * @return Driver */ public function getDriver() { return $this->_driver; } /** * Gets the Configuration used by the Connection. * * @return Configuration */ public function getConfiguration() { return $this->_config; } /** * Gets the EventManager used by the Connection. * * @return EventManager */ public function getEventManager() { return $this->_eventManager; } /** * Gets the DatabasePlatform for the connection. * * @return AbstractPlatform * * @throws DBALException */ public function getDatabasePlatform() { if ($this->platform === null) { $this->detectDatabasePlatform(); } return $this->platform; } /** * Gets the ExpressionBuilder for the connection. * * @return ExpressionBuilder */ public function getExpressionBuilder() { return $this->_expr; } /** * Establishes the connection with the database. * * @return bool TRUE if the connection was successfully established, FALSE if * the connection is already open. */ public function connect() { if ($this->isConnected) { return false; } $driverOptions = $this->params['driverOptions'] ?? []; $user = $this->params['user'] ?? null; $password = $this->params['password'] ?? null; $this->_conn = $this->_driver->connect($this->params, $user, $password, $driverOptions); $this->isConnected = true; $this->transactionNestingLevel = 0; if ($this->autoCommit === false) { $this->beginTransaction(); } if ($this->_eventManager->hasListeners(Events::postConnect)) { $eventArgs = new Event\ConnectionEventArgs($this); $this->_eventManager->dispatchEvent(Events::postConnect, $eventArgs); } return true; } /** * Detects and sets the database platform. * * Evaluates custom platform class and version in order to set the correct platform. * * @throws DBALException If an invalid platform was specified for this connection. */ private function detectDatabasePlatform() { $version = $this->getDatabasePlatformVersion(); if ($version !== null) { assert($this->_driver instanceof VersionAwarePlatformDriver); $this->platform = $this->_driver->createDatabasePlatformForVersion($version); } else { $this->platform = $this->_driver->getDatabasePlatform(); } $this->platform->setEventManager($this->_eventManager); } /** * Returns the version of the related platform if applicable. * * Returns null if either the driver is not capable to create version * specific platform instances, no explicit server version was specified * or the underlying driver connection cannot determine the platform * version without having to query it (performance reasons). * * @return string|null * * @throws Exception */ private function getDatabasePlatformVersion() { // Driver does not support version specific platforms. if (! $this->_driver instanceof VersionAwarePlatformDriver) { return null; } // Explicit platform version requested (supersedes auto-detection). if (isset($this->params['serverVersion'])) { return $this->params['serverVersion']; } // If not connected, we need to connect now to determine the platform version. if ($this->_conn === null) { try { $this->connect(); } catch (Throwable $originalException) { if (empty($this->params['dbname'])) { throw $originalException; } // The database to connect to might not yet exist. // Retry detection without database name connection parameter. $databaseName = $this->params['dbname']; $this->params['dbname'] = null; try { $this->connect(); } catch (Throwable $fallbackException) { // Either the platform does not support database-less connections // or something else went wrong. // Reset connection parameters and rethrow the original exception. $this->params['dbname'] = $databaseName; throw $originalException; } // Reset connection parameters. $this->params['dbname'] = $databaseName; $serverVersion = $this->getServerVersion(); // Close "temporary" connection to allow connecting to the real database again. $this->close(); return $serverVersion; } } return $this->getServerVersion(); } /** * Returns the database server version if the underlying driver supports it. * * @return string|null */ private function getServerVersion() { $connection = $this->getWrappedConnection(); // Automatic platform version detection. if ($connection instanceof ServerInfoAwareConnection && ! $connection->requiresQueryForServerVersion()) { return $connection->getServerVersion(); } // Unable to detect platform version. return null; } /** * Returns the current auto-commit mode for this connection. * * @see setAutoCommit * * @return bool True if auto-commit mode is currently enabled for this connection, false otherwise. */ public function isAutoCommit() { return $this->autoCommit === true; } /** * Sets auto-commit mode for this connection. * * If a connection is in auto-commit mode, then all its SQL statements will be executed and committed as individual * transactions. Otherwise, its SQL statements are grouped into transactions that are terminated by a call to either * the method commit or the method rollback. By default, new connections are in auto-commit mode. * * NOTE: If this method is called during a transaction and the auto-commit mode is changed, the transaction is * committed. If this method is called and the auto-commit mode is not changed, the call is a no-op. * * @see isAutoCommit * * @param bool $autoCommit True to enable auto-commit mode; false to disable it. */ public function setAutoCommit($autoCommit) { $autoCommit = (bool) $autoCommit; // Mode not changed, no-op. if ($autoCommit === $this->autoCommit) { return; } $this->autoCommit = $autoCommit; // Commit all currently active transactions if any when switching auto-commit mode. if ($this->isConnected !== true || $this->transactionNestingLevel === 0) { return; } $this->commitAll(); } /** * Sets the fetch mode. * * @param int $fetchMode * * @return void */ public function setFetchMode($fetchMode) { $this->defaultFetchMode = $fetchMode; } /** * Prepares and executes an SQL query and returns the first row of the result * as an associative array. * * @param string $statement The SQL query. * @param mixed[] $params The query parameters. * @param int[]|string[] $types The query parameter types. * * @return mixed[]|false False is returned if no rows are found. * * @throws DBALException */ public function fetchAssoc($statement, array $params = [], array $types = []) { return $this->executeQuery($statement, $params, $types)->fetch(FetchMode::ASSOCIATIVE); } /** * Prepares and executes an SQL query and returns the first row of the result * as a numerically indexed array. * * @param string $statement The SQL query to be executed. * @param mixed[] $params The prepared statement params. * @param int[]|string[] $types The query parameter types. * * @return mixed[]|false False is returned if no rows are found. */ public function fetchArray($statement, array $params = [], array $types = []) { return $this->executeQuery($statement, $params, $types)->fetch(FetchMode::NUMERIC); } /** * Prepares and executes an SQL query and returns the value of a single column * of the first row of the result. * * @param string $statement The SQL query to be executed. * @param mixed[] $params The prepared statement params. * @param int $column The 0-indexed column number to retrieve. * @param int[]|string[] $types The query parameter types. * * @return mixed|false False is returned if no rows are found. * * @throws DBALException */ public function fetchColumn($statement, array $params = [], $column = 0, array $types = []) { return $this->executeQuery($statement, $params, $types)->fetchColumn($column); } /** * Whether an actual connection to the database is established. * * @return bool */ public function isConnected() { return $this->isConnected; } /** * Checks whether a transaction is currently active. * * @return bool TRUE if a transaction is currently active, FALSE otherwise. */ public function isTransactionActive() { return $this->transactionNestingLevel > 0; } /** * Adds identifier condition to the query components * * @param mixed[] $identifier Map of key columns to their values * @param string[] $columns Column names * @param mixed[] $values Column values * @param string[] $conditions Key conditions * * @throws DBALException */ private function addIdentifierCondition( array $identifier, array &$columns, array &$values, array &$conditions ) : void { $platform = $this->getDatabasePlatform(); foreach ($identifier as $columnName => $value) { if ($value === null) { $conditions[] = $platform->getIsNullExpression($columnName); continue; } $columns[] = $columnName; $values[] = $value; $conditions[] = $columnName . ' = ?'; } } /** * Executes an SQL DELETE statement on a table. * * Table expression and columns are not escaped and are not safe for user-input. * * @param string $tableExpression The expression of the table on which to delete. * @param mixed[] $identifier The deletion criteria. An associative array containing column-value pairs. * @param int[]|string[] $types The types of identifiers. * * @return int The number of affected rows. * * @throws DBALException * @throws InvalidArgumentException */ public function delete($tableExpression, array $identifier, array $types = []) { if (empty($identifier)) { throw InvalidArgumentException::fromEmptyCriteria(); } $columns = $values = $conditions = []; $this->addIdentifierCondition($identifier, $columns, $values, $conditions); return $this->executeUpdate( 'DELETE FROM ' . $tableExpression . ' WHERE ' . implode(' AND ', $conditions), $values, is_string(key($types)) ? $this->extractTypeValues($columns, $types) : $types ); } /** * Closes the connection. * * @return void */ public function close() { $this->_conn = null; $this->isConnected = false; } /** * Sets the transaction isolation level. * * @param int $level The level to set. * * @return int */ public function setTransactionIsolation($level) { $this->transactionIsolationLevel = $level; return $this->executeUpdate($this->getDatabasePlatform()->getSetTransactionIsolationSQL($level)); } /** * Gets the currently active transaction isolation level. * * @return int The current transaction isolation level. */ public function getTransactionIsolation() { if ($this->transactionIsolationLevel === null) { $this->transactionIsolationLevel = $this->getDatabasePlatform()->getDefaultTransactionIsolationLevel(); } return $this->transactionIsolationLevel; } /** * Executes an SQL UPDATE statement on a table. * * Table expression and columns are not escaped and are not safe for user-input. * * @param string $tableExpression The expression of the table to update quoted or unquoted. * @param mixed[] $data An associative array containing column-value pairs. * @param mixed[] $identifier The update criteria. An associative array containing column-value pairs. * @param int[]|string[] $types Types of the merged $data and $identifier arrays in that order. * * @return int The number of affected rows. * * @throws DBALException */ public function update($tableExpression, array $data, array $identifier, array $types = []) { $columns = $values = $conditions = $set = []; foreach ($data as $columnName => $value) { $columns[] = $columnName; $values[] = $value; $set[] = $columnName . ' = ?'; } $this->addIdentifierCondition($identifier, $columns, $values, $conditions); if (is_string(key($types))) { $types = $this->extractTypeValues($columns, $types); } $sql = 'UPDATE ' . $tableExpression . ' SET ' . implode(', ', $set) . ' WHERE ' . implode(' AND ', $conditions); return $this->executeUpdate($sql, $values, $types); } /** * Inserts a table row with specified data. * * Table expression and columns are not escaped and are not safe for user-input. * * @param string $tableExpression The expression of the table to insert data into, quoted or unquoted. * @param mixed[] $data An associative array containing column-value pairs. * @param int[]|string[] $types Types of the inserted data. * * @return int The number of affected rows. * * @throws DBALException */ public function insert($tableExpression, array $data, array $types = []) { if (empty($data)) { return $this->executeUpdate('INSERT INTO ' . $tableExpression . ' () VALUES ()'); } $columns = []; $values = []; $set = []; foreach ($data as $columnName => $value) { $columns[] = $columnName; $values[] = $value; $set[] = '?'; } return $this->executeUpdate( 'INSERT INTO ' . $tableExpression . ' (' . implode(', ', $columns) . ')' . ' VALUES (' . implode(', ', $set) . ')', $values, is_string(key($types)) ? $this->extractTypeValues($columns, $types) : $types ); } /** * Extract ordered type list from an ordered column list and type map. * * @param int[]|string[] $columnList * @param int[]|string[] $types * * @return int[]|string[] */ private function extractTypeValues(array $columnList, array $types) { $typeValues = []; foreach ($columnList as $columnIndex => $columnName) { $typeValues[] = $types[$columnName] ?? ParameterType::STRING; } return $typeValues; } /** * Quotes a string so it can be safely used as a table or column name, even if * it is a reserved name. * * Delimiting style depends on the underlying database platform that is being used. * * NOTE: Just because you CAN use quoted identifiers does not mean * you SHOULD use them. In general, they end up causing way more * problems than they solve. * * @param string $str The name to be quoted. * * @return string The quoted name. */ public function quoteIdentifier($str) { return $this->getDatabasePlatform()->quoteIdentifier($str); } /** * {@inheritDoc} */ public function quote($input, $type = null) { $connection = $this->getWrappedConnection(); [$value, $bindingType] = $this->getBindingInfo($input, $type); return $connection->quote($value, $bindingType); } /** * Prepares and executes an SQL query and returns the result as an associative array. * * @param string $sql The SQL query. * @param mixed[] $params The query parameters. * @param int[]|string[] $types The query parameter types. * * @return mixed[] */ public function fetchAll($sql, array $params = [], $types = []) { return $this->executeQuery($sql, $params, $types)->fetchAll(); } /** * Prepares an SQL statement. * * @param string $statement The SQL statement to prepare. * * @return DriverStatement The prepared statement. * * @throws DBALException */ public function prepare($statement) { try { $stmt = new Statement($statement, $this); } catch (Throwable $ex) { throw DBALException::driverExceptionDuringQuery($this->_driver, $ex, $statement); } $stmt->setFetchMode($this->defaultFetchMode); return $stmt; } /** * Executes an, optionally parametrized, SQL query. * * If the query is parametrized, a prepared statement is used. * If an SQLLogger is configured, the execution is logged. * * @param string $query The SQL query to execute. * @param mixed[] $params The parameters to bind to the query, if any. * @param int[]|string[] $types The types the previous parameters are in. * @param QueryCacheProfile|null $qcp The query cache profile, optional. * * @return ResultStatement The executed statement. * * @throws DBALException */ public function executeQuery($query, array $params = [], $types = [], ?QueryCacheProfile $qcp = null) { if ($qcp !== null) { return $this->executeCacheQuery($query, $params, $types, $qcp); } $connection = $this->getWrappedConnection(); $logger = $this->_config->getSQLLogger(); if ($logger) { $logger->startQuery($query, $params, $types); } try { if ($params) { [$query, $params, $types] = SQLParserUtils::expandListParameters($query, $params, $types); $stmt = $connection->prepare($query); if ($types) { $this->_bindTypedValues($stmt, $params, $types); $stmt->execute(); } else { $stmt->execute($params); } } else { $stmt = $connection->query($query); } } catch (Throwable $ex) { throw DBALException::driverExceptionDuringQuery($this->_driver, $ex, $query, $this->resolveParams($params, $types)); } $stmt->setFetchMode($this->defaultFetchMode); if ($logger) { $logger->stopQuery(); } return $stmt; } /** * Executes a caching query. * * @param string $query The SQL query to execute. * @param mixed[] $params The parameters to bind to the query, if any. * @param int[]|string[] $types The types the previous parameters are in. * @param QueryCacheProfile $qcp The query cache profile. * * @return ResultStatement * * @throws CacheException */ public function executeCacheQuery($query, $params, $types, QueryCacheProfile $qcp) { $resultCache = $qcp->getResultCacheDriver() ?? $this->_config->getResultCacheImpl(); if ($resultCache === null) { throw CacheException::noResultDriverConfigured(); } $connectionParams = $this->getParams(); unset($connectionParams['platform']); [$cacheKey, $realKey] = $qcp->generateCacheKeys($query, $params, $types, $connectionParams); // fetch the row pointers entry $data = $resultCache->fetch($cacheKey); if ($data !== false) { // is the real key part of this row pointers map or is the cache only pointing to other cache keys? if (isset($data[$realKey])) { $stmt = new ArrayStatement($data[$realKey]); } elseif (array_key_exists($realKey, $data)) { $stmt = new ArrayStatement([]); } } if (! isset($stmt)) { $stmt = new ResultCacheStatement($this->executeQuery($query, $params, $types), $resultCache, $cacheKey, $realKey, $qcp->getLifetime()); } $stmt->setFetchMode($this->defaultFetchMode); return $stmt; } /** * Executes an, optionally parametrized, SQL query and returns the result, * applying a given projection/transformation function on each row of the result. * * @param string $query The SQL query to execute. * @param mixed[] $params The parameters, if any. * @param Closure $function The transformation function that is applied on each row. * The function receives a single parameter, an array, that * represents a row of the result set. * * @return mixed[] The projected result of the query. */ public function project($query, array $params, Closure $function) { $result = []; $stmt = $this->executeQuery($query, $params); while ($row = $stmt->fetch()) { $result[] = $function($row); } $stmt->closeCursor(); return $result; } /** * Executes an SQL statement, returning a result set as a Statement object. * * @return \Doctrine\DBAL\Driver\Statement * * @throws DBALException */ public function query() { $connection = $this->getWrappedConnection(); $args = func_get_args(); $logger = $this->_config->getSQLLogger(); if ($logger) { $logger->startQuery($args[0]); } try { $statement = $connection->query(...$args); } catch (Throwable $ex) { throw DBALException::driverExceptionDuringQuery($this->_driver, $ex, $args[0]); } $statement->setFetchMode($this->defaultFetchMode); if ($logger) { $logger->stopQuery(); } return $statement; } /** * Executes an SQL INSERT/UPDATE/DELETE query with the given parameters * and returns the number of affected rows. * * This method supports PDO binding types as well as DBAL mapping types. * * @param string $query The SQL query. * @param mixed[] $params The query parameters. * @param int[]|string[] $types The parameter types. * * @return int The number of affected rows. * * @throws DBALException */ public function executeUpdate($query, array $params = [], array $types = []) { $connection = $this->getWrappedConnection(); $logger = $this->_config->getSQLLogger(); if ($logger) { $logger->startQuery($query, $params, $types); } try { if ($params) { [$query, $params, $types] = SQLParserUtils::expandListParameters($query, $params, $types); $stmt = $connection->prepare($query); if ($types) { $this->_bindTypedValues($stmt, $params, $types); $stmt->execute(); } else { $stmt->execute($params); } $result = $stmt->rowCount(); } else { $result = $connection->exec($query); } } catch (Throwable $ex) { throw DBALException::driverExceptionDuringQuery($this->_driver, $ex, $query, $this->resolveParams($params, $types)); } if ($logger) { $logger->stopQuery(); } return $result; } /** * Executes an SQL statement and return the number of affected rows. * * @param string $statement * * @return int The number of affected rows. * * @throws DBALException */ public function exec($statement) { $connection = $this->getWrappedConnection(); $logger = $this->_config->getSQLLogger(); if ($logger) { $logger->startQuery($statement); } try { $result = $connection->exec($statement); } catch (Throwable $ex) { throw DBALException::driverExceptionDuringQuery($this->_driver, $ex, $statement); } if ($logger) { $logger->stopQuery(); } return $result; } /** * Returns the current transaction nesting level. * * @return int The nesting level. A value of 0 means there's no active transaction. */ public function getTransactionNestingLevel() { return $this->transactionNestingLevel; } /** * Fetches the SQLSTATE associated with the last database operation. * * @return string|null The last error code. */ public function errorCode() { return $this->getWrappedConnection()->errorCode(); } /** * {@inheritDoc} */ public function errorInfo() { return $this->getWrappedConnection()->errorInfo(); } /** * Returns the ID of the last inserted row, or the last value from a sequence object, * depending on the underlying driver. * * Note: This method may not return a meaningful or consistent result across different drivers, * because the underlying database may not even support the notion of AUTO_INCREMENT/IDENTITY * columns or sequences. * * @param string|null $seqName Name of the sequence object from which the ID should be returned. * * @return string A string representation of the last inserted ID. */ public function lastInsertId($seqName = null) { return $this->getWrappedConnection()->lastInsertId($seqName); } /** * Executes a function in a transaction. * * The function gets passed this Connection instance as an (optional) parameter. * * If an exception occurs during execution of the function or transaction commit, * the transaction is rolled back and the exception re-thrown. * * @param Closure $func The function to execute transactionally. * * @return mixed The value returned by $func * * @throws Exception * @throws Throwable */ public function transactional(Closure $func) { $this->beginTransaction(); try { $res = $func($this); $this->commit(); return $res; } catch (Exception $e) { $this->rollBack(); throw $e; } catch (Throwable $e) { $this->rollBack(); throw $e; } } /** * Sets if nested transactions should use savepoints. * * @param bool $nestTransactionsWithSavepoints * * @return void * * @throws ConnectionException */ public function setNestTransactionsWithSavepoints($nestTransactionsWithSavepoints) { if ($this->transactionNestingLevel > 0) { throw ConnectionException::mayNotAlterNestedTransactionWithSavepointsInTransaction(); } if (! $this->getDatabasePlatform()->supportsSavepoints()) { throw ConnectionException::savepointsNotSupported(); } $this->nestTransactionsWithSavepoints = (bool) $nestTransactionsWithSavepoints; } /** * Gets if nested transactions should use savepoints. * * @return bool */ public function getNestTransactionsWithSavepoints() { return $this->nestTransactionsWithSavepoints; } /** * Returns the savepoint name to use for nested transactions are false if they are not supported * "savepointFormat" parameter is not set * * @return mixed A string with the savepoint name or false. */ protected function _getNestedTransactionSavePointName() { return 'DOCTRINE2_SAVEPOINT_' . $this->transactionNestingLevel; } /** * {@inheritDoc} */ public function beginTransaction() { $connection = $this->getWrappedConnection(); ++$this->transactionNestingLevel; $logger = $this->_config->getSQLLogger(); if ($this->transactionNestingLevel === 1) { if ($logger) { $logger->startQuery('"START TRANSACTION"'); } $connection->beginTransaction(); if ($logger) { $logger->stopQuery(); } } elseif ($this->nestTransactionsWithSavepoints) { if ($logger) { $logger->startQuery('"SAVEPOINT"'); } $this->createSavepoint($this->_getNestedTransactionSavePointName()); if ($logger) { $logger->stopQuery(); } } return true; } /** * {@inheritDoc} * * @throws ConnectionException If the commit failed due to no active transaction or * because the transaction was marked for rollback only. */ public function commit() { if ($this->transactionNestingLevel === 0) { throw ConnectionException::noActiveTransaction(); } if ($this->isRollbackOnly) { throw ConnectionException::commitFailedRollbackOnly(); } $result = true; $connection = $this->getWrappedConnection(); $logger = $this->_config->getSQLLogger(); if ($this->transactionNestingLevel === 1) { if ($logger) { $logger->startQuery('"COMMIT"'); } $result = $connection->commit(); if ($logger) { $logger->stopQuery(); } } elseif ($this->nestTransactionsWithSavepoints) { if ($logger) { $logger->startQuery('"RELEASE SAVEPOINT"'); } $this->releaseSavepoint($this->_getNestedTransactionSavePointName()); if ($logger) { $logger->stopQuery(); } } --$this->transactionNestingLevel; if ($this->autoCommit !== false || $this->transactionNestingLevel !== 0) { return $result; } $this->beginTransaction(); return $result; } /** * Commits all current nesting transactions. */ private function commitAll() { while ($this->transactionNestingLevel !== 0) { if ($this->autoCommit === false && $this->transactionNestingLevel === 1) { // When in no auto-commit mode, the last nesting commit immediately starts a new transaction. // Therefore we need to do the final commit here and then leave to avoid an infinite loop. $this->commit(); return; } $this->commit(); } } /** * Cancels any database changes done during the current transaction. * * @throws ConnectionException If the rollback operation failed. */ public function rollBack() { if ($this->transactionNestingLevel === 0) { throw ConnectionException::noActiveTransaction(); } $connection = $this->getWrappedConnection(); $logger = $this->_config->getSQLLogger(); if ($this->transactionNestingLevel === 1) { if ($logger) { $logger->startQuery('"ROLLBACK"'); } $this->transactionNestingLevel = 0; $connection->rollBack(); $this->isRollbackOnly = false; if ($logger) { $logger->stopQuery(); } if ($this->autoCommit === false) { $this->beginTransaction(); } } elseif ($this->nestTransactionsWithSavepoints) { if ($logger) { $logger->startQuery('"ROLLBACK TO SAVEPOINT"'); } $this->rollbackSavepoint($this->_getNestedTransactionSavePointName()); --$this->transactionNestingLevel; if ($logger) { $logger->stopQuery(); } } else { $this->isRollbackOnly = true; --$this->transactionNestingLevel; } } /** * Creates a new savepoint. * * @param string $savepoint The name of the savepoint to create. * * @return void * * @throws ConnectionException */ public function createSavepoint($savepoint) { if (! $this->getDatabasePlatform()->supportsSavepoints()) { throw ConnectionException::savepointsNotSupported(); } $this->getWrappedConnection()->exec($this->platform->createSavePoint($savepoint)); } /** * Releases the given savepoint. * * @param string $savepoint The name of the savepoint to release. * * @return void * * @throws ConnectionException */ public function releaseSavepoint($savepoint) { if (! $this->getDatabasePlatform()->supportsSavepoints()) { throw ConnectionException::savepointsNotSupported(); } if (! $this->platform->supportsReleaseSavepoints()) { return; } $this->getWrappedConnection()->exec($this->platform->releaseSavePoint($savepoint)); } /** * Rolls back to the given savepoint. * * @param string $savepoint The name of the savepoint to rollback to. * * @return void * * @throws ConnectionException */ public function rollbackSavepoint($savepoint) { if (! $this->getDatabasePlatform()->supportsSavepoints()) { throw ConnectionException::savepointsNotSupported(); } $this->getWrappedConnection()->exec($this->platform->rollbackSavePoint($savepoint)); } /** * Gets the wrapped driver connection. * * @return DriverConnection */ public function getWrappedConnection() { $this->connect(); return $this->_conn; } /** * Gets the SchemaManager that can be used to inspect or change the * database schema through the connection. * * @return AbstractSchemaManager */ public function getSchemaManager() { if ($this->_schemaManager === null) { $this->_schemaManager = $this->_driver->getSchemaManager($this); } return $this->_schemaManager; } /** * Marks the current transaction so that the only possible * outcome for the transaction to be rolled back. * * @return void * * @throws ConnectionException If no transaction is active. */ public function setRollbackOnly() { if ($this->transactionNestingLevel === 0) { throw ConnectionException::noActiveTransaction(); } $this->isRollbackOnly = true; } /** * Checks whether the current transaction is marked for rollback only. * * @return bool * * @throws ConnectionException If no transaction is active. */ public function isRollbackOnly() { if ($this->transactionNestingLevel === 0) { throw ConnectionException::noActiveTransaction(); } return $this->isRollbackOnly; } /** * Converts a given value to its database representation according to the conversion * rules of a specific DBAL mapping type. * * @param mixed $value The value to convert. * @param string $type The name of the DBAL mapping type. * * @return mixed The converted value. */ public function convertToDatabaseValue($value, $type) { return Type::getType($type)->convertToDatabaseValue($value, $this->getDatabasePlatform()); } /** * Converts a given value to its PHP representation according to the conversion * rules of a specific DBAL mapping type. * * @param mixed $value The value to convert. * @param string $type The name of the DBAL mapping type. * * @return mixed The converted type. */ public function convertToPHPValue($value, $type) { return Type::getType($type)->convertToPHPValue($value, $this->getDatabasePlatform()); } /** * Binds a set of parameters, some or all of which are typed with a PDO binding type * or DBAL mapping type, to a given statement. * * @internal Duck-typing used on the $stmt parameter to support driver statements as well as * raw PDOStatement instances. * * @param \Doctrine\DBAL\Driver\Statement $stmt The statement to bind the values to. * @param mixed[] $params The map/list of named/positional parameters. * @param int[]|string[] $types The parameter types (PDO binding types or DBAL mapping types). * * @return void */ private function _bindTypedValues($stmt, array $params, array $types) { // Check whether parameters are positional or named. Mixing is not allowed, just like in PDO. if (is_int(key($params))) { // Positional parameters $typeOffset = array_key_exists(0, $types) ? -1 : 0; $bindIndex = 1; foreach ($params as $value) { $typeIndex = $bindIndex + $typeOffset; if (isset($types[$typeIndex])) { $type = $types[$typeIndex]; [$value, $bindingType] = $this->getBindingInfo($value, $type); $stmt->bindValue($bindIndex, $value, $bindingType); } else { $stmt->bindValue($bindIndex, $value); } ++$bindIndex; } } else { // Named parameters foreach ($params as $name => $value) { if (isset($types[$name])) { $type = $types[$name]; [$value, $bindingType] = $this->getBindingInfo($value, $type); $stmt->bindValue($name, $value, $bindingType); } else { $stmt->bindValue($name, $value); } } } } /** * Gets the binding type of a given type. The given type can be a PDO or DBAL mapping type. * * @param mixed $value The value to bind. * @param int|string|null $type The type to bind (PDO or DBAL). * * @return mixed[] [0] => the (escaped) value, [1] => the binding type. */ private function getBindingInfo($value, $type) { if (is_string($type)) { $type = Type::getType($type); } if ($type instanceof Type) { $value = $type->convertToDatabaseValue($value, $this->getDatabasePlatform()); $bindingType = $type->getBindingType(); } else { $bindingType = $type; } return [$value, $bindingType]; } /** * Resolves the parameters to a format which can be displayed. * * @internal This is a purely internal method. If you rely on this method, you are advised to * copy/paste the code as this method may change, or be removed without prior notice. * * @param mixed[] $params * @param int[]|string[] $types * * @return mixed[] */ public function resolveParams(array $params, array $types) { $resolvedParams = []; // Check whether parameters are positional or named. Mixing is not allowed, just like in PDO. if (is_int(key($params))) { // Positional parameters $typeOffset = array_key_exists(0, $types) ? -1 : 0; $bindIndex = 1; foreach ($params as $value) { $typeIndex = $bindIndex + $typeOffset; if (isset($types[$typeIndex])) { $type = $types[$typeIndex]; [$value] = $this->getBindingInfo($value, $type); $resolvedParams[$bindIndex] = $value; } else { $resolvedParams[$bindIndex] = $value; } ++$bindIndex; } } else { // Named parameters foreach ($params as $name => $value) { if (isset($types[$name])) { $type = $types[$name]; [$value] = $this->getBindingInfo($value, $type); $resolvedParams[$name] = $value; } else { $resolvedParams[$name] = $value; } } } return $resolvedParams; } /** * Creates a new instance of a SQL query builder. * * @return QueryBuilder */ public function createQueryBuilder() { return new Query\QueryBuilder($this); } /** * Ping the server * * When the server is not available the method returns FALSE. * It is responsibility of the developer to handle this case * and abort the request or reconnect manually: * * @return bool * * @example * * if ($conn->ping() === false) { * $conn->close(); * $conn->connect(); * } * * It is undefined if the underlying driver attempts to reconnect * or disconnect when the connection is not available anymore * as long it returns TRUE when a reconnect succeeded and * FALSE when the connection was dropped. */ public function ping() { $connection = $this->getWrappedConnection(); if ($connection instanceof PingableConnection) { return $connection->ping(); } try { $this->query($this->getDatabasePlatform()->getDummySelectSQL()); return true; } catch (DBALException $e) { return false; } } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/ConnectionException.php000066400000000000000000000017551360544566000246160ustar00rootroot00000000000000executeQuery("DELETE FROM table"); * * Be aware that Connection#executeQuery is a method specifically for READ * operations only. * * This connection is limited to slave operations using the * Connection#executeQuery operation only, because it wouldn't be compatible * with the ORM or SchemaManager code otherwise. Both use all the other * operations in a context where writes could happen to a slave, which makes * this restricted approach necessary. * * You can manually connect to the master at any time by calling: * * $conn->connect('master'); * * Instantiation through the DriverManager looks like: * * @example * * $conn = DriverManager::getConnection(array( * 'wrapperClass' => 'Doctrine\DBAL\Connections\MasterSlaveConnection', * 'driver' => 'pdo_mysql', * 'master' => array('user' => '', 'password' => '', 'host' => '', 'dbname' => ''), * 'slaves' => array( * array('user' => 'slave1', 'password', 'host' => '', 'dbname' => ''), * array('user' => 'slave2', 'password', 'host' => '', 'dbname' => ''), * ) * )); * * You can also pass 'driverOptions' and any other documented option to each of this drivers to pass additional information. */ class MasterSlaveConnection extends Connection { /** * Master and slave connection (one of the randomly picked slaves). * * @var DriverConnection[]|null[] */ protected $connections = ['master' => null, 'slave' => null]; /** * You can keep the slave connection and then switch back to it * during the request if you know what you are doing. * * @var bool */ protected $keepSlave = false; /** * Creates Master Slave Connection. * * @param mixed[] $params * * @throws InvalidArgumentException */ public function __construct(array $params, Driver $driver, ?Configuration $config = null, ?EventManager $eventManager = null) { if (! isset($params['slaves'], $params['master'])) { throw new InvalidArgumentException('master or slaves configuration missing'); } if (count($params['slaves']) === 0) { throw new InvalidArgumentException('You have to configure at least one slaves.'); } $params['master']['driver'] = $params['driver']; foreach ($params['slaves'] as $slaveKey => $slave) { $params['slaves'][$slaveKey]['driver'] = $params['driver']; } $this->keepSlave = (bool) ($params['keepSlave'] ?? false); parent::__construct($params, $driver, $config, $eventManager); } /** * Checks if the connection is currently towards the master or not. * * @return bool */ public function isConnectedToMaster() { return $this->_conn !== null && $this->_conn === $this->connections['master']; } /** * {@inheritDoc} */ public function connect($connectionName = null) { $requestedConnectionChange = ($connectionName !== null); $connectionName = $connectionName ?: 'slave'; if ($connectionName !== 'slave' && $connectionName !== 'master') { throw new InvalidArgumentException('Invalid option to connect(), only master or slave allowed.'); } // If we have a connection open, and this is not an explicit connection // change request, then abort right here, because we are already done. // This prevents writes to the slave in case of "keepSlave" option enabled. if ($this->_conn !== null && ! $requestedConnectionChange) { return false; } $forceMasterAsSlave = false; if ($this->getTransactionNestingLevel() > 0) { $connectionName = 'master'; $forceMasterAsSlave = true; } if (isset($this->connections[$connectionName])) { $this->_conn = $this->connections[$connectionName]; if ($forceMasterAsSlave && ! $this->keepSlave) { $this->connections['slave'] = $this->_conn; } return false; } if ($connectionName === 'master') { $this->connections['master'] = $this->_conn = $this->connectTo($connectionName); // Set slave connection to master to avoid invalid reads if (! $this->keepSlave) { $this->connections['slave'] = $this->connections['master']; } } else { $this->connections['slave'] = $this->_conn = $this->connectTo($connectionName); } if ($this->_eventManager->hasListeners(Events::postConnect)) { $eventArgs = new ConnectionEventArgs($this); $this->_eventManager->dispatchEvent(Events::postConnect, $eventArgs); } return true; } /** * Connects to a specific connection. * * @param string $connectionName * * @return DriverConnection */ protected function connectTo($connectionName) { $params = $this->getParams(); $driverOptions = $params['driverOptions'] ?? []; $connectionParams = $this->chooseConnectionConfiguration($connectionName, $params); $user = $connectionParams['user'] ?? null; $password = $connectionParams['password'] ?? null; return $this->_driver->connect($connectionParams, $user, $password, $driverOptions); } /** * @param string $connectionName * @param mixed[] $params * * @return mixed */ protected function chooseConnectionConfiguration($connectionName, $params) { if ($connectionName === 'master') { return $params['master']; } $config = $params['slaves'][array_rand($params['slaves'])]; if (! isset($config['charset']) && isset($params['master']['charset'])) { $config['charset'] = $params['master']['charset']; } return $config; } /** * {@inheritDoc} */ public function executeUpdate($query, array $params = [], array $types = []) { $this->connect('master'); return parent::executeUpdate($query, $params, $types); } /** * {@inheritDoc} */ public function beginTransaction() { $this->connect('master'); return parent::beginTransaction(); } /** * {@inheritDoc} */ public function commit() { $this->connect('master'); return parent::commit(); } /** * {@inheritDoc} */ public function rollBack() { $this->connect('master'); return parent::rollBack(); } /** * {@inheritDoc} */ public function delete($tableName, array $identifier, array $types = []) { $this->connect('master'); return parent::delete($tableName, $identifier, $types); } /** * {@inheritDoc} */ public function close() { unset($this->connections['master'], $this->connections['slave']); parent::close(); $this->_conn = null; $this->connections = ['master' => null, 'slave' => null]; } /** * {@inheritDoc} */ public function update($tableName, array $data, array $identifier, array $types = []) { $this->connect('master'); return parent::update($tableName, $data, $identifier, $types); } /** * {@inheritDoc} */ public function insert($tableName, array $data, array $types = []) { $this->connect('master'); return parent::insert($tableName, $data, $types); } /** * {@inheritDoc} */ public function exec($statement) { $this->connect('master'); return parent::exec($statement); } /** * {@inheritDoc} */ public function createSavepoint($savepoint) { $this->connect('master'); parent::createSavepoint($savepoint); } /** * {@inheritDoc} */ public function releaseSavepoint($savepoint) { $this->connect('master'); parent::releaseSavepoint($savepoint); } /** * {@inheritDoc} */ public function rollbackSavepoint($savepoint) { $this->connect('master'); parent::rollbackSavepoint($savepoint); } /** * {@inheritDoc} */ public function query() { $this->connect('master'); assert($this->_conn instanceof DriverConnection); $args = func_get_args(); $logger = $this->getConfiguration()->getSQLLogger(); if ($logger) { $logger->startQuery($args[0]); } $statement = $this->_conn->query(...$args); $statement->setFetchMode($this->defaultFetchMode); if ($logger) { $logger->stopQuery(); } return $statement; } /** * {@inheritDoc} */ public function prepare($statement) { $this->connect('master'); return parent::prepare($statement); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/DBALException.php000066400000000000000000000215101360544566000232100ustar00rootroot00000000000000getMessage(); return static::wrapException($driver, $driverEx, $msg); } /** * @return self */ public static function driverException(Driver $driver, Throwable $driverEx) { return static::wrapException($driver, $driverEx, 'An exception occurred in driver: ' . $driverEx->getMessage()); } /** * @return self */ private static function wrapException(Driver $driver, Throwable $driverEx, $msg) { if ($driverEx instanceof DriverException) { return $driverEx; } if ($driver instanceof ExceptionConverterDriver && $driverEx instanceof DriverExceptionInterface) { return $driver->convertException($msg, $driverEx); } return new self($msg, 0, $driverEx); } /** * Returns a human-readable representation of an array of parameters. * This properly handles binary data by returning a hex representation. * * @param mixed[] $params * * @return string */ private static function formatParameters(array $params) { return '[' . implode(', ', array_map(static function ($param) { if (is_resource($param)) { return (string) $param; } $json = @json_encode($param); if (! is_string($json) || $json === 'null' && is_string($param)) { // JSON encoding failed, this is not a UTF-8 string. return sprintf('"%s"', preg_replace('/.{2}/', '\\x$0', bin2hex($param))); } return $json; }, $params)) . ']'; } /** * @param string $wrapperClass * * @return \Doctrine\DBAL\DBALException */ public static function invalidWrapperClass($wrapperClass) { return new self("The given 'wrapperClass' " . $wrapperClass . ' has to be a ' . 'subtype of \Doctrine\DBAL\Connection.'); } /** * @param string $driverClass * * @return \Doctrine\DBAL\DBALException */ public static function invalidDriverClass($driverClass) { return new self("The given 'driverClass' " . $driverClass . ' has to implement the ' . Driver::class . ' interface.'); } /** * @param string $tableName * * @return \Doctrine\DBAL\DBALException */ public static function invalidTableName($tableName) { return new self('Invalid table name specified: ' . $tableName); } /** * @param string $tableName * * @return \Doctrine\DBAL\DBALException */ public static function noColumnsSpecifiedForTable($tableName) { return new self('No columns specified for table ' . $tableName); } /** * @return \Doctrine\DBAL\DBALException */ public static function limitOffsetInvalid() { return new self('Invalid Offset in Limit Query, it has to be larger than or equal to 0.'); } /** * @param string $name * * @return \Doctrine\DBAL\DBALException */ public static function typeExists($name) { return new self('Type ' . $name . ' already exists.'); } /** * @param string $name * * @return \Doctrine\DBAL\DBALException */ public static function unknownColumnType($name) { return new self('Unknown column type "' . $name . '" requested. Any Doctrine type that you use has ' . 'to be registered with \Doctrine\DBAL\Types\Type::addType(). You can get a list of all the ' . 'known types with \Doctrine\DBAL\Types\Type::getTypesMap(). If this error occurs during database ' . 'introspection then you might have forgotten to register all database types for a Doctrine Type. Use ' . 'AbstractPlatform#registerDoctrineTypeMapping() or have your custom types implement ' . 'Type#getMappedDatabaseTypes(). If the type name is empty you might ' . 'have a problem with the cache or forgot some mapping information.'); } /** * @param string $name * * @return \Doctrine\DBAL\DBALException */ public static function typeNotFound($name) { return new self('Type to be overwritten ' . $name . ' does not exist.'); } public static function typeNotRegistered(Type $type) : self { return new self(sprintf('Type of the class %s@%s is not registered.', get_class($type), spl_object_hash($type))); } public static function typeAlreadyRegistered(Type $type) : self { return new self( sprintf('Type of the class %s@%s is already registered.', get_class($type), spl_object_hash($type)) ); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver.php000066400000000000000000000034131360544566000220640ustar00rootroot00000000000000getParams(); return $params['dbname']; } /** * {@inheritdoc} */ public function getDatabasePlatform() { return new DB2Platform(); } /** * {@inheritdoc} */ public function getSchemaManager(Connection $conn) { return new DB2SchemaManager($conn); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/AbstractDriverException.php000066400000000000000000000022131360544566000266570ustar00rootroot00000000000000errorCode = $errorCode; $this->sqlState = $sqlState; } /** * {@inheritdoc} */ public function getErrorCode() { return $this->errorCode; } /** * {@inheritdoc} */ public function getSQLState() { return $this->sqlState; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/AbstractMySQLDriver.php000066400000000000000000000151271360544566000256760ustar00rootroot00000000000000getErrorCode()) { case '1213': return new Exception\DeadlockException($message, $exception); case '1205': return new Exception\LockWaitTimeoutException($message, $exception); case '1050': return new Exception\TableExistsException($message, $exception); case '1051': case '1146': return new Exception\TableNotFoundException($message, $exception); case '1216': case '1217': case '1451': case '1452': case '1701': return new Exception\ForeignKeyConstraintViolationException($message, $exception); case '1062': case '1557': case '1569': case '1586': return new Exception\UniqueConstraintViolationException($message, $exception); case '1054': case '1166': case '1611': return new Exception\InvalidFieldNameException($message, $exception); case '1052': case '1060': case '1110': return new Exception\NonUniqueFieldNameException($message, $exception); case '1064': case '1149': case '1287': case '1341': case '1342': case '1343': case '1344': case '1382': case '1479': case '1541': case '1554': case '1626': return new Exception\SyntaxErrorException($message, $exception); case '1044': case '1045': case '1046': case '1049': case '1095': case '1142': case '1143': case '1227': case '1370': case '1429': case '2002': case '2005': return new Exception\ConnectionException($message, $exception); case '1048': case '1121': case '1138': case '1171': case '1252': case '1263': case '1364': case '1566': return new Exception\NotNullConstraintViolationException($message, $exception); } return new Exception\DriverException($message, $exception); } /** * {@inheritdoc} * * @throws DBALException */ public function createDatabasePlatformForVersion($version) { $mariadb = stripos($version, 'mariadb') !== false; if ($mariadb && version_compare($this->getMariaDbMysqlVersionNumber($version), '10.2.7', '>=')) { return new MariaDb1027Platform(); } if (! $mariadb) { $oracleMysqlVersion = $this->getOracleMysqlVersionNumber($version); if (version_compare($oracleMysqlVersion, '8', '>=')) { return new MySQL80Platform(); } if (version_compare($oracleMysqlVersion, '5.7.9', '>=')) { return new MySQL57Platform(); } } return $this->getDatabasePlatform(); } /** * Get a normalized 'version number' from the server string * returned by Oracle MySQL servers. * * @param string $versionString Version string returned by the driver, i.e. '5.7.10' * * @throws DBALException */ private function getOracleMysqlVersionNumber(string $versionString) : string { if (! preg_match( '/^(?P\d+)(?:\.(?P\d+)(?:\.(?P\d+))?)?/', $versionString, $versionParts )) { throw DBALException::invalidPlatformVersionSpecified( $versionString, '..' ); } $majorVersion = $versionParts['major']; $minorVersion = $versionParts['minor'] ?? 0; $patchVersion = $versionParts['patch'] ?? null; if ($majorVersion === '5' && $minorVersion === '7' && $patchVersion === null) { $patchVersion = '9'; } return $majorVersion . '.' . $minorVersion . '.' . $patchVersion; } /** * Detect MariaDB server version, including hack for some mariadb distributions * that starts with the prefix '5.5.5-' * * @param string $versionString Version string as returned by mariadb server, i.e. '5.5.5-Mariadb-10.0.8-xenial' * * @throws DBALException */ private function getMariaDbMysqlVersionNumber(string $versionString) : string { if (! preg_match( '/^(?:5\.5\.5-)?(mariadb-)?(?P\d+)\.(?P\d+)\.(?P\d+)/i', $versionString, $versionParts )) { throw DBALException::invalidPlatformVersionSpecified( $versionString, '^(?:5\.5\.5-)?(mariadb-)?..' ); } return $versionParts['major'] . '.' . $versionParts['minor'] . '.' . $versionParts['patch']; } /** * {@inheritdoc} */ public function getDatabase(Connection $conn) { $params = $conn->getParams(); return $params['dbname'] ?? $conn->query('SELECT DATABASE()')->fetchColumn(); } /** * {@inheritdoc} * * @return MySqlPlatform */ public function getDatabasePlatform() { return new MySqlPlatform(); } /** * {@inheritdoc} * * @return MySqlSchemaManager */ public function getSchemaManager(Connection $conn) { return new MySqlSchemaManager($conn); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/AbstractOracleDriver.php000066400000000000000000000052341360544566000261340ustar00rootroot00000000000000getErrorCode()) { case '1': case '2299': case '38911': return new Exception\UniqueConstraintViolationException($message, $exception); case '904': return new Exception\InvalidFieldNameException($message, $exception); case '918': case '960': return new Exception\NonUniqueFieldNameException($message, $exception); case '923': return new Exception\SyntaxErrorException($message, $exception); case '942': return new Exception\TableNotFoundException($message, $exception); case '955': return new Exception\TableExistsException($message, $exception); case '1017': case '12545': return new Exception\ConnectionException($message, $exception); case '1400': return new Exception\NotNullConstraintViolationException($message, $exception); case '2266': case '2291': case '2292': return new Exception\ForeignKeyConstraintViolationException($message, $exception); } return new Exception\DriverException($message, $exception); } /** * {@inheritdoc} */ public function getDatabase(Connection $conn) { $params = $conn->getParams(); return $params['user']; } /** * {@inheritdoc} */ public function getDatabasePlatform() { return new OraclePlatform(); } /** * {@inheritdoc} */ public function getSchemaManager(Connection $conn) { return new OracleSchemaManager($conn); } /** * Returns an appropriate Easy Connect String for the given parameters. * * @param mixed[] $params The connection parameters to return the Easy Connect String for. * * @return string */ protected function getEasyConnectString(array $params) { return (string) EasyConnectString::fromConnectionParameters($params); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/AbstractOracleDriver/000077500000000000000000000000001360544566000254175ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/AbstractOracleDriver/EasyConnectString.php000066400000000000000000000053511360544566000315360ustar00rootroot00000000000000string = $string; } public function __toString() : string { return $this->string; } /** * Creates the object from an array representation * * @param mixed[] $params */ public static function fromArray(array $params) : self { return new self(self::renderParams($params)); } /** * Creates the object from the given DBAL connection parameters. * * @param mixed[] $params */ public static function fromConnectionParameters(array $params) : self { if (! empty($params['connectstring'])) { return new self($params['connectstring']); } if (empty($params['host'])) { return new self($params['dbname'] ?? ''); } $connectData = []; if (isset($params['servicename']) || isset($params['dbname'])) { $serviceKey = 'SID'; if (! empty($params['service'])) { $serviceKey = 'SERVICE_NAME'; } $serviceName = $params['servicename'] ?? $params['dbname']; $connectData[$serviceKey] = $serviceName; } if (! empty($params['instancename'])) { $connectData['INSTANCE_NAME'] = $params['instancename']; } if (! empty($params['pooled'])) { $connectData['SERVER'] = 'POOLED'; } return self::fromArray([ 'DESCRIPTION' => [ 'ADDRESS' => [ 'PROTOCOL' => 'TCP', 'HOST' => $params['host'], 'PORT' => $params['port'] ?? 1521, ], 'CONNECT_DATA' => $connectData, ], ]); } /** * @param mixed[] $params */ private static function renderParams(array $params) : string { $chunks = []; foreach ($params as $key => $value) { $string = self::renderValue($value); if ($string === '') { continue; } $chunks[] = sprintf('(%s=%s)', $key, $string); } return implode('', $chunks); } /** * @param mixed $value */ private static function renderValue($value) : string { if (is_array($value)) { return self::renderParams($value); } return (string) $value; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/AbstractPostgreSQLDriver.php000066400000000000000000000113271360544566000267320ustar00rootroot00000000000000getSQLState()) { case '40001': case '40P01': return new Exception\DeadlockException($message, $exception); case '0A000': // Foreign key constraint violations during a TRUNCATE operation // are considered "feature not supported" in PostgreSQL. if (strpos($exception->getMessage(), 'truncate') !== false) { return new Exception\ForeignKeyConstraintViolationException($message, $exception); } break; case '23502': return new Exception\NotNullConstraintViolationException($message, $exception); case '23503': return new Exception\ForeignKeyConstraintViolationException($message, $exception); case '23505': return new Exception\UniqueConstraintViolationException($message, $exception); case '42601': return new Exception\SyntaxErrorException($message, $exception); case '42702': return new Exception\NonUniqueFieldNameException($message, $exception); case '42703': return new Exception\InvalidFieldNameException($message, $exception); case '42P01': return new Exception\TableNotFoundException($message, $exception); case '42P07': return new Exception\TableExistsException($message, $exception); case '7': // In some case (mainly connection errors) the PDO exception does not provide a SQLSTATE via its code. // The exception code is always set to 7 here. // We have to match against the SQLSTATE in the error message in these cases. if (strpos($exception->getMessage(), 'SQLSTATE[08006]') !== false) { return new Exception\ConnectionException($message, $exception); } break; } return new Exception\DriverException($message, $exception); } /** * {@inheritdoc} */ public function createDatabasePlatformForVersion($version) { if (! preg_match('/^(?P\d+)(?:\.(?P\d+)(?:\.(?P\d+))?)?/', $version, $versionParts)) { throw DBALException::invalidPlatformVersionSpecified( $version, '..' ); } $majorVersion = $versionParts['major']; $minorVersion = $versionParts['minor'] ?? 0; $patchVersion = $versionParts['patch'] ?? 0; $version = $majorVersion . '.' . $minorVersion . '.' . $patchVersion; switch (true) { case version_compare($version, '10.0', '>='): return new PostgreSQL100Platform(); case version_compare($version, '9.4', '>='): return new PostgreSQL94Platform(); case version_compare($version, '9.2', '>='): return new PostgreSQL92Platform(); case version_compare($version, '9.1', '>='): return new PostgreSQL91Platform(); default: return new PostgreSqlPlatform(); } } /** * {@inheritdoc} */ public function getDatabase(Connection $conn) { $params = $conn->getParams(); return $params['dbname'] ?? $conn->query('SELECT CURRENT_DATABASE()')->fetchColumn(); } /** * {@inheritdoc} */ public function getDatabasePlatform() { return new PostgreSqlPlatform(); } /** * {@inheritdoc} */ public function getSchemaManager(Connection $conn) { return new PostgreSqlSchemaManager($conn); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/AbstractSQLAnywhereDriver.php000066400000000000000000000103501360544566000270640ustar00rootroot00000000000000getErrorCode()) { case '-306': case '-307': case '-684': return new Exception\DeadlockException($message, $exception); case '-210': case '-1175': case '-1281': return new Exception\LockWaitTimeoutException($message, $exception); case '-100': case '-103': case '-832': return new Exception\ConnectionException($message, $exception); case '-143': return new Exception\InvalidFieldNameException($message, $exception); case '-193': case '-196': return new Exception\UniqueConstraintViolationException($message, $exception); case '-194': case '-198': return new Exception\ForeignKeyConstraintViolationException($message, $exception); case '-144': return new Exception\NonUniqueFieldNameException($message, $exception); case '-184': case '-195': return new Exception\NotNullConstraintViolationException($message, $exception); case '-131': return new Exception\SyntaxErrorException($message, $exception); case '-110': return new Exception\TableExistsException($message, $exception); case '-141': case '-1041': return new Exception\TableNotFoundException($message, $exception); } return new Exception\DriverException($message, $exception); } /** * {@inheritdoc} */ public function createDatabasePlatformForVersion($version) { if (! preg_match( '/^(?P\d+)(?:\.(?P\d+)(?:\.(?P\d+)(?:\.(?P\d+))?)?)?/', $version, $versionParts )) { throw DBALException::invalidPlatformVersionSpecified( $version, '...' ); } $majorVersion = $versionParts['major']; $minorVersion = $versionParts['minor'] ?? 0; $patchVersion = $versionParts['patch'] ?? 0; $buildVersion = $versionParts['build'] ?? 0; $version = $majorVersion . '.' . $minorVersion . '.' . $patchVersion . '.' . $buildVersion; switch (true) { case version_compare($version, '16', '>='): return new SQLAnywhere16Platform(); case version_compare($version, '12', '>='): return new SQLAnywhere12Platform(); case version_compare($version, '11', '>='): return new SQLAnywhere11Platform(); default: return new SQLAnywherePlatform(); } } /** * {@inheritdoc} */ public function getDatabase(Connection $conn) { $params = $conn->getParams(); return $params['dbname'] ?? $conn->query('SELECT DB_NAME()')->fetchColumn(); } /** * {@inheritdoc} */ public function getDatabasePlatform() { return new SQLAnywhere12Platform(); } /** * {@inheritdoc} */ public function getSchemaManager(Connection $conn) { return new SQLAnywhereSchemaManager($conn); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/AbstractSQLServerDriver.php000066400000000000000000000046441360544566000265610ustar00rootroot00000000000000\d+)(?:\.(?P\d+)(?:\.(?P\d+)(?:\.(?P\d+))?)?)?/', $version, $versionParts )) { throw DBALException::invalidPlatformVersionSpecified( $version, '...' ); } $majorVersion = $versionParts['major']; $minorVersion = $versionParts['minor'] ?? 0; $patchVersion = $versionParts['patch'] ?? 0; $buildVersion = $versionParts['build'] ?? 0; $version = $majorVersion . '.' . $minorVersion . '.' . $patchVersion . '.' . $buildVersion; switch (true) { case version_compare($version, '11.00.2100', '>='): return new SQLServer2012Platform(); case version_compare($version, '10.00.1600', '>='): return new SQLServer2008Platform(); case version_compare($version, '9.00.1399', '>='): return new SQLServer2005Platform(); default: return new SQLServerPlatform(); } } /** * {@inheritdoc} */ public function getDatabase(Connection $conn) { $params = $conn->getParams(); return $params['dbname'] ?? $conn->query('SELECT DB_NAME()')->fetchColumn(); } /** * {@inheritdoc} */ public function getDatabasePlatform() { return new SQLServer2008Platform(); } /** * {@inheritdoc} */ public function getSchemaManager(Connection $conn) { return new SQLServerSchemaManager($conn); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/AbstractSQLiteDriver.php000066400000000000000000000062271360544566000260730ustar00rootroot00000000000000getMessage(), 'database is locked') !== false) { return new Exception\LockWaitTimeoutException($message, $exception); } if (strpos($exception->getMessage(), 'must be unique') !== false || strpos($exception->getMessage(), 'is not unique') !== false || strpos($exception->getMessage(), 'are not unique') !== false || strpos($exception->getMessage(), 'UNIQUE constraint failed') !== false ) { return new Exception\UniqueConstraintViolationException($message, $exception); } if (strpos($exception->getMessage(), 'may not be NULL') !== false || strpos($exception->getMessage(), 'NOT NULL constraint failed') !== false ) { return new Exception\NotNullConstraintViolationException($message, $exception); } if (strpos($exception->getMessage(), 'no such table:') !== false) { return new Exception\TableNotFoundException($message, $exception); } if (strpos($exception->getMessage(), 'already exists') !== false) { return new Exception\TableExistsException($message, $exception); } if (strpos($exception->getMessage(), 'has no column named') !== false) { return new Exception\InvalidFieldNameException($message, $exception); } if (strpos($exception->getMessage(), 'ambiguous column name') !== false) { return new Exception\NonUniqueFieldNameException($message, $exception); } if (strpos($exception->getMessage(), 'syntax error') !== false) { return new Exception\SyntaxErrorException($message, $exception); } if (strpos($exception->getMessage(), 'attempt to write a readonly database') !== false) { return new Exception\ReadOnlyException($message, $exception); } if (strpos($exception->getMessage(), 'unable to open database file') !== false) { return new Exception\ConnectionException($message, $exception); } return new Exception\DriverException($message, $exception); } /** * {@inheritdoc} */ public function getDatabase(Connection $conn) { $params = $conn->getParams(); return $params['path'] ?? null; } /** * {@inheritdoc} */ public function getDatabasePlatform() { return new SqlitePlatform(); } /** * {@inheritdoc} */ public function getSchemaManager(Connection $conn) { return new SqliteSchemaManager($conn); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/Connection.php000066400000000000000000000041221360544566000241610ustar00rootroot00000000000000constructPdoDsn($params), $username, $password, $driverOptions ); } /** * {@inheritdoc} */ public function createDatabasePlatformForVersion($version) { return $this->getDatabasePlatform(); } /** * {@inheritdoc} */ public function getDatabasePlatform() { return new DrizzlePlatform(); } /** * {@inheritdoc} */ public function getSchemaManager(\Doctrine\DBAL\Connection $conn) { return new DrizzleSchemaManager($conn); } /** * {@inheritdoc} * * @deprecated */ public function getName() { return 'drizzle_pdo_mysql'; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/ExceptionConverterDriver.php000066400000000000000000000015041360544566000270650ustar00rootroot00000000000000conn = $conn; } /** * {@inheritdoc} */ public function getServerVersion() { /** @var stdClass $serverInfo */ $serverInfo = db2_server_info($this->conn); return $serverInfo->DBMS_VER; } /** * {@inheritdoc} */ public function requiresQueryForServerVersion() { return false; } /** * {@inheritdoc} */ public function prepare($sql) { $stmt = @db2_prepare($this->conn, $sql); if (! $stmt) { throw new DB2Exception(db2_stmt_errormsg()); } return new DB2Statement($stmt); } /** * {@inheritdoc} */ public function query() { $args = func_get_args(); $sql = $args[0]; $stmt = $this->prepare($sql); $stmt->execute(); return $stmt; } /** * {@inheritdoc} */ public function quote($input, $type = ParameterType::STRING) { $input = db2_escape_string($input); if ($type === ParameterType::INTEGER) { return $input; } return "'" . $input . "'"; } /** * {@inheritdoc} */ public function exec($statement) { $stmt = @db2_exec($this->conn, $statement); if ($stmt === false) { throw new DB2Exception(db2_stmt_errormsg()); } return db2_num_rows($stmt); } /** * {@inheritdoc} */ public function lastInsertId($name = null) { return db2_last_insert_id($this->conn); } /** * {@inheritdoc} */ public function beginTransaction() { db2_autocommit($this->conn, DB2_AUTOCOMMIT_OFF); } /** * {@inheritdoc} */ public function commit() { if (! db2_commit($this->conn)) { throw new DB2Exception(db2_conn_errormsg($this->conn)); } db2_autocommit($this->conn, DB2_AUTOCOMMIT_ON); } /** * {@inheritdoc} */ public function rollBack() { if (! db2_rollback($this->conn)) { throw new DB2Exception(db2_conn_errormsg($this->conn)); } db2_autocommit($this->conn, DB2_AUTOCOMMIT_ON); } /** * {@inheritdoc} */ public function errorCode() { return db2_conn_error($this->conn); } /** * {@inheritdoc} */ public function errorInfo() { return [ 0 => db2_conn_errormsg($this->conn), 1 => $this->errorCode(), ]; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/IBMDB2/DB2Driver.php000066400000000000000000000024521360544566000245100ustar00rootroot00000000000000stmt = $stmt; } /** * {@inheritdoc} */ public function bindValue($param, $value, $type = ParameterType::STRING) { return $this->bindParam($param, $value, $type); } /** * {@inheritdoc} */ public function bindParam($column, &$variable, $type = ParameterType::STRING, $length = null) { switch ($type) { case ParameterType::INTEGER: $this->bind($column, $variable, DB2_PARAM_IN, DB2_LONG); break; case ParameterType::LARGE_OBJECT: if (isset($this->lobs[$column])) { [, $handle] = $this->lobs[$column]; fclose($handle); } $handle = $this->createTemporaryFile(); $path = stream_get_meta_data($handle)['uri']; $this->bind($column, $path, DB2_PARAM_FILE, DB2_BINARY); $this->lobs[$column] = [&$variable, $handle]; break; default: $this->bind($column, $variable, DB2_PARAM_IN, DB2_CHAR); break; } return true; } /** * @param int $position Parameter position * @param mixed $variable * * @throws DB2Exception */ private function bind($position, &$variable, int $parameterType, int $dataType) : void { $this->bindParam[$position] =& $variable; if (! db2_bind_param($this->stmt, $position, 'variable', $parameterType, $dataType)) { throw new DB2Exception(db2_stmt_errormsg()); } } /** * {@inheritdoc} */ public function closeCursor() { $this->bindParam = []; if (! db2_free_result($this->stmt)) { return false; } $this->result = false; return true; } /** * {@inheritdoc} */ public function columnCount() { return db2_num_fields($this->stmt) ?: 0; } /** * {@inheritdoc} */ public function errorCode() { return db2_stmt_error(); } /** * {@inheritdoc} */ public function errorInfo() { return [ db2_stmt_errormsg(), db2_stmt_error(), ]; } /** * {@inheritdoc} */ public function execute($params = null) { if ($params === null) { ksort($this->bindParam); $params = []; foreach ($this->bindParam as $column => $value) { $params[] = $value; } } foreach ($this->lobs as [$source, $target]) { if (is_resource($source)) { $this->copyStreamToStream($source, $target); continue; } $this->writeStringToStream($source, $target); } $retval = db2_execute($this->stmt, $params); foreach ($this->lobs as [, $handle]) { fclose($handle); } $this->lobs = []; if ($retval === false) { throw new DB2Exception(db2_stmt_errormsg()); } $this->result = true; return $retval; } /** * {@inheritdoc} */ public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) { $this->defaultFetchMode = $fetchMode; $this->defaultFetchClass = $arg2 ?: $this->defaultFetchClass; $this->defaultFetchClassCtorArgs = $arg3 ? (array) $arg3 : $this->defaultFetchClassCtorArgs; return true; } /** * {@inheritdoc} */ public function getIterator() { return new StatementIterator($this); } /** * {@inheritdoc} */ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) { // do not try fetching from the statement if it's not expected to contain result // in order to prevent exceptional situation if (! $this->result) { return false; } $fetchMode = $fetchMode ?: $this->defaultFetchMode; switch ($fetchMode) { case FetchMode::COLUMN: return $this->fetchColumn(); case FetchMode::MIXED: return db2_fetch_both($this->stmt); case FetchMode::ASSOCIATIVE: return db2_fetch_assoc($this->stmt); case FetchMode::CUSTOM_OBJECT: $className = $this->defaultFetchClass; $ctorArgs = $this->defaultFetchClassCtorArgs; if (func_num_args() >= 2) { $args = func_get_args(); $className = $args[1]; $ctorArgs = $args[2] ?? []; } $result = db2_fetch_object($this->stmt); if ($result instanceof stdClass) { $result = $this->castObject($result, $className, $ctorArgs); } return $result; case FetchMode::NUMERIC: return db2_fetch_array($this->stmt); case FetchMode::STANDARD_OBJECT: return db2_fetch_object($this->stmt); default: throw new DB2Exception('Given Fetch-Style ' . $fetchMode . ' is not supported.'); } } /** * {@inheritdoc} */ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) { $rows = []; switch ($fetchMode) { case FetchMode::CUSTOM_OBJECT: while (($row = $this->fetch(...func_get_args())) !== false) { $rows[] = $row; } break; case FetchMode::COLUMN: while (($row = $this->fetchColumn()) !== false) { $rows[] = $row; } break; default: while (($row = $this->fetch($fetchMode)) !== false) { $rows[] = $row; } } return $rows; } /** * {@inheritdoc} */ public function fetchColumn($columnIndex = 0) { $row = $this->fetch(FetchMode::NUMERIC); if ($row === false) { return false; } return $row[$columnIndex] ?? null; } /** * {@inheritdoc} */ public function rowCount() { return @db2_num_rows($this->stmt) ? : 0; } /** * Casts a stdClass object to the given class name mapping its' properties. * * @param stdClass $sourceObject Object to cast from. * @param string|object $destinationClass Name of the class or class instance to cast to. * @param mixed[] $ctorArgs Arguments to use for constructing the destination class instance. * * @return object * * @throws DB2Exception */ private function castObject(stdClass $sourceObject, $destinationClass, array $ctorArgs = []) { if (! is_string($destinationClass)) { if (! is_object($destinationClass)) { throw new DB2Exception(sprintf( 'Destination class has to be of type string or object, %s given.', gettype($destinationClass) )); } } else { $destinationClass = new ReflectionClass($destinationClass); $destinationClass = $destinationClass->newInstanceArgs($ctorArgs); } $sourceReflection = new ReflectionObject($sourceObject); $destinationClassReflection = new ReflectionObject($destinationClass); /** @var ReflectionProperty[] $destinationProperties */ $destinationProperties = array_change_key_case($destinationClassReflection->getProperties(), CASE_LOWER); foreach ($sourceReflection->getProperties() as $sourceProperty) { $sourceProperty->setAccessible(true); $name = $sourceProperty->getName(); $value = $sourceProperty->getValue($sourceObject); // Try to find a case-matching property. if ($destinationClassReflection->hasProperty($name)) { $destinationProperty = $destinationClassReflection->getProperty($name); $destinationProperty->setAccessible(true); $destinationProperty->setValue($destinationClass, $value); continue; } $name = strtolower($name); // Try to find a property without matching case. // Fallback for the driver returning either all uppercase or all lowercase column names. if (isset($destinationProperties[$name])) { $destinationProperty = $destinationProperties[$name]; $destinationProperty->setAccessible(true); $destinationProperty->setValue($destinationClass, $value); continue; } $destinationClass->$name = $value; } return $destinationClass; } /** * @return resource * * @throws DB2Exception */ private function createTemporaryFile() { $handle = @tmpfile(); if ($handle === false) { throw new DB2Exception('Could not create temporary file: ' . error_get_last()['message']); } return $handle; } /** * @param resource $source * @param resource $target * * @throws DB2Exception */ private function copyStreamToStream($source, $target) : void { if (@stream_copy_to_stream($source, $target) === false) { throw new DB2Exception('Could not copy source stream to temporary file: ' . error_get_last()['message']); } } /** * @param resource $target * * @throws DB2Exception */ private function writeStringToStream(string $string, $target) : void { if (@fwrite($target, $string) === false) { throw new DB2Exception('Could not write string to temporary file: ' . error_get_last()['message']); } } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/Mysqli/000077500000000000000000000000001360544566000226305ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/Mysqli/Driver.php000066400000000000000000000012261360544566000245750ustar00rootroot00000000000000conn = mysqli_init(); $this->setSecureConnection($params); $this->setDriverOptions($driverOptions); set_error_handler(static function () { }); try { if (! $this->conn->real_connect($params['host'], $username, $password, $dbname, $port, $socket, $flags)) { throw new MysqliException($this->conn->connect_error, $this->conn->sqlstate ?? 'HY000', $this->conn->connect_errno); } } finally { restore_error_handler(); } if (! isset($params['charset'])) { return; } $this->conn->set_charset($params['charset']); } /** * Retrieves mysqli native resource handle. * * Could be used if part of your application is not using DBAL. * * @return mysqli */ public function getWrappedResourceHandle() { return $this->conn; } /** * {@inheritdoc} * * The server version detection includes a special case for MariaDB * to support '5.5.5-' prefixed versions introduced in Maria 10+ * * @link https://jira.mariadb.org/browse/MDEV-4088 */ public function getServerVersion() { $serverInfos = $this->conn->get_server_info(); if (stripos($serverInfos, 'mariadb') !== false) { return $serverInfos; } $majorVersion = floor($this->conn->server_version / 10000); $minorVersion = floor(($this->conn->server_version - $majorVersion * 10000) / 100); $patchVersion = floor($this->conn->server_version - $majorVersion * 10000 - $minorVersion * 100); return $majorVersion . '.' . $minorVersion . '.' . $patchVersion; } /** * {@inheritdoc} */ public function requiresQueryForServerVersion() { return false; } /** * {@inheritdoc} */ public function prepare($prepareString) { return new MysqliStatement($this->conn, $prepareString); } /** * {@inheritdoc} */ public function query() { $args = func_get_args(); $sql = $args[0]; $stmt = $this->prepare($sql); $stmt->execute(); return $stmt; } /** * {@inheritdoc} */ public function quote($input, $type = ParameterType::STRING) { return "'" . $this->conn->escape_string($input) . "'"; } /** * {@inheritdoc} */ public function exec($statement) { if ($this->conn->query($statement) === false) { throw new MysqliException($this->conn->error, $this->conn->sqlstate, $this->conn->errno); } return $this->conn->affected_rows; } /** * {@inheritdoc} */ public function lastInsertId($name = null) { return $this->conn->insert_id; } /** * {@inheritdoc} */ public function beginTransaction() { $this->conn->query('START TRANSACTION'); return true; } /** * {@inheritdoc} */ public function commit() { return $this->conn->commit(); } /** * {@inheritdoc}non-PHPdoc) */ public function rollBack() { return $this->conn->rollback(); } /** * {@inheritdoc} */ public function errorCode() { return $this->conn->errno; } /** * {@inheritdoc} */ public function errorInfo() { return $this->conn->error; } /** * Apply the driver options to the connection. * * @param mixed[] $driverOptions * * @throws MysqliException When one of of the options is not supported. * @throws MysqliException When applying doesn't work - e.g. due to incorrect value. */ private function setDriverOptions(array $driverOptions = []) { $supportedDriverOptions = [ MYSQLI_OPT_CONNECT_TIMEOUT, MYSQLI_OPT_LOCAL_INFILE, MYSQLI_INIT_COMMAND, MYSQLI_READ_DEFAULT_FILE, MYSQLI_READ_DEFAULT_GROUP, ]; if (defined('MYSQLI_SERVER_PUBLIC_KEY')) { $supportedDriverOptions[] = MYSQLI_SERVER_PUBLIC_KEY; } $exceptionMsg = "%s option '%s' with value '%s'"; foreach ($driverOptions as $option => $value) { if ($option === static::OPTION_FLAGS) { continue; } if (! in_array($option, $supportedDriverOptions, true)) { throw new MysqliException( sprintf($exceptionMsg, 'Unsupported', $option, $value) ); } if (@mysqli_options($this->conn, $option, $value)) { continue; } $msg = sprintf($exceptionMsg, 'Failed to set', $option, $value); $msg .= sprintf(', error: %s (%d)', mysqli_error($this->conn), mysqli_errno($this->conn)); throw new MysqliException( $msg, $this->conn->sqlstate, $this->conn->errno ); } } /** * Pings the server and re-connects when `mysqli.reconnect = 1` * * @return bool */ public function ping() { return $this->conn->ping(); } /** * Establish a secure connection * * @param mixed[] $params * * @throws MysqliException */ private function setSecureConnection(array $params) { if (! isset($params['ssl_key']) && ! isset($params['ssl_cert']) && ! isset($params['ssl_ca']) && ! isset($params['ssl_capath']) && ! isset($params['ssl_cipher']) ) { return; } $this->conn->ssl_set( $params['ssl_key'] ?? null, $params['ssl_cert'] ?? null, $params['ssl_ca'] ?? null, $params['ssl_capath'] ?? null, $params['ssl_cipher'] ?? null ); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/Mysqli/MysqliException.php000066400000000000000000000003321360544566000264740ustar00rootroot00000000000000 's', ParameterType::BINARY => 's', ParameterType::BOOLEAN => 'i', ParameterType::NULL => 's', ParameterType::INTEGER => 'i', ParameterType::LARGE_OBJECT => 'b', ]; /** @var mysqli */ protected $_conn; /** @var mysqli_stmt */ protected $_stmt; /** @var string[]|false|null */ protected $_columnNames; /** @var mixed[] */ protected $_rowBindedValues = []; /** @var mixed[] */ protected $_bindedValues; /** @var string */ protected $types; /** * Contains ref values for bindValue(). * * @var mixed[] */ protected $_values = []; /** @var int */ protected $_defaultFetchMode = FetchMode::MIXED; /** * Indicates whether the statement is in the state when fetching results is possible * * @var bool */ private $result = false; /** * @param string $prepareString * * @throws MysqliException */ public function __construct(mysqli $conn, $prepareString) { $this->_conn = $conn; $stmt = $conn->prepare($prepareString); if ($stmt === false) { throw new MysqliException($this->_conn->error, $this->_conn->sqlstate, $this->_conn->errno); } $this->_stmt = $stmt; $paramCount = $this->_stmt->param_count; if (0 >= $paramCount) { return; } $this->types = str_repeat('s', $paramCount); $this->_bindedValues = array_fill(1, $paramCount, null); } /** * {@inheritdoc} */ public function bindParam($column, &$variable, $type = ParameterType::STRING, $length = null) { assert(is_int($column)); if (! isset(self::$_paramTypeMap[$type])) { throw new MysqliException(sprintf("Unknown type: '%s'", $type)); } $this->_bindedValues[$column] =& $variable; $this->types[$column - 1] = self::$_paramTypeMap[$type]; return true; } /** * {@inheritdoc} */ public function bindValue($param, $value, $type = ParameterType::STRING) { assert(is_int($param)); if (! isset(self::$_paramTypeMap[$type])) { throw new MysqliException(sprintf("Unknown type: '%s'", $type)); } $this->_values[$param] = $value; $this->_bindedValues[$param] =& $this->_values[$param]; $this->types[$param - 1] = self::$_paramTypeMap[$type]; return true; } /** * {@inheritdoc} */ public function execute($params = null) { if ($this->_bindedValues !== null) { if ($params !== null) { if (! $this->bindUntypedValues($params)) { throw new MysqliException($this->_stmt->error, $this->_stmt->errno); } } else { $this->bindTypedParameters(); } } if (! $this->_stmt->execute()) { throw new MysqliException($this->_stmt->error, $this->_stmt->sqlstate, $this->_stmt->errno); } if ($this->_columnNames === null) { $meta = $this->_stmt->result_metadata(); if ($meta !== false) { $fields = $meta->fetch_fields(); assert(is_array($fields)); $columnNames = []; foreach ($fields as $col) { $columnNames[] = $col->name; } $meta->free(); $this->_columnNames = $columnNames; } else { $this->_columnNames = false; } } if ($this->_columnNames !== false) { // Store result of every execution which has it. Otherwise it will be impossible // to execute a new statement in case if the previous one has non-fetched rows // @link http://dev.mysql.com/doc/refman/5.7/en/commands-out-of-sync.html $this->_stmt->store_result(); // Bind row values _after_ storing the result. Otherwise, if mysqli is compiled with libmysql, // it will have to allocate as much memory as it may be needed for the given column type // (e.g. for a LONGBLOB field it's 4 gigabytes) // @link https://bugs.php.net/bug.php?id=51386#1270673122 // // Make sure that the values are bound after each execution. Otherwise, if closeCursor() has been // previously called on the statement, the values are unbound making the statement unusable. // // It's also important that row values are bound after _each_ call to store_result(). Otherwise, // if mysqli is compiled with libmysql, subsequently fetched string values will get truncated // to the length of the ones fetched during the previous execution. $this->_rowBindedValues = array_fill(0, count($this->_columnNames), null); $refs = []; foreach ($this->_rowBindedValues as $key => &$value) { $refs[$key] =& $value; } if (! $this->_stmt->bind_result(...$refs)) { throw new MysqliException($this->_stmt->error, $this->_stmt->sqlstate, $this->_stmt->errno); } } $this->result = true; return true; } /** * Binds parameters with known types previously bound to the statement */ private function bindTypedParameters() { $streams = $values = []; $types = $this->types; foreach ($this->_bindedValues as $parameter => $value) { if (! isset($types[$parameter - 1])) { $types[$parameter - 1] = static::$_paramTypeMap[ParameterType::STRING]; } if ($types[$parameter - 1] === static::$_paramTypeMap[ParameterType::LARGE_OBJECT]) { if (is_resource($value)) { if (get_resource_type($value) !== 'stream') { throw new InvalidArgumentException('Resources passed with the LARGE_OBJECT parameter type must be stream resources.'); } $streams[$parameter] = $value; $values[$parameter] = null; continue; } $types[$parameter - 1] = static::$_paramTypeMap[ParameterType::STRING]; } $values[$parameter] = $value; } if (! $this->_stmt->bind_param($types, ...$values)) { throw new MysqliException($this->_stmt->error, $this->_stmt->sqlstate, $this->_stmt->errno); } $this->sendLongData($streams); } /** * Handle $this->_longData after regular query parameters have been bound * * @throws MysqliException */ private function sendLongData($streams) { foreach ($streams as $paramNr => $stream) { while (! feof($stream)) { $chunk = fread($stream, 8192); if ($chunk === false) { throw new MysqliException("Failed reading the stream resource for parameter offset ${paramNr}."); } if (! $this->_stmt->send_long_data($paramNr - 1, $chunk)) { throw new MysqliException($this->_stmt->error, $this->_stmt->sqlstate, $this->_stmt->errno); } } } } /** * Binds a array of values to bound parameters. * * @param mixed[] $values * * @return bool */ private function bindUntypedValues(array $values) { $params = []; $types = str_repeat('s', count($values)); foreach ($values as &$v) { $params[] =& $v; } return $this->_stmt->bind_param($types, ...$params); } /** * @return mixed[]|false|null */ private function _fetch() { $ret = $this->_stmt->fetch(); if ($ret === true) { $values = []; foreach ($this->_rowBindedValues as $v) { $values[] = $v; } return $values; } return $ret; } /** * {@inheritdoc} */ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) { // do not try fetching from the statement if it's not expected to contain result // in order to prevent exceptional situation if (! $this->result) { return false; } $fetchMode = $fetchMode ?: $this->_defaultFetchMode; if ($fetchMode === FetchMode::COLUMN) { return $this->fetchColumn(); } $values = $this->_fetch(); if ($values === null) { return false; } if ($values === false) { throw new MysqliException($this->_stmt->error, $this->_stmt->sqlstate, $this->_stmt->errno); } if ($fetchMode === FetchMode::NUMERIC) { return $values; } assert(is_array($this->_columnNames)); $assoc = array_combine($this->_columnNames, $values); assert(is_array($assoc)); switch ($fetchMode) { case FetchMode::ASSOCIATIVE: return $assoc; case FetchMode::MIXED: return $assoc + $values; case FetchMode::STANDARD_OBJECT: return (object) $assoc; default: throw new MysqliException(sprintf("Unknown fetch type '%s'", $fetchMode)); } } /** * {@inheritdoc} */ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) { $fetchMode = $fetchMode ?: $this->_defaultFetchMode; $rows = []; if ($fetchMode === FetchMode::COLUMN) { while (($row = $this->fetchColumn()) !== false) { $rows[] = $row; } } else { while (($row = $this->fetch($fetchMode)) !== false) { $rows[] = $row; } } return $rows; } /** * {@inheritdoc} */ public function fetchColumn($columnIndex = 0) { $row = $this->fetch(FetchMode::NUMERIC); if ($row === false) { return false; } return $row[$columnIndex] ?? null; } /** * {@inheritdoc} */ public function errorCode() { return $this->_stmt->errno; } /** * {@inheritdoc} */ public function errorInfo() { return $this->_stmt->error; } /** * {@inheritdoc} */ public function closeCursor() { $this->_stmt->free_result(); $this->result = false; return true; } /** * {@inheritdoc} */ public function rowCount() { if ($this->_columnNames === false) { return $this->_stmt->affected_rows; } return $this->_stmt->num_rows; } /** * {@inheritdoc} */ public function columnCount() { return $this->_stmt->field_count; } /** * {@inheritdoc} */ public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) { $this->_defaultFetchMode = $fetchMode; return true; } /** * {@inheritdoc} */ public function getIterator() { return new StatementIterator($this); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/OCI8/000077500000000000000000000000001360544566000220545ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/OCI8/Driver.php000066400000000000000000000023171360544566000240230ustar00rootroot00000000000000_constructDsn($params), $params['charset'] ?? '', $params['sessionMode'] ?? OCI_DEFAULT, $params['persistent'] ?? false ); } catch (OCI8Exception $e) { throw DBALException::driverException($this, $e); } } /** * Constructs the Oracle DSN. * * @param mixed[] $params * * @return string The DSN. */ protected function _constructDsn(array $params) { return $this->getEasyConnectString($params); } /** * {@inheritdoc} * * @deprecated */ public function getName() { return 'oci8'; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/OCI8/OCI8Connection.php000066400000000000000000000125041360544566000253110ustar00rootroot00000000000000dbh = $dbh; } /** * {@inheritdoc} * * @throws UnexpectedValueException If the version string returned by the database server * does not contain a parsable version number. */ public function getServerVersion() { $version = oci_server_version($this->dbh); if ($version === false) { throw OCI8Exception::fromErrorInfo(oci_error($this->dbh)); } if (! preg_match('/\s+(\d+\.\d+\.\d+\.\d+\.\d+)\s+/', $version, $matches)) { throw new UnexpectedValueException( sprintf( 'Unexpected database version string "%s". Cannot parse an appropriate version number from it. ' . 'Please report this database version string to the Doctrine team.', $version ) ); } return $matches[1]; } /** * {@inheritdoc} */ public function requiresQueryForServerVersion() { return false; } /** * {@inheritdoc} */ public function prepare($prepareString) { return new OCI8Statement($this->dbh, $prepareString, $this); } /** * {@inheritdoc} */ public function query() { $args = func_get_args(); $sql = $args[0]; //$fetchMode = $args[1]; $stmt = $this->prepare($sql); $stmt->execute(); return $stmt; } /** * {@inheritdoc} */ public function quote($value, $type = ParameterType::STRING) { if (is_int($value) || is_float($value)) { return $value; } $value = str_replace("'", "''", $value); return "'" . addcslashes($value, "\000\n\r\\\032") . "'"; } /** * {@inheritdoc} */ public function exec($statement) { $stmt = $this->prepare($statement); $stmt->execute(); return $stmt->rowCount(); } /** * {@inheritdoc} */ public function lastInsertId($name = null) { if ($name === null) { return false; } $sql = 'SELECT ' . $name . '.CURRVAL FROM DUAL'; $stmt = $this->query($sql); $result = $stmt->fetchColumn(); if ($result === false) { throw new OCI8Exception('lastInsertId failed: Query was executed but no result was returned.'); } return (int) $result; } /** * Returns the current execution mode. * * @return int */ public function getExecuteMode() { return $this->executeMode; } /** * {@inheritdoc} */ public function beginTransaction() { $this->executeMode = OCI_NO_AUTO_COMMIT; return true; } /** * {@inheritdoc} */ public function commit() { if (! oci_commit($this->dbh)) { throw OCI8Exception::fromErrorInfo($this->errorInfo()); } $this->executeMode = OCI_COMMIT_ON_SUCCESS; return true; } /** * {@inheritdoc} */ public function rollBack() { if (! oci_rollback($this->dbh)) { throw OCI8Exception::fromErrorInfo($this->errorInfo()); } $this->executeMode = OCI_COMMIT_ON_SUCCESS; return true; } /** * {@inheritdoc} */ public function errorCode() { $error = oci_error($this->dbh); if ($error !== false) { $error = $error['code']; } return $error; } /** * {@inheritdoc} */ public function errorInfo() { $error = oci_error($this->dbh); if ($error === false) { return []; } return $error; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/OCI8/OCI8Exception.php000066400000000000000000000010441360544566000251450ustar00rootroot00000000000000 OCI_BOTH, FetchMode::ASSOCIATIVE => OCI_ASSOC, FetchMode::NUMERIC => OCI_NUM, FetchMode::COLUMN => OCI_NUM, ]; /** @var int */ protected $_defaultFetchMode = FetchMode::MIXED; /** @var string[] */ protected $_paramMap = []; /** * Holds references to bound parameter values. * * This is a new requirement for PHP7's oci8 extension that prevents bound values from being garbage collected. * * @var mixed[] */ private $boundValues = []; /** * Indicates whether the statement is in the state when fetching results is possible * * @var bool */ private $result = false; /** * Creates a new OCI8Statement that uses the given connection handle and SQL statement. * * @param resource $dbh The connection handle. * @param string $query The SQL query. */ public function __construct($dbh, $query, OCI8Connection $conn) { [$query, $paramMap] = self::convertPositionalToNamedPlaceholders($query); $stmt = oci_parse($dbh, $query); assert(is_resource($stmt)); $this->_sth = $stmt; $this->_dbh = $dbh; $this->_paramMap = $paramMap; $this->_conn = $conn; } /** * Converts positional (?) into named placeholders (:param). * * Oracle does not support positional parameters, hence this method converts all * positional parameters into artificially named parameters. Note that this conversion * is not perfect. All question marks (?) in the original statement are treated as * placeholders and converted to a named parameter. * * The algorithm uses a state machine with two possible states: InLiteral and NotInLiteral. * Question marks inside literal strings are therefore handled correctly by this method. * This comes at a cost, the whole sql statement has to be looped over. * * @param string $statement The SQL statement to convert. * * @return mixed[] [0] => the statement value (string), [1] => the paramMap value (array). * * @throws OCI8Exception * * @todo extract into utility class in Doctrine\DBAL\Util namespace * @todo review and test for lost spaces. we experienced missing spaces with oci8 in some sql statements. */ public static function convertPositionalToNamedPlaceholders($statement) { $fragmentOffset = $tokenOffset = 0; $fragments = $paramMap = []; $currentLiteralDelimiter = null; do { if (! $currentLiteralDelimiter) { $result = self::findPlaceholderOrOpeningQuote( $statement, $tokenOffset, $fragmentOffset, $fragments, $currentLiteralDelimiter, $paramMap ); } else { $result = self::findClosingQuote($statement, $tokenOffset, $currentLiteralDelimiter); } } while ($result); if ($currentLiteralDelimiter) { throw new OCI8Exception(sprintf( 'The statement contains non-terminated string literal starting at offset %d', $tokenOffset - 1 )); } $fragments[] = substr($statement, $fragmentOffset); $statement = implode('', $fragments); return [$statement, $paramMap]; } /** * Finds next placeholder or opening quote. * * @param string $statement The SQL statement to parse * @param string $tokenOffset The offset to start searching from * @param int $fragmentOffset The offset to build the next fragment from * @param string[] $fragments Fragments of the original statement not containing placeholders * @param string|null $currentLiteralDelimiter The delimiter of the current string literal * or NULL if not currently in a literal * @param array $paramMap Mapping of the original parameter positions to their named replacements * * @return bool Whether the token was found */ private static function findPlaceholderOrOpeningQuote( $statement, &$tokenOffset, &$fragmentOffset, &$fragments, &$currentLiteralDelimiter, &$paramMap ) { $token = self::findToken($statement, $tokenOffset, '/[?\'"]/'); if (! $token) { return false; } if ($token === '?') { $position = count($paramMap) + 1; $param = ':param' . $position; $fragments[] = substr($statement, $fragmentOffset, $tokenOffset - $fragmentOffset); $fragments[] = $param; $paramMap[$position] = $param; $tokenOffset += 1; $fragmentOffset = $tokenOffset; return true; } $currentLiteralDelimiter = $token; ++$tokenOffset; return true; } /** * Finds closing quote * * @param string $statement The SQL statement to parse * @param string $tokenOffset The offset to start searching from * @param string $currentLiteralDelimiter The delimiter of the current string literal * * @return bool Whether the token was found */ private static function findClosingQuote( $statement, &$tokenOffset, &$currentLiteralDelimiter ) { $token = self::findToken( $statement, $tokenOffset, '/' . preg_quote($currentLiteralDelimiter, '/') . '/' ); if (! $token) { return false; } $currentLiteralDelimiter = false; ++$tokenOffset; return true; } /** * Finds the token described by regex starting from the given offset. Updates the offset with the position * where the token was found. * * @param string $statement The SQL statement to parse * @param int $offset The offset to start searching from * @param string $regex The regex containing token pattern * * @return string|null Token or NULL if not found */ private static function findToken($statement, &$offset, $regex) { if (preg_match($regex, $statement, $matches, PREG_OFFSET_CAPTURE, $offset)) { $offset = $matches[0][1]; return $matches[0][0]; } return null; } /** * {@inheritdoc} */ public function bindValue($param, $value, $type = ParameterType::STRING) { return $this->bindParam($param, $value, $type, null); } /** * {@inheritdoc} */ public function bindParam($param, &$variable, $type = ParameterType::STRING, $length = null) { if (is_int($param)) { if (! isset($this->_paramMap[$param])) { throw new OCI8Exception(sprintf('Could not find variable mapping with index %d, in the SQL statement', $param)); } $param = $this->_paramMap[$param]; } if ($type === ParameterType::LARGE_OBJECT) { $lob = oci_new_descriptor($this->_dbh, OCI_D_LOB); $class = 'OCI-Lob'; assert($lob instanceof $class); $lob->writeTemporary($variable, OCI_TEMP_BLOB); $variable =& $lob; } $this->boundValues[$param] =& $variable; return oci_bind_by_name( $this->_sth, $param, $variable, $length ?? -1, $this->convertParameterType($type) ); } /** * Converts DBAL parameter type to oci8 parameter type */ private function convertParameterType(int $type) : int { switch ($type) { case ParameterType::BINARY: return OCI_B_BIN; case ParameterType::LARGE_OBJECT: return OCI_B_BLOB; default: return SQLT_CHR; } } /** * {@inheritdoc} */ public function closeCursor() { // not having the result means there's nothing to close if (! $this->result) { return true; } oci_cancel($this->_sth); $this->result = false; return true; } /** * {@inheritdoc} */ public function columnCount() { return oci_num_fields($this->_sth) ?: 0; } /** * {@inheritdoc} */ public function errorCode() { $error = oci_error($this->_sth); if ($error !== false) { $error = $error['code']; } return $error; } /** * {@inheritdoc} */ public function errorInfo() { $error = oci_error($this->_sth); if ($error === false) { return []; } return $error; } /** * {@inheritdoc} */ public function execute($params = null) { if ($params) { $hasZeroIndex = array_key_exists(0, $params); foreach ($params as $key => $val) { if ($hasZeroIndex && is_int($key)) { $this->bindValue($key + 1, $val); } else { $this->bindValue($key, $val); } } } $ret = @oci_execute($this->_sth, $this->_conn->getExecuteMode()); if (! $ret) { throw OCI8Exception::fromErrorInfo($this->errorInfo()); } $this->result = true; return $ret; } /** * {@inheritdoc} */ public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) { $this->_defaultFetchMode = $fetchMode; return true; } /** * {@inheritdoc} */ public function getIterator() { return new StatementIterator($this); } /** * {@inheritdoc} */ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) { // do not try fetching from the statement if it's not expected to contain result // in order to prevent exceptional situation if (! $this->result) { return false; } $fetchMode = $fetchMode ?: $this->_defaultFetchMode; if ($fetchMode === FetchMode::COLUMN) { return $this->fetchColumn(); } if ($fetchMode === FetchMode::STANDARD_OBJECT) { return oci_fetch_object($this->_sth); } if (! isset(self::$fetchModeMap[$fetchMode])) { throw new InvalidArgumentException('Invalid fetch style: ' . $fetchMode); } return oci_fetch_array( $this->_sth, self::$fetchModeMap[$fetchMode] | OCI_RETURN_NULLS | OCI_RETURN_LOBS ); } /** * {@inheritdoc} */ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) { $fetchMode = $fetchMode ?: $this->_defaultFetchMode; $result = []; if ($fetchMode === FetchMode::STANDARD_OBJECT) { while ($row = $this->fetch($fetchMode)) { $result[] = $row; } return $result; } if (! isset(self::$fetchModeMap[$fetchMode])) { throw new InvalidArgumentException('Invalid fetch style: ' . $fetchMode); } if (self::$fetchModeMap[$fetchMode] === OCI_BOTH) { while ($row = $this->fetch($fetchMode)) { $result[] = $row; } } else { $fetchStructure = OCI_FETCHSTATEMENT_BY_ROW; if ($fetchMode === FetchMode::COLUMN) { $fetchStructure = OCI_FETCHSTATEMENT_BY_COLUMN; } // do not try fetching from the statement if it's not expected to contain result // in order to prevent exceptional situation if (! $this->result) { return []; } oci_fetch_all( $this->_sth, $result, 0, -1, self::$fetchModeMap[$fetchMode] | OCI_RETURN_NULLS | $fetchStructure | OCI_RETURN_LOBS ); if ($fetchMode === FetchMode::COLUMN) { $result = $result[0]; } } return $result; } /** * {@inheritdoc} */ public function fetchColumn($columnIndex = 0) { // do not try fetching from the statement if it's not expected to contain result // in order to prevent exceptional situation if (! $this->result) { return false; } $row = oci_fetch_array($this->_sth, OCI_NUM | OCI_RETURN_NULLS | OCI_RETURN_LOBS); if ($row === false) { return false; } return $row[$columnIndex] ?? null; } /** * {@inheritdoc} */ public function rowCount() { return oci_num_rows($this->_sth) ?: 0; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/PDOConnection.php000066400000000000000000000052041360544566000245260ustar00rootroot00000000000000setAttribute(PDO::ATTR_STATEMENT_CLASS, [PDOStatement::class, []]); $this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch (\PDOException $exception) { throw new PDOException($exception); } } /** * {@inheritdoc} */ public function exec($statement) { try { return parent::exec($statement); } catch (\PDOException $exception) { throw new PDOException($exception); } } /** * {@inheritdoc} */ public function getServerVersion() { return PDO::getAttribute(PDO::ATTR_SERVER_VERSION); } /** * {@inheritdoc} */ public function prepare($prepareString, $driverOptions = []) { try { return parent::prepare($prepareString, $driverOptions); } catch (\PDOException $exception) { throw new PDOException($exception); } } /** * {@inheritdoc} */ public function query() { $args = func_get_args(); try { $stmt = parent::query(...$args); assert($stmt instanceof \PDOStatement); return $stmt; } catch (\PDOException $exception) { throw new PDOException($exception); } } /** * {@inheritdoc} */ public function quote($input, $type = ParameterType::STRING) { return parent::quote($input, $type); } /** * {@inheritdoc} */ public function lastInsertId($name = null) { try { if ($name === null) { return parent::lastInsertId(); } return parent::lastInsertId($name); } catch (\PDOException $exception) { throw new PDOException($exception); } } /** * {@inheritdoc} */ public function requiresQueryForServerVersion() { return false; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/PDOException.php000066400000000000000000000021751360544566000243710ustar00rootroot00000000000000getMessage(), 0, $exception); $this->code = $exception->getCode(); $this->errorInfo = $exception->errorInfo; $this->errorCode = $exception->errorInfo[1] ?? $exception->getCode(); $this->sqlState = $exception->errorInfo[0] ?? $exception->getCode(); } /** * {@inheritdoc} */ public function getErrorCode() { return $this->errorCode; } /** * {@inheritdoc} */ public function getSQLState() { return $this->sqlState; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/PDOIbm/000077500000000000000000000000001360544566000224245ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/PDOIbm/Driver.php000066400000000000000000000023521360544566000243720ustar00rootroot00000000000000_constructPdoDsn($params), $username, $password, $driverOptions ); } /** * Constructs the IBM PDO DSN. * * @param mixed[] $params * * @return string The DSN. */ private function _constructPdoDsn(array $params) { $dsn = 'ibm:'; if (isset($params['host'])) { $dsn .= 'HOSTNAME=' . $params['host'] . ';'; } if (isset($params['port'])) { $dsn .= 'PORT=' . $params['port'] . ';'; } $dsn .= 'PROTOCOL=TCPIP;'; if (isset($params['dbname'])) { $dsn .= 'DATABASE=' . $params['dbname'] . ';'; } return $dsn; } /** * {@inheritdoc} * * @deprecated */ public function getName() { return 'pdo_ibm'; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/PDOMySql/000077500000000000000000000000001360544566000227625ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/PDOMySql/Driver.php000066400000000000000000000032331360544566000247270ustar00rootroot00000000000000constructPdoDsn($params), $username, $password, $driverOptions ); } catch (PDOException $e) { throw DBALException::driverException($this, $e); } return $conn; } /** * Constructs the MySql PDO DSN. * * @param mixed[] $params * * @return string The DSN. */ protected function constructPdoDsn(array $params) { $dsn = 'mysql:'; if (isset($params['host']) && $params['host'] !== '') { $dsn .= 'host=' . $params['host'] . ';'; } if (isset($params['port'])) { $dsn .= 'port=' . $params['port'] . ';'; } if (isset($params['dbname'])) { $dsn .= 'dbname=' . $params['dbname'] . ';'; } if (isset($params['unix_socket'])) { $dsn .= 'unix_socket=' . $params['unix_socket'] . ';'; } if (isset($params['charset'])) { $dsn .= 'charset=' . $params['charset'] . ';'; } return $dsn; } /** * {@inheritdoc} * * @deprecated */ public function getName() { return 'pdo_mysql'; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/PDOOracle/000077500000000000000000000000001360544566000231225ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/PDOOracle/Driver.php000066400000000000000000000027211360544566000250700ustar00rootroot00000000000000constructPdoDsn($params), $username, $password, $driverOptions ); } catch (PDOException $e) { throw DBALException::driverException($this, $e); } } /** * Constructs the Oracle PDO DSN. * * @param mixed[] $params * * @return string The DSN. */ private function constructPdoDsn(array $params) { $dsn = 'oci:dbname=' . $this->getEasyConnectString($params); if (isset($params['charset'])) { $dsn .= ';charset=' . $params['charset']; } return $dsn; } /** * {@inheritdoc} */ public function getName() { return 'pdo_oracle'; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/PDOPgSql/000077500000000000000000000000001360544566000227435ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/PDOPgSql/Driver.php000066400000000000000000000066241360544566000247170ustar00rootroot00000000000000_constructPdoDsn($params), $username, $password, $driverOptions ); if (defined('PDO::PGSQL_ATTR_DISABLE_PREPARES') && (! isset($driverOptions[PDO::PGSQL_ATTR_DISABLE_PREPARES]) || $driverOptions[PDO::PGSQL_ATTR_DISABLE_PREPARES] === true ) ) { $pdo->setAttribute(PDO::PGSQL_ATTR_DISABLE_PREPARES, true); } /* defining client_encoding via SET NAMES to avoid inconsistent DSN support * - the 'client_encoding' connection param only works with postgres >= 9.1 * - passing client_encoding via the 'options' param breaks pgbouncer support */ if (isset($params['charset'])) { $pdo->exec('SET NAMES \'' . $params['charset'] . '\''); } return $pdo; } catch (PDOException $e) { throw DBALException::driverException($this, $e); } } /** * Constructs the Postgres PDO DSN. * * @param mixed[] $params * * @return string The DSN. */ private function _constructPdoDsn(array $params) { $dsn = 'pgsql:'; if (isset($params['host']) && $params['host'] !== '') { $dsn .= 'host=' . $params['host'] . ';'; } if (isset($params['port']) && $params['port'] !== '') { $dsn .= 'port=' . $params['port'] . ';'; } if (isset($params['dbname'])) { $dsn .= 'dbname=' . $params['dbname'] . ';'; } elseif (isset($params['default_dbname'])) { $dsn .= 'dbname=' . $params['default_dbname'] . ';'; } else { // Used for temporary connections to allow operations like dropping the database currently connected to. // Connecting without an explicit database does not work, therefore "postgres" database is used // as it is mostly present in every server setup. $dsn .= 'dbname=postgres;'; } if (isset($params['sslmode'])) { $dsn .= 'sslmode=' . $params['sslmode'] . ';'; } if (isset($params['sslrootcert'])) { $dsn .= 'sslrootcert=' . $params['sslrootcert'] . ';'; } if (isset($params['sslcert'])) { $dsn .= 'sslcert=' . $params['sslcert'] . ';'; } if (isset($params['sslkey'])) { $dsn .= 'sslkey=' . $params['sslkey'] . ';'; } if (isset($params['sslcrl'])) { $dsn .= 'sslcrl=' . $params['sslcrl'] . ';'; } if (isset($params['application_name'])) { $dsn .= 'application_name=' . $params['application_name'] . ';'; } return $dsn; } /** * {@inheritdoc} * * @deprecated */ public function getName() { return 'pdo_pgsql'; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/PDOSqlite/000077500000000000000000000000001360544566000231565ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/PDOSqlite/Driver.php000066400000000000000000000041671360544566000251320ustar00rootroot00000000000000 ['callback' => [SqlitePlatform::class, 'udfSqrt'], 'numArgs' => 1], 'mod' => ['callback' => [SqlitePlatform::class, 'udfMod'], 'numArgs' => 2], 'locate' => ['callback' => [SqlitePlatform::class, 'udfLocate'], 'numArgs' => -1], ]; /** * {@inheritdoc} */ public function connect(array $params, $username = null, $password = null, array $driverOptions = []) { if (isset($driverOptions['userDefinedFunctions'])) { $this->_userDefinedFunctions = array_merge( $this->_userDefinedFunctions, $driverOptions['userDefinedFunctions'] ); unset($driverOptions['userDefinedFunctions']); } try { $pdo = new PDOConnection( $this->_constructPdoDsn($params), $username, $password, $driverOptions ); } catch (PDOException $ex) { throw DBALException::driverException($this, $ex); } foreach ($this->_userDefinedFunctions as $fn => $data) { $pdo->sqliteCreateFunction($fn, $data['callback'], $data['numArgs']); } return $pdo; } /** * Constructs the Sqlite PDO DSN. * * @param mixed[] $params * * @return string The DSN. */ protected function _constructPdoDsn(array $params) { $dsn = 'sqlite:'; if (isset($params['path'])) { $dsn .= $params['path']; } elseif (isset($params['memory'])) { $dsn .= ':memory:'; } return $dsn; } /** * {@inheritdoc} * * @deprecated */ public function getName() { return 'pdo_sqlite'; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/PDOSqlsrv/000077500000000000000000000000001360544566000232075ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Connection.php000066400000000000000000000023661360544566000260260ustar00rootroot00000000000000setAttribute(PDO::ATTR_STATEMENT_CLASS, [Statement::class, []]); } /** * {@inheritDoc} */ public function lastInsertId($name = null) { if ($name === null) { return parent::lastInsertId($name); } $stmt = $this->prepare('SELECT CONVERT(VARCHAR(MAX), current_value) FROM sys.sequences WHERE name = ?'); $stmt->execute([$name]); return $stmt->fetchColumn(); } /** * {@inheritDoc} */ public function quote($value, $type = ParameterType::STRING) { $val = parent::quote($value, $type); // Fix for a driver version terminating all values with null byte if (strpos($val, "\0") !== false) { $val = substr($val, 0, -1); } return $val; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Driver.php000066400000000000000000000043641360544566000251620ustar00rootroot00000000000000 $value) { if (is_int($option)) { $pdoOptions[$option] = $value; } else { $dsnOptions[$option] = $value; } } return new Connection( $this->_constructPdoDsn($params, $dsnOptions), $username, $password, $pdoOptions ); } /** * Constructs the Sqlsrv PDO DSN. * * @param mixed[] $params * @param string[] $connectionOptions * * @return string The DSN. */ private function _constructPdoDsn(array $params, array $connectionOptions) { $dsn = 'sqlsrv:server='; if (isset($params['host'])) { $dsn .= $params['host']; } if (isset($params['port']) && ! empty($params['port'])) { $dsn .= ',' . $params['port']; } if (isset($params['dbname'])) { $connectionOptions['Database'] = $params['dbname']; } if (isset($params['MultipleActiveResultSets'])) { $connectionOptions['MultipleActiveResultSets'] = $params['MultipleActiveResultSets'] ? 'true' : 'false'; } return $dsn . $this->getConnectionOptionsDsn($connectionOptions); } /** * Converts a connection options array to the DSN * * @param string[] $connectionOptions */ private function getConnectionOptionsDsn(array $connectionOptions) : string { $connectionOptionsDsn = ''; foreach ($connectionOptions as $paramName => $paramValue) { $connectionOptionsDsn .= sprintf(';%s=%s', $paramName, $paramValue); } return $connectionOptionsDsn; } /** * {@inheritdoc} * * @deprecated */ public function getName() { return 'pdo_sqlsrv'; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/PDOSqlsrv/Statement.php000066400000000000000000000015271360544566000256710ustar00rootroot00000000000000bindParam($param, $value, $type); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/PDOStatement.php000066400000000000000000000144211360544566000243740ustar00rootroot00000000000000 PDO::PARAM_NULL, ParameterType::INTEGER => PDO::PARAM_INT, ParameterType::STRING => PDO::PARAM_STR, ParameterType::BINARY => PDO::PARAM_LOB, ParameterType::LARGE_OBJECT => PDO::PARAM_LOB, ParameterType::BOOLEAN => PDO::PARAM_BOOL, ]; private const FETCH_MODE_MAP = [ FetchMode::ASSOCIATIVE => PDO::FETCH_ASSOC, FetchMode::NUMERIC => PDO::FETCH_NUM, FetchMode::MIXED => PDO::FETCH_BOTH, FetchMode::STANDARD_OBJECT => PDO::FETCH_OBJ, FetchMode::COLUMN => PDO::FETCH_COLUMN, FetchMode::CUSTOM_OBJECT => PDO::FETCH_CLASS, ]; /** * Protected constructor. */ protected function __construct() { } /** * {@inheritdoc} */ public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) { $fetchMode = $this->convertFetchMode($fetchMode); // This thin wrapper is necessary to shield against the weird signature // of PDOStatement::setFetchMode(): even if the second and third // parameters are optional, PHP will not let us remove it from this // declaration. try { if ($arg2 === null && $arg3 === null) { return parent::setFetchMode($fetchMode); } if ($arg3 === null) { return parent::setFetchMode($fetchMode, $arg2); } return parent::setFetchMode($fetchMode, $arg2, $arg3); } catch (\PDOException $exception) { throw new PDOException($exception); } } /** * {@inheritdoc} */ public function bindValue($param, $value, $type = ParameterType::STRING) { $type = $this->convertParamType($type); try { return parent::bindValue($param, $value, $type); } catch (\PDOException $exception) { throw new PDOException($exception); } } /** * {@inheritdoc} */ public function bindParam($column, &$variable, $type = ParameterType::STRING, $length = null, $driverOptions = null) { $type = $this->convertParamType($type); try { return parent::bindParam($column, $variable, $type, ...array_slice(func_get_args(), 3)); } catch (\PDOException $exception) { throw new PDOException($exception); } } /** * {@inheritdoc} */ public function closeCursor() { try { return parent::closeCursor(); } catch (\PDOException $exception) { // Exceptions not allowed by the interface. // In case driver implementations do not adhere to the interface, silence exceptions here. return true; } } /** * {@inheritdoc} */ public function execute($params = null) { try { return parent::execute($params); } catch (\PDOException $exception) { throw new PDOException($exception); } } /** * {@inheritdoc} */ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) { $args = func_get_args(); if (isset($args[0])) { $args[0] = $this->convertFetchMode($args[0]); } try { return parent::fetch(...$args); } catch (\PDOException $exception) { throw new PDOException($exception); } } /** * {@inheritdoc} */ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) { $args = func_get_args(); if (isset($args[0])) { $args[0] = $this->convertFetchMode($args[0]); } if ($fetchMode === null && $fetchArgument === null && $ctorArgs === null) { $args = []; } elseif ($fetchArgument === null && $ctorArgs === null) { $args = [$fetchMode]; } elseif ($ctorArgs === null) { $args = [$fetchMode, $fetchArgument]; } else { $args = [$fetchMode, $fetchArgument, $ctorArgs]; } try { $data = parent::fetchAll(...$args); assert(is_array($data)); return $data; } catch (\PDOException $exception) { throw new PDOException($exception); } } /** * {@inheritdoc} */ public function fetchColumn($columnIndex = 0) { try { return parent::fetchColumn($columnIndex); } catch (\PDOException $exception) { throw new PDOException($exception); } } /** * Converts DBAL parameter type to PDO parameter type * * @param int $type Parameter type */ private function convertParamType(int $type) : int { if (! isset(self::PARAM_TYPE_MAP[$type])) { // TODO: next major: throw an exception @trigger_error(sprintf( 'Using a PDO parameter type (%d given) is deprecated and will cause an error in Doctrine DBAL 3.0', $type ), E_USER_DEPRECATED); return $type; } return self::PARAM_TYPE_MAP[$type]; } /** * Converts DBAL fetch mode to PDO fetch mode * * @param int $fetchMode Fetch mode */ private function convertFetchMode(int $fetchMode) : int { if (! isset(self::FETCH_MODE_MAP[$fetchMode])) { // TODO: next major: throw an exception @trigger_error(sprintf( 'Using a PDO fetch mode or their combination (%d given)' . ' is deprecated and will cause an error in Doctrine DBAL 3.0', $fetchMode ), E_USER_DEPRECATED); return $fetchMode; } return self::FETCH_MODE_MAP[$fetchMode]; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/PingableConnection.php000066400000000000000000000005631360544566000256300ustar00rootroot00000000000000buildDsn( $params['host'] ?? null, $params['port'] ?? null, $params['server'] ?? null, $params['dbname'] ?? null, $username, $password, $driverOptions ), $params['persistent'] ?? false ); } catch (SQLAnywhereException $e) { throw DBALException::driverException($this, $e); } } /** * {@inheritdoc} * * @deprecated */ public function getName() { return 'sqlanywhere'; } /** * Build the connection string for given connection parameters and driver options. * * @param string $host Host address to connect to. * @param int $port Port to use for the connection (default to SQL Anywhere standard port 2638). * @param string $server Database server name on the host to connect to. * SQL Anywhere allows multiple database server instances on the same host, * therefore specifying the server instance name to use is mandatory. * @param string $dbname Name of the database on the server instance to connect to. * @param string $username User name to use for connection authentication. * @param string $password Password to use for connection authentication. * @param mixed[] $driverOptions Additional parameters to use for the connection. * * @return string */ private function buildDsn($host, $port, $server, $dbname, $username = null, $password = null, array $driverOptions = []) { $host = $host ?: 'localhost'; $port = $port ?: 2638; if (! empty($server)) { $server = ';ServerName=' . $server; } return 'HOST=' . $host . ':' . $port . $server . ';DBN=' . $dbname . ';UID=' . $username . ';PWD=' . $password . ';' . implode( ';', array_map(static function ($key, $value) { return $key . '=' . $value; }, array_keys($driverOptions), $driverOptions) ); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereConnection.php000066400000000000000000000117741360544566000304210ustar00rootroot00000000000000connection = $persistent ? @sasql_pconnect($dsn) : @sasql_connect($dsn); if (! is_resource($this->connection)) { throw SQLAnywhereException::fromSQLAnywhereError(); } // Disable PHP warnings on error. if (! sasql_set_option($this->connection, 'verbose_errors', false)) { throw SQLAnywhereException::fromSQLAnywhereError($this->connection); } // Enable auto committing by default. if (! sasql_set_option($this->connection, 'auto_commit', 'on')) { throw SQLAnywhereException::fromSQLAnywhereError($this->connection); } } /** * {@inheritdoc} * * @throws SQLAnywhereException */ public function beginTransaction() { if (! sasql_set_option($this->connection, 'auto_commit', 'off')) { throw SQLAnywhereException::fromSQLAnywhereError($this->connection); } return true; } /** * {@inheritdoc} * * @throws SQLAnywhereException */ public function commit() { if (! sasql_commit($this->connection)) { throw SQLAnywhereException::fromSQLAnywhereError($this->connection); } $this->endTransaction(); return true; } /** * {@inheritdoc} */ public function errorCode() { return sasql_errorcode($this->connection); } /** * {@inheritdoc} */ public function errorInfo() { return sasql_error($this->connection); } /** * {@inheritdoc} */ public function exec($statement) { if (sasql_real_query($this->connection, $statement) === false) { throw SQLAnywhereException::fromSQLAnywhereError($this->connection); } return sasql_affected_rows($this->connection); } /** * {@inheritdoc} */ public function getServerVersion() { $version = $this->query("SELECT PROPERTY('ProductVersion')")->fetchColumn(); assert(is_string($version)); return $version; } /** * {@inheritdoc} */ public function lastInsertId($name = null) { if ($name === null) { return sasql_insert_id($this->connection); } return $this->query('SELECT ' . $name . '.CURRVAL')->fetchColumn(); } /** * {@inheritdoc} */ public function prepare($prepareString) { return new SQLAnywhereStatement($this->connection, $prepareString); } /** * {@inheritdoc} */ public function query() { $args = func_get_args(); $stmt = $this->prepare($args[0]); $stmt->execute(); return $stmt; } /** * {@inheritdoc} */ public function quote($input, $type = ParameterType::STRING) { if (is_int($input) || is_float($input)) { return $input; } return "'" . sasql_escape_string($this->connection, $input) . "'"; } /** * {@inheritdoc} */ public function requiresQueryForServerVersion() { return true; } /** * {@inheritdoc} * * @throws SQLAnywhereException */ public function rollBack() { if (! sasql_rollback($this->connection)) { throw SQLAnywhereException::fromSQLAnywhereError($this->connection); } $this->endTransaction(); return true; } /** * Ends transactional mode and enables auto commit again. * * @return bool Whether or not ending transactional mode succeeded. * * @throws SQLAnywhereException */ private function endTransaction() { if (! sasql_set_option($this->connection, 'auto_commit', 'on')) { throw SQLAnywhereException::fromSQLAnywhereError($this->connection); } return true; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereException.php000066400000000000000000000045101360544566000302460ustar00rootroot00000000000000conn = $conn; $this->stmt = sasql_prepare($conn, $sql); if (! is_resource($this->stmt)) { throw SQLAnywhereException::fromSQLAnywhereError($conn); } } /** * {@inheritdoc} * * @throws SQLAnywhereException */ public function bindParam($column, &$variable, $type = ParameterType::STRING, $length = null) { switch ($type) { case ParameterType::INTEGER: case ParameterType::BOOLEAN: $type = 'i'; break; case ParameterType::LARGE_OBJECT: $type = 'b'; break; case ParameterType::NULL: case ParameterType::STRING: case ParameterType::BINARY: $type = 's'; break; default: throw new SQLAnywhereException('Unknown type: ' . $type); } $this->boundValues[$column] =& $variable; if (! sasql_stmt_bind_param_ex($this->stmt, $column - 1, $variable, $type, $variable === null)) { throw SQLAnywhereException::fromSQLAnywhereError($this->conn, $this->stmt); } return true; } /** * {@inheritdoc} */ public function bindValue($param, $value, $type = ParameterType::STRING) { return $this->bindParam($param, $value, $type); } /** * {@inheritdoc} * * @throws SQLAnywhereException */ public function closeCursor() { if (! sasql_stmt_reset($this->stmt)) { throw SQLAnywhereException::fromSQLAnywhereError($this->conn, $this->stmt); } return true; } /** * {@inheritdoc} */ public function columnCount() { return sasql_stmt_field_count($this->stmt); } /** * {@inheritdoc} */ public function errorCode() { return sasql_stmt_errno($this->stmt); } /** * {@inheritdoc} */ public function errorInfo() { return sasql_stmt_error($this->stmt); } /** * {@inheritdoc} * * @throws SQLAnywhereException */ public function execute($params = null) { if (is_array($params)) { $hasZeroIndex = array_key_exists(0, $params); foreach ($params as $key => $val) { if ($hasZeroIndex && is_int($key)) { $this->bindValue($key + 1, $val); } else { $this->bindValue($key, $val); } } } if (! sasql_stmt_execute($this->stmt)) { throw SQLAnywhereException::fromSQLAnywhereError($this->conn, $this->stmt); } $this->result = sasql_stmt_result_metadata($this->stmt); return true; } /** * {@inheritdoc} * * @throws SQLAnywhereException */ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) { if (! is_resource($this->result)) { return false; } $fetchMode = $fetchMode ?: $this->defaultFetchMode; switch ($fetchMode) { case FetchMode::COLUMN: return $this->fetchColumn(); case FetchMode::ASSOCIATIVE: return sasql_fetch_assoc($this->result); case FetchMode::MIXED: return sasql_fetch_array($this->result, SASQL_BOTH); case FetchMode::CUSTOM_OBJECT: $className = $this->defaultFetchClass; $ctorArgs = $this->defaultFetchClassCtorArgs; if (func_num_args() >= 2) { $args = func_get_args(); $className = $args[1]; $ctorArgs = $args[2] ?? []; } $result = sasql_fetch_object($this->result); if ($result instanceof stdClass) { $result = $this->castObject($result, $className, $ctorArgs); } return $result; case FetchMode::NUMERIC: return sasql_fetch_row($this->result); case FetchMode::STANDARD_OBJECT: return sasql_fetch_object($this->result); default: throw new SQLAnywhereException('Fetch mode is not supported: ' . $fetchMode); } } /** * {@inheritdoc} */ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) { $rows = []; switch ($fetchMode) { case FetchMode::CUSTOM_OBJECT: while (($row = $this->fetch(...func_get_args())) !== false) { $rows[] = $row; } break; case FetchMode::COLUMN: while (($row = $this->fetchColumn()) !== false) { $rows[] = $row; } break; default: while (($row = $this->fetch($fetchMode)) !== false) { $rows[] = $row; } } return $rows; } /** * {@inheritdoc} */ public function fetchColumn($columnIndex = 0) { $row = $this->fetch(FetchMode::NUMERIC); if ($row === false) { return false; } return $row[$columnIndex] ?? null; } /** * {@inheritdoc} */ public function getIterator() { return new StatementIterator($this); } /** * {@inheritdoc} */ public function rowCount() { return sasql_stmt_affected_rows($this->stmt); } /** * {@inheritdoc} */ public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) { $this->defaultFetchMode = $fetchMode; $this->defaultFetchClass = $arg2 ?: $this->defaultFetchClass; $this->defaultFetchClassCtorArgs = $arg3 ? (array) $arg3 : $this->defaultFetchClassCtorArgs; } /** * Casts a stdClass object to the given class name mapping its' properties. * * @param stdClass $sourceObject Object to cast from. * @param string|object $destinationClass Name of the class or class instance to cast to. * @param mixed[] $ctorArgs Arguments to use for constructing the destination class instance. * * @return object * * @throws SQLAnywhereException */ private function castObject(stdClass $sourceObject, $destinationClass, array $ctorArgs = []) { if (! is_string($destinationClass)) { if (! is_object($destinationClass)) { throw new SQLAnywhereException(sprintf( 'Destination class has to be of type string or object, %s given.', gettype($destinationClass) )); } } else { $destinationClass = new ReflectionClass($destinationClass); $destinationClass = $destinationClass->newInstanceArgs($ctorArgs); } $sourceReflection = new ReflectionObject($sourceObject); $destinationClassReflection = new ReflectionObject($destinationClass); foreach ($sourceReflection->getProperties() as $sourceProperty) { $sourceProperty->setAccessible(true); $name = $sourceProperty->getName(); $value = $sourceProperty->getValue($sourceObject); if ($destinationClassReflection->hasProperty($name)) { $destinationProperty = $destinationClassReflection->getProperty($name); $destinationProperty->setAccessible(true); $destinationProperty->setValue($destinationClass, $value); } else { $destinationClass->$name = $value; } } return $destinationClass; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/SQLSrv/000077500000000000000000000000001360544566000225045ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/SQLSrv/Driver.php000066400000000000000000000025161360544566000244540ustar00rootroot00000000000000id = $id; } /** * @return int */ public function getId() { return $this->id; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvConnection.php000066400000000000000000000102301360544566000263630ustar00rootroot00000000000000conn = $conn; $this->lastInsertId = new LastInsertId(); } /** * {@inheritdoc} */ public function getServerVersion() { $serverInfo = sqlsrv_server_info($this->conn); return $serverInfo['SQLServerVersion']; } /** * {@inheritdoc} */ public function requiresQueryForServerVersion() { return false; } /** * {@inheritDoc} */ public function prepare($sql) { return new SQLSrvStatement($this->conn, $sql, $this->lastInsertId); } /** * {@inheritDoc} */ public function query() { $args = func_get_args(); $sql = $args[0]; $stmt = $this->prepare($sql); $stmt->execute(); return $stmt; } /** * {@inheritDoc} */ public function quote($value, $type = ParameterType::STRING) { if (is_int($value)) { return $value; } if (is_float($value)) { return sprintf('%F', $value); } return "'" . str_replace("'", "''", $value) . "'"; } /** * {@inheritDoc} */ public function exec($statement) { $stmt = sqlsrv_query($this->conn, $statement); if ($stmt === false) { throw SQLSrvException::fromSqlSrvErrors(); } $rowsAffected = sqlsrv_rows_affected($stmt); if ($rowsAffected === false) { throw SQLSrvException::fromSqlSrvErrors(); } return $rowsAffected; } /** * {@inheritDoc} */ public function lastInsertId($name = null) { if ($name !== null) { $stmt = $this->prepare('SELECT CONVERT(VARCHAR(MAX), current_value) FROM sys.sequences WHERE name = ?'); $stmt->execute([$name]); } else { $stmt = $this->query('SELECT @@IDENTITY'); } return $stmt->fetchColumn(); } /** * {@inheritDoc} */ public function beginTransaction() { if (! sqlsrv_begin_transaction($this->conn)) { throw SQLSrvException::fromSqlSrvErrors(); } } /** * {@inheritDoc} */ public function commit() { if (! sqlsrv_commit($this->conn)) { throw SQLSrvException::fromSqlSrvErrors(); } } /** * {@inheritDoc} */ public function rollBack() { if (! sqlsrv_rollback($this->conn)) { throw SQLSrvException::fromSqlSrvErrors(); } } /** * {@inheritDoc} */ public function errorCode() { $errors = sqlsrv_errors(SQLSRV_ERR_ERRORS); if ($errors) { return $errors[0]['code']; } return false; } /** * {@inheritDoc} */ public function errorInfo() { return (array) sqlsrv_errors(SQLSRV_ERR_ERRORS); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvException.php000066400000000000000000000021661360544566000262330ustar00rootroot00000000000000 SQLSRV_FETCH_BOTH, FetchMode::ASSOCIATIVE => SQLSRV_FETCH_ASSOC, FetchMode::NUMERIC => SQLSRV_FETCH_NUMERIC, ]; /** * The name of the default class to instantiate when fetching class instances. * * @var string */ private $defaultFetchClass = '\stdClass'; /** * The constructor arguments for the default class to instantiate when fetching class instances. * * @var mixed[] */ private $defaultFetchClassCtorArgs = []; /** * The fetch style. * * @var int */ private $defaultFetchMode = FetchMode::MIXED; /** * The last insert ID. * * @var LastInsertId|null */ private $lastInsertId; /** * Indicates whether the statement is in the state when fetching results is possible * * @var bool */ private $result = false; /** * Append to any INSERT query to retrieve the last insert id. * * @deprecated This constant has been deprecated and will be made private in 3.0 */ public const LAST_INSERT_ID_SQL = ';SELECT SCOPE_IDENTITY() AS LastInsertId;'; /** * @param resource $conn * @param string $sql */ public function __construct($conn, $sql, ?LastInsertId $lastInsertId = null) { $this->conn = $conn; $this->sql = $sql; if (stripos($sql, 'INSERT INTO ') !== 0) { return; } $this->sql .= self::LAST_INSERT_ID_SQL; $this->lastInsertId = $lastInsertId; } /** * {@inheritdoc} */ public function bindValue($param, $value, $type = ParameterType::STRING) { if (! is_numeric($param)) { throw new SQLSrvException( 'sqlsrv does not support named parameters to queries, use question mark (?) placeholders instead.' ); } $this->variables[$param] = $value; $this->types[$param] = $type; } /** * {@inheritdoc} */ public function bindParam($column, &$variable, $type = ParameterType::STRING, $length = null) { if (! is_numeric($column)) { throw new SQLSrvException('sqlsrv does not support named parameters to queries, use question mark (?) placeholders instead.'); } $this->variables[$column] =& $variable; $this->types[$column] = $type; // unset the statement resource if it exists as the new one will need to be bound to the new variable $this->stmt = null; } /** * {@inheritdoc} */ public function closeCursor() { // not having the result means there's nothing to close if ($this->stmt === null || ! $this->result) { return true; } // emulate it by fetching and discarding rows, similarly to what PDO does in this case // @link http://php.net/manual/en/pdostatement.closecursor.php // @link https://github.com/php/php-src/blob/php-7.0.11/ext/pdo/pdo_stmt.c#L2075 // deliberately do not consider multiple result sets, since doctrine/dbal doesn't support them while (sqlsrv_fetch($this->stmt)) { } $this->result = false; return true; } /** * {@inheritdoc} */ public function columnCount() { if ($this->stmt === null) { return 0; } return sqlsrv_num_fields($this->stmt) ?: 0; } /** * {@inheritdoc} */ public function errorCode() { $errors = sqlsrv_errors(SQLSRV_ERR_ERRORS); if ($errors) { return $errors[0]['code']; } return false; } /** * {@inheritdoc} */ public function errorInfo() { return (array) sqlsrv_errors(SQLSRV_ERR_ERRORS); } /** * {@inheritdoc} */ public function execute($params = null) { if ($params) { $hasZeroIndex = array_key_exists(0, $params); foreach ($params as $key => $val) { if ($hasZeroIndex && is_int($key)) { $this->bindValue($key + 1, $val); } else { $this->bindValue($key, $val); } } } if (! $this->stmt) { $this->stmt = $this->prepare(); } if (! sqlsrv_execute($this->stmt)) { throw SQLSrvException::fromSqlSrvErrors(); } if ($this->lastInsertId) { sqlsrv_next_result($this->stmt); sqlsrv_fetch($this->stmt); $this->lastInsertId->setId(sqlsrv_get_field($this->stmt, 0)); } $this->result = true; } /** * Prepares SQL Server statement resource * * @return resource * * @throws SQLSrvException */ private function prepare() { $params = []; foreach ($this->variables as $column => &$variable) { switch ($this->types[$column]) { case ParameterType::LARGE_OBJECT: $params[$column - 1] = [ &$variable, SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STREAM(SQLSRV_ENC_BINARY), SQLSRV_SQLTYPE_VARBINARY('max'), ]; break; case ParameterType::BINARY: $params[$column - 1] = [ &$variable, SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_BINARY), ]; break; default: $params[$column - 1] =& $variable; break; } } $stmt = sqlsrv_prepare($this->conn, $this->sql, $params); if (! $stmt) { throw SQLSrvException::fromSqlSrvErrors(); } return $stmt; } /** * {@inheritdoc} */ public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) { $this->defaultFetchMode = $fetchMode; $this->defaultFetchClass = $arg2 ?: $this->defaultFetchClass; $this->defaultFetchClassCtorArgs = $arg3 ? (array) $arg3 : $this->defaultFetchClassCtorArgs; return true; } /** * {@inheritdoc} */ public function getIterator() { return new StatementIterator($this); } /** * {@inheritdoc} * * @throws SQLSrvException */ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) { // do not try fetching from the statement if it's not expected to contain result // in order to prevent exceptional situation if ($this->stmt === null || ! $this->result) { return false; } $args = func_get_args(); $fetchMode = $fetchMode ?: $this->defaultFetchMode; if ($fetchMode === FetchMode::COLUMN) { return $this->fetchColumn(); } if (isset(self::$fetchMap[$fetchMode])) { return sqlsrv_fetch_array($this->stmt, self::$fetchMap[$fetchMode]) ?: false; } if (in_array($fetchMode, [FetchMode::STANDARD_OBJECT, FetchMode::CUSTOM_OBJECT], true)) { $className = $this->defaultFetchClass; $ctorArgs = $this->defaultFetchClassCtorArgs; if (count($args) >= 2) { $className = $args[1]; $ctorArgs = $args[2] ?? []; } return sqlsrv_fetch_object($this->stmt, $className, $ctorArgs) ?: false; } throw new SQLSrvException('Fetch mode is not supported!'); } /** * {@inheritdoc} */ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) { $rows = []; switch ($fetchMode) { case FetchMode::CUSTOM_OBJECT: while (($row = $this->fetch(...func_get_args())) !== false) { $rows[] = $row; } break; case FetchMode::COLUMN: while (($row = $this->fetchColumn()) !== false) { $rows[] = $row; } break; default: while (($row = $this->fetch($fetchMode)) !== false) { $rows[] = $row; } } return $rows; } /** * {@inheritdoc} */ public function fetchColumn($columnIndex = 0) { $row = $this->fetch(FetchMode::NUMERIC); if ($row === false) { return false; } return $row[$columnIndex] ?? null; } /** * {@inheritdoc} */ public function rowCount() { if ($this->stmt === null) { return 0; } return sqlsrv_rows_affected($this->stmt) ?: 0; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/ServerInfoAwareConnection.php000066400000000000000000000011441360544566000271450ustar00rootroot00000000000000bindValue(), * the variable is bound as a reference and will only be evaluated at the time * that PDOStatement->execute() is called. * * As mentioned above, the named parameters are not natively supported by the mysqli driver, use executeQuery(), * fetchAll(), fetchArray(), fetchColumn(), fetchAssoc() methods to have the named parameter emulated by doctrine. * * Most parameters are input parameters, that is, parameters that are * used in a read-only fashion to build up the query. Some drivers support the invocation * of stored procedures that return data as output parameters, and some also as input/output * parameters that both send in data and are updated to receive it. * * @param mixed $column Parameter identifier. For a prepared statement using named placeholders, * this will be a parameter name of the form :name. For a prepared statement using * question mark placeholders, this will be the 1-indexed position of the parameter. * @param mixed $variable Name of the PHP variable to bind to the SQL statement parameter. * @param int $type Explicit data type for the parameter using the {@link \Doctrine\DBAL\ParameterType} * constants. To return an INOUT parameter from a stored procedure, use the bitwise * OR operator to set the PDO::PARAM_INPUT_OUTPUT bits for the data_type parameter. * @param int|null $length You must specify maxlength when using an OUT bind * so that PHP allocates enough memory to hold the returned value. * * @return bool TRUE on success or FALSE on failure. */ public function bindParam($column, &$variable, $type = ParameterType::STRING, $length = null); /** * Fetches the SQLSTATE associated with the last operation on the statement handle. * * @see Doctrine_Adapter_Interface::errorCode() * * @return string|int|bool The error code string. */ public function errorCode(); /** * Fetches extended error information associated with the last operation on the statement handle. * * @return mixed[] The error info array. */ public function errorInfo(); /** * Executes a prepared statement * * If the prepared statement included parameter markers, you must either: * call PDOStatement->bindParam() to bind PHP variables to the parameter markers: * bound variables pass their value as input and receive the output value, * if any, of their associated parameter markers or pass an array of input-only * parameter values. * * @param mixed[]|null $params An array of values with as many elements as there are * bound parameters in the SQL statement being executed. * * @return bool TRUE on success or FALSE on failure. */ public function execute($params = null); /** * Returns the number of rows affected by the last DELETE, INSERT, or UPDATE statement * executed by the corresponding object. * * If the last SQL statement executed by the associated Statement object was a SELECT statement, * some databases may return the number of rows returned by that statement. However, * this behaviour is not guaranteed for all databases and should not be * relied on for portable applications. * * @return int The number of rows. */ public function rowCount(); } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Driver/StatementIterator.php000066400000000000000000000007341360544566000255450ustar00rootroot00000000000000statement = $statement; } /** * {@inheritdoc} */ public function getIterator() { while (($result = $this->statement->fetch()) !== false) { yield $result; } } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/DriverManager.php000066400000000000000000000352541360544566000233670ustar00rootroot00000000000000 PDOMySQLDriver::class, 'pdo_sqlite' => PDOSQLiteDriver::class, 'pdo_pgsql' => PDOPgSQLDriver::class, 'pdo_oci' => PDOOCIDriver::class, 'oci8' => OCI8Driver::class, 'ibm_db2' => DB2Driver::class, 'pdo_sqlsrv' => PDOSQLSrvDriver::class, 'mysqli' => MySQLiDriver::class, 'drizzle_pdo_mysql' => DrizzlePDOMySQLDriver::class, 'sqlanywhere' => SQLAnywhereDriver::class, 'sqlsrv' => SQLSrvDriver::class, ]; /** * List of URL schemes from a database URL and their mappings to driver. * * @var string[] */ private static $driverSchemeAliases = [ 'db2' => 'ibm_db2', 'mssql' => 'pdo_sqlsrv', 'mysql' => 'pdo_mysql', 'mysql2' => 'pdo_mysql', // Amazon RDS, for some weird reason 'postgres' => 'pdo_pgsql', 'postgresql' => 'pdo_pgsql', 'pgsql' => 'pdo_pgsql', 'sqlite' => 'pdo_sqlite', 'sqlite3' => 'pdo_sqlite', ]; /** * Private constructor. This class cannot be instantiated. */ private function __construct() { } /** * Creates a connection object based on the specified parameters. * This method returns a Doctrine\DBAL\Connection which wraps the underlying * driver connection. * * $params must contain at least one of the following. * * Either 'driver' with one of the following values: * * pdo_mysql * pdo_sqlite * pdo_pgsql * pdo_oci (unstable) * pdo_sqlsrv * pdo_sqlsrv * mysqli * sqlanywhere * sqlsrv * ibm_db2 (unstable) * drizzle_pdo_mysql * * OR 'driverClass' that contains the full class name (with namespace) of the * driver class to instantiate. * * Other (optional) parameters: * * user (string): * The username to use when connecting. * * password (string): * The password to use when connecting. * * driverOptions (array): * Any additional driver-specific options for the driver. These are just passed * through to the driver. * * pdo: * You can pass an existing PDO instance through this parameter. The PDO * instance will be wrapped in a Doctrine\DBAL\Connection. * * wrapperClass: * You may specify a custom wrapper class through the 'wrapperClass' * parameter but this class MUST inherit from Doctrine\DBAL\Connection. * * driverClass: * The driver class to use. * * @param mixed[] $params The parameters. * @param Configuration|null $config The configuration to use. * @param EventManager|null $eventManager The event manager to use. * * @throws DBALException */ public static function getConnection( array $params, ?Configuration $config = null, ?EventManager $eventManager = null ) : Connection { // create default config and event manager, if not set if (! $config) { $config = new Configuration(); } if (! $eventManager) { $eventManager = new EventManager(); } $params = self::parseDatabaseUrl($params); // URL support for MasterSlaveConnection if (isset($params['master'])) { $params['master'] = self::parseDatabaseUrl($params['master']); } if (isset($params['slaves'])) { foreach ($params['slaves'] as $key => $slaveParams) { $params['slaves'][$key] = self::parseDatabaseUrl($slaveParams); } } // URL support for PoolingShardConnection if (isset($params['global'])) { $params['global'] = self::parseDatabaseUrl($params['global']); } if (isset($params['shards'])) { foreach ($params['shards'] as $key => $shardParams) { $params['shards'][$key] = self::parseDatabaseUrl($shardParams); } } // check for existing pdo object if (isset($params['pdo']) && ! $params['pdo'] instanceof PDO) { throw DBALException::invalidPdoInstance(); } if (isset($params['pdo'])) { $params['pdo']->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $params['driver'] = 'pdo_' . $params['pdo']->getAttribute(PDO::ATTR_DRIVER_NAME); } else { self::_checkParams($params); } $className = $params['driverClass'] ?? self::$_driverMap[$params['driver']]; $driver = new $className(); $wrapperClass = Connection::class; if (isset($params['wrapperClass'])) { if (! is_subclass_of($params['wrapperClass'], $wrapperClass)) { throw DBALException::invalidWrapperClass($params['wrapperClass']); } $wrapperClass = $params['wrapperClass']; } return new $wrapperClass($params, $driver, $config, $eventManager); } /** * Returns the list of supported drivers. * * @return string[] */ public static function getAvailableDrivers() : array { return array_keys(self::$_driverMap); } /** * Checks the list of parameters. * * @param mixed[] $params The list of parameters. * * @throws DBALException */ private static function _checkParams(array $params) : void { // check existence of mandatory parameters // driver if (! isset($params['driver']) && ! isset($params['driverClass'])) { throw DBALException::driverRequired(); } // check validity of parameters // driver if (isset($params['driver']) && ! isset(self::$_driverMap[$params['driver']])) { throw DBALException::unknownDriver($params['driver'], array_keys(self::$_driverMap)); } if (isset($params['driverClass']) && ! in_array(Driver::class, class_implements($params['driverClass'], true))) { throw DBALException::invalidDriverClass($params['driverClass']); } } /** * Normalizes the given connection URL path. * * @return string The normalized connection URL path */ private static function normalizeDatabaseUrlPath(string $urlPath) : string { // Trim leading slash from URL path. return substr($urlPath, 1); } /** * Extracts parts from a database URL, if present, and returns an * updated list of parameters. * * @param mixed[] $params The list of parameters. * * @return mixed[] A modified list of parameters with info from a database * URL extracted into indidivual parameter parts. * * @throws DBALException */ private static function parseDatabaseUrl(array $params) : array { if (! isset($params['url'])) { return $params; } // (pdo_)?sqlite3?:///... => (pdo_)?sqlite3?://localhost/... or else the URL will be invalid $url = preg_replace('#^((?:pdo_)?sqlite3?):///#', '$1://localhost/', $params['url']); assert(is_string($url)); $url = parse_url($url); if ($url === false) { throw new DBALException('Malformed parameter "url".'); } $url = array_map('rawurldecode', $url); // If we have a connection URL, we have to unset the default PDO instance connection parameter (if any) // as we cannot merge connection details from the URL into the PDO instance (URL takes precedence). unset($params['pdo']); $params = self::parseDatabaseUrlScheme($url, $params); if (isset($url['host'])) { $params['host'] = $url['host']; } if (isset($url['port'])) { $params['port'] = $url['port']; } if (isset($url['user'])) { $params['user'] = $url['user']; } if (isset($url['pass'])) { $params['password'] = $url['pass']; } $params = self::parseDatabaseUrlPath($url, $params); $params = self::parseDatabaseUrlQuery($url, $params); return $params; } /** * Parses the given connection URL and resolves the given connection parameters. * * Assumes that the connection URL scheme is already parsed and resolved into the given connection parameters * via {@link parseDatabaseUrlScheme}. * * @see parseDatabaseUrlScheme * * @param mixed[] $url The URL parts to evaluate. * @param mixed[] $params The connection parameters to resolve. * * @return mixed[] The resolved connection parameters. */ private static function parseDatabaseUrlPath(array $url, array $params) : array { if (! isset($url['path'])) { return $params; } $url['path'] = self::normalizeDatabaseUrlPath($url['path']); // If we do not have a known DBAL driver, we do not know any connection URL path semantics to evaluate // and therefore treat the path as regular DBAL connection URL path. if (! isset($params['driver'])) { return self::parseRegularDatabaseUrlPath($url, $params); } if (strpos($params['driver'], 'sqlite') !== false) { return self::parseSqliteDatabaseUrlPath($url, $params); } return self::parseRegularDatabaseUrlPath($url, $params); } /** * Parses the query part of the given connection URL and resolves the given connection parameters. * * @param mixed[] $url The connection URL parts to evaluate. * @param mixed[] $params The connection parameters to resolve. * * @return mixed[] The resolved connection parameters. */ private static function parseDatabaseUrlQuery(array $url, array $params) : array { if (! isset($url['query'])) { return $params; } $query = []; parse_str($url['query'], $query); // simply ingest query as extra params, e.g. charset or sslmode return array_merge($params, $query); // parse_str wipes existing array elements } /** * Parses the given regular connection URL and resolves the given connection parameters. * * Assumes that the "path" URL part is already normalized via {@link normalizeDatabaseUrlPath}. * * @see normalizeDatabaseUrlPath * * @param mixed[] $url The regular connection URL parts to evaluate. * @param mixed[] $params The connection parameters to resolve. * * @return mixed[] The resolved connection parameters. */ private static function parseRegularDatabaseUrlPath(array $url, array $params) : array { $params['dbname'] = $url['path']; return $params; } /** * Parses the given SQLite connection URL and resolves the given connection parameters. * * Assumes that the "path" URL part is already normalized via {@link normalizeDatabaseUrlPath}. * * @see normalizeDatabaseUrlPath * * @param mixed[] $url The SQLite connection URL parts to evaluate. * @param mixed[] $params The connection parameters to resolve. * * @return mixed[] The resolved connection parameters. */ private static function parseSqliteDatabaseUrlPath(array $url, array $params) : array { if ($url['path'] === ':memory:') { $params['memory'] = true; return $params; } $params['path'] = $url['path']; // pdo_sqlite driver uses 'path' instead of 'dbname' key return $params; } /** * Parses the scheme part from given connection URL and resolves the given connection parameters. * * @param mixed[] $url The connection URL parts to evaluate. * @param mixed[] $params The connection parameters to resolve. * * @return mixed[] The resolved connection parameters. * * @throws DBALException If parsing failed or resolution is not possible. */ private static function parseDatabaseUrlScheme(array $url, array $params) : array { if (isset($url['scheme'])) { // The requested driver from the URL scheme takes precedence // over the default custom driver from the connection parameters (if any). unset($params['driverClass']); // URL schemes must not contain underscores, but dashes are ok $driver = str_replace('-', '_', $url['scheme']); assert(is_string($driver)); // The requested driver from the URL scheme takes precedence over the // default driver from the connection parameters. If the driver is // an alias (e.g. "postgres"), map it to the actual name ("pdo-pgsql"). // Otherwise, let checkParams decide later if the driver exists. $params['driver'] = self::$driverSchemeAliases[$driver] ?? $driver; return $params; } // If a schemeless connection URL is given, we require a default driver or default custom driver // as connection parameter. if (! isset($params['driverClass']) && ! isset($params['driver'])) { throw DBALException::driverRequired($params['url']); } return $params; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Event/000077500000000000000000000000001360544566000212005ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Event/ConnectionEventArgs.php000066400000000000000000000026371360544566000256370ustar00rootroot00000000000000connection = $connection; } /** * @return Connection */ public function getConnection() { return $this->connection; } /** * @deprecated Use ConnectionEventArgs::getConnection() and Connection::getDriver() instead. * * @return Driver */ public function getDriver() { return $this->connection->getDriver(); } /** * @deprecated Use ConnectionEventArgs::getConnection() and Connection::getDatabasePlatform() instead. * * @return AbstractPlatform */ public function getDatabasePlatform() { return $this->connection->getDatabasePlatform(); } /** * @deprecated Use ConnectionEventArgs::getConnection() and Connection::getSchemaManager() instead. * * @return AbstractSchemaManager */ public function getSchemaManager() { return $this->connection->getSchemaManager(); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Event/Listeners/000077500000000000000000000000001360544566000231505ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Event/Listeners/MysqlSessionInit.php000066400000000000000000000025631360544566000271640ustar00rootroot00000000000000charset = $charset; $this->collation = $collation; } /** * @return void */ public function postConnect(ConnectionEventArgs $args) { $collation = $this->collation ? ' COLLATE ' . $this->collation : ''; $args->getConnection()->executeUpdate('SET NAMES ' . $this->charset . $collation); } /** * {@inheritdoc} */ public function getSubscribedEvents() { return [Events::postConnect]; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Event/Listeners/OracleSessionInit.php000066400000000000000000000040521360544566000272570ustar00rootroot00000000000000 'HH24:MI:SS', 'NLS_DATE_FORMAT' => 'YYYY-MM-DD HH24:MI:SS', 'NLS_TIMESTAMP_FORMAT' => 'YYYY-MM-DD HH24:MI:SS', 'NLS_TIMESTAMP_TZ_FORMAT' => 'YYYY-MM-DD HH24:MI:SS TZH:TZM', 'NLS_NUMERIC_CHARACTERS' => '.,', ]; /** * @param string[] $oracleSessionVars */ public function __construct(array $oracleSessionVars = []) { $this->_defaultSessionVars = array_merge($this->_defaultSessionVars, $oracleSessionVars); } /** * @return void */ public function postConnect(ConnectionEventArgs $args) { if (! count($this->_defaultSessionVars)) { return; } array_change_key_case($this->_defaultSessionVars, CASE_UPPER); $vars = []; foreach ($this->_defaultSessionVars as $option => $value) { if ($option === 'CURRENT_SCHEMA') { $vars[] = $option . ' = ' . $value; } else { $vars[] = $option . " = '" . $value . "'"; } } $sql = 'ALTER SESSION SET ' . implode(' ', $vars); $args->getConnection()->executeUpdate($sql); } /** * {@inheritdoc} */ public function getSubscribedEvents() { return [Events::postConnect]; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Event/Listeners/SQLSessionInit.php000066400000000000000000000014261360544566000265130ustar00rootroot00000000000000sql = $sql; } /** * @return void */ public function postConnect(ConnectionEventArgs $args) { $conn = $args->getConnection(); $conn->exec($this->sql); } /** * {@inheritdoc} */ public function getSubscribedEvents() { return [Events::postConnect]; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Event/SchemaAlterTableAddColumnEventArgs.php000066400000000000000000000033131360544566000304570ustar00rootroot00000000000000column = $column; $this->tableDiff = $tableDiff; $this->platform = $platform; } /** * @return Column */ public function getColumn() { return $this->column; } /** * @return TableDiff */ public function getTableDiff() { return $this->tableDiff; } /** * @return AbstractPlatform */ public function getPlatform() { return $this->platform; } /** * Passing multiple SQL statements as an array is deprecated. Pass each statement as an individual argument instead. * * @param string|string[] $sql * * @return \Doctrine\DBAL\Event\SchemaAlterTableAddColumnEventArgs */ public function addSql($sql) { $this->sql = array_merge($this->sql, is_array($sql) ? $sql : func_get_args()); return $this; } /** * @return string[] */ public function getSql() { return $this->sql; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Event/SchemaAlterTableChangeColumnEventArgs.php000066400000000000000000000033721360544566000311610ustar00rootroot00000000000000columnDiff = $columnDiff; $this->tableDiff = $tableDiff; $this->platform = $platform; } /** * @return ColumnDiff */ public function getColumnDiff() { return $this->columnDiff; } /** * @return TableDiff */ public function getTableDiff() { return $this->tableDiff; } /** * @return AbstractPlatform */ public function getPlatform() { return $this->platform; } /** * Passing multiple SQL statements as an array is deprecated. Pass each statement as an individual argument instead. * * @param string|string[] $sql * * @return \Doctrine\DBAL\Event\SchemaAlterTableChangeColumnEventArgs */ public function addSql($sql) { $this->sql = array_merge($this->sql, is_array($sql) ? $sql : func_get_args()); return $this; } /** * @return string[] */ public function getSql() { return $this->sql; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Event/SchemaAlterTableEventArgs.php000066400000000000000000000027011360544566000266700ustar00rootroot00000000000000tableDiff = $tableDiff; $this->platform = $platform; } /** * @return TableDiff */ public function getTableDiff() { return $this->tableDiff; } /** * @return AbstractPlatform */ public function getPlatform() { return $this->platform; } /** * Passing multiple SQL statements as an array is deprecated. Pass each statement as an individual argument instead. * * @param string|string[] $sql * * @return \Doctrine\DBAL\Event\SchemaAlterTableEventArgs */ public function addSql($sql) { $this->sql = array_merge($this->sql, is_array($sql) ? $sql : func_get_args()); return $this; } /** * @return string[] */ public function getSql() { return $this->sql; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Event/SchemaAlterTableRemoveColumnEventArgs.php000066400000000000000000000033231360544566000312250ustar00rootroot00000000000000column = $column; $this->tableDiff = $tableDiff; $this->platform = $platform; } /** * @return Column */ public function getColumn() { return $this->column; } /** * @return TableDiff */ public function getTableDiff() { return $this->tableDiff; } /** * @return AbstractPlatform */ public function getPlatform() { return $this->platform; } /** * Passing multiple SQL statements as an array is deprecated. Pass each statement as an individual argument instead. * * @param string|string[] $sql * * @return \Doctrine\DBAL\Event\SchemaAlterTableRemoveColumnEventArgs */ public function addSql($sql) { $this->sql = array_merge($this->sql, is_array($sql) ? $sql : func_get_args()); return $this; } /** * @return string[] */ public function getSql() { return $this->sql; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Event/SchemaAlterTableRenameColumnEventArgs.php000066400000000000000000000040051360544566000311750ustar00rootroot00000000000000oldColumnName = $oldColumnName; $this->column = $column; $this->tableDiff = $tableDiff; $this->platform = $platform; } /** * @return string */ public function getOldColumnName() { return $this->oldColumnName; } /** * @return Column */ public function getColumn() { return $this->column; } /** * @return TableDiff */ public function getTableDiff() { return $this->tableDiff; } /** * @return AbstractPlatform */ public function getPlatform() { return $this->platform; } /** * Passing multiple SQL statements as an array is deprecated. Pass each statement as an individual argument instead. * * @param string|string[] $sql * * @return \Doctrine\DBAL\Event\SchemaAlterTableRenameColumnEventArgs */ public function addSql($sql) { $this->sql = array_merge($this->sql, is_array($sql) ? $sql : func_get_args()); return $this; } /** * @return string[] */ public function getSql() { return $this->sql; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Event/SchemaColumnDefinitionEventArgs.php000066400000000000000000000043151360544566000301220ustar00rootroot00000000000000tableColumn = $tableColumn; $this->table = $table; $this->database = $database; $this->connection = $connection; } /** * Allows to clear the column which means the column will be excluded from * tables column list. * * @return \Doctrine\DBAL\Event\SchemaColumnDefinitionEventArgs */ public function setColumn(?Column $column = null) { $this->column = $column; return $this; } /** * @return Column|null */ public function getColumn() { return $this->column; } /** * @return mixed[] */ public function getTableColumn() { return $this->tableColumn; } /** * @return string */ public function getTable() { return $this->table; } /** * @return string */ public function getDatabase() { return $this->database; } /** * @return Connection */ public function getConnection() { return $this->connection; } /** * @deprecated Use SchemaColumnDefinitionEventArgs::getConnection() and Connection::getDatabasePlatform() instead. * * @return AbstractPlatform */ public function getDatabasePlatform() { return $this->connection->getDatabasePlatform(); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Event/SchemaCreateTableColumnEventArgs.php000066400000000000000000000032511360544566000302030ustar00rootroot00000000000000column = $column; $this->table = $table; $this->platform = $platform; } /** * @return Column */ public function getColumn() { return $this->column; } /** * @return Table */ public function getTable() { return $this->table; } /** * @return AbstractPlatform */ public function getPlatform() { return $this->platform; } /** * Passing multiple SQL statements as an array is deprecated. Pass each statement as an individual argument instead. * * @param string|string[] $sql * * @return \Doctrine\DBAL\Event\SchemaCreateTableColumnEventArgs */ public function addSql($sql) { $this->sql = array_merge($this->sql, is_array($sql) ? $sql : func_get_args()); return $this; } /** * @return string[] */ public function getSql() { return $this->sql; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Event/SchemaCreateTableEventArgs.php000066400000000000000000000036501360544566000270300ustar00rootroot00000000000000table = $table; $this->columns = $columns; $this->options = $options; $this->platform = $platform; } /** * @return Table */ public function getTable() { return $this->table; } /** * @return mixed[][] */ public function getColumns() { return $this->columns; } /** * @return mixed[] */ public function getOptions() { return $this->options; } /** * @return AbstractPlatform */ public function getPlatform() { return $this->platform; } /** * Passing multiple SQL statements as an array is deprecated. Pass each statement as an individual argument instead. * * @param string|string[] $sql * * @return \Doctrine\DBAL\Event\SchemaCreateTableEventArgs */ public function addSql($sql) { $this->sql = array_merge($this->sql, is_array($sql) ? $sql : func_get_args()); return $this; } /** * @return string[] */ public function getSql() { return $this->sql; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Event/SchemaDropTableEventArgs.php000066400000000000000000000024371360544566000265330ustar00rootroot00000000000000table = $table; $this->platform = $platform; } /** * @return string|Table */ public function getTable() { return $this->table; } /** * @return AbstractPlatform */ public function getPlatform() { return $this->platform; } /** * @param string $sql * * @return \Doctrine\DBAL\Event\SchemaDropTableEventArgs */ public function setSql($sql) { $this->sql = $sql; return $this; } /** * @return string|null */ public function getSql() { return $this->sql; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Event/SchemaEventArgs.php000066400000000000000000000010211360544566000247220ustar00rootroot00000000000000preventDefault = true; return $this; } /** * @return bool */ public function isDefaultPrevented() { return $this->preventDefault; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Event/SchemaIndexDefinitionEventArgs.php000066400000000000000000000034411360544566000277330ustar00rootroot00000000000000tableIndex = $tableIndex; $this->table = $table; $this->connection = $connection; } /** * Allows to clear the index which means the index will be excluded from tables index list. * * @return SchemaIndexDefinitionEventArgs */ public function setIndex(?Index $index = null) { $this->index = $index; return $this; } /** * @return Index|null */ public function getIndex() { return $this->index; } /** * @return mixed[] */ public function getTableIndex() { return $this->tableIndex; } /** * @return string */ public function getTable() { return $this->table; } /** * @return Connection */ public function getConnection() { return $this->connection; } /** * @return AbstractPlatform */ public function getDatabasePlatform() { return $this->connection->getDatabasePlatform(); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Events.php000066400000000000000000000021101360544566000220660ustar00rootroot00000000000000driverException = $driverException; } /** * Returns the driver specific error code if given. * * Returns null if no error code was given by the driver. * * @return int|string|null */ public function getErrorCode() { return $this->driverException->getErrorCode(); } /** * Returns the SQLSTATE the driver was in at the time the error occurred, if given. * * Returns null if no SQLSTATE was given by the driver. * * @return string|null */ public function getSQLState() { return $this->driverException->getSQLState(); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Exception/ForeignKeyConstraintViolationException.php000066400000000000000000000003251360544566000324410ustar00rootroot00000000000000getParams(); if ($params['driver'] === 'pdo_sqlite') { throw new DBALException('Cannot use TableGenerator with SQLite.'); } $this->conn = DriverManager::getConnection($params, $conn->getConfiguration(), $conn->getEventManager()); $this->generatorTableName = $generatorTableName; } /** * Generates the next unused value for the given sequence name. * * @param string $sequenceName * * @return int * * @throws DBALException */ public function nextValue($sequenceName) { if (isset($this->sequences[$sequenceName])) { $value = $this->sequences[$sequenceName]['value']; $this->sequences[$sequenceName]['value']++; if ($this->sequences[$sequenceName]['value'] >= $this->sequences[$sequenceName]['max']) { unset($this->sequences[$sequenceName]); } return $value; } $this->conn->beginTransaction(); try { $platform = $this->conn->getDatabasePlatform(); $sql = 'SELECT sequence_value, sequence_increment_by' . ' FROM ' . $platform->appendLockHint($this->generatorTableName, LockMode::PESSIMISTIC_WRITE) . ' WHERE sequence_name = ? ' . $platform->getWriteLockSQL(); $stmt = $this->conn->executeQuery($sql, [$sequenceName]); $row = $stmt->fetch(FetchMode::ASSOCIATIVE); if ($row !== false) { $row = array_change_key_case($row, CASE_LOWER); $value = $row['sequence_value']; $value++; if ($row['sequence_increment_by'] > 1) { $this->sequences[$sequenceName] = [ 'value' => $value, 'max' => $row['sequence_value'] + $row['sequence_increment_by'], ]; } $sql = 'UPDATE ' . $this->generatorTableName . ' ' . 'SET sequence_value = sequence_value + sequence_increment_by ' . 'WHERE sequence_name = ? AND sequence_value = ?'; $rows = $this->conn->executeUpdate($sql, [$sequenceName, $row['sequence_value']]); if ($rows !== 1) { throw new DBALException('Race-condition detected while updating sequence. Aborting generation'); } } else { $this->conn->insert( $this->generatorTableName, ['sequence_name' => $sequenceName, 'sequence_value' => 1, 'sequence_increment_by' => 1] ); $value = 1; } $this->conn->commit(); } catch (Throwable $e) { $this->conn->rollBack(); throw new DBALException('Error occurred while generating ID with TableGenerator, aborted generation: ' . $e->getMessage(), 0, $e); } return $value; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Id/TableGeneratorSchemaVisitor.php000066400000000000000000000030021360544566000265560ustar00rootroot00000000000000generatorTableName = $generatorTableName; } /** * {@inheritdoc} */ public function acceptSchema(Schema $schema) { $table = $schema->createTable($this->generatorTableName); $table->addColumn('sequence_name', 'string'); $table->addColumn('sequence_value', 'integer', ['default' => 1]); $table->addColumn('sequence_increment_by', 'integer', ['default' => 1]); } /** * {@inheritdoc} */ public function acceptTable(Table $table) { } /** * {@inheritdoc} */ public function acceptColumn(Table $table, Column $column) { } /** * {@inheritdoc} */ public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint) { } /** * {@inheritdoc} */ public function acceptIndex(Table $table, Index $index) { } /** * {@inheritdoc} */ public function acceptSequence(Sequence $sequence) { } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/LockMode.php000066400000000000000000000006011360544566000223220ustar00rootroot00000000000000enabled) { return; } $this->start = microtime(true); $this->queries[++$this->currentQuery] = ['sql' => $sql, 'params' => $params, 'types' => $types, 'executionMS' => 0]; } /** * {@inheritdoc} */ public function stopQuery() { if (! $this->enabled) { return; } $this->queries[$this->currentQuery]['executionMS'] = microtime(true) - $this->start; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Logging/EchoSQLLogger.php000066400000000000000000000011241360544566000246120ustar00rootroot00000000000000loggers = $loggers; } /** * Adds a logger in the chain. * * @deprecated Inject list of loggers via constructor instead * * @return void */ public function addLogger(SQLLogger $logger) { $this->loggers[] = $logger; } /** * {@inheritdoc} */ public function startQuery($sql, ?array $params = null, ?array $types = null) { foreach ($this->loggers as $logger) { $logger->startQuery($sql, $params, $types); } } /** * {@inheritdoc} */ public function stopQuery() { foreach ($this->loggers as $logger) { $logger->stopQuery(); } } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Logging/SQLLogger.php000066400000000000000000000011731360544566000240170ustar00rootroot00000000000000_eventManager = $eventManager; } /** * Gets the EventManager used by the Platform. * * @return EventManager */ public function getEventManager() { return $this->_eventManager; } /** * Returns the SQL snippet that declares a boolean column. * * @param mixed[] $columnDef * * @return string */ abstract public function getBooleanTypeDeclarationSQL(array $columnDef); /** * Returns the SQL snippet that declares a 4 byte integer column. * * @param mixed[] $columnDef * * @return string */ abstract public function getIntegerTypeDeclarationSQL(array $columnDef); /** * Returns the SQL snippet that declares an 8 byte integer column. * * @param mixed[] $columnDef * * @return string */ abstract public function getBigIntTypeDeclarationSQL(array $columnDef); /** * Returns the SQL snippet that declares a 2 byte integer column. * * @param mixed[] $columnDef * * @return string */ abstract public function getSmallIntTypeDeclarationSQL(array $columnDef); /** * Returns the SQL snippet that declares common properties of an integer column. * * @param mixed[] $columnDef * * @return string */ abstract protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef); /** * Lazy load Doctrine Type Mappings. * * @return void */ abstract protected function initializeDoctrineTypeMappings(); /** * Initializes Doctrine Type Mappings with the platform defaults * and with all additional type mappings. * * @return void */ private function initializeAllDoctrineTypeMappings() { $this->initializeDoctrineTypeMappings(); foreach (Type::getTypesMap() as $typeName => $className) { foreach (Type::getType($typeName)->getMappedDatabaseTypes($this) as $dbType) { $this->doctrineTypeMapping[$dbType] = $typeName; } } } /** * Returns the SQL snippet used to declare a VARCHAR column type. * * @param mixed[] $field * * @return string */ public function getVarcharTypeDeclarationSQL(array $field) { if (! isset($field['length'])) { $field['length'] = $this->getVarcharDefaultLength(); } $fixed = $field['fixed'] ?? false; $maxLength = $fixed ? $this->getCharMaxLength() : $this->getVarcharMaxLength(); if ($field['length'] > $maxLength) { return $this->getClobTypeDeclarationSQL($field); } return $this->getVarcharTypeDeclarationSQLSnippet($field['length'], $fixed); } /** * Returns the SQL snippet used to declare a BINARY/VARBINARY column type. * * @param mixed[] $field The column definition. * * @return string */ public function getBinaryTypeDeclarationSQL(array $field) { if (! isset($field['length'])) { $field['length'] = $this->getBinaryDefaultLength(); } $fixed = $field['fixed'] ?? false; $maxLength = $this->getBinaryMaxLength(); if ($field['length'] > $maxLength) { if ($maxLength > 0) { @trigger_error(sprintf( 'Binary field length %d is greater than supported by the platform (%d). Reduce the field length or use a BLOB field instead.', $field['length'], $maxLength ), E_USER_DEPRECATED); } return $this->getBlobTypeDeclarationSQL($field); } return $this->getBinaryTypeDeclarationSQLSnippet($field['length'], $fixed); } /** * Returns the SQL snippet to declare a GUID/UUID field. * * By default this maps directly to a CHAR(36) and only maps to more * special datatypes when the underlying databases support this datatype. * * @param mixed[] $field * * @return string */ public function getGuidTypeDeclarationSQL(array $field) { $field['length'] = 36; $field['fixed'] = true; return $this->getVarcharTypeDeclarationSQL($field); } /** * Returns the SQL snippet to declare a JSON field. * * By default this maps directly to a CLOB and only maps to more * special datatypes when the underlying databases support this datatype. * * @param mixed[] $field * * @return string */ public function getJsonTypeDeclarationSQL(array $field) { return $this->getClobTypeDeclarationSQL($field); } /** * @param int $length * @param bool $fixed * * @return string * * @throws DBALException If not supported on this platform. */ protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) { throw DBALException::notSupported('VARCHARs not supported by Platform.'); } /** * Returns the SQL snippet used to declare a BINARY/VARBINARY column type. * * @param int $length The length of the column. * @param bool $fixed Whether the column length is fixed. * * @return string * * @throws DBALException If not supported on this platform. */ protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed) { throw DBALException::notSupported('BINARY/VARBINARY column types are not supported by this platform.'); } /** * Returns the SQL snippet used to declare a CLOB column type. * * @param mixed[] $field * * @return string */ abstract public function getClobTypeDeclarationSQL(array $field); /** * Returns the SQL Snippet used to declare a BLOB column type. * * @param mixed[] $field * * @return string */ abstract public function getBlobTypeDeclarationSQL(array $field); /** * Gets the name of the platform. * * @return string */ abstract public function getName(); /** * Registers a doctrine type to be used in conjunction with a column type of this platform. * * @param string $dbType * @param string $doctrineType * * @throws DBALException If the type is not found. */ public function registerDoctrineTypeMapping($dbType, $doctrineType) { if ($this->doctrineTypeMapping === null) { $this->initializeAllDoctrineTypeMappings(); } if (! Types\Type::hasType($doctrineType)) { throw DBALException::typeNotFound($doctrineType); } $dbType = strtolower($dbType); $this->doctrineTypeMapping[$dbType] = $doctrineType; $doctrineType = Type::getType($doctrineType); if (! $doctrineType->requiresSQLCommentHint($this)) { return; } $this->markDoctrineTypeCommented($doctrineType); } /** * Gets the Doctrine type that is mapped for the given database column type. * * @param string $dbType * * @return string * * @throws DBALException */ public function getDoctrineTypeMapping($dbType) { if ($this->doctrineTypeMapping === null) { $this->initializeAllDoctrineTypeMappings(); } $dbType = strtolower($dbType); if (! isset($this->doctrineTypeMapping[$dbType])) { throw new DBALException('Unknown database type ' . $dbType . ' requested, ' . static::class . ' may not support it.'); } return $this->doctrineTypeMapping[$dbType]; } /** * Checks if a database type is currently supported by this platform. * * @param string $dbType * * @return bool */ public function hasDoctrineTypeMappingFor($dbType) { if ($this->doctrineTypeMapping === null) { $this->initializeAllDoctrineTypeMappings(); } $dbType = strtolower($dbType); return isset($this->doctrineTypeMapping[$dbType]); } /** * Initializes the Doctrine Type comments instance variable for in_array() checks. * * @return void */ protected function initializeCommentedDoctrineTypes() { $this->doctrineTypeComments = []; foreach (Type::getTypesMap() as $typeName => $className) { $type = Type::getType($typeName); if (! $type->requiresSQLCommentHint($this)) { continue; } $this->doctrineTypeComments[] = $typeName; } } /** * Is it necessary for the platform to add a parsable type comment to allow reverse engineering the given type? * * @return bool */ public function isCommentedDoctrineType(Type $doctrineType) { if ($this->doctrineTypeComments === null) { $this->initializeCommentedDoctrineTypes(); } assert(is_array($this->doctrineTypeComments)); return in_array($doctrineType->getName(), $this->doctrineTypeComments); } /** * Marks this type as to be commented in ALTER TABLE and CREATE TABLE statements. * * @param string|Type $doctrineType * * @return void */ public function markDoctrineTypeCommented($doctrineType) { if ($this->doctrineTypeComments === null) { $this->initializeCommentedDoctrineTypes(); } assert(is_array($this->doctrineTypeComments)); $this->doctrineTypeComments[] = $doctrineType instanceof Type ? $doctrineType->getName() : $doctrineType; } /** * Gets the comment to append to a column comment that helps parsing this type in reverse engineering. * * @return string */ public function getDoctrineTypeComment(Type $doctrineType) { return '(DC2Type:' . $doctrineType->getName() . ')'; } /** * Gets the comment of a passed column modified by potential doctrine type comment hints. * * @return string|null */ protected function getColumnComment(Column $column) { $comment = $column->getComment(); if ($this->isCommentedDoctrineType($column->getType())) { $comment .= $this->getDoctrineTypeComment($column->getType()); } return $comment; } /** * Gets the character used for identifier quoting. * * @return string */ public function getIdentifierQuoteCharacter() { return '"'; } /** * Gets the string portion that starts an SQL comment. * * @return string */ public function getSqlCommentStartString() { return '--'; } /** * Gets the string portion that ends an SQL comment. * * @return string */ public function getSqlCommentEndString() { return "\n"; } /** * Gets the maximum length of a char field. */ public function getCharMaxLength() : int { return $this->getVarcharMaxLength(); } /** * Gets the maximum length of a varchar field. * * @return int */ public function getVarcharMaxLength() { return 4000; } /** * Gets the default length of a varchar field. * * @return int */ public function getVarcharDefaultLength() { return 255; } /** * Gets the maximum length of a binary field. * * @return int */ public function getBinaryMaxLength() { return 4000; } /** * Gets the default length of a binary field. * * @return int */ public function getBinaryDefaultLength() { return 255; } /** * Gets all SQL wildcard characters of the platform. * * @return string[] */ public function getWildcards() { return ['%', '_']; } /** * Returns the regular expression operator. * * @return string * * @throws DBALException If not supported on this platform. */ public function getRegexpExpression() { throw DBALException::notSupported(__METHOD__); } /** * Returns the global unique identifier expression. * * @deprecated Use application-generated UUIDs instead * * @return string * * @throws DBALException If not supported on this platform. */ public function getGuidExpression() { throw DBALException::notSupported(__METHOD__); } /** * Returns the SQL snippet to get the average value of a column. * * @param string $column The column to use. * * @return string Generated SQL including an AVG aggregate function. */ public function getAvgExpression($column) { return 'AVG(' . $column . ')'; } /** * Returns the SQL snippet to get the number of rows (without a NULL value) of a column. * * If a '*' is used instead of a column the number of selected rows is returned. * * @param string|int $column The column to use. * * @return string Generated SQL including a COUNT aggregate function. */ public function getCountExpression($column) { return 'COUNT(' . $column . ')'; } /** * Returns the SQL snippet to get the highest value of a column. * * @param string $column The column to use. * * @return string Generated SQL including a MAX aggregate function. */ public function getMaxExpression($column) { return 'MAX(' . $column . ')'; } /** * Returns the SQL snippet to get the lowest value of a column. * * @param string $column The column to use. * * @return string Generated SQL including a MIN aggregate function. */ public function getMinExpression($column) { return 'MIN(' . $column . ')'; } /** * Returns the SQL snippet to get the total sum of a column. * * @param string $column The column to use. * * @return string Generated SQL including a SUM aggregate function. */ public function getSumExpression($column) { return 'SUM(' . $column . ')'; } // scalar functions /** * Returns the SQL snippet to get the md5 sum of a field. * * Note: Not SQL92, but common functionality. * * @param string $column * * @return string */ public function getMd5Expression($column) { return 'MD5(' . $column . ')'; } /** * Returns the SQL snippet to get the length of a text field. * * @param string $column * * @return string */ public function getLengthExpression($column) { return 'LENGTH(' . $column . ')'; } /** * Returns the SQL snippet to get the squared value of a column. * * @param string $column The column to use. * * @return string Generated SQL including an SQRT aggregate function. */ public function getSqrtExpression($column) { return 'SQRT(' . $column . ')'; } /** * Returns the SQL snippet to round a numeric field to the number of decimals specified. * * @param string $column * @param int $decimals * * @return string */ public function getRoundExpression($column, $decimals = 0) { return 'ROUND(' . $column . ', ' . $decimals . ')'; } /** * Returns the SQL snippet to get the remainder of the division operation $expression1 / $expression2. * * @param string $expression1 * @param string $expression2 * * @return string */ public function getModExpression($expression1, $expression2) { return 'MOD(' . $expression1 . ', ' . $expression2 . ')'; } /** * Returns the SQL snippet to trim a string. * * @param string $str The expression to apply the trim to. * @param int $mode The position of the trim (leading/trailing/both). * @param string|bool $char The char to trim, has to be quoted already. Defaults to space. * * @return string */ public function getTrimExpression($str, $mode = TrimMode::UNSPECIFIED, $char = false) { $expression = ''; switch ($mode) { case TrimMode::LEADING: $expression = 'LEADING '; break; case TrimMode::TRAILING: $expression = 'TRAILING '; break; case TrimMode::BOTH: $expression = 'BOTH '; break; } if ($char !== false) { $expression .= $char . ' '; } if ($mode || $char !== false) { $expression .= 'FROM '; } return 'TRIM(' . $expression . $str . ')'; } /** * Returns the SQL snippet to trim trailing space characters from the expression. * * @param string $str Literal string or column name. * * @return string */ public function getRtrimExpression($str) { return 'RTRIM(' . $str . ')'; } /** * Returns the SQL snippet to trim leading space characters from the expression. * * @param string $str Literal string or column name. * * @return string */ public function getLtrimExpression($str) { return 'LTRIM(' . $str . ')'; } /** * Returns the SQL snippet to change all characters from the expression to uppercase, * according to the current character set mapping. * * @param string $str Literal string or column name. * * @return string */ public function getUpperExpression($str) { return 'UPPER(' . $str . ')'; } /** * Returns the SQL snippet to change all characters from the expression to lowercase, * according to the current character set mapping. * * @param string $str Literal string or column name. * * @return string */ public function getLowerExpression($str) { return 'LOWER(' . $str . ')'; } /** * Returns the SQL snippet to get the position of the first occurrence of substring $substr in string $str. * * @param string $str Literal string. * @param string $substr Literal string to find. * @param int|false $startPos Position to start at, beginning of string by default. * * @return string * * @throws DBALException If not supported on this platform. */ public function getLocateExpression($str, $substr, $startPos = false) { throw DBALException::notSupported(__METHOD__); } /** * Returns the SQL snippet to get the current system date. * * @return string */ public function getNowExpression() { return 'NOW()'; } /** * Returns a SQL snippet to get a substring inside an SQL statement. * * Note: Not SQL92, but common functionality. * * SQLite only supports the 2 parameter variant of this function. * * @param string $value An sql string literal or column name/alias. * @param int $from Where to start the substring portion. * @param int|null $length The substring portion length. * * @return string */ public function getSubstringExpression($value, $from, $length = null) { if ($length === null) { return 'SUBSTRING(' . $value . ' FROM ' . $from . ')'; } return 'SUBSTRING(' . $value . ' FROM ' . $from . ' FOR ' . $length . ')'; } /** * Returns a SQL snippet to concatenate the given expressions. * * Accepts an arbitrary number of string parameters. Each parameter must contain an expression. * * @return string */ public function getConcatExpression() { return implode(' || ', func_get_args()); } /** * Returns the SQL for a logical not. * * Example: * * $q = new Doctrine_Query(); * $e = $q->expr; * $q->select('*')->from('table') * ->where($e->eq('id', $e->not('null')); * * * @param string $expression * * @return string The logical expression. */ public function getNotExpression($expression) { return 'NOT(' . $expression . ')'; } /** * Returns the SQL that checks if an expression is null. * * @param string $expression The expression that should be compared to null. * * @return string The logical expression. */ public function getIsNullExpression($expression) { return $expression . ' IS NULL'; } /** * Returns the SQL that checks if an expression is not null. * * @param string $expression The expression that should be compared to null. * * @return string The logical expression. */ public function getIsNotNullExpression($expression) { return $expression . ' IS NOT NULL'; } /** * Returns the SQL that checks if an expression evaluates to a value between two values. * * The parameter $expression is checked if it is between $value1 and $value2. * * Note: There is a slight difference in the way BETWEEN works on some databases. * http://www.w3schools.com/sql/sql_between.asp. If you want complete database * independence you should avoid using between(). * * @param string $expression The value to compare to. * @param string $value1 The lower value to compare with. * @param string $value2 The higher value to compare with. * * @return string The logical expression. */ public function getBetweenExpression($expression, $value1, $value2) { return $expression . ' BETWEEN ' . $value1 . ' AND ' . $value2; } /** * Returns the SQL to get the arccosine of a value. * * @param string $value * * @return string */ public function getAcosExpression($value) { return 'ACOS(' . $value . ')'; } /** * Returns the SQL to get the sine of a value. * * @param string $value * * @return string */ public function getSinExpression($value) { return 'SIN(' . $value . ')'; } /** * Returns the SQL to get the PI value. * * @return string */ public function getPiExpression() { return 'PI()'; } /** * Returns the SQL to get the cosine of a value. * * @param string $value * * @return string */ public function getCosExpression($value) { return 'COS(' . $value . ')'; } /** * Returns the SQL to calculate the difference in days between the two passed dates. * * Computes diff = date1 - date2. * * @param string $date1 * @param string $date2 * * @return string * * @throws DBALException If not supported on this platform. */ public function getDateDiffExpression($date1, $date2) { throw DBALException::notSupported(__METHOD__); } /** * Returns the SQL to add the number of given seconds to a date. * * @param string $date * @param int $seconds * * @return string * * @throws DBALException If not supported on this platform. */ public function getDateAddSecondsExpression($date, $seconds) { return $this->getDateArithmeticIntervalExpression($date, '+', $seconds, DateIntervalUnit::SECOND); } /** * Returns the SQL to subtract the number of given seconds from a date. * * @param string $date * @param int $seconds * * @return string * * @throws DBALException If not supported on this platform. */ public function getDateSubSecondsExpression($date, $seconds) { return $this->getDateArithmeticIntervalExpression($date, '-', $seconds, DateIntervalUnit::SECOND); } /** * Returns the SQL to add the number of given minutes to a date. * * @param string $date * @param int $minutes * * @return string * * @throws DBALException If not supported on this platform. */ public function getDateAddMinutesExpression($date, $minutes) { return $this->getDateArithmeticIntervalExpression($date, '+', $minutes, DateIntervalUnit::MINUTE); } /** * Returns the SQL to subtract the number of given minutes from a date. * * @param string $date * @param int $minutes * * @return string * * @throws DBALException If not supported on this platform. */ public function getDateSubMinutesExpression($date, $minutes) { return $this->getDateArithmeticIntervalExpression($date, '-', $minutes, DateIntervalUnit::MINUTE); } /** * Returns the SQL to add the number of given hours to a date. * * @param string $date * @param int $hours * * @return string * * @throws DBALException If not supported on this platform. */ public function getDateAddHourExpression($date, $hours) { return $this->getDateArithmeticIntervalExpression($date, '+', $hours, DateIntervalUnit::HOUR); } /** * Returns the SQL to subtract the number of given hours to a date. * * @param string $date * @param int $hours * * @return string * * @throws DBALException If not supported on this platform. */ public function getDateSubHourExpression($date, $hours) { return $this->getDateArithmeticIntervalExpression($date, '-', $hours, DateIntervalUnit::HOUR); } /** * Returns the SQL to add the number of given days to a date. * * @param string $date * @param int $days * * @return string * * @throws DBALException If not supported on this platform. */ public function getDateAddDaysExpression($date, $days) { return $this->getDateArithmeticIntervalExpression($date, '+', $days, DateIntervalUnit::DAY); } /** * Returns the SQL to subtract the number of given days to a date. * * @param string $date * @param int $days * * @return string * * @throws DBALException If not supported on this platform. */ public function getDateSubDaysExpression($date, $days) { return $this->getDateArithmeticIntervalExpression($date, '-', $days, DateIntervalUnit::DAY); } /** * Returns the SQL to add the number of given weeks to a date. * * @param string $date * @param int $weeks * * @return string * * @throws DBALException If not supported on this platform. */ public function getDateAddWeeksExpression($date, $weeks) { return $this->getDateArithmeticIntervalExpression($date, '+', $weeks, DateIntervalUnit::WEEK); } /** * Returns the SQL to subtract the number of given weeks from a date. * * @param string $date * @param int $weeks * * @return string * * @throws DBALException If not supported on this platform. */ public function getDateSubWeeksExpression($date, $weeks) { return $this->getDateArithmeticIntervalExpression($date, '-', $weeks, DateIntervalUnit::WEEK); } /** * Returns the SQL to add the number of given months to a date. * * @param string $date * @param int $months * * @return string * * @throws DBALException If not supported on this platform. */ public function getDateAddMonthExpression($date, $months) { return $this->getDateArithmeticIntervalExpression($date, '+', $months, DateIntervalUnit::MONTH); } /** * Returns the SQL to subtract the number of given months to a date. * * @param string $date * @param int $months * * @return string * * @throws DBALException If not supported on this platform. */ public function getDateSubMonthExpression($date, $months) { return $this->getDateArithmeticIntervalExpression($date, '-', $months, DateIntervalUnit::MONTH); } /** * Returns the SQL to add the number of given quarters to a date. * * @param string $date * @param int $quarters * * @return string * * @throws DBALException If not supported on this platform. */ public function getDateAddQuartersExpression($date, $quarters) { return $this->getDateArithmeticIntervalExpression($date, '+', $quarters, DateIntervalUnit::QUARTER); } /** * Returns the SQL to subtract the number of given quarters from a date. * * @param string $date * @param int $quarters * * @return string * * @throws DBALException If not supported on this platform. */ public function getDateSubQuartersExpression($date, $quarters) { return $this->getDateArithmeticIntervalExpression($date, '-', $quarters, DateIntervalUnit::QUARTER); } /** * Returns the SQL to add the number of given years to a date. * * @param string $date * @param int $years * * @return string * * @throws DBALException If not supported on this platform. */ public function getDateAddYearsExpression($date, $years) { return $this->getDateArithmeticIntervalExpression($date, '+', $years, DateIntervalUnit::YEAR); } /** * Returns the SQL to subtract the number of given years from a date. * * @param string $date * @param int $years * * @return string * * @throws DBALException If not supported on this platform. */ public function getDateSubYearsExpression($date, $years) { return $this->getDateArithmeticIntervalExpression($date, '-', $years, DateIntervalUnit::YEAR); } /** * Returns the SQL for a date arithmetic expression. * * @param string $date The column or literal representing a date to perform the arithmetic operation on. * @param string $operator The arithmetic operator (+ or -). * @param int $interval The interval that shall be calculated into the date. * @param string $unit The unit of the interval that shall be calculated into the date. * One of the DATE_INTERVAL_UNIT_* constants. * * @return string * * @throws DBALException If not supported on this platform. */ protected function getDateArithmeticIntervalExpression($date, $operator, $interval, $unit) { throw DBALException::notSupported(__METHOD__); } /** * Returns the SQL bit AND comparison expression. * * @param string $value1 * @param string $value2 * * @return string */ public function getBitAndComparisonExpression($value1, $value2) { return '(' . $value1 . ' & ' . $value2 . ')'; } /** * Returns the SQL bit OR comparison expression. * * @param string $value1 * @param string $value2 * * @return string */ public function getBitOrComparisonExpression($value1, $value2) { return '(' . $value1 . ' | ' . $value2 . ')'; } /** * Returns the FOR UPDATE expression. * * @return string */ public function getForUpdateSQL() { return 'FOR UPDATE'; } /** * Honors that some SQL vendors such as MsSql use table hints for locking instead of the ANSI SQL FOR UPDATE specification. * * @param string $fromClause The FROM clause to append the hint for the given lock mode to. * @param int|null $lockMode One of the Doctrine\DBAL\LockMode::* constants. If null is given, nothing will * be appended to the FROM clause. * * @return string */ public function appendLockHint($fromClause, $lockMode) { return $fromClause; } /** * Returns the SQL snippet to append to any SELECT statement which locks rows in shared read lock. * * This defaults to the ANSI SQL "FOR UPDATE", which is an exclusive lock (Write). Some database * vendors allow to lighten this constraint up to be a real read lock. * * @return string */ public function getReadLockSQL() { return $this->getForUpdateSQL(); } /** * Returns the SQL snippet to append to any SELECT statement which obtains an exclusive lock on the rows. * * The semantics of this lock mode should equal the SELECT .. FOR UPDATE of the ANSI SQL standard. * * @return string */ public function getWriteLockSQL() { return $this->getForUpdateSQL(); } /** * Returns the SQL snippet to drop an existing database. * * @param string $database The name of the database that should be dropped. * * @return string */ public function getDropDatabaseSQL($database) { return 'DROP DATABASE ' . $database; } /** * Returns the SQL snippet to drop an existing table. * * @param Table|string $table * * @return string * * @throws InvalidArgumentException */ public function getDropTableSQL($table) { $tableArg = $table; if ($table instanceof Table) { $table = $table->getQuotedName($this); } if (! is_string($table)) { throw new InvalidArgumentException('getDropTableSQL() expects $table parameter to be string or \Doctrine\DBAL\Schema\Table.'); } if ($this->_eventManager !== null && $this->_eventManager->hasListeners(Events::onSchemaDropTable)) { $eventArgs = new SchemaDropTableEventArgs($tableArg, $this); $this->_eventManager->dispatchEvent(Events::onSchemaDropTable, $eventArgs); if ($eventArgs->isDefaultPrevented()) { $sql = $eventArgs->getSql(); if ($sql === null) { throw new UnexpectedValueException('Default implementation of DROP TABLE was overridden with NULL'); } return $sql; } } return 'DROP TABLE ' . $table; } /** * Returns the SQL to safely drop a temporary table WITHOUT implicitly committing an open transaction. * * @param Table|string $table * * @return string */ public function getDropTemporaryTableSQL($table) { return $this->getDropTableSQL($table); } /** * Returns the SQL to drop an index from a table. * * @param Index|string $index * @param Table|string $table * * @return string * * @throws InvalidArgumentException */ public function getDropIndexSQL($index, $table = null) { if ($index instanceof Index) { $index = $index->getQuotedName($this); } elseif (! is_string($index)) { throw new InvalidArgumentException('AbstractPlatform::getDropIndexSQL() expects $index parameter to be string or \Doctrine\DBAL\Schema\Index.'); } return 'DROP INDEX ' . $index; } /** * Returns the SQL to drop a constraint. * * @param Constraint|string $constraint * @param Table|string $table * * @return string */ public function getDropConstraintSQL($constraint, $table) { if (! $constraint instanceof Constraint) { $constraint = new Identifier($constraint); } if (! $table instanceof Table) { $table = new Identifier($table); } $constraint = $constraint->getQuotedName($this); $table = $table->getQuotedName($this); return 'ALTER TABLE ' . $table . ' DROP CONSTRAINT ' . $constraint; } /** * Returns the SQL to drop a foreign key. * * @param ForeignKeyConstraint|string $foreignKey * @param Table|string $table * * @return string */ public function getDropForeignKeySQL($foreignKey, $table) { if (! $foreignKey instanceof ForeignKeyConstraint) { $foreignKey = new Identifier($foreignKey); } if (! $table instanceof Table) { $table = new Identifier($table); } $foreignKey = $foreignKey->getQuotedName($this); $table = $table->getQuotedName($this); return 'ALTER TABLE ' . $table . ' DROP FOREIGN KEY ' . $foreignKey; } /** * Returns the SQL statement(s) to create a table with the specified name, columns and constraints * on this platform. * * @param int $createFlags * * @return string[] The sequence of SQL statements. * * @throws DBALException * @throws InvalidArgumentException */ public function getCreateTableSQL(Table $table, $createFlags = self::CREATE_INDEXES) { if (! is_int($createFlags)) { throw new InvalidArgumentException('Second argument of AbstractPlatform::getCreateTableSQL() has to be integer.'); } if (count($table->getColumns()) === 0) { throw DBALException::noColumnsSpecifiedForTable($table->getName()); } $tableName = $table->getQuotedName($this); $options = $table->getOptions(); $options['uniqueConstraints'] = []; $options['indexes'] = []; $options['primary'] = []; if (($createFlags&self::CREATE_INDEXES) > 0) { foreach ($table->getIndexes() as $index) { /** @var $index Index */ if ($index->isPrimary()) { $options['primary'] = $index->getQuotedColumns($this); $options['primary_index'] = $index; } else { $options['indexes'][$index->getQuotedName($this)] = $index; } } } $columnSql = []; $columns = []; foreach ($table->getColumns() as $column) { if ($this->_eventManager !== null && $this->_eventManager->hasListeners(Events::onSchemaCreateTableColumn)) { $eventArgs = new SchemaCreateTableColumnEventArgs($column, $table, $this); $this->_eventManager->dispatchEvent(Events::onSchemaCreateTableColumn, $eventArgs); $columnSql = array_merge($columnSql, $eventArgs->getSql()); if ($eventArgs->isDefaultPrevented()) { continue; } } $columnData = $column->toArray(); $columnData['name'] = $column->getQuotedName($this); $columnData['version'] = $column->hasPlatformOption('version') ? $column->getPlatformOption('version') : false; $columnData['comment'] = $this->getColumnComment($column); if ($columnData['type'] instanceof Types\StringType && $columnData['length'] === null) { $columnData['length'] = 255; } if (in_array($column->getName(), $options['primary'])) { $columnData['primary'] = true; } $columns[$columnData['name']] = $columnData; } if (($createFlags&self::CREATE_FOREIGNKEYS) > 0) { $options['foreignKeys'] = []; foreach ($table->getForeignKeys() as $fkConstraint) { $options['foreignKeys'][] = $fkConstraint; } } if ($this->_eventManager !== null && $this->_eventManager->hasListeners(Events::onSchemaCreateTable)) { $eventArgs = new SchemaCreateTableEventArgs($table, $columns, $options, $this); $this->_eventManager->dispatchEvent(Events::onSchemaCreateTable, $eventArgs); if ($eventArgs->isDefaultPrevented()) { return array_merge($eventArgs->getSql(), $columnSql); } } $sql = $this->_getCreateTableSQL($tableName, $columns, $options); if ($this->supportsCommentOnStatement()) { if ($table->hasOption('comment')) { $sql[] = $this->getCommentOnTableSQL($tableName, $table->getOption('comment')); } foreach ($table->getColumns() as $column) { $comment = $this->getColumnComment($column); if ($comment === null || $comment === '') { continue; } $sql[] = $this->getCommentOnColumnSQL($tableName, $column->getQuotedName($this), $comment); } } return array_merge($sql, $columnSql); } protected function getCommentOnTableSQL(string $tableName, ?string $comment) : string { $tableName = new Identifier($tableName); return sprintf( 'COMMENT ON TABLE %s IS %s', $tableName->getQuotedName($this), $this->quoteStringLiteral((string) $comment) ); } /** * @param string $tableName * @param string $columnName * @param string|null $comment * * @return string */ public function getCommentOnColumnSQL($tableName, $columnName, $comment) { $tableName = new Identifier($tableName); $columnName = new Identifier($columnName); return sprintf( 'COMMENT ON COLUMN %s.%s IS %s', $tableName->getQuotedName($this), $columnName->getQuotedName($this), $this->quoteStringLiteral((string) $comment) ); } /** * Returns the SQL to create inline comment on a column. * * @param string $comment * * @return string * * @throws DBALException If not supported on this platform. */ public function getInlineColumnCommentSQL($comment) { if (! $this->supportsInlineColumnComments()) { throw DBALException::notSupported(__METHOD__); } return 'COMMENT ' . $this->quoteStringLiteral($comment); } /** * Returns the SQL used to create a table. * * @param string $tableName * @param mixed[][] $columns * @param mixed[] $options * * @return string[] */ protected function _getCreateTableSQL($tableName, array $columns, array $options = []) { $columnListSql = $this->getColumnDeclarationListSQL($columns); if (isset($options['uniqueConstraints']) && ! empty($options['uniqueConstraints'])) { foreach ($options['uniqueConstraints'] as $name => $definition) { $columnListSql .= ', ' . $this->getUniqueConstraintDeclarationSQL($name, $definition); } } if (isset($options['primary']) && ! empty($options['primary'])) { $columnListSql .= ', PRIMARY KEY(' . implode(', ', array_unique(array_values($options['primary']))) . ')'; } if (isset($options['indexes']) && ! empty($options['indexes'])) { foreach ($options['indexes'] as $index => $definition) { $columnListSql .= ', ' . $this->getIndexDeclarationSQL($index, $definition); } } $query = 'CREATE TABLE ' . $tableName . ' (' . $columnListSql; $check = $this->getCheckDeclarationSQL($columns); if (! empty($check)) { $query .= ', ' . $check; } $query .= ')'; $sql[] = $query; if (isset($options['foreignKeys'])) { foreach ((array) $options['foreignKeys'] as $definition) { $sql[] = $this->getCreateForeignKeySQL($definition, $tableName); } } return $sql; } /** * @return string */ public function getCreateTemporaryTableSnippetSQL() { return 'CREATE TEMPORARY TABLE'; } /** * Returns the SQL to create a sequence on this platform. * * @return string * * @throws DBALException If not supported on this platform. */ public function getCreateSequenceSQL(Sequence $sequence) { throw DBALException::notSupported(__METHOD__); } /** * Returns the SQL to change a sequence on this platform. * * @return string * * @throws DBALException If not supported on this platform. */ public function getAlterSequenceSQL(Sequence $sequence) { throw DBALException::notSupported(__METHOD__); } /** * Returns the SQL to create a constraint on a table on this platform. * * @param Table|string $table * * @return string * * @throws InvalidArgumentException */ public function getCreateConstraintSQL(Constraint $constraint, $table) { if ($table instanceof Table) { $table = $table->getQuotedName($this); } $query = 'ALTER TABLE ' . $table . ' ADD CONSTRAINT ' . $constraint->getQuotedName($this); $columnList = '(' . implode(', ', $constraint->getQuotedColumns($this)) . ')'; $referencesClause = ''; if ($constraint instanceof Index) { if ($constraint->isPrimary()) { $query .= ' PRIMARY KEY'; } elseif ($constraint->isUnique()) { $query .= ' UNIQUE'; } else { throw new InvalidArgumentException( 'Can only create primary or unique constraints, no common indexes with getCreateConstraintSQL().' ); } } elseif ($constraint instanceof ForeignKeyConstraint) { $query .= ' FOREIGN KEY'; $referencesClause = ' REFERENCES ' . $constraint->getQuotedForeignTableName($this) . ' (' . implode(', ', $constraint->getQuotedForeignColumns($this)) . ')'; } $query .= ' ' . $columnList . $referencesClause; return $query; } /** * Returns the SQL to create an index on a table on this platform. * * @param Table|string $table The name of the table on which the index is to be created. * * @return string * * @throws InvalidArgumentException */ public function getCreateIndexSQL(Index $index, $table) { if ($table instanceof Table) { $table = $table->getQuotedName($this); } $name = $index->getQuotedName($this); $columns = $index->getColumns(); if (count($columns) === 0) { throw new InvalidArgumentException("Incomplete definition. 'columns' required."); } if ($index->isPrimary()) { return $this->getCreatePrimaryKeySQL($index, $table); } $query = 'CREATE ' . $this->getCreateIndexSQLFlags($index) . 'INDEX ' . $name . ' ON ' . $table; $query .= ' (' . $this->getIndexFieldDeclarationListSQL($index) . ')' . $this->getPartialIndexSQL($index); return $query; } /** * Adds condition for partial index. * * @return string */ protected function getPartialIndexSQL(Index $index) { if ($this->supportsPartialIndexes() && $index->hasOption('where')) { return ' WHERE ' . $index->getOption('where'); } return ''; } /** * Adds additional flags for index generation. * * @return string */ protected function getCreateIndexSQLFlags(Index $index) { return $index->isUnique() ? 'UNIQUE ' : ''; } /** * Returns the SQL to create an unnamed primary key constraint. * * @param Table|string $table * * @return string */ public function getCreatePrimaryKeySQL(Index $index, $table) { if ($table instanceof Table) { $table = $table->getQuotedName($this); } return 'ALTER TABLE ' . $table . ' ADD PRIMARY KEY (' . $this->getIndexFieldDeclarationListSQL($index) . ')'; } /** * Returns the SQL to create a named schema. * * @param string $schemaName * * @return string * * @throws DBALException If not supported on this platform. */ public function getCreateSchemaSQL($schemaName) { throw DBALException::notSupported(__METHOD__); } /** * Quotes a string so that it can be safely used as a table or column name, * even if it is a reserved word of the platform. This also detects identifier * chains separated by dot and quotes them independently. * * NOTE: Just because you CAN use quoted identifiers doesn't mean * you SHOULD use them. In general, they end up causing way more * problems than they solve. * * @param string $str The identifier name to be quoted. * * @return string The quoted identifier string. */ public function quoteIdentifier($str) { if (strpos($str, '.') !== false) { $parts = array_map([$this, 'quoteSingleIdentifier'], explode('.', $str)); return implode('.', $parts); } return $this->quoteSingleIdentifier($str); } /** * Quotes a single identifier (no dot chain separation). * * @param string $str The identifier name to be quoted. * * @return string The quoted identifier string. */ public function quoteSingleIdentifier($str) { $c = $this->getIdentifierQuoteCharacter(); return $c . str_replace($c, $c . $c, $str) . $c; } /** * Returns the SQL to create a new foreign key. * * @param ForeignKeyConstraint $foreignKey The foreign key constraint. * @param Table|string $table The name of the table on which the foreign key is to be created. * * @return string */ public function getCreateForeignKeySQL(ForeignKeyConstraint $foreignKey, $table) { if ($table instanceof Table) { $table = $table->getQuotedName($this); } return 'ALTER TABLE ' . $table . ' ADD ' . $this->getForeignKeyDeclarationSQL($foreignKey); } /** * Gets the SQL statements for altering an existing table. * * This method returns an array of SQL statements, since some platforms need several statements. * * @return string[] * * @throws DBALException If not supported on this platform. */ public function getAlterTableSQL(TableDiff $diff) { throw DBALException::notSupported(__METHOD__); } /** * @param mixed[] $columnSql * * @return bool */ protected function onSchemaAlterTableAddColumn(Column $column, TableDiff $diff, &$columnSql) { if ($this->_eventManager === null) { return false; } if (! $this->_eventManager->hasListeners(Events::onSchemaAlterTableAddColumn)) { return false; } $eventArgs = new SchemaAlterTableAddColumnEventArgs($column, $diff, $this); $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableAddColumn, $eventArgs); $columnSql = array_merge($columnSql, $eventArgs->getSql()); return $eventArgs->isDefaultPrevented(); } /** * @param string[] $columnSql * * @return bool */ protected function onSchemaAlterTableRemoveColumn(Column $column, TableDiff $diff, &$columnSql) { if ($this->_eventManager === null) { return false; } if (! $this->_eventManager->hasListeners(Events::onSchemaAlterTableRemoveColumn)) { return false; } $eventArgs = new SchemaAlterTableRemoveColumnEventArgs($column, $diff, $this); $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableRemoveColumn, $eventArgs); $columnSql = array_merge($columnSql, $eventArgs->getSql()); return $eventArgs->isDefaultPrevented(); } /** * @param string[] $columnSql * * @return bool */ protected function onSchemaAlterTableChangeColumn(ColumnDiff $columnDiff, TableDiff $diff, &$columnSql) { if ($this->_eventManager === null) { return false; } if (! $this->_eventManager->hasListeners(Events::onSchemaAlterTableChangeColumn)) { return false; } $eventArgs = new SchemaAlterTableChangeColumnEventArgs($columnDiff, $diff, $this); $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableChangeColumn, $eventArgs); $columnSql = array_merge($columnSql, $eventArgs->getSql()); return $eventArgs->isDefaultPrevented(); } /** * @param string $oldColumnName * @param string[] $columnSql * * @return bool */ protected function onSchemaAlterTableRenameColumn($oldColumnName, Column $column, TableDiff $diff, &$columnSql) { if ($this->_eventManager === null) { return false; } if (! $this->_eventManager->hasListeners(Events::onSchemaAlterTableRenameColumn)) { return false; } $eventArgs = new SchemaAlterTableRenameColumnEventArgs($oldColumnName, $column, $diff, $this); $this->_eventManager->dispatchEvent(Events::onSchemaAlterTableRenameColumn, $eventArgs); $columnSql = array_merge($columnSql, $eventArgs->getSql()); return $eventArgs->isDefaultPrevented(); } /** * @param string[] $sql * * @return bool */ protected function onSchemaAlterTable(TableDiff $diff, &$sql) { if ($this->_eventManager === null) { return false; } if (! $this->_eventManager->hasListeners(Events::onSchemaAlterTable)) { return false; } $eventArgs = new SchemaAlterTableEventArgs($diff, $this); $this->_eventManager->dispatchEvent(Events::onSchemaAlterTable, $eventArgs); $sql = array_merge($sql, $eventArgs->getSql()); return $eventArgs->isDefaultPrevented(); } /** * @return string[] */ protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff) { $tableName = $diff->getName($this)->getQuotedName($this); $sql = []; if ($this->supportsForeignKeyConstraints()) { foreach ($diff->removedForeignKeys as $foreignKey) { $sql[] = $this->getDropForeignKeySQL($foreignKey, $tableName); } foreach ($diff->changedForeignKeys as $foreignKey) { $sql[] = $this->getDropForeignKeySQL($foreignKey, $tableName); } } foreach ($diff->removedIndexes as $index) { $sql[] = $this->getDropIndexSQL($index, $tableName); } foreach ($diff->changedIndexes as $index) { $sql[] = $this->getDropIndexSQL($index, $tableName); } return $sql; } /** * @return string[] */ protected function getPostAlterTableIndexForeignKeySQL(TableDiff $diff) { $sql = []; $newName = $diff->getNewName(); if ($newName !== false) { $tableName = $newName->getQuotedName($this); } else { $tableName = $diff->getName($this)->getQuotedName($this); } if ($this->supportsForeignKeyConstraints()) { foreach ($diff->addedForeignKeys as $foreignKey) { $sql[] = $this->getCreateForeignKeySQL($foreignKey, $tableName); } foreach ($diff->changedForeignKeys as $foreignKey) { $sql[] = $this->getCreateForeignKeySQL($foreignKey, $tableName); } } foreach ($diff->addedIndexes as $index) { $sql[] = $this->getCreateIndexSQL($index, $tableName); } foreach ($diff->changedIndexes as $index) { $sql[] = $this->getCreateIndexSQL($index, $tableName); } foreach ($diff->renamedIndexes as $oldIndexName => $index) { $oldIndexName = new Identifier($oldIndexName); $sql = array_merge( $sql, $this->getRenameIndexSQL($oldIndexName->getQuotedName($this), $index, $tableName) ); } return $sql; } /** * Returns the SQL for renaming an index on a table. * * @param string $oldIndexName The name of the index to rename from. * @param Index $index The definition of the index to rename to. * @param string $tableName The table to rename the given index on. * * @return string[] The sequence of SQL statements for renaming the given index. */ protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName) { return [ $this->getDropIndexSQL($oldIndexName, $tableName), $this->getCreateIndexSQL($index, $tableName), ]; } /** * Common code for alter table statement generation that updates the changed Index and Foreign Key definitions. * * @deprecated * * @return string[] */ protected function _getAlterTableIndexForeignKeySQL(TableDiff $diff) { return array_merge($this->getPreAlterTableIndexForeignKeySQL($diff), $this->getPostAlterTableIndexForeignKeySQL($diff)); } /** * Gets declaration of a number of fields in bulk. * * @param mixed[][] $fields A multidimensional associative array. * The first dimension determines the field name, while the second * dimension is keyed with the name of the properties * of the field being declared as array indexes. Currently, the types * of supported field properties are as follows: * * length * Integer value that determines the maximum length of the text * field. If this argument is missing the field should be * declared to have the longest length allowed by the DBMS. * * default * Text value to be used as default for this field. * * notnull * Boolean flag that indicates whether this field is constrained * to not be set to null. * charset * Text value with the default CHARACTER SET for this field. * collation * Text value with the default COLLATION for this field. * unique * unique constraint * * @return string */ public function getColumnDeclarationListSQL(array $fields) { $queryFields = []; foreach ($fields as $fieldName => $field) { $queryFields[] = $this->getColumnDeclarationSQL($fieldName, $field); } return implode(', ', $queryFields); } /** * Obtains DBMS specific SQL code portion needed to declare a generic type * field to be used in statements like CREATE TABLE. * * @param string $name The name the field to be declared. * @param mixed[] $field An associative array with the name of the properties * of the field being declared as array indexes. Currently, the types * of supported field properties are as follows: * * length * Integer value that determines the maximum length of the text * field. If this argument is missing the field should be * declared to have the longest length allowed by the DBMS. * * default * Text value to be used as default for this field. * * notnull * Boolean flag that indicates whether this field is constrained * to not be set to null. * charset * Text value with the default CHARACTER SET for this field. * collation * Text value with the default COLLATION for this field. * unique * unique constraint * check * column check constraint * columnDefinition * a string that defines the complete column * * @return string DBMS specific SQL code portion that should be used to declare the column. */ public function getColumnDeclarationSQL($name, array $field) { if (isset($field['columnDefinition'])) { $columnDef = $this->getCustomTypeDeclarationSQL($field); } else { $default = $this->getDefaultValueDeclarationSQL($field); $charset = isset($field['charset']) && $field['charset'] ? ' ' . $this->getColumnCharsetDeclarationSQL($field['charset']) : ''; $collation = isset($field['collation']) && $field['collation'] ? ' ' . $this->getColumnCollationDeclarationSQL($field['collation']) : ''; $notnull = isset($field['notnull']) && $field['notnull'] ? ' NOT NULL' : ''; $unique = isset($field['unique']) && $field['unique'] ? ' ' . $this->getUniqueFieldDeclarationSQL() : ''; $check = isset($field['check']) && $field['check'] ? ' ' . $field['check'] : ''; $typeDecl = $field['type']->getSQLDeclaration($field, $this); $columnDef = $typeDecl . $charset . $default . $notnull . $unique . $check . $collation; if ($this->supportsInlineColumnComments() && isset($field['comment']) && $field['comment'] !== '') { $columnDef .= ' ' . $this->getInlineColumnCommentSQL($field['comment']); } } return $name . ' ' . $columnDef; } /** * Returns the SQL snippet that declares a floating point column of arbitrary precision. * * @param mixed[] $columnDef * * @return string */ public function getDecimalTypeDeclarationSQL(array $columnDef) { $columnDef['precision'] = ! isset($columnDef['precision']) || empty($columnDef['precision']) ? 10 : $columnDef['precision']; $columnDef['scale'] = ! isset($columnDef['scale']) || empty($columnDef['scale']) ? 0 : $columnDef['scale']; return 'NUMERIC(' . $columnDef['precision'] . ', ' . $columnDef['scale'] . ')'; } /** * Obtains DBMS specific SQL code portion needed to set a default value * declaration to be used in statements like CREATE TABLE. * * @param mixed[] $field The field definition array. * * @return string DBMS specific SQL code portion needed to set a default value. */ public function getDefaultValueDeclarationSQL($field) { if (! isset($field['default'])) { return empty($field['notnull']) ? ' DEFAULT NULL' : ''; } $default = $field['default']; if (! isset($field['type'])) { return " DEFAULT '" . $default . "'"; } $type = $field['type']; if ($type instanceof Types\PhpIntegerMappingType) { return ' DEFAULT ' . $default; } if ($type instanceof Types\PhpDateTimeMappingType && $default === $this->getCurrentTimestampSQL()) { return ' DEFAULT ' . $this->getCurrentTimestampSQL(); } if ($type instanceof Types\TimeType && $default === $this->getCurrentTimeSQL()) { return ' DEFAULT ' . $this->getCurrentTimeSQL(); } if ($type instanceof Types\DateType && $default === $this->getCurrentDateSQL()) { return ' DEFAULT ' . $this->getCurrentDateSQL(); } if ($type instanceof Types\BooleanType) { return " DEFAULT '" . $this->convertBooleans($default) . "'"; } return ' DEFAULT ' . $this->quoteStringLiteral($default); } /** * Obtains DBMS specific SQL code portion needed to set a CHECK constraint * declaration to be used in statements like CREATE TABLE. * * @param string[]|mixed[][] $definition The check definition. * * @return string DBMS specific SQL code portion needed to set a CHECK constraint. */ public function getCheckDeclarationSQL(array $definition) { $constraints = []; foreach ($definition as $field => $def) { if (is_string($def)) { $constraints[] = 'CHECK (' . $def . ')'; } else { if (isset($def['min'])) { $constraints[] = 'CHECK (' . $field . ' >= ' . $def['min'] . ')'; } if (isset($def['max'])) { $constraints[] = 'CHECK (' . $field . ' <= ' . $def['max'] . ')'; } } } return implode(', ', $constraints); } /** * Obtains DBMS specific SQL code portion needed to set a unique * constraint declaration to be used in statements like CREATE TABLE. * * @param string $name The name of the unique constraint. * @param Index $index The index definition. * * @return string DBMS specific SQL code portion needed to set a constraint. * * @throws InvalidArgumentException */ public function getUniqueConstraintDeclarationSQL($name, Index $index) { $columns = $index->getColumns(); $name = new Identifier($name); if (count($columns) === 0) { throw new InvalidArgumentException("Incomplete definition. 'columns' required."); } return 'CONSTRAINT ' . $name->getQuotedName($this) . ' UNIQUE (' . $this->getIndexFieldDeclarationListSQL($index) . ')' . $this->getPartialIndexSQL($index); } /** * Obtains DBMS specific SQL code portion needed to set an index * declaration to be used in statements like CREATE TABLE. * * @param string $name The name of the index. * @param Index $index The index definition. * * @return string DBMS specific SQL code portion needed to set an index. * * @throws InvalidArgumentException */ public function getIndexDeclarationSQL($name, Index $index) { $columns = $index->getColumns(); $name = new Identifier($name); if (count($columns) === 0) { throw new InvalidArgumentException("Incomplete definition. 'columns' required."); } return $this->getCreateIndexSQLFlags($index) . 'INDEX ' . $name->getQuotedName($this) . ' (' . $this->getIndexFieldDeclarationListSQL($index) . ')' . $this->getPartialIndexSQL($index); } /** * Obtains SQL code portion needed to create a custom column, * e.g. when a field has the "columnDefinition" keyword. * Only "AUTOINCREMENT" and "PRIMARY KEY" are added if appropriate. * * @param mixed[] $columnDef * * @return string */ public function getCustomTypeDeclarationSQL(array $columnDef) { return $columnDef['columnDefinition']; } /** * Obtains DBMS specific SQL code portion needed to set an index * declaration to be used in statements like CREATE TABLE. * * @param mixed[]|Index $columnsOrIndex array declaration is deprecated, prefer passing Index to this method */ public function getIndexFieldDeclarationListSQL($columnsOrIndex) : string { if ($columnsOrIndex instanceof Index) { return implode(', ', $columnsOrIndex->getQuotedColumns($this)); } if (! is_array($columnsOrIndex)) { throw new InvalidArgumentException('Fields argument should be an Index or array.'); } $ret = []; foreach ($columnsOrIndex as $column => $definition) { if (is_array($definition)) { $ret[] = $column; } else { $ret[] = $definition; } } return implode(', ', $ret); } /** * Returns the required SQL string that fits between CREATE ... TABLE * to create the table as a temporary table. * * Should be overridden in driver classes to return the correct string for the * specific database type. * * The default is to return the string "TEMPORARY" - this will result in a * SQL error for any database that does not support temporary tables, or that * requires a different SQL command from "CREATE TEMPORARY TABLE". * * @return string The string required to be placed between "CREATE" and "TABLE" * to generate a temporary table, if possible. */ public function getTemporaryTableSQL() { return 'TEMPORARY'; } /** * Some vendors require temporary table names to be qualified specially. * * @param string $tableName * * @return string */ public function getTemporaryTableName($tableName) { return $tableName; } /** * Obtain DBMS specific SQL code portion needed to set the FOREIGN KEY constraint * of a field declaration to be used in statements like CREATE TABLE. * * @return string DBMS specific SQL code portion needed to set the FOREIGN KEY constraint * of a field declaration. */ public function getForeignKeyDeclarationSQL(ForeignKeyConstraint $foreignKey) { $sql = $this->getForeignKeyBaseDeclarationSQL($foreignKey); $sql .= $this->getAdvancedForeignKeyOptionsSQL($foreignKey); return $sql; } /** * Returns the FOREIGN KEY query section dealing with non-standard options * as MATCH, INITIALLY DEFERRED, ON UPDATE, ... * * @param ForeignKeyConstraint $foreignKey The foreign key definition. * * @return string */ public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey) { $query = ''; if ($this->supportsForeignKeyOnUpdate() && $foreignKey->hasOption('onUpdate')) { $query .= ' ON UPDATE ' . $this->getForeignKeyReferentialActionSQL($foreignKey->getOption('onUpdate')); } if ($foreignKey->hasOption('onDelete')) { $query .= ' ON DELETE ' . $this->getForeignKeyReferentialActionSQL($foreignKey->getOption('onDelete')); } return $query; } /** * Returns the given referential action in uppercase if valid, otherwise throws an exception. * * @param string $action The foreign key referential action. * * @return string * * @throws InvalidArgumentException If unknown referential action given. */ public function getForeignKeyReferentialActionSQL($action) { $upper = strtoupper($action); switch ($upper) { case 'CASCADE': case 'SET NULL': case 'NO ACTION': case 'RESTRICT': case 'SET DEFAULT': return $upper; default: throw new InvalidArgumentException('Invalid foreign key action: ' . $upper); } } /** * Obtains DBMS specific SQL code portion needed to set the FOREIGN KEY constraint * of a field declaration to be used in statements like CREATE TABLE. * * @return string * * @throws InvalidArgumentException */ public function getForeignKeyBaseDeclarationSQL(ForeignKeyConstraint $foreignKey) { $sql = ''; if (strlen($foreignKey->getName())) { $sql .= 'CONSTRAINT ' . $foreignKey->getQuotedName($this) . ' '; } $sql .= 'FOREIGN KEY ('; if (count($foreignKey->getLocalColumns()) === 0) { throw new InvalidArgumentException("Incomplete definition. 'local' required."); } if (count($foreignKey->getForeignColumns()) === 0) { throw new InvalidArgumentException("Incomplete definition. 'foreign' required."); } if (strlen($foreignKey->getForeignTableName()) === 0) { throw new InvalidArgumentException("Incomplete definition. 'foreignTable' required."); } return $sql . implode(', ', $foreignKey->getQuotedLocalColumns($this)) . ') REFERENCES ' . $foreignKey->getQuotedForeignTableName($this) . ' (' . implode(', ', $foreignKey->getQuotedForeignColumns($this)) . ')'; } /** * Obtains DBMS specific SQL code portion needed to set the UNIQUE constraint * of a field declaration to be used in statements like CREATE TABLE. * * @return string DBMS specific SQL code portion needed to set the UNIQUE constraint * of a field declaration. */ public function getUniqueFieldDeclarationSQL() { return 'UNIQUE'; } /** * Obtains DBMS specific SQL code portion needed to set the CHARACTER SET * of a field declaration to be used in statements like CREATE TABLE. * * @param string $charset The name of the charset. * * @return string DBMS specific SQL code portion needed to set the CHARACTER SET * of a field declaration. */ public function getColumnCharsetDeclarationSQL($charset) { return ''; } /** * Obtains DBMS specific SQL code portion needed to set the COLLATION * of a field declaration to be used in statements like CREATE TABLE. * * @param string $collation The name of the collation. * * @return string DBMS specific SQL code portion needed to set the COLLATION * of a field declaration. */ public function getColumnCollationDeclarationSQL($collation) { return $this->supportsColumnCollation() ? 'COLLATE ' . $collation : ''; } /** * Whether the platform prefers sequences for ID generation. * Subclasses should override this method to return TRUE if they prefer sequences. * * @return bool */ public function prefersSequences() { return false; } /** * Whether the platform prefers identity columns (eg. autoincrement) for ID generation. * Subclasses should override this method to return TRUE if they prefer identity columns. * * @return bool */ public function prefersIdentityColumns() { return false; } /** * Some platforms need the boolean values to be converted. * * The default conversion in this implementation converts to integers (false => 0, true => 1). * * Note: if the input is not a boolean the original input might be returned. * * There are two contexts when converting booleans: Literals and Prepared Statements. * This method should handle the literal case * * @param mixed $item A boolean or an array of them. * * @return mixed A boolean database value or an array of them. */ public function convertBooleans($item) { if (is_array($item)) { foreach ($item as $k => $value) { if (! is_bool($value)) { continue; } $item[$k] = (int) $value; } } elseif (is_bool($item)) { $item = (int) $item; } return $item; } /** * Some platforms have boolean literals that needs to be correctly converted * * The default conversion tries to convert value into bool "(bool)$item" * * @param mixed $item * * @return bool|null */ public function convertFromBoolean($item) { return $item === null ? null: (bool) $item; } /** * This method should handle the prepared statements case. When there is no * distinction, it's OK to use the same method. * * Note: if the input is not a boolean the original input might be returned. * * @param mixed $item A boolean or an array of them. * * @return mixed A boolean database value or an array of them. */ public function convertBooleansToDatabaseValue($item) { return $this->convertBooleans($item); } /** * Returns the SQL specific for the platform to get the current date. * * @return string */ public function getCurrentDateSQL() { return 'CURRENT_DATE'; } /** * Returns the SQL specific for the platform to get the current time. * * @return string */ public function getCurrentTimeSQL() { return 'CURRENT_TIME'; } /** * Returns the SQL specific for the platform to get the current timestamp * * @return string */ public function getCurrentTimestampSQL() { return 'CURRENT_TIMESTAMP'; } /** * Returns the SQL for a given transaction isolation level Connection constant. * * @param int $level * * @return string * * @throws InvalidArgumentException */ protected function _getTransactionIsolationLevelSQL($level) { switch ($level) { case TransactionIsolationLevel::READ_UNCOMMITTED: return 'READ UNCOMMITTED'; case TransactionIsolationLevel::READ_COMMITTED: return 'READ COMMITTED'; case TransactionIsolationLevel::REPEATABLE_READ: return 'REPEATABLE READ'; case TransactionIsolationLevel::SERIALIZABLE: return 'SERIALIZABLE'; default: throw new InvalidArgumentException('Invalid isolation level:' . $level); } } /** * @return string * * @throws DBALException If not supported on this platform. */ public function getListDatabasesSQL() { throw DBALException::notSupported(__METHOD__); } /** * Returns the SQL statement for retrieving the namespaces defined in the database. * * @return string * * @throws DBALException If not supported on this platform. */ public function getListNamespacesSQL() { throw DBALException::notSupported(__METHOD__); } /** * @param string $database * * @return string * * @throws DBALException If not supported on this platform. */ public function getListSequencesSQL($database) { throw DBALException::notSupported(__METHOD__); } /** * @param string $table * * @return string * * @throws DBALException If not supported on this platform. */ public function getListTableConstraintsSQL($table) { throw DBALException::notSupported(__METHOD__); } /** * @param string $table * @param string|null $database * * @return string * * @throws DBALException If not supported on this platform. */ public function getListTableColumnsSQL($table, $database = null) { throw DBALException::notSupported(__METHOD__); } /** * @return string * * @throws DBALException If not supported on this platform. */ public function getListTablesSQL() { throw DBALException::notSupported(__METHOD__); } /** * @return string * * @throws DBALException If not supported on this platform. */ public function getListUsersSQL() { throw DBALException::notSupported(__METHOD__); } /** * Returns the SQL to list all views of a database or user. * * @param string $database * * @return string * * @throws DBALException If not supported on this platform. */ public function getListViewsSQL($database) { throw DBALException::notSupported(__METHOD__); } /** * Returns the list of indexes for the current database. * * The current database parameter is optional but will always be passed * when using the SchemaManager API and is the database the given table is in. * * Attention: Some platforms only support currentDatabase when they * are connected with that database. Cross-database information schema * requests may be impossible. * * @param string $table * @param string $currentDatabase * * @return string * * @throws DBALException If not supported on this platform. */ public function getListTableIndexesSQL($table, $currentDatabase = null) { throw DBALException::notSupported(__METHOD__); } /** * @param string $table * * @return string * * @throws DBALException If not supported on this platform. */ public function getListTableForeignKeysSQL($table) { throw DBALException::notSupported(__METHOD__); } /** * @param string $name * @param string $sql * * @return string * * @throws DBALException If not supported on this platform. */ public function getCreateViewSQL($name, $sql) { throw DBALException::notSupported(__METHOD__); } /** * @param string $name * * @return string * * @throws DBALException If not supported on this platform. */ public function getDropViewSQL($name) { throw DBALException::notSupported(__METHOD__); } /** * Returns the SQL snippet to drop an existing sequence. * * @param Sequence|string $sequence * * @return string * * @throws DBALException If not supported on this platform. */ public function getDropSequenceSQL($sequence) { throw DBALException::notSupported(__METHOD__); } /** * @param string $sequenceName * * @return string * * @throws DBALException If not supported on this platform. */ public function getSequenceNextValSQL($sequenceName) { throw DBALException::notSupported(__METHOD__); } /** * Returns the SQL to create a new database. * * @param string $database The name of the database that should be created. * * @return string * * @throws DBALException If not supported on this platform. */ public function getCreateDatabaseSQL($database) { throw DBALException::notSupported(__METHOD__); } /** * Returns the SQL to set the transaction isolation level. * * @param int $level * * @return string * * @throws DBALException If not supported on this platform. */ public function getSetTransactionIsolationSQL($level) { throw DBALException::notSupported(__METHOD__); } /** * Obtains DBMS specific SQL to be used to create datetime fields in * statements like CREATE TABLE. * * @param mixed[] $fieldDeclaration * * @return string * * @throws DBALException If not supported on this platform. */ public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) { throw DBALException::notSupported(__METHOD__); } /** * Obtains DBMS specific SQL to be used to create datetime with timezone offset fields. * * @param mixed[] $fieldDeclaration * * @return string */ public function getDateTimeTzTypeDeclarationSQL(array $fieldDeclaration) { return $this->getDateTimeTypeDeclarationSQL($fieldDeclaration); } /** * Obtains DBMS specific SQL to be used to create date fields in statements * like CREATE TABLE. * * @param mixed[] $fieldDeclaration * * @return string * * @throws DBALException If not supported on this platform. */ public function getDateTypeDeclarationSQL(array $fieldDeclaration) { throw DBALException::notSupported(__METHOD__); } /** * Obtains DBMS specific SQL to be used to create time fields in statements * like CREATE TABLE. * * @param mixed[] $fieldDeclaration * * @return string * * @throws DBALException If not supported on this platform. */ public function getTimeTypeDeclarationSQL(array $fieldDeclaration) { throw DBALException::notSupported(__METHOD__); } /** * @param mixed[] $fieldDeclaration * * @return string */ public function getFloatDeclarationSQL(array $fieldDeclaration) { return 'DOUBLE PRECISION'; } /** * Gets the default transaction isolation level of the platform. * * @see TransactionIsolationLevel * * @return int The default isolation level. */ public function getDefaultTransactionIsolationLevel() { return TransactionIsolationLevel::READ_COMMITTED; } /* supports*() methods */ /** * Whether the platform supports sequences. * * @return bool */ public function supportsSequences() { return false; } /** * Whether the platform supports identity columns. * * Identity columns are columns that receive an auto-generated value from the * database on insert of a row. * * @return bool */ public function supportsIdentityColumns() { return false; } /** * Whether the platform emulates identity columns through sequences. * * Some platforms that do not support identity columns natively * but support sequences can emulate identity columns by using * sequences. * * @return bool */ public function usesSequenceEmulatedIdentityColumns() { return false; } /** * Returns the name of the sequence for a particular identity column in a particular table. * * @see usesSequenceEmulatedIdentityColumns * * @param string $tableName The name of the table to return the sequence name for. * @param string $columnName The name of the identity column in the table to return the sequence name for. * * @return string * * @throws DBALException If not supported on this platform. */ public function getIdentitySequenceName($tableName, $columnName) { throw DBALException::notSupported(__METHOD__); } /** * Whether the platform supports indexes. * * @return bool */ public function supportsIndexes() { return true; } /** * Whether the platform supports partial indexes. * * @return bool */ public function supportsPartialIndexes() { return false; } /** * Whether the platform supports indexes with column length definitions. */ public function supportsColumnLengthIndexes() : bool { return false; } /** * Whether the platform supports altering tables. * * @return bool */ public function supportsAlterTable() { return true; } /** * Whether the platform supports transactions. * * @return bool */ public function supportsTransactions() { return true; } /** * Whether the platform supports savepoints. * * @return bool */ public function supportsSavepoints() { return true; } /** * Whether the platform supports releasing savepoints. * * @return bool */ public function supportsReleaseSavepoints() { return $this->supportsSavepoints(); } /** * Whether the platform supports primary key constraints. * * @return bool */ public function supportsPrimaryConstraints() { return true; } /** * Whether the platform supports foreign key constraints. * * @return bool */ public function supportsForeignKeyConstraints() { return true; } /** * Whether this platform supports onUpdate in foreign key constraints. * * @return bool */ public function supportsForeignKeyOnUpdate() { return $this->supportsForeignKeyConstraints(); } /** * Whether the platform supports database schemas. * * @return bool */ public function supportsSchemas() { return false; } /** * Whether this platform can emulate schemas. * * Platforms that either support or emulate schemas don't automatically * filter a schema for the namespaced elements in {@link * AbstractManager#createSchema}. * * @return bool */ public function canEmulateSchemas() { return false; } /** * Returns the default schema name. * * @return string * * @throws DBALException If not supported on this platform. */ public function getDefaultSchemaName() { throw DBALException::notSupported(__METHOD__); } /** * Whether this platform supports create database. * * Some databases don't allow to create and drop databases at all or only with certain tools. * * @return bool */ public function supportsCreateDropDatabase() { return true; } /** * Whether the platform supports getting the affected rows of a recent update/delete type query. * * @return bool */ public function supportsGettingAffectedRows() { return true; } /** * Whether this platform support to add inline column comments as postfix. * * @return bool */ public function supportsInlineColumnComments() { return false; } /** * Whether this platform support the proprietary syntax "COMMENT ON asset". * * @return bool */ public function supportsCommentOnStatement() { return false; } /** * Does this platform have native guid type. * * @return bool */ public function hasNativeGuidType() { return false; } /** * Does this platform have native JSON type. * * @return bool */ public function hasNativeJsonType() { return false; } /** * @deprecated * * @todo Remove in 3.0 */ public function getIdentityColumnNullInsertSQL() { return ''; } /** * Whether this platform supports views. * * @return bool */ public function supportsViews() { return true; } /** * Does this platform support column collation? * * @return bool */ public function supportsColumnCollation() { return false; } /** * Gets the format string, as accepted by the date() function, that describes * the format of a stored datetime value of this platform. * * @return string The format string. */ public function getDateTimeFormatString() { return 'Y-m-d H:i:s'; } /** * Gets the format string, as accepted by the date() function, that describes * the format of a stored datetime with timezone value of this platform. * * @return string The format string. */ public function getDateTimeTzFormatString() { return 'Y-m-d H:i:s'; } /** * Gets the format string, as accepted by the date() function, that describes * the format of a stored date value of this platform. * * @return string The format string. */ public function getDateFormatString() { return 'Y-m-d'; } /** * Gets the format string, as accepted by the date() function, that describes * the format of a stored time value of this platform. * * @return string The format string. */ public function getTimeFormatString() { return 'H:i:s'; } /** * Adds an driver-specific LIMIT clause to the query. * * @param string $query * @param int|null $limit * @param int|null $offset * * @return string * * @throws DBALException */ final public function modifyLimitQuery($query, $limit, $offset = null) { if ($limit !== null) { $limit = (int) $limit; } $offset = (int) $offset; if ($offset < 0) { throw new DBALException(sprintf( 'Offset must be a positive integer or zero, %d given', $offset )); } if ($offset > 0 && ! $this->supportsLimitOffset()) { throw new DBALException(sprintf( 'Platform %s does not support offset values in limit queries.', $this->getName() )); } return $this->doModifyLimitQuery($query, $limit, $offset); } /** * Adds an platform-specific LIMIT clause to the query. * * @param string $query * @param int|null $limit * @param int|null $offset * * @return string */ protected function doModifyLimitQuery($query, $limit, $offset) { if ($limit !== null) { $query .= ' LIMIT ' . $limit; } if ($offset > 0) { $query .= ' OFFSET ' . $offset; } return $query; } /** * Whether the database platform support offsets in modify limit clauses. * * @return bool */ public function supportsLimitOffset() { return true; } /** * Gets the character casing of a column in an SQL result set of this platform. * * @param string $column The column name for which to get the correct character casing. * * @return string The column name in the character casing used in SQL result sets. */ public function getSQLResultCasing($column) { return $column; } /** * Makes any fixes to a name of a schema element (table, sequence, ...) that are required * by restrictions of the platform, like a maximum length. * * @param string $schemaElementName * * @return string */ public function fixSchemaElementName($schemaElementName) { return $schemaElementName; } /** * Maximum length of any given database identifier, like tables or column names. * * @return int */ public function getMaxIdentifierLength() { return 63; } /** * Returns the insert SQL for an empty insert statement. * * @param string $tableName * @param string $identifierColumnName * * @return string */ public function getEmptyIdentityInsertSQL($tableName, $identifierColumnName) { return 'INSERT INTO ' . $tableName . ' (' . $identifierColumnName . ') VALUES (null)'; } /** * Generates a Truncate Table SQL statement for a given table. * * Cascade is not supported on many platforms but would optionally cascade the truncate by * following the foreign keys. * * @param string $tableName * @param bool $cascade * * @return string */ public function getTruncateTableSQL($tableName, $cascade = false) { $tableIdentifier = new Identifier($tableName); return 'TRUNCATE ' . $tableIdentifier->getQuotedName($this); } /** * This is for test reasons, many vendors have special requirements for dummy statements. * * @return string */ public function getDummySelectSQL() { $expression = func_num_args() > 0 ? func_get_arg(0) : '1'; return sprintf('SELECT %s', $expression); } /** * Returns the SQL to create a new savepoint. * * @param string $savepoint * * @return string */ public function createSavePoint($savepoint) { return 'SAVEPOINT ' . $savepoint; } /** * Returns the SQL to release a savepoint. * * @param string $savepoint * * @return string */ public function releaseSavePoint($savepoint) { return 'RELEASE SAVEPOINT ' . $savepoint; } /** * Returns the SQL to rollback a savepoint. * * @param string $savepoint * * @return string */ public function rollbackSavePoint($savepoint) { return 'ROLLBACK TO SAVEPOINT ' . $savepoint; } /** * Returns the keyword list instance of this platform. * * @return KeywordList * * @throws DBALException If no keyword list is specified. */ final public function getReservedKeywordsList() { // Check for an existing instantiation of the keywords class. if ($this->_keywords) { return $this->_keywords; } $class = $this->getReservedKeywordsClass(); $keywords = new $class(); if (! $keywords instanceof KeywordList) { throw DBALException::notSupported(__METHOD__); } // Store the instance so it doesn't need to be generated on every request. $this->_keywords = $keywords; return $keywords; } /** * Returns the class name of the reserved keywords list. * * @return string * * @throws DBALException If not supported on this platform. */ protected function getReservedKeywordsClass() { throw DBALException::notSupported(__METHOD__); } /** * Quotes a literal string. * This method is NOT meant to fix SQL injections! * It is only meant to escape this platform's string literal * quote character inside the given literal string. * * @param string $str The literal string to be quoted. * * @return string The quoted literal string. */ public function quoteStringLiteral($str) { $c = $this->getStringLiteralQuoteCharacter(); return $c . str_replace($c, $c . $c, $str) . $c; } /** * Gets the character used for string literal quoting. * * @return string */ public function getStringLiteralQuoteCharacter() { return "'"; } /** * Escapes metacharacters in a string intended to be used with a LIKE * operator. * * @param string $inputString a literal, unquoted string * @param string $escapeChar should be reused by the caller in the LIKE * expression. */ final public function escapeStringForLike(string $inputString, string $escapeChar) : string { return preg_replace( '~([' . preg_quote($this->getLikeWildcardCharacters() . $escapeChar, '~') . '])~u', addcslashes($escapeChar, '\\') . '$1', $inputString ); } protected function getLikeWildcardCharacters() : string { return '%_'; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Platforms/DB2Platform.php000066400000000000000000000612721360544566000246630ustar00rootroot00000000000000getCharMaxLength(); } return parent::getVarcharTypeDeclarationSQL($field); } /** * {@inheritDoc} */ public function getBlobTypeDeclarationSQL(array $field) { // todo blob(n) with $field['length']; return 'BLOB(1M)'; } /** * {@inheritDoc} */ public function initializeDoctrineTypeMappings() { $this->doctrineTypeMapping = [ 'smallint' => 'smallint', 'bigint' => 'bigint', 'integer' => 'integer', 'time' => 'time', 'date' => 'date', 'varchar' => 'string', 'character' => 'string', 'varbinary' => 'binary', 'binary' => 'binary', 'clob' => 'text', 'blob' => 'blob', 'decimal' => 'decimal', 'double' => 'float', 'real' => 'float', 'timestamp' => 'datetime', ]; } /** * {@inheritdoc} */ public function isCommentedDoctrineType(Type $doctrineType) { if ($doctrineType->getName() === Types::BOOLEAN) { // We require a commented boolean type in order to distinguish between boolean and smallint // as both (have to) map to the same native type. return true; } return parent::isCommentedDoctrineType($doctrineType); } /** * {@inheritDoc} */ protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) { return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(254)') : ($length ? 'VARCHAR(' . $length . ')' : 'VARCHAR(255)'); } /** * {@inheritdoc} */ protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed) { return $this->getVarcharTypeDeclarationSQLSnippet($length, $fixed) . ' FOR BIT DATA'; } /** * {@inheritDoc} */ public function getClobTypeDeclarationSQL(array $field) { // todo clob(n) with $field['length']; return 'CLOB(1M)'; } /** * {@inheritDoc} */ public function getName() { return 'db2'; } /** * {@inheritDoc} */ public function getBooleanTypeDeclarationSQL(array $columnDef) { return 'SMALLINT'; } /** * {@inheritDoc} */ public function getIntegerTypeDeclarationSQL(array $columnDef) { return 'INTEGER' . $this->_getCommonIntegerTypeDeclarationSQL($columnDef); } /** * {@inheritDoc} */ public function getBigIntTypeDeclarationSQL(array $columnDef) { return 'BIGINT' . $this->_getCommonIntegerTypeDeclarationSQL($columnDef); } /** * {@inheritDoc} */ public function getSmallIntTypeDeclarationSQL(array $columnDef) { return 'SMALLINT' . $this->_getCommonIntegerTypeDeclarationSQL($columnDef); } /** * {@inheritDoc} */ protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) { $autoinc = ''; if (! empty($columnDef['autoincrement'])) { $autoinc = ' GENERATED BY DEFAULT AS IDENTITY'; } return $autoinc; } /** * {@inheritdoc} */ public function getBitAndComparisonExpression($value1, $value2) { return 'BITAND(' . $value1 . ', ' . $value2 . ')'; } /** * {@inheritdoc} */ public function getBitOrComparisonExpression($value1, $value2) { return 'BITOR(' . $value1 . ', ' . $value2 . ')'; } /** * {@inheritdoc} */ protected function getDateArithmeticIntervalExpression($date, $operator, $interval, $unit) { switch ($unit) { case DateIntervalUnit::WEEK: $interval *= 7; $unit = DateIntervalUnit::DAY; break; case DateIntervalUnit::QUARTER: $interval *= 3; $unit = DateIntervalUnit::MONTH; break; } return $date . ' ' . $operator . ' ' . $interval . ' ' . $unit; } /** * {@inheritdoc} */ public function getDateDiffExpression($date1, $date2) { return 'DAYS(' . $date1 . ') - DAYS(' . $date2 . ')'; } /** * {@inheritDoc} */ public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) { if (isset($fieldDeclaration['version']) && $fieldDeclaration['version'] === true) { return 'TIMESTAMP(0) WITH DEFAULT'; } return 'TIMESTAMP(0)'; } /** * {@inheritDoc} */ public function getDateTypeDeclarationSQL(array $fieldDeclaration) { return 'DATE'; } /** * {@inheritDoc} */ public function getTimeTypeDeclarationSQL(array $fieldDeclaration) { return 'TIME'; } /** * {@inheritdoc} */ public function getTruncateTableSQL($tableName, $cascade = false) { $tableIdentifier = new Identifier($tableName); return 'TRUNCATE ' . $tableIdentifier->getQuotedName($this) . ' IMMEDIATE'; } /** * This code fragment is originally from the Zend_Db_Adapter_Db2 class, but has been edited. * * @param string $table * @param string $database * * @return string */ public function getListTableColumnsSQL($table, $database = null) { $table = $this->quoteStringLiteral($table); // We do the funky subquery and join syscat.columns.default this crazy way because // as of db2 v10, the column is CLOB(64k) and the distinct operator won't allow a CLOB, // it wants shorter stuff like a varchar. return " SELECT cols.default, subq.* FROM ( SELECT DISTINCT c.tabschema, c.tabname, c.colname, c.colno, c.typename, c.nulls, c.length, c.scale, c.identity, tc.type AS tabconsttype, c.remarks AS comment, k.colseq, CASE WHEN c.generated = 'D' THEN 1 ELSE 0 END AS autoincrement FROM syscat.columns c LEFT JOIN (syscat.keycoluse k JOIN syscat.tabconst tc ON (k.tabschema = tc.tabschema AND k.tabname = tc.tabname AND tc.type = 'P')) ON (c.tabschema = k.tabschema AND c.tabname = k.tabname AND c.colname = k.colname) WHERE UPPER(c.tabname) = UPPER(" . $table . ') ORDER BY c.colno ) subq JOIN syscat.columns cols ON subq.tabschema = cols.tabschema AND subq.tabname = cols.tabname AND subq.colno = cols.colno ORDER BY subq.colno '; } /** * {@inheritDoc} */ public function getListTablesSQL() { return "SELECT NAME FROM SYSIBM.SYSTABLES WHERE TYPE = 'T'"; } /** * {@inheritDoc} */ public function getListViewsSQL($database) { return 'SELECT NAME, TEXT FROM SYSIBM.SYSVIEWS'; } /** * {@inheritDoc} */ public function getListTableIndexesSQL($table, $currentDatabase = null) { $table = $this->quoteStringLiteral($table); return "SELECT idx.INDNAME AS key_name, idxcol.COLNAME AS column_name, CASE WHEN idx.UNIQUERULE = 'P' THEN 1 ELSE 0 END AS primary, CASE WHEN idx.UNIQUERULE = 'D' THEN 1 ELSE 0 END AS non_unique FROM SYSCAT.INDEXES AS idx JOIN SYSCAT.INDEXCOLUSE AS idxcol ON idx.INDSCHEMA = idxcol.INDSCHEMA AND idx.INDNAME = idxcol.INDNAME WHERE idx.TABNAME = UPPER(" . $table . ') ORDER BY idxcol.COLSEQ ASC'; } /** * {@inheritDoc} */ public function getListTableForeignKeysSQL($table) { $table = $this->quoteStringLiteral($table); return "SELECT fkcol.COLNAME AS local_column, fk.REFTABNAME AS foreign_table, pkcol.COLNAME AS foreign_column, fk.CONSTNAME AS index_name, CASE WHEN fk.UPDATERULE = 'R' THEN 'RESTRICT' ELSE NULL END AS on_update, CASE WHEN fk.DELETERULE = 'C' THEN 'CASCADE' WHEN fk.DELETERULE = 'N' THEN 'SET NULL' WHEN fk.DELETERULE = 'R' THEN 'RESTRICT' ELSE NULL END AS on_delete FROM SYSCAT.REFERENCES AS fk JOIN SYSCAT.KEYCOLUSE AS fkcol ON fk.CONSTNAME = fkcol.CONSTNAME AND fk.TABSCHEMA = fkcol.TABSCHEMA AND fk.TABNAME = fkcol.TABNAME JOIN SYSCAT.KEYCOLUSE AS pkcol ON fk.REFKEYNAME = pkcol.CONSTNAME AND fk.REFTABSCHEMA = pkcol.TABSCHEMA AND fk.REFTABNAME = pkcol.TABNAME WHERE fk.TABNAME = UPPER(" . $table . ') ORDER BY fkcol.COLSEQ ASC'; } /** * {@inheritDoc} */ public function getCreateViewSQL($name, $sql) { return 'CREATE VIEW ' . $name . ' AS ' . $sql; } /** * {@inheritDoc} */ public function getDropViewSQL($name) { return 'DROP VIEW ' . $name; } /** * {@inheritDoc} */ public function getCreateDatabaseSQL($database) { return 'CREATE DATABASE ' . $database; } /** * {@inheritDoc} */ public function getDropDatabaseSQL($database) { return 'DROP DATABASE ' . $database; } /** * {@inheritDoc} */ public function supportsCreateDropDatabase() { return false; } /** * {@inheritDoc} */ public function supportsReleaseSavepoints() { return false; } /** * {@inheritdoc} */ public function supportsCommentOnStatement() { return true; } /** * {@inheritDoc} */ public function getCurrentDateSQL() { return 'CURRENT DATE'; } /** * {@inheritDoc} */ public function getCurrentTimeSQL() { return 'CURRENT TIME'; } /** * {@inheritDoc} */ public function getCurrentTimestampSQL() { return 'CURRENT TIMESTAMP'; } /** * {@inheritDoc} */ public function getIndexDeclarationSQL($name, Index $index) { // Index declaration in statements like CREATE TABLE is not supported. throw DBALException::notSupported(__METHOD__); } /** * {@inheritDoc} */ protected function _getCreateTableSQL($tableName, array $columns, array $options = []) { $indexes = []; if (isset($options['indexes'])) { $indexes = $options['indexes']; } $options['indexes'] = []; $sqls = parent::_getCreateTableSQL($tableName, $columns, $options); foreach ($indexes as $definition) { $sqls[] = $this->getCreateIndexSQL($definition, $tableName); } return $sqls; } /** * {@inheritDoc} */ public function getAlterTableSQL(TableDiff $diff) { $sql = []; $columnSql = []; $commentsSQL = []; $queryParts = []; foreach ($diff->addedColumns as $column) { if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) { continue; } $columnDef = $column->toArray(); $queryPart = 'ADD COLUMN ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnDef); // Adding non-nullable columns to a table requires a default value to be specified. if (! empty($columnDef['notnull']) && ! isset($columnDef['default']) && empty($columnDef['autoincrement']) ) { $queryPart .= ' WITH DEFAULT'; } $queryParts[] = $queryPart; $comment = $this->getColumnComment($column); if ($comment === null || $comment === '') { continue; } $commentsSQL[] = $this->getCommentOnColumnSQL( $diff->getName($this)->getQuotedName($this), $column->getQuotedName($this), $comment ); } foreach ($diff->removedColumns as $column) { if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) { continue; } $queryParts[] = 'DROP COLUMN ' . $column->getQuotedName($this); } foreach ($diff->changedColumns as $columnDiff) { if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) { continue; } if ($columnDiff->hasChanged('comment')) { $commentsSQL[] = $this->getCommentOnColumnSQL( $diff->getName($this)->getQuotedName($this), $columnDiff->column->getQuotedName($this), $this->getColumnComment($columnDiff->column) ); if (count($columnDiff->changedProperties) === 1) { continue; } } $this->gatherAlterColumnSQL($diff->getName($this), $columnDiff, $sql, $queryParts); } foreach ($diff->renamedColumns as $oldColumnName => $column) { if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) { continue; } $oldColumnName = new Identifier($oldColumnName); $queryParts[] = 'RENAME COLUMN ' . $oldColumnName->getQuotedName($this) . ' TO ' . $column->getQuotedName($this); } $tableSql = []; if (! $this->onSchemaAlterTable($diff, $tableSql)) { if (count($queryParts) > 0) { $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) . ' ' . implode(' ', $queryParts); } // Some table alteration operations require a table reorganization. if (! empty($diff->removedColumns) || ! empty($diff->changedColumns)) { $sql[] = "CALL SYSPROC.ADMIN_CMD ('REORG TABLE " . $diff->getName($this)->getQuotedName($this) . "')"; } $sql = array_merge($sql, $commentsSQL); $newName = $diff->getNewName(); if ($newName !== false) { $sql[] = sprintf( 'RENAME TABLE %s TO %s', $diff->getName($this)->getQuotedName($this), $newName->getQuotedName($this) ); } $sql = array_merge( $this->getPreAlterTableIndexForeignKeySQL($diff), $sql, $this->getPostAlterTableIndexForeignKeySQL($diff) ); } return array_merge($sql, $tableSql, $columnSql); } /** * Gathers the table alteration SQL for a given column diff. * * @param Identifier $table The table to gather the SQL for. * @param ColumnDiff $columnDiff The column diff to evaluate. * @param string[] $sql The sequence of table alteration statements to fill. * @param mixed[] $queryParts The sequence of column alteration clauses to fill. */ private function gatherAlterColumnSQL(Identifier $table, ColumnDiff $columnDiff, array &$sql, array &$queryParts) { $alterColumnClauses = $this->getAlterColumnClausesSQL($columnDiff); if (empty($alterColumnClauses)) { return; } // If we have a single column alteration, we can append the clause to the main query. if (count($alterColumnClauses) === 1) { $queryParts[] = current($alterColumnClauses); return; } // We have multiple alterations for the same column, // so we need to trigger a complete ALTER TABLE statement // for each ALTER COLUMN clause. foreach ($alterColumnClauses as $alterColumnClause) { $sql[] = 'ALTER TABLE ' . $table->getQuotedName($this) . ' ' . $alterColumnClause; } } /** * Returns the ALTER COLUMN SQL clauses for altering a column described by the given column diff. * * @param ColumnDiff $columnDiff The column diff to evaluate. * * @return string[] */ private function getAlterColumnClausesSQL(ColumnDiff $columnDiff) { $column = $columnDiff->column->toArray(); $alterClause = 'ALTER COLUMN ' . $columnDiff->column->getQuotedName($this); if ($column['columnDefinition']) { return [$alterClause . ' ' . $column['columnDefinition']]; } $clauses = []; if ($columnDiff->hasChanged('type') || $columnDiff->hasChanged('length') || $columnDiff->hasChanged('precision') || $columnDiff->hasChanged('scale') || $columnDiff->hasChanged('fixed') ) { $clauses[] = $alterClause . ' SET DATA TYPE ' . $column['type']->getSQLDeclaration($column, $this); } if ($columnDiff->hasChanged('notnull')) { $clauses[] = $column['notnull'] ? $alterClause . ' SET NOT NULL' : $alterClause . ' DROP NOT NULL'; } if ($columnDiff->hasChanged('default')) { if (isset($column['default'])) { $defaultClause = $this->getDefaultValueDeclarationSQL($column); if ($defaultClause) { $clauses[] = $alterClause . ' SET' . $defaultClause; } } else { $clauses[] = $alterClause . ' DROP DEFAULT'; } } return $clauses; } /** * {@inheritDoc} */ protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff) { $sql = []; $table = $diff->getName($this)->getQuotedName($this); foreach ($diff->removedIndexes as $remKey => $remIndex) { foreach ($diff->addedIndexes as $addKey => $addIndex) { if ($remIndex->getColumns() === $addIndex->getColumns()) { if ($remIndex->isPrimary()) { $sql[] = 'ALTER TABLE ' . $table . ' DROP PRIMARY KEY'; } elseif ($remIndex->isUnique()) { $sql[] = 'ALTER TABLE ' . $table . ' DROP UNIQUE ' . $remIndex->getQuotedName($this); } else { $sql[] = $this->getDropIndexSQL($remIndex, $table); } $sql[] = $this->getCreateIndexSQL($addIndex, $table); unset($diff->removedIndexes[$remKey], $diff->addedIndexes[$addKey]); break; } } } $sql = array_merge($sql, parent::getPreAlterTableIndexForeignKeySQL($diff)); return $sql; } /** * {@inheritdoc} */ protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName) { if (strpos($tableName, '.') !== false) { [$schema] = explode('.', $tableName); $oldIndexName = $schema . '.' . $oldIndexName; } return ['RENAME INDEX ' . $oldIndexName . ' TO ' . $index->getQuotedName($this)]; } /** * {@inheritDoc} */ public function getDefaultValueDeclarationSQL($field) { if (! empty($field['autoincrement'])) { return ''; } if (isset($field['version']) && $field['version']) { if ((string) $field['type'] !== 'DateTime') { $field['default'] = '1'; } } return parent::getDefaultValueDeclarationSQL($field); } /** * {@inheritDoc} */ public function getEmptyIdentityInsertSQL($tableName, $identifierColumnName) { return 'INSERT INTO ' . $tableName . ' (' . $identifierColumnName . ') VALUES (DEFAULT)'; } /** * {@inheritDoc} */ public function getCreateTemporaryTableSnippetSQL() { return 'DECLARE GLOBAL TEMPORARY TABLE'; } /** * {@inheritDoc} */ public function getTemporaryTableName($tableName) { return 'SESSION.' . $tableName; } /** * {@inheritDoc} */ protected function doModifyLimitQuery($query, $limit, $offset = null) { $where = []; if ($offset > 0) { $where[] = sprintf('db22.DC_ROWNUM >= %d', $offset + 1); } if ($limit !== null) { $where[] = sprintf('db22.DC_ROWNUM <= %d', $offset + $limit); } if (empty($where)) { return $query; } // Todo OVER() needs ORDER BY data! return sprintf( 'SELECT db22.* FROM (SELECT db21.*, ROW_NUMBER() OVER() AS DC_ROWNUM FROM (%s) db21) db22 WHERE %s', $query, implode(' AND ', $where) ); } /** * {@inheritDoc} */ public function getLocateExpression($str, $substr, $startPos = false) { if ($startPos === false) { return 'LOCATE(' . $substr . ', ' . $str . ')'; } return 'LOCATE(' . $substr . ', ' . $str . ', ' . $startPos . ')'; } /** * {@inheritDoc} */ public function getSubstringExpression($value, $from, $length = null) { if ($length === null) { return 'SUBSTR(' . $value . ', ' . $from . ')'; } return 'SUBSTR(' . $value . ', ' . $from . ', ' . $length . ')'; } /** * {@inheritDoc} */ public function supportsIdentityColumns() { return true; } /** * {@inheritDoc} */ public function prefersIdentityColumns() { return true; } /** * {@inheritDoc} * * DB2 returns all column names in SQL result sets in uppercase. */ public function getSQLResultCasing($column) { return strtoupper($column); } /** * {@inheritDoc} */ public function getForUpdateSQL() { return ' WITH RR USE AND KEEP UPDATE LOCKS'; } /** * {@inheritDoc} */ public function getDummySelectSQL() { $expression = func_num_args() > 0 ? func_get_arg(0) : '1'; return sprintf('SELECT %s FROM sysibm.sysdummy1', $expression); } /** * {@inheritDoc} * * DB2 supports savepoints, but they work semantically different than on other vendor platforms. * * TODO: We have to investigate how to get DB2 up and running with savepoints. */ public function supportsSavepoints() { return false; } /** * {@inheritDoc} */ protected function getReservedKeywordsClass() { return Keywords\DB2Keywords::class; } public function getListTableCommentsSQL(string $table) : string { return sprintf( <<<'SQL' SELECT REMARKS FROM SYSIBM.SYSTABLES WHERE NAME = UPPER( %s ) SQL , $this->quoteStringLiteral($table) ); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Platforms/DateIntervalUnit.php000066400000000000000000000006531360544566000260250ustar00rootroot00000000000000_getCommonIntegerTypeDeclarationSQL($field); } /** * {@inheritDoc} */ protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) { $autoinc = ''; if (! empty($columnDef['autoincrement'])) { $autoinc = ' AUTO_INCREMENT'; } return $autoinc; } /** * {@inheritDoc} */ public function getBigIntTypeDeclarationSQL(array $field) { return 'BIGINT' . $this->_getCommonIntegerTypeDeclarationSQL($field); } /** * {@inheritDoc} */ public function getSmallIntTypeDeclarationSQL(array $field) { return 'INT' . $this->_getCommonIntegerTypeDeclarationSQL($field); } /** * {@inheritDoc} */ protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) { return $length ? 'VARCHAR(' . $length . ')' : 'VARCHAR(255)'; } /** * {@inheritdoc} */ protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed) { return 'VARBINARY(' . ($length ?: 255) . ')'; } /** * {@inheritDoc} */ protected function initializeDoctrineTypeMappings() { $this->doctrineTypeMapping = [ 'boolean' => 'boolean', 'varchar' => 'string', 'varbinary' => 'binary', 'integer' => 'integer', 'blob' => 'blob', 'decimal' => 'decimal', 'datetime' => 'datetime', 'date' => 'date', 'time' => 'time', 'text' => 'text', 'timestamp' => 'datetime', 'double' => 'float', 'bigint' => 'bigint', ]; } /** * {@inheritDoc} */ public function getClobTypeDeclarationSQL(array $field) { return 'TEXT'; } /** * {@inheritDoc} */ public function getBlobTypeDeclarationSQL(array $field) { return 'BLOB'; } /** * {@inheritDoc} */ public function getCreateDatabaseSQL($name) { return 'CREATE DATABASE ' . $name; } /** * {@inheritDoc} */ public function getDropDatabaseSQL($name) { return 'DROP DATABASE ' . $name; } /** * {@inheritDoc} */ protected function _getCreateTableSQL($tableName, array $columns, array $options = []) { $queryFields = $this->getColumnDeclarationListSQL($columns); if (isset($options['uniqueConstraints']) && ! empty($options['uniqueConstraints'])) { foreach ($options['uniqueConstraints'] as $index => $definition) { $queryFields .= ', ' . $this->getUniqueConstraintDeclarationSQL($index, $definition); } } // add all indexes if (isset($options['indexes']) && ! empty($options['indexes'])) { foreach ($options['indexes'] as $index => $definition) { $queryFields .= ', ' . $this->getIndexDeclarationSQL($index, $definition); } } // attach all primary keys if (isset($options['primary']) && ! empty($options['primary'])) { $keyColumns = array_unique(array_values($options['primary'])); $queryFields .= ', PRIMARY KEY(' . implode(', ', $keyColumns) . ')'; } $query = 'CREATE '; if (! empty($options['temporary'])) { $query .= 'TEMPORARY '; } $query .= 'TABLE ' . $tableName . ' (' . $queryFields . ') '; $query .= $this->buildTableOptions($options); $query .= $this->buildPartitionOptions($options); $sql = [$query]; if (isset($options['foreignKeys'])) { foreach ((array) $options['foreignKeys'] as $definition) { $sql[] = $this->getCreateForeignKeySQL($definition, $tableName); } } return $sql; } /** * Build SQL for table options * * @param mixed[] $options * * @return string */ private function buildTableOptions(array $options) { if (isset($options['table_options'])) { return $options['table_options']; } $tableOptions = []; // Collate if (! isset($options['collate'])) { $options['collate'] = 'utf8_unicode_ci'; } $tableOptions[] = sprintf('COLLATE %s', $options['collate']); // Engine if (! isset($options['engine'])) { $options['engine'] = 'InnoDB'; } $tableOptions[] = sprintf('ENGINE = %s', $options['engine']); // Auto increment if (isset($options['auto_increment'])) { $tableOptions[] = sprintf('AUTO_INCREMENT = %s', $options['auto_increment']); } // Comment if (isset($options['comment'])) { $comment = trim($options['comment'], " '"); $tableOptions[] = sprintf('COMMENT = %s ', $this->quoteStringLiteral($comment)); } // Row format if (isset($options['row_format'])) { $tableOptions[] = sprintf('ROW_FORMAT = %s', $options['row_format']); } return implode(' ', $tableOptions); } /** * Build SQL for partition options. * * @param mixed[] $options * * @return string */ private function buildPartitionOptions(array $options) { return isset($options['partition_options']) ? ' ' . $options['partition_options'] : ''; } /** * {@inheritDoc} */ public function getListDatabasesSQL() { return "SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE CATALOG_NAME='LOCAL'"; } /** * {@inheritDoc} */ protected function getReservedKeywordsClass() { return Keywords\DrizzleKeywords::class; } /** * {@inheritDoc} */ public function getListTablesSQL() { return "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE' AND TABLE_SCHEMA=DATABASE()"; } /** * {@inheritDoc} */ public function getListTableColumnsSQL($table, $database = null) { if ($database) { $databaseSQL = $this->quoteStringLiteral($database); } else { $databaseSQL = 'DATABASE()'; } return 'SELECT COLUMN_NAME, DATA_TYPE, COLUMN_COMMENT, IS_NULLABLE, IS_AUTO_INCREMENT, CHARACTER_MAXIMUM_LENGTH, COLUMN_DEFAULT,' . ' NUMERIC_PRECISION, NUMERIC_SCALE, COLLATION_NAME' . ' FROM DATA_DICTIONARY.COLUMNS' . ' WHERE TABLE_SCHEMA=' . $databaseSQL . ' AND TABLE_NAME = ' . $this->quoteStringLiteral($table); } /** * {@inheritDoc} */ public function getListTableForeignKeysSQL($table, $database = null) { if ($database) { $databaseSQL = $this->quoteStringLiteral($database); } else { $databaseSQL = 'DATABASE()'; } return 'SELECT CONSTRAINT_NAME, CONSTRAINT_COLUMNS, REFERENCED_TABLE_NAME, REFERENCED_TABLE_COLUMNS, UPDATE_RULE, DELETE_RULE' . ' FROM DATA_DICTIONARY.FOREIGN_KEYS' . ' WHERE CONSTRAINT_SCHEMA=' . $databaseSQL . ' AND CONSTRAINT_TABLE=' . $this->quoteStringLiteral($table); } /** * {@inheritDoc} */ public function getListTableIndexesSQL($table, $database = null) { if ($database) { $databaseSQL = $this->quoteStringLiteral($database); } else { $databaseSQL = 'DATABASE()'; } return "SELECT INDEX_NAME AS 'key_name', COLUMN_NAME AS 'column_name', IS_USED_IN_PRIMARY AS 'primary', IS_UNIQUE=0 AS 'non_unique'" . ' FROM DATA_DICTIONARY.INDEX_PARTS' . ' WHERE TABLE_SCHEMA=' . $databaseSQL . ' AND TABLE_NAME=' . $this->quoteStringLiteral($table); } /** * {@inheritDoc} */ public function prefersIdentityColumns() { return true; } /** * {@inheritDoc} */ public function supportsIdentityColumns() { return true; } /** * {@inheritDoc} */ public function supportsInlineColumnComments() { return true; } /** * {@inheritDoc} */ public function supportsViews() { return false; } /** * {@inheritdoc} */ public function supportsColumnCollation() { return true; } /** * {@inheritDoc} */ public function getDropIndexSQL($index, $table = null) { if ($index instanceof Index) { $indexName = $index->getQuotedName($this); } elseif (is_string($index)) { $indexName = $index; } else { throw new InvalidArgumentException('DrizzlePlatform::getDropIndexSQL() expects $index parameter to be string or \Doctrine\DBAL\Schema\Index.'); } if ($table instanceof Table) { $table = $table->getQuotedName($this); } elseif (! is_string($table)) { throw new InvalidArgumentException('DrizzlePlatform::getDropIndexSQL() expects $table parameter to be string or \Doctrine\DBAL\Schema\Table.'); } if ($index instanceof Index && $index->isPrimary()) { // drizzle primary keys are always named "PRIMARY", // so we cannot use them in statements because of them being keyword. return $this->getDropPrimaryKeySQL($table); } return 'DROP INDEX ' . $indexName . ' ON ' . $table; } /** * {@inheritDoc} */ protected function getDropPrimaryKeySQL($table) { return 'ALTER TABLE ' . $table . ' DROP PRIMARY KEY'; } /** * {@inheritDoc} */ public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) { if (isset($fieldDeclaration['version']) && $fieldDeclaration['version'] === true) { return 'TIMESTAMP'; } return 'DATETIME'; } /** * {@inheritDoc} */ public function getTimeTypeDeclarationSQL(array $fieldDeclaration) { return 'TIME'; } /** * {@inheritDoc} */ public function getDateTypeDeclarationSQL(array $fieldDeclaration) { return 'DATE'; } /** * {@inheritDoc} */ public function getAlterTableSQL(TableDiff $diff) { $columnSql = []; $queryParts = []; $newName = $diff->getNewName(); if ($newName !== false) { $queryParts[] = 'RENAME TO ' . $newName->getQuotedName($this); } foreach ($diff->addedColumns as $column) { if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) { continue; } $columnArray = $column->toArray(); $columnArray['comment'] = $this->getColumnComment($column); $queryParts[] = 'ADD ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray); } foreach ($diff->removedColumns as $column) { if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) { continue; } $queryParts[] = 'DROP ' . $column->getQuotedName($this); } foreach ($diff->changedColumns as $columnDiff) { if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) { continue; } $column = $columnDiff->column; $columnArray = $column->toArray(); // Do not generate column alteration clause if type is binary and only fixed property has changed. // Drizzle only supports binary type columns with variable length. // Avoids unnecessary table alteration statements. if ($columnArray['type'] instanceof BinaryType && $columnDiff->hasChanged('fixed') && count($columnDiff->changedProperties) === 1 ) { continue; } $columnArray['comment'] = $this->getColumnComment($column); $queryParts[] = 'CHANGE ' . ($columnDiff->getOldColumnName()->getQuotedName($this)) . ' ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray); } foreach ($diff->renamedColumns as $oldColumnName => $column) { if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) { continue; } $oldColumnName = new Identifier($oldColumnName); $columnArray = $column->toArray(); $columnArray['comment'] = $this->getColumnComment($column); $queryParts[] = 'CHANGE ' . $oldColumnName->getQuotedName($this) . ' ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray); } $sql = []; $tableSql = []; if (! $this->onSchemaAlterTable($diff, $tableSql)) { if (count($queryParts) > 0) { $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) . ' ' . implode(', ', $queryParts); } $sql = array_merge( $this->getPreAlterTableIndexForeignKeySQL($diff), $sql, $this->getPostAlterTableIndexForeignKeySQL($diff) ); } return array_merge($sql, $tableSql, $columnSql); } /** * {@inheritDoc} */ public function getDropTemporaryTableSQL($table) { if ($table instanceof Table) { $table = $table->getQuotedName($this); } elseif (! is_string($table)) { throw new InvalidArgumentException('getDropTableSQL() expects $table parameter to be string or \Doctrine\DBAL\Schema\Table.'); } return 'DROP TEMPORARY TABLE ' . $table; } /** * {@inheritDoc} */ public function convertBooleans($item) { if (is_array($item)) { foreach ($item as $key => $value) { if (! is_bool($value) && ! is_numeric($value)) { continue; } $item[$key] = $value ? 'true' : 'false'; } } elseif (is_bool($item) || is_numeric($item)) { $item = $item ? 'true' : 'false'; } return $item; } /** * {@inheritDoc} */ public function getLocateExpression($str, $substr, $startPos = false) { if ($startPos === false) { return 'LOCATE(' . $substr . ', ' . $str . ')'; } return 'LOCATE(' . $substr . ', ' . $str . ', ' . $startPos . ')'; } /** * {@inheritDoc} * * @deprecated Use application-generated UUIDs instead */ public function getGuidExpression() { return 'UUID()'; } /** * {@inheritDoc} */ public function getRegexpExpression() { return 'RLIKE'; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Platforms/Keywords/000077500000000000000000000000001360544566000236755ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Platforms/Keywords/DB2Keywords.php000066400000000000000000000222201360544566000265030ustar00rootroot00000000000000keywords === null) { $this->initializeKeywords(); } return isset($this->keywords[strtoupper($word)]); } /** * @return void */ protected function initializeKeywords() { $this->keywords = array_flip(array_map('strtoupper', $this->getKeywords())); } /** * Returns the list of keywords. * * @return string[] */ abstract protected function getKeywords(); /** * Returns the name of this keyword list. * * @return string */ abstract public function getName(); } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Platforms/Keywords/MariaDb102Keywords.php000066400000000000000000000140001360544566000276530ustar00rootroot00000000000000keywordLists = $keywordLists; } /** * @return string[] */ public function getViolations() { return $this->violations; } /** * @param string $word * * @return string[] */ private function isReservedWord($word) { if ($word[0] === '`') { $word = str_replace('`', '', $word); } $keywordLists = []; foreach ($this->keywordLists as $keywordList) { if (! $keywordList->isKeyword($word)) { continue; } $keywordLists[] = $keywordList->getName(); } return $keywordLists; } /** * @param string $asset * @param string[] $violatedPlatforms * * @return void */ private function addViolation($asset, $violatedPlatforms) { if (! $violatedPlatforms) { return; } $this->violations[] = $asset . ' keyword violations: ' . implode(', ', $violatedPlatforms); } /** * {@inheritdoc} */ public function acceptColumn(Table $table, Column $column) { $this->addViolation( 'Table ' . $table->getName() . ' column ' . $column->getName(), $this->isReservedWord($column->getName()) ); } /** * {@inheritdoc} */ public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint) { } /** * {@inheritdoc} */ public function acceptIndex(Table $table, Index $index) { } /** * {@inheritdoc} */ public function acceptSchema(Schema $schema) { } /** * {@inheritdoc} */ public function acceptSequence(Sequence $sequence) { } /** * {@inheritdoc} */ public function acceptTable(Table $table) { $this->addViolation( 'Table ' . $table->getName(), $this->isReservedWord($table->getName()) ); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Platforms/Keywords/SQLAnywhere11Keywords.php000066400000000000000000000013341360544566000304430ustar00rootroot00000000000000doctrineTypeMapping['json'] = Types::JSON; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Platforms/MySQL57Platform.php000066400000000000000000000026611360544566000254320ustar00rootroot00000000000000getQuotedName($this)]; } /** * {@inheritdoc} */ protected function getReservedKeywordsClass() { return Keywords\MySQL57Keywords::class; } /** * {@inheritdoc} */ protected function initializeDoctrineTypeMappings() { parent::initializeDoctrineTypeMappings(); $this->doctrineTypeMapping['json'] = Types::JSON; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Platforms/MySQL80Platform.php000066400000000000000000000005301360544566000254170ustar00rootroot00000000000000 0) { $query .= ' OFFSET ' . $offset; } } elseif ($offset > 0) { // 2^64-1 is the maximum of unsigned BIGINT, the biggest limit possible $query .= ' LIMIT 18446744073709551615 OFFSET ' . $offset; } return $query; } /** * {@inheritDoc} */ public function getIdentifierQuoteCharacter() { return '`'; } /** * {@inheritDoc} */ public function getRegexpExpression() { return 'RLIKE'; } /** * {@inheritDoc} * * @deprecated Use application-generated UUIDs instead */ public function getGuidExpression() { return 'UUID()'; } /** * {@inheritDoc} */ public function getLocateExpression($str, $substr, $startPos = false) { if ($startPos === false) { return 'LOCATE(' . $substr . ', ' . $str . ')'; } return 'LOCATE(' . $substr . ', ' . $str . ', ' . $startPos . ')'; } /** * {@inheritDoc} */ public function getConcatExpression() { return sprintf('CONCAT(%s)', implode(', ', func_get_args())); } /** * {@inheritdoc} */ protected function getDateArithmeticIntervalExpression($date, $operator, $interval, $unit) { $function = $operator === '+' ? 'DATE_ADD' : 'DATE_SUB'; return $function . '(' . $date . ', INTERVAL ' . $interval . ' ' . $unit . ')'; } /** * {@inheritDoc} */ public function getDateDiffExpression($date1, $date2) { return 'DATEDIFF(' . $date1 . ', ' . $date2 . ')'; } /** * {@inheritDoc} */ public function getListDatabasesSQL() { return 'SHOW DATABASES'; } /** * {@inheritDoc} */ public function getListTableConstraintsSQL($table) { return 'SHOW INDEX FROM ' . $table; } /** * {@inheritDoc} * * Two approaches to listing the table indexes. The information_schema is * preferred, because it doesn't cause problems with SQL keywords such as "order" or "table". */ public function getListTableIndexesSQL($table, $currentDatabase = null) { if ($currentDatabase) { $currentDatabase = $this->quoteStringLiteral($currentDatabase); $table = $this->quoteStringLiteral($table); return 'SELECT NON_UNIQUE AS Non_Unique, INDEX_NAME AS Key_name, COLUMN_NAME AS Column_Name,' . ' SUB_PART AS Sub_Part, INDEX_TYPE AS Index_Type' . ' FROM information_schema.STATISTICS WHERE TABLE_NAME = ' . $table . ' AND TABLE_SCHEMA = ' . $currentDatabase . ' ORDER BY SEQ_IN_INDEX ASC'; } return 'SHOW INDEX FROM ' . $table; } /** * {@inheritDoc} */ public function getListViewsSQL($database) { $database = $this->quoteStringLiteral($database); return 'SELECT * FROM information_schema.VIEWS WHERE TABLE_SCHEMA = ' . $database; } /** * {@inheritDoc} */ public function getListTableForeignKeysSQL($table, $database = null) { $table = $this->quoteStringLiteral($table); if ($database !== null) { $database = $this->quoteStringLiteral($database); } $sql = 'SELECT DISTINCT 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 = ' . $table . ' */ WHERE k.table_name = ' . $table; $databaseNameSql = $database ?? 'DATABASE()'; $sql .= ' AND k.table_schema = ' . $databaseNameSql . ' /*!50116 AND c.constraint_schema = ' . $databaseNameSql . ' */'; $sql .= ' AND k.`REFERENCED_COLUMN_NAME` is not NULL'; return $sql; } /** * {@inheritDoc} */ public function getCreateViewSQL($name, $sql) { return 'CREATE VIEW ' . $name . ' AS ' . $sql; } /** * {@inheritDoc} */ public function getDropViewSQL($name) { return 'DROP VIEW ' . $name; } /** * {@inheritDoc} */ protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) { return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)') : ($length ? 'VARCHAR(' . $length . ')' : 'VARCHAR(255)'); } /** * {@inheritdoc} */ protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed) { return $fixed ? 'BINARY(' . ($length ?: 255) . ')' : 'VARBINARY(' . ($length ?: 255) . ')'; } /** * Gets the SQL snippet used to declare a CLOB column type. * TINYTEXT : 2 ^ 8 - 1 = 255 * TEXT : 2 ^ 16 - 1 = 65535 * MEDIUMTEXT : 2 ^ 24 - 1 = 16777215 * LONGTEXT : 2 ^ 32 - 1 = 4294967295 * * {@inheritDoc} */ public function getClobTypeDeclarationSQL(array $field) { if (! empty($field['length']) && is_numeric($field['length'])) { $length = $field['length']; if ($length <= static::LENGTH_LIMIT_TINYTEXT) { return 'TINYTEXT'; } if ($length <= static::LENGTH_LIMIT_TEXT) { return 'TEXT'; } if ($length <= static::LENGTH_LIMIT_MEDIUMTEXT) { return 'MEDIUMTEXT'; } } return 'LONGTEXT'; } /** * {@inheritDoc} */ public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) { if (isset($fieldDeclaration['version']) && $fieldDeclaration['version'] === true) { return 'TIMESTAMP'; } return 'DATETIME'; } /** * {@inheritDoc} */ public function getDateTypeDeclarationSQL(array $fieldDeclaration) { return 'DATE'; } /** * {@inheritDoc} */ public function getTimeTypeDeclarationSQL(array $fieldDeclaration) { return 'TIME'; } /** * {@inheritDoc} */ public function getBooleanTypeDeclarationSQL(array $field) { return 'TINYINT(1)'; } /** * Obtain DBMS specific SQL code portion needed to set the COLLATION * of a field declaration to be used in statements like CREATE TABLE. * * @deprecated Deprecated since version 2.5, Use {@link self::getColumnCollationDeclarationSQL()} instead. * * @param string $collation name of the collation * * @return string DBMS specific SQL code portion needed to set the COLLATION * of a field declaration. */ public function getCollationFieldDeclaration($collation) { return $this->getColumnCollationDeclarationSQL($collation); } /** * {@inheritDoc} * * MySql prefers "autoincrement" identity columns since sequences can only * be emulated with a table. */ public function prefersIdentityColumns() { return true; } /** * {@inheritDoc} * * MySql supports this through AUTO_INCREMENT columns. */ public function supportsIdentityColumns() { return true; } /** * {@inheritDoc} */ public function supportsInlineColumnComments() { return true; } /** * {@inheritDoc} */ public function supportsColumnCollation() { return true; } /** * {@inheritDoc} */ public function getListTablesSQL() { return "SHOW FULL TABLES WHERE Table_type = 'BASE TABLE'"; } /** * {@inheritDoc} */ public function getListTableColumnsSQL($table, $database = null) { $table = $this->quoteStringLiteral($table); if ($database) { $database = $this->quoteStringLiteral($database); } else { $database = 'DATABASE()'; } return 'SELECT COLUMN_NAME AS Field, COLUMN_TYPE AS Type, IS_NULLABLE AS `Null`, ' . 'COLUMN_KEY AS `Key`, COLUMN_DEFAULT AS `Default`, EXTRA AS Extra, COLUMN_COMMENT AS Comment, ' . 'CHARACTER_SET_NAME AS CharacterSet, COLLATION_NAME AS Collation ' . 'FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ' . $database . ' AND TABLE_NAME = ' . $table . ' ORDER BY ORDINAL_POSITION ASC'; } public function getListTableMetadataSQL(string $table, ?string $database = null) : string { return sprintf( <<<'SQL' SELECT ENGINE, AUTO_INCREMENT, TABLE_COLLATION, TABLE_COMMENT, CREATE_OPTIONS FROM information_schema.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_SCHEMA = %s AND TABLE_NAME = %s SQL , $database ? $this->quoteStringLiteral($database) : 'DATABASE()', $this->quoteStringLiteral($table) ); } /** * {@inheritDoc} */ public function getCreateDatabaseSQL($name) { return 'CREATE DATABASE ' . $name; } /** * {@inheritDoc} */ public function getDropDatabaseSQL($name) { return 'DROP DATABASE ' . $name; } /** * {@inheritDoc} */ protected function _getCreateTableSQL($tableName, array $columns, array $options = []) { $queryFields = $this->getColumnDeclarationListSQL($columns); if (isset($options['uniqueConstraints']) && ! empty($options['uniqueConstraints'])) { foreach ($options['uniqueConstraints'] as $index => $definition) { $queryFields .= ', ' . $this->getUniqueConstraintDeclarationSQL($index, $definition); } } // add all indexes if (isset($options['indexes']) && ! empty($options['indexes'])) { foreach ($options['indexes'] as $index => $definition) { $queryFields .= ', ' . $this->getIndexDeclarationSQL($index, $definition); } } // attach all primary keys if (isset($options['primary']) && ! empty($options['primary'])) { $keyColumns = array_unique(array_values($options['primary'])); $queryFields .= ', PRIMARY KEY(' . implode(', ', $keyColumns) . ')'; } $query = 'CREATE '; if (! empty($options['temporary'])) { $query .= 'TEMPORARY '; } $query .= 'TABLE ' . $tableName . ' (' . $queryFields . ') '; $query .= $this->buildTableOptions($options); $query .= $this->buildPartitionOptions($options); $sql = [$query]; $engine = 'INNODB'; if (isset($options['engine'])) { $engine = strtoupper(trim($options['engine'])); } // Propagate foreign key constraints only for InnoDB. if (isset($options['foreignKeys']) && $engine === 'INNODB') { foreach ((array) $options['foreignKeys'] as $definition) { $sql[] = $this->getCreateForeignKeySQL($definition, $tableName); } } return $sql; } /** * {@inheritdoc} */ public function getDefaultValueDeclarationSQL($field) { // Unset the default value if the given field definition does not allow default values. if ($field['type'] instanceof TextType || $field['type'] instanceof BlobType) { $field['default'] = null; } return parent::getDefaultValueDeclarationSQL($field); } /** * Build SQL for table options * * @param mixed[] $options * * @return string */ private function buildTableOptions(array $options) { if (isset($options['table_options'])) { return $options['table_options']; } $tableOptions = []; // Charset if (! isset($options['charset'])) { $options['charset'] = 'utf8'; } $tableOptions[] = sprintf('DEFAULT CHARACTER SET %s', $options['charset']); // Collate if (! isset($options['collate'])) { $options['collate'] = $options['charset'] . '_unicode_ci'; } $tableOptions[] = $this->getColumnCollationDeclarationSQL($options['collate']); // Engine if (! isset($options['engine'])) { $options['engine'] = 'InnoDB'; } $tableOptions[] = sprintf('ENGINE = %s', $options['engine']); // Auto increment if (isset($options['auto_increment'])) { $tableOptions[] = sprintf('AUTO_INCREMENT = %s', $options['auto_increment']); } // Comment if (isset($options['comment'])) { $tableOptions[] = sprintf('COMMENT = %s ', $this->quoteStringLiteral($options['comment'])); } // Row format if (isset($options['row_format'])) { $tableOptions[] = sprintf('ROW_FORMAT = %s', $options['row_format']); } return implode(' ', $tableOptions); } /** * Build SQL for partition options. * * @param mixed[] $options * * @return string */ private function buildPartitionOptions(array $options) { return isset($options['partition_options']) ? ' ' . $options['partition_options'] : ''; } /** * {@inheritDoc} */ public function getAlterTableSQL(TableDiff $diff) { $columnSql = []; $queryParts = []; $newName = $diff->getNewName(); if ($newName !== false) { $queryParts[] = 'RENAME TO ' . $newName->getQuotedName($this); } foreach ($diff->addedColumns as $column) { if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) { continue; } $columnArray = $column->toArray(); $columnArray['comment'] = $this->getColumnComment($column); $queryParts[] = 'ADD ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray); } foreach ($diff->removedColumns as $column) { if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) { continue; } $queryParts[] = 'DROP ' . $column->getQuotedName($this); } foreach ($diff->changedColumns as $columnDiff) { if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) { continue; } $column = $columnDiff->column; $columnArray = $column->toArray(); // Don't propagate default value changes for unsupported column types. if ($columnDiff->hasChanged('default') && count($columnDiff->changedProperties) === 1 && ($columnArray['type'] instanceof TextType || $columnArray['type'] instanceof BlobType) ) { continue; } $columnArray['comment'] = $this->getColumnComment($column); $queryParts[] = 'CHANGE ' . ($columnDiff->getOldColumnName()->getQuotedName($this)) . ' ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray); } foreach ($diff->renamedColumns as $oldColumnName => $column) { if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) { continue; } $oldColumnName = new Identifier($oldColumnName); $columnArray = $column->toArray(); $columnArray['comment'] = $this->getColumnComment($column); $queryParts[] = 'CHANGE ' . $oldColumnName->getQuotedName($this) . ' ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnArray); } if (isset($diff->addedIndexes['primary'])) { $keyColumns = array_unique(array_values($diff->addedIndexes['primary']->getColumns())); $queryParts[] = 'ADD PRIMARY KEY (' . implode(', ', $keyColumns) . ')'; unset($diff->addedIndexes['primary']); } elseif (isset($diff->changedIndexes['primary'])) { // Necessary in case the new primary key includes a new auto_increment column foreach ($diff->changedIndexes['primary']->getColumns() as $columnName) { if (isset($diff->addedColumns[$columnName]) && $diff->addedColumns[$columnName]->getAutoincrement()) { $keyColumns = array_unique(array_values($diff->changedIndexes['primary']->getColumns())); $queryParts[] = 'DROP PRIMARY KEY'; $queryParts[] = 'ADD PRIMARY KEY (' . implode(', ', $keyColumns) . ')'; unset($diff->changedIndexes['primary']); break; } } } $sql = []; $tableSql = []; if (! $this->onSchemaAlterTable($diff, $tableSql)) { if (count($queryParts) > 0) { $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) . ' ' . implode(', ', $queryParts); } $sql = array_merge( $this->getPreAlterTableIndexForeignKeySQL($diff), $sql, $this->getPostAlterTableIndexForeignKeySQL($diff) ); } return array_merge($sql, $tableSql, $columnSql); } /** * {@inheritDoc} */ protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff) { $sql = []; $table = $diff->getName($this)->getQuotedName($this); foreach ($diff->changedIndexes as $changedIndex) { $sql = array_merge($sql, $this->getPreAlterTableAlterPrimaryKeySQL($diff, $changedIndex)); } foreach ($diff->removedIndexes as $remKey => $remIndex) { $sql = array_merge($sql, $this->getPreAlterTableAlterPrimaryKeySQL($diff, $remIndex)); foreach ($diff->addedIndexes as $addKey => $addIndex) { if ($remIndex->getColumns() === $addIndex->getColumns()) { $indexClause = 'INDEX ' . $addIndex->getName(); if ($addIndex->isPrimary()) { $indexClause = 'PRIMARY KEY'; } elseif ($addIndex->isUnique()) { $indexClause = 'UNIQUE INDEX ' . $addIndex->getName(); } $query = 'ALTER TABLE ' . $table . ' DROP INDEX ' . $remIndex->getName() . ', '; $query .= 'ADD ' . $indexClause; $query .= ' (' . $this->getIndexFieldDeclarationListSQL($addIndex) . ')'; $sql[] = $query; unset($diff->removedIndexes[$remKey], $diff->addedIndexes[$addKey]); break; } } } $engine = 'INNODB'; if ($diff->fromTable instanceof Table && $diff->fromTable->hasOption('engine')) { $engine = strtoupper(trim($diff->fromTable->getOption('engine'))); } // Suppress foreign key constraint propagation on non-supporting engines. if ($engine !== 'INNODB') { $diff->addedForeignKeys = []; $diff->changedForeignKeys = []; $diff->removedForeignKeys = []; } $sql = array_merge( $sql, $this->getPreAlterTableAlterIndexForeignKeySQL($diff), parent::getPreAlterTableIndexForeignKeySQL($diff), $this->getPreAlterTableRenameIndexForeignKeySQL($diff) ); return $sql; } /** * @return string[] */ private function getPreAlterTableAlterPrimaryKeySQL(TableDiff $diff, Index $index) { $sql = []; if (! $index->isPrimary() || ! $diff->fromTable instanceof Table) { return $sql; } $tableName = $diff->getName($this)->getQuotedName($this); // Dropping primary keys requires to unset autoincrement attribute on the particular column first. foreach ($index->getColumns() as $columnName) { if (! $diff->fromTable->hasColumn($columnName)) { continue; } $column = $diff->fromTable->getColumn($columnName); if ($column->getAutoincrement() !== true) { continue; } $column->setAutoincrement(false); $sql[] = 'ALTER TABLE ' . $tableName . ' MODIFY ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $column->toArray()); // original autoincrement information might be needed later on by other parts of the table alteration $column->setAutoincrement(true); } return $sql; } /** * @param TableDiff $diff The table diff to gather the SQL for. * * @return string[] */ private function getPreAlterTableAlterIndexForeignKeySQL(TableDiff $diff) { $sql = []; $table = $diff->getName($this)->getQuotedName($this); foreach ($diff->changedIndexes as $changedIndex) { // Changed primary key if (! $changedIndex->isPrimary() || ! ($diff->fromTable instanceof Table)) { continue; } foreach ($diff->fromTable->getPrimaryKeyColumns() as $columnName) { $column = $diff->fromTable->getColumn($columnName); // Check if an autoincrement column was dropped from the primary key. if (! $column->getAutoincrement() || in_array($columnName, $changedIndex->getColumns())) { continue; } // The autoincrement attribute needs to be removed from the dropped column // before we can drop and recreate the primary key. $column->setAutoincrement(false); $sql[] = 'ALTER TABLE ' . $table . ' MODIFY ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $column->toArray()); // Restore the autoincrement attribute as it might be needed later on // by other parts of the table alteration. $column->setAutoincrement(true); } } return $sql; } /** * @param TableDiff $diff The table diff to gather the SQL for. * * @return string[] */ protected function getPreAlterTableRenameIndexForeignKeySQL(TableDiff $diff) { $sql = []; $tableName = $diff->getName($this)->getQuotedName($this); foreach ($this->getRemainingForeignKeyConstraintsRequiringRenamedIndexes($diff) as $foreignKey) { if (in_array($foreignKey, $diff->changedForeignKeys, true)) { continue; } $sql[] = $this->getDropForeignKeySQL($foreignKey, $tableName); } return $sql; } /** * Returns the remaining foreign key constraints that require one of the renamed indexes. * * "Remaining" here refers to the diff between the foreign keys currently defined in the associated * table and the foreign keys to be removed. * * @param TableDiff $diff The table diff to evaluate. * * @return ForeignKeyConstraint[] */ private function getRemainingForeignKeyConstraintsRequiringRenamedIndexes(TableDiff $diff) { if (empty($diff->renamedIndexes) || ! $diff->fromTable instanceof Table) { return []; } $foreignKeys = []; /** @var ForeignKeyConstraint[] $remainingForeignKeys */ $remainingForeignKeys = array_diff_key( $diff->fromTable->getForeignKeys(), $diff->removedForeignKeys ); foreach ($remainingForeignKeys as $foreignKey) { foreach ($diff->renamedIndexes as $index) { if ($foreignKey->intersectsIndexColumns($index)) { $foreignKeys[] = $foreignKey; break; } } } return $foreignKeys; } /** * {@inheritdoc} */ protected function getPostAlterTableIndexForeignKeySQL(TableDiff $diff) { return array_merge( parent::getPostAlterTableIndexForeignKeySQL($diff), $this->getPostAlterTableRenameIndexForeignKeySQL($diff) ); } /** * @param TableDiff $diff The table diff to gather the SQL for. * * @return string[] */ protected function getPostAlterTableRenameIndexForeignKeySQL(TableDiff $diff) { $sql = []; $newName = $diff->getNewName(); if ($newName !== false) { $tableName = $newName->getQuotedName($this); } else { $tableName = $diff->getName($this)->getQuotedName($this); } foreach ($this->getRemainingForeignKeyConstraintsRequiringRenamedIndexes($diff) as $foreignKey) { if (in_array($foreignKey, $diff->changedForeignKeys, true)) { continue; } $sql[] = $this->getCreateForeignKeySQL($foreignKey, $tableName); } return $sql; } /** * {@inheritDoc} */ protected function getCreateIndexSQLFlags(Index $index) { $type = ''; if ($index->isUnique()) { $type .= 'UNIQUE '; } elseif ($index->hasFlag('fulltext')) { $type .= 'FULLTEXT '; } elseif ($index->hasFlag('spatial')) { $type .= 'SPATIAL '; } return $type; } /** * {@inheritDoc} */ public function getIntegerTypeDeclarationSQL(array $field) { return 'INT' . $this->_getCommonIntegerTypeDeclarationSQL($field); } /** * {@inheritDoc} */ public function getBigIntTypeDeclarationSQL(array $field) { return 'BIGINT' . $this->_getCommonIntegerTypeDeclarationSQL($field); } /** * {@inheritDoc} */ public function getSmallIntTypeDeclarationSQL(array $field) { return 'SMALLINT' . $this->_getCommonIntegerTypeDeclarationSQL($field); } /** * {@inheritdoc} */ public function getFloatDeclarationSQL(array $field) { return 'DOUBLE PRECISION' . $this->getUnsignedDeclaration($field); } /** * {@inheritdoc} */ public function getDecimalTypeDeclarationSQL(array $columnDef) { return parent::getDecimalTypeDeclarationSQL($columnDef) . $this->getUnsignedDeclaration($columnDef); } /** * Get unsigned declaration for a column. * * @param mixed[] $columnDef * * @return string */ private function getUnsignedDeclaration(array $columnDef) { return ! empty($columnDef['unsigned']) ? ' UNSIGNED' : ''; } /** * {@inheritDoc} */ protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) { $autoinc = ''; if (! empty($columnDef['autoincrement'])) { $autoinc = ' AUTO_INCREMENT'; } return $this->getUnsignedDeclaration($columnDef) . $autoinc; } /** * {@inheritDoc} */ public function getColumnCharsetDeclarationSQL($charset) { return 'CHARACTER SET ' . $charset; } /** * {@inheritDoc} */ public function getColumnCollationDeclarationSQL($collation) { return 'COLLATE ' . $this->quoteSingleIdentifier($collation); } /** * {@inheritDoc} */ public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey) { $query = ''; if ($foreignKey->hasOption('match')) { $query .= ' MATCH ' . $foreignKey->getOption('match'); } $query .= parent::getAdvancedForeignKeyOptionsSQL($foreignKey); return $query; } /** * {@inheritDoc} */ public function getDropIndexSQL($index, $table = null) { if ($index instanceof Index) { $indexName = $index->getQuotedName($this); } elseif (is_string($index)) { $indexName = $index; } else { throw new InvalidArgumentException('MysqlPlatform::getDropIndexSQL() expects $index parameter to be string or \Doctrine\DBAL\Schema\Index.'); } if ($table instanceof Table) { $table = $table->getQuotedName($this); } elseif (! is_string($table)) { throw new InvalidArgumentException('MysqlPlatform::getDropIndexSQL() expects $table parameter to be string or \Doctrine\DBAL\Schema\Table.'); } if ($index instanceof Index && $index->isPrimary()) { // mysql primary keys are always named "PRIMARY", // so we cannot use them in statements because of them being keyword. return $this->getDropPrimaryKeySQL($table); } return 'DROP INDEX ' . $indexName . ' ON ' . $table; } /** * @param string $table * * @return string */ protected function getDropPrimaryKeySQL($table) { return 'ALTER TABLE ' . $table . ' DROP PRIMARY KEY'; } /** * {@inheritDoc} */ public function getSetTransactionIsolationSQL($level) { return 'SET SESSION TRANSACTION ISOLATION LEVEL ' . $this->_getTransactionIsolationLevelSQL($level); } /** * {@inheritDoc} */ public function getName() { return 'mysql'; } /** * {@inheritDoc} */ public function getReadLockSQL() { return 'LOCK IN SHARE MODE'; } /** * {@inheritDoc} */ protected function initializeDoctrineTypeMappings() { $this->doctrineTypeMapping = [ 'tinyint' => 'boolean', 'smallint' => 'smallint', 'mediumint' => 'integer', 'int' => 'integer', 'integer' => 'integer', 'bigint' => 'bigint', 'tinytext' => 'text', 'mediumtext' => 'text', 'longtext' => 'text', 'text' => 'text', 'varchar' => 'string', 'string' => 'string', 'char' => 'string', 'date' => 'date', 'datetime' => 'datetime', 'timestamp' => 'datetime', 'time' => 'time', 'float' => 'float', 'double' => 'float', 'real' => 'float', 'decimal' => 'decimal', 'numeric' => 'decimal', 'year' => 'date', 'longblob' => 'blob', 'blob' => 'blob', 'mediumblob' => 'blob', 'tinyblob' => 'blob', 'binary' => 'binary', 'varbinary' => 'binary', 'set' => 'simple_array', ]; } /** * {@inheritDoc} */ public function getVarcharMaxLength() { return 65535; } /** * {@inheritdoc} */ public function getBinaryMaxLength() { return 65535; } /** * {@inheritDoc} */ protected function getReservedKeywordsClass() { return Keywords\MySQLKeywords::class; } /** * {@inheritDoc} * * MySQL commits a transaction implicitly when DROP TABLE is executed, however not * if DROP TEMPORARY TABLE is executed. */ public function getDropTemporaryTableSQL($table) { if ($table instanceof Table) { $table = $table->getQuotedName($this); } elseif (! is_string($table)) { throw new InvalidArgumentException('getDropTemporaryTableSQL() expects $table parameter to be string or \Doctrine\DBAL\Schema\Table.'); } return 'DROP TEMPORARY TABLE ' . $table; } /** * Gets the SQL Snippet used to declare a BLOB column type. * TINYBLOB : 2 ^ 8 - 1 = 255 * BLOB : 2 ^ 16 - 1 = 65535 * MEDIUMBLOB : 2 ^ 24 - 1 = 16777215 * LONGBLOB : 2 ^ 32 - 1 = 4294967295 * * {@inheritDoc} */ public function getBlobTypeDeclarationSQL(array $field) { if (! empty($field['length']) && is_numeric($field['length'])) { $length = $field['length']; if ($length <= static::LENGTH_LIMIT_TINYBLOB) { return 'TINYBLOB'; } if ($length <= static::LENGTH_LIMIT_BLOB) { return 'BLOB'; } if ($length <= static::LENGTH_LIMIT_MEDIUMBLOB) { return 'MEDIUMBLOB'; } } return 'LONGBLOB'; } /** * {@inheritdoc} */ public function quoteStringLiteral($str) { $str = str_replace('\\', '\\\\', $str); // MySQL requires backslashes to be escaped aswell. return parent::quoteStringLiteral($str); } /** * {@inheritdoc} */ public function getDefaultTransactionIsolationLevel() { return TransactionIsolationLevel::REPEATABLE_READ; } /** * {@inheritdoc} */ public function supportsColumnLengthIndexes() : bool { return true; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Platforms/OraclePlatform.php000066400000000000000000001022701360544566000255130ustar00rootroot00000000000000getBitAndComparisonExpression($value1, $value2) . '+' . $value2 . ')'; } /** * {@inheritDoc} * * Need to specifiy minvalue, since start with is hidden in the system and MINVALUE <= START WITH. * Therefore we can use MINVALUE to be able to get a hint what START WITH was for later introspection * in {@see listSequences()} */ public function getCreateSequenceSQL(Sequence $sequence) { return 'CREATE SEQUENCE ' . $sequence->getQuotedName($this) . ' START WITH ' . $sequence->getInitialValue() . ' MINVALUE ' . $sequence->getInitialValue() . ' INCREMENT BY ' . $sequence->getAllocationSize() . $this->getSequenceCacheSQL($sequence); } /** * {@inheritDoc} */ public function getAlterSequenceSQL(Sequence $sequence) { return 'ALTER SEQUENCE ' . $sequence->getQuotedName($this) . ' INCREMENT BY ' . $sequence->getAllocationSize() . $this->getSequenceCacheSQL($sequence); } /** * Cache definition for sequences * * @return string */ private function getSequenceCacheSQL(Sequence $sequence) { if ($sequence->getCache() === 0) { return ' NOCACHE'; } if ($sequence->getCache() === 1) { return ' NOCACHE'; } if ($sequence->getCache() > 1) { return ' CACHE ' . $sequence->getCache(); } return ''; } /** * {@inheritDoc} */ public function getSequenceNextValSQL($sequenceName) { return 'SELECT ' . $sequenceName . '.nextval FROM DUAL'; } /** * {@inheritDoc} */ public function getSetTransactionIsolationSQL($level) { return 'SET TRANSACTION ISOLATION LEVEL ' . $this->_getTransactionIsolationLevelSQL($level); } /** * {@inheritDoc} */ protected function _getTransactionIsolationLevelSQL($level) { switch ($level) { case TransactionIsolationLevel::READ_UNCOMMITTED: return 'READ UNCOMMITTED'; case TransactionIsolationLevel::READ_COMMITTED: return 'READ COMMITTED'; case TransactionIsolationLevel::REPEATABLE_READ: case TransactionIsolationLevel::SERIALIZABLE: return 'SERIALIZABLE'; default: return parent::_getTransactionIsolationLevelSQL($level); } } /** * {@inheritDoc} */ public function getBooleanTypeDeclarationSQL(array $field) { return 'NUMBER(1)'; } /** * {@inheritDoc} */ public function getIntegerTypeDeclarationSQL(array $field) { return 'NUMBER(10)'; } /** * {@inheritDoc} */ public function getBigIntTypeDeclarationSQL(array $field) { return 'NUMBER(20)'; } /** * {@inheritDoc} */ public function getSmallIntTypeDeclarationSQL(array $field) { return 'NUMBER(5)'; } /** * {@inheritDoc} */ public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) { return 'TIMESTAMP(0)'; } /** * {@inheritDoc} */ public function getDateTimeTzTypeDeclarationSQL(array $fieldDeclaration) { return 'TIMESTAMP(0) WITH TIME ZONE'; } /** * {@inheritDoc} */ public function getDateTypeDeclarationSQL(array $fieldDeclaration) { return 'DATE'; } /** * {@inheritDoc} */ public function getTimeTypeDeclarationSQL(array $fieldDeclaration) { return 'DATE'; } /** * {@inheritDoc} */ protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) { return ''; } /** * {@inheritDoc} */ protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) { return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(2000)') : ($length ? 'VARCHAR2(' . $length . ')' : 'VARCHAR2(4000)'); } /** * {@inheritdoc} */ protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed) { return 'RAW(' . ($length ?: $this->getBinaryMaxLength()) . ')'; } /** * {@inheritdoc} */ public function getBinaryMaxLength() { return 2000; } /** * {@inheritDoc} */ public function getClobTypeDeclarationSQL(array $field) { return 'CLOB'; } /** * {@inheritDoc} */ public function getListDatabasesSQL() { return 'SELECT username FROM all_users'; } /** * {@inheritDoc} */ public function getListSequencesSQL($database) { $database = $this->normalizeIdentifier($database); $database = $this->quoteStringLiteral($database->getName()); return 'SELECT sequence_name, min_value, increment_by FROM sys.all_sequences ' . 'WHERE SEQUENCE_OWNER = ' . $database; } /** * {@inheritDoc} */ protected function _getCreateTableSQL($table, array $columns, array $options = []) { $indexes = $options['indexes'] ?? []; $options['indexes'] = []; $sql = parent::_getCreateTableSQL($table, $columns, $options); foreach ($columns as $name => $column) { if (isset($column['sequence'])) { $sql[] = $this->getCreateSequenceSQL($column['sequence']); } if (! isset($column['autoincrement']) || ! $column['autoincrement'] && (! isset($column['autoinc']) || ! $column['autoinc'])) { continue; } $sql = array_merge($sql, $this->getCreateAutoincrementSql($name, $table)); } if (isset($indexes) && ! empty($indexes)) { foreach ($indexes as $index) { $sql[] = $this->getCreateIndexSQL($index, $table); } } return $sql; } /** * {@inheritDoc} * * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaOracleReader.html */ public function getListTableIndexesSQL($table, $currentDatabase = null) { $table = $this->normalizeIdentifier($table); $table = $this->quoteStringLiteral($table->getName()); return "SELECT uind_col.index_name AS name, ( SELECT uind.index_type FROM user_indexes uind WHERE uind.index_name = uind_col.index_name ) AS type, decode( ( SELECT uind.uniqueness FROM user_indexes uind WHERE uind.index_name = uind_col.index_name ), 'NONUNIQUE', 0, 'UNIQUE', 1 ) AS is_unique, uind_col.column_name AS column_name, uind_col.column_position AS column_pos, ( SELECT ucon.constraint_type FROM user_constraints ucon WHERE ucon.index_name = uind_col.index_name ) AS is_primary FROM user_ind_columns uind_col WHERE uind_col.table_name = " . $table . ' ORDER BY uind_col.column_position ASC'; } /** * {@inheritDoc} */ public function getListTablesSQL() { return 'SELECT * FROM sys.user_tables'; } /** * {@inheritDoc} */ public function getListViewsSQL($database) { return 'SELECT view_name, text FROM sys.user_views'; } /** * {@inheritDoc} */ public function getCreateViewSQL($name, $sql) { return 'CREATE VIEW ' . $name . ' AS ' . $sql; } /** * {@inheritDoc} */ public function getDropViewSQL($name) { return 'DROP VIEW ' . $name; } /** * @param string $name * @param string $table * @param int $start * * @return string[] */ public function getCreateAutoincrementSql($name, $table, $start = 1) { $tableIdentifier = $this->normalizeIdentifier($table); $quotedTableName = $tableIdentifier->getQuotedName($this); $unquotedTableName = $tableIdentifier->getName(); $nameIdentifier = $this->normalizeIdentifier($name); $quotedName = $nameIdentifier->getQuotedName($this); $unquotedName = $nameIdentifier->getName(); $sql = []; $autoincrementIdentifierName = $this->getAutoincrementIdentifierName($tableIdentifier); $idx = new Index($autoincrementIdentifierName, [$quotedName], true, true); $sql[] = 'DECLARE constraints_Count NUMBER; BEGIN SELECT COUNT(CONSTRAINT_NAME) INTO constraints_Count FROM USER_CONSTRAINTS WHERE TABLE_NAME = \'' . $unquotedTableName . '\' AND CONSTRAINT_TYPE = \'P\'; IF constraints_Count = 0 OR constraints_Count = \'\' THEN EXECUTE IMMEDIATE \'' . $this->getCreateConstraintSQL($idx, $quotedTableName) . '\'; END IF; END;'; $sequenceName = $this->getIdentitySequenceName( $tableIdentifier->isQuoted() ? $quotedTableName : $unquotedTableName, $nameIdentifier->isQuoted() ? $quotedName : $unquotedName ); $sequence = new Sequence($sequenceName, $start); $sql[] = $this->getCreateSequenceSQL($sequence); $sql[] = 'CREATE TRIGGER ' . $autoincrementIdentifierName . ' BEFORE INSERT ON ' . $quotedTableName . ' FOR EACH ROW DECLARE last_Sequence NUMBER; last_InsertID NUMBER; BEGIN SELECT ' . $sequenceName . '.NEXTVAL INTO :NEW.' . $quotedName . ' FROM DUAL; IF (:NEW.' . $quotedName . ' IS NULL OR :NEW.' . $quotedName . ' = 0) THEN SELECT ' . $sequenceName . '.NEXTVAL INTO :NEW.' . $quotedName . ' FROM DUAL; ELSE SELECT NVL(Last_Number, 0) INTO last_Sequence FROM User_Sequences WHERE Sequence_Name = \'' . $sequence->getName() . '\'; SELECT :NEW.' . $quotedName . ' INTO last_InsertID FROM DUAL; WHILE (last_InsertID > last_Sequence) LOOP SELECT ' . $sequenceName . '.NEXTVAL INTO last_Sequence FROM DUAL; END LOOP; END IF; END;'; return $sql; } /** * Returns the SQL statements to drop the autoincrement for the given table name. * * @param string $table The table name to drop the autoincrement for. * * @return string[] */ public function getDropAutoincrementSql($table) { $table = $this->normalizeIdentifier($table); $autoincrementIdentifierName = $this->getAutoincrementIdentifierName($table); $identitySequenceName = $this->getIdentitySequenceName( $table->isQuoted() ? $table->getQuotedName($this) : $table->getName(), '' ); return [ 'DROP TRIGGER ' . $autoincrementIdentifierName, $this->getDropSequenceSQL($identitySequenceName), $this->getDropConstraintSQL($autoincrementIdentifierName, $table->getQuotedName($this)), ]; } /** * Normalizes the given identifier. * * Uppercases the given identifier if it is not quoted by intention * to reflect Oracle's internal auto uppercasing strategy of unquoted identifiers. * * @param string $name The identifier to normalize. * * @return Identifier The normalized identifier. */ private function normalizeIdentifier($name) { $identifier = new Identifier($name); return $identifier->isQuoted() ? $identifier : new Identifier(strtoupper($name)); } /** * Returns the autoincrement primary key identifier name for the given table identifier. * * Quotes the autoincrement primary key identifier name * if the given table name is quoted by intention. * * @param Identifier $table The table identifier to return the autoincrement primary key identifier name for. * * @return string */ private function getAutoincrementIdentifierName(Identifier $table) { $identifierName = $table->getName() . '_AI_PK'; return $table->isQuoted() ? $this->quoteSingleIdentifier($identifierName) : $identifierName; } /** * {@inheritDoc} */ public function getListTableForeignKeysSQL($table) { $table = $this->normalizeIdentifier($table); $table = $this->quoteStringLiteral($table->getName()); return "SELECT alc.constraint_name, alc.DELETE_RULE, cols.column_name \"local_column\", cols.position, ( SELECT r_cols.table_name FROM user_cons_columns r_cols WHERE alc.r_constraint_name = r_cols.constraint_name AND r_cols.position = cols.position ) AS \"references_table\", ( SELECT r_cols.column_name FROM user_cons_columns r_cols WHERE alc.r_constraint_name = r_cols.constraint_name AND r_cols.position = cols.position ) AS \"foreign_column\" FROM user_cons_columns cols JOIN user_constraints alc ON alc.constraint_name = cols.constraint_name AND alc.constraint_type = 'R' AND alc.table_name = " . $table . ' ORDER BY cols.constraint_name ASC, cols.position ASC'; } /** * {@inheritDoc} */ public function getListTableConstraintsSQL($table) { $table = $this->normalizeIdentifier($table); $table = $this->quoteStringLiteral($table->getName()); return 'SELECT * FROM user_constraints WHERE table_name = ' . $table; } /** * {@inheritDoc} */ public function getListTableColumnsSQL($table, $database = null) { $table = $this->normalizeIdentifier($table); $table = $this->quoteStringLiteral($table->getName()); $tabColumnsTableName = 'user_tab_columns'; $colCommentsTableName = 'user_col_comments'; $tabColumnsOwnerCondition = ''; $colCommentsOwnerCondition = ''; if ($database !== null && $database !== '/') { $database = $this->normalizeIdentifier($database); $database = $this->quoteStringLiteral($database->getName()); $tabColumnsTableName = 'all_tab_columns'; $colCommentsTableName = 'all_col_comments'; $tabColumnsOwnerCondition = ' AND c.owner = ' . $database; $colCommentsOwnerCondition = ' AND d.OWNER = c.OWNER'; } return sprintf( <<<'SQL' SELECT c.*, ( SELECT d.comments FROM %s d WHERE d.TABLE_NAME = c.TABLE_NAME%s AND d.COLUMN_NAME = c.COLUMN_NAME ) AS comments FROM %s c WHERE c.table_name = %s%s ORDER BY c.column_id SQL , $colCommentsTableName, $colCommentsOwnerCondition, $tabColumnsTableName, $table, $tabColumnsOwnerCondition ); } /** * {@inheritDoc} */ public function getDropSequenceSQL($sequence) { if ($sequence instanceof Sequence) { $sequence = $sequence->getQuotedName($this); } return 'DROP SEQUENCE ' . $sequence; } /** * {@inheritDoc} */ public function getDropForeignKeySQL($foreignKey, $table) { if (! $foreignKey instanceof ForeignKeyConstraint) { $foreignKey = new Identifier($foreignKey); } if (! $table instanceof Table) { $table = new Identifier($table); } $foreignKey = $foreignKey->getQuotedName($this); $table = $table->getQuotedName($this); return 'ALTER TABLE ' . $table . ' DROP CONSTRAINT ' . $foreignKey; } /** * {@inheritdoc} */ public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey) { $referentialAction = null; if ($foreignKey->hasOption('onDelete')) { $referentialAction = $this->getForeignKeyReferentialActionSQL($foreignKey->getOption('onDelete')); } return $referentialAction ? ' ON DELETE ' . $referentialAction : ''; } /** * {@inheritdoc} */ public function getForeignKeyReferentialActionSQL($action) { $action = strtoupper($action); switch ($action) { case 'RESTRICT': // RESTRICT is not supported, therefore falling back to NO ACTION. case 'NO ACTION': // NO ACTION cannot be declared explicitly, // therefore returning empty string to indicate to OMIT the referential clause. return ''; case 'CASCADE': case 'SET NULL': return $action; default: // SET DEFAULT is not supported, throw exception instead. throw new InvalidArgumentException('Invalid foreign key action: ' . $action); } } /** * {@inheritDoc} */ public function getDropDatabaseSQL($database) { return 'DROP USER ' . $database . ' CASCADE'; } /** * {@inheritDoc} */ public function getAlterTableSQL(TableDiff $diff) { $sql = []; $commentsSQL = []; $columnSql = []; $fields = []; foreach ($diff->addedColumns as $column) { if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) { continue; } $fields[] = $this->getColumnDeclarationSQL($column->getQuotedName($this), $column->toArray()); $comment = $this->getColumnComment($column); if (! $comment) { continue; } $commentsSQL[] = $this->getCommentOnColumnSQL( $diff->getName($this)->getQuotedName($this), $column->getQuotedName($this), $comment ); } if (count($fields)) { $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) . ' ADD (' . implode(', ', $fields) . ')'; } $fields = []; foreach ($diff->changedColumns as $columnDiff) { if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) { continue; } $column = $columnDiff->column; // Do not generate column alteration clause if type is binary and only fixed property has changed. // Oracle only supports binary type columns with variable length. // Avoids unnecessary table alteration statements. if ($column->getType() instanceof BinaryType && $columnDiff->hasChanged('fixed') && count($columnDiff->changedProperties) === 1 ) { continue; } $columnHasChangedComment = $columnDiff->hasChanged('comment'); /** * Do not add query part if only comment has changed */ if (! ($columnHasChangedComment && count($columnDiff->changedProperties) === 1)) { $columnInfo = $column->toArray(); if (! $columnDiff->hasChanged('notnull')) { unset($columnInfo['notnull']); } $fields[] = $column->getQuotedName($this) . $this->getColumnDeclarationSQL('', $columnInfo); } if (! $columnHasChangedComment) { continue; } $commentsSQL[] = $this->getCommentOnColumnSQL( $diff->getName($this)->getQuotedName($this), $column->getQuotedName($this), $this->getColumnComment($column) ); } if (count($fields)) { $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) . ' MODIFY (' . implode(', ', $fields) . ')'; } foreach ($diff->renamedColumns as $oldColumnName => $column) { if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) { continue; } $oldColumnName = new Identifier($oldColumnName); $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) . ' RENAME COLUMN ' . $oldColumnName->getQuotedName($this) . ' TO ' . $column->getQuotedName($this); } $fields = []; foreach ($diff->removedColumns as $column) { if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) { continue; } $fields[] = $column->getQuotedName($this); } if (count($fields)) { $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) . ' DROP (' . implode(', ', $fields) . ')'; } $tableSql = []; if (! $this->onSchemaAlterTable($diff, $tableSql)) { $sql = array_merge($sql, $commentsSQL); $newName = $diff->getNewName(); if ($newName !== false) { $sql[] = sprintf( 'ALTER TABLE %s RENAME TO %s', $diff->getName($this)->getQuotedName($this), $newName->getQuotedName($this) ); } $sql = array_merge( $this->getPreAlterTableIndexForeignKeySQL($diff), $sql, $this->getPostAlterTableIndexForeignKeySQL($diff) ); } return array_merge($sql, $tableSql, $columnSql); } /** * {@inheritdoc} */ public function getColumnDeclarationSQL($name, array $field) { if (isset($field['columnDefinition'])) { $columnDef = $this->getCustomTypeDeclarationSQL($field); } else { $default = $this->getDefaultValueDeclarationSQL($field); $notnull = ''; if (isset($field['notnull'])) { $notnull = $field['notnull'] ? ' NOT NULL' : ' NULL'; } $unique = isset($field['unique']) && $field['unique'] ? ' ' . $this->getUniqueFieldDeclarationSQL() : ''; $check = isset($field['check']) && $field['check'] ? ' ' . $field['check'] : ''; $typeDecl = $field['type']->getSQLDeclaration($field, $this); $columnDef = $typeDecl . $default . $notnull . $unique . $check; } return $name . ' ' . $columnDef; } /** * {@inheritdoc} */ protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName) { if (strpos($tableName, '.') !== false) { [$schema] = explode('.', $tableName); $oldIndexName = $schema . '.' . $oldIndexName; } return ['ALTER INDEX ' . $oldIndexName . ' RENAME TO ' . $index->getQuotedName($this)]; } /** * {@inheritDoc} */ public function prefersSequences() { return true; } /** * {@inheritdoc} */ public function usesSequenceEmulatedIdentityColumns() { return true; } /** * {@inheritdoc} */ public function getIdentitySequenceName($tableName, $columnName) { $table = new Identifier($tableName); // No usage of column name to preserve BC compatibility with <2.5 $identitySequenceName = $table->getName() . '_SEQ'; if ($table->isQuoted()) { $identitySequenceName = '"' . $identitySequenceName . '"'; } $identitySequenceIdentifier = $this->normalizeIdentifier($identitySequenceName); return $identitySequenceIdentifier->getQuotedName($this); } /** * {@inheritDoc} */ public function supportsCommentOnStatement() { return true; } /** * {@inheritDoc} */ public function getName() { return 'oracle'; } /** * {@inheritDoc} */ protected function doModifyLimitQuery($query, $limit, $offset = null) { if ($limit === null && $offset <= 0) { return $query; } if (preg_match('/^\s*SELECT/i', $query)) { if (! preg_match('/\sFROM\s/i', $query)) { $query .= ' FROM dual'; } $columns = ['a.*']; if ($offset > 0) { $columns[] = 'ROWNUM AS doctrine_rownum'; } $query = sprintf('SELECT %s FROM (%s) a', implode(', ', $columns), $query); if ($limit !== null) { $query .= sprintf(' WHERE ROWNUM <= %d', $offset + $limit); } if ($offset > 0) { $query = sprintf('SELECT * FROM (%s) WHERE doctrine_rownum >= %d', $query, $offset + 1); } } return $query; } /** * {@inheritDoc} * * Oracle returns all column names in SQL result sets in uppercase. */ public function getSQLResultCasing($column) { return strtoupper($column); } /** * {@inheritDoc} */ public function getCreateTemporaryTableSnippetSQL() { return 'CREATE GLOBAL TEMPORARY TABLE'; } /** * {@inheritDoc} */ public function getDateTimeTzFormatString() { return 'Y-m-d H:i:sP'; } /** * {@inheritDoc} */ public function getDateFormatString() { return 'Y-m-d 00:00:00'; } /** * {@inheritDoc} */ public function getTimeFormatString() { return '1900-01-01 H:i:s'; } /** * {@inheritDoc} */ public function fixSchemaElementName($schemaElementName) { if (strlen($schemaElementName) > 30) { // Trim it return substr($schemaElementName, 0, 30); } return $schemaElementName; } /** * {@inheritDoc} */ public function getMaxIdentifierLength() { return 30; } /** * {@inheritDoc} */ public function supportsSequences() { return true; } /** * {@inheritDoc} */ public function supportsForeignKeyOnUpdate() { return false; } /** * {@inheritDoc} */ public function supportsReleaseSavepoints() { return false; } /** * {@inheritDoc} */ public function getTruncateTableSQL($tableName, $cascade = false) { $tableIdentifier = new Identifier($tableName); return 'TRUNCATE TABLE ' . $tableIdentifier->getQuotedName($this); } /** * {@inheritDoc} */ public function getDummySelectSQL() { $expression = func_num_args() > 0 ? func_get_arg(0) : '1'; return sprintf('SELECT %s FROM DUAL', $expression); } /** * {@inheritDoc} */ protected function initializeDoctrineTypeMappings() { $this->doctrineTypeMapping = [ 'integer' => 'integer', 'number' => 'integer', 'pls_integer' => 'boolean', 'binary_integer' => 'boolean', 'varchar' => 'string', 'varchar2' => 'string', 'nvarchar2' => 'string', 'char' => 'string', 'nchar' => 'string', 'date' => 'date', 'timestamp' => 'datetime', 'timestamptz' => 'datetimetz', 'float' => 'float', 'binary_float' => 'float', 'binary_double' => 'float', 'long' => 'string', 'clob' => 'text', 'nclob' => 'text', 'raw' => 'binary', 'long raw' => 'blob', 'rowid' => 'string', 'urowid' => 'string', 'blob' => 'blob', ]; } /** * {@inheritDoc} */ public function releaseSavePoint($savepoint) { return ''; } /** * {@inheritDoc} */ protected function getReservedKeywordsClass() { return Keywords\OracleKeywords::class; } /** * {@inheritDoc} */ public function getBlobTypeDeclarationSQL(array $field) { return 'BLOB'; } public function getListTableCommentsSQL(string $table, ?string $database = null) : string { $tableCommentsName = 'user_tab_comments'; $ownerCondition = ''; if ($database !== null && $database !== '/') { $tableCommentsName = 'all_tab_comments'; $ownerCondition = ' AND owner = ' . $this->quoteStringLiteral($this->normalizeIdentifier($database)->getName()); } return sprintf( <<<'SQL' SELECT comments FROM %s WHERE table_name = %s%s SQL , $tableCommentsName, $this->quoteStringLiteral($this->normalizeIdentifier($table)->getName()), $ownerCondition ); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Platforms/PostgreSQL100Platform.php000066400000000000000000000017261360544566000265360ustar00rootroot00000000000000quoteStringLiteral($database) . " AND sequence_schema NOT LIKE 'pg\_%' AND sequence_schema != 'information_schema'"; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Platforms/PostgreSQL91Platform.php000066400000000000000000000020721360544566000264620ustar00rootroot00000000000000quoteSingleIdentifier($collation); } /** * {@inheritDoc} */ public function getListTableColumnsSQL($table, $database = null) { $sql = parent::getListTableColumnsSQL($table, $database); $parts = explode('AS complete_type,', $sql, 2); return $parts[0] . 'AS complete_type, (SELECT tc.collcollate FROM pg_catalog.pg_collation tc WHERE tc.oid = a.attcollation) AS collation,' . $parts[1]; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Platforms/PostgreSQL92Platform.php000066400000000000000000000026241360544566000264660ustar00rootroot00000000000000doctrineTypeMapping['json'] = Types::JSON; } /** * {@inheritdoc} */ public function getCloseActiveDatabaseConnectionsSQL($database) { return sprintf( 'SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = %s', $this->quoteStringLiteral($database) ); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Platforms/PostgreSQL94Platform.php000066400000000000000000000014571360544566000264730ustar00rootroot00000000000000doctrineTypeMapping['jsonb'] = Types::JSON; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Platforms/PostgreSqlPlatform.php000066400000000000000000001101031360544566000264030ustar00rootroot00000000000000 [ 't', 'true', 'y', 'yes', 'on', '1', ], 'false' => [ 'f', 'false', 'n', 'no', 'off', '0', ], ]; /** * PostgreSQL has different behavior with some drivers * with regard to how booleans have to be handled. * * Enables use of 'true'/'false' or otherwise 1 and 0 instead. * * @param bool $flag */ public function setUseBooleanTrueFalseStrings($flag) { $this->useBooleanTrueFalseStrings = (bool) $flag; } /** * {@inheritDoc} */ public function getSubstringExpression($value, $from, $length = null) { if ($length === null) { return 'SUBSTRING(' . $value . ' FROM ' . $from . ')'; } return 'SUBSTRING(' . $value . ' FROM ' . $from . ' FOR ' . $length . ')'; } /** * {@inheritDoc} */ public function getNowExpression() { return 'LOCALTIMESTAMP(0)'; } /** * {@inheritDoc} */ public function getRegexpExpression() { return 'SIMILAR TO'; } /** * {@inheritDoc} */ public function getLocateExpression($str, $substr, $startPos = false) { if ($startPos !== false) { $str = $this->getSubstringExpression($str, $startPos); return 'CASE WHEN (POSITION(' . $substr . ' IN ' . $str . ') = 0) THEN 0 ELSE (POSITION(' . $substr . ' IN ' . $str . ') + ' . ($startPos-1) . ') END'; } return 'POSITION(' . $substr . ' IN ' . $str . ')'; } /** * {@inheritdoc} */ protected function getDateArithmeticIntervalExpression($date, $operator, $interval, $unit) { if ($unit === DateIntervalUnit::QUARTER) { $interval *= 3; $unit = DateIntervalUnit::MONTH; } return '(' . $date . ' ' . $operator . ' (' . $interval . " || ' " . $unit . "')::interval)"; } /** * {@inheritDoc} */ public function getDateDiffExpression($date1, $date2) { return '(DATE(' . $date1 . ')-DATE(' . $date2 . '))'; } /** * {@inheritDoc} */ public function supportsSequences() { return true; } /** * {@inheritDoc} */ public function supportsSchemas() { return true; } /** * {@inheritdoc} */ public function getDefaultSchemaName() { return 'public'; } /** * {@inheritDoc} */ public function supportsIdentityColumns() { return true; } /** * {@inheritdoc} */ public function supportsPartialIndexes() { return true; } /** * {@inheritdoc} */ public function usesSequenceEmulatedIdentityColumns() { return true; } /** * {@inheritdoc} */ public function getIdentitySequenceName($tableName, $columnName) { return $tableName . '_' . $columnName . '_seq'; } /** * {@inheritDoc} */ public function supportsCommentOnStatement() { return true; } /** * {@inheritDoc} */ public function prefersSequences() { return true; } /** * {@inheritDoc} */ public function hasNativeGuidType() { return true; } /** * {@inheritDoc} */ public function getListDatabasesSQL() { return 'SELECT datname FROM pg_database'; } /** * {@inheritDoc} */ public function getListNamespacesSQL() { return "SELECT schema_name AS nspname FROM information_schema.schemata WHERE schema_name NOT LIKE 'pg\_%' AND schema_name != 'information_schema'"; } /** * {@inheritDoc} */ public function getListSequencesSQL($database) { return "SELECT sequence_name AS relname, sequence_schema AS schemaname FROM information_schema.sequences WHERE sequence_schema NOT LIKE 'pg\_%' AND sequence_schema != 'information_schema'"; } /** * {@inheritDoc} */ public function getListTablesSQL() { return "SELECT quote_ident(table_name) AS table_name, table_schema AS schema_name FROM information_schema.tables WHERE table_schema NOT LIKE 'pg\_%' AND table_schema != 'information_schema' AND table_name != 'geometry_columns' AND table_name != 'spatial_ref_sys' AND table_type != 'VIEW'"; } /** * {@inheritDoc} */ public function getListViewsSQL($database) { return 'SELECT quote_ident(table_name) AS viewname, table_schema AS schemaname, view_definition AS definition FROM information_schema.views WHERE view_definition IS NOT NULL'; } /** * {@inheritDoc} */ public function getListTableForeignKeysSQL($table, $database = null) { return 'SELECT quote_ident(r.conname) as conname, pg_catalog.pg_get_constraintdef(r.oid, true) as condef FROM pg_catalog.pg_constraint r WHERE r.conrelid = ( SELECT c.oid FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n WHERE ' . $this->getTableWhereClause($table) . " AND n.oid = c.relnamespace ) AND r.contype = 'f'"; } /** * {@inheritDoc} */ public function getCreateViewSQL($name, $sql) { return 'CREATE VIEW ' . $name . ' AS ' . $sql; } /** * {@inheritDoc} */ public function getDropViewSQL($name) { return 'DROP VIEW ' . $name; } /** * {@inheritDoc} */ public function getListTableConstraintsSQL($table) { $table = new Identifier($table); $table = $this->quoteStringLiteral($table->getName()); return sprintf( <<<'SQL' SELECT quote_ident(relname) as relname FROM pg_class WHERE oid IN ( SELECT indexrelid FROM pg_index, pg_class WHERE pg_class.relname = %s AND pg_class.oid = pg_index.indrelid AND (indisunique = 't' OR indisprimary = 't') ) SQL , $table ); } /** * {@inheritDoc} * * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html */ public function getListTableIndexesSQL($table, $currentDatabase = null) { return 'SELECT quote_ident(relname) as relname, pg_index.indisunique, pg_index.indisprimary, pg_index.indkey, pg_index.indrelid, pg_get_expr(indpred, indrelid) AS where FROM pg_class, pg_index WHERE oid IN ( SELECT indexrelid FROM pg_index si, pg_class sc, pg_namespace sn WHERE ' . $this->getTableWhereClause($table, 'sc', 'sn') . ' AND sc.oid=si.indrelid AND sc.relnamespace = sn.oid ) AND pg_index.indexrelid = oid'; } /** * @param string $table * @param string $classAlias * @param string $namespaceAlias * * @return string */ private function getTableWhereClause($table, $classAlias = 'c', $namespaceAlias = 'n') { $whereClause = $namespaceAlias . ".nspname NOT IN ('pg_catalog', 'information_schema', 'pg_toast') AND "; if (strpos($table, '.') !== false) { [$schema, $table] = explode('.', $table); $schema = $this->quoteStringLiteral($schema); } else { $schema = "ANY(string_to_array((select replace(replace(setting,'\"\$user\"',user),' ','') from pg_catalog.pg_settings where name = 'search_path'),','))"; } $table = new Identifier($table); $table = $this->quoteStringLiteral($table->getName()); return $whereClause . sprintf( '%s.relname = %s AND %s.nspname = %s', $classAlias, $table, $namespaceAlias, $schema ); } /** * {@inheritDoc} */ public function getListTableColumnsSQL($table, $database = null) { return "SELECT a.attnum, quote_ident(a.attname) AS field, t.typname AS type, format_type(a.atttypid, a.atttypmod) AS complete_type, (SELECT t1.typname FROM pg_catalog.pg_type t1 WHERE t1.oid = t.typbasetype) AS domain_type, (SELECT format_type(t2.typbasetype, t2.typtypmod) FROM pg_catalog.pg_type t2 WHERE t2.typtype = 'd' AND t2.oid = a.atttypid) AS domain_complete_type, a.attnotnull AS isnotnull, (SELECT 't' FROM pg_index WHERE c.oid = pg_index.indrelid AND pg_index.indkey[0] = a.attnum AND pg_index.indisprimary = 't' ) AS pri, (SELECT pg_get_expr(adbin, adrelid) FROM pg_attrdef WHERE c.oid = pg_attrdef.adrelid AND pg_attrdef.adnum=a.attnum ) AS default, (SELECT pg_description.description FROM pg_description WHERE pg_description.objoid = c.oid AND a.attnum = pg_description.objsubid ) AS comment FROM pg_attribute a, pg_class c, pg_type t, pg_namespace n WHERE " . $this->getTableWhereClause($table, 'c', 'n') . ' AND a.attnum > 0 AND a.attrelid = c.oid AND a.atttypid = t.oid AND n.oid = c.relnamespace ORDER BY a.attnum'; } /** * {@inheritDoc} */ public function getCreateDatabaseSQL($name) { return 'CREATE DATABASE ' . $name; } /** * Returns the SQL statement for disallowing new connections on the given database. * * This is useful to force DROP DATABASE operations which could fail because of active connections. * * @param string $database The name of the database to disallow new connections for. * * @return string */ public function getDisallowDatabaseConnectionsSQL($database) { return "UPDATE pg_database SET datallowconn = 'false' WHERE datname = " . $this->quoteStringLiteral($database); } /** * Returns the SQL statement for closing currently active connections on the given database. * * This is useful to force DROP DATABASE operations which could fail because of active connections. * * @param string $database The name of the database to close currently active connections for. * * @return string */ public function getCloseActiveDatabaseConnectionsSQL($database) { return 'SELECT pg_terminate_backend(procpid) FROM pg_stat_activity WHERE datname = ' . $this->quoteStringLiteral($database); } /** * {@inheritDoc} */ public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey) { $query = ''; if ($foreignKey->hasOption('match')) { $query .= ' MATCH ' . $foreignKey->getOption('match'); } $query .= parent::getAdvancedForeignKeyOptionsSQL($foreignKey); if ($foreignKey->hasOption('deferrable') && $foreignKey->getOption('deferrable') !== false) { $query .= ' DEFERRABLE'; } else { $query .= ' NOT DEFERRABLE'; } if (($foreignKey->hasOption('feferred') && $foreignKey->getOption('feferred') !== false) || ($foreignKey->hasOption('deferred') && $foreignKey->getOption('deferred') !== false) ) { $query .= ' INITIALLY DEFERRED'; } else { $query .= ' INITIALLY IMMEDIATE'; } return $query; } /** * {@inheritDoc} */ public function getAlterTableSQL(TableDiff $diff) { $sql = []; $commentsSQL = []; $columnSql = []; foreach ($diff->addedColumns as $column) { if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) { continue; } $query = 'ADD ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $column->toArray()); $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) . ' ' . $query; $comment = $this->getColumnComment($column); if ($comment === null || $comment === '') { continue; } $commentsSQL[] = $this->getCommentOnColumnSQL( $diff->getName($this)->getQuotedName($this), $column->getQuotedName($this), $comment ); } foreach ($diff->removedColumns as $column) { if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) { continue; } $query = 'DROP ' . $column->getQuotedName($this); $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) . ' ' . $query; } foreach ($diff->changedColumns as $columnDiff) { /** @var $columnDiff \Doctrine\DBAL\Schema\ColumnDiff */ if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) { continue; } if ($this->isUnchangedBinaryColumn($columnDiff)) { continue; } $oldColumnName = $columnDiff->getOldColumnName()->getQuotedName($this); $column = $columnDiff->column; if ($columnDiff->hasChanged('type') || $columnDiff->hasChanged('precision') || $columnDiff->hasChanged('scale') || $columnDiff->hasChanged('fixed')) { $type = $column->getType(); // SERIAL/BIGSERIAL are not "real" types and we can't alter a column to that type $columnDefinition = $column->toArray(); $columnDefinition['autoincrement'] = false; // here was a server version check before, but DBAL API does not support this anymore. $query = 'ALTER ' . $oldColumnName . ' TYPE ' . $type->getSQLDeclaration($columnDefinition, $this); $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) . ' ' . $query; } if ($columnDiff->hasChanged('default') || $this->typeChangeBreaksDefaultValue($columnDiff)) { $defaultClause = $column->getDefault() === null ? ' DROP DEFAULT' : ' SET' . $this->getDefaultValueDeclarationSQL($column->toArray()); $query = 'ALTER ' . $oldColumnName . $defaultClause; $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) . ' ' . $query; } if ($columnDiff->hasChanged('notnull')) { $query = 'ALTER ' . $oldColumnName . ' ' . ($column->getNotnull() ? 'SET' : 'DROP') . ' NOT NULL'; $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) . ' ' . $query; } if ($columnDiff->hasChanged('autoincrement')) { if ($column->getAutoincrement()) { // add autoincrement $seqName = $this->getIdentitySequenceName($diff->name, $oldColumnName); $sql[] = 'CREATE SEQUENCE ' . $seqName; $sql[] = "SELECT setval('" . $seqName . "', (SELECT MAX(" . $oldColumnName . ') FROM ' . $diff->getName($this)->getQuotedName($this) . '))'; $query = 'ALTER ' . $oldColumnName . " SET DEFAULT nextval('" . $seqName . "')"; $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) . ' ' . $query; } else { // Drop autoincrement, but do NOT drop the sequence. It might be re-used by other tables or have $query = 'ALTER ' . $oldColumnName . ' DROP DEFAULT'; $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) . ' ' . $query; } } $newComment = $this->getColumnComment($column); $oldComment = $this->getOldColumnComment($columnDiff); if ($columnDiff->hasChanged('comment') || ($columnDiff->fromColumn !== null && $oldComment !== $newComment)) { $commentsSQL[] = $this->getCommentOnColumnSQL( $diff->getName($this)->getQuotedName($this), $column->getQuotedName($this), $newComment ); } if (! $columnDiff->hasChanged('length')) { continue; } $query = 'ALTER ' . $oldColumnName . ' TYPE ' . $column->getType()->getSQLDeclaration($column->toArray(), $this); $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) . ' ' . $query; } foreach ($diff->renamedColumns as $oldColumnName => $column) { if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) { continue; } $oldColumnName = new Identifier($oldColumnName); $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) . ' RENAME COLUMN ' . $oldColumnName->getQuotedName($this) . ' TO ' . $column->getQuotedName($this); } $tableSql = []; if (! $this->onSchemaAlterTable($diff, $tableSql)) { $sql = array_merge($sql, $commentsSQL); $newName = $diff->getNewName(); if ($newName !== false) { $sql[] = sprintf( 'ALTER TABLE %s RENAME TO %s', $diff->getName($this)->getQuotedName($this), $newName->getQuotedName($this) ); } $sql = array_merge( $this->getPreAlterTableIndexForeignKeySQL($diff), $sql, $this->getPostAlterTableIndexForeignKeySQL($diff) ); } return array_merge($sql, $tableSql, $columnSql); } /** * Checks whether a given column diff is a logically unchanged binary type column. * * Used to determine whether a column alteration for a binary type column can be skipped. * Doctrine's {@link \Doctrine\DBAL\Types\BinaryType} and {@link \Doctrine\DBAL\Types\BlobType} * are mapped to the same database column type on this platform as this platform * does not have a native VARBINARY/BINARY column type. Therefore the {@link \Doctrine\DBAL\Schema\Comparator} * might detect differences for binary type columns which do not have to be propagated * to database as there actually is no difference at database level. * * @param ColumnDiff $columnDiff The column diff to check against. * * @return bool True if the given column diff is an unchanged binary type column, false otherwise. */ private function isUnchangedBinaryColumn(ColumnDiff $columnDiff) { $columnType = $columnDiff->column->getType(); if (! $columnType instanceof BinaryType && ! $columnType instanceof BlobType) { return false; } $fromColumn = $columnDiff->fromColumn instanceof Column ? $columnDiff->fromColumn : null; if ($fromColumn) { $fromColumnType = $fromColumn->getType(); if (! $fromColumnType instanceof BinaryType && ! $fromColumnType instanceof BlobType) { return false; } return count(array_diff($columnDiff->changedProperties, ['type', 'length', 'fixed'])) === 0; } if ($columnDiff->hasChanged('type')) { return false; } return count(array_diff($columnDiff->changedProperties, ['length', 'fixed'])) === 0; } /** * {@inheritdoc} */ protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName) { if (strpos($tableName, '.') !== false) { [$schema] = explode('.', $tableName); $oldIndexName = $schema . '.' . $oldIndexName; } return ['ALTER INDEX ' . $oldIndexName . ' RENAME TO ' . $index->getQuotedName($this)]; } /** * {@inheritdoc} */ public function getCommentOnColumnSQL($tableName, $columnName, $comment) { $tableName = new Identifier($tableName); $columnName = new Identifier($columnName); $comment = $comment === null ? 'NULL' : $this->quoteStringLiteral($comment); return sprintf( 'COMMENT ON COLUMN %s.%s IS %s', $tableName->getQuotedName($this), $columnName->getQuotedName($this), $comment ); } /** * {@inheritDoc} */ public function getCreateSequenceSQL(Sequence $sequence) { return 'CREATE SEQUENCE ' . $sequence->getQuotedName($this) . ' INCREMENT BY ' . $sequence->getAllocationSize() . ' MINVALUE ' . $sequence->getInitialValue() . ' START ' . $sequence->getInitialValue() . $this->getSequenceCacheSQL($sequence); } /** * {@inheritDoc} */ public function getAlterSequenceSQL(Sequence $sequence) { return 'ALTER SEQUENCE ' . $sequence->getQuotedName($this) . ' INCREMENT BY ' . $sequence->getAllocationSize() . $this->getSequenceCacheSQL($sequence); } /** * Cache definition for sequences * * @return string */ private function getSequenceCacheSQL(Sequence $sequence) { if ($sequence->getCache() > 1) { return ' CACHE ' . $sequence->getCache(); } return ''; } /** * {@inheritDoc} */ public function getDropSequenceSQL($sequence) { if ($sequence instanceof Sequence) { $sequence = $sequence->getQuotedName($this); } return 'DROP SEQUENCE ' . $sequence . ' CASCADE'; } /** * {@inheritDoc} */ public function getCreateSchemaSQL($schemaName) { return 'CREATE SCHEMA ' . $schemaName; } /** * {@inheritDoc} */ public function getDropForeignKeySQL($foreignKey, $table) { return $this->getDropConstraintSQL($foreignKey, $table); } /** * {@inheritDoc} */ protected function _getCreateTableSQL($tableName, array $columns, array $options = []) { $queryFields = $this->getColumnDeclarationListSQL($columns); if (isset($options['primary']) && ! empty($options['primary'])) { $keyColumns = array_unique(array_values($options['primary'])); $queryFields .= ', PRIMARY KEY(' . implode(', ', $keyColumns) . ')'; } $query = 'CREATE TABLE ' . $tableName . ' (' . $queryFields . ')'; $sql = [$query]; if (isset($options['indexes']) && ! empty($options['indexes'])) { foreach ($options['indexes'] as $index) { $sql[] = $this->getCreateIndexSQL($index, $tableName); } } if (isset($options['foreignKeys'])) { foreach ((array) $options['foreignKeys'] as $definition) { $sql[] = $this->getCreateForeignKeySQL($definition, $tableName); } } return $sql; } /** * Converts a single boolean value. * * First converts the value to its native PHP boolean type * and passes it to the given callback function to be reconverted * into any custom representation. * * @param mixed $value The value to convert. * @param callable $callback The callback function to use for converting the real boolean value. * * @return mixed * * @throws UnexpectedValueException */ private function convertSingleBooleanValue($value, $callback) { if ($value === null) { return $callback(null); } if (is_bool($value) || is_numeric($value)) { return $callback((bool) $value); } if (! is_string($value)) { return $callback(true); } /** * Better safe than sorry: http://php.net/in_array#106319 */ if (in_array(strtolower(trim($value)), $this->booleanLiterals['false'], true)) { return $callback(false); } if (in_array(strtolower(trim($value)), $this->booleanLiterals['true'], true)) { return $callback(true); } throw new UnexpectedValueException("Unrecognized boolean literal '${value}'"); } /** * Converts one or multiple boolean values. * * First converts the value(s) to their native PHP boolean type * and passes them to the given callback function to be reconverted * into any custom representation. * * @param mixed $item The value(s) to convert. * @param callable $callback The callback function to use for converting the real boolean value(s). * * @return mixed */ private function doConvertBooleans($item, $callback) { if (is_array($item)) { foreach ($item as $key => $value) { $item[$key] = $this->convertSingleBooleanValue($value, $callback); } return $item; } return $this->convertSingleBooleanValue($item, $callback); } /** * {@inheritDoc} * * Postgres wants boolean values converted to the strings 'true'/'false'. */ public function convertBooleans($item) { if (! $this->useBooleanTrueFalseStrings) { return parent::convertBooleans($item); } return $this->doConvertBooleans( $item, static function ($boolean) { if ($boolean === null) { return 'NULL'; } return $boolean === true ? 'true' : 'false'; } ); } /** * {@inheritDoc} */ public function convertBooleansToDatabaseValue($item) { if (! $this->useBooleanTrueFalseStrings) { return parent::convertBooleansToDatabaseValue($item); } return $this->doConvertBooleans( $item, static function ($boolean) { return $boolean === null ? null : (int) $boolean; } ); } /** * {@inheritDoc} */ public function convertFromBoolean($item) { if (in_array(strtolower($item), $this->booleanLiterals['false'], true)) { return false; } return parent::convertFromBoolean($item); } /** * {@inheritDoc} */ public function getSequenceNextValSQL($sequenceName) { return "SELECT NEXTVAL('" . $sequenceName . "')"; } /** * {@inheritDoc} */ public function getSetTransactionIsolationSQL($level) { return 'SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL ' . $this->_getTransactionIsolationLevelSQL($level); } /** * {@inheritDoc} */ public function getBooleanTypeDeclarationSQL(array $field) { return 'BOOLEAN'; } /** * {@inheritDoc} */ public function getIntegerTypeDeclarationSQL(array $field) { if (! empty($field['autoincrement'])) { return 'SERIAL'; } return 'INT'; } /** * {@inheritDoc} */ public function getBigIntTypeDeclarationSQL(array $field) { if (! empty($field['autoincrement'])) { return 'BIGSERIAL'; } return 'BIGINT'; } /** * {@inheritDoc} */ public function getSmallIntTypeDeclarationSQL(array $field) { return 'SMALLINT'; } /** * {@inheritDoc} */ public function getGuidTypeDeclarationSQL(array $field) { return 'UUID'; } /** * {@inheritDoc} */ public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) { return 'TIMESTAMP(0) WITHOUT TIME ZONE'; } /** * {@inheritDoc} */ public function getDateTimeTzTypeDeclarationSQL(array $fieldDeclaration) { return 'TIMESTAMP(0) WITH TIME ZONE'; } /** * {@inheritDoc} */ public function getDateTypeDeclarationSQL(array $fieldDeclaration) { return 'DATE'; } /** * {@inheritDoc} */ public function getTimeTypeDeclarationSQL(array $fieldDeclaration) { return 'TIME(0) WITHOUT TIME ZONE'; } /** * {@inheritDoc} * * @deprecated Use application-generated UUIDs instead */ public function getGuidExpression() { return 'UUID_GENERATE_V4()'; } /** * {@inheritDoc} */ protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) { return ''; } /** * {@inheritDoc} */ protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) { return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)') : ($length ? 'VARCHAR(' . $length . ')' : 'VARCHAR(255)'); } /** * {@inheritdoc} */ protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed) { return 'BYTEA'; } /** * {@inheritDoc} */ public function getClobTypeDeclarationSQL(array $field) { return 'TEXT'; } /** * {@inheritDoc} */ public function getName() { return 'postgresql'; } /** * {@inheritDoc} * * PostgreSQL returns all column names in SQL result sets in lowercase. */ public function getSQLResultCasing($column) { return strtolower($column); } /** * {@inheritDoc} */ public function getDateTimeTzFormatString() { return 'Y-m-d H:i:sO'; } /** * {@inheritDoc} */ public function getEmptyIdentityInsertSQL($quotedTableName, $quotedIdentifierColumnName) { return 'INSERT INTO ' . $quotedTableName . ' (' . $quotedIdentifierColumnName . ') VALUES (DEFAULT)'; } /** * {@inheritDoc} */ public function getTruncateTableSQL($tableName, $cascade = false) { $tableIdentifier = new Identifier($tableName); $sql = 'TRUNCATE ' . $tableIdentifier->getQuotedName($this); if ($cascade) { $sql .= ' CASCADE'; } return $sql; } /** * {@inheritDoc} */ public function getReadLockSQL() { return 'FOR SHARE'; } /** * {@inheritDoc} */ protected function initializeDoctrineTypeMappings() { $this->doctrineTypeMapping = [ 'smallint' => 'smallint', 'int2' => 'smallint', 'serial' => 'integer', 'serial4' => 'integer', 'int' => 'integer', 'int4' => 'integer', 'integer' => 'integer', 'bigserial' => 'bigint', 'serial8' => 'bigint', 'bigint' => 'bigint', 'int8' => 'bigint', 'bool' => 'boolean', 'boolean' => 'boolean', 'text' => 'text', 'tsvector' => 'text', 'varchar' => 'string', 'interval' => 'string', '_varchar' => 'string', 'char' => 'string', 'bpchar' => 'string', 'inet' => 'string', 'date' => 'date', 'datetime' => 'datetime', 'timestamp' => 'datetime', 'timestamptz' => 'datetimetz', 'time' => 'time', 'timetz' => 'time', 'float' => 'float', 'float4' => 'float', 'float8' => 'float', 'double' => 'float', 'double precision' => 'float', 'real' => 'float', 'decimal' => 'decimal', 'money' => 'decimal', 'numeric' => 'decimal', 'year' => 'date', 'uuid' => 'guid', 'bytea' => 'blob', ]; } /** * {@inheritDoc} */ public function getVarcharMaxLength() { return 65535; } /** * {@inheritdoc} */ public function getBinaryMaxLength() { return 0; } /** * {@inheritdoc} */ public function getBinaryDefaultLength() { return 0; } /** * {@inheritDoc} */ protected function getReservedKeywordsClass() { return Keywords\PostgreSQLKeywords::class; } /** * {@inheritDoc} */ public function getBlobTypeDeclarationSQL(array $field) { return 'BYTEA'; } /** * {@inheritdoc} */ public function getDefaultValueDeclarationSQL($field) { if ($this->isSerialField($field)) { return ''; } return parent::getDefaultValueDeclarationSQL($field); } /** * @param mixed[] $field */ private function isSerialField(array $field) : bool { return isset($field['type'], $field['autoincrement']) && $field['autoincrement'] === true && $this->isNumericType($field['type']); } /** * Check whether the type of a column is changed in a way that invalidates the default value for the column */ private function typeChangeBreaksDefaultValue(ColumnDiff $columnDiff) : bool { if (! $columnDiff->fromColumn) { return $columnDiff->hasChanged('type'); } $oldTypeIsNumeric = $this->isNumericType($columnDiff->fromColumn->getType()); $newTypeIsNumeric = $this->isNumericType($columnDiff->column->getType()); // default should not be changed when switching between numeric types and the default comes from a sequence return $columnDiff->hasChanged('type') && ! ($oldTypeIsNumeric && $newTypeIsNumeric && $columnDiff->column->getAutoincrement()); } private function isNumericType(Type $type) : bool { return $type instanceof IntegerType || $type instanceof BigIntType; } private function getOldColumnComment(ColumnDiff $columnDiff) : ?string { return $columnDiff->fromColumn ? $this->getColumnComment($columnDiff->fromColumn) : null; } public function getListTableMetadataSQL(string $table, ?string $schema = null) : string { if ($schema !== null) { $table = $schema . '.' . $table; } return sprintf( <<<'SQL' SELECT obj_description(%s::regclass) AS table_comment; SQL , $this->quoteStringLiteral($table) ); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Platforms/SQLAnywhere11Platform.php000066400000000000000000000010021360544566000266010ustar00rootroot00000000000000getQuotedName($this) . ' INCREMENT BY ' . $sequence->getAllocationSize() . ' START WITH ' . $sequence->getInitialValue() . ' MINVALUE ' . $sequence->getInitialValue(); } /** * {@inheritdoc} */ public function getAlterSequenceSQL(Sequence $sequence) { return 'ALTER SEQUENCE ' . $sequence->getQuotedName($this) . ' INCREMENT BY ' . $sequence->getAllocationSize(); } /** * {@inheritdoc} */ public function getDateTimeTzFormatString() { return 'Y-m-d H:i:s.uP'; } /** * {@inheritdoc} */ public function getDateTimeTzTypeDeclarationSQL(array $fieldDeclaration) { return 'TIMESTAMP WITH TIME ZONE'; } /** * {@inheritdoc} */ public function getDropSequenceSQL($sequence) { if ($sequence instanceof Sequence) { $sequence = $sequence->getQuotedName($this); } return 'DROP SEQUENCE ' . $sequence; } /** * {@inheritdoc} */ public function getListSequencesSQL($database) { return 'SELECT sequence_name, increment_by, start_with, min_value FROM SYS.SYSSEQUENCE'; } /** * {@inheritdoc} */ public function getSequenceNextValSQL($sequenceName) { return 'SELECT ' . $sequenceName . '.NEXTVAL'; } /** * {@inheritdoc} */ public function supportsSequences() { return true; } /** * {@inheritdoc} */ protected function getAdvancedIndexOptionsSQL(Index $index) { if (! $index->isPrimary() && $index->isUnique() && $index->hasFlag('with_nulls_not_distinct')) { return ' WITH NULLS NOT DISTINCT' . parent::getAdvancedIndexOptionsSQL($index); } return parent::getAdvancedIndexOptionsSQL($index); } /** * {@inheritdoc} */ protected function getReservedKeywordsClass() { return Keywords\SQLAnywhere12Keywords::class; } /** * {@inheritDoc} */ protected function initializeDoctrineTypeMappings() { parent::initializeDoctrineTypeMappings(); $this->doctrineTypeMapping['timestamp with time zone'] = 'datetime'; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Platforms/SQLAnywhere16Platform.php000066400000000000000000000021441360544566000266160ustar00rootroot00000000000000hasFlag('with_nulls_distinct') && $index->hasFlag('with_nulls_not_distinct')) { throw new UnexpectedValueException( 'An Index can either have a "with_nulls_distinct" or "with_nulls_not_distinct" flag but not both.' ); } if (! $index->isPrimary() && $index->isUnique() && $index->hasFlag('with_nulls_distinct')) { return ' WITH NULLS DISTINCT' . parent::getAdvancedIndexOptionsSQL($index); } return parent::getAdvancedIndexOptionsSQL($index); } /** * {@inheritdoc} */ protected function getReservedKeywordsClass() { return Keywords\SQLAnywhere16Keywords::class; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php000066400000000000000000001237441360544566000264610ustar00rootroot00000000000000getMaxIdentifierLength(); if (strlen($schemaElementName) > $maxIdentifierLength) { return substr($schemaElementName, 0, $maxIdentifierLength); } return $schemaElementName; } /** * {@inheritdoc} */ public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey) { $query = ''; if ($foreignKey->hasOption('match')) { $query = ' MATCH ' . $this->getForeignKeyMatchClauseSQL($foreignKey->getOption('match')); } $query .= parent::getAdvancedForeignKeyOptionsSQL($foreignKey); if ($foreignKey->hasOption('check_on_commit') && (bool) $foreignKey->getOption('check_on_commit')) { $query .= ' CHECK ON COMMIT'; } if ($foreignKey->hasOption('clustered') && (bool) $foreignKey->getOption('clustered')) { $query .= ' CLUSTERED'; } if ($foreignKey->hasOption('for_olap_workload') && (bool) $foreignKey->getOption('for_olap_workload')) { $query .= ' FOR OLAP WORKLOAD'; } return $query; } /** * {@inheritdoc} */ public function getAlterTableSQL(TableDiff $diff) { $sql = []; $columnSql = []; $commentsSQL = []; $tableSql = []; $alterClauses = []; foreach ($diff->addedColumns as $column) { if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) { continue; } $alterClauses[] = $this->getAlterTableAddColumnClause($column); $comment = $this->getColumnComment($column); if ($comment === null || $comment === '') { continue; } $commentsSQL[] = $this->getCommentOnColumnSQL( $diff->getName($this)->getQuotedName($this), $column->getQuotedName($this), $comment ); } foreach ($diff->removedColumns as $column) { if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) { continue; } $alterClauses[] = $this->getAlterTableRemoveColumnClause($column); } foreach ($diff->changedColumns as $columnDiff) { if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) { continue; } $alterClause = $this->getAlterTableChangeColumnClause($columnDiff); if ($alterClause !== null) { $alterClauses[] = $alterClause; } if (! $columnDiff->hasChanged('comment')) { continue; } $column = $columnDiff->column; $commentsSQL[] = $this->getCommentOnColumnSQL( $diff->getName($this)->getQuotedName($this), $column->getQuotedName($this), $this->getColumnComment($column) ); } foreach ($diff->renamedColumns as $oldColumnName => $column) { if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) { continue; } $sql[] = $this->getAlterTableClause($diff->getName($this)) . ' ' . $this->getAlterTableRenameColumnClause($oldColumnName, $column); } if (! $this->onSchemaAlterTable($diff, $tableSql)) { if (! empty($alterClauses)) { $sql[] = $this->getAlterTableClause($diff->getName($this)) . ' ' . implode(', ', $alterClauses); } $sql = array_merge($sql, $commentsSQL); $newName = $diff->getNewName(); if ($newName !== false) { $sql[] = $this->getAlterTableClause($diff->getName($this)) . ' ' . $this->getAlterTableRenameTableClause($newName); } $sql = array_merge( $this->getPreAlterTableIndexForeignKeySQL($diff), $sql, $this->getPostAlterTableIndexForeignKeySQL($diff) ); } return array_merge($sql, $tableSql, $columnSql); } /** * Returns the SQL clause for creating a column in a table alteration. * * @param Column $column The column to add. * * @return string */ protected function getAlterTableAddColumnClause(Column $column) { return 'ADD ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $column->toArray()); } /** * Returns the SQL clause for altering a table. * * @param Identifier $tableName The quoted name of the table to alter. * * @return string */ protected function getAlterTableClause(Identifier $tableName) { return 'ALTER TABLE ' . $tableName->getQuotedName($this); } /** * Returns the SQL clause for dropping a column in a table alteration. * * @param Column $column The column to drop. * * @return string */ protected function getAlterTableRemoveColumnClause(Column $column) { return 'DROP ' . $column->getQuotedName($this); } /** * Returns the SQL clause for renaming a column in a table alteration. * * @param string $oldColumnName The quoted name of the column to rename. * @param Column $column The column to rename to. * * @return string */ protected function getAlterTableRenameColumnClause($oldColumnName, Column $column) { $oldColumnName = new Identifier($oldColumnName); return 'RENAME ' . $oldColumnName->getQuotedName($this) . ' TO ' . $column->getQuotedName($this); } /** * Returns the SQL clause for renaming a table in a table alteration. * * @param Identifier $newTableName The quoted name of the table to rename to. * * @return string */ protected function getAlterTableRenameTableClause(Identifier $newTableName) { return 'RENAME ' . $newTableName->getQuotedName($this); } /** * Returns the SQL clause for altering a column in a table alteration. * * This method returns null in case that only the column comment has changed. * Changes in column comments have to be handled differently. * * @param ColumnDiff $columnDiff The diff of the column to alter. * * @return string|null */ protected function getAlterTableChangeColumnClause(ColumnDiff $columnDiff) { $column = $columnDiff->column; // Do not return alter clause if only comment has changed. if (! ($columnDiff->hasChanged('comment') && count($columnDiff->changedProperties) === 1)) { $columnAlterationClause = 'ALTER ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $column->toArray()); if ($columnDiff->hasChanged('default') && $column->getDefault() === null) { $columnAlterationClause .= ', ALTER ' . $column->getQuotedName($this) . ' DROP DEFAULT'; } return $columnAlterationClause; } return null; } /** * {@inheritdoc} */ public function getBigIntTypeDeclarationSQL(array $columnDef) { $columnDef['integer_type'] = 'BIGINT'; return $this->_getCommonIntegerTypeDeclarationSQL($columnDef); } /** * {@inheritdoc} */ public function getBinaryDefaultLength() { return 1; } /** * {@inheritdoc} */ public function getBinaryMaxLength() { return 32767; } /** * {@inheritdoc} */ public function getBlobTypeDeclarationSQL(array $field) { return 'LONG BINARY'; } /** * {@inheritdoc} * * BIT type columns require an explicit NULL declaration * in SQL Anywhere if they shall be nullable. * Otherwise by just omitting the NOT NULL clause, * SQL Anywhere will declare them NOT NULL nonetheless. */ public function getBooleanTypeDeclarationSQL(array $columnDef) { $nullClause = isset($columnDef['notnull']) && (bool) $columnDef['notnull'] === false ? ' NULL' : ''; return 'BIT' . $nullClause; } /** * {@inheritdoc} */ public function getClobTypeDeclarationSQL(array $field) { return 'TEXT'; } /** * {@inheritdoc} */ public function getCommentOnColumnSQL($tableName, $columnName, $comment) { $tableName = new Identifier($tableName); $columnName = new Identifier($columnName); $comment = $comment === null ? 'NULL' : $this->quoteStringLiteral($comment); return sprintf( 'COMMENT ON COLUMN %s.%s IS %s', $tableName->getQuotedName($this), $columnName->getQuotedName($this), $comment ); } /** * {@inheritdoc} */ public function getConcatExpression() { return 'STRING(' . implode(', ', (array) func_get_args()) . ')'; } /** * {@inheritdoc} */ public function getCreateConstraintSQL(Constraint $constraint, $table) { if ($constraint instanceof ForeignKeyConstraint) { return $this->getCreateForeignKeySQL($constraint, $table); } if ($table instanceof Table) { $table = $table->getQuotedName($this); } return 'ALTER TABLE ' . $table . ' ADD ' . $this->getTableConstraintDeclarationSQL($constraint, $constraint->getQuotedName($this)); } /** * {@inheritdoc} */ public function getCreateDatabaseSQL($database) { $database = new Identifier($database); return "CREATE DATABASE '" . $database->getName() . "'"; } /** * {@inheritdoc} * * Appends SQL Anywhere specific flags if given. */ public function getCreateIndexSQL(Index $index, $table) { return parent::getCreateIndexSQL($index, $table) . $this->getAdvancedIndexOptionsSQL($index); } /** * {@inheritdoc} */ public function getCreatePrimaryKeySQL(Index $index, $table) { if ($table instanceof Table) { $table = $table->getQuotedName($this); } return 'ALTER TABLE ' . $table . ' ADD ' . $this->getPrimaryKeyDeclarationSQL($index); } /** * {@inheritdoc} */ public function getCreateTemporaryTableSnippetSQL() { return 'CREATE ' . $this->getTemporaryTableSQL() . ' TABLE'; } /** * {@inheritdoc} */ public function getCreateViewSQL($name, $sql) { return 'CREATE VIEW ' . $name . ' AS ' . $sql; } /** * {@inheritdoc} */ public function getCurrentDateSQL() { return 'CURRENT DATE'; } /** * {@inheritdoc} */ public function getCurrentTimeSQL() { return 'CURRENT TIME'; } /** * {@inheritdoc} */ public function getCurrentTimestampSQL() { return 'CURRENT TIMESTAMP'; } /** * {@inheritdoc} */ protected function getDateArithmeticIntervalExpression($date, $operator, $interval, $unit) { $factorClause = ''; if ($operator === '-') { $factorClause = '-1 * '; } return 'DATEADD(' . $unit . ', ' . $factorClause . $interval . ', ' . $date . ')'; } /** * {@inheritdoc} */ public function getDateDiffExpression($date1, $date2) { return 'DATEDIFF(day, ' . $date2 . ', ' . $date1 . ')'; } /** * {@inheritdoc} */ public function getDateTimeFormatString() { return 'Y-m-d H:i:s.u'; } /** * {@inheritdoc} */ public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) { return 'DATETIME'; } /** * {@inheritdoc} */ public function getDateTimeTzFormatString() { return $this->getDateTimeFormatString(); } /** * {@inheritdoc} */ public function getDateTypeDeclarationSQL(array $fieldDeclaration) { return 'DATE'; } /** * {@inheritdoc} */ public function getDefaultTransactionIsolationLevel() { return TransactionIsolationLevel::READ_UNCOMMITTED; } /** * {@inheritdoc} */ public function getDropDatabaseSQL($database) { $database = new Identifier($database); return "DROP DATABASE '" . $database->getName() . "'"; } /** * {@inheritdoc} */ public function getDropIndexSQL($index, $table = null) { if ($index instanceof Index) { $index = $index->getQuotedName($this); } if (! is_string($index)) { throw new InvalidArgumentException( 'SQLAnywherePlatform::getDropIndexSQL() expects $index parameter to be string or ' . Index::class . '.' ); } if (! isset($table)) { return 'DROP INDEX ' . $index; } if ($table instanceof Table) { $table = $table->getQuotedName($this); } if (! is_string($table)) { throw new InvalidArgumentException( 'SQLAnywherePlatform::getDropIndexSQL() expects $table parameter to be string or ' . Index::class . '.' ); } return 'DROP INDEX ' . $table . '.' . $index; } /** * {@inheritdoc} */ public function getDropViewSQL($name) { return 'DROP VIEW ' . $name; } /** * {@inheritdoc} */ public function getForeignKeyBaseDeclarationSQL(ForeignKeyConstraint $foreignKey) { $sql = ''; $foreignKeyName = $foreignKey->getName(); $localColumns = $foreignKey->getQuotedLocalColumns($this); $foreignColumns = $foreignKey->getQuotedForeignColumns($this); $foreignTableName = $foreignKey->getQuotedForeignTableName($this); if (! empty($foreignKeyName)) { $sql .= 'CONSTRAINT ' . $foreignKey->getQuotedName($this) . ' '; } if (empty($localColumns)) { throw new InvalidArgumentException("Incomplete definition. 'local' required."); } if (empty($foreignColumns)) { throw new InvalidArgumentException("Incomplete definition. 'foreign' required."); } if (empty($foreignTableName)) { throw new InvalidArgumentException("Incomplete definition. 'foreignTable' required."); } if ($foreignKey->hasOption('notnull') && (bool) $foreignKey->getOption('notnull')) { $sql .= 'NOT NULL '; } return $sql . 'FOREIGN KEY (' . $this->getIndexFieldDeclarationListSQL($localColumns) . ') ' . 'REFERENCES ' . $foreignKey->getQuotedForeignTableName($this) . ' (' . $this->getIndexFieldDeclarationListSQL($foreignColumns) . ')'; } /** * Returns foreign key MATCH clause for given type. * * @param int $type The foreign key match type * * @return string * * @throws InvalidArgumentException If unknown match type given. */ public function getForeignKeyMatchClauseSQL($type) { switch ((int) $type) { case self::FOREIGN_KEY_MATCH_SIMPLE: return 'SIMPLE'; break; case self::FOREIGN_KEY_MATCH_FULL: return 'FULL'; break; case self::FOREIGN_KEY_MATCH_SIMPLE_UNIQUE: return 'UNIQUE SIMPLE'; break; case self::FOREIGN_KEY_MATCH_FULL_UNIQUE: return 'UNIQUE FULL'; default: throw new InvalidArgumentException('Invalid foreign key match type: ' . $type); } } /** * {@inheritdoc} */ public function getForeignKeyReferentialActionSQL($action) { // NO ACTION is not supported, therefore falling back to RESTRICT. if (strtoupper($action) === 'NO ACTION') { return 'RESTRICT'; } return parent::getForeignKeyReferentialActionSQL($action); } /** * {@inheritdoc} */ public function getForUpdateSQL() { return ''; } /** * {@inheritdoc} * * @deprecated Use application-generated UUIDs instead */ public function getGuidExpression() { return 'NEWID()'; } /** * {@inheritdoc} */ public function getGuidTypeDeclarationSQL(array $field) { return 'UNIQUEIDENTIFIER'; } /** * {@inheritdoc} */ public function getIndexDeclarationSQL($name, Index $index) { // Index declaration in statements like CREATE TABLE is not supported. throw DBALException::notSupported(__METHOD__); } /** * {@inheritdoc} */ public function getIntegerTypeDeclarationSQL(array $columnDef) { $columnDef['integer_type'] = 'INT'; return $this->_getCommonIntegerTypeDeclarationSQL($columnDef); } /** * {@inheritdoc} */ public function getListDatabasesSQL() { return 'SELECT db_name(number) AS name FROM sa_db_list()'; } /** * {@inheritdoc} */ public function getListTableColumnsSQL($table, $database = null) { $user = 'USER_NAME()'; if (strpos($table, '.') !== false) { [$user, $table] = explode('.', $table); $user = $this->quoteStringLiteral($user); } return sprintf( <<<'SQL' SELECT col.column_name, COALESCE(def.user_type_name, def.domain_name) AS 'type', def.declared_width AS 'length', def.scale, CHARINDEX('unsigned', def.domain_name) AS 'unsigned', IF col.nulls = 'Y' THEN 0 ELSE 1 ENDIF AS 'notnull', col."default", def.is_autoincrement AS 'autoincrement', rem.remarks AS 'comment' FROM sa_describe_query('SELECT * FROM "%s"') AS def JOIN SYS.SYSTABCOL AS col ON col.table_id = def.base_table_id AND col.column_id = def.base_column_id LEFT JOIN SYS.SYSREMARK AS rem ON col.object_id = rem.object_id WHERE def.base_owner_name = %s ORDER BY def.base_column_id ASC SQL , $table, $user ); } /** * {@inheritdoc} * * @todo Where is this used? Which information should be retrieved? */ public function getListTableConstraintsSQL($table) { $user = ''; if (strpos($table, '.') !== false) { [$user, $table] = explode('.', $table); $user = $this->quoteStringLiteral($user); $table = $this->quoteStringLiteral($table); } else { $table = $this->quoteStringLiteral($table); } return sprintf( <<<'SQL' SELECT con.* FROM SYS.SYSCONSTRAINT AS con JOIN SYS.SYSTAB AS tab ON con.table_object_id = tab.object_id WHERE tab.table_name = %s AND tab.creator = USER_ID(%s) SQL , $table, $user ); } /** * {@inheritdoc} */ public function getListTableForeignKeysSQL($table) { $user = ''; if (strpos($table, '.') !== false) { [$user, $table] = explode('.', $table); $user = $this->quoteStringLiteral($user); $table = $this->quoteStringLiteral($table); } else { $table = $this->quoteStringLiteral($table); } return sprintf( <<<'SQL' SELECT fcol.column_name AS local_column, ptbl.table_name AS foreign_table, pcol.column_name AS foreign_column, idx.index_name, IF fk.nulls = 'N' THEN 1 ELSE NULL ENDIF AS notnull, CASE ut.referential_action WHEN 'C' THEN 'CASCADE' WHEN 'D' THEN 'SET DEFAULT' WHEN 'N' THEN 'SET NULL' WHEN 'R' THEN 'RESTRICT' ELSE NULL END AS on_update, CASE dt.referential_action WHEN 'C' THEN 'CASCADE' WHEN 'D' THEN 'SET DEFAULT' WHEN 'N' THEN 'SET NULL' WHEN 'R' THEN 'RESTRICT' ELSE NULL END AS on_delete, IF fk.check_on_commit = 'Y' THEN 1 ELSE NULL ENDIF AS check_on_commit, -- check_on_commit flag IF ftbl.clustered_index_id = idx.index_id THEN 1 ELSE NULL ENDIF AS 'clustered', -- clustered flag IF fk.match_type = 0 THEN NULL ELSE fk.match_type ENDIF AS 'match', -- match option IF pidx.max_key_distance = 1 THEN 1 ELSE NULL ENDIF AS for_olap_workload -- for_olap_workload flag FROM SYS.SYSFKEY AS fk JOIN SYS.SYSIDX AS idx ON fk.foreign_table_id = idx.table_id AND fk.foreign_index_id = idx.index_id JOIN SYS.SYSPHYSIDX pidx ON idx.table_id = pidx.table_id AND idx.phys_index_id = pidx.phys_index_id JOIN SYS.SYSTAB AS ptbl ON fk.primary_table_id = ptbl.table_id JOIN SYS.SYSTAB AS ftbl ON fk.foreign_table_id = ftbl.table_id JOIN SYS.SYSIDXCOL AS idxcol ON idx.table_id = idxcol.table_id AND idx.index_id = idxcol.index_id JOIN SYS.SYSTABCOL AS pcol ON ptbl.table_id = pcol.table_id AND idxcol.primary_column_id = pcol.column_id JOIN SYS.SYSTABCOL AS fcol ON ftbl.table_id = fcol.table_id AND idxcol.column_id = fcol.column_id LEFT JOIN SYS.SYSTRIGGER ut ON fk.foreign_table_id = ut.foreign_table_id AND fk.foreign_index_id = ut.foreign_key_id AND ut.event = 'C' LEFT JOIN SYS.SYSTRIGGER dt ON fk.foreign_table_id = dt.foreign_table_id AND fk.foreign_index_id = dt.foreign_key_id AND dt.event = 'D' WHERE ftbl.table_name = %s AND ftbl.creator = USER_ID(%s) ORDER BY fk.foreign_index_id ASC, idxcol.sequence ASC SQL , $table, $user ); } /** * {@inheritdoc} */ public function getListTableIndexesSQL($table, $currentDatabase = null) { $user = ''; if (strpos($table, '.') !== false) { [$user, $table] = explode('.', $table); $user = $this->quoteStringLiteral($user); $table = $this->quoteStringLiteral($table); } else { $table = $this->quoteStringLiteral($table); } return sprintf( <<<'SQL' SELECT idx.index_name AS key_name, IF idx.index_category = 1 THEN 1 ELSE 0 ENDIF AS 'primary', col.column_name, IF idx."unique" IN(1, 2, 5) THEN 0 ELSE 1 ENDIF AS non_unique, IF tbl.clustered_index_id = idx.index_id THEN 1 ELSE NULL ENDIF AS 'clustered', -- clustered flag IF idx."unique" = 5 THEN 1 ELSE NULL ENDIF AS with_nulls_not_distinct, -- with_nulls_not_distinct flag IF pidx.max_key_distance = 1 THEN 1 ELSE NULL ENDIF AS for_olap_workload -- for_olap_workload flag FROM SYS.SYSIDX AS idx JOIN SYS.SYSPHYSIDX pidx ON idx.table_id = pidx.table_id AND idx.phys_index_id = pidx.phys_index_id JOIN SYS.SYSIDXCOL AS idxcol ON idx.table_id = idxcol.table_id AND idx.index_id = idxcol.index_id JOIN SYS.SYSTABCOL AS col ON idxcol.table_id = col.table_id AND idxcol.column_id = col.column_id JOIN SYS.SYSTAB AS tbl ON idx.table_id = tbl.table_id WHERE tbl.table_name = %s AND tbl.creator = USER_ID(%s) AND idx.index_category != 2 -- exclude indexes implicitly created by foreign key constraints ORDER BY idx.index_id ASC, idxcol.sequence ASC SQL , $table, $user ); } /** * {@inheritdoc} */ public function getListTablesSQL() { return "SELECT tbl.table_name FROM SYS.SYSTAB AS tbl JOIN SYS.SYSUSER AS usr ON tbl.creator = usr.user_id JOIN dbo.SYSOBJECTS AS obj ON tbl.object_id = obj.id WHERE tbl.table_type IN(1, 3) -- 'BASE', 'GBL TEMP' AND usr.user_name NOT IN('SYS', 'dbo', 'rs_systabgroup') -- exclude system users AND obj.type = 'U' -- user created tables only ORDER BY tbl.table_name ASC"; } /** * {@inheritdoc} * * @todo Where is this used? Which information should be retrieved? */ public function getListUsersSQL() { return 'SELECT * FROM SYS.SYSUSER ORDER BY user_name ASC'; } /** * {@inheritdoc} */ public function getListViewsSQL($database) { return "SELECT tbl.table_name, v.view_def FROM SYS.SYSVIEW v JOIN SYS.SYSTAB tbl ON v.view_object_id = tbl.object_id JOIN SYS.SYSUSER usr ON tbl.creator = usr.user_id JOIN dbo.SYSOBJECTS obj ON tbl.object_id = obj.id WHERE usr.user_name NOT IN('SYS', 'dbo', 'rs_systabgroup') -- exclude system users ORDER BY tbl.table_name ASC"; } /** * {@inheritdoc} */ public function getLocateExpression($str, $substr, $startPos = false) { if ($startPos === false) { return 'LOCATE(' . $str . ', ' . $substr . ')'; } return 'LOCATE(' . $str . ', ' . $substr . ', ' . $startPos . ')'; } /** * {@inheritdoc} */ public function getMaxIdentifierLength() { return 128; } /** * {@inheritdoc} */ public function getMd5Expression($column) { return 'HASH(' . $column . ", 'MD5')"; } /** * {@inheritdoc} */ public function getName() { return 'sqlanywhere'; } /** * Obtain DBMS specific SQL code portion needed to set a primary key * declaration to be used in statements like ALTER TABLE. * * @param Index $index Index definition * @param string $name Name of the primary key * * @return string DBMS specific SQL code portion needed to set a primary key * * @throws InvalidArgumentException If the given index is not a primary key. */ public function getPrimaryKeyDeclarationSQL(Index $index, $name = null) { if (! $index->isPrimary()) { throw new InvalidArgumentException( 'Can only create primary key declarations with getPrimaryKeyDeclarationSQL()' ); } return $this->getTableConstraintDeclarationSQL($index, $name); } /** * {@inheritdoc} */ public function getSetTransactionIsolationSQL($level) { return 'SET TEMPORARY OPTION isolation_level = ' . $this->_getTransactionIsolationLevelSQL($level); } /** * {@inheritdoc} */ public function getSmallIntTypeDeclarationSQL(array $columnDef) { $columnDef['integer_type'] = 'SMALLINT'; return $this->_getCommonIntegerTypeDeclarationSQL($columnDef); } /** * Returns the SQL statement for starting an existing database. * * In SQL Anywhere you can start and stop databases on a * database server instance. * This is a required statement after having created a new database * as it has to be explicitly started to be usable. * SQL Anywhere does not automatically start a database after creation! * * @param string $database Name of the database to start. * * @return string */ public function getStartDatabaseSQL($database) { $database = new Identifier($database); return "START DATABASE '" . $database->getName() . "' AUTOSTOP OFF"; } /** * Returns the SQL statement for stopping a running database. * * In SQL Anywhere you can start and stop databases on a * database server instance. * This is a required statement before dropping an existing database * as it has to be explicitly stopped before it can be dropped. * * @param string $database Name of the database to stop. * * @return string */ public function getStopDatabaseSQL($database) { $database = new Identifier($database); return 'STOP DATABASE "' . $database->getName() . '" UNCONDITIONALLY'; } /** * {@inheritdoc} */ public function getSubstringExpression($value, $from, $length = null) { if ($length === null) { return 'SUBSTRING(' . $value . ', ' . $from . ')'; } return 'SUBSTRING(' . $value . ', ' . $from . ', ' . $length . ')'; } /** * {@inheritdoc} */ public function getTemporaryTableSQL() { return 'GLOBAL TEMPORARY'; } /** * {@inheritdoc} */ public function getTimeFormatString() { return 'H:i:s.u'; } /** * {@inheritdoc} */ public function getTimeTypeDeclarationSQL(array $fieldDeclaration) { return 'TIME'; } /** * {@inheritdoc} */ public function getTrimExpression($str, $pos = TrimMode::UNSPECIFIED, $char = false) { if (! $char) { switch ($pos) { case TrimMode::LEADING: return $this->getLtrimExpression($str); case TrimMode::TRAILING: return $this->getRtrimExpression($str); default: return 'TRIM(' . $str . ')'; } } $pattern = "'%[^' + " . $char . " + ']%'"; switch ($pos) { case TrimMode::LEADING: return 'SUBSTR(' . $str . ', PATINDEX(' . $pattern . ', ' . $str . '))'; case TrimMode::TRAILING: return 'REVERSE(SUBSTR(REVERSE(' . $str . '), PATINDEX(' . $pattern . ', REVERSE(' . $str . '))))'; default: return 'REVERSE(SUBSTR(REVERSE(SUBSTR(' . $str . ', PATINDEX(' . $pattern . ', ' . $str . '))), ' . 'PATINDEX(' . $pattern . ', REVERSE(SUBSTR(' . $str . ', PATINDEX(' . $pattern . ', ' . $str . '))))))'; } } /** * {@inheritdoc} */ public function getTruncateTableSQL($tableName, $cascade = false) { $tableIdentifier = new Identifier($tableName); return 'TRUNCATE TABLE ' . $tableIdentifier->getQuotedName($this); } /** * {@inheritdoc} */ public function getUniqueConstraintDeclarationSQL($name, Index $index) { if ($index->isPrimary()) { throw new InvalidArgumentException( 'Cannot create primary key constraint declarations with getUniqueConstraintDeclarationSQL().' ); } if (! $index->isUnique()) { throw new InvalidArgumentException( 'Can only create unique constraint declarations, no common index declarations with ' . 'getUniqueConstraintDeclarationSQL().' ); } return $this->getTableConstraintDeclarationSQL($index, $name); } /** * {@inheritdoc} */ public function getVarcharDefaultLength() { return 1; } /** * {@inheritdoc} */ public function getVarcharMaxLength() { return 32767; } /** * {@inheritdoc} */ public function hasNativeGuidType() { return true; } /** * {@inheritdoc} */ public function prefersIdentityColumns() { return true; } /** * {@inheritdoc} */ public function supportsCommentOnStatement() { return true; } /** * {@inheritdoc} */ public function supportsIdentityColumns() { return true; } /** * {@inheritdoc} */ protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) { $unsigned = ! empty($columnDef['unsigned']) ? 'UNSIGNED ' : ''; $autoincrement = ! empty($columnDef['autoincrement']) ? ' IDENTITY' : ''; return $unsigned . $columnDef['integer_type'] . $autoincrement; } /** * {@inheritdoc} */ protected function _getCreateTableSQL($tableName, array $columns, array $options = []) { $columnListSql = $this->getColumnDeclarationListSQL($columns); $indexSql = []; if (! empty($options['uniqueConstraints'])) { foreach ((array) $options['uniqueConstraints'] as $name => $definition) { $columnListSql .= ', ' . $this->getUniqueConstraintDeclarationSQL($name, $definition); } } if (! empty($options['indexes'])) { /** @var Index $index */ foreach ((array) $options['indexes'] as $index) { $indexSql[] = $this->getCreateIndexSQL($index, $tableName); } } if (! empty($options['primary'])) { $flags = ''; if (isset($options['primary_index']) && $options['primary_index']->hasFlag('clustered')) { $flags = ' CLUSTERED '; } $columnListSql .= ', PRIMARY KEY' . $flags . ' (' . implode(', ', array_unique(array_values((array) $options['primary']))) . ')'; } if (! empty($options['foreignKeys'])) { foreach ((array) $options['foreignKeys'] as $definition) { $columnListSql .= ', ' . $this->getForeignKeyDeclarationSQL($definition); } } $query = 'CREATE TABLE ' . $tableName . ' (' . $columnListSql; $check = $this->getCheckDeclarationSQL($columns); if (! empty($check)) { $query .= ', ' . $check; } $query .= ')'; return array_merge([$query], $indexSql); } /** * {@inheritdoc} */ protected function _getTransactionIsolationLevelSQL($level) { switch ($level) { case TransactionIsolationLevel::READ_UNCOMMITTED: return 0; case TransactionIsolationLevel::READ_COMMITTED: return 1; case TransactionIsolationLevel::REPEATABLE_READ: return 2; case TransactionIsolationLevel::SERIALIZABLE: return 3; default: throw new InvalidArgumentException('Invalid isolation level:' . $level); } } /** * {@inheritdoc} */ protected function doModifyLimitQuery($query, $limit, $offset) { $limitOffsetClause = $this->getTopClauseSQL($limit, $offset); if ($limitOffsetClause === '') { return $query; } if (! preg_match('/^\s*(SELECT\s+(DISTINCT\s+)?)(.*)/i', $query, $matches)) { return $query; } return $matches[1] . $limitOffsetClause . ' ' . $matches[3]; } private function getTopClauseSQL(?int $limit, ?int $offset) : string { if ($offset > 0) { return sprintf('TOP %s START AT %d', $limit ?? 'ALL', $offset + 1); } return $limit === null ? '' : 'TOP ' . $limit; } /** * Return the INDEX query section dealing with non-standard * SQL Anywhere options. * * @param Index $index Index definition * * @return string */ protected function getAdvancedIndexOptionsSQL(Index $index) { $sql = ''; if (! $index->isPrimary() && $index->hasFlag('for_olap_workload')) { $sql .= ' FOR OLAP WORKLOAD'; } return $sql; } /** * {@inheritdoc} */ protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed) { return $fixed ? 'BINARY(' . ($length ?: $this->getBinaryDefaultLength()) . ')' : 'VARBINARY(' . ($length ?: $this->getBinaryDefaultLength()) . ')'; } /** * Returns the SQL snippet for creating a table constraint. * * @param Constraint $constraint The table constraint to create the SQL snippet for. * @param string|null $name The table constraint name to use if any. * * @return string * * @throws InvalidArgumentException If the given table constraint type is not supported by this method. */ protected function getTableConstraintDeclarationSQL(Constraint $constraint, $name = null) { if ($constraint instanceof ForeignKeyConstraint) { return $this->getForeignKeyDeclarationSQL($constraint); } if (! $constraint instanceof Index) { throw new InvalidArgumentException('Unsupported constraint type: ' . get_class($constraint)); } if (! $constraint->isPrimary() && ! $constraint->isUnique()) { throw new InvalidArgumentException( 'Can only create primary, unique or foreign key constraint declarations, no common index declarations ' . 'with getTableConstraintDeclarationSQL().' ); } $constraintColumns = $constraint->getQuotedColumns($this); if (empty($constraintColumns)) { throw new InvalidArgumentException("Incomplete definition. 'columns' required."); } $sql = ''; $flags = ''; if (! empty($name)) { $name = new Identifier($name); $sql .= 'CONSTRAINT ' . $name->getQuotedName($this) . ' '; } if ($constraint->hasFlag('clustered')) { $flags = 'CLUSTERED '; } if ($constraint->isPrimary()) { return $sql . 'PRIMARY KEY ' . $flags . '(' . $this->getIndexFieldDeclarationListSQL($constraintColumns) . ')'; } return $sql . 'UNIQUE ' . $flags . '(' . $this->getIndexFieldDeclarationListSQL($constraintColumns) . ')'; } /** * {@inheritdoc} */ protected function getCreateIndexSQLFlags(Index $index) { $type = ''; if ($index->hasFlag('virtual')) { $type .= 'VIRTUAL '; } if ($index->isUnique()) { $type .= 'UNIQUE '; } if ($index->hasFlag('clustered')) { $type .= 'CLUSTERED '; } return $type; } /** * {@inheritdoc} */ protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName) { return ['ALTER INDEX ' . $oldIndexName . ' ON ' . $tableName . ' RENAME TO ' . $index->getQuotedName($this)]; } /** * {@inheritdoc} */ protected function getReservedKeywordsClass() { return Keywords\SQLAnywhereKeywords::class; } /** * {@inheritdoc} */ protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) { return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(' . $this->getVarcharDefaultLength() . ')') : ($length ? 'VARCHAR(' . $length . ')' : 'VARCHAR(' . $this->getVarcharDefaultLength() . ')'); } /** * {@inheritdoc} */ protected function initializeDoctrineTypeMappings() { $this->doctrineTypeMapping = [ 'char' => 'string', 'long nvarchar' => 'text', 'long varchar' => 'text', 'nchar' => 'string', 'ntext' => 'text', 'nvarchar' => 'string', 'text' => 'text', 'uniqueidentifierstr' => 'guid', 'varchar' => 'string', 'xml' => 'text', 'bigint' => 'bigint', 'unsigned bigint' => 'bigint', 'bit' => 'boolean', 'decimal' => 'decimal', 'double' => 'float', 'float' => 'float', 'int' => 'integer', 'integer' => 'integer', 'unsigned int' => 'integer', 'numeric' => 'decimal', 'smallint' => 'smallint', 'unsigned smallint' => 'smallint', 'tinyint' => 'smallint', 'unsigned tinyint' => 'smallint', 'money' => 'decimal', 'smallmoney' => 'decimal', 'long varbit' => 'text', 'varbit' => 'string', 'date' => 'date', 'datetime' => 'datetime', 'smalldatetime' => 'datetime', 'time' => 'time', 'timestamp' => 'datetime', 'binary' => 'binary', 'image' => 'blob', 'long binary' => 'blob', 'uniqueidentifier' => 'guid', 'varbinary' => 'binary', ]; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Platforms/SQLAzurePlatform.php000066400000000000000000000016351360544566000257570ustar00rootroot00000000000000hasOption('azure.federatedOnColumnName')) { $distributionName = $table->getOption('azure.federatedOnDistributionName'); $columnName = $table->getOption('azure.federatedOnColumnName'); $stmt = ' FEDERATED ON (' . $distributionName . ' = ' . $columnName . ')'; $sql[0] .= $stmt; } return $sql; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Platforms/SQLServer2005Platform.php000066400000000000000000000022131360544566000264370ustar00rootroot00000000000000doctrineTypeMapping['datetime2'] = 'datetime'; $this->doctrineTypeMapping['date'] = 'date'; $this->doctrineTypeMapping['time'] = 'time'; $this->doctrineTypeMapping['datetimeoffset'] = 'datetimetz'; } /** * {@inheritdoc} * * Returns Microsoft SQL Server 2008 specific keywords class */ protected function getReservedKeywordsClass() { return Keywords\SQLServer2008Keywords::class; } protected function getLikeWildcardCharacters() : string { return parent::getLikeWildcardCharacters() . '[]^'; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Platforms/SQLServer2012Platform.php000066400000000000000000000106761360544566000264510ustar00rootroot00000000000000getQuotedName($this) . ' INCREMENT BY ' . $sequence->getAllocationSize(); } /** * {@inheritdoc} */ public function getCreateSequenceSQL(Sequence $sequence) { return 'CREATE SEQUENCE ' . $sequence->getQuotedName($this) . ' START WITH ' . $sequence->getInitialValue() . ' INCREMENT BY ' . $sequence->getAllocationSize() . ' MINVALUE ' . $sequence->getInitialValue(); } /** * {@inheritdoc} */ public function getDropSequenceSQL($sequence) { if ($sequence instanceof Sequence) { $sequence = $sequence->getQuotedName($this); } return 'DROP SEQUENCE ' . $sequence; } /** * {@inheritdoc} */ public function getListSequencesSQL($database) { return 'SELECT seq.name, CAST( seq.increment AS VARCHAR(MAX) ) AS increment, -- CAST avoids driver error for sql_variant type CAST( seq.start_value AS VARCHAR(MAX) ) AS start_value -- CAST avoids driver error for sql_variant type FROM sys.sequences AS seq'; } /** * {@inheritdoc} */ public function getSequenceNextValSQL($sequenceName) { return 'SELECT NEXT VALUE FOR ' . $sequenceName; } /** * {@inheritdoc} */ public function supportsSequences() { return true; } /** * {@inheritdoc} * * Returns Microsoft SQL Server 2012 specific keywords class */ protected function getReservedKeywordsClass() { return Keywords\SQLServer2012Keywords::class; } /** * {@inheritdoc} */ protected function doModifyLimitQuery($query, $limit, $offset = null) { if ($limit === null && $offset <= 0) { return $query; } // Queries using OFFSET... FETCH MUST have an ORDER BY clause // Find the position of the last instance of ORDER BY and ensure it is not within a parenthetical statement // but can be in a newline $matches = []; $matchesCount = preg_match_all('/[\\s]+order\\s+by\\s/im', $query, $matches, PREG_OFFSET_CAPTURE); $orderByPos = false; if ($matchesCount > 0) { $orderByPos = $matches[0][($matchesCount - 1)][1]; } if ($orderByPos === false || substr_count($query, '(', $orderByPos) - substr_count($query, ')', $orderByPos) ) { if (preg_match('/^SELECT\s+DISTINCT/im', $query)) { // SQL Server won't let us order by a non-selected column in a DISTINCT query, // so we have to do this madness. This says, order by the first column in the // result. SQL Server's docs say that a nonordered query's result order is non- // deterministic anyway, so this won't do anything that a bunch of update and // deletes to the table wouldn't do anyway. $query .= ' ORDER BY 1'; } else { // In another DBMS, we could do ORDER BY 0, but SQL Server gets angry if you // use constant expressions in the order by list. $query .= ' ORDER BY (SELECT 0)'; } } if ($offset === null) { $offset = 0; } // This looks somewhat like MYSQL, but limit/offset are in inverse positions // Supposedly SQL:2008 core standard. // Per TSQL spec, FETCH NEXT n ROWS ONLY is not valid without OFFSET n ROWS. $query .= ' OFFSET ' . (int) $offset . ' ROWS'; if ($limit !== null) { $query .= ' FETCH NEXT ' . (int) $limit . ' ROWS ONLY'; } return $query; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php000066400000000000000000001505701360544566000261420ustar00rootroot00000000000000getConvertExpression('date', 'GETDATE()'); } /** * {@inheritdoc} */ public function getCurrentTimeSQL() { return $this->getConvertExpression('time', 'GETDATE()'); } /** * Returns an expression that converts an expression of one data type to another. * * @param string $dataType The target native data type. Alias data types cannot be used. * @param string $expression The SQL expression to convert. * * @return string */ private function getConvertExpression($dataType, $expression) { return sprintf('CONVERT(%s, %s)', $dataType, $expression); } /** * {@inheritdoc} */ protected function getDateArithmeticIntervalExpression($date, $operator, $interval, $unit) { $factorClause = ''; if ($operator === '-') { $factorClause = '-1 * '; } return 'DATEADD(' . $unit . ', ' . $factorClause . $interval . ', ' . $date . ')'; } /** * {@inheritDoc} */ public function getDateDiffExpression($date1, $date2) { return 'DATEDIFF(day, ' . $date2 . ',' . $date1 . ')'; } /** * {@inheritDoc} * * Microsoft SQL Server prefers "autoincrement" identity columns * since sequences can only be emulated with a table. */ public function prefersIdentityColumns() { return true; } /** * {@inheritDoc} * * Microsoft SQL Server supports this through AUTO_INCREMENT columns. */ public function supportsIdentityColumns() { return true; } /** * {@inheritDoc} */ public function supportsReleaseSavepoints() { return false; } /** * {@inheritdoc} */ public function supportsSchemas() { return true; } /** * {@inheritdoc} */ public function getDefaultSchemaName() { return 'dbo'; } /** * {@inheritDoc} */ public function supportsColumnCollation() { return true; } /** * {@inheritDoc} */ public function hasNativeGuidType() { return true; } /** * {@inheritDoc} */ public function getCreateDatabaseSQL($name) { return 'CREATE DATABASE ' . $name; } /** * {@inheritDoc} */ public function getDropDatabaseSQL($name) { return 'DROP DATABASE ' . $name; } /** * {@inheritDoc} */ public function supportsCreateDropDatabase() { return true; } /** * {@inheritDoc} */ public function getCreateSchemaSQL($schemaName) { return 'CREATE SCHEMA ' . $schemaName; } /** * {@inheritDoc} */ public function getDropForeignKeySQL($foreignKey, $table) { if (! $foreignKey instanceof ForeignKeyConstraint) { $foreignKey = new Identifier($foreignKey); } if (! $table instanceof Table) { $table = new Identifier($table); } $foreignKey = $foreignKey->getQuotedName($this); $table = $table->getQuotedName($this); return 'ALTER TABLE ' . $table . ' DROP CONSTRAINT ' . $foreignKey; } /** * {@inheritDoc} */ public function getDropIndexSQL($index, $table = null) { if ($index instanceof Index) { $index = $index->getQuotedName($this); } elseif (! is_string($index)) { throw new InvalidArgumentException('AbstractPlatform::getDropIndexSQL() expects $index parameter to be string or \Doctrine\DBAL\Schema\Index.'); } if (! isset($table)) { return 'DROP INDEX ' . $index; } if ($table instanceof Table) { $table = $table->getQuotedName($this); } return sprintf( <<getCommentOnTableSQL($tableName, $tableComment); } // @todo does other code breaks because of this? // force primary keys to be not null foreach ($columns as &$column) { if (isset($column['primary']) && $column['primary']) { $column['notnull'] = true; } // Build default constraints SQL statements. if (isset($column['default'])) { $defaultConstraintsSql[] = 'ALTER TABLE ' . $tableName . ' ADD' . $this->getDefaultConstraintDeclarationSQL($tableName, $column); } if (empty($column['comment']) && ! is_numeric($column['comment'])) { continue; } $commentsSql[] = $this->getCreateColumnCommentSQL($tableName, $column['name'], $column['comment']); } $columnListSql = $this->getColumnDeclarationListSQL($columns); if (isset($options['uniqueConstraints']) && ! empty($options['uniqueConstraints'])) { foreach ($options['uniqueConstraints'] as $name => $definition) { $columnListSql .= ', ' . $this->getUniqueConstraintDeclarationSQL($name, $definition); } } if (isset($options['primary']) && ! empty($options['primary'])) { $flags = ''; if (isset($options['primary_index']) && $options['primary_index']->hasFlag('nonclustered')) { $flags = ' NONCLUSTERED'; } $columnListSql .= ', PRIMARY KEY' . $flags . ' (' . implode(', ', array_unique(array_values($options['primary']))) . ')'; } $query = 'CREATE TABLE ' . $tableName . ' (' . $columnListSql; $check = $this->getCheckDeclarationSQL($columns); if (! empty($check)) { $query .= ', ' . $check; } $query .= ')'; $sql = [$query]; if (isset($options['indexes']) && ! empty($options['indexes'])) { foreach ($options['indexes'] as $index) { $sql[] = $this->getCreateIndexSQL($index, $tableName); } } if (isset($options['foreignKeys'])) { foreach ((array) $options['foreignKeys'] as $definition) { $sql[] = $this->getCreateForeignKeySQL($definition, $tableName); } } return array_merge($sql, $commentsSql, $defaultConstraintsSql); } /** * {@inheritDoc} */ public function getCreatePrimaryKeySQL(Index $index, $table) { if ($table instanceof Table) { $identifier = $table->getQuotedName($this); } else { $identifier = $table; } $sql = 'ALTER TABLE ' . $identifier . ' ADD PRIMARY KEY'; if ($index->hasFlag('nonclustered')) { $sql .= ' NONCLUSTERED'; } return $sql . ' (' . $this->getIndexFieldDeclarationListSQL($index) . ')'; } /** * Returns the SQL statement for creating a column comment. * * SQL Server does not support native column comments, * therefore the extended properties functionality is used * as a workaround to store them. * The property name used to store column comments is "MS_Description" * which provides compatibility with SQL Server Management Studio, * as column comments are stored in the same property there when * specifying a column's "Description" attribute. * * @param string $tableName The quoted table name to which the column belongs. * @param string $columnName The quoted column name to create the comment for. * @param string|null $comment The column's comment. * * @return string */ protected function getCreateColumnCommentSQL($tableName, $columnName, $comment) { if (strpos($tableName, '.') !== false) { [$schemaSQL, $tableSQL] = explode('.', $tableName); $schemaSQL = $this->quoteStringLiteral($schemaSQL); $tableSQL = $this->quoteStringLiteral($tableSQL); } else { $schemaSQL = "'dbo'"; $tableSQL = $this->quoteStringLiteral($tableName); } return $this->getAddExtendedPropertySQL( 'MS_Description', $comment, 'SCHEMA', $schemaSQL, 'TABLE', $tableSQL, 'COLUMN', $columnName ); } /** * Returns the SQL snippet for declaring a default constraint. * * @param string $table Name of the table to return the default constraint declaration for. * @param mixed[] $column Column definition. * * @return string * * @throws InvalidArgumentException */ public function getDefaultConstraintDeclarationSQL($table, array $column) { if (! isset($column['default'])) { throw new InvalidArgumentException("Incomplete column definition. 'default' required."); } $columnName = new Identifier($column['name']); return ' CONSTRAINT ' . $this->generateDefaultConstraintName($table, $column['name']) . $this->getDefaultValueDeclarationSQL($column) . ' FOR ' . $columnName->getQuotedName($this); } /** * {@inheritDoc} */ public function getUniqueConstraintDeclarationSQL($name, Index $index) { $constraint = parent::getUniqueConstraintDeclarationSQL($name, $index); $constraint = $this->_appendUniqueConstraintDefinition($constraint, $index); return $constraint; } /** * {@inheritDoc} */ public function getCreateIndexSQL(Index $index, $table) { $constraint = parent::getCreateIndexSQL($index, $table); if ($index->isUnique() && ! $index->isPrimary()) { $constraint = $this->_appendUniqueConstraintDefinition($constraint, $index); } return $constraint; } /** * {@inheritDoc} */ protected function getCreateIndexSQLFlags(Index $index) { $type = ''; if ($index->isUnique()) { $type .= 'UNIQUE '; } if ($index->hasFlag('clustered')) { $type .= 'CLUSTERED '; } elseif ($index->hasFlag('nonclustered')) { $type .= 'NONCLUSTERED '; } return $type; } /** * Extend unique key constraint with required filters * * @param string $sql * * @return string */ private function _appendUniqueConstraintDefinition($sql, Index $index) { $fields = []; foreach ($index->getQuotedColumns($this) as $field) { $fields[] = $field . ' IS NOT NULL'; } return $sql . ' WHERE ' . implode(' AND ', $fields); } /** * {@inheritDoc} */ public function getAlterTableSQL(TableDiff $diff) { $queryParts = []; $sql = []; $columnSql = []; $commentsSql = []; foreach ($diff->addedColumns as $column) { if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) { continue; } $columnDef = $column->toArray(); $queryParts[] = 'ADD ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnDef); if (isset($columnDef['default'])) { $queryParts[] = $this->getAlterTableAddDefaultConstraintClause($diff->name, $column); } $comment = $this->getColumnComment($column); if (empty($comment) && ! is_numeric($comment)) { continue; } $commentsSql[] = $this->getCreateColumnCommentSQL( $diff->name, $column->getQuotedName($this), $comment ); } foreach ($diff->removedColumns as $column) { if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) { continue; } $queryParts[] = 'DROP COLUMN ' . $column->getQuotedName($this); } foreach ($diff->changedColumns as $columnDiff) { if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) { continue; } $column = $columnDiff->column; $comment = $this->getColumnComment($column); $hasComment = ! empty($comment) || is_numeric($comment); if ($columnDiff->fromColumn instanceof Column) { $fromComment = $this->getColumnComment($columnDiff->fromColumn); $hasFromComment = ! empty($fromComment) || is_numeric($fromComment); if ($hasFromComment && $hasComment && $fromComment !== $comment) { $commentsSql[] = $this->getAlterColumnCommentSQL( $diff->name, $column->getQuotedName($this), $comment ); } elseif ($hasFromComment && ! $hasComment) { $commentsSql[] = $this->getDropColumnCommentSQL($diff->name, $column->getQuotedName($this)); } elseif ($hasComment) { $commentsSql[] = $this->getCreateColumnCommentSQL( $diff->name, $column->getQuotedName($this), $comment ); } } // Do not add query part if only comment has changed. if ($columnDiff->hasChanged('comment') && count($columnDiff->changedProperties) === 1) { continue; } $requireDropDefaultConstraint = $this->alterColumnRequiresDropDefaultConstraint($columnDiff); if ($requireDropDefaultConstraint) { $queryParts[] = $this->getAlterTableDropDefaultConstraintClause( $diff->name, $columnDiff->oldColumnName ); } $columnDef = $column->toArray(); $queryParts[] = 'ALTER COLUMN ' . $this->getColumnDeclarationSQL($column->getQuotedName($this), $columnDef); if (! isset($columnDef['default']) || (! $requireDropDefaultConstraint && ! $columnDiff->hasChanged('default'))) { continue; } $queryParts[] = $this->getAlterTableAddDefaultConstraintClause($diff->name, $column); } foreach ($diff->renamedColumns as $oldColumnName => $column) { if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) { continue; } $oldColumnName = new Identifier($oldColumnName); $sql[] = "sp_RENAME '" . $diff->getName($this)->getQuotedName($this) . '.' . $oldColumnName->getQuotedName($this) . "', '" . $column->getQuotedName($this) . "', 'COLUMN'"; // Recreate default constraint with new column name if necessary (for future reference). if ($column->getDefault() === null) { continue; } $queryParts[] = $this->getAlterTableDropDefaultConstraintClause( $diff->name, $oldColumnName->getQuotedName($this) ); $queryParts[] = $this->getAlterTableAddDefaultConstraintClause($diff->name, $column); } $tableSql = []; if ($this->onSchemaAlterTable($diff, $tableSql)) { return array_merge($tableSql, $columnSql); } foreach ($queryParts as $query) { $sql[] = 'ALTER TABLE ' . $diff->getName($this)->getQuotedName($this) . ' ' . $query; } $sql = array_merge($sql, $commentsSql); $newName = $diff->getNewName(); if ($newName !== false) { $sql[] = "sp_RENAME '" . $diff->getName($this)->getQuotedName($this) . "', '" . $newName->getName() . "'"; /** * Rename table's default constraints names * to match the new table name. * This is necessary to ensure that the default * constraints can be referenced in future table * alterations as the table name is encoded in * default constraints' names. */ $sql[] = "DECLARE @sql NVARCHAR(MAX) = N''; " . "SELECT @sql += N'EXEC sp_rename N''' + dc.name + ''', N''' " . "+ REPLACE(dc.name, '" . $this->generateIdentifierName($diff->name) . "', " . "'" . $this->generateIdentifierName($newName->getName()) . "') + ''', ''OBJECT'';' " . 'FROM sys.default_constraints dc ' . 'JOIN sys.tables tbl ON dc.parent_object_id = tbl.object_id ' . "WHERE tbl.name = '" . $newName->getName() . "';" . 'EXEC sp_executesql @sql'; } $sql = array_merge( $this->getPreAlterTableIndexForeignKeySQL($diff), $sql, $this->getPostAlterTableIndexForeignKeySQL($diff) ); return array_merge($sql, $tableSql, $columnSql); } /** * Returns the SQL clause for adding a default constraint in an ALTER TABLE statement. * * @param string $tableName The name of the table to generate the clause for. * @param Column $column The column to generate the clause for. * * @return string */ private function getAlterTableAddDefaultConstraintClause($tableName, Column $column) { $columnDef = $column->toArray(); $columnDef['name'] = $column->getQuotedName($this); return 'ADD' . $this->getDefaultConstraintDeclarationSQL($tableName, $columnDef); } /** * Returns the SQL clause for dropping an existing default constraint in an ALTER TABLE statement. * * @param string $tableName The name of the table to generate the clause for. * @param string $columnName The name of the column to generate the clause for. * * @return string */ private function getAlterTableDropDefaultConstraintClause($tableName, $columnName) { return 'DROP CONSTRAINT ' . $this->generateDefaultConstraintName($tableName, $columnName); } /** * Checks whether a column alteration requires dropping its default constraint first. * * Different to other database vendors SQL Server implements column default values * as constraints and therefore changes in a column's default value as well as changes * in a column's type require dropping the default constraint first before being to * alter the particular column to the new definition. * * @param ColumnDiff $columnDiff The column diff to evaluate. * * @return bool True if the column alteration requires dropping its default constraint first, false otherwise. */ private function alterColumnRequiresDropDefaultConstraint(ColumnDiff $columnDiff) { // We can only decide whether to drop an existing default constraint // if we know the original default value. if (! $columnDiff->fromColumn instanceof Column) { return false; } // We only need to drop an existing default constraint if we know the // column was defined with a default value before. if ($columnDiff->fromColumn->getDefault() === null) { return false; } // We need to drop an existing default constraint if the column was // defined with a default value before and it has changed. if ($columnDiff->hasChanged('default')) { return true; } // We need to drop an existing default constraint if the column was // defined with a default value before and the native column type has changed. return $columnDiff->hasChanged('type') || $columnDiff->hasChanged('fixed'); } /** * Returns the SQL statement for altering a column comment. * * SQL Server does not support native column comments, * therefore the extended properties functionality is used * as a workaround to store them. * The property name used to store column comments is "MS_Description" * which provides compatibility with SQL Server Management Studio, * as column comments are stored in the same property there when * specifying a column's "Description" attribute. * * @param string $tableName The quoted table name to which the column belongs. * @param string $columnName The quoted column name to alter the comment for. * @param string|null $comment The column's comment. * * @return string */ protected function getAlterColumnCommentSQL($tableName, $columnName, $comment) { if (strpos($tableName, '.') !== false) { [$schemaSQL, $tableSQL] = explode('.', $tableName); $schemaSQL = $this->quoteStringLiteral($schemaSQL); $tableSQL = $this->quoteStringLiteral($tableSQL); } else { $schemaSQL = "'dbo'"; $tableSQL = $this->quoteStringLiteral($tableName); } return $this->getUpdateExtendedPropertySQL( 'MS_Description', $comment, 'SCHEMA', $schemaSQL, 'TABLE', $tableSQL, 'COLUMN', $columnName ); } /** * Returns the SQL statement for dropping a column comment. * * SQL Server does not support native column comments, * therefore the extended properties functionality is used * as a workaround to store them. * The property name used to store column comments is "MS_Description" * which provides compatibility with SQL Server Management Studio, * as column comments are stored in the same property there when * specifying a column's "Description" attribute. * * @param string $tableName The quoted table name to which the column belongs. * @param string $columnName The quoted column name to drop the comment for. * * @return string */ protected function getDropColumnCommentSQL($tableName, $columnName) { if (strpos($tableName, '.') !== false) { [$schemaSQL, $tableSQL] = explode('.', $tableName); $schemaSQL = $this->quoteStringLiteral($schemaSQL); $tableSQL = $this->quoteStringLiteral($tableSQL); } else { $schemaSQL = "'dbo'"; $tableSQL = $this->quoteStringLiteral($tableName); } return $this->getDropExtendedPropertySQL( 'MS_Description', 'SCHEMA', $schemaSQL, 'TABLE', $tableSQL, 'COLUMN', $columnName ); } /** * {@inheritdoc} */ protected function getRenameIndexSQL($oldIndexName, Index $index, $tableName) { return [sprintf( "EXEC sp_RENAME N'%s.%s', N'%s', N'INDEX'", $tableName, $oldIndexName, $index->getQuotedName($this) ), ]; } /** * Returns the SQL statement for adding an extended property to a database object. * * @link http://msdn.microsoft.com/en-us/library/ms180047%28v=sql.90%29.aspx * * @param string $name The name of the property to add. * @param string|null $value The value of the property to add. * @param string|null $level0Type The type of the object at level 0 the property belongs to. * @param string|null $level0Name The name of the object at level 0 the property belongs to. * @param string|null $level1Type The type of the object at level 1 the property belongs to. * @param string|null $level1Name The name of the object at level 1 the property belongs to. * @param string|null $level2Type The type of the object at level 2 the property belongs to. * @param string|null $level2Name The name of the object at level 2 the property belongs to. * * @return string */ public function getAddExtendedPropertySQL( $name, $value = null, $level0Type = null, $level0Name = null, $level1Type = null, $level1Name = null, $level2Type = null, $level2Name = null ) { return 'EXEC sp_addextendedproperty ' . 'N' . $this->quoteStringLiteral($name) . ', N' . $this->quoteStringLiteral((string) $value) . ', ' . 'N' . $this->quoteStringLiteral((string) $level0Type) . ', ' . $level0Name . ', ' . 'N' . $this->quoteStringLiteral((string) $level1Type) . ', ' . $level1Name . ', ' . 'N' . $this->quoteStringLiteral((string) $level2Type) . ', ' . $level2Name; } /** * Returns the SQL statement for dropping an extended property from a database object. * * @link http://technet.microsoft.com/en-gb/library/ms178595%28v=sql.90%29.aspx * * @param string $name The name of the property to drop. * @param string|null $level0Type The type of the object at level 0 the property belongs to. * @param string|null $level0Name The name of the object at level 0 the property belongs to. * @param string|null $level1Type The type of the object at level 1 the property belongs to. * @param string|null $level1Name The name of the object at level 1 the property belongs to. * @param string|null $level2Type The type of the object at level 2 the property belongs to. * @param string|null $level2Name The name of the object at level 2 the property belongs to. * * @return string */ public function getDropExtendedPropertySQL( $name, $level0Type = null, $level0Name = null, $level1Type = null, $level1Name = null, $level2Type = null, $level2Name = null ) { return 'EXEC sp_dropextendedproperty ' . 'N' . $this->quoteStringLiteral($name) . ', ' . 'N' . $this->quoteStringLiteral((string) $level0Type) . ', ' . $level0Name . ', ' . 'N' . $this->quoteStringLiteral((string) $level1Type) . ', ' . $level1Name . ', ' . 'N' . $this->quoteStringLiteral((string) $level2Type) . ', ' . $level2Name; } /** * Returns the SQL statement for updating an extended property of a database object. * * @link http://msdn.microsoft.com/en-us/library/ms186885%28v=sql.90%29.aspx * * @param string $name The name of the property to update. * @param string|null $value The value of the property to update. * @param string|null $level0Type The type of the object at level 0 the property belongs to. * @param string|null $level0Name The name of the object at level 0 the property belongs to. * @param string|null $level1Type The type of the object at level 1 the property belongs to. * @param string|null $level1Name The name of the object at level 1 the property belongs to. * @param string|null $level2Type The type of the object at level 2 the property belongs to. * @param string|null $level2Name The name of the object at level 2 the property belongs to. * * @return string */ public function getUpdateExtendedPropertySQL( $name, $value = null, $level0Type = null, $level0Name = null, $level1Type = null, $level1Name = null, $level2Type = null, $level2Name = null ) { return 'EXEC sp_updateextendedproperty ' . 'N' . $this->quoteStringLiteral($name) . ', N' . $this->quoteStringLiteral((string) $value) . ', ' . 'N' . $this->quoteStringLiteral((string) $level0Type) . ', ' . $level0Name . ', ' . 'N' . $this->quoteStringLiteral((string) $level1Type) . ', ' . $level1Name . ', ' . 'N' . $this->quoteStringLiteral((string) $level2Type) . ', ' . $level2Name; } /** * {@inheritDoc} */ public function getEmptyIdentityInsertSQL($quotedTableName, $quotedIdentifierColumnName) { return 'INSERT INTO ' . $quotedTableName . ' DEFAULT VALUES'; } /** * {@inheritDoc} */ public function getListTablesSQL() { // "sysdiagrams" table must be ignored as it's internal SQL Server table for Database Diagrams // Category 2 must be ignored as it is "MS SQL Server 'pseudo-system' object[s]" for replication return "SELECT name FROM sysobjects WHERE type = 'U' AND name != 'sysdiagrams' AND category != 2 ORDER BY name"; } /** * {@inheritDoc} */ public function getListTableColumnsSQL($table, $database = null) { return "SELECT col.name, type.name AS type, col.max_length AS length, ~col.is_nullable AS notnull, def.definition AS [default], col.scale, col.precision, col.is_identity AS autoincrement, col.collation_name AS collation, CAST(prop.value AS NVARCHAR(MAX)) AS comment -- CAST avoids driver error for sql_variant type FROM sys.columns AS col JOIN sys.types AS type ON col.user_type_id = type.user_type_id JOIN sys.objects AS obj ON col.object_id = obj.object_id JOIN sys.schemas AS scm ON obj.schema_id = scm.schema_id LEFT JOIN sys.default_constraints def ON col.default_object_id = def.object_id AND col.object_id = def.parent_object_id LEFT JOIN sys.extended_properties AS prop ON obj.object_id = prop.major_id AND col.column_id = prop.minor_id AND prop.name = 'MS_Description' WHERE obj.type = 'U' AND " . $this->getTableWhereClause($table, 'scm.name', 'obj.name'); } /** * {@inheritDoc} */ public function getListTableForeignKeysSQL($table, $database = null) { return 'SELECT f.name AS ForeignKey, SCHEMA_NAME (f.SCHEMA_ID) AS SchemaName, OBJECT_NAME (f.parent_object_id) AS TableName, COL_NAME (fc.parent_object_id,fc.parent_column_id) AS ColumnName, SCHEMA_NAME (o.SCHEMA_ID) ReferenceSchemaName, OBJECT_NAME (f.referenced_object_id) AS ReferenceTableName, COL_NAME(fc.referenced_object_id,fc.referenced_column_id) AS ReferenceColumnName, f.delete_referential_action_desc, f.update_referential_action_desc FROM sys.foreign_keys AS f INNER JOIN sys.foreign_key_columns AS fc INNER JOIN sys.objects AS o ON o.OBJECT_ID = fc.referenced_object_id ON f.OBJECT_ID = fc.constraint_object_id WHERE ' . $this->getTableWhereClause($table, 'SCHEMA_NAME (f.schema_id)', 'OBJECT_NAME (f.parent_object_id)'); } /** * {@inheritDoc} */ public function getListTableIndexesSQL($table, $currentDatabase = null) { return "SELECT idx.name AS key_name, col.name AS column_name, ~idx.is_unique AS non_unique, idx.is_primary_key AS [primary], CASE idx.type WHEN '1' THEN 'clustered' WHEN '2' THEN 'nonclustered' ELSE NULL END AS flags FROM sys.tables AS tbl JOIN sys.schemas AS scm ON tbl.schema_id = scm.schema_id JOIN sys.indexes AS idx ON tbl.object_id = idx.object_id JOIN sys.index_columns AS idxcol ON idx.object_id = idxcol.object_id AND idx.index_id = idxcol.index_id JOIN sys.columns AS col ON idxcol.object_id = col.object_id AND idxcol.column_id = col.column_id WHERE " . $this->getTableWhereClause($table, 'scm.name', 'tbl.name') . ' ORDER BY idx.index_id ASC, idxcol.key_ordinal ASC'; } /** * {@inheritDoc} */ public function getCreateViewSQL($name, $sql) { return 'CREATE VIEW ' . $name . ' AS ' . $sql; } /** * {@inheritDoc} */ public function getListViewsSQL($database) { return "SELECT name FROM sysobjects WHERE type = 'V' ORDER BY name"; } /** * Returns the where clause to filter schema and table name in a query. * * @param string $table The full qualified name of the table. * @param string $schemaColumn The name of the column to compare the schema to in the where clause. * @param string $tableColumn The name of the column to compare the table to in the where clause. * * @return string */ private function getTableWhereClause($table, $schemaColumn, $tableColumn) { if (strpos($table, '.') !== false) { [$schema, $table] = explode('.', $table); $schema = $this->quoteStringLiteral($schema); $table = $this->quoteStringLiteral($table); } else { $schema = 'SCHEMA_NAME()'; $table = $this->quoteStringLiteral($table); } return sprintf('(%s = %s AND %s = %s)', $tableColumn, $table, $schemaColumn, $schema); } /** * {@inheritDoc} */ public function getDropViewSQL($name) { return 'DROP VIEW ' . $name; } /** * {@inheritDoc} * * @deprecated Use application-generated UUIDs instead */ public function getGuidExpression() { return 'NEWID()'; } /** * {@inheritDoc} */ public function getLocateExpression($str, $substr, $startPos = false) { if ($startPos === false) { return 'CHARINDEX(' . $substr . ', ' . $str . ')'; } return 'CHARINDEX(' . $substr . ', ' . $str . ', ' . $startPos . ')'; } /** * {@inheritDoc} */ public function getModExpression($expression1, $expression2) { return $expression1 . ' % ' . $expression2; } /** * {@inheritDoc} */ public function getTrimExpression($str, $pos = TrimMode::UNSPECIFIED, $char = false) { if (! $char) { switch ($pos) { case TrimMode::LEADING: $trimFn = 'LTRIM'; break; case TrimMode::TRAILING: $trimFn = 'RTRIM'; break; default: return 'LTRIM(RTRIM(' . $str . '))'; } return $trimFn . '(' . $str . ')'; } /** Original query used to get those expressions declare @c varchar(100) = 'xxxBarxxx', @trim_char char(1) = 'x'; declare @pat varchar(10) = '%[^' + @trim_char + ']%'; select @c as string , @trim_char as trim_char , stuff(@c, 1, patindex(@pat, @c) - 1, null) as trim_leading , reverse(stuff(reverse(@c), 1, patindex(@pat, reverse(@c)) - 1, null)) as trim_trailing , reverse(stuff(reverse(stuff(@c, 1, patindex(@pat, @c) - 1, null)), 1, patindex(@pat, reverse(stuff(@c, 1, patindex(@pat, @c) - 1, null))) - 1, null)) as trim_both; */ $pattern = "'%[^' + " . $char . " + ']%'"; if ($pos === TrimMode::LEADING) { return 'stuff(' . $str . ', 1, patindex(' . $pattern . ', ' . $str . ') - 1, null)'; } if ($pos === TrimMode::TRAILING) { return 'reverse(stuff(reverse(' . $str . '), 1, patindex(' . $pattern . ', reverse(' . $str . ')) - 1, null))'; } return 'reverse(stuff(reverse(stuff(' . $str . ', 1, patindex(' . $pattern . ', ' . $str . ') - 1, null)), 1, patindex(' . $pattern . ', reverse(stuff(' . $str . ', 1, patindex(' . $pattern . ', ' . $str . ') - 1, null))) - 1, null))'; } /** * {@inheritDoc} */ public function getConcatExpression() { $args = func_get_args(); return '(' . implode(' + ', $args) . ')'; } /** * {@inheritDoc} */ public function getListDatabasesSQL() { return 'SELECT * FROM sys.databases'; } /** * {@inheritDoc} */ public function getListNamespacesSQL() { return "SELECT name FROM sys.schemas WHERE name NOT IN('guest', 'INFORMATION_SCHEMA', 'sys')"; } /** * {@inheritDoc} */ public function getSubstringExpression($value, $from, $length = null) { if ($length !== null) { return 'SUBSTRING(' . $value . ', ' . $from . ', ' . $length . ')'; } return 'SUBSTRING(' . $value . ', ' . $from . ', LEN(' . $value . ') - ' . $from . ' + 1)'; } /** * {@inheritDoc} */ public function getLengthExpression($column) { return 'LEN(' . $column . ')'; } /** * {@inheritDoc} */ public function getSetTransactionIsolationSQL($level) { return 'SET TRANSACTION ISOLATION LEVEL ' . $this->_getTransactionIsolationLevelSQL($level); } /** * {@inheritDoc} */ public function getIntegerTypeDeclarationSQL(array $field) { return 'INT' . $this->_getCommonIntegerTypeDeclarationSQL($field); } /** * {@inheritDoc} */ public function getBigIntTypeDeclarationSQL(array $field) { return 'BIGINT' . $this->_getCommonIntegerTypeDeclarationSQL($field); } /** * {@inheritDoc} */ public function getSmallIntTypeDeclarationSQL(array $field) { return 'SMALLINT' . $this->_getCommonIntegerTypeDeclarationSQL($field); } /** * {@inheritDoc} */ public function getGuidTypeDeclarationSQL(array $field) { return 'UNIQUEIDENTIFIER'; } /** * {@inheritDoc} */ protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) { return $fixed ? ($length ? 'NCHAR(' . $length . ')' : 'CHAR(255)') : ($length ? 'NVARCHAR(' . $length . ')' : 'NVARCHAR(255)'); } /** * {@inheritdoc} */ protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed) { return $fixed ? 'BINARY(' . ($length ?: 255) . ')' : 'VARBINARY(' . ($length ?: 255) . ')'; } /** * {@inheritdoc} */ public function getBinaryMaxLength() { return 8000; } /** * {@inheritDoc} */ public function getClobTypeDeclarationSQL(array $field) { return 'VARCHAR(MAX)'; } /** * {@inheritDoc} */ protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) { return ! empty($columnDef['autoincrement']) ? ' IDENTITY' : ''; } /** * {@inheritDoc} */ public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) { return 'DATETIME'; } /** * {@inheritDoc} */ public function getDateTypeDeclarationSQL(array $fieldDeclaration) { return 'DATETIME'; } /** * {@inheritDoc} */ public function getTimeTypeDeclarationSQL(array $fieldDeclaration) { return 'DATETIME'; } /** * {@inheritDoc} */ public function getBooleanTypeDeclarationSQL(array $field) { return 'BIT'; } /** * {@inheritDoc} */ protected function doModifyLimitQuery($query, $limit, $offset = null) { $where = []; if ($offset > 0) { $where[] = sprintf('doctrine_rownum >= %d', $offset + 1); } if ($limit !== null) { $where[] = sprintf('doctrine_rownum <= %d', $offset + $limit); $top = sprintf('TOP %d', $offset + $limit); } else { $top = 'TOP 9223372036854775807'; } if (empty($where)) { return $query; } // We'll find a SELECT or SELECT distinct and prepend TOP n to it // Even if the TOP n is very large, the use of a CTE will // allow the SQL Server query planner to optimize it so it doesn't // actually scan the entire range covered by the TOP clause. if (! preg_match('/^(\s*SELECT\s+(?:DISTINCT\s+)?)(.*)$/is', $query, $matches)) { return $query; } $query = $matches[1] . $top . ' ' . $matches[2]; if (stristr($query, 'ORDER BY')) { // Inner order by is not valid in SQL Server for our purposes // unless it's in a TOP N subquery. $query = $this->scrubInnerOrderBy($query); } // Build a new limited query around the original, using a CTE return sprintf( 'WITH dctrn_cte AS (%s) ' . 'SELECT * FROM (' . 'SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS doctrine_rownum FROM dctrn_cte' . ') AS doctrine_tbl ' . 'WHERE %s ORDER BY doctrine_rownum ASC', $query, implode(' AND ', $where) ); } /** * Remove ORDER BY clauses in subqueries - they're not supported by SQL Server. * Caveat: will leave ORDER BY in TOP N subqueries. * * @param string $query * * @return string */ private function scrubInnerOrderBy($query) { $count = substr_count(strtoupper($query), 'ORDER BY'); $offset = 0; while ($count-- > 0) { $orderByPos = stripos($query, ' ORDER BY', $offset); if ($orderByPos === false) { break; } $qLen = strlen($query); $parenCount = 0; $currentPosition = $orderByPos; while ($parenCount >= 0 && $currentPosition < $qLen) { if ($query[$currentPosition] === '(') { $parenCount++; } elseif ($query[$currentPosition] === ')') { $parenCount--; } $currentPosition++; } if ($this->isOrderByInTopNSubquery($query, $orderByPos)) { // If the order by clause is in a TOP N subquery, do not remove // it and continue iteration from the current position. $offset = $currentPosition; continue; } if ($currentPosition >= $qLen - 1) { continue; } $query = substr($query, 0, $orderByPos) . substr($query, $currentPosition - 1); $offset = $orderByPos; } return $query; } /** * Check an ORDER BY clause to see if it is in a TOP N query or subquery. * * @param string $query The query * @param int $currentPosition Start position of ORDER BY clause * * @return bool true if ORDER BY is in a TOP N query, false otherwise */ private function isOrderByInTopNSubquery($query, $currentPosition) { // Grab query text on the same nesting level as the ORDER BY clause we're examining. $subQueryBuffer = ''; $parenCount = 0; // If $parenCount goes negative, we've exited the subquery we're examining. // If $currentPosition goes negative, we've reached the beginning of the query. while ($parenCount >= 0 && $currentPosition >= 0) { if ($query[$currentPosition] === '(') { $parenCount--; } elseif ($query[$currentPosition] === ')') { $parenCount++; } // Only yank query text on the same nesting level as the ORDER BY clause. $subQueryBuffer = ($parenCount === 0 ? $query[$currentPosition] : ' ') . $subQueryBuffer; $currentPosition--; } return (bool) preg_match('/SELECT\s+(DISTINCT\s+)?TOP\s/i', $subQueryBuffer); } /** * {@inheritDoc} */ public function supportsLimitOffset() { return false; } /** * {@inheritDoc} */ public function convertBooleans($item) { if (is_array($item)) { foreach ($item as $key => $value) { if (! is_bool($value) && ! is_numeric($value)) { continue; } $item[$key] = $value ? 1 : 0; } } elseif (is_bool($item) || is_numeric($item)) { $item = $item ? 1 : 0; } return $item; } /** * {@inheritDoc} */ public function getCreateTemporaryTableSnippetSQL() { return 'CREATE TABLE'; } /** * {@inheritDoc} */ public function getTemporaryTableName($tableName) { return '#' . $tableName; } /** * {@inheritDoc} */ public function getDateTimeFormatString() { return 'Y-m-d H:i:s.000'; } /** * {@inheritDoc} */ public function getDateFormatString() { return 'Y-m-d H:i:s.000'; } /** * {@inheritDoc} */ public function getTimeFormatString() { return 'Y-m-d H:i:s.000'; } /** * {@inheritDoc} */ public function getDateTimeTzFormatString() { return $this->getDateTimeFormatString(); } /** * {@inheritDoc} */ public function getName() { return 'mssql'; } /** * {@inheritDoc} */ protected function initializeDoctrineTypeMappings() { $this->doctrineTypeMapping = [ 'bigint' => 'bigint', 'numeric' => 'decimal', 'bit' => 'boolean', 'smallint' => 'smallint', 'decimal' => 'decimal', 'smallmoney' => 'integer', 'int' => 'integer', 'tinyint' => 'smallint', 'money' => 'integer', 'float' => 'float', 'real' => 'float', 'double' => 'float', 'double precision' => 'float', 'smalldatetime' => 'datetime', 'datetime' => 'datetime', 'char' => 'string', 'varchar' => 'string', 'text' => 'text', 'nchar' => 'string', 'nvarchar' => 'string', 'ntext' => 'text', 'binary' => 'binary', 'varbinary' => 'binary', 'image' => 'blob', 'uniqueidentifier' => 'guid', ]; } /** * {@inheritDoc} */ public function createSavePoint($savepoint) { return 'SAVE TRANSACTION ' . $savepoint; } /** * {@inheritDoc} */ public function releaseSavePoint($savepoint) { return ''; } /** * {@inheritDoc} */ public function rollbackSavePoint($savepoint) { return 'ROLLBACK TRANSACTION ' . $savepoint; } /** * {@inheritdoc} */ public function getForeignKeyReferentialActionSQL($action) { // RESTRICT is not supported, therefore falling back to NO ACTION. if (strtoupper($action) === 'RESTRICT') { return 'NO ACTION'; } return parent::getForeignKeyReferentialActionSQL($action); } /** * {@inheritDoc} */ public function appendLockHint($fromClause, $lockMode) { switch (true) { case $lockMode === LockMode::NONE: return $fromClause . ' WITH (NOLOCK)'; case $lockMode === LockMode::PESSIMISTIC_READ: return $fromClause . ' WITH (HOLDLOCK, ROWLOCK)'; case $lockMode === LockMode::PESSIMISTIC_WRITE: return $fromClause . ' WITH (UPDLOCK, ROWLOCK)'; default: return $fromClause; } } /** * {@inheritDoc} */ public function getForUpdateSQL() { return ' '; } /** * {@inheritDoc} */ protected function getReservedKeywordsClass() { return Keywords\SQLServerKeywords::class; } /** * {@inheritDoc} */ public function quoteSingleIdentifier($str) { return '[' . str_replace(']', '][', $str) . ']'; } /** * {@inheritDoc} */ public function getTruncateTableSQL($tableName, $cascade = false) { $tableIdentifier = new Identifier($tableName); return 'TRUNCATE TABLE ' . $tableIdentifier->getQuotedName($this); } /** * {@inheritDoc} */ public function getBlobTypeDeclarationSQL(array $field) { return 'VARBINARY(MAX)'; } /** * {@inheritdoc} * * Modifies column declaration order as it differs in Microsoft SQL Server. */ public function getColumnDeclarationSQL($name, array $field) { if (isset($field['columnDefinition'])) { $columnDef = $this->getCustomTypeDeclarationSQL($field); } else { $collation = isset($field['collation']) && $field['collation'] ? ' ' . $this->getColumnCollationDeclarationSQL($field['collation']) : ''; $notnull = isset($field['notnull']) && $field['notnull'] ? ' NOT NULL' : ''; $unique = isset($field['unique']) && $field['unique'] ? ' ' . $this->getUniqueFieldDeclarationSQL() : ''; $check = isset($field['check']) && $field['check'] ? ' ' . $field['check'] : ''; $typeDecl = $field['type']->getSQLDeclaration($field, $this); $columnDef = $typeDecl . $collation . $notnull . $unique . $check; } return $name . ' ' . $columnDef; } /** * Returns a unique default constraint name for a table and column. * * @param string $table Name of the table to generate the unique default constraint name for. * @param string $column Name of the column in the table to generate the unique default constraint name for. * * @return string */ private function generateDefaultConstraintName($table, $column) { return 'DF_' . $this->generateIdentifierName($table) . '_' . $this->generateIdentifierName($column); } /** * Returns a hash value for a given identifier. * * @param string $identifier Identifier to generate a hash value for. * * @return string */ private function generateIdentifierName($identifier) { // Always generate name for unquoted identifiers to ensure consistency. $identifier = new Identifier($identifier); return strtoupper(dechex(crc32($identifier->getName()))); } protected function getCommentOnTableSQL(string $tableName, ?string $comment) : string { return sprintf( <<<'SQL' EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N%s, @level0type=N'SCHEMA', @level0name=N'dbo', @level1type=N'TABLE', @level1name=N%s SQL , $this->quoteStringLiteral((string) $comment), $this->quoteStringLiteral($tableName) ); } public function getListTableMetadataSQL(string $table) : string { return sprintf( <<<'SQL' SELECT p.value AS [table_comment] FROM sys.tables AS tbl INNER JOIN sys.extended_properties AS p ON p.major_id=tbl.object_id AND p.minor_id=0 AND p.class=1 WHERE (tbl.name=N%s and SCHEMA_NAME(tbl.schema_id)=N'dbo' and p.name=N'MS_Description') SQL , $this->quoteStringLiteral($table) ); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php000066400000000000000000001045431360544566000255540ustar00rootroot00000000000000_getTransactionIsolationLevelSQL($level); } /** * {@inheritDoc} */ public function prefersIdentityColumns() { return true; } /** * {@inheritDoc} */ public function getBooleanTypeDeclarationSQL(array $field) { return 'BOOLEAN'; } /** * {@inheritDoc} */ public function getIntegerTypeDeclarationSQL(array $field) { return 'INTEGER' . $this->_getCommonIntegerTypeDeclarationSQL($field); } /** * {@inheritDoc} */ public function getBigIntTypeDeclarationSQL(array $field) { // SQLite autoincrement is implicit for INTEGER PKs, but not for BIGINT fields. if (! empty($field['autoincrement'])) { return $this->getIntegerTypeDeclarationSQL($field); } return 'BIGINT' . $this->_getCommonIntegerTypeDeclarationSQL($field); } /** * {@inheritDoc} */ public function getTinyIntTypeDeclarationSql(array $field) { // SQLite autoincrement is implicit for INTEGER PKs, but not for TINYINT fields. if (! empty($field['autoincrement'])) { return $this->getIntegerTypeDeclarationSQL($field); } return 'TINYINT' . $this->_getCommonIntegerTypeDeclarationSQL($field); } /** * {@inheritDoc} */ public function getSmallIntTypeDeclarationSQL(array $field) { // SQLite autoincrement is implicit for INTEGER PKs, but not for SMALLINT fields. if (! empty($field['autoincrement'])) { return $this->getIntegerTypeDeclarationSQL($field); } return 'SMALLINT' . $this->_getCommonIntegerTypeDeclarationSQL($field); } /** * {@inheritDoc} */ public function getMediumIntTypeDeclarationSql(array $field) { // SQLite autoincrement is implicit for INTEGER PKs, but not for MEDIUMINT fields. if (! empty($field['autoincrement'])) { return $this->getIntegerTypeDeclarationSQL($field); } return 'MEDIUMINT' . $this->_getCommonIntegerTypeDeclarationSQL($field); } /** * {@inheritDoc} */ public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration) { return 'DATETIME'; } /** * {@inheritDoc} */ public function getDateTypeDeclarationSQL(array $fieldDeclaration) { return 'DATE'; } /** * {@inheritDoc} */ public function getTimeTypeDeclarationSQL(array $fieldDeclaration) { return 'TIME'; } /** * {@inheritDoc} */ protected function _getCommonIntegerTypeDeclarationSQL(array $columnDef) { // sqlite autoincrement is only possible for the primary key if (! empty($columnDef['autoincrement'])) { return ' PRIMARY KEY AUTOINCREMENT'; } return ! empty($columnDef['unsigned']) ? ' UNSIGNED' : ''; } /** * {@inheritDoc} */ public function getForeignKeyDeclarationSQL(ForeignKeyConstraint $foreignKey) { return parent::getForeignKeyDeclarationSQL(new ForeignKeyConstraint( $foreignKey->getQuotedLocalColumns($this), str_replace('.', '__', $foreignKey->getQuotedForeignTableName($this)), $foreignKey->getQuotedForeignColumns($this), $foreignKey->getName(), $foreignKey->getOptions() )); } /** * {@inheritDoc} */ protected function _getCreateTableSQL($name, array $columns, array $options = []) { $name = str_replace('.', '__', $name); $queryFields = $this->getColumnDeclarationListSQL($columns); if (isset($options['uniqueConstraints']) && ! empty($options['uniqueConstraints'])) { foreach ($options['uniqueConstraints'] as $name => $definition) { $queryFields .= ', ' . $this->getUniqueConstraintDeclarationSQL($name, $definition); } } $queryFields .= $this->getNonAutoincrementPrimaryKeyDefinition($columns, $options); if (isset($options['foreignKeys'])) { foreach ($options['foreignKeys'] as $foreignKey) { $queryFields .= ', ' . $this->getForeignKeyDeclarationSQL($foreignKey); } } $tableComment = ''; if (isset($options['comment'])) { $comment = trim($options['comment'], " '"); $tableComment = $this->getInlineTableCommentSQL($comment); } $query = ['CREATE TABLE ' . $name . ' ' . $tableComment . '(' . $queryFields . ')']; if (isset($options['alter']) && $options['alter'] === true) { return $query; } if (isset($options['indexes']) && ! empty($options['indexes'])) { foreach ($options['indexes'] as $indexDef) { $query[] = $this->getCreateIndexSQL($indexDef, $name); } } if (isset($options['unique']) && ! empty($options['unique'])) { foreach ($options['unique'] as $indexDef) { $query[] = $this->getCreateIndexSQL($indexDef, $name); } } return $query; } /** * Generate a PRIMARY KEY definition if no autoincrement value is used * * @param mixed[][] $columns * @param mixed[] $options */ private function getNonAutoincrementPrimaryKeyDefinition(array $columns, array $options) : string { if (empty($options['primary'])) { return ''; } $keyColumns = array_unique(array_values($options['primary'])); foreach ($keyColumns as $keyColumn) { if (! empty($columns[$keyColumn]['autoincrement'])) { return ''; } } return ', PRIMARY KEY(' . implode(', ', $keyColumns) . ')'; } /** * {@inheritDoc} */ protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) { return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)') : ($length ? 'VARCHAR(' . $length . ')' : 'TEXT'); } /** * {@inheritdoc} */ protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed) { return 'BLOB'; } /** * {@inheritdoc} */ public function getBinaryMaxLength() { return 0; } /** * {@inheritdoc} */ public function getBinaryDefaultLength() { return 0; } /** * {@inheritDoc} */ public function getClobTypeDeclarationSQL(array $field) { return 'CLOB'; } /** * {@inheritDoc} */ public function getListTableConstraintsSQL($table) { $table = str_replace('.', '__', $table); return sprintf( "SELECT sql FROM sqlite_master WHERE type='index' AND tbl_name = %s AND sql NOT NULL ORDER BY name", $this->quoteStringLiteral($table) ); } /** * {@inheritDoc} */ public function getListTableColumnsSQL($table, $currentDatabase = null) { $table = str_replace('.', '__', $table); return sprintf('PRAGMA table_info(%s)', $this->quoteStringLiteral($table)); } /** * {@inheritDoc} */ public function getListTableIndexesSQL($table, $currentDatabase = null) { $table = str_replace('.', '__', $table); return sprintf('PRAGMA index_list(%s)', $this->quoteStringLiteral($table)); } /** * {@inheritDoc} */ public function getListTablesSQL() { return "SELECT name FROM sqlite_master WHERE type = 'table' AND name != 'sqlite_sequence' AND name != 'geometry_columns' AND name != 'spatial_ref_sys' " . 'UNION ALL SELECT name FROM sqlite_temp_master ' . "WHERE type = 'table' ORDER BY name"; } /** * {@inheritDoc} */ public function getListViewsSQL($database) { return "SELECT name, sql FROM sqlite_master WHERE type='view' AND sql NOT NULL"; } /** * {@inheritDoc} */ public function getCreateViewSQL($name, $sql) { return 'CREATE VIEW ' . $name . ' AS ' . $sql; } /** * {@inheritDoc} */ public function getDropViewSQL($name) { return 'DROP VIEW ' . $name; } /** * {@inheritDoc} */ public function getAdvancedForeignKeyOptionsSQL(ForeignKeyConstraint $foreignKey) { $query = parent::getAdvancedForeignKeyOptionsSQL($foreignKey); $query .= ($foreignKey->hasOption('deferrable') && $foreignKey->getOption('deferrable') !== false ? ' ' : ' NOT ') . 'DEFERRABLE'; $query .= ' INITIALLY ' . ($foreignKey->hasOption('deferred') && $foreignKey->getOption('deferred') !== false ? 'DEFERRED' : 'IMMEDIATE'); return $query; } /** * {@inheritDoc} */ public function supportsIdentityColumns() { return true; } /** * {@inheritDoc} */ public function supportsColumnCollation() { return true; } /** * {@inheritDoc} */ public function supportsInlineColumnComments() { return true; } /** * {@inheritDoc} */ public function getName() { return 'sqlite'; } /** * {@inheritDoc} */ public function getTruncateTableSQL($tableName, $cascade = false) { $tableIdentifier = new Identifier($tableName); $tableName = str_replace('.', '__', $tableIdentifier->getQuotedName($this)); return 'DELETE FROM ' . $tableName; } /** * User-defined function for Sqlite that is used with PDO::sqliteCreateFunction(). * * @param int|float $value * * @return float */ public static function udfSqrt($value) { return sqrt($value); } /** * User-defined function for Sqlite that implements MOD(a, b). * * @param int $a * @param int $b * * @return int */ public static function udfMod($a, $b) { return $a % $b; } /** * @param string $str * @param string $substr * @param int $offset * * @return int */ public static function udfLocate($str, $substr, $offset = 0) { // SQL's LOCATE function works on 1-based positions, while PHP's strpos works on 0-based positions. // So we have to make them compatible if an offset is given. if ($offset > 0) { $offset -= 1; } $pos = strpos($str, $substr, $offset); if ($pos !== false) { return $pos + 1; } return 0; } /** * {@inheritDoc} */ public function getForUpdateSql() { return ''; } /** * {@inheritDoc} */ public function getInlineColumnCommentSQL($comment) { return '--' . str_replace("\n", "\n--", $comment) . "\n"; } private function getInlineTableCommentSQL(string $comment) : string { return $this->getInlineColumnCommentSQL($comment); } /** * {@inheritDoc} */ protected function initializeDoctrineTypeMappings() { $this->doctrineTypeMapping = [ 'boolean' => 'boolean', 'tinyint' => 'boolean', 'smallint' => 'smallint', 'mediumint' => 'integer', 'int' => 'integer', 'integer' => 'integer', 'serial' => 'integer', 'bigint' => 'bigint', 'bigserial' => 'bigint', 'clob' => 'text', 'tinytext' => 'text', 'mediumtext' => 'text', 'longtext' => 'text', 'text' => 'text', 'varchar' => 'string', 'longvarchar' => 'string', 'varchar2' => 'string', 'nvarchar' => 'string', 'image' => 'string', 'ntext' => 'string', 'char' => 'string', 'date' => 'date', 'datetime' => 'datetime', 'timestamp' => 'datetime', 'time' => 'time', 'float' => 'float', 'double' => 'float', 'double precision' => 'float', 'real' => 'float', 'decimal' => 'decimal', 'numeric' => 'decimal', 'blob' => 'blob', ]; } /** * {@inheritDoc} */ protected function getReservedKeywordsClass() { return Keywords\SQLiteKeywords::class; } /** * {@inheritDoc} */ protected function getPreAlterTableIndexForeignKeySQL(TableDiff $diff) { if (! $diff->fromTable instanceof Table) { throw new DBALException('Sqlite platform requires for alter table the table diff with reference to original table schema'); } $sql = []; foreach ($diff->fromTable->getIndexes() as $index) { if ($index->isPrimary()) { continue; } $sql[] = $this->getDropIndexSQL($index, $diff->name); } return $sql; } /** * {@inheritDoc} */ protected function getPostAlterTableIndexForeignKeySQL(TableDiff $diff) { if (! $diff->fromTable instanceof Table) { throw new DBALException('Sqlite platform requires for alter table the table diff with reference to original table schema'); } $sql = []; $tableName = $diff->getNewName(); if ($tableName === false) { $tableName = $diff->getName($this); } foreach ($this->getIndexesInAlteredTable($diff) as $index) { if ($index->isPrimary()) { continue; } $sql[] = $this->getCreateIndexSQL($index, $tableName->getQuotedName($this)); } return $sql; } /** * {@inheritDoc} */ protected function doModifyLimitQuery($query, $limit, $offset) { if ($limit === null && $offset > 0) { return $query . ' LIMIT -1 OFFSET ' . $offset; } return parent::doModifyLimitQuery($query, $limit, $offset); } /** * {@inheritDoc} */ public function getBlobTypeDeclarationSQL(array $field) { return 'BLOB'; } /** * {@inheritDoc} */ public function getTemporaryTableName($tableName) { $tableName = str_replace('.', '__', $tableName); return $tableName; } /** * {@inheritDoc} * * Sqlite Platform emulates schema by underscoring each dot and generating tables * into the default database. * * This hack is implemented to be able to use SQLite as testdriver when * using schema supporting databases. */ public function canEmulateSchemas() { return true; } /** * {@inheritDoc} */ public function supportsForeignKeyConstraints() { return false; } /** * {@inheritDoc} */ public function getCreatePrimaryKeySQL(Index $index, $table) { throw new DBALException('Sqlite platform does not support alter primary key.'); } /** * {@inheritdoc} */ public function getCreateForeignKeySQL(ForeignKeyConstraint $foreignKey, $table) { throw new DBALException('Sqlite platform does not support alter foreign key.'); } /** * {@inheritdoc} */ public function getDropForeignKeySQL($foreignKey, $table) { throw new DBALException('Sqlite platform does not support alter foreign key.'); } /** * {@inheritDoc} */ public function getCreateConstraintSQL(Constraint $constraint, $table) { throw new DBALException('Sqlite platform does not support alter constraint.'); } /** * {@inheritDoc} */ public function getCreateTableSQL(Table $table, $createFlags = null) { $createFlags = $createFlags ?? self::CREATE_INDEXES | self::CREATE_FOREIGNKEYS; return parent::getCreateTableSQL($table, $createFlags); } /** * {@inheritDoc} */ public function getListTableForeignKeysSQL($table, $database = null) { $table = str_replace('.', '__', $table); return sprintf('PRAGMA foreign_key_list(%s)', $this->quoteStringLiteral($table)); } /** * {@inheritDoc} */ public function getAlterTableSQL(TableDiff $diff) { $sql = $this->getSimpleAlterTableSQL($diff); if ($sql !== false) { return $sql; } $fromTable = $diff->fromTable; if (! $fromTable instanceof Table) { throw new DBALException('Sqlite platform requires for alter table the table diff with reference to original table schema'); } $table = clone $fromTable; $columns = []; $oldColumnNames = []; $newColumnNames = []; $columnSql = []; foreach ($table->getColumns() as $columnName => $column) { $columnName = strtolower($columnName); $columns[$columnName] = $column; $oldColumnNames[$columnName] = $newColumnNames[$columnName] = $column->getQuotedName($this); } foreach ($diff->removedColumns as $columnName => $column) { if ($this->onSchemaAlterTableRemoveColumn($column, $diff, $columnSql)) { continue; } $columnName = strtolower($columnName); if (! isset($columns[$columnName])) { continue; } unset( $columns[$columnName], $oldColumnNames[$columnName], $newColumnNames[$columnName] ); } foreach ($diff->renamedColumns as $oldColumnName => $column) { if ($this->onSchemaAlterTableRenameColumn($oldColumnName, $column, $diff, $columnSql)) { continue; } $oldColumnName = strtolower($oldColumnName); if (isset($columns[$oldColumnName])) { unset($columns[$oldColumnName]); } $columns[strtolower($column->getName())] = $column; if (! isset($newColumnNames[$oldColumnName])) { continue; } $newColumnNames[$oldColumnName] = $column->getQuotedName($this); } foreach ($diff->changedColumns as $oldColumnName => $columnDiff) { if ($this->onSchemaAlterTableChangeColumn($columnDiff, $diff, $columnSql)) { continue; } if (isset($columns[$oldColumnName])) { unset($columns[$oldColumnName]); } $columns[strtolower($columnDiff->column->getName())] = $columnDiff->column; if (! isset($newColumnNames[$oldColumnName])) { continue; } $newColumnNames[$oldColumnName] = $columnDiff->column->getQuotedName($this); } foreach ($diff->addedColumns as $columnName => $column) { if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) { continue; } $columns[strtolower($columnName)] = $column; } $sql = []; $tableSql = []; if (! $this->onSchemaAlterTable($diff, $tableSql)) { $dataTable = new Table('__temp__' . $table->getName()); $newTable = new Table($table->getQuotedName($this), $columns, $this->getPrimaryIndexInAlteredTable($diff), $this->getForeignKeysInAlteredTable($diff), 0, $table->getOptions()); $newTable->addOption('alter', true); $sql = $this->getPreAlterTableIndexForeignKeySQL($diff); //$sql = array_merge($sql, $this->getCreateTableSQL($dataTable, 0)); $sql[] = sprintf('CREATE TEMPORARY TABLE %s AS SELECT %s FROM %s', $dataTable->getQuotedName($this), implode(', ', $oldColumnNames), $table->getQuotedName($this)); $sql[] = $this->getDropTableSQL($fromTable); $sql = array_merge($sql, $this->getCreateTableSQL($newTable)); $sql[] = sprintf('INSERT INTO %s (%s) SELECT %s FROM %s', $newTable->getQuotedName($this), implode(', ', $newColumnNames), implode(', ', $oldColumnNames), $dataTable->getQuotedName($this)); $sql[] = $this->getDropTableSQL($dataTable); $newName = $diff->getNewName(); if ($newName !== false) { $sql[] = sprintf( 'ALTER TABLE %s RENAME TO %s', $newTable->getQuotedName($this), $newName->getQuotedName($this) ); } $sql = array_merge($sql, $this->getPostAlterTableIndexForeignKeySQL($diff)); } return array_merge($sql, $tableSql, $columnSql); } /** * @return string[]|false */ private function getSimpleAlterTableSQL(TableDiff $diff) { // Suppress changes on integer type autoincrement columns. foreach ($diff->changedColumns as $oldColumnName => $columnDiff) { if (! $columnDiff->fromColumn instanceof Column || ! $columnDiff->column instanceof Column || ! $columnDiff->column->getAutoincrement() || ! $columnDiff->column->getType() instanceof Types\IntegerType ) { continue; } if (! $columnDiff->hasChanged('type') && $columnDiff->hasChanged('unsigned')) { unset($diff->changedColumns[$oldColumnName]); continue; } $fromColumnType = $columnDiff->fromColumn->getType(); if (! ($fromColumnType instanceof Types\SmallIntType) && ! ($fromColumnType instanceof Types\BigIntType)) { continue; } unset($diff->changedColumns[$oldColumnName]); } if (! empty($diff->renamedColumns) || ! empty($diff->addedForeignKeys) || ! empty($diff->addedIndexes) || ! empty($diff->changedColumns) || ! empty($diff->changedForeignKeys) || ! empty($diff->changedIndexes) || ! empty($diff->removedColumns) || ! empty($diff->removedForeignKeys) || ! empty($diff->removedIndexes) || ! empty($diff->renamedIndexes) ) { return false; } $table = new Table($diff->name); $sql = []; $tableSql = []; $columnSql = []; foreach ($diff->addedColumns as $column) { if ($this->onSchemaAlterTableAddColumn($column, $diff, $columnSql)) { continue; } $field = array_merge(['unique' => null, 'autoincrement' => null, 'default' => null], $column->toArray()); $type = $field['type']; switch (true) { case isset($field['columnDefinition']) || $field['autoincrement'] || $field['unique']: case $type instanceof Types\DateTimeType && $field['default'] === $this->getCurrentTimestampSQL(): case $type instanceof Types\DateType && $field['default'] === $this->getCurrentDateSQL(): case $type instanceof Types\TimeType && $field['default'] === $this->getCurrentTimeSQL(): return false; } $field['name'] = $column->getQuotedName($this); if ($type instanceof Types\StringType && $field['length'] === null) { $field['length'] = 255; } $sql[] = 'ALTER TABLE ' . $table->getQuotedName($this) . ' ADD COLUMN ' . $this->getColumnDeclarationSQL($field['name'], $field); } if (! $this->onSchemaAlterTable($diff, $tableSql)) { if ($diff->newName !== false) { $newTable = new Identifier($diff->newName); $sql[] = 'ALTER TABLE ' . $table->getQuotedName($this) . ' RENAME TO ' . $newTable->getQuotedName($this); } } return array_merge($sql, $tableSql, $columnSql); } /** * @return string[] */ private function getColumnNamesInAlteredTable(TableDiff $diff) { $columns = []; foreach ($diff->fromTable->getColumns() as $columnName => $column) { $columns[strtolower($columnName)] = $column->getName(); } foreach ($diff->removedColumns as $columnName => $column) { $columnName = strtolower($columnName); if (! isset($columns[$columnName])) { continue; } unset($columns[$columnName]); } foreach ($diff->renamedColumns as $oldColumnName => $column) { $columnName = $column->getName(); $columns[strtolower($oldColumnName)] = $columnName; $columns[strtolower($columnName)] = $columnName; } foreach ($diff->changedColumns as $oldColumnName => $columnDiff) { $columnName = $columnDiff->column->getName(); $columns[strtolower($oldColumnName)] = $columnName; $columns[strtolower($columnName)] = $columnName; } foreach ($diff->addedColumns as $column) { $columnName = $column->getName(); $columns[strtolower($columnName)] = $columnName; } return $columns; } /** * @return Index[] */ private function getIndexesInAlteredTable(TableDiff $diff) { $indexes = $diff->fromTable->getIndexes(); $columnNames = $this->getColumnNamesInAlteredTable($diff); foreach ($indexes as $key => $index) { foreach ($diff->renamedIndexes as $oldIndexName => $renamedIndex) { if (strtolower($key) !== strtolower($oldIndexName)) { continue; } unset($indexes[$key]); } $changed = false; $indexColumns = []; foreach ($index->getColumns() as $columnName) { $normalizedColumnName = strtolower($columnName); if (! isset($columnNames[$normalizedColumnName])) { unset($indexes[$key]); continue 2; } $indexColumns[] = $columnNames[$normalizedColumnName]; if ($columnName === $columnNames[$normalizedColumnName]) { continue; } $changed = true; } if (! $changed) { continue; } $indexes[$key] = new Index($index->getName(), $indexColumns, $index->isUnique(), $index->isPrimary(), $index->getFlags()); } foreach ($diff->removedIndexes as $index) { $indexName = strtolower($index->getName()); if (! strlen($indexName) || ! isset($indexes[$indexName])) { continue; } unset($indexes[$indexName]); } foreach (array_merge($diff->changedIndexes, $diff->addedIndexes, $diff->renamedIndexes) as $index) { $indexName = strtolower($index->getName()); if (strlen($indexName)) { $indexes[$indexName] = $index; } else { $indexes[] = $index; } } return $indexes; } /** * @return ForeignKeyConstraint[] */ private function getForeignKeysInAlteredTable(TableDiff $diff) { $foreignKeys = $diff->fromTable->getForeignKeys(); $columnNames = $this->getColumnNamesInAlteredTable($diff); foreach ($foreignKeys as $key => $constraint) { $changed = false; $localColumns = []; foreach ($constraint->getLocalColumns() as $columnName) { $normalizedColumnName = strtolower($columnName); if (! isset($columnNames[$normalizedColumnName])) { unset($foreignKeys[$key]); continue 2; } $localColumns[] = $columnNames[$normalizedColumnName]; if ($columnName === $columnNames[$normalizedColumnName]) { continue; } $changed = true; } if (! $changed) { continue; } $foreignKeys[$key] = new ForeignKeyConstraint($localColumns, $constraint->getForeignTableName(), $constraint->getForeignColumns(), $constraint->getName(), $constraint->getOptions()); } foreach ($diff->removedForeignKeys as $constraint) { if (! $constraint instanceof ForeignKeyConstraint) { $constraint = new Identifier($constraint); } $constraintName = strtolower($constraint->getName()); if (! strlen($constraintName) || ! isset($foreignKeys[$constraintName])) { continue; } unset($foreignKeys[$constraintName]); } foreach (array_merge($diff->changedForeignKeys, $diff->addedForeignKeys) as $constraint) { $constraintName = strtolower($constraint->getName()); if (strlen($constraintName)) { $foreignKeys[$constraintName] = $constraint; } else { $foreignKeys[] = $constraint; } } return $foreignKeys; } /** * @return Index[] */ private function getPrimaryIndexInAlteredTable(TableDiff $diff) { $primaryIndex = []; foreach ($this->getIndexesInAlteredTable($diff) as $index) { if (! $index->isPrimary()) { continue; } $primaryIndex = [$index->getName() => $index]; } return $primaryIndex; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Platforms/TrimMode.php000066400000000000000000000004131360544566000243150ustar00rootroot00000000000000getParams(); if (isset($params['portability'])) { if ($this->getDatabasePlatform()->getName() === 'oracle') { $params['portability'] &= self::PORTABILITY_ORACLE; } elseif ($this->getDatabasePlatform()->getName() === 'postgresql') { $params['portability'] &= self::PORTABILITY_POSTGRESQL; } elseif ($this->getDatabasePlatform()->getName() === 'sqlite') { $params['portability'] &= self::PORTABILITY_SQLITE; } elseif ($this->getDatabasePlatform()->getName() === 'drizzle') { $params['portability'] &= self::PORTABILITY_DRIZZLE; } elseif ($this->getDatabasePlatform()->getName() === 'sqlanywhere') { $params['portability'] &= self::PORTABILITY_SQLANYWHERE; } elseif ($this->getDatabasePlatform()->getName() === 'db2') { $params['portability'] &= self::PORTABILITY_DB2; } elseif ($this->getDatabasePlatform()->getName() === 'mssql') { $params['portability'] &= self::PORTABILITY_SQLSRV; } else { $params['portability'] &= self::PORTABILITY_OTHERVENDORS; } $this->portability = $params['portability']; } if (isset($params['fetch_case']) && $this->portability & self::PORTABILITY_FIX_CASE) { if ($this->_conn instanceof PDOConnection) { // make use of c-level support for case handling $this->_conn->setAttribute(PDO::ATTR_CASE, $params['fetch_case']); } else { $this->case = $params['fetch_case'] === ColumnCase::LOWER ? CASE_LOWER : CASE_UPPER; } } } return $ret; } /** * @return int */ public function getPortability() { return $this->portability; } /** * @return int */ public function getFetchCase() { return $this->case; } /** * {@inheritdoc} */ public function executeQuery($query, array $params = [], $types = [], ?QueryCacheProfile $qcp = null) { $stmt = new Statement(parent::executeQuery($query, $params, $types, $qcp), $this); $stmt->setFetchMode($this->defaultFetchMode); return $stmt; } /** * {@inheritdoc} */ public function prepare($statement) { $stmt = new Statement(parent::prepare($statement), $this); $stmt->setFetchMode($this->defaultFetchMode); return $stmt; } /** * {@inheritdoc} */ public function query() { $connection = $this->getWrappedConnection(); $stmt = $connection->query(...func_get_args()); $stmt = new Statement($stmt, $this); $stmt->setFetchMode($this->defaultFetchMode); return $stmt; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Portability/Statement.php000066400000000000000000000141001360544566000250720ustar00rootroot00000000000000Statement and applies portability measures. * * @param DriverStatement|ResultStatement $stmt */ public function __construct($stmt, Connection $conn) { $this->stmt = $stmt; $this->portability = $conn->getPortability(); $this->case = $conn->getFetchCase(); } /** * {@inheritdoc} */ public function bindParam($column, &$variable, $type = ParameterType::STRING, $length = null) { assert($this->stmt instanceof DriverStatement); return $this->stmt->bindParam($column, $variable, $type, $length); } /** * {@inheritdoc} */ public function bindValue($param, $value, $type = ParameterType::STRING) { assert($this->stmt instanceof DriverStatement); return $this->stmt->bindValue($param, $value, $type); } /** * {@inheritdoc} */ public function closeCursor() { return $this->stmt->closeCursor(); } /** * {@inheritdoc} */ public function columnCount() { return $this->stmt->columnCount(); } /** * {@inheritdoc} */ public function errorCode() { assert($this->stmt instanceof DriverStatement); return $this->stmt->errorCode(); } /** * {@inheritdoc} */ public function errorInfo() { assert($this->stmt instanceof DriverStatement); return $this->stmt->errorInfo(); } /** * {@inheritdoc} */ public function execute($params = null) { assert($this->stmt instanceof DriverStatement); return $this->stmt->execute($params); } /** * {@inheritdoc} */ public function setFetchMode($fetchMode, $arg1 = null, $arg2 = null) { $this->defaultFetchMode = $fetchMode; return $this->stmt->setFetchMode($fetchMode, $arg1, $arg2); } /** * {@inheritdoc} */ public function getIterator() { return new StatementIterator($this); } /** * {@inheritdoc} */ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) { $fetchMode = $fetchMode ?: $this->defaultFetchMode; $row = $this->stmt->fetch($fetchMode); $iterateRow = $this->portability & (Connection::PORTABILITY_EMPTY_TO_NULL|Connection::PORTABILITY_RTRIM); $fixCase = $this->case !== null && ($fetchMode === FetchMode::ASSOCIATIVE || $fetchMode === FetchMode::MIXED) && ($this->portability & Connection::PORTABILITY_FIX_CASE); $row = $this->fixRow($row, $iterateRow, $fixCase); return $row; } /** * {@inheritdoc} */ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) { $fetchMode = $fetchMode ?: $this->defaultFetchMode; if ($fetchArgument) { $rows = $this->stmt->fetchAll($fetchMode, $fetchArgument); } else { $rows = $this->stmt->fetchAll($fetchMode); } $iterateRow = $this->portability & (Connection::PORTABILITY_EMPTY_TO_NULL|Connection::PORTABILITY_RTRIM); $fixCase = $this->case !== null && ($fetchMode === FetchMode::ASSOCIATIVE || $fetchMode === FetchMode::MIXED) && ($this->portability & Connection::PORTABILITY_FIX_CASE); if (! $iterateRow && ! $fixCase) { return $rows; } if ($fetchMode === FetchMode::COLUMN) { foreach ($rows as $num => $row) { $rows[$num] = [$row]; } } foreach ($rows as $num => $row) { $rows[$num] = $this->fixRow($row, $iterateRow, $fixCase); } if ($fetchMode === FetchMode::COLUMN) { foreach ($rows as $num => $row) { $rows[$num] = $row[0]; } } return $rows; } /** * @param mixed $row * @param int $iterateRow * @param bool $fixCase * * @return mixed */ protected function fixRow($row, $iterateRow, $fixCase) { if (! $row) { return $row; } if ($fixCase) { $row = array_change_key_case($row, $this->case); } if ($iterateRow) { foreach ($row as $k => $v) { if (($this->portability & Connection::PORTABILITY_EMPTY_TO_NULL) && $v === '') { $row[$k] = null; } elseif (($this->portability & Connection::PORTABILITY_RTRIM) && is_string($v)) { $row[$k] = rtrim($v); } } } return $row; } /** * {@inheritdoc} */ public function fetchColumn($columnIndex = 0) { $value = $this->stmt->fetchColumn($columnIndex); if ($this->portability & (Connection::PORTABILITY_EMPTY_TO_NULL|Connection::PORTABILITY_RTRIM)) { if (($this->portability & Connection::PORTABILITY_EMPTY_TO_NULL) && $value === '') { $value = null; } elseif (($this->portability & Connection::PORTABILITY_RTRIM) && is_string($value)) { $value = rtrim($value); } } return $value; } /** * {@inheritdoc} */ public function rowCount() { assert($this->stmt instanceof DriverStatement); return $this->stmt->rowCount(); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Query/000077500000000000000000000000001360544566000212245ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Query/Expression/000077500000000000000000000000001360544566000233635ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Query/Expression/CompositeExpression.php000066400000000000000000000047401360544566000301230ustar00rootroot00000000000000type = $type; $this->addMultiple($parts); } /** * Adds multiple parts to composite expression. * * @param self[]|string[] $parts * * @return \Doctrine\DBAL\Query\Expression\CompositeExpression */ public function addMultiple(array $parts = []) { foreach ($parts as $part) { $this->add($part); } return $this; } /** * Adds an expression to composite expression. * * @param mixed $part * * @return \Doctrine\DBAL\Query\Expression\CompositeExpression */ public function add($part) { if (empty($part)) { return $this; } if ($part instanceof self && count($part) === 0) { return $this; } $this->parts[] = $part; return $this; } /** * Retrieves the amount of expressions on composite expression. * * @return int */ public function count() { return count($this->parts); } /** * Retrieves the string representation of this composite expression. * * @return string */ public function __toString() { if ($this->count() === 1) { return (string) $this->parts[0]; } return '(' . implode(') ' . $this->type . ' (', $this->parts) . ')'; } /** * Returns the type of this composite expression (AND/OR). * * @return string */ public function getType() { return $this->type; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Query/Expression/ExpressionBuilder.php000066400000000000000000000210341360544566000275420ustar00rootroot00000000000000'; public const LT = '<'; public const LTE = '<='; public const GT = '>'; public const GTE = '>='; /** * The DBAL Connection. * * @var Connection */ private $connection; /** * Initializes a new ExpressionBuilder. * * @param Connection $connection The DBAL Connection. */ public function __construct(Connection $connection) { $this->connection = $connection; } /** * Creates a conjunction of the given boolean expressions. * * Example: * * [php] * // (u.type = ?) AND (u.role = ?) * $expr->andX('u.type = ?', 'u.role = ?')); * * @param mixed $x Optional clause. Defaults = null, but requires * at least one defined when converting to string. * * @return CompositeExpression */ public function andX($x = null) { return new CompositeExpression(CompositeExpression::TYPE_AND, func_get_args()); } /** * Creates a disjunction of the given boolean expressions. * * Example: * * [php] * // (u.type = ?) OR (u.role = ?) * $qb->where($qb->expr()->orX('u.type = ?', 'u.role = ?')); * * @param mixed $x Optional clause. Defaults = null, but requires * at least one defined when converting to string. * * @return CompositeExpression */ public function orX($x = null) { return new CompositeExpression(CompositeExpression::TYPE_OR, func_get_args()); } /** * Creates a comparison expression. * * @param mixed $x The left expression. * @param string $operator One of the ExpressionBuilder::* constants. * @param mixed $y The right expression. * * @return string */ public function comparison($x, $operator, $y) { return $x . ' ' . $operator . ' ' . $y; } /** * Creates an equality comparison expression with the given arguments. * * First argument is considered the left expression and the second is the right expression. * When converted to string, it will generated a = . Example: * * [php] * // u.id = ? * $expr->eq('u.id', '?'); * * @param mixed $x The left expression. * @param mixed $y The right expression. * * @return string */ public function eq($x, $y) { return $this->comparison($x, self::EQ, $y); } /** * Creates a non equality comparison expression with the given arguments. * First argument is considered the left expression and the second is the right expression. * When converted to string, it will generated a <> . Example: * * [php] * // u.id <> 1 * $q->where($q->expr()->neq('u.id', '1')); * * @param mixed $x The left expression. * @param mixed $y The right expression. * * @return string */ public function neq($x, $y) { return $this->comparison($x, self::NEQ, $y); } /** * Creates a lower-than comparison expression with the given arguments. * First argument is considered the left expression and the second is the right expression. * When converted to string, it will generated a < . Example: * * [php] * // u.id < ? * $q->where($q->expr()->lt('u.id', '?')); * * @param mixed $x The left expression. * @param mixed $y The right expression. * * @return string */ public function lt($x, $y) { return $this->comparison($x, self::LT, $y); } /** * Creates a lower-than-equal comparison expression with the given arguments. * First argument is considered the left expression and the second is the right expression. * When converted to string, it will generated a <= . Example: * * [php] * // u.id <= ? * $q->where($q->expr()->lte('u.id', '?')); * * @param mixed $x The left expression. * @param mixed $y The right expression. * * @return string */ public function lte($x, $y) { return $this->comparison($x, self::LTE, $y); } /** * Creates a greater-than comparison expression with the given arguments. * First argument is considered the left expression and the second is the right expression. * When converted to string, it will generated a > . Example: * * [php] * // u.id > ? * $q->where($q->expr()->gt('u.id', '?')); * * @param mixed $x The left expression. * @param mixed $y The right expression. * * @return string */ public function gt($x, $y) { return $this->comparison($x, self::GT, $y); } /** * Creates a greater-than-equal comparison expression with the given arguments. * First argument is considered the left expression and the second is the right expression. * When converted to string, it will generated a >= . Example: * * [php] * // u.id >= ? * $q->where($q->expr()->gte('u.id', '?')); * * @param mixed $x The left expression. * @param mixed $y The right expression. * * @return string */ public function gte($x, $y) { return $this->comparison($x, self::GTE, $y); } /** * Creates an IS NULL expression with the given arguments. * * @param string $x The field in string format to be restricted by IS NULL. * * @return string */ public function isNull($x) { return $x . ' IS NULL'; } /** * Creates an IS NOT NULL expression with the given arguments. * * @param string $x The field in string format to be restricted by IS NOT NULL. * * @return string */ public function isNotNull($x) { return $x . ' IS NOT NULL'; } /** * Creates a LIKE() comparison expression with the given arguments. * * @param string $x Field in string format to be inspected by LIKE() comparison. * @param mixed $y Argument to be used in LIKE() comparison. * * @return string */ public function like($x, $y/*, ?string $escapeChar = null */) { return $this->comparison($x, 'LIKE', $y) . (func_num_args() >= 3 ? sprintf(' ESCAPE %s', func_get_arg(2)) : ''); } /** * Creates a NOT LIKE() comparison expression with the given arguments. * * @param string $x Field in string format to be inspected by NOT LIKE() comparison. * @param mixed $y Argument to be used in NOT LIKE() comparison. * * @return string */ public function notLike($x, $y/*, ?string $escapeChar = null */) { return $this->comparison($x, 'NOT LIKE', $y) . (func_num_args() >= 3 ? sprintf(' ESCAPE %s', func_get_arg(2)) : ''); } /** * Creates a IN () comparison expression with the given arguments. * * @param string $x The field in string format to be inspected by IN() comparison. * @param string|string[] $y The placeholder or the array of values to be used by IN() comparison. * * @return string */ public function in($x, $y) { return $this->comparison($x, 'IN', '(' . implode(', ', (array) $y) . ')'); } /** * Creates a NOT IN () comparison expression with the given arguments. * * @param string $x The field in string format to be inspected by NOT IN() comparison. * @param string|string[] $y The placeholder or the array of values to be used by NOT IN() comparison. * * @return string */ public function notIn($x, $y) { return $this->comparison($x, 'NOT IN', '(' . implode(', ', (array) $y) . ')'); } /** * Quotes a given input parameter. * * @param mixed $input The parameter to be quoted. * @param int|null $type The type of the parameter. * * @return string */ public function literal($input, $type = null) { return $this->connection->quote($input, $type); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Query/QueryBuilder.php000066400000000000000000001150231360544566000243530ustar00rootroot00000000000000 [], 'distinct' => false, 'from' => [], 'join' => [], 'set' => [], 'where' => null, 'groupBy' => [], 'having' => null, 'orderBy' => [], 'values' => [], ]; /** * The array of SQL parts collected. * * @var mixed[] */ private $sqlParts = self::SQL_PARTS_DEFAULTS; /** * The complete SQL string for this query. * * @var string */ private $sql; /** * The query parameters. * * @var mixed[] */ private $params = []; /** * The parameter type map of this query. * * @var int[]|string[] */ private $paramTypes = []; /** * The type of query this is. Can be select, update or delete. * * @var int */ private $type = self::SELECT; /** * The state of the query object. Can be dirty or clean. * * @var int */ private $state = self::STATE_CLEAN; /** * The index of the first result to retrieve. * * @var int */ private $firstResult = null; /** * The maximum number of results to retrieve. * * @var int */ private $maxResults = null; /** * The counter of bound parameters used with {@see bindValue). * * @var int */ private $boundCounter = 0; /** * Initializes a new QueryBuilder. * * @param Connection $connection The DBAL Connection. */ public function __construct(Connection $connection) { $this->connection = $connection; } /** * Gets an ExpressionBuilder used for object-oriented construction of query expressions. * This producer method is intended for convenient inline usage. Example: * * * $qb = $conn->createQueryBuilder() * ->select('u') * ->from('users', 'u') * ->where($qb->expr()->eq('u.id', 1)); * * * For more complex expression construction, consider storing the expression * builder object in a local variable. * * @return ExpressionBuilder */ public function expr() { return $this->connection->getExpressionBuilder(); } /** * Gets the type of the currently built query. * * @return int */ public function getType() { return $this->type; } /** * Gets the associated DBAL Connection for this query builder. * * @return Connection */ public function getConnection() { return $this->connection; } /** * Gets the state of this query builder instance. * * @return int Either QueryBuilder::STATE_DIRTY or QueryBuilder::STATE_CLEAN. */ public function getState() { return $this->state; } /** * Executes this query using the bound parameters and their types. * * Uses {@see Connection::executeQuery} for select statements and {@see Connection::executeUpdate} * for insert, update and delete statements. * * @return Statement|int */ public function execute() { if ($this->type === self::SELECT) { return $this->connection->executeQuery($this->getSQL(), $this->params, $this->paramTypes); } return $this->connection->executeUpdate($this->getSQL(), $this->params, $this->paramTypes); } /** * Gets the complete SQL string formed by the current specifications of this QueryBuilder. * * * $qb = $em->createQueryBuilder() * ->select('u') * ->from('User', 'u') * echo $qb->getSQL(); // SELECT u FROM User u * * * @return string The SQL query string. */ public function getSQL() { if ($this->sql !== null && $this->state === self::STATE_CLEAN) { return $this->sql; } switch ($this->type) { case self::INSERT: $sql = $this->getSQLForInsert(); break; case self::DELETE: $sql = $this->getSQLForDelete(); break; case self::UPDATE: $sql = $this->getSQLForUpdate(); break; case self::SELECT: default: $sql = $this->getSQLForSelect(); break; } $this->state = self::STATE_CLEAN; $this->sql = $sql; return $sql; } /** * Sets a query parameter for the query being constructed. * * * $qb = $conn->createQueryBuilder() * ->select('u') * ->from('users', 'u') * ->where('u.id = :user_id') * ->setParameter(':user_id', 1); * * * @param string|int $key The parameter position or name. * @param mixed $value The parameter value. * @param string|int|null $type One of the {@link \Doctrine\DBAL\ParameterType} constants. * * @return $this This QueryBuilder instance. */ public function setParameter($key, $value, $type = null) { if ($type !== null) { $this->paramTypes[$key] = $type; } $this->params[$key] = $value; return $this; } /** * Sets a collection of query parameters for the query being constructed. * * * $qb = $conn->createQueryBuilder() * ->select('u') * ->from('users', 'u') * ->where('u.id = :user_id1 OR u.id = :user_id2') * ->setParameters(array( * ':user_id1' => 1, * ':user_id2' => 2 * )); * * * @param mixed[] $params The query parameters to set. * @param int[]|string[] $types The query parameters types to set. * * @return $this This QueryBuilder instance. */ public function setParameters(array $params, array $types = []) { $this->paramTypes = $types; $this->params = $params; return $this; } /** * Gets all defined query parameters for the query being constructed indexed by parameter index or name. * * @return mixed[] The currently defined query parameters indexed by parameter index or name. */ public function getParameters() { return $this->params; } /** * Gets a (previously set) query parameter of the query being constructed. * * @param mixed $key The key (index or name) of the bound parameter. * * @return mixed The value of the bound parameter. */ public function getParameter($key) { return $this->params[$key] ?? null; } /** * Gets all defined query parameter types for the query being constructed indexed by parameter index or name. * * @return int[]|string[] The currently defined query parameter types indexed by parameter index or name. */ public function getParameterTypes() { return $this->paramTypes; } /** * Gets a (previously set) query parameter type of the query being constructed. * * @param mixed $key The key (index or name) of the bound parameter type. * * @return mixed The value of the bound parameter type. */ public function getParameterType($key) { return $this->paramTypes[$key] ?? null; } /** * Sets the position of the first result to retrieve (the "offset"). * * @param int $firstResult The first result to return. * * @return $this This QueryBuilder instance. */ public function setFirstResult($firstResult) { $this->state = self::STATE_DIRTY; $this->firstResult = $firstResult; return $this; } /** * Gets the position of the first result the query object was set to retrieve (the "offset"). * Returns NULL if {@link setFirstResult} was not applied to this QueryBuilder. * * @return int The position of the first result. */ public function getFirstResult() { return $this->firstResult; } /** * Sets the maximum number of results to retrieve (the "limit"). * * @param int $maxResults The maximum number of results to retrieve. * * @return $this This QueryBuilder instance. */ public function setMaxResults($maxResults) { $this->state = self::STATE_DIRTY; $this->maxResults = $maxResults; return $this; } /** * Gets the maximum number of results the query object was set to retrieve (the "limit"). * Returns NULL if {@link setMaxResults} was not applied to this query builder. * * @return int The maximum number of results. */ public function getMaxResults() { return $this->maxResults; } /** * Either appends to or replaces a single, generic query part. * * The available parts are: 'select', 'from', 'set', 'where', * 'groupBy', 'having' and 'orderBy'. * * @param string $sqlPartName * @param mixed $sqlPart * @param bool $append * * @return $this This QueryBuilder instance. */ public function add($sqlPartName, $sqlPart, $append = false) { $isArray = is_array($sqlPart); $isMultiple = is_array($this->sqlParts[$sqlPartName]); if ($isMultiple && ! $isArray) { $sqlPart = [$sqlPart]; } $this->state = self::STATE_DIRTY; if ($append) { if ($sqlPartName === 'orderBy' || $sqlPartName === 'groupBy' || $sqlPartName === 'select' || $sqlPartName === 'set') { foreach ($sqlPart as $part) { $this->sqlParts[$sqlPartName][] = $part; } } elseif ($isArray && is_array($sqlPart[key($sqlPart)])) { $key = key($sqlPart); $this->sqlParts[$sqlPartName][$key][] = $sqlPart[$key]; } elseif ($isMultiple) { $this->sqlParts[$sqlPartName][] = $sqlPart; } else { $this->sqlParts[$sqlPartName] = $sqlPart; } return $this; } $this->sqlParts[$sqlPartName] = $sqlPart; return $this; } /** * Specifies an item that is to be returned in the query result. * Replaces any previously specified selections, if any. * * * $qb = $conn->createQueryBuilder() * ->select('u.id', 'p.id') * ->from('users', 'u') * ->leftJoin('u', 'phonenumbers', 'p', 'u.id = p.user_id'); * * * @param mixed $select The selection expressions. * * @return $this This QueryBuilder instance. */ public function select($select = null) { $this->type = self::SELECT; if (empty($select)) { return $this; } $selects = is_array($select) ? $select : func_get_args(); return $this->add('select', $selects); } /** * Adds DISTINCT to the query. * * * $qb = $conn->createQueryBuilder() * ->select('u.id') * ->distinct() * ->from('users', 'u') * * * @return $this This QueryBuilder instance. */ public function distinct() : self { $this->sqlParts['distinct'] = true; return $this; } /** * Adds an item that is to be returned in the query result. * * * $qb = $conn->createQueryBuilder() * ->select('u.id') * ->addSelect('p.id') * ->from('users', 'u') * ->leftJoin('u', 'phonenumbers', 'u.id = p.user_id'); * * * @param mixed $select The selection expression. * * @return $this This QueryBuilder instance. */ public function addSelect($select = null) { $this->type = self::SELECT; if (empty($select)) { return $this; } $selects = is_array($select) ? $select : func_get_args(); return $this->add('select', $selects, true); } /** * Turns the query being built into a bulk delete query that ranges over * a certain table. * * * $qb = $conn->createQueryBuilder() * ->delete('users', 'u') * ->where('u.id = :user_id') * ->setParameter(':user_id', 1); * * * @param string $delete The table whose rows are subject to the deletion. * @param string $alias The table alias used in the constructed query. * * @return $this This QueryBuilder instance. */ public function delete($delete = null, $alias = null) { $this->type = self::DELETE; if (! $delete) { return $this; } return $this->add('from', [ 'table' => $delete, 'alias' => $alias, ]); } /** * Turns the query being built into a bulk update query that ranges over * a certain table * * * $qb = $conn->createQueryBuilder() * ->update('counters', 'c') * ->set('c.value', 'c.value + 1') * ->where('c.id = ?'); * * * @param string $update The table whose rows are subject to the update. * @param string $alias The table alias used in the constructed query. * * @return $this This QueryBuilder instance. */ public function update($update = null, $alias = null) { $this->type = self::UPDATE; if (! $update) { return $this; } return $this->add('from', [ 'table' => $update, 'alias' => $alias, ]); } /** * Turns the query being built into an insert query that inserts into * a certain table * * * $qb = $conn->createQueryBuilder() * ->insert('users') * ->values( * array( * 'name' => '?', * 'password' => '?' * ) * ); * * * @param string $insert The table into which the rows should be inserted. * * @return $this This QueryBuilder instance. */ public function insert($insert = null) { $this->type = self::INSERT; if (! $insert) { return $this; } return $this->add('from', ['table' => $insert]); } /** * Creates and adds a query root corresponding to the table identified by the * given alias, forming a cartesian product with any existing query roots. * * * $qb = $conn->createQueryBuilder() * ->select('u.id') * ->from('users', 'u') * * * @param string $from The table. * @param string|null $alias The alias of the table. * * @return $this This QueryBuilder instance. */ public function from($from, $alias = null) { return $this->add('from', [ 'table' => $from, 'alias' => $alias, ], true); } /** * Creates and adds a join to the query. * * * $qb = $conn->createQueryBuilder() * ->select('u.name') * ->from('users', 'u') * ->join('u', 'phonenumbers', 'p', 'p.is_primary = 1'); * * * @param string $fromAlias The alias that points to a from clause. * @param string $join The table name to join. * @param string $alias The alias of the join table. * @param string $condition The condition for the join. * * @return $this This QueryBuilder instance. */ public function join($fromAlias, $join, $alias, $condition = null) { return $this->innerJoin($fromAlias, $join, $alias, $condition); } /** * Creates and adds a join to the query. * * * $qb = $conn->createQueryBuilder() * ->select('u.name') * ->from('users', 'u') * ->innerJoin('u', 'phonenumbers', 'p', 'p.is_primary = 1'); * * * @param string $fromAlias The alias that points to a from clause. * @param string $join The table name to join. * @param string $alias The alias of the join table. * @param string $condition The condition for the join. * * @return $this This QueryBuilder instance. */ public function innerJoin($fromAlias, $join, $alias, $condition = null) { return $this->add('join', [ $fromAlias => [ 'joinType' => 'inner', 'joinTable' => $join, 'joinAlias' => $alias, 'joinCondition' => $condition, ], ], true); } /** * Creates and adds a left join to the query. * * * $qb = $conn->createQueryBuilder() * ->select('u.name') * ->from('users', 'u') * ->leftJoin('u', 'phonenumbers', 'p', 'p.is_primary = 1'); * * * @param string $fromAlias The alias that points to a from clause. * @param string $join The table name to join. * @param string $alias The alias of the join table. * @param string $condition The condition for the join. * * @return $this This QueryBuilder instance. */ public function leftJoin($fromAlias, $join, $alias, $condition = null) { return $this->add('join', [ $fromAlias => [ 'joinType' => 'left', 'joinTable' => $join, 'joinAlias' => $alias, 'joinCondition' => $condition, ], ], true); } /** * Creates and adds a right join to the query. * * * $qb = $conn->createQueryBuilder() * ->select('u.name') * ->from('users', 'u') * ->rightJoin('u', 'phonenumbers', 'p', 'p.is_primary = 1'); * * * @param string $fromAlias The alias that points to a from clause. * @param string $join The table name to join. * @param string $alias The alias of the join table. * @param string $condition The condition for the join. * * @return $this This QueryBuilder instance. */ public function rightJoin($fromAlias, $join, $alias, $condition = null) { return $this->add('join', [ $fromAlias => [ 'joinType' => 'right', 'joinTable' => $join, 'joinAlias' => $alias, 'joinCondition' => $condition, ], ], true); } /** * Sets a new value for a column in a bulk update query. * * * $qb = $conn->createQueryBuilder() * ->update('counters', 'c') * ->set('c.value', 'c.value + 1') * ->where('c.id = ?'); * * * @param string $key The column to set. * @param string $value The value, expression, placeholder, etc. * * @return $this This QueryBuilder instance. */ public function set($key, $value) { return $this->add('set', $key . ' = ' . $value, true); } /** * Specifies one or more restrictions to the query result. * Replaces any previously specified restrictions, if any. * * * $qb = $conn->createQueryBuilder() * ->select('c.value') * ->from('counters', 'c') * ->where('c.id = ?'); * * // You can optionally programatically build and/or expressions * $qb = $conn->createQueryBuilder(); * * $or = $qb->expr()->orx(); * $or->add($qb->expr()->eq('c.id', 1)); * $or->add($qb->expr()->eq('c.id', 2)); * * $qb->update('counters', 'c') * ->set('c.value', 'c.value + 1') * ->where($or); * * * @param mixed $predicates The restriction predicates. * * @return $this This QueryBuilder instance. */ public function where($predicates) { if (! (func_num_args() === 1 && $predicates instanceof CompositeExpression)) { $predicates = new CompositeExpression(CompositeExpression::TYPE_AND, func_get_args()); } return $this->add('where', $predicates); } /** * Adds one or more restrictions to the query results, forming a logical * conjunction with any previously specified restrictions. * * * $qb = $conn->createQueryBuilder() * ->select('u') * ->from('users', 'u') * ->where('u.username LIKE ?') * ->andWhere('u.is_active = 1'); * * * @see where() * * @param mixed $where The query restrictions. * * @return $this This QueryBuilder instance. */ public function andWhere($where) { $args = func_get_args(); $where = $this->getQueryPart('where'); if ($where instanceof CompositeExpression && $where->getType() === CompositeExpression::TYPE_AND) { $where->addMultiple($args); } else { array_unshift($args, $where); $where = new CompositeExpression(CompositeExpression::TYPE_AND, $args); } return $this->add('where', $where, true); } /** * Adds one or more restrictions to the query results, forming a logical * disjunction with any previously specified restrictions. * * * $qb = $em->createQueryBuilder() * ->select('u.name') * ->from('users', 'u') * ->where('u.id = 1') * ->orWhere('u.id = 2'); * * * @see where() * * @param mixed $where The WHERE statement. * * @return $this This QueryBuilder instance. */ public function orWhere($where) { $args = func_get_args(); $where = $this->getQueryPart('where'); if ($where instanceof CompositeExpression && $where->getType() === CompositeExpression::TYPE_OR) { $where->addMultiple($args); } else { array_unshift($args, $where); $where = new CompositeExpression(CompositeExpression::TYPE_OR, $args); } return $this->add('where', $where, true); } /** * Specifies a grouping over the results of the query. * Replaces any previously specified groupings, if any. * * * $qb = $conn->createQueryBuilder() * ->select('u.name') * ->from('users', 'u') * ->groupBy('u.id'); * * * @param mixed $groupBy The grouping expression. * * @return $this This QueryBuilder instance. */ public function groupBy($groupBy) { if (empty($groupBy)) { return $this; } $groupBy = is_array($groupBy) ? $groupBy : func_get_args(); return $this->add('groupBy', $groupBy, false); } /** * Adds a grouping expression to the query. * * * $qb = $conn->createQueryBuilder() * ->select('u.name') * ->from('users', 'u') * ->groupBy('u.lastLogin') * ->addGroupBy('u.createdAt'); * * * @param mixed $groupBy The grouping expression. * * @return $this This QueryBuilder instance. */ public function addGroupBy($groupBy) { if (empty($groupBy)) { return $this; } $groupBy = is_array($groupBy) ? $groupBy : func_get_args(); return $this->add('groupBy', $groupBy, true); } /** * Sets a value for a column in an insert query. * * * $qb = $conn->createQueryBuilder() * ->insert('users') * ->values( * array( * 'name' => '?' * ) * ) * ->setValue('password', '?'); * * * @param string $column The column into which the value should be inserted. * @param string $value The value that should be inserted into the column. * * @return $this This QueryBuilder instance. */ public function setValue($column, $value) { $this->sqlParts['values'][$column] = $value; return $this; } /** * Specifies values for an insert query indexed by column names. * Replaces any previous values, if any. * * * $qb = $conn->createQueryBuilder() * ->insert('users') * ->values( * array( * 'name' => '?', * 'password' => '?' * ) * ); * * * @param mixed[] $values The values to specify for the insert query indexed by column names. * * @return $this This QueryBuilder instance. */ public function values(array $values) { return $this->add('values', $values); } /** * Specifies a restriction over the groups of the query. * Replaces any previous having restrictions, if any. * * @param mixed $having The restriction over the groups. * * @return $this This QueryBuilder instance. */ public function having($having) { if (! (func_num_args() === 1 && $having instanceof CompositeExpression)) { $having = new CompositeExpression(CompositeExpression::TYPE_AND, func_get_args()); } return $this->add('having', $having); } /** * Adds a restriction over the groups of the query, forming a logical * conjunction with any existing having restrictions. * * @param mixed $having The restriction to append. * * @return $this This QueryBuilder instance. */ public function andHaving($having) { $args = func_get_args(); $having = $this->getQueryPart('having'); if ($having instanceof CompositeExpression && $having->getType() === CompositeExpression::TYPE_AND) { $having->addMultiple($args); } else { array_unshift($args, $having); $having = new CompositeExpression(CompositeExpression::TYPE_AND, $args); } return $this->add('having', $having); } /** * Adds a restriction over the groups of the query, forming a logical * disjunction with any existing having restrictions. * * @param mixed $having The restriction to add. * * @return $this This QueryBuilder instance. */ public function orHaving($having) { $args = func_get_args(); $having = $this->getQueryPart('having'); if ($having instanceof CompositeExpression && $having->getType() === CompositeExpression::TYPE_OR) { $having->addMultiple($args); } else { array_unshift($args, $having); $having = new CompositeExpression(CompositeExpression::TYPE_OR, $args); } return $this->add('having', $having); } /** * Specifies an ordering for the query results. * Replaces any previously specified orderings, if any. * * @param string $sort The ordering expression. * @param string $order The ordering direction. * * @return $this This QueryBuilder instance. */ public function orderBy($sort, $order = null) { return $this->add('orderBy', $sort . ' ' . (! $order ? 'ASC' : $order), false); } /** * Adds an ordering to the query results. * * @param string $sort The ordering expression. * @param string $order The ordering direction. * * @return $this This QueryBuilder instance. */ public function addOrderBy($sort, $order = null) { return $this->add('orderBy', $sort . ' ' . (! $order ? 'ASC' : $order), true); } /** * Gets a query part by its name. * * @param string $queryPartName * * @return mixed */ public function getQueryPart($queryPartName) { return $this->sqlParts[$queryPartName]; } /** * Gets all query parts. * * @return mixed[] */ public function getQueryParts() { return $this->sqlParts; } /** * Resets SQL parts. * * @param string[]|null $queryPartNames * * @return $this This QueryBuilder instance. */ public function resetQueryParts($queryPartNames = null) { if ($queryPartNames === null) { $queryPartNames = array_keys($this->sqlParts); } foreach ($queryPartNames as $queryPartName) { $this->resetQueryPart($queryPartName); } return $this; } /** * Resets a single SQL part. * * @param string $queryPartName * * @return $this This QueryBuilder instance. */ public function resetQueryPart($queryPartName) { $this->sqlParts[$queryPartName] = self::SQL_PARTS_DEFAULTS[$queryPartName]; $this->state = self::STATE_DIRTY; return $this; } /** * @return string * * @throws QueryException */ private function getSQLForSelect() { $query = 'SELECT ' . ($this->sqlParts['distinct'] ? 'DISTINCT ' : '') . implode(', ', $this->sqlParts['select']); $query .= ($this->sqlParts['from'] ? ' FROM ' . implode(', ', $this->getFromClauses()) : '') . ($this->sqlParts['where'] !== null ? ' WHERE ' . ((string) $this->sqlParts['where']) : '') . ($this->sqlParts['groupBy'] ? ' GROUP BY ' . implode(', ', $this->sqlParts['groupBy']) : '') . ($this->sqlParts['having'] !== null ? ' HAVING ' . ((string) $this->sqlParts['having']) : '') . ($this->sqlParts['orderBy'] ? ' ORDER BY ' . implode(', ', $this->sqlParts['orderBy']) : ''); if ($this->isLimitQuery()) { return $this->connection->getDatabasePlatform()->modifyLimitQuery( $query, $this->maxResults, $this->firstResult ); } return $query; } /** * @return string[] */ private function getFromClauses() { $fromClauses = []; $knownAliases = []; // Loop through all FROM clauses foreach ($this->sqlParts['from'] as $from) { if ($from['alias'] === null) { $tableSql = $from['table']; $tableReference = $from['table']; } else { $tableSql = $from['table'] . ' ' . $from['alias']; $tableReference = $from['alias']; } $knownAliases[$tableReference] = true; $fromClauses[$tableReference] = $tableSql . $this->getSQLForJoins($tableReference, $knownAliases); } $this->verifyAllAliasesAreKnown($knownAliases); return $fromClauses; } /** * @param string[] $knownAliases * * @throws QueryException */ private function verifyAllAliasesAreKnown(array $knownAliases) { foreach ($this->sqlParts['join'] as $fromAlias => $joins) { if (! isset($knownAliases[$fromAlias])) { throw QueryException::unknownAlias($fromAlias, array_keys($knownAliases)); } } } /** * @return bool */ private function isLimitQuery() { return $this->maxResults !== null || $this->firstResult !== null; } /** * Converts this instance into an INSERT string in SQL. * * @return string */ private function getSQLForInsert() { return 'INSERT INTO ' . $this->sqlParts['from']['table'] . ' (' . implode(', ', array_keys($this->sqlParts['values'])) . ')' . ' VALUES(' . implode(', ', $this->sqlParts['values']) . ')'; } /** * Converts this instance into an UPDATE string in SQL. * * @return string */ private function getSQLForUpdate() { $table = $this->sqlParts['from']['table'] . ($this->sqlParts['from']['alias'] ? ' ' . $this->sqlParts['from']['alias'] : ''); return 'UPDATE ' . $table . ' SET ' . implode(', ', $this->sqlParts['set']) . ($this->sqlParts['where'] !== null ? ' WHERE ' . ((string) $this->sqlParts['where']) : ''); } /** * Converts this instance into a DELETE string in SQL. * * @return string */ private function getSQLForDelete() { $table = $this->sqlParts['from']['table'] . ($this->sqlParts['from']['alias'] ? ' ' . $this->sqlParts['from']['alias'] : ''); return 'DELETE FROM ' . $table . ($this->sqlParts['where'] !== null ? ' WHERE ' . ((string) $this->sqlParts['where']) : ''); } /** * Gets a string representation of this QueryBuilder which corresponds to * the final SQL query being constructed. * * @return string The string representation of this QueryBuilder. */ public function __toString() { return $this->getSQL(); } /** * Creates a new named parameter and bind the value $value to it. * * This method provides a shortcut for PDOStatement::bindValue * when using prepared statements. * * The parameter $value specifies the value that you want to bind. If * $placeholder is not provided bindValue() will automatically create a * placeholder for you. An automatic placeholder will be of the name * ':dcValue1', ':dcValue2' etc. * * For more information see {@link http://php.net/pdostatement-bindparam} * * Example: * * $value = 2; * $q->eq( 'id', $q->bindValue( $value ) ); * $stmt = $q->executeQuery(); // executed with 'id = 2' * * * @link http://www.zetacomponents.org * * @param mixed $value * @param mixed $type * @param string $placeHolder The name to bind with. The string must start with a colon ':'. * * @return string the placeholder name used. */ public function createNamedParameter($value, $type = ParameterType::STRING, $placeHolder = null) { if ($placeHolder === null) { $this->boundCounter++; $placeHolder = ':dcValue' . $this->boundCounter; } $this->setParameter(substr($placeHolder, 1), $value, $type); return $placeHolder; } /** * Creates a new positional parameter and bind the given value to it. * * Attention: If you are using positional parameters with the query builder you have * to be very careful to bind all parameters in the order they appear in the SQL * statement , otherwise they get bound in the wrong order which can lead to serious * bugs in your code. * * Example: * * $qb = $conn->createQueryBuilder(); * $qb->select('u.*') * ->from('users', 'u') * ->where('u.username = ' . $qb->createPositionalParameter('Foo', ParameterType::STRING)) * ->orWhere('u.username = ' . $qb->createPositionalParameter('Bar', ParameterType::STRING)) * * * @param mixed $value * @param int $type * * @return string */ public function createPositionalParameter($value, $type = ParameterType::STRING) { $this->boundCounter++; $this->setParameter($this->boundCounter, $value, $type); return '?'; } /** * @param string $fromAlias * @param string[] $knownAliases * * @return string * * @throws QueryException */ private function getSQLForJoins($fromAlias, array &$knownAliases) { $sql = ''; if (isset($this->sqlParts['join'][$fromAlias])) { foreach ($this->sqlParts['join'][$fromAlias] as $join) { if (array_key_exists($join['joinAlias'], $knownAliases)) { throw QueryException::nonUniqueAlias($join['joinAlias'], array_keys($knownAliases)); } $sql .= ' ' . strtoupper($join['joinType']) . ' JOIN ' . $join['joinTable'] . ' ' . $join['joinAlias'] . ' ON ' . ((string) $join['joinCondition']); $knownAliases[$join['joinAlias']] = true; } foreach ($this->sqlParts['join'][$fromAlias] as $join) { $sql .= $this->getSQLForJoins($join['joinAlias'], $knownAliases); } } return $sql; } /** * Deep clone of all expression objects in the SQL parts. * * @return void */ public function __clone() { foreach ($this->sqlParts as $part => $elements) { if (is_array($this->sqlParts[$part])) { foreach ($this->sqlParts[$part] as $idx => $element) { if (! is_object($element)) { continue; } $this->sqlParts[$part][$idx] = clone $element; } } elseif (is_object($elements)) { $this->sqlParts[$part] = clone $elements; } } foreach ($this->params as $name => $param) { if (! is_object($param)) { continue; } $this->params[$name] = clone $param; } } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Query/QueryException.php000066400000000000000000000020201360544566000247130ustar00rootroot00000000000000 $type) { ++$bindIndex; if ($type !== Connection::PARAM_INT_ARRAY && $type !== Connection::PARAM_STR_ARRAY) { continue; } if ($isPositional) { $name = $bindIndex; } $arrayPositions[$name] = false; } if (( ! $arrayPositions && $isPositional)) { return [$query, $params, $types]; } if ($isPositional) { $paramOffset = 0; $queryOffset = 0; $params = array_values($params); $types = array_values($types); $paramPos = self::getPositionalPlaceholderPositions($query); foreach ($paramPos as $needle => $needlePos) { if (! isset($arrayPositions[$needle])) { continue; } $needle += $paramOffset; $needlePos += $queryOffset; $count = count($params[$needle]); $params = array_merge( array_slice($params, 0, $needle), $params[$needle], array_slice($params, $needle + 1) ); $types = array_merge( array_slice($types, 0, $needle), $count ? // array needles are at {@link \Doctrine\DBAL\ParameterType} constants // + {@link Doctrine\DBAL\Connection::ARRAY_PARAM_OFFSET} array_fill(0, $count, $types[$needle] - Connection::ARRAY_PARAM_OFFSET) : [], array_slice($types, $needle + 1) ); $expandStr = $count ? implode(', ', array_fill(0, $count, '?')) : 'NULL'; $query = substr($query, 0, $needlePos) . $expandStr . substr($query, $needlePos + 1); $paramOffset += ($count - 1); // Grows larger by number of parameters minus the replaced needle. $queryOffset += (strlen($expandStr) - 1); } return [$query, $params, $types]; } $queryOffset = 0; $typesOrd = []; $paramsOrd = []; $paramPos = self::getNamedPlaceholderPositions($query); foreach ($paramPos as $pos => $paramName) { $paramLen = strlen($paramName) + 1; $value = static::extractParam($paramName, $params, true); if (! isset($arrayPositions[$paramName]) && ! isset($arrayPositions[':' . $paramName])) { $pos += $queryOffset; $queryOffset -= ($paramLen - 1); $paramsOrd[] = $value; $typesOrd[] = static::extractParam($paramName, $types, false, ParameterType::STRING); $query = substr($query, 0, $pos) . '?' . substr($query, ($pos + $paramLen)); continue; } $count = count($value); $expandStr = $count > 0 ? implode(', ', array_fill(0, $count, '?')) : 'NULL'; foreach ($value as $val) { $paramsOrd[] = $val; $typesOrd[] = static::extractParam($paramName, $types, false) - Connection::ARRAY_PARAM_OFFSET; } $pos += $queryOffset; $queryOffset += (strlen($expandStr) - $paramLen); $query = substr($query, 0, $pos) . $expandStr . substr($query, ($pos + $paramLen)); } return [$query, $paramsOrd, $typesOrd]; } /** * Slice the SQL statement around pairs of quotes and * return string fragments of SQL outside of quoted literals. * Each fragment is captured as a 2-element array: * * 0 => matched fragment string, * 1 => offset of fragment in $statement * * @param string $statement * * @return mixed[][] */ private static function getUnquotedStatementFragments($statement) { $literal = self::ESCAPED_SINGLE_QUOTED_TEXT . '|' . self::ESCAPED_DOUBLE_QUOTED_TEXT . '|' . self::ESCAPED_BACKTICK_QUOTED_TEXT . '|' . self::ESCAPED_BRACKET_QUOTED_TEXT; $expression = sprintf('/((.+(?i:ARRAY)\\[.+\\])|([^\'"`\\[]+))(?:%s)?/s', $literal); preg_match_all($expression, $statement, $fragments, PREG_OFFSET_CAPTURE); return $fragments[1]; } /** * @param string $paramName The name of the parameter (without a colon in front) * @param mixed $paramsOrTypes A hash of parameters or types * @param bool $isParam * @param mixed $defaultValue An optional default value. If omitted, an exception is thrown * * @return mixed * * @throws SQLParserUtilsException */ private static function extractParam($paramName, $paramsOrTypes, $isParam, $defaultValue = null) { if (array_key_exists($paramName, $paramsOrTypes)) { return $paramsOrTypes[$paramName]; } // Hash keys can be prefixed with a colon for compatibility if (array_key_exists(':' . $paramName, $paramsOrTypes)) { return $paramsOrTypes[':' . $paramName]; } if ($defaultValue !== null) { return $defaultValue; } if ($isParam) { throw SQLParserUtilsException::missingParam($paramName); } throw SQLParserUtilsException::missingType($paramName); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/SQLParserUtilsException.php000066400000000000000000000013561360544566000253510ustar00rootroot00000000000000 Table($tableName)); if you want to rename the table, you have to make sure */ abstract class AbstractAsset { /** @var string */ protected $_name; /** * Namespace of the asset. If none isset the default namespace is assumed. * * @var string|null */ protected $_namespace = null; /** @var bool */ protected $_quoted = false; /** * Sets the name of this asset. * * @param string $name * * @return void */ protected function _setName($name) { if ($this->isIdentifierQuoted($name)) { $this->_quoted = true; $name = $this->trimQuotes($name); } if (strpos($name, '.') !== false) { $parts = explode('.', $name); $this->_namespace = $parts[0]; $name = $parts[1]; } $this->_name = $name; } /** * Is this asset in the default namespace? * * @param string $defaultNamespaceName * * @return bool */ public function isInDefaultNamespace($defaultNamespaceName) { return $this->_namespace === $defaultNamespaceName || $this->_namespace === null; } /** * Gets the namespace name of this asset. * * If NULL is returned this means the default namespace is used. * * @return string|null */ public function getNamespaceName() { return $this->_namespace; } /** * The shortest name is stripped of the default namespace. All other * namespaced elements are returned as full-qualified names. * * @param string|null $defaultNamespaceName * * @return string */ public function getShortestName($defaultNamespaceName) { $shortestName = $this->getName(); if ($this->_namespace === $defaultNamespaceName) { $shortestName = $this->_name; } return strtolower($shortestName); } /** * The normalized name is full-qualified and lowerspaced. Lowerspacing is * actually wrong, but we have to do it to keep our sanity. If you are * using database objects that only differentiate in the casing (FOO vs * Foo) then you will NOT be able to use Doctrine Schema abstraction. * * Every non-namespaced element is prefixed with the default namespace * name which is passed as argument to this method. * * @param string $defaultNamespaceName * * @return string */ public function getFullQualifiedName($defaultNamespaceName) { $name = $this->getName(); if (! $this->_namespace) { $name = $defaultNamespaceName . '.' . $name; } return strtolower($name); } /** * Checks if this asset's name is quoted. * * @return bool */ public function isQuoted() { return $this->_quoted; } /** * Checks if this identifier is quoted. * * @param string $identifier * * @return bool */ protected function isIdentifierQuoted($identifier) { return isset($identifier[0]) && ($identifier[0] === '`' || $identifier[0] === '"' || $identifier[0] === '['); } /** * Trim quotes from the identifier. * * @param string $identifier * * @return string */ protected function trimQuotes($identifier) { return str_replace(['`', '"', '[', ']'], '', $identifier); } /** * Returns the name of this schema asset. * * @return string */ public function getName() { if ($this->_namespace) { return $this->_namespace . '.' . $this->_name; } return $this->_name; } /** * Gets the quoted representation of this asset but only if it was defined with one. Otherwise * return the plain unquoted value as inserted. * * @return string */ public function getQuotedName(AbstractPlatform $platform) { $keywords = $platform->getReservedKeywordsList(); $parts = explode('.', $this->getName()); foreach ($parts as $k => $v) { $parts[$k] = $this->_quoted || $keywords->isKeyword($v) ? $platform->quoteIdentifier($v) : $v; } return implode('.', $parts); } /** * Generates an identifier from a list of column names obeying a certain string length. * * This is especially important for Oracle, since it does not allow identifiers larger than 30 chars, * however building idents automatically for foreign keys, composite keys or such can easily create * very long names. * * @param string[] $columnNames * @param string $prefix * @param int $maxSize * * @return string */ protected function _generateIdentifierName($columnNames, $prefix = '', $maxSize = 30) { $hash = implode('', array_map(static function ($column) { return dechex(crc32($column)); }, $columnNames)); return strtoupper(substr($prefix . '_' . $hash, 0, $maxSize)); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php000066400000000000000000000720131360544566000262120ustar00rootroot00000000000000_conn = $conn; $this->_platform = $platform ?: $this->_conn->getDatabasePlatform(); } /** * Returns the associated platform. * * @return AbstractPlatform */ public function getDatabasePlatform() { return $this->_platform; } /** * Tries any method on the schema manager. Normally a method throws an * exception when your DBMS doesn't support it or if an error occurs. * This method allows you to try and method on your SchemaManager * instance and will return false if it does not work or is not supported. * * * $result = $sm->tryMethod('dropView', 'view_name'); * * * @return mixed */ public function tryMethod() { $args = func_get_args(); $method = $args[0]; unset($args[0]); $args = array_values($args); $callback = [$this, $method]; assert(is_callable($callback)); try { return call_user_func_array($callback, $args); } catch (Throwable $e) { return false; } } /** * Lists the available databases for this connection. * * @return string[] */ public function listDatabases() { $sql = $this->_platform->getListDatabasesSQL(); $databases = $this->_conn->fetchAll($sql); return $this->_getPortableDatabasesList($databases); } /** * Returns a list of all namespaces in the current database. * * @return string[] */ public function listNamespaceNames() { $sql = $this->_platform->getListNamespacesSQL(); $namespaces = $this->_conn->fetchAll($sql); return $this->getPortableNamespacesList($namespaces); } /** * Lists the available sequences for this connection. * * @param string|null $database * * @return Sequence[] */ public function listSequences($database = null) { if ($database === null) { $database = $this->_conn->getDatabase(); } $sql = $this->_platform->getListSequencesSQL($database); $sequences = $this->_conn->fetchAll($sql); return $this->filterAssetNames($this->_getPortableSequencesList($sequences)); } /** * Lists the columns for a given table. * * In contrast to other libraries and to the old version of Doctrine, * this column definition does try to contain the 'primary' field for * the reason that it is not portable across different RDBMS. Use * {@see listTableIndexes($tableName)} to retrieve the primary key * of a table. Where a RDBMS specifies more details, these are held * in the platformDetails array. * * @param string $table The name of the table. * @param string|null $database * * @return Column[] */ public function listTableColumns($table, $database = null) { if (! $database) { $database = $this->_conn->getDatabase(); } $sql = $this->_platform->getListTableColumnsSQL($table, $database); $tableColumns = $this->_conn->fetchAll($sql); return $this->_getPortableTableColumnList($table, $database, $tableColumns); } /** * Lists the indexes for a given table returning an array of Index instances. * * Keys of the portable indexes list are all lower-cased. * * @param string $table The name of the table. * * @return Index[] */ public function listTableIndexes($table) { $sql = $this->_platform->getListTableIndexesSQL($table, $this->_conn->getDatabase()); $tableIndexes = $this->_conn->fetchAll($sql); return $this->_getPortableTableIndexesList($tableIndexes, $table); } /** * Returns true if all the given tables exist. * * The usage of a string $tableNames is deprecated. Pass a one-element array instead. * * @param string|string[] $tableNames * * @return bool */ public function tablesExist($tableNames) { $tableNames = array_map('strtolower', (array) $tableNames); return count($tableNames) === count(array_intersect($tableNames, array_map('strtolower', $this->listTableNames()))); } /** * Returns a list of all tables in the current database. * * @return string[] */ public function listTableNames() { $sql = $this->_platform->getListTablesSQL(); $tables = $this->_conn->fetchAll($sql); $tableNames = $this->_getPortableTablesList($tables); return $this->filterAssetNames($tableNames); } /** * Filters asset names if they are configured to return only a subset of all * the found elements. * * @param mixed[] $assetNames * * @return mixed[] */ protected function filterAssetNames($assetNames) { $filter = $this->_conn->getConfiguration()->getSchemaAssetsFilter(); if (! $filter) { return $assetNames; } return array_values(array_filter($assetNames, $filter)); } /** * @deprecated Use Configuration::getSchemaAssetsFilter() instead * * @return string|null */ protected function getFilterSchemaAssetsExpression() { return $this->_conn->getConfiguration()->getFilterSchemaAssetsExpression(); } /** * Lists the tables for this connection. * * @return Table[] */ public function listTables() { $tableNames = $this->listTableNames(); $tables = []; foreach ($tableNames as $tableName) { $tables[] = $this->listTableDetails($tableName); } return $tables; } /** * @param string $tableName * * @return Table */ public function listTableDetails($tableName) { $columns = $this->listTableColumns($tableName); $foreignKeys = []; if ($this->_platform->supportsForeignKeyConstraints()) { $foreignKeys = $this->listTableForeignKeys($tableName); } $indexes = $this->listTableIndexes($tableName); return new Table($tableName, $columns, $indexes, $foreignKeys); } /** * Lists the views this connection has. * * @return View[] */ public function listViews() { $database = $this->_conn->getDatabase(); $sql = $this->_platform->getListViewsSQL($database); $views = $this->_conn->fetchAll($sql); return $this->_getPortableViewsList($views); } /** * Lists the foreign keys for the given table. * * @param string $table The name of the table. * @param string|null $database * * @return ForeignKeyConstraint[] */ public function listTableForeignKeys($table, $database = null) { if ($database === null) { $database = $this->_conn->getDatabase(); } $sql = $this->_platform->getListTableForeignKeysSQL($table, $database); $tableForeignKeys = $this->_conn->fetchAll($sql); return $this->_getPortableTableForeignKeysList($tableForeignKeys); } /* drop*() Methods */ /** * Drops a database. * * NOTE: You can not drop the database this SchemaManager is currently connected to. * * @param string $database The name of the database to drop. * * @return void */ public function dropDatabase($database) { $this->_execSql($this->_platform->getDropDatabaseSQL($database)); } /** * Drops the given table. * * @param string $tableName The name of the table to drop. * * @return void */ public function dropTable($tableName) { $this->_execSql($this->_platform->getDropTableSQL($tableName)); } /** * Drops the index from the given table. * * @param Index|string $index The name of the index. * @param Table|string $table The name of the table. * * @return void */ public function dropIndex($index, $table) { if ($index instanceof Index) { $index = $index->getQuotedName($this->_platform); } $this->_execSql($this->_platform->getDropIndexSQL($index, $table)); } /** * Drops the constraint from the given table. * * @param Table|string $table The name of the table. * * @return void */ public function dropConstraint(Constraint $constraint, $table) { $this->_execSql($this->_platform->getDropConstraintSQL($constraint, $table)); } /** * Drops a foreign key from a table. * * @param ForeignKeyConstraint|string $foreignKey The name of the foreign key. * @param Table|string $table The name of the table with the foreign key. * * @return void */ public function dropForeignKey($foreignKey, $table) { $this->_execSql($this->_platform->getDropForeignKeySQL($foreignKey, $table)); } /** * Drops a sequence with a given name. * * @param string $name The name of the sequence to drop. * * @return void */ public function dropSequence($name) { $this->_execSql($this->_platform->getDropSequenceSQL($name)); } /** * Drops a view. * * @param string $name The name of the view. * * @return void */ public function dropView($name) { $this->_execSql($this->_platform->getDropViewSQL($name)); } /* create*() Methods */ /** * Creates a new database. * * @param string $database The name of the database to create. * * @return void */ public function createDatabase($database) { $this->_execSql($this->_platform->getCreateDatabaseSQL($database)); } /** * Creates a new table. * * @return void */ public function createTable(Table $table) { $createFlags = AbstractPlatform::CREATE_INDEXES|AbstractPlatform::CREATE_FOREIGNKEYS; $this->_execSql($this->_platform->getCreateTableSQL($table, $createFlags)); } /** * Creates a new sequence. * * @param Sequence $sequence * * @return void * * @throws ConnectionException If something fails at database level. */ public function createSequence($sequence) { $this->_execSql($this->_platform->getCreateSequenceSQL($sequence)); } /** * Creates a constraint on a table. * * @param Table|string $table * * @return void */ public function createConstraint(Constraint $constraint, $table) { $this->_execSql($this->_platform->getCreateConstraintSQL($constraint, $table)); } /** * Creates a new index on a table. * * @param Table|string $table The name of the table on which the index is to be created. * * @return void */ public function createIndex(Index $index, $table) { $this->_execSql($this->_platform->getCreateIndexSQL($index, $table)); } /** * Creates a new foreign key. * * @param ForeignKeyConstraint $foreignKey The ForeignKey instance. * @param Table|string $table The name of the table on which the foreign key is to be created. * * @return void */ public function createForeignKey(ForeignKeyConstraint $foreignKey, $table) { $this->_execSql($this->_platform->getCreateForeignKeySQL($foreignKey, $table)); } /** * Creates a new view. * * @return void */ public function createView(View $view) { $this->_execSql($this->_platform->getCreateViewSQL($view->getQuotedName($this->_platform), $view->getSql())); } /* dropAndCreate*() Methods */ /** * Drops and creates a constraint. * * @see dropConstraint() * @see createConstraint() * * @param Table|string $table * * @return void */ public function dropAndCreateConstraint(Constraint $constraint, $table) { $this->tryMethod('dropConstraint', $constraint, $table); $this->createConstraint($constraint, $table); } /** * Drops and creates a new index on a table. * * @param Table|string $table The name of the table on which the index is to be created. * * @return void */ public function dropAndCreateIndex(Index $index, $table) { $this->tryMethod('dropIndex', $index->getQuotedName($this->_platform), $table); $this->createIndex($index, $table); } /** * Drops and creates a new foreign key. * * @param ForeignKeyConstraint $foreignKey An associative array that defines properties of the foreign key to be created. * @param Table|string $table The name of the table on which the foreign key is to be created. * * @return void */ public function dropAndCreateForeignKey(ForeignKeyConstraint $foreignKey, $table) { $this->tryMethod('dropForeignKey', $foreignKey, $table); $this->createForeignKey($foreignKey, $table); } /** * Drops and create a new sequence. * * @return void * * @throws ConnectionException If something fails at database level. */ public function dropAndCreateSequence(Sequence $sequence) { $this->tryMethod('dropSequence', $sequence->getQuotedName($this->_platform)); $this->createSequence($sequence); } /** * Drops and creates a new table. * * @return void */ public function dropAndCreateTable(Table $table) { $this->tryMethod('dropTable', $table->getQuotedName($this->_platform)); $this->createTable($table); } /** * Drops and creates a new database. * * @param string $database The name of the database to create. * * @return void */ public function dropAndCreateDatabase($database) { $this->tryMethod('dropDatabase', $database); $this->createDatabase($database); } /** * Drops and creates a new view. * * @return void */ public function dropAndCreateView(View $view) { $this->tryMethod('dropView', $view->getQuotedName($this->_platform)); $this->createView($view); } /* alterTable() Methods */ /** * Alters an existing tables schema. * * @return void */ public function alterTable(TableDiff $tableDiff) { $queries = $this->_platform->getAlterTableSQL($tableDiff); if (! is_array($queries) || ! count($queries)) { return; } foreach ($queries as $ddlQuery) { $this->_execSql($ddlQuery); } } /** * Renames a given table to another name. * * @param string $name The current name of the table. * @param string $newName The new name of the table. * * @return void */ public function renameTable($name, $newName) { $tableDiff = new TableDiff($name); $tableDiff->newName = $newName; $this->alterTable($tableDiff); } /** * Methods for filtering return values of list*() methods to convert * the native DBMS data definition to a portable Doctrine definition */ /** * @param mixed[] $databases * * @return string[] */ protected function _getPortableDatabasesList($databases) { $list = []; foreach ($databases as $value) { $value = $this->_getPortableDatabaseDefinition($value); if (! $value) { continue; } $list[] = $value; } return $list; } /** * Converts a list of namespace names from the native DBMS data definition to a portable Doctrine definition. * * @param mixed[][] $namespaces The list of namespace names in the native DBMS data definition. * * @return string[] */ protected function getPortableNamespacesList(array $namespaces) { $namespacesList = []; foreach ($namespaces as $namespace) { $namespacesList[] = $this->getPortableNamespaceDefinition($namespace); } return $namespacesList; } /** * @param mixed $database * * @return mixed */ protected function _getPortableDatabaseDefinition($database) { return $database; } /** * Converts a namespace definition from the native DBMS data definition to a portable Doctrine definition. * * @param mixed[] $namespace The native DBMS namespace definition. * * @return mixed */ protected function getPortableNamespaceDefinition(array $namespace) { return $namespace; } /** * @deprecated * * @param mixed[][] $functions * * @return mixed[][] */ protected function _getPortableFunctionsList($functions) { $list = []; foreach ($functions as $value) { $value = $this->_getPortableFunctionDefinition($value); if (! $value) { continue; } $list[] = $value; } return $list; } /** * @deprecated * * @param mixed[] $function * * @return mixed */ protected function _getPortableFunctionDefinition($function) { return $function; } /** * @param mixed[][] $triggers * * @return mixed[][] */ protected function _getPortableTriggersList($triggers) { $list = []; foreach ($triggers as $value) { $value = $this->_getPortableTriggerDefinition($value); if (! $value) { continue; } $list[] = $value; } return $list; } /** * @param mixed[] $trigger * * @return mixed */ protected function _getPortableTriggerDefinition($trigger) { return $trigger; } /** * @param mixed[][] $sequences * * @return Sequence[] */ protected function _getPortableSequencesList($sequences) { $list = []; foreach ($sequences as $value) { $list[] = $this->_getPortableSequenceDefinition($value); } return $list; } /** * @param mixed[] $sequence * * @return Sequence * * @throws DBALException */ protected function _getPortableSequenceDefinition($sequence) { throw DBALException::notSupported('Sequences'); } /** * Independent of the database the keys of the column list result are lowercased. * * The name of the created column instance however is kept in its case. * * @param string $table The name of the table. * @param string $database * @param mixed[][] $tableColumns * * @return Column[] */ protected function _getPortableTableColumnList($table, $database, $tableColumns) { $eventManager = $this->_platform->getEventManager(); $list = []; foreach ($tableColumns as $tableColumn) { $column = null; $defaultPrevented = false; if ($eventManager !== null && $eventManager->hasListeners(Events::onSchemaColumnDefinition)) { $eventArgs = new SchemaColumnDefinitionEventArgs($tableColumn, $table, $database, $this->_conn); $eventManager->dispatchEvent(Events::onSchemaColumnDefinition, $eventArgs); $defaultPrevented = $eventArgs->isDefaultPrevented(); $column = $eventArgs->getColumn(); } if (! $defaultPrevented) { $column = $this->_getPortableTableColumnDefinition($tableColumn); } if (! $column) { continue; } $name = strtolower($column->getQuotedName($this->_platform)); $list[$name] = $column; } return $list; } /** * Gets Table Column Definition. * * @param mixed[] $tableColumn * * @return Column */ abstract protected function _getPortableTableColumnDefinition($tableColumn); /** * Aggregates and groups the index results according to the required data result. * * @param mixed[][] $tableIndexRows * @param string|null $tableName * * @return Index[] */ protected function _getPortableTableIndexesList($tableIndexRows, $tableName = null) { $result = []; foreach ($tableIndexRows as $tableIndex) { $indexName = $keyName = $tableIndex['key_name']; if ($tableIndex['primary']) { $keyName = 'primary'; } $keyName = strtolower($keyName); if (! isset($result[$keyName])) { $options = [ 'lengths' => [], ]; if (isset($tableIndex['where'])) { $options['where'] = $tableIndex['where']; } $result[$keyName] = [ 'name' => $indexName, 'columns' => [], 'unique' => ! $tableIndex['non_unique'], 'primary' => $tableIndex['primary'], 'flags' => $tableIndex['flags'] ?? [], 'options' => $options, ]; } $result[$keyName]['columns'][] = $tableIndex['column_name']; $result[$keyName]['options']['lengths'][] = $tableIndex['length'] ?? null; } $eventManager = $this->_platform->getEventManager(); $indexes = []; foreach ($result as $indexKey => $data) { $index = null; $defaultPrevented = false; if ($eventManager !== null && $eventManager->hasListeners(Events::onSchemaIndexDefinition)) { $eventArgs = new SchemaIndexDefinitionEventArgs($data, $tableName, $this->_conn); $eventManager->dispatchEvent(Events::onSchemaIndexDefinition, $eventArgs); $defaultPrevented = $eventArgs->isDefaultPrevented(); $index = $eventArgs->getIndex(); } if (! $defaultPrevented) { $index = new Index($data['name'], $data['columns'], $data['unique'], $data['primary'], $data['flags'], $data['options']); } if (! $index) { continue; } $indexes[$indexKey] = $index; } return $indexes; } /** * @param mixed[][] $tables * * @return string[] */ protected function _getPortableTablesList($tables) { $list = []; foreach ($tables as $value) { $value = $this->_getPortableTableDefinition($value); if (! $value) { continue; } $list[] = $value; } return $list; } /** * @param mixed $table * * @return string */ protected function _getPortableTableDefinition($table) { return $table; } /** * @param mixed[][] $users * * @return string[][] */ protected function _getPortableUsersList($users) { $list = []; foreach ($users as $value) { $value = $this->_getPortableUserDefinition($value); if (! $value) { continue; } $list[] = $value; } return $list; } /** * @param string[] $user * * @return string[] */ protected function _getPortableUserDefinition($user) { return $user; } /** * @param mixed[][] $views * * @return View[] */ protected function _getPortableViewsList($views) { $list = []; foreach ($views as $value) { $view = $this->_getPortableViewDefinition($value); if (! $view) { continue; } $viewName = strtolower($view->getQuotedName($this->_platform)); $list[$viewName] = $view; } return $list; } /** * @param mixed[] $view * * @return View|false */ protected function _getPortableViewDefinition($view) { return false; } /** * @param mixed[][] $tableForeignKeys * * @return ForeignKeyConstraint[] */ protected function _getPortableTableForeignKeysList($tableForeignKeys) { $list = []; foreach ($tableForeignKeys as $value) { $list[] = $this->_getPortableTableForeignKeyDefinition($value); } return $list; } /** * @param mixed $tableForeignKey * * @return ForeignKeyConstraint */ protected function _getPortableTableForeignKeyDefinition($tableForeignKey) { return $tableForeignKey; } /** * @param string[]|string $sql * * @return void */ protected function _execSql($sql) { foreach ((array) $sql as $query) { $this->_conn->executeUpdate($query); } } /** * Creates a schema instance for the current database. * * @return Schema */ public function createSchema() { $namespaces = []; if ($this->_platform->supportsSchemas()) { $namespaces = $this->listNamespaceNames(); } $sequences = []; if ($this->_platform->supportsSequences()) { $sequences = $this->listSequences(); } $tables = $this->listTables(); return new Schema($tables, $sequences, $this->createSchemaConfig(), $namespaces); } /** * Creates the configuration for this schema. * * @return SchemaConfig */ public function createSchemaConfig() { $schemaConfig = new SchemaConfig(); $schemaConfig->setMaxIdentifierLength($this->_platform->getMaxIdentifierLength()); $searchPaths = $this->getSchemaSearchPaths(); if (isset($searchPaths[0])) { $schemaConfig->setName($searchPaths[0]); } $params = $this->_conn->getParams(); if (! isset($params['defaultTableOptions'])) { $params['defaultTableOptions'] = []; } if (! isset($params['defaultTableOptions']['charset']) && isset($params['charset'])) { $params['defaultTableOptions']['charset'] = $params['charset']; } $schemaConfig->setDefaultTableOptions($params['defaultTableOptions']); return $schemaConfig; } /** * The search path for namespaces in the currently connected database. * * The first entry is usually the default namespace in the Schema. All * further namespaces contain tables/sequences which can also be addressed * with a short, not full-qualified name. * * For databases that don't support subschema/namespaces this method * returns the name of the currently connected database. * * @return string[] */ public function getSchemaSearchPaths() { return [$this->_conn->getDatabase()]; } /** * Given a table comment this method tries to extract a typehint for Doctrine Type, or returns * the type given as default. * * @param string|null $comment * @param string $currentType * * @return string */ public function extractDoctrineTypeFromComment($comment, $currentType) { if ($comment !== null && preg_match('(\(DC2Type:(((?!\)).)+)\))', $comment, $match)) { return $match[1]; } return $currentType; } /** * @param string|null $comment * @param string|null $type * * @return string|null */ public function removeDoctrineTypeFromComment($comment, $type) { if ($comment === null) { return null; } return str_replace('(DC2Type:' . $type . ')', '', $comment); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Schema/Column.php000066400000000000000000000204331360544566000232670ustar00rootroot00000000000000_setName($columnName); $this->setType($type); $this->setOptions($options); } /** * @param mixed[] $options * * @return Column */ public function setOptions(array $options) { foreach ($options as $name => $value) { $method = 'set' . $name; if (! method_exists($this, $method)) { // next major: throw an exception @trigger_error(sprintf( 'The "%s" column option is not supported,' . ' setting it is deprecated and will cause an error in Doctrine DBAL 3.0', $name ), E_USER_DEPRECATED); continue; } $this->$method($value); } return $this; } /** * @return Column */ public function setType(Type $type) { $this->_type = $type; return $this; } /** * @param int|null $length * * @return Column */ public function setLength($length) { if ($length !== null) { $this->_length = (int) $length; } else { $this->_length = null; } return $this; } /** * @param int $precision * * @return Column */ public function setPrecision($precision) { if (! is_numeric($precision)) { $precision = 10; // defaults to 10 when no valid precision is given. } $this->_precision = (int) $precision; return $this; } /** * @param int $scale * * @return Column */ public function setScale($scale) { if (! is_numeric($scale)) { $scale = 0; } $this->_scale = (int) $scale; return $this; } /** * @param bool $unsigned * * @return Column */ public function setUnsigned($unsigned) { $this->_unsigned = (bool) $unsigned; return $this; } /** * @param bool $fixed * * @return Column */ public function setFixed($fixed) { $this->_fixed = (bool) $fixed; return $this; } /** * @param bool $notnull * * @return Column */ public function setNotnull($notnull) { $this->_notnull = (bool) $notnull; return $this; } /** * @param mixed $default * * @return Column */ public function setDefault($default) { $this->_default = $default; return $this; } /** * @param mixed[] $platformOptions * * @return Column */ public function setPlatformOptions(array $platformOptions) { $this->_platformOptions = $platformOptions; return $this; } /** * @param string $name * @param mixed $value * * @return Column */ public function setPlatformOption($name, $value) { $this->_platformOptions[$name] = $value; return $this; } /** * @param string $value * * @return Column */ public function setColumnDefinition($value) { $this->_columnDefinition = $value; return $this; } /** * @return Type */ public function getType() { return $this->_type; } /** * @return int|null */ public function getLength() { return $this->_length; } /** * @return int */ public function getPrecision() { return $this->_precision; } /** * @return int */ public function getScale() { return $this->_scale; } /** * @return bool */ public function getUnsigned() { return $this->_unsigned; } /** * @return bool */ public function getFixed() { return $this->_fixed; } /** * @return bool */ public function getNotnull() { return $this->_notnull; } /** * @return string|null */ public function getDefault() { return $this->_default; } /** * @return mixed[] */ public function getPlatformOptions() { return $this->_platformOptions; } /** * @param string $name * * @return bool */ public function hasPlatformOption($name) { return isset($this->_platformOptions[$name]); } /** * @param string $name * * @return mixed */ public function getPlatformOption($name) { return $this->_platformOptions[$name]; } /** * @return string|null */ public function getColumnDefinition() { return $this->_columnDefinition; } /** * @return bool */ public function getAutoincrement() { return $this->_autoincrement; } /** * @param bool $flag * * @return Column */ public function setAutoincrement($flag) { $this->_autoincrement = $flag; return $this; } /** * @param string|null $comment * * @return Column */ public function setComment($comment) { $this->_comment = $comment; return $this; } /** * @return string|null */ public function getComment() { return $this->_comment; } /** * @param string $name * @param mixed $value * * @return Column */ public function setCustomSchemaOption($name, $value) { $this->_customSchemaOptions[$name] = $value; return $this; } /** * @param string $name * * @return bool */ public function hasCustomSchemaOption($name) { return isset($this->_customSchemaOptions[$name]); } /** * @param string $name * * @return mixed */ public function getCustomSchemaOption($name) { return $this->_customSchemaOptions[$name]; } /** * @param mixed[] $customSchemaOptions * * @return Column */ public function setCustomSchemaOptions(array $customSchemaOptions) { $this->_customSchemaOptions = $customSchemaOptions; return $this; } /** * @return mixed[] */ public function getCustomSchemaOptions() { return $this->_customSchemaOptions; } /** * @return mixed[] */ public function toArray() { return array_merge([ 'name' => $this->_name, 'type' => $this->_type, 'default' => $this->_default, 'notnull' => $this->_notnull, 'length' => $this->_length, 'precision' => $this->_precision, 'scale' => $this->_scale, 'fixed' => $this->_fixed, 'unsigned' => $this->_unsigned, 'autoincrement' => $this->_autoincrement, 'columnDefinition' => $this->_columnDefinition, 'comment' => $this->_comment, ], $this->_platformOptions, $this->_customSchemaOptions); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Schema/ColumnDiff.php000066400000000000000000000022561360544566000240630ustar00rootroot00000000000000oldColumnName = $oldColumnName; $this->column = $column; $this->changedProperties = $changedProperties; $this->fromColumn = $fromColumn; } /** * @param string $propertyName * * @return bool */ public function hasChanged($propertyName) { return in_array($propertyName, $this->changedProperties); } /** * @return Identifier */ public function getOldColumnName() { $quote = $this->fromColumn && $this->fromColumn->isQuoted(); return new Identifier($this->oldColumnName, $quote); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Schema/Comparator.php000066400000000000000000000461751360544566000241540ustar00rootroot00000000000000compare($fromSchema, $toSchema); } /** * Returns a SchemaDiff object containing the differences between the schemas $fromSchema and $toSchema. * * The returned differences are returned in such a way that they contain the * operations to change the schema stored in $fromSchema to the schema that is * stored in $toSchema. * * @return SchemaDiff */ public function compare(Schema $fromSchema, Schema $toSchema) { $diff = new SchemaDiff(); $diff->fromSchema = $fromSchema; $foreignKeysToTable = []; foreach ($toSchema->getNamespaces() as $namespace) { if ($fromSchema->hasNamespace($namespace)) { continue; } $diff->newNamespaces[$namespace] = $namespace; } foreach ($fromSchema->getNamespaces() as $namespace) { if ($toSchema->hasNamespace($namespace)) { continue; } $diff->removedNamespaces[$namespace] = $namespace; } foreach ($toSchema->getTables() as $table) { $tableName = $table->getShortestName($toSchema->getName()); if (! $fromSchema->hasTable($tableName)) { $diff->newTables[$tableName] = $toSchema->getTable($tableName); } else { $tableDifferences = $this->diffTable($fromSchema->getTable($tableName), $toSchema->getTable($tableName)); if ($tableDifferences !== false) { $diff->changedTables[$tableName] = $tableDifferences; } } } /* Check if there are tables removed */ foreach ($fromSchema->getTables() as $table) { $tableName = $table->getShortestName($fromSchema->getName()); $table = $fromSchema->getTable($tableName); if (! $toSchema->hasTable($tableName)) { $diff->removedTables[$tableName] = $table; } // also remember all foreign keys that point to a specific table foreach ($table->getForeignKeys() as $foreignKey) { $foreignTable = strtolower($foreignKey->getForeignTableName()); if (! isset($foreignKeysToTable[$foreignTable])) { $foreignKeysToTable[$foreignTable] = []; } $foreignKeysToTable[$foreignTable][] = $foreignKey; } } foreach ($diff->removedTables as $tableName => $table) { if (! isset($foreignKeysToTable[$tableName])) { continue; } $diff->orphanedForeignKeys = array_merge($diff->orphanedForeignKeys, $foreignKeysToTable[$tableName]); // deleting duplicated foreign keys present on both on the orphanedForeignKey // and the removedForeignKeys from changedTables foreach ($foreignKeysToTable[$tableName] as $foreignKey) { // strtolower the table name to make if compatible with getShortestName $localTableName = strtolower($foreignKey->getLocalTableName()); if (! isset($diff->changedTables[$localTableName])) { continue; } foreach ($diff->changedTables[$localTableName]->removedForeignKeys as $key => $removedForeignKey) { assert($removedForeignKey instanceof ForeignKeyConstraint); // We check if the key is from the removed table if not we skip. if ($tableName !== strtolower($removedForeignKey->getForeignTableName())) { continue; } unset($diff->changedTables[$localTableName]->removedForeignKeys[$key]); } } } foreach ($toSchema->getSequences() as $sequence) { $sequenceName = $sequence->getShortestName($toSchema->getName()); if (! $fromSchema->hasSequence($sequenceName)) { if (! $this->isAutoIncrementSequenceInSchema($fromSchema, $sequence)) { $diff->newSequences[] = $sequence; } } else { if ($this->diffSequence($sequence, $fromSchema->getSequence($sequenceName))) { $diff->changedSequences[] = $toSchema->getSequence($sequenceName); } } } foreach ($fromSchema->getSequences() as $sequence) { if ($this->isAutoIncrementSequenceInSchema($toSchema, $sequence)) { continue; } $sequenceName = $sequence->getShortestName($fromSchema->getName()); if ($toSchema->hasSequence($sequenceName)) { continue; } $diff->removedSequences[] = $sequence; } return $diff; } /** * @param Schema $schema * @param Sequence $sequence * * @return bool */ private function isAutoIncrementSequenceInSchema($schema, $sequence) { foreach ($schema->getTables() as $table) { if ($sequence->isAutoIncrementsFor($table)) { return true; } } return false; } /** * @return bool */ public function diffSequence(Sequence $sequence1, Sequence $sequence2) { if ($sequence1->getAllocationSize() !== $sequence2->getAllocationSize()) { return true; } return $sequence1->getInitialValue() !== $sequence2->getInitialValue(); } /** * Returns the difference between the tables $table1 and $table2. * * If there are no differences this method returns the boolean false. * * @return TableDiff|false */ public function diffTable(Table $table1, Table $table2) { $changes = 0; $tableDifferences = new TableDiff($table1->getName()); $tableDifferences->fromTable = $table1; $table1Columns = $table1->getColumns(); $table2Columns = $table2->getColumns(); /* See if all the fields in table 1 exist in table 2 */ foreach ($table2Columns as $columnName => $column) { if ($table1->hasColumn($columnName)) { continue; } $tableDifferences->addedColumns[$columnName] = $column; $changes++; } /* See if there are any removed fields in table 2 */ foreach ($table1Columns as $columnName => $column) { // See if column is removed in table 2. if (! $table2->hasColumn($columnName)) { $tableDifferences->removedColumns[$columnName] = $column; $changes++; continue; } // See if column has changed properties in table 2. $changedProperties = $this->diffColumn($column, $table2->getColumn($columnName)); if (empty($changedProperties)) { continue; } $columnDiff = new ColumnDiff($column->getName(), $table2->getColumn($columnName), $changedProperties); $columnDiff->fromColumn = $column; $tableDifferences->changedColumns[$column->getName()] = $columnDiff; $changes++; } $this->detectColumnRenamings($tableDifferences); $table1Indexes = $table1->getIndexes(); $table2Indexes = $table2->getIndexes(); /* See if all the indexes in table 1 exist in table 2 */ foreach ($table2Indexes as $indexName => $index) { if (($index->isPrimary() && $table1->hasPrimaryKey()) || $table1->hasIndex($indexName)) { continue; } $tableDifferences->addedIndexes[$indexName] = $index; $changes++; } /* See if there are any removed indexes in table 2 */ foreach ($table1Indexes as $indexName => $index) { // See if index is removed in table 2. if (($index->isPrimary() && ! $table2->hasPrimaryKey()) || ! $index->isPrimary() && ! $table2->hasIndex($indexName) ) { $tableDifferences->removedIndexes[$indexName] = $index; $changes++; continue; } // See if index has changed in table 2. $table2Index = $index->isPrimary() ? $table2->getPrimaryKey() : $table2->getIndex($indexName); assert($table2Index instanceof Index); if (! $this->diffIndex($index, $table2Index)) { continue; } $tableDifferences->changedIndexes[$indexName] = $table2Index; $changes++; } $this->detectIndexRenamings($tableDifferences); $fromFkeys = $table1->getForeignKeys(); $toFkeys = $table2->getForeignKeys(); foreach ($fromFkeys as $key1 => $constraint1) { foreach ($toFkeys as $key2 => $constraint2) { if ($this->diffForeignKey($constraint1, $constraint2) === false) { unset($fromFkeys[$key1], $toFkeys[$key2]); } else { if (strtolower($constraint1->getName()) === strtolower($constraint2->getName())) { $tableDifferences->changedForeignKeys[] = $constraint2; $changes++; unset($fromFkeys[$key1], $toFkeys[$key2]); } } } } foreach ($fromFkeys as $constraint1) { $tableDifferences->removedForeignKeys[] = $constraint1; $changes++; } foreach ($toFkeys as $constraint2) { $tableDifferences->addedForeignKeys[] = $constraint2; $changes++; } return $changes ? $tableDifferences : false; } /** * Try to find columns that only changed their name, rename operations maybe cheaper than add/drop * however ambiguities between different possibilities should not lead to renaming at all. * * @return void */ private function detectColumnRenamings(TableDiff $tableDifferences) { $renameCandidates = []; foreach ($tableDifferences->addedColumns as $addedColumnName => $addedColumn) { foreach ($tableDifferences->removedColumns as $removedColumn) { if (count($this->diffColumn($addedColumn, $removedColumn)) !== 0) { continue; } $renameCandidates[$addedColumn->getName()][] = [$removedColumn, $addedColumn, $addedColumnName]; } } foreach ($renameCandidates as $candidateColumns) { if (count($candidateColumns) !== 1) { continue; } [$removedColumn, $addedColumn] = $candidateColumns[0]; $removedColumnName = strtolower($removedColumn->getName()); $addedColumnName = strtolower($addedColumn->getName()); if (isset($tableDifferences->renamedColumns[$removedColumnName])) { continue; } $tableDifferences->renamedColumns[$removedColumnName] = $addedColumn; unset( $tableDifferences->addedColumns[$addedColumnName], $tableDifferences->removedColumns[$removedColumnName] ); } } /** * Try to find indexes that only changed their name, rename operations maybe cheaper than add/drop * however ambiguities between different possibilities should not lead to renaming at all. * * @return void */ private function detectIndexRenamings(TableDiff $tableDifferences) { $renameCandidates = []; // Gather possible rename candidates by comparing each added and removed index based on semantics. foreach ($tableDifferences->addedIndexes as $addedIndexName => $addedIndex) { foreach ($tableDifferences->removedIndexes as $removedIndex) { if ($this->diffIndex($addedIndex, $removedIndex)) { continue; } $renameCandidates[$addedIndex->getName()][] = [$removedIndex, $addedIndex, $addedIndexName]; } } foreach ($renameCandidates as $candidateIndexes) { // If the current rename candidate contains exactly one semantically equal index, // we can safely rename it. // Otherwise it is unclear if a rename action is really intended, // therefore we let those ambiguous indexes be added/dropped. if (count($candidateIndexes) !== 1) { continue; } [$removedIndex, $addedIndex] = $candidateIndexes[0]; $removedIndexName = strtolower($removedIndex->getName()); $addedIndexName = strtolower($addedIndex->getName()); if (isset($tableDifferences->renamedIndexes[$removedIndexName])) { continue; } $tableDifferences->renamedIndexes[$removedIndexName] = $addedIndex; unset( $tableDifferences->addedIndexes[$addedIndexName], $tableDifferences->removedIndexes[$removedIndexName] ); } } /** * @return bool */ public function diffForeignKey(ForeignKeyConstraint $key1, ForeignKeyConstraint $key2) { if (array_map('strtolower', $key1->getUnquotedLocalColumns()) !== array_map('strtolower', $key2->getUnquotedLocalColumns())) { return true; } if (array_map('strtolower', $key1->getUnquotedForeignColumns()) !== array_map('strtolower', $key2->getUnquotedForeignColumns())) { return true; } if ($key1->getUnqualifiedForeignTableName() !== $key2->getUnqualifiedForeignTableName()) { return true; } if ($key1->onUpdate() !== $key2->onUpdate()) { return true; } return $key1->onDelete() !== $key2->onDelete(); } /** * Returns the difference between the fields $field1 and $field2. * * If there are differences this method returns $field2, otherwise the * boolean false. * * @return string[] */ public function diffColumn(Column $column1, Column $column2) { $properties1 = $column1->toArray(); $properties2 = $column2->toArray(); $changedProperties = []; if (get_class($properties1['type']) !== get_class($properties2['type'])) { $changedProperties[] = 'type'; } foreach (['notnull', 'unsigned', 'autoincrement'] as $property) { if ($properties1[$property] === $properties2[$property]) { continue; } $changedProperties[] = $property; } // This is a very nasty hack to make comparator work with the legacy json_array type, which should be killed in v3 if ($this->isALegacyJsonComparison($properties1['type'], $properties2['type'])) { array_shift($changedProperties); $changedProperties[] = 'comment'; } // Null values need to be checked additionally as they tell whether to create or drop a default value. // null != 0, null != false, null != '' etc. This affects platform's table alteration SQL generation. if (($properties1['default'] === null) !== ($properties2['default'] === null) || $properties1['default'] != $properties2['default']) { $changedProperties[] = 'default'; } if (($properties1['type'] instanceof Types\StringType && ! $properties1['type'] instanceof Types\GuidType) || $properties1['type'] instanceof Types\BinaryType ) { // check if value of length is set at all, default value assumed otherwise. $length1 = $properties1['length'] ?: 255; $length2 = $properties2['length'] ?: 255; if ($length1 !== $length2) { $changedProperties[] = 'length'; } if ($properties1['fixed'] !== $properties2['fixed']) { $changedProperties[] = 'fixed'; } } elseif ($properties1['type'] instanceof Types\DecimalType) { if (($properties1['precision'] ?: 10) !== ($properties2['precision'] ?: 10)) { $changedProperties[] = 'precision'; } if ($properties1['scale'] !== $properties2['scale']) { $changedProperties[] = 'scale'; } } // A null value and an empty string are actually equal for a comment so they should not trigger a change. if ($properties1['comment'] !== $properties2['comment'] && ! ($properties1['comment'] === null && $properties2['comment'] === '') && ! ($properties2['comment'] === null && $properties1['comment'] === '') ) { $changedProperties[] = 'comment'; } $customOptions1 = $column1->getCustomSchemaOptions(); $customOptions2 = $column2->getCustomSchemaOptions(); foreach (array_merge(array_keys($customOptions1), array_keys($customOptions2)) as $key) { if (! array_key_exists($key, $properties1) || ! array_key_exists($key, $properties2)) { $changedProperties[] = $key; } elseif ($properties1[$key] !== $properties2[$key]) { $changedProperties[] = $key; } } $platformOptions1 = $column1->getPlatformOptions(); $platformOptions2 = $column2->getPlatformOptions(); foreach (array_keys(array_intersect_key($platformOptions1, $platformOptions2)) as $key) { if ($properties1[$key] === $properties2[$key]) { continue; } $changedProperties[] = $key; } return array_unique($changedProperties); } /** * TODO: kill with fire on v3.0 * * @deprecated */ private function isALegacyJsonComparison(Types\Type $one, Types\Type $other) : bool { if (! $one instanceof Types\JsonType || ! $other instanceof Types\JsonType) { return false; } return ( ! $one instanceof Types\JsonArrayType && $other instanceof Types\JsonArrayType) || ( ! $other instanceof Types\JsonArrayType && $one instanceof Types\JsonArrayType); } /** * Finds the difference between the indexes $index1 and $index2. * * Compares $index1 with $index2 and returns $index2 if there are any * differences or false in case there are no differences. * * @return bool */ public function diffIndex(Index $index1, Index $index2) { return ! ($index1->isFullfilledBy($index2) && $index2->isFullfilledBy($index1)); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Schema/Constraint.php000066400000000000000000000017411360544566000241570ustar00rootroot00000000000000_platform->getListTablesSQL(); $sql .= ' AND CREATOR = UPPER(' . $this->_conn->quote($this->_conn->getUsername()) . ')'; $tables = $this->_conn->fetchAll($sql); return $this->filterAssetNames($this->_getPortableTablesList($tables)); } /** * {@inheritdoc} */ protected function _getPortableTableColumnDefinition($tableColumn) { $tableColumn = array_change_key_case($tableColumn, CASE_LOWER); $length = null; $fixed = null; $scale = false; $precision = false; $default = null; if ($tableColumn['default'] !== null && $tableColumn['default'] !== 'NULL') { $default = $tableColumn['default']; if (preg_match('/^\'(.*)\'$/s', $default, $matches)) { $default = str_replace("''", "'", $matches[1]); } } $type = $this->_platform->getDoctrineTypeMapping($tableColumn['typename']); if (isset($tableColumn['comment'])) { $type = $this->extractDoctrineTypeFromComment($tableColumn['comment'], $type); $tableColumn['comment'] = $this->removeDoctrineTypeFromComment($tableColumn['comment'], $type); } switch (strtolower($tableColumn['typename'])) { case 'varchar': $length = $tableColumn['length']; $fixed = false; break; case 'character': $length = $tableColumn['length']; $fixed = true; break; case 'clob': $length = $tableColumn['length']; break; case 'decimal': case 'double': case 'real': $scale = $tableColumn['scale']; $precision = $tableColumn['length']; break; } $options = [ 'length' => $length, 'unsigned' => false, 'fixed' => (bool) $fixed, 'default' => $default, 'autoincrement' => (bool) $tableColumn['autoincrement'], 'notnull' => (bool) ($tableColumn['nulls'] === 'N'), 'scale' => null, 'precision' => null, 'comment' => isset($tableColumn['comment']) && $tableColumn['comment'] !== '' ? $tableColumn['comment'] : null, 'platformOptions' => [], ]; if ($scale !== null && $precision !== null) { $options['scale'] = $scale; $options['precision'] = $precision; } return new Column($tableColumn['colname'], Type::getType($type), $options); } /** * {@inheritdoc} */ protected function _getPortableTablesList($tables) { $tableNames = []; foreach ($tables as $tableRow) { $tableRow = array_change_key_case($tableRow, CASE_LOWER); $tableNames[] = $tableRow['name']; } return $tableNames; } /** * {@inheritdoc} */ protected function _getPortableTableIndexesList($tableIndexRows, $tableName = null) { foreach ($tableIndexRows as &$tableIndexRow) { $tableIndexRow = array_change_key_case($tableIndexRow, CASE_LOWER); $tableIndexRow['primary'] = (bool) $tableIndexRow['primary']; } return parent::_getPortableTableIndexesList($tableIndexRows, $tableName); } /** * {@inheritdoc} */ protected function _getPortableTableForeignKeyDefinition($tableForeignKey) { return new ForeignKeyConstraint( $tableForeignKey['local_columns'], $tableForeignKey['foreign_table'], $tableForeignKey['foreign_columns'], $tableForeignKey['name'], $tableForeignKey['options'] ); } /** * {@inheritdoc} */ protected function _getPortableTableForeignKeysList($tableForeignKeys) { $foreignKeys = []; foreach ($tableForeignKeys as $tableForeignKey) { $tableForeignKey = array_change_key_case($tableForeignKey, CASE_LOWER); if (! isset($foreignKeys[$tableForeignKey['index_name']])) { $foreignKeys[$tableForeignKey['index_name']] = [ 'local_columns' => [$tableForeignKey['local_column']], 'foreign_table' => $tableForeignKey['foreign_table'], 'foreign_columns' => [$tableForeignKey['foreign_column']], 'name' => $tableForeignKey['index_name'], 'options' => [ 'onUpdate' => $tableForeignKey['on_update'], 'onDelete' => $tableForeignKey['on_delete'], ], ]; } else { $foreignKeys[$tableForeignKey['index_name']]['local_columns'][] = $tableForeignKey['local_column']; $foreignKeys[$tableForeignKey['index_name']]['foreign_columns'][] = $tableForeignKey['foreign_column']; } } return parent::_getPortableTableForeignKeysList($foreignKeys); } /** * {@inheritdoc} */ protected function _getPortableForeignKeyRuleDef($def) { if ($def === 'C') { return 'CASCADE'; } if ($def === 'N') { return 'SET NULL'; } return null; } /** * {@inheritdoc} */ protected function _getPortableViewDefinition($view) { $view = array_change_key_case($view, CASE_LOWER); // sadly this still segfaults on PDO_IBM, see http://pecl.php.net/bugs/bug.php?id=17199 //$view['text'] = (is_resource($view['text']) ? stream_get_contents($view['text']) : $view['text']); if (! is_resource($view['text'])) { $pos = strpos($view['text'], ' AS '); $sql = substr($view['text'], $pos+4); } else { $sql = ''; } return new View($view['name'], $sql); } public function listTableDetails($tableName) : Table { $table = parent::listTableDetails($tableName); /** @var DB2Platform $platform */ $platform = $this->_platform; $sql = $platform->getListTableCommentsSQL($tableName); $tableOptions = $this->_conn->fetchAssoc($sql); $table->addOption('comment', $tableOptions['REMARKS']); return $table; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Schema/DrizzleSchemaManager.php000066400000000000000000000060611360544566000260720ustar00rootroot00000000000000_platform->getDoctrineTypeMapping($dbType); $type = $this->extractDoctrineTypeFromComment($tableColumn['COLUMN_COMMENT'], $type); $tableColumn['COLUMN_COMMENT'] = $this->removeDoctrineTypeFromComment($tableColumn['COLUMN_COMMENT'], $type); $options = [ 'notnull' => ! (bool) $tableColumn['IS_NULLABLE'], 'length' => (int) $tableColumn['CHARACTER_MAXIMUM_LENGTH'], 'default' => $tableColumn['COLUMN_DEFAULT'] ?? null, 'autoincrement' => (bool) $tableColumn['IS_AUTO_INCREMENT'], 'scale' => (int) $tableColumn['NUMERIC_SCALE'], 'precision' => (int) $tableColumn['NUMERIC_PRECISION'], 'comment' => isset($tableColumn['COLUMN_COMMENT']) && $tableColumn['COLUMN_COMMENT'] !== '' ? $tableColumn['COLUMN_COMMENT'] : null, ]; $column = new Column($tableColumn['COLUMN_NAME'], Type::getType($type), $options); if (! empty($tableColumn['COLLATION_NAME'])) { $column->setPlatformOption('collation', $tableColumn['COLLATION_NAME']); } return $column; } /** * {@inheritdoc} */ protected function _getPortableDatabaseDefinition($database) { return $database['SCHEMA_NAME']; } /** * {@inheritdoc} */ protected function _getPortableTableDefinition($table) { return $table['TABLE_NAME']; } /** * {@inheritdoc} */ public function _getPortableTableForeignKeyDefinition($tableForeignKey) { $columns = []; foreach (explode(',', $tableForeignKey['CONSTRAINT_COLUMNS']) as $value) { $columns[] = trim($value, ' `'); } $refColumns = []; foreach (explode(',', $tableForeignKey['REFERENCED_TABLE_COLUMNS']) as $value) { $refColumns[] = trim($value, ' `'); } return new ForeignKeyConstraint( $columns, $tableForeignKey['REFERENCED_TABLE_NAME'], $refColumns, $tableForeignKey['CONSTRAINT_NAME'], [ 'onUpdate' => $tableForeignKey['UPDATE_RULE'], 'onDelete' => $tableForeignKey['DELETE_RULE'], ] ); } /** * {@inheritdoc} */ protected function _getPortableTableIndexesList($tableIndexes, $tableName = null) { $indexes = []; foreach ($tableIndexes as $k) { $k['primary'] = (bool) $k['primary']; $indexes[] = $k; } return parent::_getPortableTableIndexesList($indexes, $tableName); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Schema/ForeignKeyConstraint.php000066400000000000000000000250411360544566000261410ustar00rootroot00000000000000 Identifier) * * @var Identifier[] */ protected $_localColumnNames; /** * Table or asset identifier instance of the referenced table name the foreign key constraint is associated with. * * @var Table|Identifier */ protected $_foreignTableName; /** * Asset identifier instances of the referenced table column names the foreign key constraint is associated with. * array($columnName => Identifier) * * @var Identifier[] */ protected $_foreignColumnNames; /** * Options associated with the foreign key constraint. * * @var mixed[] */ protected $_options; /** * Initializes the foreign key constraint. * * @param string[] $localColumnNames Names of the referencing table columns. * @param Table|string $foreignTableName Referenced table. * @param string[] $foreignColumnNames Names of the referenced table columns. * @param string|null $name Name of the foreign key constraint. * @param mixed[] $options Options associated with the foreign key constraint. */ public function __construct(array $localColumnNames, $foreignTableName, array $foreignColumnNames, $name = null, array $options = []) { if ($name !== null) { $this->_setName($name); } $this->_localColumnNames = $this->createIdentifierMap($localColumnNames); if ($foreignTableName instanceof Table) { $this->_foreignTableName = $foreignTableName; } else { $this->_foreignTableName = new Identifier($foreignTableName); } $this->_foreignColumnNames = $this->createIdentifierMap($foreignColumnNames); $this->_options = $options; } /** * @param string[] $names * * @return Identifier[] */ private function createIdentifierMap(array $names) : array { $identifiers = []; foreach ($names as $name) { $identifiers[$name] = new Identifier($name); } return $identifiers; } /** * Returns the name of the referencing table * the foreign key constraint is associated with. * * @return string */ public function getLocalTableName() { return $this->_localTable->getName(); } /** * Sets the Table instance of the referencing table * the foreign key constraint is associated with. * * @param Table $table Instance of the referencing table. * * @return void */ public function setLocalTable(Table $table) { $this->_localTable = $table; } /** * @return Table */ public function getLocalTable() { return $this->_localTable; } /** * Returns the names of the referencing table columns * the foreign key constraint is associated with. * * @return string[] */ public function getLocalColumns() { return array_keys($this->_localColumnNames); } /** * Returns the quoted representation of the referencing table column names * the foreign key constraint is associated with. * * But only if they were defined with one or the referencing table column name * is a keyword reserved by the platform. * Otherwise the plain unquoted value as inserted is returned. * * @param AbstractPlatform $platform The platform to use for quotation. * * @return string[] */ public function getQuotedLocalColumns(AbstractPlatform $platform) { $columns = []; foreach ($this->_localColumnNames as $column) { $columns[] = $column->getQuotedName($platform); } return $columns; } /** * Returns unquoted representation of local table column names for comparison with other FK * * @return string[] */ public function getUnquotedLocalColumns() { return array_map([$this, 'trimQuotes'], $this->getLocalColumns()); } /** * Returns unquoted representation of foreign table column names for comparison with other FK * * @return string[] */ public function getUnquotedForeignColumns() { return array_map([$this, 'trimQuotes'], $this->getForeignColumns()); } /** * {@inheritdoc} * * @see getLocalColumns */ public function getColumns() { return $this->getLocalColumns(); } /** * Returns the quoted representation of the referencing table column names * the foreign key constraint is associated with. * * But only if they were defined with one or the referencing table column name * is a keyword reserved by the platform. * Otherwise the plain unquoted value as inserted is returned. * * @see getQuotedLocalColumns * * @param AbstractPlatform $platform The platform to use for quotation. * * @return string[] */ public function getQuotedColumns(AbstractPlatform $platform) { return $this->getQuotedLocalColumns($platform); } /** * Returns the name of the referenced table * the foreign key constraint is associated with. * * @return string */ public function getForeignTableName() { return $this->_foreignTableName->getName(); } /** * Returns the non-schema qualified foreign table name. * * @return string */ public function getUnqualifiedForeignTableName() { $name = $this->_foreignTableName->getName(); $position = strrpos($name, '.'); if ($position !== false) { $name = substr($name, $position); } return strtolower($name); } /** * Returns the quoted representation of the referenced table name * the foreign key constraint is associated with. * * But only if it was defined with one or the referenced table name * is a keyword reserved by the platform. * Otherwise the plain unquoted value as inserted is returned. * * @param AbstractPlatform $platform The platform to use for quotation. * * @return string */ public function getQuotedForeignTableName(AbstractPlatform $platform) { return $this->_foreignTableName->getQuotedName($platform); } /** * Returns the names of the referenced table columns * the foreign key constraint is associated with. * * @return string[] */ public function getForeignColumns() { return array_keys($this->_foreignColumnNames); } /** * Returns the quoted representation of the referenced table column names * the foreign key constraint is associated with. * * But only if they were defined with one or the referenced table column name * is a keyword reserved by the platform. * Otherwise the plain unquoted value as inserted is returned. * * @param AbstractPlatform $platform The platform to use for quotation. * * @return string[] */ public function getQuotedForeignColumns(AbstractPlatform $platform) { $columns = []; foreach ($this->_foreignColumnNames as $column) { $columns[] = $column->getQuotedName($platform); } return $columns; } /** * Returns whether or not a given option * is associated with the foreign key constraint. * * @param string $name Name of the option to check. * * @return bool */ public function hasOption($name) { return isset($this->_options[$name]); } /** * Returns an option associated with the foreign key constraint. * * @param string $name Name of the option the foreign key constraint is associated with. * * @return mixed */ public function getOption($name) { return $this->_options[$name]; } /** * Returns the options associated with the foreign key constraint. * * @return mixed[] */ public function getOptions() { return $this->_options; } /** * Returns the referential action for UPDATE operations * on the referenced table the foreign key constraint is associated with. * * @return string|null */ public function onUpdate() { return $this->onEvent('onUpdate'); } /** * Returns the referential action for DELETE operations * on the referenced table the foreign key constraint is associated with. * * @return string|null */ public function onDelete() { return $this->onEvent('onDelete'); } /** * Returns the referential action for a given database operation * on the referenced table the foreign key constraint is associated with. * * @param string $event Name of the database operation/event to return the referential action for. * * @return string|null */ private function onEvent($event) { if (isset($this->_options[$event])) { $onEvent = strtoupper($this->_options[$event]); if (! in_array($onEvent, ['NO ACTION', 'RESTRICT'])) { return $onEvent; } } return false; } /** * Checks whether this foreign key constraint intersects the given index columns. * * Returns `true` if at least one of this foreign key's local columns * matches one of the given index's columns, `false` otherwise. * * @param Index $index The index to be checked against. * * @return bool */ public function intersectsIndexColumns(Index $index) { foreach ($index->getColumns() as $indexColumn) { foreach ($this->_localColumnNames as $localColumn) { if (strtolower($indexColumn) === strtolower($localColumn->getName())) { return true; } } } return false; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Schema/Identifier.php000066400000000000000000000012321360544566000241100ustar00rootroot00000000000000_setName($identifier); if (! $quote || $this->_quoted) { return; } $this->_setName('"' . $this->getName() . '"'); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Schema/Index.php000066400000000000000000000211701360544566000231000ustar00rootroot00000000000000 Identifier) * * @var Identifier[] */ protected $_columns = []; /** @var bool */ protected $_isUnique = false; /** @var bool */ protected $_isPrimary = false; /** * Platform specific flags for indexes. * array($flagName => true) * * @var true[] */ protected $_flags = []; /** * Platform specific options * * @todo $_flags should eventually be refactored into options * @var mixed[] */ private $options = []; /** * @param string $indexName * @param string[] $columns * @param bool $isUnique * @param bool $isPrimary * @param string[] $flags * @param mixed[] $options */ public function __construct($indexName, array $columns, $isUnique = false, $isPrimary = false, array $flags = [], array $options = []) { $isUnique = $isUnique || $isPrimary; $this->_setName($indexName); $this->_isUnique = $isUnique; $this->_isPrimary = $isPrimary; $this->options = $options; foreach ($columns as $column) { $this->_addColumn($column); } foreach ($flags as $flag) { $this->addFlag($flag); } } /** * @param string $column * * @return void * * @throws InvalidArgumentException */ protected function _addColumn($column) { if (! is_string($column)) { throw new InvalidArgumentException('Expecting a string as Index Column'); } $this->_columns[$column] = new Identifier($column); } /** * {@inheritdoc} */ public function getColumns() { return array_keys($this->_columns); } /** * {@inheritdoc} */ public function getQuotedColumns(AbstractPlatform $platform) { $subParts = $platform->supportsColumnLengthIndexes() && $this->hasOption('lengths') ? $this->getOption('lengths') : []; $columns = []; foreach ($this->_columns as $column) { $length = array_shift($subParts); $quotedColumn = $column->getQuotedName($platform); if ($length !== null) { $quotedColumn .= '(' . $length . ')'; } $columns[] = $quotedColumn; } return $columns; } /** * @return string[] */ public function getUnquotedColumns() { return array_map([$this, 'trimQuotes'], $this->getColumns()); } /** * Is the index neither unique nor primary key? * * @return bool */ public function isSimpleIndex() { return ! $this->_isPrimary && ! $this->_isUnique; } /** * @return bool */ public function isUnique() { return $this->_isUnique; } /** * @return bool */ public function isPrimary() { return $this->_isPrimary; } /** * @param string $columnName * @param int $pos * * @return bool */ public function hasColumnAtPosition($columnName, $pos = 0) { $columnName = $this->trimQuotes(strtolower($columnName)); $indexColumns = array_map('strtolower', $this->getUnquotedColumns()); return array_search($columnName, $indexColumns) === $pos; } /** * Checks if this index exactly spans the given column names in the correct order. * * @param string[] $columnNames * * @return bool */ public function spansColumns(array $columnNames) { $columns = $this->getColumns(); $numberOfColumns = count($columns); $sameColumns = true; for ($i = 0; $i < $numberOfColumns; $i++) { if (isset($columnNames[$i]) && $this->trimQuotes(strtolower($columns[$i])) === $this->trimQuotes(strtolower($columnNames[$i]))) { continue; } $sameColumns = false; } return $sameColumns; } /** * Checks if the other index already fulfills all the indexing and constraint needs of the current one. * * @return bool */ public function isFullfilledBy(Index $other) { // allow the other index to be equally large only. It being larger is an option // but it creates a problem with scenarios of the kind PRIMARY KEY(foo,bar) UNIQUE(foo) if (count($other->getColumns()) !== count($this->getColumns())) { return false; } // Check if columns are the same, and even in the same order $sameColumns = $this->spansColumns($other->getColumns()); if ($sameColumns) { if (! $this->samePartialIndex($other)) { return false; } if (! $this->hasSameColumnLengths($other)) { return false; } if (! $this->isUnique() && ! $this->isPrimary()) { // this is a special case: If the current key is neither primary or unique, any unique or // primary key will always have the same effect for the index and there cannot be any constraint // overlaps. This means a primary or unique index can always fulfill the requirements of just an // index that has no constraints. return true; } if ($other->isPrimary() !== $this->isPrimary()) { return false; } return $other->isUnique() === $this->isUnique(); } return false; } /** * Detects if the other index is a non-unique, non primary index that can be overwritten by this one. * * @return bool */ public function overrules(Index $other) { if ($other->isPrimary()) { return false; } if ($this->isSimpleIndex() && $other->isUnique()) { return false; } return $this->spansColumns($other->getColumns()) && ($this->isPrimary() || $this->isUnique()) && $this->samePartialIndex($other); } /** * Returns platform specific flags for indexes. * * @return string[] */ public function getFlags() { return array_keys($this->_flags); } /** * Adds Flag for an index that translates to platform specific handling. * * @param string $flag * * @return Index * * @example $index->addFlag('CLUSTERED') */ public function addFlag($flag) { $this->_flags[strtolower($flag)] = true; return $this; } /** * Does this index have a specific flag? * * @param string $flag * * @return bool */ public function hasFlag($flag) { return isset($this->_flags[strtolower($flag)]); } /** * Removes a flag. * * @param string $flag * * @return void */ public function removeFlag($flag) { unset($this->_flags[strtolower($flag)]); } /** * @param string $name * * @return bool */ public function hasOption($name) { return isset($this->options[strtolower($name)]); } /** * @param string $name * * @return mixed */ public function getOption($name) { return $this->options[strtolower($name)]; } /** * @return mixed[] */ public function getOptions() { return $this->options; } /** * Return whether the two indexes have the same partial index * * @return bool */ private function samePartialIndex(Index $other) { if ($this->hasOption('where') && $other->hasOption('where') && $this->getOption('where') === $other->getOption('where')) { return true; } return ! $this->hasOption('where') && ! $other->hasOption('where'); } /** * Returns whether the index has the same column lengths as the other */ private function hasSameColumnLengths(self $other) : bool { $filter = static function (?int $length) : bool { return $length !== null; }; return array_filter($this->options['lengths'] ?? [], $filter) === array_filter($other->options['lengths'] ?? [], $filter); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Schema/MySqlSchemaManager.php000066400000000000000000000260711360544566000255170ustar00rootroot00000000000000 "\0", "\\'" => "'", '\\"' => '"', '\\b' => "\b", '\\n' => "\n", '\\r' => "\r", '\\t' => "\t", '\\Z' => "\x1a", '\\\\' => '\\', '\\%' => '%', '\\_' => '_', // Internally, MariaDB escapes single quotes using the standard syntax "''" => "'", ]; /** * {@inheritdoc} */ protected function _getPortableViewDefinition($view) { return new View($view['TABLE_NAME'], $view['VIEW_DEFINITION']); } /** * {@inheritdoc} */ protected function _getPortableTableDefinition($table) { return array_shift($table); } /** * {@inheritdoc} */ protected function _getPortableUserDefinition($user) { return [ 'user' => $user['User'], 'password' => $user['Password'], ]; } /** * {@inheritdoc} */ protected function _getPortableTableIndexesList($tableIndexes, $tableName = null) { foreach ($tableIndexes as $k => $v) { $v = array_change_key_case($v, CASE_LOWER); if ($v['key_name'] === 'PRIMARY') { $v['primary'] = true; } else { $v['primary'] = false; } if (strpos($v['index_type'], 'FULLTEXT') !== false) { $v['flags'] = ['FULLTEXT']; } elseif (strpos($v['index_type'], 'SPATIAL') !== false) { $v['flags'] = ['SPATIAL']; } $v['length'] = isset($v['sub_part']) ? (int) $v['sub_part'] : null; $tableIndexes[$k] = $v; } return parent::_getPortableTableIndexesList($tableIndexes, $tableName); } /** * {@inheritdoc} */ protected function _getPortableDatabaseDefinition($database) { return $database['Database']; } /** * {@inheritdoc} */ protected function _getPortableTableColumnDefinition($tableColumn) { $tableColumn = array_change_key_case($tableColumn, CASE_LOWER); $dbType = strtolower($tableColumn['type']); $dbType = strtok($dbType, '(), '); assert(is_string($dbType)); $length = $tableColumn['length'] ?? strtok('(), '); $fixed = null; if (! isset($tableColumn['name'])) { $tableColumn['name'] = ''; } $scale = null; $precision = null; $type = $this->_platform->getDoctrineTypeMapping($dbType); // In cases where not connected to a database DESCRIBE $table does not return 'Comment' if (isset($tableColumn['comment'])) { $type = $this->extractDoctrineTypeFromComment($tableColumn['comment'], $type); $tableColumn['comment'] = $this->removeDoctrineTypeFromComment($tableColumn['comment'], $type); } switch ($dbType) { case 'char': case 'binary': $fixed = true; break; case 'float': case 'double': case 'real': case 'numeric': case 'decimal': if (preg_match('([A-Za-z]+\(([0-9]+)\,([0-9]+)\))', $tableColumn['type'], $match)) { $precision = $match[1]; $scale = $match[2]; $length = null; } break; case 'tinytext': $length = MySqlPlatform::LENGTH_LIMIT_TINYTEXT; break; case 'text': $length = MySqlPlatform::LENGTH_LIMIT_TEXT; break; case 'mediumtext': $length = MySqlPlatform::LENGTH_LIMIT_MEDIUMTEXT; break; case 'tinyblob': $length = MySqlPlatform::LENGTH_LIMIT_TINYBLOB; break; case 'blob': $length = MySqlPlatform::LENGTH_LIMIT_BLOB; break; case 'mediumblob': $length = MySqlPlatform::LENGTH_LIMIT_MEDIUMBLOB; break; case 'tinyint': case 'smallint': case 'mediumint': case 'int': case 'integer': case 'bigint': case 'year': $length = null; break; } if ($this->_platform instanceof MariaDb1027Platform) { $columnDefault = $this->getMariaDb1027ColumnDefault($this->_platform, $tableColumn['default']); } else { $columnDefault = $tableColumn['default']; } $options = [ 'length' => $length !== null ? (int) $length : null, 'unsigned' => strpos($tableColumn['type'], 'unsigned') !== false, 'fixed' => (bool) $fixed, 'default' => $columnDefault, 'notnull' => $tableColumn['null'] !== 'YES', 'scale' => null, 'precision' => null, 'autoincrement' => strpos($tableColumn['extra'], 'auto_increment') !== false, 'comment' => isset($tableColumn['comment']) && $tableColumn['comment'] !== '' ? $tableColumn['comment'] : null, ]; if ($scale !== null && $precision !== null) { $options['scale'] = (int) $scale; $options['precision'] = (int) $precision; } $column = new Column($tableColumn['field'], Type::getType($type), $options); if (isset($tableColumn['characterset'])) { $column->setPlatformOption('charset', $tableColumn['characterset']); } if (isset($tableColumn['collation'])) { $column->setPlatformOption('collation', $tableColumn['collation']); } return $column; } /** * Return Doctrine/Mysql-compatible column default values for MariaDB 10.2.7+ servers. * * - Since MariaDb 10.2.7 column defaults stored in information_schema are now quoted * to distinguish them from expressions (see MDEV-10134). * - CURRENT_TIMESTAMP, CURRENT_TIME, CURRENT_DATE are stored in information_schema * as current_timestamp(), currdate(), currtime() * - Quoted 'NULL' is not enforced by Maria, it is technically possible to have * null in some circumstances (see https://jira.mariadb.org/browse/MDEV-14053) * - \' is always stored as '' in information_schema (normalized) * * @link https://mariadb.com/kb/en/library/information-schema-columns-table/ * @link https://jira.mariadb.org/browse/MDEV-13132 * * @param string|null $columnDefault default value as stored in information_schema for MariaDB >= 10.2.7 */ private function getMariaDb1027ColumnDefault(MariaDb1027Platform $platform, ?string $columnDefault) : ?string { if ($columnDefault === 'NULL' || $columnDefault === null) { return null; } if (preg_match('/^\'(.*)\'$/', $columnDefault, $matches)) { return strtr($matches[1], self::MARIADB_ESCAPE_SEQUENCES); } switch ($columnDefault) { case 'current_timestamp()': return $platform->getCurrentTimestampSQL(); case 'curdate()': return $platform->getCurrentDateSQL(); case 'curtime()': return $platform->getCurrentTimeSQL(); } return $columnDefault; } /** * {@inheritdoc} */ protected function _getPortableTableForeignKeysList($tableForeignKeys) { $list = []; foreach ($tableForeignKeys as $value) { $value = array_change_key_case($value, CASE_LOWER); if (! isset($list[$value['constraint_name']])) { if (! isset($value['delete_rule']) || $value['delete_rule'] === 'RESTRICT') { $value['delete_rule'] = null; } if (! isset($value['update_rule']) || $value['update_rule'] === 'RESTRICT') { $value['update_rule'] = null; } $list[$value['constraint_name']] = [ 'name' => $value['constraint_name'], 'local' => [], 'foreign' => [], 'foreignTable' => $value['referenced_table_name'], 'onDelete' => $value['delete_rule'], 'onUpdate' => $value['update_rule'], ]; } $list[$value['constraint_name']]['local'][] = $value['column_name']; $list[$value['constraint_name']]['foreign'][] = $value['referenced_column_name']; } $result = []; foreach ($list as $constraint) { $result[] = new ForeignKeyConstraint( array_values($constraint['local']), $constraint['foreignTable'], array_values($constraint['foreign']), $constraint['name'], [ 'onDelete' => $constraint['onDelete'], 'onUpdate' => $constraint['onUpdate'], ] ); } return $result; } public function listTableDetails($tableName) { $table = parent::listTableDetails($tableName); /** @var MySqlPlatform $platform */ $platform = $this->_platform; $sql = $platform->getListTableMetadataSQL($tableName); $tableOptions = $this->_conn->fetchAssoc($sql); if ($tableOptions === false) { return $table; } $table->addOption('engine', $tableOptions['ENGINE']); if ($tableOptions['TABLE_COLLATION'] !== null) { $table->addOption('collation', $tableOptions['TABLE_COLLATION']); } if ($tableOptions['AUTO_INCREMENT'] !== null) { $table->addOption('autoincrement', $tableOptions['AUTO_INCREMENT']); } $table->addOption('comment', $tableOptions['TABLE_COMMENT']); $table->addOption('create_options', $this->parseCreateOptions($tableOptions['CREATE_OPTIONS'])); return $table; } /** * @return string[]|true[] */ private function parseCreateOptions(?string $string) : array { $options = []; if ($string === null || $string === '') { return $options; } foreach (explode(' ', $string) as $pair) { $parts = explode('=', $pair, 2); $options[$parts[0]] = $parts[1] ?? true; } return $options; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Schema/OracleSchemaManager.php000066400000000000000000000301101360544566000256440ustar00rootroot00000000000000getPrevious(); assert($exception instanceof Throwable); if (! $exception instanceof DriverException) { throw $exception; } // If we have a error code 1940 (ORA-01940), the drop database operation failed // because of active connections on the database. // To force dropping the database, we first have to close all active connections // on that database and issue the drop database operation again. if ($exception->getErrorCode() !== 1940) { throw $exception; } $this->killUserSessions($database); parent::dropDatabase($database); } } /** * {@inheritdoc} */ protected function _getPortableViewDefinition($view) { $view = array_change_key_case($view, CASE_LOWER); return new View($this->getQuotedIdentifierName($view['view_name']), $view['text']); } /** * {@inheritdoc} */ protected function _getPortableUserDefinition($user) { $user = array_change_key_case($user, CASE_LOWER); return [ 'user' => $user['username'], ]; } /** * {@inheritdoc} */ protected function _getPortableTableDefinition($table) { $table = array_change_key_case($table, CASE_LOWER); return $this->getQuotedIdentifierName($table['table_name']); } /** * {@inheritdoc} * * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html */ protected function _getPortableTableIndexesList($tableIndexes, $tableName = null) { $indexBuffer = []; foreach ($tableIndexes as $tableIndex) { $tableIndex = array_change_key_case($tableIndex, CASE_LOWER); $keyName = strtolower($tableIndex['name']); $buffer = []; if (strtolower($tableIndex['is_primary']) === 'p') { $keyName = 'primary'; $buffer['primary'] = true; $buffer['non_unique'] = false; } else { $buffer['primary'] = false; $buffer['non_unique'] = ! $tableIndex['is_unique']; } $buffer['key_name'] = $keyName; $buffer['column_name'] = $this->getQuotedIdentifierName($tableIndex['column_name']); $indexBuffer[] = $buffer; } return parent::_getPortableTableIndexesList($indexBuffer, $tableName); } /** * {@inheritdoc} */ protected function _getPortableTableColumnDefinition($tableColumn) { $tableColumn = array_change_key_case($tableColumn, CASE_LOWER); $dbType = strtolower($tableColumn['data_type']); if (strpos($dbType, 'timestamp(') === 0) { if (strpos($dbType, 'with time zone')) { $dbType = 'timestamptz'; } else { $dbType = 'timestamp'; } } $unsigned = $fixed = $precision = $scale = $length = null; if (! isset($tableColumn['column_name'])) { $tableColumn['column_name'] = ''; } // Default values returned from database sometimes have trailing spaces. $tableColumn['data_default'] = trim($tableColumn['data_default']); if ($tableColumn['data_default'] === '' || $tableColumn['data_default'] === 'NULL') { $tableColumn['data_default'] = null; } if ($tableColumn['data_default'] !== null) { // Default values returned from database are represented as literal expressions if (preg_match('/^\'(.*)\'$/s', $tableColumn['data_default'], $matches)) { $tableColumn['data_default'] = str_replace("''", "'", $matches[1]); } } if ($tableColumn['data_precision'] !== null) { $precision = (int) $tableColumn['data_precision']; } if ($tableColumn['data_scale'] !== null) { $scale = (int) $tableColumn['data_scale']; } $type = $this->_platform->getDoctrineTypeMapping($dbType); $type = $this->extractDoctrineTypeFromComment($tableColumn['comments'], $type); $tableColumn['comments'] = $this->removeDoctrineTypeFromComment($tableColumn['comments'], $type); switch ($dbType) { case 'number': if ($precision === 20 && $scale === 0) { $type = 'bigint'; } elseif ($precision === 5 && $scale === 0) { $type = 'smallint'; } elseif ($precision === 1 && $scale === 0) { $type = 'boolean'; } elseif ($scale > 0) { $type = 'decimal'; } break; case 'varchar': case 'varchar2': case 'nvarchar2': $length = $tableColumn['char_length']; $fixed = false; break; case 'char': case 'nchar': $length = $tableColumn['char_length']; $fixed = true; break; } $options = [ 'notnull' => (bool) ($tableColumn['nullable'] === 'N'), 'fixed' => (bool) $fixed, 'unsigned' => (bool) $unsigned, 'default' => $tableColumn['data_default'], 'length' => $length, 'precision' => $precision, 'scale' => $scale, 'comment' => isset($tableColumn['comments']) && $tableColumn['comments'] !== '' ? $tableColumn['comments'] : null, ]; return new Column($this->getQuotedIdentifierName($tableColumn['column_name']), Type::getType($type), $options); } /** * {@inheritdoc} */ protected function _getPortableTableForeignKeysList($tableForeignKeys) { $list = []; foreach ($tableForeignKeys as $value) { $value = array_change_key_case($value, CASE_LOWER); if (! isset($list[$value['constraint_name']])) { if ($value['delete_rule'] === 'NO ACTION') { $value['delete_rule'] = null; } $list[$value['constraint_name']] = [ 'name' => $this->getQuotedIdentifierName($value['constraint_name']), 'local' => [], 'foreign' => [], 'foreignTable' => $value['references_table'], 'onDelete' => $value['delete_rule'], ]; } $localColumn = $this->getQuotedIdentifierName($value['local_column']); $foreignColumn = $this->getQuotedIdentifierName($value['foreign_column']); $list[$value['constraint_name']]['local'][$value['position']] = $localColumn; $list[$value['constraint_name']]['foreign'][$value['position']] = $foreignColumn; } $result = []; foreach ($list as $constraint) { $result[] = new ForeignKeyConstraint( array_values($constraint['local']), $this->getQuotedIdentifierName($constraint['foreignTable']), array_values($constraint['foreign']), $this->getQuotedIdentifierName($constraint['name']), ['onDelete' => $constraint['onDelete']] ); } return $result; } /** * {@inheritdoc} */ protected function _getPortableSequenceDefinition($sequence) { $sequence = array_change_key_case($sequence, CASE_LOWER); return new Sequence( $this->getQuotedIdentifierName($sequence['sequence_name']), (int) $sequence['increment_by'], (int) $sequence['min_value'] ); } /** * {@inheritdoc} * * @deprecated */ protected function _getPortableFunctionDefinition($function) { $function = array_change_key_case($function, CASE_LOWER); return $function['name']; } /** * {@inheritdoc} */ protected function _getPortableDatabaseDefinition($database) { $database = array_change_key_case($database, CASE_LOWER); return $database['username']; } /** * {@inheritdoc} * * Calling this method without an argument or by passing NULL is deprecated. */ public function createDatabase($database = null) { if ($database === null) { $database = $this->_conn->getDatabase(); } $params = $this->_conn->getParams(); $username = $database; $password = $params['password']; $query = 'CREATE USER ' . $username . ' IDENTIFIED BY ' . $password; $this->_conn->executeUpdate($query); $query = 'GRANT DBA TO ' . $username; $this->_conn->executeUpdate($query); } /** * @param string $table * * @return bool */ public function dropAutoincrement($table) { assert($this->_platform instanceof OraclePlatform); $sql = $this->_platform->getDropAutoincrementSql($table); foreach ($sql as $query) { $this->_conn->executeUpdate($query); } return true; } /** * {@inheritdoc} */ public function dropTable($name) { $this->tryMethod('dropAutoincrement', $name); parent::dropTable($name); } /** * Returns the quoted representation of the given identifier name. * * Quotes non-uppercase identifiers explicitly to preserve case * and thus make references to the particular identifier work. * * @param string $identifier The identifier to quote. * * @return string The quoted identifier. */ private function getQuotedIdentifierName($identifier) { if (preg_match('/[a-z]/', $identifier)) { return $this->_platform->quoteIdentifier($identifier); } return $identifier; } /** * Kills sessions connected with the given user. * * This is useful to force DROP USER operations which could fail because of active user sessions. * * @param string $user The name of the user to kill sessions for. * * @return void */ private function killUserSessions($user) { $sql = <<_conn->fetchAll($sql, [strtoupper($user)]); foreach ($activeUserSessions as $activeUserSession) { $activeUserSession = array_change_key_case($activeUserSession, CASE_LOWER); $this->_execSql( sprintf( "ALTER SYSTEM KILL SESSION '%s, %s' IMMEDIATE", $activeUserSession['sid'], $activeUserSession['serial#'] ) ); } } public function listTableDetails($tableName) : Table { $table = parent::listTableDetails($tableName); /** @var OraclePlatform $platform */ $platform = $this->_platform; $sql = $platform->getListTableCommentsSQL($tableName); $tableOptions = $this->_conn->fetchAssoc($sql); $table->addOption('comment', $tableOptions['COMMENTS']); return $table; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Schema/PostgreSqlSchemaManager.php000066400000000000000000000372441360544566000265610ustar00rootroot00000000000000_conn->executeQuery("SELECT nspname FROM pg_namespace WHERE nspname !~ '^pg_.*' AND nspname != 'information_schema'"); return $statement->fetchAll(FetchMode::COLUMN); } /** * Returns an array of schema search paths. * * This is a PostgreSQL only function. * * @return string[] */ public function getSchemaSearchPaths() { $params = $this->_conn->getParams(); $schema = explode(',', $this->_conn->fetchColumn('SHOW search_path')); if (isset($params['user'])) { $schema = str_replace('"$user"', $params['user'], $schema); } return array_map('trim', $schema); } /** * Gets names of all existing schemas in the current users search path. * * This is a PostgreSQL only function. * * @return string[] */ public function getExistingSchemaSearchPaths() { if ($this->existingSchemaPaths === null) { $this->determineExistingSchemaSearchPaths(); } return $this->existingSchemaPaths; } /** * Sets or resets the order of the existing schemas in the current search path of the user. * * This is a PostgreSQL only function. * * @return void */ public function determineExistingSchemaSearchPaths() { $names = $this->getSchemaNames(); $paths = $this->getSchemaSearchPaths(); $this->existingSchemaPaths = array_filter($paths, static function ($v) use ($names) { return in_array($v, $names); }); } /** * {@inheritdoc} */ public function dropDatabase($database) { try { parent::dropDatabase($database); } catch (DriverException $exception) { // If we have a SQLSTATE 55006, the drop database operation failed // because of active connections on the database. // To force dropping the database, we first have to close all active connections // on that database and issue the drop database operation again. if ($exception->getSQLState() !== '55006') { throw $exception; } assert($this->_platform instanceof PostgreSqlPlatform); $this->_execSql( [ $this->_platform->getDisallowDatabaseConnectionsSQL($database), $this->_platform->getCloseActiveDatabaseConnectionsSQL($database), ] ); parent::dropDatabase($database); } } /** * {@inheritdoc} */ protected function _getPortableTableForeignKeyDefinition($tableForeignKey) { $onUpdate = null; $onDelete = null; $localColumns = []; $foreignColumns = []; $foreignTable = null; if (preg_match('(ON UPDATE ([a-zA-Z0-9]+( (NULL|ACTION|DEFAULT))?))', $tableForeignKey['condef'], $match)) { $onUpdate = $match[1]; } if (preg_match('(ON DELETE ([a-zA-Z0-9]+( (NULL|ACTION|DEFAULT))?))', $tableForeignKey['condef'], $match)) { $onDelete = $match[1]; } if (preg_match('/FOREIGN KEY \((.+)\) REFERENCES (.+)\((.+)\)/', $tableForeignKey['condef'], $values)) { // PostgreSQL returns identifiers that are keywords with quotes, we need them later, don't get // the idea to trim them here. $localColumns = array_map('trim', explode(',', $values[1])); $foreignColumns = array_map('trim', explode(',', $values[3])); $foreignTable = $values[2]; } return new ForeignKeyConstraint( $localColumns, $foreignTable, $foreignColumns, $tableForeignKey['conname'], ['onUpdate' => $onUpdate, 'onDelete' => $onDelete] ); } /** * {@inheritdoc} */ protected function _getPortableTriggerDefinition($trigger) { return $trigger['trigger_name']; } /** * {@inheritdoc} */ protected function _getPortableViewDefinition($view) { return new View($view['schemaname'] . '.' . $view['viewname'], $view['definition']); } /** * {@inheritdoc} */ protected function _getPortableUserDefinition($user) { return [ 'user' => $user['usename'], 'password' => $user['passwd'], ]; } /** * {@inheritdoc} */ protected function _getPortableTableDefinition($table) { $schemas = $this->getExistingSchemaSearchPaths(); $firstSchema = array_shift($schemas); if ($table['schema_name'] === $firstSchema) { return $table['table_name']; } return $table['schema_name'] . '.' . $table['table_name']; } /** * {@inheritdoc} * * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html */ protected function _getPortableTableIndexesList($tableIndexes, $tableName = null) { $buffer = []; foreach ($tableIndexes as $row) { $colNumbers = array_map('intval', explode(' ', $row['indkey'])); $columnNameSql = sprintf( 'SELECT attnum, attname FROM pg_attribute WHERE attrelid=%d AND attnum IN (%s) ORDER BY attnum ASC', $row['indrelid'], implode(' ,', $colNumbers) ); $stmt = $this->_conn->executeQuery($columnNameSql); $indexColumns = $stmt->fetchAll(); // required for getting the order of the columns right. foreach ($colNumbers as $colNum) { foreach ($indexColumns as $colRow) { if ($colNum !== $colRow['attnum']) { continue; } $buffer[] = [ 'key_name' => $row['relname'], 'column_name' => trim($colRow['attname']), 'non_unique' => ! $row['indisunique'], 'primary' => $row['indisprimary'], 'where' => $row['where'], ]; } } } return parent::_getPortableTableIndexesList($buffer, $tableName); } /** * {@inheritdoc} */ protected function _getPortableDatabaseDefinition($database) { return $database['datname']; } /** * {@inheritdoc} */ protected function _getPortableSequencesList($sequences) { $sequenceDefinitions = []; foreach ($sequences as $sequence) { if ($sequence['schemaname'] !== 'public') { $sequenceName = $sequence['schemaname'] . '.' . $sequence['relname']; } else { $sequenceName = $sequence['relname']; } $sequenceDefinitions[$sequenceName] = $sequence; } $list = []; foreach ($this->filterAssetNames(array_keys($sequenceDefinitions)) as $sequenceName) { $list[] = $this->_getPortableSequenceDefinition($sequenceDefinitions[$sequenceName]); } return $list; } /** * {@inheritdoc} */ protected function getPortableNamespaceDefinition(array $namespace) { return $namespace['nspname']; } /** * {@inheritdoc} */ protected function _getPortableSequenceDefinition($sequence) { if ($sequence['schemaname'] !== 'public') { $sequenceName = $sequence['schemaname'] . '.' . $sequence['relname']; } else { $sequenceName = $sequence['relname']; } if (! isset($sequence['increment_by'], $sequence['min_value'])) { /** @var string[] $data */ $data = $this->_conn->fetchAssoc('SELECT min_value, increment_by FROM ' . $this->_platform->quoteIdentifier($sequenceName)); $sequence += $data; } return new Sequence($sequenceName, (int) $sequence['increment_by'], (int) $sequence['min_value']); } /** * {@inheritdoc} */ protected function _getPortableTableColumnDefinition($tableColumn) { $tableColumn = array_change_key_case($tableColumn, CASE_LOWER); if (strtolower($tableColumn['type']) === 'varchar' || strtolower($tableColumn['type']) === 'bpchar') { // get length from varchar definition $length = preg_replace('~.*\(([0-9]*)\).*~', '$1', $tableColumn['complete_type']); $tableColumn['length'] = $length; } $matches = []; $autoincrement = false; if (preg_match("/^nextval\('(.*)'(::.*)?\)$/", $tableColumn['default'], $matches)) { $tableColumn['sequence'] = $matches[1]; $tableColumn['default'] = null; $autoincrement = true; } if (preg_match("/^['(](.*)[')]::/", $tableColumn['default'], $matches)) { $tableColumn['default'] = $matches[1]; } elseif (preg_match('/^NULL::/', $tableColumn['default'])) { $tableColumn['default'] = null; } $length = $tableColumn['length'] ?? null; if ($length === '-1' && isset($tableColumn['atttypmod'])) { $length = $tableColumn['atttypmod'] - 4; } if ((int) $length <= 0) { $length = null; } $fixed = null; if (! isset($tableColumn['name'])) { $tableColumn['name'] = ''; } $precision = null; $scale = null; $jsonb = null; $dbType = strtolower($tableColumn['type']); if (strlen($tableColumn['domain_type']) && ! $this->_platform->hasDoctrineTypeMappingFor($tableColumn['type'])) { $dbType = strtolower($tableColumn['domain_type']); $tableColumn['complete_type'] = $tableColumn['domain_complete_type']; } $type = $this->_platform->getDoctrineTypeMapping($dbType); $type = $this->extractDoctrineTypeFromComment($tableColumn['comment'], $type); $tableColumn['comment'] = $this->removeDoctrineTypeFromComment($tableColumn['comment'], $type); switch ($dbType) { case 'smallint': case 'int2': $tableColumn['default'] = $this->fixVersion94NegativeNumericDefaultValue($tableColumn['default']); $length = null; break; case 'int': case 'int4': case 'integer': $tableColumn['default'] = $this->fixVersion94NegativeNumericDefaultValue($tableColumn['default']); $length = null; break; case 'bigint': case 'int8': $tableColumn['default'] = $this->fixVersion94NegativeNumericDefaultValue($tableColumn['default']); $length = null; break; case 'bool': case 'boolean': if ($tableColumn['default'] === 'true') { $tableColumn['default'] = true; } if ($tableColumn['default'] === 'false') { $tableColumn['default'] = false; } $length = null; break; case 'text': case '_varchar': case 'varchar': $tableColumn['default'] = $this->parseDefaultExpression($tableColumn['default']); $fixed = false; break; case 'interval': $fixed = false; break; case 'char': case 'bpchar': $fixed = true; break; case 'float': case 'float4': case 'float8': case 'double': case 'double precision': case 'real': case 'decimal': case 'money': case 'numeric': $tableColumn['default'] = $this->fixVersion94NegativeNumericDefaultValue($tableColumn['default']); if (preg_match('([A-Za-z]+\(([0-9]+)\,([0-9]+)\))', $tableColumn['complete_type'], $match)) { $precision = $match[1]; $scale = $match[2]; $length = null; } break; case 'year': $length = null; break; // PostgreSQL 9.4+ only case 'jsonb': $jsonb = true; break; } if ($tableColumn['default'] && preg_match("('([^']+)'::)", $tableColumn['default'], $match)) { $tableColumn['default'] = $match[1]; } $options = [ 'length' => $length, 'notnull' => (bool) $tableColumn['isnotnull'], 'default' => $tableColumn['default'], 'precision' => $precision, 'scale' => $scale, 'fixed' => $fixed, 'unsigned' => false, 'autoincrement' => $autoincrement, 'comment' => isset($tableColumn['comment']) && $tableColumn['comment'] !== '' ? $tableColumn['comment'] : null, ]; $column = new Column($tableColumn['field'], Type::getType($type), $options); if (isset($tableColumn['collation']) && ! empty($tableColumn['collation'])) { $column->setPlatformOption('collation', $tableColumn['collation']); } if (in_array($column->getType()->getName(), [Types::JSON_ARRAY, Types::JSON], true)) { $column->setPlatformOption('jsonb', $jsonb); } return $column; } /** * PostgreSQL 9.4 puts parentheses around negative numeric default values that need to be stripped eventually. * * @param mixed $defaultValue * * @return mixed */ private function fixVersion94NegativeNumericDefaultValue($defaultValue) { if (strpos($defaultValue, '(') === 0) { return trim($defaultValue, '()'); } return $defaultValue; } /** * Parses a default value expression as given by PostgreSQL */ private function parseDefaultExpression(?string $default) : ?string { if ($default === null) { return $default; } return str_replace("''", "'", $default); } public function listTableDetails($tableName) : Table { $table = parent::listTableDetails($tableName); /** @var PostgreSqlPlatform $platform */ $platform = $this->_platform; $sql = $platform->getListTableMetadataSQL($tableName); $tableOptions = $this->_conn->fetchAssoc($sql); $table->addOption('comment', $tableOptions['table_comment']); return $table; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Schema/SQLAnywhereSchemaManager.php000066400000000000000000000162561360544566000266200ustar00rootroot00000000000000startDatabase($database); } /** * {@inheritdoc} * * Tries stopping a database before dropping * as SQL Anywhere needs a database to be stopped * before it can be dropped. * * @see stopDatabase */ public function dropDatabase($database) { $this->tryMethod('stopDatabase', $database); parent::dropDatabase($database); } /** * Starts a database. * * @param string $database The name of the database to start. */ public function startDatabase($database) { assert($this->_platform instanceof SQLAnywherePlatform); $this->_execSql($this->_platform->getStartDatabaseSQL($database)); } /** * Stops a database. * * @param string $database The name of the database to stop. */ public function stopDatabase($database) { assert($this->_platform instanceof SQLAnywherePlatform); $this->_execSql($this->_platform->getStopDatabaseSQL($database)); } /** * {@inheritdoc} */ protected function _getPortableDatabaseDefinition($database) { return $database['name']; } /** * {@inheritdoc} */ protected function _getPortableSequenceDefinition($sequence) { return new Sequence($sequence['sequence_name'], $sequence['increment_by'], $sequence['start_with']); } /** * {@inheritdoc} */ protected function _getPortableTableColumnDefinition($tableColumn) { $type = $this->_platform->getDoctrineTypeMapping($tableColumn['type']); $type = $this->extractDoctrineTypeFromComment($tableColumn['comment'], $type); $tableColumn['comment'] = $this->removeDoctrineTypeFromComment($tableColumn['comment'], $type); $precision = null; $scale = null; $fixed = false; $default = null; if ($tableColumn['default'] !== null) { // Strip quotes from default value. $default = preg_replace(["/^'(.*)'$/", "/''/"], ['$1', "'"], $tableColumn['default']); if ($default === 'autoincrement') { $default = null; } } switch ($tableColumn['type']) { case 'binary': case 'char': case 'nchar': $fixed = true; } switch ($type) { case 'decimal': case 'float': $precision = $tableColumn['length']; $scale = $tableColumn['scale']; } return new Column( $tableColumn['column_name'], Type::getType($type), [ 'length' => $type === 'string' ? $tableColumn['length'] : null, 'precision' => $precision, 'scale' => $scale, 'unsigned' => (bool) $tableColumn['unsigned'], 'fixed' => $fixed, 'notnull' => (bool) $tableColumn['notnull'], 'default' => $default, 'autoincrement' => (bool) $tableColumn['autoincrement'], 'comment' => isset($tableColumn['comment']) && $tableColumn['comment'] !== '' ? $tableColumn['comment'] : null, ] ); } /** * {@inheritdoc} */ protected function _getPortableTableDefinition($table) { return $table['table_name']; } /** * {@inheritdoc} */ protected function _getPortableTableForeignKeyDefinition($tableForeignKey) { return new ForeignKeyConstraint( $tableForeignKey['local_columns'], $tableForeignKey['foreign_table'], $tableForeignKey['foreign_columns'], $tableForeignKey['name'], $tableForeignKey['options'] ); } /** * {@inheritdoc} */ protected function _getPortableTableForeignKeysList($tableForeignKeys) { $foreignKeys = []; foreach ($tableForeignKeys as $tableForeignKey) { if (! isset($foreignKeys[$tableForeignKey['index_name']])) { $foreignKeys[$tableForeignKey['index_name']] = [ 'local_columns' => [$tableForeignKey['local_column']], 'foreign_table' => $tableForeignKey['foreign_table'], 'foreign_columns' => [$tableForeignKey['foreign_column']], 'name' => $tableForeignKey['index_name'], 'options' => [ 'notnull' => $tableForeignKey['notnull'], 'match' => $tableForeignKey['match'], 'onUpdate' => $tableForeignKey['on_update'], 'onDelete' => $tableForeignKey['on_delete'], 'check_on_commit' => $tableForeignKey['check_on_commit'], 'clustered' => $tableForeignKey['clustered'], 'for_olap_workload' => $tableForeignKey['for_olap_workload'], ], ]; } else { $foreignKeys[$tableForeignKey['index_name']]['local_columns'][] = $tableForeignKey['local_column']; $foreignKeys[$tableForeignKey['index_name']]['foreign_columns'][] = $tableForeignKey['foreign_column']; } } return parent::_getPortableTableForeignKeysList($foreignKeys); } /** * {@inheritdoc} */ protected function _getPortableTableIndexesList($tableIndexRows, $tableName = null) { foreach ($tableIndexRows as &$tableIndex) { $tableIndex['primary'] = (bool) $tableIndex['primary']; $tableIndex['flags'] = []; if ($tableIndex['clustered']) { $tableIndex['flags'][] = 'clustered'; } if ($tableIndex['with_nulls_not_distinct']) { $tableIndex['flags'][] = 'with_nulls_not_distinct'; } if (! $tableIndex['for_olap_workload']) { continue; } $tableIndex['flags'][] = 'for_olap_workload'; } return parent::_getPortableTableIndexesList($tableIndexRows, $tableName); } /** * {@inheritdoc} */ protected function _getPortableViewDefinition($view) { $definition = preg_replace('/^.*\s+as\s+SELECT(.*)/i', 'SELECT$1', $view['view_def']); assert(is_string($definition)); return new View($view['table_name'], $definition); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Schema/SQLServerSchemaManager.php000066400000000000000000000253171360544566000263020ustar00rootroot00000000000000getPrevious(); assert($exception instanceof Throwable); if (! $exception instanceof DriverException) { throw $exception; } // If we have a error code 3702, the drop database operation failed // because of active connections on the database. // To force dropping the database, we first have to close all active connections // on that database and issue the drop database operation again. if ($exception->getErrorCode() !== 3702) { throw $exception; } $this->closeActiveDatabaseConnections($database); parent::dropDatabase($database); } } /** * {@inheritdoc} */ protected function _getPortableSequenceDefinition($sequence) { return new Sequence($sequence['name'], (int) $sequence['increment'], (int) $sequence['start_value']); } /** * {@inheritdoc} */ protected function _getPortableTableColumnDefinition($tableColumn) { $dbType = strtok($tableColumn['type'], '(), '); assert(is_string($dbType)); $fixed = null; $length = (int) $tableColumn['length']; $default = $tableColumn['default']; if (! isset($tableColumn['name'])) { $tableColumn['name'] = ''; } if ($default !== null) { $default = $this->parseDefaultExpression($default); } switch ($dbType) { case 'nchar': case 'nvarchar': case 'ntext': // Unicode data requires 2 bytes per character $length /= 2; break; case 'varchar': // TEXT type is returned as VARCHAR(MAX) with a length of -1 if ($length === -1) { $dbType = 'text'; } break; } if ($dbType === 'char' || $dbType === 'nchar' || $dbType === 'binary') { $fixed = true; } $type = $this->_platform->getDoctrineTypeMapping($dbType); $type = $this->extractDoctrineTypeFromComment($tableColumn['comment'], $type); $tableColumn['comment'] = $this->removeDoctrineTypeFromComment($tableColumn['comment'], $type); $options = [ 'length' => $length === 0 || ! in_array($type, ['text', 'string']) ? null : $length, 'unsigned' => false, 'fixed' => (bool) $fixed, 'default' => $default, 'notnull' => (bool) $tableColumn['notnull'], 'scale' => $tableColumn['scale'], 'precision' => $tableColumn['precision'], 'autoincrement' => (bool) $tableColumn['autoincrement'], 'comment' => $tableColumn['comment'] !== '' ? $tableColumn['comment'] : null, ]; $column = new Column($tableColumn['name'], Type::getType($type), $options); if (isset($tableColumn['collation']) && $tableColumn['collation'] !== 'NULL') { $column->setPlatformOption('collation', $tableColumn['collation']); } return $column; } private function parseDefaultExpression(string $value) : ?string { while (preg_match('/^\((.*)\)$/s', $value, $matches)) { $value = $matches[1]; } if ($value === 'NULL') { return null; } if (preg_match('/^\'(.*)\'$/s', $value, $matches)) { $value = str_replace("''", "'", $matches[1]); } if ($value === 'getdate()') { return $this->_platform->getCurrentTimestampSQL(); } return $value; } /** * {@inheritdoc} */ protected function _getPortableTableForeignKeysList($tableForeignKeys) { $foreignKeys = []; foreach ($tableForeignKeys as $tableForeignKey) { if (! isset($foreignKeys[$tableForeignKey['ForeignKey']])) { $foreignKeys[$tableForeignKey['ForeignKey']] = [ 'local_columns' => [$tableForeignKey['ColumnName']], 'foreign_table' => $tableForeignKey['ReferenceTableName'], 'foreign_columns' => [$tableForeignKey['ReferenceColumnName']], 'name' => $tableForeignKey['ForeignKey'], 'options' => [ 'onUpdate' => str_replace('_', ' ', $tableForeignKey['update_referential_action_desc']), 'onDelete' => str_replace('_', ' ', $tableForeignKey['delete_referential_action_desc']), ], ]; } else { $foreignKeys[$tableForeignKey['ForeignKey']]['local_columns'][] = $tableForeignKey['ColumnName']; $foreignKeys[$tableForeignKey['ForeignKey']]['foreign_columns'][] = $tableForeignKey['ReferenceColumnName']; } } return parent::_getPortableTableForeignKeysList($foreignKeys); } /** * {@inheritdoc} */ protected function _getPortableTableIndexesList($tableIndexRows, $tableName = null) { foreach ($tableIndexRows as &$tableIndex) { $tableIndex['non_unique'] = (bool) $tableIndex['non_unique']; $tableIndex['primary'] = (bool) $tableIndex['primary']; $tableIndex['flags'] = $tableIndex['flags'] ? [$tableIndex['flags']] : null; } return parent::_getPortableTableIndexesList($tableIndexRows, $tableName); } /** * {@inheritdoc} */ protected function _getPortableTableForeignKeyDefinition($tableForeignKey) { return new ForeignKeyConstraint( $tableForeignKey['local_columns'], $tableForeignKey['foreign_table'], $tableForeignKey['foreign_columns'], $tableForeignKey['name'], $tableForeignKey['options'] ); } /** * {@inheritdoc} */ protected function _getPortableTableDefinition($table) { if (isset($table['schema_name']) && $table['schema_name'] !== 'dbo') { return $table['schema_name'] . '.' . $table['name']; } return $table['name']; } /** * {@inheritdoc} */ protected function _getPortableDatabaseDefinition($database) { return $database['name']; } /** * {@inheritdoc} */ protected function getPortableNamespaceDefinition(array $namespace) { return $namespace['name']; } /** * {@inheritdoc} */ protected function _getPortableViewDefinition($view) { // @todo return new View($view['name'], ''); } /** * {@inheritdoc} */ public function listTableIndexes($table) { $sql = $this->_platform->getListTableIndexesSQL($table, $this->_conn->getDatabase()); try { $tableIndexes = $this->_conn->fetchAll($sql); } catch (PDOException $e) { if ($e->getCode() === 'IMSSP') { return []; } throw $e; } catch (DBALException $e) { if (strpos($e->getMessage(), 'SQLSTATE [01000, 15472]') === 0) { return []; } throw $e; } return $this->_getPortableTableIndexesList($tableIndexes, $table); } /** * {@inheritdoc} */ public function alterTable(TableDiff $tableDiff) { if (count($tableDiff->removedColumns) > 0) { foreach ($tableDiff->removedColumns as $col) { $columnConstraintSql = $this->getColumnConstraintSQL($tableDiff->name, $col->getName()); foreach ($this->_conn->fetchAll($columnConstraintSql) as $constraint) { $this->_conn->exec( sprintf( 'ALTER TABLE %s DROP CONSTRAINT %s', $tableDiff->name, $constraint['Name'] ) ); } } } parent::alterTable($tableDiff); } /** * Returns the SQL to retrieve the constraints for a given column. * * @param string $table * @param string $column * * @return string */ private function getColumnConstraintSQL($table, $column) { return "SELECT SysObjects.[Name] FROM SysObjects INNER JOIN (SELECT [Name],[ID] FROM SysObjects WHERE XType = 'U') AS Tab ON Tab.[ID] = Sysobjects.[Parent_Obj] INNER JOIN sys.default_constraints DefCons ON DefCons.[object_id] = Sysobjects.[ID] INNER JOIN SysColumns Col ON Col.[ColID] = DefCons.[parent_column_id] AND Col.[ID] = Tab.[ID] WHERE Col.[Name] = " . $this->_conn->quote($column) . ' AND Tab.[Name] = ' . $this->_conn->quote($table) . ' ORDER BY Col.[Name]'; } /** * Closes currently active connections on the given database. * * This is useful to force DROP DATABASE operations which could fail because of active connections. * * @param string $database The name of the database to close currently active connections for. * * @return void */ private function closeActiveDatabaseConnections($database) { $database = new Identifier($database); $this->_execSql( sprintf( 'ALTER DATABASE %s SET SINGLE_USER WITH ROLLBACK IMMEDIATE', $database->getQuotedName($this->_platform) ) ); } /** * @param string $tableName */ public function listTableDetails($tableName) : Table { $table = parent::listTableDetails($tableName); /** @var SQLServerPlatform $platform */ $platform = $this->_platform; $sql = $platform->getListTableMetadataSQL($tableName); $tableOptions = $this->_conn->fetchAssoc($sql); if ($tableOptions !== false) { $table->addOption('comment', $tableOptions['table_comment']); } return $table; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Schema/Schema.php000066400000000000000000000300221360544566000232250ustar00rootroot00000000000000_schemaConfig = $schemaConfig; $this->_setName($schemaConfig->getName() ?: 'public'); foreach ($namespaces as $namespace) { $this->createNamespace($namespace); } foreach ($tables as $table) { $this->_addTable($table); } foreach ($sequences as $sequence) { $this->_addSequence($sequence); } } /** * @return bool */ public function hasExplicitForeignKeyIndexes() { return $this->_schemaConfig->hasExplicitForeignKeyIndexes(); } /** * @return void * * @throws SchemaException */ protected function _addTable(Table $table) { $namespaceName = $table->getNamespaceName(); $tableName = $table->getFullQualifiedName($this->getName()); if (isset($this->_tables[$tableName])) { throw SchemaException::tableAlreadyExists($tableName); } if ($namespaceName !== null && ! $table->isInDefaultNamespace($this->getName()) && ! $this->hasNamespace($namespaceName)) { $this->createNamespace($namespaceName); } $this->_tables[$tableName] = $table; $table->setSchemaConfig($this->_schemaConfig); } /** * @return void * * @throws SchemaException */ protected function _addSequence(Sequence $sequence) { $namespaceName = $sequence->getNamespaceName(); $seqName = $sequence->getFullQualifiedName($this->getName()); if (isset($this->_sequences[$seqName])) { throw SchemaException::sequenceAlreadyExists($seqName); } if ($namespaceName !== null && ! $sequence->isInDefaultNamespace($this->getName()) && ! $this->hasNamespace($namespaceName)) { $this->createNamespace($namespaceName); } $this->_sequences[$seqName] = $sequence; } /** * Returns the namespaces of this schema. * * @return string[] A list of namespace names. */ public function getNamespaces() { return $this->namespaces; } /** * Gets all tables of this schema. * * @return Table[] */ public function getTables() { return $this->_tables; } /** * @param string $tableName * * @return Table * * @throws SchemaException */ public function getTable($tableName) { $tableName = $this->getFullQualifiedAssetName($tableName); if (! isset($this->_tables[$tableName])) { throw SchemaException::tableDoesNotExist($tableName); } return $this->_tables[$tableName]; } /** * @param string $name * * @return string */ private function getFullQualifiedAssetName($name) { $name = $this->getUnquotedAssetName($name); if (strpos($name, '.') === false) { $name = $this->getName() . '.' . $name; } return strtolower($name); } /** * Returns the unquoted representation of a given asset name. * * @param string $assetName Quoted or unquoted representation of an asset name. * * @return string */ private function getUnquotedAssetName($assetName) { if ($this->isIdentifierQuoted($assetName)) { return $this->trimQuotes($assetName); } return $assetName; } /** * Does this schema have a namespace with the given name? * * @param string $namespaceName * * @return bool */ public function hasNamespace($namespaceName) { $namespaceName = strtolower($this->getUnquotedAssetName($namespaceName)); return isset($this->namespaces[$namespaceName]); } /** * Does this schema have a table with the given name? * * @param string $tableName * * @return bool */ public function hasTable($tableName) { $tableName = $this->getFullQualifiedAssetName($tableName); return isset($this->_tables[$tableName]); } /** * Gets all table names, prefixed with a schema name, even the default one if present. * * @return string[] */ public function getTableNames() { return array_keys($this->_tables); } /** * @param string $sequenceName * * @return bool */ public function hasSequence($sequenceName) { $sequenceName = $this->getFullQualifiedAssetName($sequenceName); return isset($this->_sequences[$sequenceName]); } /** * @param string $sequenceName * * @return Sequence * * @throws SchemaException */ public function getSequence($sequenceName) { $sequenceName = $this->getFullQualifiedAssetName($sequenceName); if (! $this->hasSequence($sequenceName)) { throw SchemaException::sequenceDoesNotExist($sequenceName); } return $this->_sequences[$sequenceName]; } /** * @return Sequence[] */ public function getSequences() { return $this->_sequences; } /** * Creates a new namespace. * * @param string $namespaceName The name of the namespace to create. * * @return \Doctrine\DBAL\Schema\Schema This schema instance. * * @throws SchemaException */ public function createNamespace($namespaceName) { $unquotedNamespaceName = strtolower($this->getUnquotedAssetName($namespaceName)); if (isset($this->namespaces[$unquotedNamespaceName])) { throw SchemaException::namespaceAlreadyExists($unquotedNamespaceName); } $this->namespaces[$unquotedNamespaceName] = $namespaceName; return $this; } /** * Creates a new table. * * @param string $tableName * * @return Table */ public function createTable($tableName) { $table = new Table($tableName); $this->_addTable($table); foreach ($this->_schemaConfig->getDefaultTableOptions() as $name => $value) { $table->addOption($name, $value); } return $table; } /** * Renames a table. * * @param string $oldTableName * @param string $newTableName * * @return \Doctrine\DBAL\Schema\Schema */ public function renameTable($oldTableName, $newTableName) { $table = $this->getTable($oldTableName); $table->_setName($newTableName); $this->dropTable($oldTableName); $this->_addTable($table); return $this; } /** * Drops a table from the schema. * * @param string $tableName * * @return \Doctrine\DBAL\Schema\Schema */ public function dropTable($tableName) { $tableName = $this->getFullQualifiedAssetName($tableName); $this->getTable($tableName); unset($this->_tables[$tableName]); return $this; } /** * Creates a new sequence. * * @param string $sequenceName * @param int $allocationSize * @param int $initialValue * * @return Sequence */ public function createSequence($sequenceName, $allocationSize = 1, $initialValue = 1) { $seq = new Sequence($sequenceName, $allocationSize, $initialValue); $this->_addSequence($seq); return $seq; } /** * @param string $sequenceName * * @return \Doctrine\DBAL\Schema\Schema */ public function dropSequence($sequenceName) { $sequenceName = $this->getFullQualifiedAssetName($sequenceName); unset($this->_sequences[$sequenceName]); return $this; } /** * Returns an array of necessary SQL queries to create the schema on the given platform. * * @return string[] */ public function toSql(AbstractPlatform $platform) { $sqlCollector = new CreateSchemaSqlCollector($platform); $this->visit($sqlCollector); return $sqlCollector->getQueries(); } /** * Return an array of necessary SQL queries to drop the schema on the given platform. * * @return string[] */ public function toDropSql(AbstractPlatform $platform) { $dropSqlCollector = new DropSchemaSqlCollector($platform); $this->visit($dropSqlCollector); return $dropSqlCollector->getQueries(); } /** * @return string[] */ public function getMigrateToSql(Schema $toSchema, AbstractPlatform $platform) { $comparator = new Comparator(); $schemaDiff = $comparator->compare($this, $toSchema); return $schemaDiff->toSql($platform); } /** * @return string[] */ public function getMigrateFromSql(Schema $fromSchema, AbstractPlatform $platform) { $comparator = new Comparator(); $schemaDiff = $comparator->compare($fromSchema, $this); return $schemaDiff->toSql($platform); } /** * @return void */ public function visit(Visitor $visitor) { $visitor->acceptSchema($this); if ($visitor instanceof NamespaceVisitor) { foreach ($this->namespaces as $namespace) { $visitor->acceptNamespace($namespace); } } foreach ($this->_tables as $table) { $table->visit($visitor); } foreach ($this->_sequences as $sequence) { $sequence->visit($visitor); } } /** * Cloning a Schema triggers a deep clone of all related assets. * * @return void */ public function __clone() { foreach ($this->_tables as $k => $table) { $this->_tables[$k] = clone $table; } foreach ($this->_sequences as $k => $sequence) { $this->_sequences[$k] = clone $sequence; } } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Schema/SchemaConfig.php000066400000000000000000000035601360544566000243620ustar00rootroot00000000000000hasExplicitForeignKeyIndexes; } /** * @param bool $flag * * @return void */ public function setExplicitForeignKeyIndexes($flag) { $this->hasExplicitForeignKeyIndexes = (bool) $flag; } /** * @param int $length * * @return void */ public function setMaxIdentifierLength($length) { $this->maxIdentifierLength = (int) $length; } /** * @return int */ public function getMaxIdentifierLength() { return $this->maxIdentifierLength; } /** * Gets the default namespace of schema objects. * * @return string */ public function getName() { return $this->name; } /** * Sets the default namespace name of schema objects. * * @param string $name The value to set. * * @return void */ public function setName($name) { $this->name = $name; } /** * Gets the default options that are passed to Table instances created with * Schema#createTable(). * * @return mixed[] */ public function getDefaultTableOptions() { return $this->defaultTableOptions; } /** * @param mixed[] $defaultTableOptions * * @return void */ public function setDefaultTableOptions(array $defaultTableOptions) { $this->defaultTableOptions = $defaultTableOptions; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Schema/SchemaDiff.php000066400000000000000000000103251360544566000240220ustar00rootroot00000000000000newTables = $newTables; $this->changedTables = $changedTables; $this->removedTables = $removedTables; $this->fromSchema = $fromSchema; } /** * The to save sql mode ensures that the following things don't happen: * * 1. Tables are deleted * 2. Sequences are deleted * 3. Foreign Keys which reference tables that would otherwise be deleted. * * This way it is ensured that assets are deleted which might not be relevant to the metadata schema at all. * * @return string[] */ public function toSaveSql(AbstractPlatform $platform) { return $this->_toSql($platform, true); } /** * @return string[] */ public function toSql(AbstractPlatform $platform) { return $this->_toSql($platform, false); } /** * @param bool $saveMode * * @return string[] */ protected function _toSql(AbstractPlatform $platform, $saveMode = false) { $sql = []; if ($platform->supportsSchemas()) { foreach ($this->newNamespaces as $newNamespace) { $sql[] = $platform->getCreateSchemaSQL($newNamespace); } } if ($platform->supportsForeignKeyConstraints() && $saveMode === false) { foreach ($this->orphanedForeignKeys as $orphanedForeignKey) { $sql[] = $platform->getDropForeignKeySQL($orphanedForeignKey, $orphanedForeignKey->getLocalTable()); } } if ($platform->supportsSequences() === true) { foreach ($this->changedSequences as $sequence) { $sql[] = $platform->getAlterSequenceSQL($sequence); } if ($saveMode === false) { foreach ($this->removedSequences as $sequence) { $sql[] = $platform->getDropSequenceSQL($sequence); } } foreach ($this->newSequences as $sequence) { $sql[] = $platform->getCreateSequenceSQL($sequence); } } $foreignKeySql = []; foreach ($this->newTables as $table) { $sql = array_merge( $sql, $platform->getCreateTableSQL($table, AbstractPlatform::CREATE_INDEXES) ); if (! $platform->supportsForeignKeyConstraints()) { continue; } foreach ($table->getForeignKeys() as $foreignKey) { $foreignKeySql[] = $platform->getCreateForeignKeySQL($foreignKey, $table); } } $sql = array_merge($sql, $foreignKeySql); if ($saveMode === false) { foreach ($this->removedTables as $table) { $sql[] = $platform->getDropTableSQL($table); } } foreach ($this->changedTables as $tableDiff) { $sql = array_merge($sql, $platform->getAlterTableSQL($tableDiff)); } return $sql; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Schema/SchemaException.php000066400000000000000000000125011360544566000251060ustar00rootroot00000000000000getName() . ' requires a named foreign key, ' . 'but the given foreign key from (' . implode(', ', $foreignKey->getColumns()) . ') onto foreign table ' . "'" . $foreignKey->getForeignTableName() . "' (" . implode(', ', $foreignKey->getForeignColumns()) . ') is currently ' . 'unnamed.' ); } /** * @param string $changeName * * @return \Doctrine\DBAL\Schema\SchemaException */ public static function alterTableChangeNotSupported($changeName) { return new self( sprintf("Alter table change not supported, given '%s'", $changeName) ); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Schema/Sequence.php000066400000000000000000000057201360544566000236040ustar00rootroot00000000000000_setName($name); $this->setAllocationSize($allocationSize); $this->setInitialValue($initialValue); $this->cache = $cache; } /** * @return int */ public function getAllocationSize() { return $this->allocationSize; } /** * @return int */ public function getInitialValue() { return $this->initialValue; } /** * @return int|null */ public function getCache() { return $this->cache; } /** * @param int $allocationSize * * @return \Doctrine\DBAL\Schema\Sequence */ public function setAllocationSize($allocationSize) { $this->allocationSize = (int) $allocationSize ?: 1; return $this; } /** * @param int $initialValue * * @return \Doctrine\DBAL\Schema\Sequence */ public function setInitialValue($initialValue) { $this->initialValue = (int) $initialValue ?: 1; return $this; } /** * @param int $cache * * @return \Doctrine\DBAL\Schema\Sequence */ public function setCache($cache) { $this->cache = $cache; return $this; } /** * Checks if this sequence is an autoincrement sequence for a given table. * * This is used inside the comparator to not report sequences as missing, * when the "from" schema implicitly creates the sequences. * * @return bool */ public function isAutoIncrementsFor(Table $table) { $primaryKey = $table->getPrimaryKey(); if ($primaryKey === null) { return false; } $pkColumns = $primaryKey->getColumns(); if (count($pkColumns) !== 1) { return false; } $column = $table->getColumn($pkColumns[0]); if (! $column->getAutoincrement()) { return false; } $sequenceName = $this->getShortestName($table->getNamespaceName()); $tableName = $table->getShortestName($table->getNamespaceName()); $tableSequenceName = sprintf('%s_%s_seq', $tableName, $column->getShortestName($table->getNamespaceName())); return $tableSequenceName === $sequenceName; } /** * @return void */ public function visit(Visitor $visitor) { $visitor->acceptSequence($this); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Schema/SqliteSchemaManager.php000066400000000000000000000402361360544566000257120ustar00rootroot00000000000000_conn->getParams(); $driver = $params['driver']; $options = [ 'driver' => $driver, 'path' => $database, ]; $conn = DriverManager::getConnection($options); $conn->connect(); $conn->close(); } /** * {@inheritdoc} */ public function renameTable($name, $newName) { $tableDiff = new TableDiff($name); $tableDiff->fromTable = $this->listTableDetails($name); $tableDiff->newName = $newName; $this->alterTable($tableDiff); } /** * {@inheritdoc} */ public function createForeignKey(ForeignKeyConstraint $foreignKey, $table) { $tableDiff = $this->getTableDiffForAlterForeignKey($table); $tableDiff->addedForeignKeys[] = $foreignKey; $this->alterTable($tableDiff); } /** * {@inheritdoc} */ public function dropAndCreateForeignKey(ForeignKeyConstraint $foreignKey, $table) { $tableDiff = $this->getTableDiffForAlterForeignKey($table); $tableDiff->changedForeignKeys[] = $foreignKey; $this->alterTable($tableDiff); } /** * {@inheritdoc} */ public function dropForeignKey($foreignKey, $table) { $tableDiff = $this->getTableDiffForAlterForeignKey($table); $tableDiff->removedForeignKeys[] = $foreignKey; $this->alterTable($tableDiff); } /** * {@inheritdoc} */ public function listTableForeignKeys($table, $database = null) { if ($database === null) { $database = $this->_conn->getDatabase(); } $sql = $this->_platform->getListTableForeignKeysSQL($table, $database); $tableForeignKeys = $this->_conn->fetchAll($sql); if (! empty($tableForeignKeys)) { $createSql = $this->getCreateTableSQL($table); if ($createSql !== null && preg_match_all( '# (?:CONSTRAINT\s+([^\s]+)\s+)? (?:FOREIGN\s+KEY[^\)]+\)\s*)? REFERENCES\s+[^\s]+\s+(?:\([^\)]+\))? (?: [^,]*? (NOT\s+DEFERRABLE|DEFERRABLE) (?:\s+INITIALLY\s+(DEFERRED|IMMEDIATE))? )?#isx', $createSql, $match )) { $names = array_reverse($match[1]); $deferrable = array_reverse($match[2]); $deferred = array_reverse($match[3]); } else { $names = $deferrable = $deferred = []; } foreach ($tableForeignKeys as $key => $value) { $id = $value['id']; $tableForeignKeys[$key]['constraint_name'] = isset($names[$id]) && $names[$id] !== '' ? $names[$id] : $id; $tableForeignKeys[$key]['deferrable'] = isset($deferrable[$id]) && strtolower($deferrable[$id]) === 'deferrable'; $tableForeignKeys[$key]['deferred'] = isset($deferred[$id]) && strtolower($deferred[$id]) === 'deferred'; } } return $this->_getPortableTableForeignKeysList($tableForeignKeys); } /** * {@inheritdoc} */ protected function _getPortableTableDefinition($table) { return $table['name']; } /** * {@inheritdoc} * * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html */ protected function _getPortableTableIndexesList($tableIndexes, $tableName = null) { $indexBuffer = []; // fetch primary $stmt = $this->_conn->executeQuery(sprintf( 'PRAGMA TABLE_INFO (%s)', $this->_conn->quote($tableName) )); $indexArray = $stmt->fetchAll(FetchMode::ASSOCIATIVE); usort($indexArray, static function ($a, $b) { if ($a['pk'] === $b['pk']) { return $a['cid'] - $b['cid']; } return $a['pk'] - $b['pk']; }); foreach ($indexArray as $indexColumnRow) { if ($indexColumnRow['pk'] === '0') { continue; } $indexBuffer[] = [ 'key_name' => 'primary', 'primary' => true, 'non_unique' => false, 'column_name' => $indexColumnRow['name'], ]; } // fetch regular indexes foreach ($tableIndexes as $tableIndex) { // Ignore indexes with reserved names, e.g. autoindexes if (strpos($tableIndex['name'], 'sqlite_') === 0) { continue; } $keyName = $tableIndex['name']; $idx = []; $idx['key_name'] = $keyName; $idx['primary'] = false; $idx['non_unique'] = ! $tableIndex['unique']; $stmt = $this->_conn->executeQuery(sprintf( 'PRAGMA INDEX_INFO (%s)', $this->_conn->quote($keyName) )); $indexArray = $stmt->fetchAll(FetchMode::ASSOCIATIVE); foreach ($indexArray as $indexColumnRow) { $idx['column_name'] = $indexColumnRow['name']; $indexBuffer[] = $idx; } } return parent::_getPortableTableIndexesList($indexBuffer, $tableName); } /** * {@inheritdoc} * * @deprecated */ protected function _getPortableTableIndexDefinition($tableIndex) { return [ 'name' => $tableIndex['name'], 'unique' => (bool) $tableIndex['unique'], ]; } /** * {@inheritdoc} */ protected function _getPortableTableColumnList($table, $database, $tableColumns) { $list = parent::_getPortableTableColumnList($table, $database, $tableColumns); // find column with autoincrement $autoincrementColumn = null; $autoincrementCount = 0; foreach ($tableColumns as $tableColumn) { if ($tableColumn['pk'] === '0') { continue; } $autoincrementCount++; if ($autoincrementColumn !== null || strtolower($tableColumn['type']) !== 'integer') { continue; } $autoincrementColumn = $tableColumn['name']; } if ($autoincrementCount === 1 && $autoincrementColumn !== null) { foreach ($list as $column) { if ($autoincrementColumn !== $column->getName()) { continue; } $column->setAutoincrement(true); } } // inspect column collation and comments $createSql = $this->getCreateTableSQL($table) ?? ''; foreach ($list as $columnName => $column) { $type = $column->getType(); if ($type instanceof StringType || $type instanceof TextType) { $column->setPlatformOption('collation', $this->parseColumnCollationFromSQL($columnName, $createSql) ?: 'BINARY'); } $comment = $this->parseColumnCommentFromSQL($columnName, $createSql); if ($comment === null) { continue; } $type = $this->extractDoctrineTypeFromComment($comment, ''); if ($type !== '') { $column->setType(Type::getType($type)); $comment = $this->removeDoctrineTypeFromComment($comment, $type); } $column->setComment($comment); } return $list; } /** * {@inheritdoc} */ protected function _getPortableTableColumnDefinition($tableColumn) { $parts = explode('(', $tableColumn['type']); $tableColumn['type'] = trim($parts[0]); if (isset($parts[1])) { $length = trim($parts[1], ')'); $tableColumn['length'] = $length; } $dbType = strtolower($tableColumn['type']); $length = $tableColumn['length'] ?? null; $unsigned = false; if (strpos($dbType, ' unsigned') !== false) { $dbType = str_replace(' unsigned', '', $dbType); $unsigned = true; } $fixed = false; $type = $this->_platform->getDoctrineTypeMapping($dbType); $default = $tableColumn['dflt_value']; if ($default === 'NULL') { $default = null; } if ($default !== null) { // SQLite returns the default value as a literal expression, so we need to parse it if (preg_match('/^\'(.*)\'$/s', $default, $matches)) { $default = str_replace("''", "'", $matches[1]); } } $notnull = (bool) $tableColumn['notnull']; if (! isset($tableColumn['name'])) { $tableColumn['name'] = ''; } $precision = null; $scale = null; switch ($dbType) { case 'char': $fixed = true; break; case 'float': case 'double': case 'real': case 'decimal': case 'numeric': if (isset($tableColumn['length'])) { if (strpos($tableColumn['length'], ',') === false) { $tableColumn['length'] .= ',0'; } [$precision, $scale] = array_map('trim', explode(',', $tableColumn['length'])); } $length = null; break; } $options = [ 'length' => $length, 'unsigned' => (bool) $unsigned, 'fixed' => $fixed, 'notnull' => $notnull, 'default' => $default, 'precision' => $precision, 'scale' => $scale, 'autoincrement' => false, ]; return new Column($tableColumn['name'], Type::getType($type), $options); } /** * {@inheritdoc} */ protected function _getPortableViewDefinition($view) { return new View($view['name'], $view['sql']); } /** * {@inheritdoc} */ protected function _getPortableTableForeignKeysList($tableForeignKeys) { $list = []; foreach ($tableForeignKeys as $value) { $value = array_change_key_case($value, CASE_LOWER); $name = $value['constraint_name']; if (! isset($list[$name])) { if (! isset($value['on_delete']) || $value['on_delete'] === 'RESTRICT') { $value['on_delete'] = null; } if (! isset($value['on_update']) || $value['on_update'] === 'RESTRICT') { $value['on_update'] = null; } $list[$name] = [ 'name' => $name, 'local' => [], 'foreign' => [], 'foreignTable' => $value['table'], 'onDelete' => $value['on_delete'], 'onUpdate' => $value['on_update'], 'deferrable' => $value['deferrable'], 'deferred'=> $value['deferred'], ]; } $list[$name]['local'][] = $value['from']; $list[$name]['foreign'][] = $value['to']; } $result = []; foreach ($list as $constraint) { $result[] = new ForeignKeyConstraint( array_values($constraint['local']), $constraint['foreignTable'], array_values($constraint['foreign']), $constraint['name'], [ 'onDelete' => $constraint['onDelete'], 'onUpdate' => $constraint['onUpdate'], 'deferrable' => $constraint['deferrable'], 'deferred'=> $constraint['deferred'], ] ); } return $result; } /** * @param Table|string $table * * @return TableDiff * * @throws DBALException */ private function getTableDiffForAlterForeignKey($table) { if (! $table instanceof Table) { $tableDetails = $this->tryMethod('listTableDetails', $table); if ($tableDetails === false) { throw new DBALException(sprintf('Sqlite schema manager requires to modify foreign keys table definition "%s".', $table)); } $table = $tableDetails; } $tableDiff = new TableDiff($table->getName()); $tableDiff->fromTable = $table; return $tableDiff; } private function parseColumnCollationFromSQL(string $column, string $sql) : ?string { $pattern = '{(?:\W' . preg_quote($column) . '\W|\W' . preg_quote($this->_platform->quoteSingleIdentifier($column)) . '\W)[^,(]+(?:\([^()]+\)[^,]*)?(?:(?:DEFAULT|CHECK)\s*(?:\(.*?\))?[^,]*)*COLLATE\s+["\']?([^\s,"\')]+)}is'; if (preg_match($pattern, $sql, $match) !== 1) { return null; } return $match[1]; } private function parseTableCommentFromSQL(string $table, string $sql) : ?string { $pattern = '/\s* # Allow whitespace characters at start of line CREATE\sTABLE # Match "CREATE TABLE" (?:\W"' . preg_quote($this->_platform->quoteSingleIdentifier($table), '/') . '"\W|\W' . preg_quote($table, '/') . '\W) # Match table name (quoted and unquoted) ( # Start capture (?:\s*--[^\n]*\n?)+ # Capture anything that starts with whitespaces followed by -- until the end of the line(s) )/ix'; if (preg_match($pattern, $sql, $match) !== 1) { return null; } $comment = preg_replace('{^\s*--}m', '', rtrim($match[1], "\n")); return $comment === '' ? null : $comment; } private function parseColumnCommentFromSQL(string $column, string $sql) : ?string { $pattern = '{[\s(,](?:\W' . preg_quote($this->_platform->quoteSingleIdentifier($column)) . '\W|\W' . preg_quote($column) . '\W)(?:\(.*?\)|[^,(])*?,?((?:(?!\n))(?:\s*--[^\n]*\n?)+)}i'; if (preg_match($pattern, $sql, $match) !== 1) { return null; } $comment = preg_replace('{^\s*--}m', '', rtrim($match[1], "\n")); return $comment === '' ? null : $comment; } private function getCreateTableSQL(string $table) : ?string { return $this->_conn->fetchColumn( <<<'SQL' SELECT sql FROM ( SELECT * FROM sqlite_master UNION ALL SELECT * FROM sqlite_temp_master ) WHERE type = 'table' AND name = ? SQL , [$table] ) ?: null; } /** * @param string $tableName */ public function listTableDetails($tableName) : Table { $table = parent::listTableDetails($tableName); $tableCreateSql = $this->getCreateTableSQL($tableName) ?? ''; $comment = $this->parseTableCommentFromSQL($tableName, $tableCreateSql); if ($comment !== null) { $table->addOption('comment', $comment); } return $table; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Schema/Synchronizer/000077500000000000000000000000001360544566000240145ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Schema/Synchronizer/AbstractSchemaSynchronizer.php000066400000000000000000000015031360544566000320260ustar00rootroot00000000000000conn = $conn; } /** * @param string[] $sql */ protected function processSqlSafely(array $sql) { foreach ($sql as $s) { try { $this->conn->exec($s); } catch (Throwable $e) { } } } /** * @param string[] $sql */ protected function processSql(array $sql) { foreach ($sql as $s) { $this->conn->exec($s); } } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Schema/Synchronizer/SchemaSynchronizer.php000066400000000000000000000030621360544566000303440ustar00rootroot00000000000000platform = $conn->getDatabasePlatform(); } /** * {@inheritdoc} */ public function getCreateSchema(Schema $createSchema) { return $createSchema->toSql($this->platform); } /** * {@inheritdoc} */ public function getUpdateSchema(Schema $toSchema, $noDrops = false) { $comparator = new Comparator(); $sm = $this->conn->getSchemaManager(); $fromSchema = $sm->createSchema(); $schemaDiff = $comparator->compare($fromSchema, $toSchema); if ($noDrops) { return $schemaDiff->toSaveSql($this->platform); } return $schemaDiff->toSql($this->platform); } /** * {@inheritdoc} */ public function getDropSchema(Schema $dropSchema) { $visitor = new DropSchemaSqlCollector($this->platform); $sm = $this->conn->getSchemaManager(); $fullSchema = $sm->createSchema(); foreach ($fullSchema->getTables() as $table) { if ($dropSchema->hasTable($table->getName())) { $visitor->acceptTable($table); } foreach ($table->getForeignKeys() as $foreignKey) { if (! $dropSchema->hasTable($table->getName())) { continue; } if (! $dropSchema->hasTable($foreignKey->getForeignTableName())) { continue; } $visitor->acceptForeignKey($table, $foreignKey); } } if (! $this->platform->supportsSequences()) { return $visitor->getQueries(); } foreach ($dropSchema->getSequences() as $sequence) { $visitor->acceptSequence($sequence); } foreach ($dropSchema->getTables() as $table) { $primaryKey = $table->getPrimaryKey(); if ($primaryKey === null) { continue; } $columns = $primaryKey->getColumns(); if (count($columns) > 1) { continue; } $checkSequence = $table->getName() . '_' . $columns[0] . '_seq'; if (! $fullSchema->hasSequence($checkSequence)) { continue; } $visitor->acceptSequence($fullSchema->getSequence($checkSequence)); } return $visitor->getQueries(); } /** * {@inheritdoc} */ public function getDropAllSchema() { $sm = $this->conn->getSchemaManager(); $visitor = new DropSchemaSqlCollector($this->platform); $schema = $sm->createSchema(); $schema->visit($visitor); return $visitor->getQueries(); } /** * {@inheritdoc} */ public function createSchema(Schema $createSchema) { $this->processSql($this->getCreateSchema($createSchema)); } /** * {@inheritdoc} */ public function updateSchema(Schema $toSchema, $noDrops = false) { $this->processSql($this->getUpdateSchema($toSchema, $noDrops)); } /** * {@inheritdoc} */ public function dropSchema(Schema $dropSchema) { $this->processSqlSafely($this->getDropSchema($dropSchema)); } /** * {@inheritdoc} */ public function dropAllSchema() { $this->processSql($this->getDropAllSchema()); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Schema/Table.php000066400000000000000000000570301360544566000230640ustar00rootroot00000000000000 [], ]; /** @var SchemaConfig|null */ protected $_schemaConfig = null; /** * @param string $tableName * @param Column[] $columns * @param Index[] $indexes * @param ForeignKeyConstraint[] $fkConstraints * @param int $idGeneratorType * @param mixed[] $options * * @throws DBALException */ public function __construct($tableName, array $columns = [], array $indexes = [], array $fkConstraints = [], $idGeneratorType = 0, array $options = []) { if (strlen($tableName) === 0) { throw DBALException::invalidTableName($tableName); } $this->_setName($tableName); foreach ($columns as $column) { $this->_addColumn($column); } foreach ($indexes as $idx) { $this->_addIndex($idx); } foreach ($fkConstraints as $constraint) { $this->_addForeignKeyConstraint($constraint); } $this->_options = array_merge($this->_options, $options); } /** * @return void */ public function setSchemaConfig(SchemaConfig $schemaConfig) { $this->_schemaConfig = $schemaConfig; } /** * @return int */ protected function _getMaxIdentifierLength() { if ($this->_schemaConfig instanceof SchemaConfig) { return $this->_schemaConfig->getMaxIdentifierLength(); } return 63; } /** * Sets the Primary Key. * * @param string[] $columnNames * @param string|false $indexName * * @return self */ public function setPrimaryKey(array $columnNames, $indexName = false) { $this->_addIndex($this->_createIndex($columnNames, $indexName ?: 'primary', true, true)); foreach ($columnNames as $columnName) { $column = $this->getColumn($columnName); $column->setNotnull(true); } return $this; } /** * @param string[] $columnNames * @param string|null $indexName * @param string[] $flags * @param mixed[] $options * * @return self */ public function addIndex(array $columnNames, $indexName = null, array $flags = [], array $options = []) { if ($indexName === null) { $indexName = $this->_generateIdentifierName( array_merge([$this->getName()], $columnNames), 'idx', $this->_getMaxIdentifierLength() ); } return $this->_addIndex($this->_createIndex($columnNames, $indexName, false, false, $flags, $options)); } /** * Drops the primary key from this table. * * @return void */ public function dropPrimaryKey() { $this->dropIndex($this->_primaryKeyName); $this->_primaryKeyName = false; } /** * Drops an index from this table. * * @param string $indexName The index name. * * @return void * * @throws SchemaException If the index does not exist. */ public function dropIndex($indexName) { $indexName = $this->normalizeIdentifier($indexName); if (! $this->hasIndex($indexName)) { throw SchemaException::indexDoesNotExist($indexName, $this->_name); } unset($this->_indexes[$indexName]); } /** * @param string[] $columnNames * @param string|null $indexName * @param mixed[] $options * * @return self */ public function addUniqueIndex(array $columnNames, $indexName = null, array $options = []) { if ($indexName === null) { $indexName = $this->_generateIdentifierName( array_merge([$this->getName()], $columnNames), 'uniq', $this->_getMaxIdentifierLength() ); } return $this->_addIndex($this->_createIndex($columnNames, $indexName, true, false, [], $options)); } /** * Renames an index. * * @param string $oldIndexName The name of the index to rename from. * @param string|null $newIndexName The name of the index to rename to. * If null is given, the index name will be auto-generated. * * @return self This table instance. * * @throws SchemaException If no index exists for the given current name * or if an index with the given new name already exists on this table. */ public function renameIndex($oldIndexName, $newIndexName = null) { $oldIndexName = $this->normalizeIdentifier($oldIndexName); $normalizedNewIndexName = $this->normalizeIdentifier($newIndexName); if ($oldIndexName === $normalizedNewIndexName) { return $this; } if (! $this->hasIndex($oldIndexName)) { throw SchemaException::indexDoesNotExist($oldIndexName, $this->_name); } if ($this->hasIndex($normalizedNewIndexName)) { throw SchemaException::indexAlreadyExists($normalizedNewIndexName, $this->_name); } $oldIndex = $this->_indexes[$oldIndexName]; if ($oldIndex->isPrimary()) { $this->dropPrimaryKey(); return $this->setPrimaryKey($oldIndex->getColumns(), $newIndexName ?? false); } unset($this->_indexes[$oldIndexName]); if ($oldIndex->isUnique()) { return $this->addUniqueIndex($oldIndex->getColumns(), $newIndexName, $oldIndex->getOptions()); } return $this->addIndex($oldIndex->getColumns(), $newIndexName, $oldIndex->getFlags(), $oldIndex->getOptions()); } /** * Checks if an index begins in the order of the given columns. * * @param string[] $columnNames * * @return bool */ public function columnsAreIndexed(array $columnNames) { foreach ($this->getIndexes() as $index) { /** @var $index Index */ if ($index->spansColumns($columnNames)) { return true; } } return false; } /** * @param string[] $columnNames * @param string $indexName * @param bool $isUnique * @param bool $isPrimary * @param string[] $flags * @param mixed[] $options * * @return Index * * @throws SchemaException */ private function _createIndex(array $columnNames, $indexName, $isUnique, $isPrimary, array $flags = [], array $options = []) { if (preg_match('(([^a-zA-Z0-9_]+))', $this->normalizeIdentifier($indexName))) { throw SchemaException::indexNameInvalid($indexName); } foreach ($columnNames as $columnName) { if (! $this->hasColumn($columnName)) { throw SchemaException::columnDoesNotExist($columnName, $this->_name); } } return new Index($indexName, $columnNames, $isUnique, $isPrimary, $flags, $options); } /** * @param string $columnName * @param string $typeName * @param mixed[] $options * * @return Column */ public function addColumn($columnName, $typeName, array $options = []) { $column = new Column($columnName, Type::getType($typeName), $options); $this->_addColumn($column); return $column; } /** * Renames a Column. * * @deprecated * * @param string $oldColumnName * @param string $newColumnName * * @throws DBALException */ public function renameColumn($oldColumnName, $newColumnName) { throw new DBALException('Table#renameColumn() was removed, because it drops and recreates ' . 'the column instead. There is no fix available, because a schema diff cannot reliably detect if a ' . 'column was renamed or one column was created and another one dropped.'); } /** * Change Column Details. * * @param string $columnName * @param mixed[] $options * * @return self */ public function changeColumn($columnName, array $options) { $column = $this->getColumn($columnName); $column->setOptions($options); return $this; } /** * Drops a Column from the Table. * * @param string $columnName * * @return self */ public function dropColumn($columnName) { $columnName = $this->normalizeIdentifier($columnName); unset($this->_columns[$columnName]); return $this; } /** * Adds a foreign key constraint. * * Name is inferred from the local columns. * * @param Table|string $foreignTable Table schema instance or table name * @param string[] $localColumnNames * @param string[] $foreignColumnNames * @param mixed[] $options * @param string|null $constraintName * * @return self */ public function addForeignKeyConstraint($foreignTable, array $localColumnNames, array $foreignColumnNames, array $options = [], $constraintName = null) { $constraintName = $constraintName ?: $this->_generateIdentifierName(array_merge((array) $this->getName(), $localColumnNames), 'fk', $this->_getMaxIdentifierLength()); return $this->addNamedForeignKeyConstraint($constraintName, $foreignTable, $localColumnNames, $foreignColumnNames, $options); } /** * Adds a foreign key constraint. * * Name is to be generated by the database itself. * * @deprecated Use {@link addForeignKeyConstraint} * * @param Table|string $foreignTable Table schema instance or table name * @param string[] $localColumnNames * @param string[] $foreignColumnNames * @param mixed[] $options * * @return self */ public function addUnnamedForeignKeyConstraint($foreignTable, array $localColumnNames, array $foreignColumnNames, array $options = []) { return $this->addForeignKeyConstraint($foreignTable, $localColumnNames, $foreignColumnNames, $options); } /** * Adds a foreign key constraint with a given name. * * @deprecated Use {@link addForeignKeyConstraint} * * @param string $name * @param Table|string $foreignTable Table schema instance or table name * @param string[] $localColumnNames * @param string[] $foreignColumnNames * @param mixed[] $options * * @return self * * @throws SchemaException */ public function addNamedForeignKeyConstraint($name, $foreignTable, array $localColumnNames, array $foreignColumnNames, array $options = []) { if ($foreignTable instanceof Table) { foreach ($foreignColumnNames as $columnName) { if (! $foreignTable->hasColumn($columnName)) { throw SchemaException::columnDoesNotExist($columnName, $foreignTable->getName()); } } } foreach ($localColumnNames as $columnName) { if (! $this->hasColumn($columnName)) { throw SchemaException::columnDoesNotExist($columnName, $this->_name); } } $constraint = new ForeignKeyConstraint( $localColumnNames, $foreignTable, $foreignColumnNames, $name, $options ); $this->_addForeignKeyConstraint($constraint); return $this; } /** * @param string $name * @param mixed $value * * @return self */ public function addOption($name, $value) { $this->_options[$name] = $value; return $this; } /** * @return void * * @throws SchemaException */ protected function _addColumn(Column $column) { $columnName = $column->getName(); $columnName = $this->normalizeIdentifier($columnName); if (isset($this->_columns[$columnName])) { throw SchemaException::columnAlreadyExists($this->getName(), $columnName); } $this->_columns[$columnName] = $column; } /** * Adds an index to the table. * * @return self * * @throws SchemaException */ protected function _addIndex(Index $indexCandidate) { $indexName = $indexCandidate->getName(); $indexName = $this->normalizeIdentifier($indexName); $replacedImplicitIndexes = []; foreach ($this->implicitIndexes as $name => $implicitIndex) { if (! $implicitIndex->isFullfilledBy($indexCandidate) || ! isset($this->_indexes[$name])) { continue; } $replacedImplicitIndexes[] = $name; } if ((isset($this->_indexes[$indexName]) && ! in_array($indexName, $replacedImplicitIndexes, true)) || ($this->_primaryKeyName !== false && $indexCandidate->isPrimary()) ) { throw SchemaException::indexAlreadyExists($indexName, $this->_name); } foreach ($replacedImplicitIndexes as $name) { unset($this->_indexes[$name], $this->implicitIndexes[$name]); } if ($indexCandidate->isPrimary()) { $this->_primaryKeyName = $indexName; } $this->_indexes[$indexName] = $indexCandidate; return $this; } /** * @return void */ protected function _addForeignKeyConstraint(ForeignKeyConstraint $constraint) { $constraint->setLocalTable($this); if (strlen($constraint->getName())) { $name = $constraint->getName(); } else { $name = $this->_generateIdentifierName( array_merge((array) $this->getName(), $constraint->getLocalColumns()), 'fk', $this->_getMaxIdentifierLength() ); } $name = $this->normalizeIdentifier($name); $this->_fkConstraints[$name] = $constraint; // add an explicit index on the foreign key columns. If there is already an index that fulfils this requirements drop the request. // In the case of __construct calling this method during hydration from schema-details all the explicitly added indexes // lead to duplicates. This creates computation overhead in this case, however no duplicate indexes are ever added (based on columns). $indexName = $this->_generateIdentifierName( array_merge([$this->getName()], $constraint->getColumns()), 'idx', $this->_getMaxIdentifierLength() ); $indexCandidate = $this->_createIndex($constraint->getColumns(), $indexName, false, false); foreach ($this->_indexes as $existingIndex) { if ($indexCandidate->isFullfilledBy($existingIndex)) { return; } } $this->_addIndex($indexCandidate); $this->implicitIndexes[$this->normalizeIdentifier($indexName)] = $indexCandidate; } /** * Returns whether this table has a foreign key constraint with the given name. * * @param string $constraintName * * @return bool */ public function hasForeignKey($constraintName) { $constraintName = $this->normalizeIdentifier($constraintName); return isset($this->_fkConstraints[$constraintName]); } /** * Returns the foreign key constraint with the given name. * * @param string $constraintName The constraint name. * * @return ForeignKeyConstraint * * @throws SchemaException If the foreign key does not exist. */ public function getForeignKey($constraintName) { $constraintName = $this->normalizeIdentifier($constraintName); if (! $this->hasForeignKey($constraintName)) { throw SchemaException::foreignKeyDoesNotExist($constraintName, $this->_name); } return $this->_fkConstraints[$constraintName]; } /** * Removes the foreign key constraint with the given name. * * @param string $constraintName The constraint name. * * @return void * * @throws SchemaException */ public function removeForeignKey($constraintName) { $constraintName = $this->normalizeIdentifier($constraintName); if (! $this->hasForeignKey($constraintName)) { throw SchemaException::foreignKeyDoesNotExist($constraintName, $this->_name); } unset($this->_fkConstraints[$constraintName]); } /** * Returns ordered list of columns (primary keys are first, then foreign keys, then the rest) * * @return Column[] */ public function getColumns() { $primaryKey = $this->getPrimaryKey(); $primaryKeyColumns = []; if ($primaryKey !== null) { $primaryKeyColumns = $this->filterColumns($primaryKey->getColumns()); } return array_merge($primaryKeyColumns, $this->getForeignKeyColumns(), $this->_columns); } /** * Returns foreign key columns * * @return Column[] */ private function getForeignKeyColumns() { $foreignKeyColumns = []; foreach ($this->getForeignKeys() as $foreignKey) { $foreignKeyColumns = array_merge($foreignKeyColumns, $foreignKey->getColumns()); } return $this->filterColumns($foreignKeyColumns); } /** * Returns only columns that have specified names * * @param string[] $columnNames * * @return Column[] */ private function filterColumns(array $columnNames) { return array_filter($this->_columns, static function ($columnName) use ($columnNames) { return in_array($columnName, $columnNames, true); }, ARRAY_FILTER_USE_KEY); } /** * Returns whether this table has a Column with the given name. * * @param string $columnName The column name. * * @return bool */ public function hasColumn($columnName) { $columnName = $this->normalizeIdentifier($columnName); return isset($this->_columns[$columnName]); } /** * Returns the Column with the given name. * * @param string $columnName The column name. * * @return Column * * @throws SchemaException If the column does not exist. */ public function getColumn($columnName) { $columnName = $this->normalizeIdentifier($columnName); if (! $this->hasColumn($columnName)) { throw SchemaException::columnDoesNotExist($columnName, $this->_name); } return $this->_columns[$columnName]; } /** * Returns the primary key. * * @return Index|null The primary key, or null if this Table has no primary key. */ public function getPrimaryKey() { if (! $this->hasPrimaryKey()) { return null; } return $this->getIndex($this->_primaryKeyName); } /** * Returns the primary key columns. * * @return string[] * * @throws DBALException */ public function getPrimaryKeyColumns() { $primaryKey = $this->getPrimaryKey(); if ($primaryKey === null) { throw new DBALException('Table ' . $this->getName() . ' has no primary key.'); } return $primaryKey->getColumns(); } /** * Returns whether this table has a primary key. * * @return bool */ public function hasPrimaryKey() { return $this->_primaryKeyName && $this->hasIndex($this->_primaryKeyName); } /** * Returns whether this table has an Index with the given name. * * @param string $indexName The index name. * * @return bool */ public function hasIndex($indexName) { $indexName = $this->normalizeIdentifier($indexName); return isset($this->_indexes[$indexName]); } /** * Returns the Index with the given name. * * @param string $indexName The index name. * * @return Index * * @throws SchemaException If the index does not exist. */ public function getIndex($indexName) { $indexName = $this->normalizeIdentifier($indexName); if (! $this->hasIndex($indexName)) { throw SchemaException::indexDoesNotExist($indexName, $this->_name); } return $this->_indexes[$indexName]; } /** * @return Index[] */ public function getIndexes() { return $this->_indexes; } /** * Returns the foreign key constraints. * * @return ForeignKeyConstraint[] */ public function getForeignKeys() { return $this->_fkConstraints; } /** * @param string $name * * @return bool */ public function hasOption($name) { return isset($this->_options[$name]); } /** * @param string $name * * @return mixed */ public function getOption($name) { return $this->_options[$name]; } /** * @return mixed[] */ public function getOptions() { return $this->_options; } /** * @return void */ public function visit(Visitor $visitor) { $visitor->acceptTable($this); foreach ($this->getColumns() as $column) { $visitor->acceptColumn($this, $column); } foreach ($this->getIndexes() as $index) { $visitor->acceptIndex($this, $index); } foreach ($this->getForeignKeys() as $constraint) { $visitor->acceptForeignKey($this, $constraint); } } /** * Clone of a Table triggers a deep clone of all affected assets. * * @return void */ public function __clone() { foreach ($this->_columns as $k => $column) { $this->_columns[$k] = clone $column; } foreach ($this->_indexes as $k => $index) { $this->_indexes[$k] = clone $index; } foreach ($this->_fkConstraints as $k => $fk) { $this->_fkConstraints[$k] = clone $fk; $this->_fkConstraints[$k]->setLocalTable($this); } } /** * Normalizes a given identifier. * * Trims quotes and lowercases the given identifier. * * @param string|null $identifier The identifier to normalize. * * @return string The normalized identifier. */ private function normalizeIdentifier($identifier) { if ($identifier === null) { return ''; } return $this->trimQuotes(strtolower($identifier)); } public function setComment(?string $comment) : self { // For keeping backward compatibility with MySQL in previous releases, table comments are stored as options. $this->addOption('comment', $comment); return $this; } public function getComment() : ?string { return $this->_options['comment'] ?? null; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Schema/TableDiff.php000066400000000000000000000061701360544566000236540ustar00rootroot00000000000000name = $tableName; $this->addedColumns = $addedColumns; $this->changedColumns = $changedColumns; $this->removedColumns = $removedColumns; $this->addedIndexes = $addedIndexes; $this->changedIndexes = $changedIndexes; $this->removedIndexes = $removedIndexes; $this->fromTable = $fromTable; } /** * @param AbstractPlatform $platform The platform to use for retrieving this table diff's name. * * @return Identifier */ public function getName(AbstractPlatform $platform) { return new Identifier( $this->fromTable instanceof Table ? $this->fromTable->getQuotedName($platform) : $this->name ); } /** * @return Identifier|false */ public function getNewName() { if ($this->newName === false) { return false; } return new Identifier($this->newName); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Schema/View.php000066400000000000000000000007111360544566000227410ustar00rootroot00000000000000_setName($name); $this->sql = $sql; } /** * @return string */ public function getSql() { return $this->sql; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Schema/Visitor/000077500000000000000000000000001360544566000227565ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Schema/Visitor/AbstractVisitor.php000066400000000000000000000016471360544566000266220ustar00rootroot00000000000000platform = $platform; } /** * {@inheritdoc} */ public function acceptNamespace($namespaceName) { if (! $this->platform->supportsSchemas()) { return; } $this->createNamespaceQueries[] = $this->platform->getCreateSchemaSQL($namespaceName); } /** * {@inheritdoc} */ public function acceptTable(Table $table) { $this->createTableQueries = array_merge($this->createTableQueries, $this->platform->getCreateTableSQL($table)); } /** * {@inheritdoc} */ public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint) { if (! $this->platform->supportsForeignKeyConstraints()) { return; } $this->createFkConstraintQueries[] = $this->platform->getCreateForeignKeySQL($fkConstraint, $localTable); } /** * {@inheritdoc} */ public function acceptSequence(Sequence $sequence) { $this->createSequenceQueries[] = $this->platform->getCreateSequenceSQL($sequence); } /** * @return void */ public function resetQueries() { $this->createNamespaceQueries = []; $this->createTableQueries = []; $this->createSequenceQueries = []; $this->createFkConstraintQueries = []; } /** * Gets all queries collected so far. * * @return string[] */ public function getQueries() { return array_merge( $this->createNamespaceQueries, $this->createTableQueries, $this->createSequenceQueries, $this->createFkConstraintQueries ); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Schema/Visitor/DropSchemaSqlCollector.php000066400000000000000000000045571360544566000300560ustar00rootroot00000000000000platform = $platform; $this->clearQueries(); } /** * {@inheritdoc} */ public function acceptTable(Table $table) { $this->tables->attach($table); } /** * {@inheritdoc} */ public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint) { if (strlen($fkConstraint->getName()) === 0) { throw SchemaException::namedForeignKeyRequired($localTable, $fkConstraint); } $this->constraints->attach($fkConstraint, $localTable); } /** * {@inheritdoc} */ public function acceptSequence(Sequence $sequence) { $this->sequences->attach($sequence); } /** * @return void */ public function clearQueries() { $this->constraints = new SplObjectStorage(); $this->sequences = new SplObjectStorage(); $this->tables = new SplObjectStorage(); } /** * @return string[] */ public function getQueries() { $sql = []; /** @var ForeignKeyConstraint $fkConstraint */ foreach ($this->constraints as $fkConstraint) { $localTable = $this->constraints[$fkConstraint]; $sql[] = $this->platform->getDropForeignKeySQL($fkConstraint, $localTable); } /** @var Sequence $sequence */ foreach ($this->sequences as $sequence) { $sql[] = $this->platform->getDropSequenceSQL($sequence); } /** @var Table $table */ foreach ($this->tables as $table) { $sql[] = $this->platform->getDropTableSQL($table); } return $sql; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Schema/Visitor/Graphviz.php000066400000000000000000000105701360544566000252640ustar00rootroot00000000000000output .= $this->createNodeRelation( $fkConstraint->getLocalTableName() . ':col' . current($fkConstraint->getLocalColumns()) . ':se', $fkConstraint->getForeignTableName() . ':col' . current($fkConstraint->getForeignColumns()) . ':se', [ 'dir' => 'back', 'arrowtail' => 'dot', 'arrowhead' => 'normal', ] ); } /** * {@inheritdoc} */ public function acceptSchema(Schema $schema) { $this->output = 'digraph "' . $schema->getName() . '" {' . "\n"; $this->output .= 'splines = true;' . "\n"; $this->output .= 'overlap = false;' . "\n"; $this->output .= 'outputorder=edgesfirst;' . "\n"; $this->output .= 'mindist = 0.6;' . "\n"; $this->output .= 'sep = .2;' . "\n"; } /** * {@inheritdoc} */ public function acceptTable(Table $table) { $this->output .= $this->createNode( $table->getName(), [ 'label' => $this->createTableLabel($table), 'shape' => 'plaintext', ] ); } /** * @return string */ private function createTableLabel(Table $table) { // Start the table $label = '<'; // The title $label .= ''; // The attributes block foreach ($table->getColumns() as $column) { $columnLabel = $column->getName(); $label .= ''; $label .= ''; $label .= ''; } // End the table $label .= '
' . $table->getName() . '
'; $label .= '' . $columnLabel . ''; $label .= '' . strtolower($column->getType()) . ''; $primaryKey = $table->getPrimaryKey(); if ($primaryKey !== null && in_array($column->getName(), $primaryKey->getColumns())) { $label .= "\xe2\x9c\xb7"; } $label .= '
>'; return $label; } /** * @param string $name * @param string[] $options * * @return string */ private function createNode($name, $options) { $node = $name . ' ['; foreach ($options as $key => $value) { $node .= $key . '=' . $value . ' '; } $node .= "]\n"; return $node; } /** * @param string $node1 * @param string $node2 * @param string[] $options * * @return string */ private function createNodeRelation($node1, $node2, $options) { $relation = $node1 . ' -> ' . $node2 . ' ['; foreach ($options as $key => $value) { $relation .= $key . '=' . $value . ' '; } $relation .= "]\n"; return $relation; } /** * Get Graphviz Output * * @return string */ public function getOutput() { return $this->output . '}'; } /** * Writes dot language output to a file. This should usually be a *.dot file. * * You have to convert the output into a viewable format. For example use "neato" on linux systems * and execute: * * neato -Tpng -o er.png er.dot * * @param string $filename * * @return void */ public function write($filename) { file_put_contents($filename, $this->getOutput()); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Schema/Visitor/NamespaceVisitor.php000066400000000000000000000005011360544566000267370ustar00rootroot00000000000000schema = $schema; } /** * {@inheritdoc} */ public function acceptTable(Table $table) { if ($table->isInDefaultNamespace($this->schema->getName())) { return; } $this->schema->dropTable($table->getName()); } /** * {@inheritdoc} */ public function acceptSequence(Sequence $sequence) { if ($sequence->isInDefaultNamespace($this->schema->getName())) { return; } $this->schema->dropSequence($sequence->getName()); } /** * {@inheritdoc} */ public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint) { // The table may already be deleted in a previous // RemoveNamespacedAssets#acceptTable call. Removing Foreign keys that // point to nowhere. if (! $this->schema->hasTable($fkConstraint->getForeignTableName())) { $localTable->removeForeignKey($fkConstraint->getName()); return; } $foreignTable = $this->schema->getTable($fkConstraint->getForeignTableName()); if ($foreignTable->isInDefaultNamespace($this->schema->getName())) { return; } $localTable->removeForeignKey($fkConstraint->getName()); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Schema/Visitor/SchemaDiffVisitor.php000066400000000000000000000017311360544566000270420ustar00rootroot00000000000000 "client" to the ShardChoser interface. * - An exception is thrown if trying to switch shards during an open * transaction. * * Instantiation through the DriverManager looks like: * * @example * * $conn = DriverManager::getConnection(array( * 'wrapperClass' => 'Doctrine\DBAL\Sharding\PoolingShardConnection', * 'driver' => 'pdo_mysql', * 'global' => array('user' => '', 'password' => '', 'host' => '', 'dbname' => ''), * 'shards' => array( * array('id' => 1, 'user' => 'slave1', 'password', 'host' => '', 'dbname' => ''), * array('id' => 2, 'user' => 'slave2', 'password', 'host' => '', 'dbname' => ''), * ), * 'shardChoser' => 'Doctrine\DBAL\Sharding\ShardChoser\MultiTenantShardChoser', * )); * $shardManager = $conn->getShardManager(); * $shardManager->selectGlobal(); * $shardManager->selectShard($value); */ class PoolingShardConnection extends Connection { /** @var DriverConnection[] */ private $activeConnections = []; /** @var string|int|null */ private $activeShardId; /** @var mixed[] */ private $connectionParameters = []; /** * {@inheritDoc} * * @throws InvalidArgumentException */ public function __construct(array $params, Driver $driver, ?Configuration $config = null, ?EventManager $eventManager = null) { if (! isset($params['global'], $params['shards'])) { throw new InvalidArgumentException("Connection Parameters require 'global' and 'shards' configurations."); } if (! isset($params['shardChoser'])) { throw new InvalidArgumentException("Missing Shard Choser configuration 'shardChoser'"); } if (is_string($params['shardChoser'])) { $params['shardChoser'] = new $params['shardChoser'](); } if (! ($params['shardChoser'] instanceof ShardChoser)) { throw new InvalidArgumentException("The 'shardChoser' configuration is not a valid instance of Doctrine\DBAL\Sharding\ShardChoser\ShardChoser"); } $this->connectionParameters[0] = array_merge($params, $params['global']); foreach ($params['shards'] as $shard) { if (! isset($shard['id'])) { throw new InvalidArgumentException("Missing 'id' for one configured shard. Please specify a unique shard-id."); } if (! is_numeric($shard['id']) || $shard['id'] < 1) { throw new InvalidArgumentException('Shard Id has to be a non-negative number.'); } if (isset($this->connectionParameters[$shard['id']])) { throw new InvalidArgumentException('Shard ' . $shard['id'] . ' is duplicated in the configuration.'); } $this->connectionParameters[$shard['id']] = array_merge($params, $shard); } parent::__construct($params, $driver, $config, $eventManager); } /** * Get active shard id. * * @return string|int|null */ public function getActiveShardId() { return $this->activeShardId; } /** * {@inheritdoc} */ public function getParams() { return $this->activeShardId ? $this->connectionParameters[$this->activeShardId] : $this->connectionParameters[0]; } /** * {@inheritdoc} */ public function getHost() { $params = $this->getParams(); return $params['host'] ?? parent::getHost(); } /** * {@inheritdoc} */ public function getPort() { $params = $this->getParams(); return $params['port'] ?? parent::getPort(); } /** * {@inheritdoc} */ public function getUsername() { $params = $this->getParams(); return $params['user'] ?? parent::getUsername(); } /** * {@inheritdoc} */ public function getPassword() { $params = $this->getParams(); return $params['password'] ?? parent::getPassword(); } /** * Connects to a given shard. * * @param string|int|null $shardId * * @return bool * * @throws ShardingException */ public function connect($shardId = null) { if ($shardId === null && $this->_conn) { return false; } if ($shardId !== null && $shardId === $this->activeShardId) { return false; } if ($this->getTransactionNestingLevel() > 0) { throw new ShardingException('Cannot switch shard when transaction is active.'); } $activeShardId = $this->activeShardId = (int) $shardId; if (isset($this->activeConnections[$activeShardId])) { $this->_conn = $this->activeConnections[$activeShardId]; return false; } $this->_conn = $this->activeConnections[$activeShardId] = $this->connectTo($activeShardId); if ($this->_eventManager->hasListeners(Events::postConnect)) { $eventArgs = new ConnectionEventArgs($this); $this->_eventManager->dispatchEvent(Events::postConnect, $eventArgs); } return true; } /** * Connects to a specific connection. * * @param string|int $shardId * * @return \Doctrine\DBAL\Driver\Connection */ protected function connectTo($shardId) { $params = $this->getParams(); $driverOptions = $params['driverOptions'] ?? []; $connectionParams = $this->connectionParameters[$shardId]; $user = $connectionParams['user'] ?? null; $password = $connectionParams['password'] ?? null; return $this->_driver->connect($connectionParams, $user, $password, $driverOptions); } /** * @param string|int|null $shardId * * @return bool */ public function isConnected($shardId = null) { if ($shardId === null) { return $this->_conn !== null; } return isset($this->activeConnections[$shardId]); } /** * @return void */ public function close() { $this->_conn = null; $this->activeConnections = []; $this->activeShardId = null; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Sharding/PoolingShardManager.php000066400000000000000000000043401360544566000262540ustar00rootroot00000000000000getParams(); $this->conn = $conn; $this->choser = $params['shardChoser']; } /** * {@inheritDoc} */ public function selectGlobal() { $this->conn->connect(0); $this->currentDistributionValue = null; } /** * {@inheritDoc} */ public function selectShard($distributionValue) { $shardId = $this->choser->pickShard($distributionValue, $this->conn); $this->conn->connect($shardId); $this->currentDistributionValue = $distributionValue; } /** * {@inheritDoc} */ public function getCurrentDistributionValue() { return $this->currentDistributionValue; } /** * {@inheritDoc} */ public function getShards() { $params = $this->conn->getParams(); $shards = []; foreach ($params['shards'] as $shard) { $shards[] = ['id' => $shard['id']]; } return $shards; } /** * {@inheritDoc} * * @throws RuntimeException */ public function queryAll($sql, array $params, array $types) { $shards = $this->getShards(); if (! $shards) { throw new RuntimeException('No shards found.'); } $result = []; $oldDistribution = $this->getCurrentDistributionValue(); foreach ($shards as $shard) { $this->conn->connect($shard['id']); foreach ($this->conn->fetchAll($sql, $params, $types) as $row) { $result[] = $row; } } if ($oldDistribution === null) { $this->selectGlobal(); } else { $this->selectShard($oldDistribution); } return $result; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Sharding/SQLAzure/000077500000000000000000000000001360544566000233245ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Sharding/SQLAzure/SQLAzureFederationsSynchronizer.php000066400000000000000000000207771360544566000323220ustar00rootroot00000000000000shardManager = $shardManager; $this->synchronizer = $sync ?: new SingleDatabaseSynchronizer($conn); } /** * {@inheritdoc} */ public function getCreateSchema(Schema $createSchema) { $sql = []; [$global, $federation] = $this->partitionSchema($createSchema); $globalSql = $this->synchronizer->getCreateSchema($global); if ($globalSql) { $sql[] = "-- Create Root Federation\n" . 'USE FEDERATION ROOT WITH RESET;'; $sql = array_merge($sql, $globalSql); } $federationSql = $this->synchronizer->getCreateSchema($federation); if ($federationSql) { $defaultValue = $this->getFederationTypeDefaultValue(); $sql[] = $this->getCreateFederationStatement(); $sql[] = 'USE FEDERATION ' . $this->shardManager->getFederationName() . ' (' . $this->shardManager->getDistributionKey() . ' = ' . $defaultValue . ') WITH RESET, FILTERING = OFF;'; $sql = array_merge($sql, $federationSql); } return $sql; } /** * {@inheritdoc} */ public function getUpdateSchema(Schema $toSchema, $noDrops = false) { return $this->work($toSchema, static function ($synchronizer, $schema) use ($noDrops) { return $synchronizer->getUpdateSchema($schema, $noDrops); }); } /** * {@inheritdoc} */ public function getDropSchema(Schema $dropSchema) { return $this->work($dropSchema, static function ($synchronizer, $schema) { return $synchronizer->getDropSchema($schema); }); } /** * {@inheritdoc} */ public function createSchema(Schema $createSchema) { $this->processSql($this->getCreateSchema($createSchema)); } /** * {@inheritdoc} */ public function updateSchema(Schema $toSchema, $noDrops = false) { $this->processSql($this->getUpdateSchema($toSchema, $noDrops)); } /** * {@inheritdoc} */ public function dropSchema(Schema $dropSchema) { $this->processSqlSafely($this->getDropSchema($dropSchema)); } /** * {@inheritdoc} */ public function getDropAllSchema() { $this->shardManager->selectGlobal(); $globalSql = $this->synchronizer->getDropAllSchema(); if ($globalSql) { $sql[] = "-- Work on Root Federation\nUSE FEDERATION ROOT WITH RESET;"; $sql = array_merge($sql, $globalSql); } $shards = $this->shardManager->getShards(); foreach ($shards as $shard) { $this->shardManager->selectShard($shard['rangeLow']); $federationSql = $this->synchronizer->getDropAllSchema(); if (! $federationSql) { continue; } $sql[] = '-- Work on Federation ID ' . $shard['id'] . "\n" . 'USE FEDERATION ' . $this->shardManager->getFederationName() . ' (' . $this->shardManager->getDistributionKey() . ' = ' . $shard['rangeLow'] . ') WITH RESET, FILTERING = OFF;'; $sql = array_merge($sql, $federationSql); } $sql[] = 'USE FEDERATION ROOT WITH RESET;'; $sql[] = 'DROP FEDERATION ' . $this->shardManager->getFederationName(); return $sql; } /** * {@inheritdoc} */ public function dropAllSchema() { $this->processSqlSafely($this->getDropAllSchema()); } /** * @return Schema[] */ private function partitionSchema(Schema $schema) { return [ $this->extractSchemaFederation($schema, false), $this->extractSchemaFederation($schema, true), ]; } /** * @param bool $isFederation * * @return Schema * * @throws RuntimeException */ private function extractSchemaFederation(Schema $schema, $isFederation) { $partitionedSchema = clone $schema; foreach ($partitionedSchema->getTables() as $table) { if ($isFederation) { $table->addOption(self::FEDERATION_DISTRIBUTION_NAME, $this->shardManager->getDistributionKey()); } if ($table->hasOption(self::FEDERATION_TABLE_FEDERATED) !== $isFederation) { $partitionedSchema->dropTable($table->getName()); } else { foreach ($table->getForeignKeys() as $fk) { $foreignTable = $schema->getTable($fk->getForeignTableName()); if ($foreignTable->hasOption(self::FEDERATION_TABLE_FEDERATED) !== $isFederation) { throw new RuntimeException('Cannot have foreign key between global/federation.'); } } } } return $partitionedSchema; } /** * Work on the Global/Federation based on currently existing shards and * perform the given operation on the underlying schema synchronizer given * the different partitioned schema instances. * * @return string[] */ private function work(Schema $schema, Closure $operation) { [$global, $federation] = $this->partitionSchema($schema); $sql = []; $this->shardManager->selectGlobal(); $globalSql = $operation($this->synchronizer, $global); if ($globalSql) { $sql[] = "-- Work on Root Federation\nUSE FEDERATION ROOT WITH RESET;"; $sql = array_merge($sql, $globalSql); } $shards = $this->shardManager->getShards(); foreach ($shards as $shard) { $this->shardManager->selectShard($shard['rangeLow']); $federationSql = $operation($this->synchronizer, $federation); if (! $federationSql) { continue; } $sql[] = '-- Work on Federation ID ' . $shard['id'] . "\n" . 'USE FEDERATION ' . $this->shardManager->getFederationName() . ' (' . $this->shardManager->getDistributionKey() . ' = ' . $shard['rangeLow'] . ') WITH RESET, FILTERING = OFF;'; $sql = array_merge($sql, $federationSql); } return $sql; } /** * @return string */ private function getFederationTypeDefaultValue() { $federationType = Type::getType($this->shardManager->getDistributionType()); switch ($federationType->getName()) { case Types::GUID: $defaultValue = '00000000-0000-0000-0000-000000000000'; break; case Types::INTEGER: case Types::SMALLINT: case Types::BIGINT: $defaultValue = '0'; break; default: $defaultValue = ''; break; } return $defaultValue; } /** * @return string */ private function getCreateFederationStatement() { $federationType = Type::getType($this->shardManager->getDistributionType()); $federationTypeSql = $federationType->getSQLDeclaration([], $this->conn->getDatabasePlatform()); return "--Create Federation\n" . 'CREATE FEDERATION ' . $this->shardManager->getFederationName() . ' (' . $this->shardManager->getDistributionKey() . ' ' . $federationTypeSql . ' RANGE)'; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Sharding/SQLAzure/SQLAzureShardManager.php000066400000000000000000000126101360544566000277600ustar00rootroot00000000000000conn = $conn; $params = $conn->getParams(); if (! isset($params['sharding']['federationName'])) { throw ShardingException::missingDefaultFederationName(); } if (! isset($params['sharding']['distributionKey'])) { throw ShardingException::missingDefaultDistributionKey(); } if (! isset($params['sharding']['distributionType'])) { throw ShardingException::missingDistributionType(); } $this->federationName = $params['sharding']['federationName']; $this->distributionKey = $params['sharding']['distributionKey']; $this->distributionType = $params['sharding']['distributionType']; $this->filteringEnabled = (bool) ($params['sharding']['filteringEnabled'] ?? false); } /** * Gets the name of the federation. * * @return string */ public function getFederationName() { return $this->federationName; } /** * Gets the distribution key. * * @return string */ public function getDistributionKey() { return $this->distributionKey; } /** * Gets the Doctrine Type name used for the distribution. * * @return string */ public function getDistributionType() { return $this->distributionType; } /** * Sets Enabled/Disable filtering on the fly. * * @param bool $flag * * @return void */ public function setFilteringEnabled($flag) { $this->filteringEnabled = (bool) $flag; } /** * {@inheritDoc} */ public function selectGlobal() { if ($this->conn->isTransactionActive()) { throw ShardingException::activeTransaction(); } $sql = 'USE FEDERATION ROOT WITH RESET'; $this->conn->exec($sql); $this->currentDistributionValue = null; } /** * {@inheritDoc} */ public function selectShard($distributionValue) { if ($this->conn->isTransactionActive()) { throw ShardingException::activeTransaction(); } $platform = $this->conn->getDatabasePlatform(); $sql = sprintf( 'USE FEDERATION %s (%s = %s) WITH RESET, FILTERING = %s;', $platform->quoteIdentifier($this->federationName), $platform->quoteIdentifier($this->distributionKey), $this->conn->quote($distributionValue), ($this->filteringEnabled ? 'ON' : 'OFF') ); $this->conn->exec($sql); $this->currentDistributionValue = $distributionValue; } /** * {@inheritDoc} */ public function getCurrentDistributionValue() { return $this->currentDistributionValue; } /** * {@inheritDoc} */ public function getShards() { $sql = 'SELECT member_id as id, distribution_name as distribution_key, CAST(range_low AS CHAR) AS rangeLow, CAST(range_high AS CHAR) AS rangeHigh FROM sys.federation_member_distributions d INNER JOIN sys.federations f ON f.federation_id = d.federation_id WHERE f.name = ' . $this->conn->quote($this->federationName); return $this->conn->fetchAll($sql); } /** * {@inheritDoc} */ public function queryAll($sql, array $params = [], array $types = []) { $shards = $this->getShards(); if (! $shards) { throw new RuntimeException('No shards found for ' . $this->federationName); } $result = []; $oldDistribution = $this->getCurrentDistributionValue(); foreach ($shards as $shard) { $this->selectShard($shard['rangeLow']); foreach ($this->conn->fetchAll($sql, $params, $types) as $row) { $result[] = $row; } } if ($oldDistribution === null) { $this->selectGlobal(); } else { $this->selectShard($oldDistribution); } return $result; } /** * Splits Federation at a given distribution value. * * @param mixed $splitDistributionValue * * @return void */ public function splitFederation($splitDistributionValue) { $type = Type::getType($this->distributionType); $sql = 'ALTER FEDERATION ' . $this->getFederationName() . ' ' . 'SPLIT AT (' . $this->getDistributionKey() . ' = ' . $this->conn->quote($splitDistributionValue, $type->getBindingType()) . ')'; $this->conn->exec($sql); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Sharding/SQLAzure/Schema/000077500000000000000000000000001360544566000245245ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Sharding/SQLAzure/Schema/MultiTenantVisitor.php000066400000000000000000000102651360544566000310650ustar00rootroot00000000000000excludedTables = $excludedTables; $this->tenantColumnName = $tenantColumnName; $this->distributionName = $distributionName ?: $tenantColumnName; } /** * {@inheritdoc} */ public function acceptTable(Table $table) { if (in_array($table->getName(), $this->excludedTables)) { return; } $table->addColumn($this->tenantColumnName, $this->tenantColumnType, [ 'default' => "federation_filtering_value('" . $this->distributionName . "')", ]); $clusteredIndex = $this->getClusteredIndex($table); $indexColumns = $clusteredIndex->getColumns(); $indexColumns[] = $this->tenantColumnName; if ($clusteredIndex->isPrimary()) { $table->dropPrimaryKey(); $table->setPrimaryKey($indexColumns); } else { $table->dropIndex($clusteredIndex->getName()); $table->addIndex($indexColumns, $clusteredIndex->getName()); $table->getIndex($clusteredIndex->getName())->addFlag('clustered'); } } /** * @param Table $table * * @return Index * * @throws RuntimeException */ private function getClusteredIndex($table) { foreach ($table->getIndexes() as $index) { if ($index->isPrimary() && ! $index->hasFlag('nonclustered')) { return $index; } if ($index->hasFlag('clustered')) { return $index; } } throw new RuntimeException('No clustered index found on table ' . $table->getName()); } /** * {@inheritdoc} */ public function acceptSchema(Schema $schema) { } /** * {@inheritdoc} */ public function acceptColumn(Table $table, Column $column) { } /** * {@inheritdoc} */ public function acceptForeignKey(Table $localTable, ForeignKeyConstraint $fkConstraint) { } /** * {@inheritdoc} */ public function acceptIndex(Table $table, Index $index) { } /** * {@inheritdoc} */ public function acceptSequence(Sequence $sequence) { } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Sharding/ShardChoser/000077500000000000000000000000001360544566000240635ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Sharding/ShardChoser/MultiTenantShardChoser.php000066400000000000000000000006641360544566000311740ustar00rootroot00000000000000Statement for the given SQL and Connection. * * @param string $sql The SQL of the statement. * @param Connection $conn The connection on which the statement should be executed. */ public function __construct($sql, Connection $conn) { $this->sql = $sql; $this->stmt = $conn->getWrappedConnection()->prepare($sql); $this->conn = $conn; $this->platform = $conn->getDatabasePlatform(); } /** * Binds a parameter value to the statement. * * The value can optionally be bound with a PDO binding type or a DBAL mapping type. * If bound with a DBAL mapping type, the binding type is derived from the mapping * type and the value undergoes the conversion routines of the mapping type before * being bound. * * @param string|int $name The name or position of the parameter. * @param mixed $value The value of the parameter. * @param mixed $type Either a PDO binding type or a DBAL mapping type name or instance. * * @return bool TRUE on success, FALSE on failure. */ public function bindValue($name, $value, $type = ParameterType::STRING) { $this->params[$name] = $value; $this->types[$name] = $type; if ($type !== null) { if (is_string($type)) { $type = Type::getType($type); } if ($type instanceof Type) { $value = $type->convertToDatabaseValue($value, $this->platform); $bindingType = $type->getBindingType(); } else { $bindingType = $type; } return $this->stmt->bindValue($name, $value, $bindingType); } return $this->stmt->bindValue($name, $value); } /** * Binds a parameter to a value by reference. * * Binding a parameter by reference does not support DBAL mapping types. * * @param string|int $name The name or position of the parameter. * @param mixed $var The reference to the variable to bind. * @param int $type The PDO binding type. * @param int|null $length Must be specified when using an OUT bind * so that PHP allocates enough memory to hold the returned value. * * @return bool TRUE on success, FALSE on failure. */ public function bindParam($name, &$var, $type = ParameterType::STRING, $length = null) { $this->params[$name] = $var; $this->types[$name] = $type; return $this->stmt->bindParam($name, $var, $type, $length); } /** * Executes the statement with the currently bound parameters. * * @param mixed[]|null $params * * @return bool TRUE on success, FALSE on failure. * * @throws DBALException */ public function execute($params = null) { if (is_array($params)) { $this->params = $params; } $logger = $this->conn->getConfiguration()->getSQLLogger(); if ($logger) { $logger->startQuery($this->sql, $this->params, $this->types); } try { $stmt = $this->stmt->execute($params); } catch (Throwable $ex) { if ($logger) { $logger->stopQuery(); } throw DBALException::driverExceptionDuringQuery( $this->conn->getDriver(), $ex, $this->sql, $this->conn->resolveParams($this->params, $this->types) ); } if ($logger) { $logger->stopQuery(); } $this->params = []; $this->types = []; return $stmt; } /** * Closes the cursor, freeing the database resources used by this statement. * * @return bool TRUE on success, FALSE on failure. */ public function closeCursor() { return $this->stmt->closeCursor(); } /** * Returns the number of columns in the result set. * * @return int */ public function columnCount() { return $this->stmt->columnCount(); } /** * Fetches the SQLSTATE associated with the last operation on the statement. * * @return string|int|bool */ public function errorCode() { return $this->stmt->errorCode(); } /** * {@inheritDoc} */ public function errorInfo() { return $this->stmt->errorInfo(); } /** * {@inheritdoc} */ public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) { if ($arg2 === null) { return $this->stmt->setFetchMode($fetchMode); } if ($arg3 === null) { return $this->stmt->setFetchMode($fetchMode, $arg2); } return $this->stmt->setFetchMode($fetchMode, $arg2, $arg3); } /** * Required by interface IteratorAggregate. * * {@inheritdoc} */ public function getIterator() { return $this->stmt; } /** * {@inheritdoc} */ public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) { return $this->stmt->fetch($fetchMode); } /** * {@inheritdoc} */ public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) { if ($fetchArgument) { return $this->stmt->fetchAll($fetchMode, $fetchArgument); } return $this->stmt->fetchAll($fetchMode); } /** * {@inheritDoc} */ public function fetchColumn($columnIndex = 0) { return $this->stmt->fetchColumn($columnIndex); } /** * Returns the number of rows affected by the last execution of this statement. * * @return int The number of affected rows. */ public function rowCount() { return $this->stmt->rowCount(); } /** * Gets the wrapped driver statement. * * @return \Doctrine\DBAL\Driver\Statement */ public function getWrappedStatement() { return $this->stmt; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Tools/000077500000000000000000000000001360544566000212175ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Tools/Console/000077500000000000000000000000001360544566000226215ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Tools/Console/Command/000077500000000000000000000000001360544566000241775ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Tools/Console/Command/ImportCommand.php000066400000000000000000000076541360544566000274750ustar00rootroot00000000000000setName('dbal:import') ->setDescription('Import SQL file(s) directly to Database.') ->setDefinition([new InputArgument( 'file', InputArgument::REQUIRED | InputArgument::IS_ARRAY, 'File path(s) of SQL to be executed.' ), ]) ->setHelp(<<getHelper('db')->getConnection(); $fileNames = $input->getArgument('file'); if ($fileNames === null) { return 0; } foreach ((array) $fileNames as $fileName) { $filePath = realpath($fileName); // Phar compatibility. if ($filePath === false) { $filePath = $fileName; } if (! file_exists($filePath)) { throw new InvalidArgumentException( sprintf("SQL file '%s' does not exist.", $filePath) ); } if (! is_readable($filePath)) { throw new InvalidArgumentException( sprintf("SQL file '%s' does not have read permissions.", $filePath) ); } $output->write(sprintf("Processing file '%s'... ", $filePath)); $sql = @file_get_contents($filePath); if ($sql === false) { throw new RuntimeException( sprintf("Unable to read SQL file '%s': %s", $filePath, error_get_last()['message']) ); } if ($conn instanceof PDOConnection) { // PDO Drivers try { $lines = 0; $stmt = $conn->prepare($sql); assert($stmt instanceof PDOStatement); $stmt->execute(); do { // Required due to "MySQL has gone away!" issue $stmt->fetch(); $stmt->closeCursor(); $lines++; } while ($stmt->nextRowset()); $output->write(sprintf('%d statements executed!', $lines) . PHP_EOL); } catch (PDOException $e) { $output->write('error!' . PHP_EOL); throw new RuntimeException($e->getMessage(), $e->getCode(), $e); } } else { // Non-PDO Drivers (ie. OCI8 driver) $stmt = $conn->prepare($sql); $rs = $stmt->execute(); if (! $rs) { $error = $stmt->errorInfo(); $output->write('error!' . PHP_EOL); throw new RuntimeException($error[2], $error[0]); } $output->writeln('OK!' . PHP_EOL); $stmt->closeCursor(); } } return 0; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Tools/Console/Command/ReservedWordsCommand.php000066400000000000000000000137151360544566000310140ustar00rootroot00000000000000 MySQLKeywords::class, 'mysql57' => MySQL57Keywords::class, 'mysql80' => MySQL80Keywords::class, 'sqlserver' => SQLServerKeywords::class, 'sqlserver2005' => SQLServer2005Keywords::class, 'sqlserver2008' => SQLServer2008Keywords::class, 'sqlserver2012' => SQLServer2012Keywords::class, 'sqlite' => SQLiteKeywords::class, 'pgsql' => PostgreSQLKeywords::class, 'pgsql91' => PostgreSQL91Keywords::class, 'pgsql92' => PostgreSQL92Keywords::class, 'oracle' => OracleKeywords::class, 'db2' => DB2Keywords::class, 'sqlanywhere' => SQLAnywhereKeywords::class, 'sqlanywhere11' => SQLAnywhere11Keywords::class, 'sqlanywhere12' => SQLAnywhere12Keywords::class, 'sqlanywhere16' => SQLAnywhere16Keywords::class, ]; /** * If you want to add or replace a keywords list use this command. * * @param string $name * @param string $class * * @return void */ public function setKeywordListClass($name, $class) { $this->keywordListClasses[$name] = $class; } /** * {@inheritdoc} */ protected function configure() { $this ->setName('dbal:reserved-words') ->setDescription('Checks if the current database contains identifiers that are reserved.') ->setDefinition([new InputOption( 'list', 'l', InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Keyword-List name.' ), ]) ->setHelp(<<%command.full_name% If you want to check against specific dialects you can pass them to the command: %command.full_name% -l mysql -l pgsql The following keyword lists are currently shipped with Doctrine: * mysql * mysql57 * mysql80 * pgsql * pgsql92 * sqlite * oracle * sqlserver * sqlserver2005 * sqlserver2008 * sqlserver2012 * sqlanywhere * sqlanywhere11 * sqlanywhere12 * sqlanywhere16 * db2 (Not checked by default) EOT ); } /** * {@inheritdoc} */ protected function execute(InputInterface $input, OutputInterface $output) { /** @var Connection $conn */ $conn = $this->getHelper('db')->getConnection(); $keywordLists = (array) $input->getOption('list'); if (! $keywordLists) { $keywordLists = [ 'mysql', 'mysql57', 'mysql80', 'pgsql', 'pgsql92', 'sqlite', 'oracle', 'sqlserver', 'sqlserver2005', 'sqlserver2008', 'sqlserver2012', 'sqlanywhere', 'sqlanywhere11', 'sqlanywhere12', 'sqlanywhere16', ]; } $keywords = []; foreach ($keywordLists as $keywordList) { if (! isset($this->keywordListClasses[$keywordList])) { throw new InvalidArgumentException( "There exists no keyword list with name '" . $keywordList . "'. " . 'Known lists: ' . implode(', ', array_keys($this->keywordListClasses)) ); } $class = $this->keywordListClasses[$keywordList]; $keywords[] = new $class(); } $output->write('Checking keyword violations for ' . implode(', ', $keywordLists) . '...', true); $schema = $conn->getSchemaManager()->createSchema(); $visitor = new ReservedKeywordsValidator($keywords); $schema->visit($visitor); $violations = $visitor->getViolations(); if (count($violations) !== 0) { $output->write('There are ' . count($violations) . ' reserved keyword violations in your database schema:', true); foreach ($violations as $violation) { $output->write(' - ' . $violation, true); } return 1; } $output->write('No reserved keywords violations have been found!', true); return 0; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Tools/Console/Command/RunSqlCommand.php000066400000000000000000000041741360544566000274410ustar00rootroot00000000000000setName('dbal:run-sql') ->setDescription('Executes arbitrary SQL directly from the command line.') ->setDefinition([ new InputArgument('sql', InputArgument::REQUIRED, 'The SQL statement to execute.'), new InputOption('depth', null, InputOption::VALUE_REQUIRED, 'Dumping depth of result set.', 7), new InputOption('force-fetch', null, InputOption::VALUE_NONE, 'Forces fetching the result.'), ]) ->setHelp(<<getHelper('db')->getConnection(); $sql = $input->getArgument('sql'); if ($sql === null) { throw new RuntimeException("Argument 'SQL' is required in order to execute this command correctly."); } assert(is_string($sql)); $depth = $input->getOption('depth'); if (! is_numeric($depth)) { throw new LogicException("Option 'depth' must contains an integer value"); } if (stripos($sql, 'select') === 0 || $input->getOption('force-fetch')) { $resultSet = $conn->fetchAll($sql); } else { $resultSet = $conn->executeUpdate($sql); } $output->write(Dumper::dump($resultSet, (int) $depth)); return 0; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Tools/Console/ConsoleRunner.php000066400000000000000000000042341360544566000261310ustar00rootroot00000000000000 new ConnectionHelper($connection), ]); } /** * Runs console with the given helperset. * * @param Command[] $commands * * @return void */ public static function run(HelperSet $helperSet, $commands = []) { $cli = new Application('Doctrine Command Line Interface', Version::VERSION); $cli->setCatchExceptions(true); $cli->setHelperSet($helperSet); self::addCommands($cli); $cli->addCommands($commands); $cli->run(); } /** * @return void */ public static function addCommands(Application $cli) { $cli->addCommands([ new RunSqlCommand(), new ImportCommand(), new ReservedWordsCommand(), ]); } /** * Prints the instructions to create a configuration file */ public static function printCliConfigTemplate() { echo <<<'HELP' You are missing a "cli-config.php" or "config/cli-config.php" file in your project, which is required to get the Doctrine-DBAL Console working. You can use the following sample as a template: _connection = $connection; } /** * Retrieves the Doctrine database Connection. * * @return Connection */ public function getConnection() { return $this->_connection; } /** * {@inheritdoc} */ public function getName() { return 'connection'; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Tools/Dumper.php000066400000000000000000000107151360544566000231700ustar00rootroot00000000000000toArray(); } if ($maxDepth === 0) { return is_object($var) ? get_class($var) : (is_array($var) ? 'Array(' . count($var) . ')' : $var); } if (is_array($var)) { $return = []; foreach ($var as $k => $v) { $return[$k] = self::export($v, $maxDepth - 1); } return $return; } if (! $isObj) { return $var; } $return = new stdClass(); if ($var instanceof DateTimeInterface) { $return->__CLASS__ = get_class($var); $return->date = $var->format('c'); $return->timezone = $var->getTimezone()->getName(); return $return; } $return->__CLASS__ = self::getClass($var); if ($var instanceof Proxy) { $return->__IS_PROXY__ = true; $return->__PROXY_INITIALIZED__ = $var->__isInitialized(); } if ($var instanceof ArrayObject || $var instanceof ArrayIterator) { $return->__STORAGE__ = self::export($var->getArrayCopy(), $maxDepth - 1); } return self::fillReturnWithClassAttributes($var, $return, $maxDepth); } /** * Fill the $return variable with class attributes * Based on obj2array function from {@see https://secure.php.net/manual/en/function.get-object-vars.php#47075} * * @param object $var * * @return mixed */ private static function fillReturnWithClassAttributes($var, stdClass $return, int $maxDepth) { $clone = (array) $var; foreach (array_keys($clone) as $key) { $aux = explode("\0", $key); $name = end($aux); if ($aux[0] === '') { $name .= ':' . ($aux[1] === '*' ? 'protected' : $aux[1] . ':private'); } $return->$name = self::export($clone[$key], $maxDepth - 1); } return $return; } /** * @param object $object */ private static function getClass($object) : string { $class = get_class($object); if (! class_exists(Proxy::class)) { return $class; } $pos = strrpos($class, '\\' . Proxy::MARKER . '\\'); if ($pos === false) { return $class; } return substr($class, $pos + strlen(Proxy::MARKER) + 2); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/TransactionIsolationLevel.php000066400000000000000000000010721360544566000257670ustar00rootroot00000000000000getClobTypeDeclarationSQL($fieldDeclaration); } /** * {@inheritdoc} */ public function convertToDatabaseValue($value, AbstractPlatform $platform) { // @todo 3.0 - $value === null check to save real NULL in database return serialize($value); } /** * {@inheritdoc} */ public function convertToPHPValue($value, AbstractPlatform $platform) { if ($value === null) { return null; } $value = is_resource($value) ? stream_get_contents($value) : $value; set_error_handler(function (int $code, string $message) : bool { throw ConversionException::conversionFailedUnserialization($this->getName(), $message); }); try { return unserialize($value); } finally { restore_error_handler(); } } /** * {@inheritdoc} */ public function getName() { return Types::ARRAY; } /** * {@inheritdoc} */ public function requiresSQLCommentHint(AbstractPlatform $platform) { return true; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Types/BigIntType.php000066400000000000000000000015551360544566000237600ustar00rootroot00000000000000getBigIntTypeDeclarationSQL($fieldDeclaration); } /** * {@inheritdoc} */ public function getBindingType() { return ParameterType::STRING; } /** * {@inheritdoc} */ public function convertToPHPValue($value, AbstractPlatform $platform) { return $value === null ? null : (string) $value; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Types/BinaryType.php000066400000000000000000000025261360544566000240270ustar00rootroot00000000000000getBinaryTypeDeclarationSQL($fieldDeclaration); } /** * {@inheritdoc} */ public function convertToPHPValue($value, AbstractPlatform $platform) { if ($value === null) { return null; } if (is_string($value)) { $fp = fopen('php://temp', 'rb+'); assert(is_resource($fp)); fwrite($fp, $value); fseek($fp, 0); $value = $fp; } if (! is_resource($value)) { throw ConversionException::conversionFailed($value, Types::BINARY); } return $value; } /** * {@inheritdoc} */ public function getName() { return Types::BINARY; } /** * {@inheritdoc} */ public function getBindingType() { return ParameterType::BINARY; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Types/BlobType.php000066400000000000000000000025101360544566000234520ustar00rootroot00000000000000getBlobTypeDeclarationSQL($fieldDeclaration); } /** * {@inheritdoc} */ public function convertToPHPValue($value, AbstractPlatform $platform) { if ($value === null) { return null; } if (is_string($value)) { $fp = fopen('php://temp', 'rb+'); assert(is_resource($fp)); fwrite($fp, $value); fseek($fp, 0); $value = $fp; } if (! is_resource($value)) { throw ConversionException::conversionFailed($value, Types::BLOB); } return $value; } /** * {@inheritdoc} */ public function getName() { return Types::BLOB; } /** * {@inheritdoc} */ public function getBindingType() { return ParameterType::LARGE_OBJECT; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Types/BooleanType.php000066400000000000000000000020161360544566000241540ustar00rootroot00000000000000getBooleanTypeDeclarationSQL($fieldDeclaration); } /** * {@inheritdoc} */ public function convertToDatabaseValue($value, AbstractPlatform $platform) { return $platform->convertBooleansToDatabaseValue($value); } /** * {@inheritdoc} */ public function convertToPHPValue($value, AbstractPlatform $platform) { return $platform->convertFromBoolean($value); } /** * {@inheritdoc} */ public function getName() { return Types::BOOLEAN; } /** * {@inheritdoc} */ public function getBindingType() { return ParameterType::BOOLEAN; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Types/ConversionException.php000066400000000000000000000064211360544566000257430ustar00rootroot00000000000000 32 ? substr($value, 0, 20) . '...' : $value; return new self('Could not convert database value "' . $value . '" to Doctrine Type ' . $toType); } /** * Thrown when a Database to Doctrine Type Conversion fails and we can make a statement * about the expected format. * * @param string $value * @param string $toType * @param string $expectedFormat * * @return \Doctrine\DBAL\Types\ConversionException */ public static function conversionFailedFormat($value, $toType, $expectedFormat, ?Throwable $previous = null) { $value = strlen($value) > 32 ? substr($value, 0, 20) . '...' : $value; return new self( 'Could not convert database value "' . $value . '" to Doctrine Type ' . $toType . '. Expected format: ' . $expectedFormat, 0, $previous ); } /** * Thrown when the PHP value passed to the converter was not of the expected type. * * @param mixed $value * @param string $toType * @param string[] $possibleTypes * * @return \Doctrine\DBAL\Types\ConversionException */ public static function conversionFailedInvalidType($value, $toType, array $possibleTypes) { $actualType = is_object($value) ? get_class($value) : gettype($value); if (is_scalar($value)) { return new self(sprintf( "Could not convert PHP value '%s' of type '%s' to type '%s'. Expected one of the following types: %s", $value, $actualType, $toType, implode(', ', $possibleTypes) )); } return new self(sprintf( "Could not convert PHP value of type '%s' to type '%s'. Expected one of the following types: %s", $actualType, $toType, implode(', ', $possibleTypes) )); } public static function conversionFailedSerialization($value, $format, $error) { $actualType = is_object($value) ? get_class($value) : gettype($value); return new self(sprintf( "Could not convert PHP type '%s' to '%s', as an '%s' error was triggered by the serialization", $actualType, $format, $error )); } public static function conversionFailedUnserialization(string $format, string $error) : self { return new self(sprintf( "Could not convert database value to '%s' as an error was triggered by the unserialization: '%s'", $format, $error )); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Types/DateImmutableType.php000066400000000000000000000030131360544566000253100ustar00rootroot00000000000000format($platform->getDateFormatString()); } throw ConversionException::conversionFailedInvalidType( $value, $this->getName(), ['null', DateTimeImmutable::class] ); } /** * {@inheritdoc} */ public function convertToPHPValue($value, AbstractPlatform $platform) { if ($value === null || $value instanceof DateTimeImmutable) { return $value; } $dateTime = DateTimeImmutable::createFromFormat('!' . $platform->getDateFormatString(), $value); if (! $dateTime) { throw ConversionException::conversionFailedFormat( $value, $this->getName(), $platform->getDateFormatString() ); } return $dateTime; } /** * {@inheritdoc} */ public function requiresSQLCommentHint(AbstractPlatform $platform) { return true; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Types/DateIntervalType.php000066400000000000000000000037341360544566000251670ustar00rootroot00000000000000getVarcharTypeDeclarationSQL($fieldDeclaration); } /** * {@inheritdoc} */ public function convertToDatabaseValue($value, AbstractPlatform $platform) { if ($value === null) { return null; } if ($value instanceof DateInterval) { return $value->format(self::FORMAT); } throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['null', 'DateInterval']); } /** * {@inheritdoc} */ public function convertToPHPValue($value, AbstractPlatform $platform) { if ($value === null || $value instanceof DateInterval) { return $value; } $negative = false; if (isset($value[0]) && ($value[0] === '+' || $value[0] === '-')) { $negative = $value[0] === '-'; $value = substr($value, 1); } try { $interval = new DateInterval($value); if ($negative) { $interval->invert = 1; } return $interval; } catch (Throwable $exception) { throw ConversionException::conversionFailedFormat($value, $this->getName(), self::FORMAT, $exception); } } /** * {@inheritdoc} */ public function requiresSQLCommentHint(AbstractPlatform $platform) { return true; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Types/DateTimeImmutableType.php000066400000000000000000000032421360544566000261330ustar00rootroot00000000000000format($platform->getDateTimeFormatString()); } throw ConversionException::conversionFailedInvalidType( $value, $this->getName(), ['null', DateTimeImmutable::class] ); } /** * {@inheritdoc} */ public function convertToPHPValue($value, AbstractPlatform $platform) { if ($value === null || $value instanceof DateTimeImmutable) { return $value; } $dateTime = DateTimeImmutable::createFromFormat($platform->getDateTimeFormatString(), $value); if (! $dateTime) { $dateTime = date_create_immutable($value); } if (! $dateTime) { throw ConversionException::conversionFailedFormat( $value, $this->getName(), $platform->getDateTimeFormatString() ); } return $dateTime; } /** * {@inheritdoc} */ public function requiresSQLCommentHint(AbstractPlatform $platform) { return true; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Types/DateTimeType.php000066400000000000000000000031661360544566000243000ustar00rootroot00000000000000getDateTimeTypeDeclarationSQL($fieldDeclaration); } /** * {@inheritdoc} */ public function convertToDatabaseValue($value, AbstractPlatform $platform) { if ($value === null) { return $value; } if ($value instanceof DateTimeInterface) { return $value->format($platform->getDateTimeFormatString()); } throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['null', 'DateTime']); } /** * {@inheritdoc} */ public function convertToPHPValue($value, AbstractPlatform $platform) { if ($value === null || $value instanceof DateTimeInterface) { return $value; } $val = DateTime::createFromFormat($platform->getDateTimeFormatString(), $value); if (! $val) { $val = date_create($value); } if (! $val) { throw ConversionException::conversionFailedFormat($value, $this->getName(), $platform->getDateTimeFormatString()); } return $val; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Types/DateTimeTzImmutableType.php000066400000000000000000000030571360544566000264550ustar00rootroot00000000000000format($platform->getDateTimeTzFormatString()); } throw ConversionException::conversionFailedInvalidType( $value, $this->getName(), ['null', DateTimeImmutable::class] ); } /** * {@inheritdoc} */ public function convertToPHPValue($value, AbstractPlatform $platform) { if ($value === null || $value instanceof DateTimeImmutable) { return $value; } $dateTime = DateTimeImmutable::createFromFormat($platform->getDateTimeTzFormatString(), $value); if (! $dateTime) { throw ConversionException::conversionFailedFormat( $value, $this->getName(), $platform->getDateTimeTzFormatString() ); } return $dateTime; } /** * {@inheritdoc} */ public function requiresSQLCommentHint(AbstractPlatform $platform) { return true; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Types/DateTimeTzType.php000066400000000000000000000045171360544566000246170ustar00rootroot00000000000000getDateTimeTzTypeDeclarationSQL($fieldDeclaration); } /** * {@inheritdoc} */ public function convertToDatabaseValue($value, AbstractPlatform $platform) { if ($value === null) { return $value; } if ($value instanceof DateTimeInterface) { return $value->format($platform->getDateTimeTzFormatString()); } throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['null', 'DateTime']); } /** * {@inheritdoc} */ public function convertToPHPValue($value, AbstractPlatform $platform) { if ($value === null || $value instanceof DateTimeInterface) { return $value; } $val = DateTime::createFromFormat($platform->getDateTimeTzFormatString(), $value); if (! $val) { throw ConversionException::conversionFailedFormat($value, $this->getName(), $platform->getDateTimeTzFormatString()); } return $val; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Types/DateType.php000066400000000000000000000027141360544566000234570ustar00rootroot00000000000000getDateTypeDeclarationSQL($fieldDeclaration); } /** * {@inheritdoc} */ public function convertToDatabaseValue($value, AbstractPlatform $platform) { if ($value === null) { return $value; } if ($value instanceof DateTimeInterface) { return $value->format($platform->getDateFormatString()); } throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['null', 'DateTime']); } /** * {@inheritdoc} */ public function convertToPHPValue($value, AbstractPlatform $platform) { if ($value === null || $value instanceof DateTimeInterface) { return $value; } $val = DateTime::createFromFormat('!' . $platform->getDateFormatString(), $value); if (! $val) { throw ConversionException::conversionFailedFormat($value, $this->getName(), $platform->getDateFormatString()); } return $val; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Types/DecimalType.php000066400000000000000000000012141360544566000241320ustar00rootroot00000000000000getDecimalTypeDeclarationSQL($fieldDeclaration); } /** * {@inheritdoc} */ public function convertToPHPValue($value, AbstractPlatform $platform) { return $value; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Types/FloatType.php000066400000000000000000000011511360544566000236410ustar00rootroot00000000000000getFloatDeclarationSQL($fieldDeclaration); } /** * {@inheritdoc} */ public function convertToPHPValue($value, AbstractPlatform $platform) { return $value === null ? null : (float) $value; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Types/GuidType.php000066400000000000000000000012771360544566000234750ustar00rootroot00000000000000getGuidTypeDeclarationSQL($fieldDeclaration); } /** * {@inheritdoc} */ public function getName() { return Types::GUID; } /** * {@inheritdoc} */ public function requiresSQLCommentHint(AbstractPlatform $platform) { return ! $platform->hasNativeGuidType(); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Types/IntegerType.php000066400000000000000000000015501360544566000241740ustar00rootroot00000000000000getIntegerTypeDeclarationSQL($fieldDeclaration); } /** * {@inheritdoc} */ public function convertToPHPValue($value, AbstractPlatform $platform) { return $value === null ? null : (int) $value; } /** * {@inheritdoc} */ public function getBindingType() { return ParameterType::INTEGER; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Types/JsonArrayType.php000066400000000000000000000016021360544566000245050ustar00rootroot00000000000000getJsonTypeDeclarationSQL($fieldDeclaration); } /** * {@inheritdoc} */ public function convertToDatabaseValue($value, AbstractPlatform $platform) { if ($value === null) { return null; } $encoded = json_encode($value); if (json_last_error() !== JSON_ERROR_NONE) { throw ConversionException::conversionFailedSerialization($value, 'json', json_last_error_msg()); } return $encoded; } /** * {@inheritdoc} */ public function convertToPHPValue($value, AbstractPlatform $platform) { if ($value === null || $value === '') { return null; } if (is_resource($value)) { $value = stream_get_contents($value); } $val = json_decode($value, true); if (json_last_error() !== JSON_ERROR_NONE) { throw ConversionException::conversionFailed($value, $this->getName()); } return $val; } /** * {@inheritdoc} */ public function getName() { return Types::JSON; } /** * {@inheritdoc} */ public function requiresSQLCommentHint(AbstractPlatform $platform) { return ! $platform->hasNativeJsonType(); } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Types/ObjectType.php000066400000000000000000000030301360544566000240000ustar00rootroot00000000000000getClobTypeDeclarationSQL($fieldDeclaration); } /** * {@inheritdoc} */ public function convertToDatabaseValue($value, AbstractPlatform $platform) { return serialize($value); } /** * {@inheritdoc} */ public function convertToPHPValue($value, AbstractPlatform $platform) { if ($value === null) { return null; } $value = is_resource($value) ? stream_get_contents($value) : $value; set_error_handler(function (int $code, string $message) : bool { throw ConversionException::conversionFailedUnserialization($this->getName(), $message); }); try { return unserialize($value); } finally { restore_error_handler(); } } /** * {@inheritdoc} */ public function getName() { return Types::OBJECT; } /** * {@inheritdoc} */ public function requiresSQLCommentHint(AbstractPlatform $platform) { return true; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Types/PhpDateTimeMappingType.php000066400000000000000000000002671360544566000262630ustar00rootroot00000000000000getClobTypeDeclarationSQL($fieldDeclaration); } /** * {@inheritdoc} */ public function convertToDatabaseValue($value, AbstractPlatform $platform) { if (! $value) { return null; } return implode(',', $value); } /** * {@inheritdoc} */ public function convertToPHPValue($value, AbstractPlatform $platform) { if ($value === null) { return []; } $value = is_resource($value) ? stream_get_contents($value) : $value; return explode(',', $value); } /** * {@inheritdoc} */ public function getName() { return Types::SIMPLE_ARRAY; } /** * {@inheritdoc} */ public function requiresSQLCommentHint(AbstractPlatform $platform) { return true; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Types/SmallIntType.php000066400000000000000000000015641360544566000243270ustar00rootroot00000000000000getSmallIntTypeDeclarationSQL($fieldDeclaration); } /** * {@inheritdoc} */ public function convertToPHPValue($value, AbstractPlatform $platform) { return $value === null ? null : (int) $value; } /** * {@inheritdoc} */ public function getBindingType() { return ParameterType::INTEGER; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Types/StringType.php000066400000000000000000000012371360544566000240470ustar00rootroot00000000000000getVarcharTypeDeclarationSQL($fieldDeclaration); } /** * {@inheritdoc} */ public function getDefaultLength(AbstractPlatform $platform) { return $platform->getVarcharDefaultLength(); } /** * {@inheritdoc} */ public function getName() { return Types::STRING; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Types/TextType.php000066400000000000000000000013601360544566000235220ustar00rootroot00000000000000getClobTypeDeclarationSQL($fieldDeclaration); } /** * {@inheritdoc} */ public function convertToPHPValue($value, AbstractPlatform $platform) { return is_resource($value) ? stream_get_contents($value) : $value; } /** * {@inheritdoc} */ public function getName() { return Types::TEXT; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Types/TimeImmutableType.php000066400000000000000000000030131360544566000253310ustar00rootroot00000000000000format($platform->getTimeFormatString()); } throw ConversionException::conversionFailedInvalidType( $value, $this->getName(), ['null', DateTimeImmutable::class] ); } /** * {@inheritdoc} */ public function convertToPHPValue($value, AbstractPlatform $platform) { if ($value === null || $value instanceof DateTimeImmutable) { return $value; } $dateTime = DateTimeImmutable::createFromFormat('!' . $platform->getTimeFormatString(), $value); if (! $dateTime) { throw ConversionException::conversionFailedFormat( $value, $this->getName(), $platform->getTimeFormatString() ); } return $dateTime; } /** * {@inheritdoc} */ public function requiresSQLCommentHint(AbstractPlatform $platform) { return true; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Types/TimeType.php000066400000000000000000000027201360544566000234750ustar00rootroot00000000000000getTimeTypeDeclarationSQL($fieldDeclaration); } /** * {@inheritdoc} */ public function convertToDatabaseValue($value, AbstractPlatform $platform) { if ($value === null) { return $value; } if ($value instanceof DateTimeInterface) { return $value->format($platform->getTimeFormatString()); } throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['null', 'DateTime']); } /** * {@inheritdoc} */ public function convertToPHPValue($value, AbstractPlatform $platform) { if ($value === null || $value instanceof DateTimeInterface) { return $value; } $val = DateTime::createFromFormat('!' . $platform->getTimeFormatString(), $value); if (! $val) { throw ConversionException::conversionFailedFormat($value, $this->getName(), $platform->getTimeFormatString()); } return $val; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Types/Type.php000066400000000000000000000266761360544566000226760ustar00rootroot00000000000000 ArrayType::class, Types::BIGINT => BigIntType::class, Types::BINARY => BinaryType::class, Types::BLOB => BlobType::class, Types::BOOLEAN => BooleanType::class, Types::DATE_MUTABLE => DateType::class, Types::DATE_IMMUTABLE => DateImmutableType::class, Types::DATEINTERVAL => DateIntervalType::class, Types::DATETIME_MUTABLE => DateTimeType::class, Types::DATETIME_IMMUTABLE => DateTimeImmutableType::class, Types::DATETIMETZ_MUTABLE => DateTimeTzType::class, Types::DATETIMETZ_IMMUTABLE => DateTimeTzImmutableType::class, Types::DECIMAL => DecimalType::class, Types::FLOAT => FloatType::class, Types::GUID => GuidType::class, Types::INTEGER => IntegerType::class, Types::JSON => JsonType::class, Types::JSON_ARRAY => JsonArrayType::class, Types::OBJECT => ObjectType::class, Types::SIMPLE_ARRAY => SimpleArrayType::class, Types::SMALLINT => SmallIntType::class, Types::STRING => StringType::class, Types::TEXT => TextType::class, Types::TIME_MUTABLE => TimeType::class, Types::TIME_IMMUTABLE => TimeImmutableType::class, ]; /** @var TypeRegistry|null */ private static $typeRegistry; /** * @internal Do not instantiate directly - use {@see Type::addType()} method instead. */ final public function __construct() { } /** * Converts a value from its PHP representation to its database representation * of this type. * * @param mixed $value The value to convert. * @param AbstractPlatform $platform The currently used database platform. * * @return mixed The database representation of the value. */ public function convertToDatabaseValue($value, AbstractPlatform $platform) { return $value; } /** * Converts a value from its database representation to its PHP representation * of this type. * * @param mixed $value The value to convert. * @param AbstractPlatform $platform The currently used database platform. * * @return mixed The PHP representation of the value. */ public function convertToPHPValue($value, AbstractPlatform $platform) { return $value; } /** * Gets the default length of this type. * * @deprecated Rely on information provided by the platform instead. * * @return int|null */ public function getDefaultLength(AbstractPlatform $platform) { return null; } /** * Gets the SQL declaration snippet for a field of this type. * * @param mixed[] $fieldDeclaration The field declaration. * @param AbstractPlatform $platform The currently used database platform. * * @return string */ abstract public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform); /** * Gets the name of this type. * * @return string * * @todo Needed? */ abstract public function getName(); /** * @internal This method is only to be used within DBAL for forward compatibility purposes. Do not use directly. */ final public static function getTypeRegistry() : TypeRegistry { if (self::$typeRegistry === null) { self::$typeRegistry = self::createTypeRegistry(); } return self::$typeRegistry; } private static function createTypeRegistry() : TypeRegistry { $registry = new TypeRegistry(); foreach (self::BUILTIN_TYPES_MAP as $name => $class) { $registry->register($name, new $class()); } return $registry; } /** * Factory method to create type instances. * Type instances are implemented as flyweights. * * @param string $name The name of the type (as returned by getName()). * * @return \Doctrine\DBAL\Types\Type * * @throws DBALException */ public static function getType($name) { return self::getTypeRegistry()->get($name); } /** * Adds a custom type to the type map. * * @param string $name The name of the type. This should correspond to what getName() returns. * @param string $className The class name of the custom type. * * @return void * * @throws DBALException */ public static function addType($name, $className) { self::getTypeRegistry()->register($name, new $className()); } /** * Checks if exists support for a type. * * @param string $name The name of the type. * * @return bool TRUE if type is supported; FALSE otherwise. */ public static function hasType($name) { return self::getTypeRegistry()->has($name); } /** * Overrides an already defined type to use a different implementation. * * @param string $name * @param string $className * * @return void * * @throws DBALException */ public static function overrideType($name, $className) { self::getTypeRegistry()->override($name, new $className()); } /** * Gets the (preferred) binding type for values of this type that * can be used when binding parameters to prepared statements. * * This method should return one of the {@link \Doctrine\DBAL\ParameterType} constants. * * @return int */ public function getBindingType() { return ParameterType::STRING; } /** * Gets the types array map which holds all registered types and the corresponding * type class * * @return string[] */ public static function getTypesMap() { return array_map( static function (Type $type) : string { return get_class($type); }, self::getTypeRegistry()->getMap() ); } /** * @deprecated Relying on string representation is discouraged and will be removed in DBAL 3.0. * * @return string */ public function __toString() { $type = static::class; $position = strrpos($type, '\\'); if ($position !== false) { $type = substr($type, $position); } return str_replace('Type', '', $type); } /** * Does working with this column require SQL conversion functions? * * This is a metadata function that is required for example in the ORM. * Usage of {@link convertToDatabaseValueSQL} and * {@link convertToPHPValueSQL} works for any type and mostly * does nothing. This method can additionally be used for optimization purposes. * * @return bool */ public function canRequireSQLConversion() { return false; } /** * Modifies the SQL expression (identifier, parameter) to convert to a database value. * * @param string $sqlExpr * * @return string */ public function convertToDatabaseValueSQL($sqlExpr, AbstractPlatform $platform) { return $sqlExpr; } /** * Modifies the SQL expression (identifier, parameter) to convert to a PHP value. * * @param string $sqlExpr * @param AbstractPlatform $platform * * @return string */ public function convertToPHPValueSQL($sqlExpr, $platform) { return $sqlExpr; } /** * Gets an array of database types that map to this Doctrine type. * * @return string[] */ public function getMappedDatabaseTypes(AbstractPlatform $platform) { return []; } /** * If this Doctrine Type maps to an already mapped database type, * reverse schema engineering can't tell them apart. You need to mark * one of those types as commented, which will have Doctrine use an SQL * comment to typehint the actual Doctrine Type. * * @return bool */ public function requiresSQLCommentHint(AbstractPlatform $platform) { return false; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Types/TypeRegistry.php000066400000000000000000000054161360544566000244140ustar00rootroot00000000000000 Map of type names and their corresponding flyweight objects. */ private $instances = []; /** * Finds a type by the given name. * * @throws DBALException */ public function get(string $name) : Type { if (! isset($this->instances[$name])) { throw DBALException::unknownColumnType($name); } return $this->instances[$name]; } /** * Finds a name for the given type. * * @throws DBALException */ public function lookupName(Type $type) : string { $name = $this->findTypeName($type); if ($name === null) { throw DBALException::typeNotRegistered($type); } return $name; } /** * Checks if there is a type of the given name. */ public function has(string $name) : bool { return isset($this->instances[$name]); } /** * Registers a custom type to the type map. * * @throws DBALException */ public function register(string $name, Type $type) : void { if (isset($this->instances[$name])) { throw DBALException::typeExists($name); } if ($this->findTypeName($type) !== null) { throw DBALException::typeAlreadyRegistered($type); } $this->instances[$name] = $type; } /** * Overrides an already defined type to use a different implementation. * * @throws DBALException */ public function override(string $name, Type $type) : void { if (! isset($this->instances[$name])) { throw DBALException::typeNotFound($name); } if (! in_array($this->findTypeName($type), [$name, null], true)) { throw DBALException::typeAlreadyRegistered($type); } $this->instances[$name] = $type; } /** * Gets the map of all registered types and their corresponding type instances. * * @internal * * @return array */ public function getMap() : array { return $this->instances; } private function findTypeName(Type $type) : ?string { $name = array_search($type, $this->instances, true); if ($name === false) { return null; } return $name; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Types/Types.php000066400000000000000000000030511360544566000230370ustar00rootroot00000000000000format($platform->getDateTimeFormatString()); } throw ConversionException::conversionFailedInvalidType( $value, $this->getName(), ['null', DateTimeImmutable::class] ); } /** * {@inheritdoc} */ public function convertToPHPValue($value, AbstractPlatform $platform) { if ($value === null || $value instanceof DateTimeImmutable) { return $value; } $dateTime = date_create_immutable($value); if (! $dateTime) { throw ConversionException::conversionFailed($value, $this->getName()); } return $dateTime; } /** * {@inheritdoc} */ public function requiresSQLCommentHint(AbstractPlatform $platform) { return true; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Types/VarDateTimeType.php000066400000000000000000000015741360544566000247520ustar00rootroot00000000000000 0 it is necessary to use this type. */ class VarDateTimeType extends DateTimeType { /** * {@inheritdoc} */ public function convertToPHPValue($value, AbstractPlatform $platform) { if ($value === null || $value instanceof DateTime) { return $value; } $val = date_create($value); if (! $val) { throw ConversionException::conversionFailed($value, $this->getName()); } return $val; } } php-doctrine-dbal-2.10.1/lib/Doctrine/DBAL/Version.php000066400000000000000000000014161360544566000222570ustar00rootroot00000000000000 bin lib tests */lib/* */lib/* */tests/* */tests/* lib/Doctrine/DBAL/Events.php tests/Doctrine/Tests/DBAL/Tools/TestAsset/* lib/Doctrine/DBAL/Platforms/AbstractPlatform.php lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php tests/Doctrine/Tests/DBAL/Platforms/AbstractPlatformTestCase.php lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvStatement.php lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvStatement.php tests/Doctrine/Tests/DBAL/Platforms/OraclePlatformTest.php tests/Doctrine/Tests/DBAL/SQLParserUtilsTest.php lib/Doctrine/DBAL/Schema/Comparator.php lib/Doctrine/DBAL/Types/ArrayType.php lib/Doctrine/DBAL/Types/ObjectType.php tests/Doctrine/Tests/DBAL/Driver/Mysqli/MysqliConnectionTest.php php-doctrine-dbal-2.10.1/phpstan.neon.dist000066400000000000000000000100571360544566000204030ustar00rootroot00000000000000parameters: level: 7 paths: - %currentWorkingDirectory%/lib autoload_files: - %currentWorkingDirectory%/tests/phpstan-polyfill.php reportUnmatchedIgnoredErrors: false ignoreErrors: # extension not available - '~^(Used )?(Function|Constant) sasql_\S+ not found\.\z~i' # removing it would be BC break - '~^Constructor of class Doctrine\\DBAL\\Schema\\Table has an unused parameter \$idGeneratorType\.\z~' # declaring $tableName in AbstractSchemaManager::_getPortableTableIndexesList() non-optional will be a BC break - '~^Parameter #2 \$table of class Doctrine\\DBAL\\Event\\SchemaIndexDefinitionEventArgs constructor expects string, string\|null given\.\z~' # changing these would be a BC break, to be done in next major - "~^Casting to bool something that's already bool.~" - "~^Casting to int something that's already int.~" - '~^Method Doctrine\\DBAL\\Driver\\IBMDB2\\DB2Connection::exec\(\) should return int but returns bool\.\z~' - '~^Method Doctrine\\DBAL\\Query\\QueryBuilder::execute\(\) should return Doctrine\\DBAL\\Driver\\Statement\|int but returns Doctrine\\DBAL\\Driver\\ResultStatement\.\z~' - '~^Property Doctrine\\DBAL\\Schema\\Table::\$_primaryKeyName \(string\) does not accept (default value of type )?false\.\z~' - '~^Property Doctrine\\DBAL\\Schema\\Schema::\$_schemaConfig \(Doctrine\\DBAL\\Schema\\SchemaConfig\) does not accept default value of type false\.\z~' - '~^Method Doctrine\\DBAL\\Schema\\ForeignKeyConstraint::onEvent\(\) should return string\|null but returns false\.\z~' - '~^Method Doctrine\\DBAL\\Schema\\(Oracle|PostgreSql|SQLServer)SchemaManager::_getPortableTableDefinition\(\) should return array but returns string\.\z~' - '~^Method Doctrine\\DBAL\\Platforms\\(|SQLAnywhere|Sqlite)Platform::_getTransactionIsolationLevelSQL\(\) should return string but returns int\.\z~' - '~^Method Doctrine\\DBAL\\Driver\\OCI8\\OCI8Connection::lastInsertId\(\) should return string but returns (int|false)\.\z~' - '~^Method Doctrine\\DBAL\\Driver\\SQLSrv\\SQLSrvConnection::errorCode\(\) should return string\|null but returns false\.\z~' # https://bugs.php.net/bug.php?id=78126 - '~^Call to an undefined method Doctrine\\DBAL\\Driver\\PDOConnection::sqliteCreateFunction\(\)\.\z~' # https://github.com/phpstan/phpstan/issues/1847 - '~^Parameter #2 \$registeredAliases of static method Doctrine\\DBAL\\Query\\QueryException::unknownAlias\(\) expects array, array given\.\z~' - '~^Parameter #2 \$registeredAliases of static method Doctrine\\DBAL\\Query\\QueryException::nonUniqueAlias\(\) expects array, array given\.\z~' # PHPStan is too strict about preg_replace(): https://phpstan.org/r/993dc99f-0d43-4b51-868b-d01f982c1463 - '~^Method Doctrine\\DBAL\\Platforms\\AbstractPlatform::escapeStringForLike\(\) should return string but returns string|null\.\z~' # legacy variadic-like signature - '~^Method Doctrine\\DBAL(\\.*)?Connection::query\(\) invoked with \d+ parameters?, 0 required\.\z~' # some drivers actually do accept 2nd parameter... - '~^Method Doctrine\\DBAL\\Platforms\\AbstractPlatform::getListTableForeignKeysSQL\(\) invoked with \d+ parameters, 1 required\.\z~' # legacy remnants from doctrine/common - '~^Class Doctrine\\Common\\(Collections\\Collection|Persistence\\Proxy) not found\.\z~' - '~^.+ on an unknown class Doctrine\\Common\\(Collections\\Collection|Persistence\\Proxy)\.\z~' # inheritance variance inference issue - '~^Method Doctrine\\DBAL\\Driver\\PDOConnection::\w+\(\) should return Doctrine\\DBAL\\Driver\\Statement but returns PDOStatement\.\z~' # may not exist when pdo_sqlsrv is not loaded but PDO is - '~^Access to undefined constant PDO::SQLSRV_ENCODING_BINARY\.\z~' # weird class name, represented in stubs as OCI_(Lob|Collection) - '~unknown class OCI-(Lob|Collection)~' php-doctrine-dbal-2.10.1/phpunit.xml.dist000066400000000000000000000052441360544566000202600ustar00rootroot00000000000000 ./tests/Doctrine/Tests/DBAL ./tests/Doctrine/Tests/DBAL/Performance ./tests/Doctrine/Tests/DBAL/Performance lib/Doctrine performance php-doctrine-dbal-2.10.1/run-all.sh000077500000000000000000000005161360544566000170130ustar00rootroot00000000000000#!/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 php-doctrine-dbal-2.10.1/tests/000077500000000000000000000000001360544566000162425ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/000077500000000000000000000000001360544566000200115ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/000077500000000000000000000000001360544566000211135ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/000077500000000000000000000000001360544566000216155ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Cache/000077500000000000000000000000001360544566000226205ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Cache/QueryCacheProfileTest.php000066400000000000000000000077651360544566000275620ustar00rootroot00000000000000 'database_name', 'user' => 'database_user', 'password' => 'database_password', 'host' => 'database_host', 'driver' => 'database_driver', ]; protected function setUp() : void { $this->queryCacheProfile = new QueryCacheProfile(self::LIFETIME, self::CACHE_KEY); } public function testShouldUseTheGivenCacheKeyIfPresent() : void { [$cacheKey] = $this->queryCacheProfile->generateCacheKeys( $this->query, $this->params, $this->types, $this->connectionParams ); self::assertEquals(self::CACHE_KEY, $cacheKey, 'The returned cache key should match the given one'); } public function testShouldGenerateAnAutomaticKeyIfNoKeyHasBeenGiven() : void { $this->queryCacheProfile = $this->queryCacheProfile->setCacheKey(null); [$cacheKey] = $this->queryCacheProfile->generateCacheKeys( $this->query, $this->params, $this->types, $this->connectionParams ); self::assertNotEquals( self::CACHE_KEY, $cacheKey, 'The returned cache key should be generated automatically' ); self::assertNotEmpty($cacheKey, 'The generated cache key should not be empty'); } public function testShouldGenerateDifferentKeysForSameQueryAndParamsAndDifferentConnections() : void { $this->queryCacheProfile = $this->queryCacheProfile->setCacheKey(null); [$firstCacheKey] = $this->queryCacheProfile->generateCacheKeys( $this->query, $this->params, $this->types, $this->connectionParams ); $this->connectionParams['host'] = 'a_different_host'; [$secondCacheKey] = $this->queryCacheProfile->generateCacheKeys( $this->query, $this->params, $this->types, $this->connectionParams ); self::assertNotEquals($firstCacheKey, $secondCacheKey, 'Cache keys should be different'); } public function testConnectionParamsShouldBeHashed() : void { $this->queryCacheProfile = $this->queryCacheProfile->setCacheKey(null); [$cacheKey, $queryString] = $this->queryCacheProfile->generateCacheKeys( $this->query, $this->params, $this->types, $this->connectionParams ); $params = []; parse_str($queryString, $params); self::assertArrayHasKey('connectionParams', $params); foreach ($this->connectionParams as $param) { self::assertStringNotContainsString($param, $params['connectionParams']); } } public function testShouldGenerateSameKeysIfNoneOfTheParamsChanges() : void { $this->queryCacheProfile = $this->queryCacheProfile->setCacheKey(null); [$firstCacheKey] = $this->queryCacheProfile->generateCacheKeys( $this->query, $this->params, $this->types, $this->connectionParams ); [$secondCacheKey] = $this->queryCacheProfile->generateCacheKeys( $this->query, $this->params, $this->types, $this->connectionParams ); self::assertEquals($firstCacheKey, $secondCacheKey, 'Cache keys should be the same'); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/ConfigurationTest.php000066400000000000000000000022751360544566000260030ustar00rootroot00000000000000config = new Configuration(); } /** * Tests that the default auto-commit mode for connections can be retrieved from the configuration container. * * @group DBAL-81 */ public function testReturnsDefaultConnectionAutoCommitMode() : void { self::assertTrue($this->config->getAutoCommit()); } /** * Tests that the default auto-commit mode for connections can be set in the configuration container. * * @group DBAL-81 */ public function testSetsDefaultConnectionAutoCommitMode() : void { $this->config->setAutoCommit(false); self::assertFalse($this->config->getAutoCommit()); $this->config->setAutoCommit(0); self::assertFalse($this->config->getAutoCommit()); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/ConnectionTest.php000066400000000000000000000722701360544566000252750ustar00rootroot00000000000000 'pdo_mysql', 'host' => 'localhost', 'user' => 'root', 'password' => 'password', 'port' => '1234', ]; protected function setUp() : void { $this->connection = DriverManager::getConnection($this->params); } /** * @return Connection|MockObject */ private function getExecuteUpdateMockConnection() { $driverMock = $this->createMock(Driver::class); $driverMock->expects($this->any()) ->method('connect') ->will($this->returnValue( $this->createMock(DriverConnection::class) )); $platform = $this->getMockForAbstractClass(AbstractPlatform::class); return $this->getMockBuilder(Connection::class) ->onlyMethods(['executeUpdate']) ->setConstructorArgs([['platform' => $platform], $driverMock]) ->getMock(); } public function testIsConnected() : void { self::assertFalse($this->connection->isConnected()); } public function testNoTransactionActiveByDefault() : void { self::assertFalse($this->connection->isTransactionActive()); } public function testCommitWithNoActiveTransactionThrowsException() : void { $this->expectException(ConnectionException::class); $this->connection->commit(); } public function testRollbackWithNoActiveTransactionThrowsException() : void { $this->expectException(ConnectionException::class); $this->connection->rollBack(); } public function testSetRollbackOnlyNoActiveTransactionThrowsException() : void { $this->expectException(ConnectionException::class); $this->connection->setRollbackOnly(); } public function testIsRollbackOnlyNoActiveTransactionThrowsException() : void { $this->expectException(ConnectionException::class); $this->connection->isRollbackOnly(); } public function testGetConfiguration() : void { $config = $this->connection->getConfiguration(); self::assertInstanceOf(Configuration::class, $config); } public function testGetHost() : void { self::assertEquals('localhost', $this->connection->getHost()); } public function testGetPort() : void { self::assertEquals('1234', $this->connection->getPort()); } public function testGetUsername() : void { self::assertEquals('root', $this->connection->getUsername()); } public function testGetPassword() : void { self::assertEquals('password', $this->connection->getPassword()); } public function testGetDriver() : void { self::assertInstanceOf(\Doctrine\DBAL\Driver\PDOMySql\Driver::class, $this->connection->getDriver()); } public function testGetEventManager() : void { self::assertInstanceOf(EventManager::class, $this->connection->getEventManager()); } public function testConnectDispatchEvent() : void { $listenerMock = $this->getMockBuilder($this->getMockClass('ConnectDispatchEventListener')) ->addMethods(['postConnect']) ->getMock(); $listenerMock->expects($this->once())->method('postConnect'); $eventManager = new EventManager(); $eventManager->addEventListener([Events::postConnect], $listenerMock); $driverMock = $this->createMock(Driver::class); $driverMock->expects($this->at(0)) ->method('connect'); $conn = new Connection([], $driverMock, new Configuration(), $eventManager); $conn->connect(); } public function testEventManagerPassedToPlatform() : void { $eventManager = new EventManager(); /** @var AbstractPlatform|MockObject $driver */ $platform = $this->createMock(AbstractPlatform::class); $platform->expects($this->once()) ->method('setEventManager') ->with($eventManager); /** @var Driver|MockObject $driver */ $driver = $this->createMock(Driver::class); $driver->expects($this->any()) ->method('getDatabasePlatform') ->willReturn($platform); $connection = new Connection($this->params, $driver, null, $eventManager); $connection->getDatabasePlatform(); } /** * @requires extension pdo_sqlite * @dataProvider getQueryMethods */ public function testDriverExceptionIsWrapped(string $method) : void { $this->expectException(DBALException::class); $this->expectExceptionMessage("An exception occurred while executing 'MUUHAAAAHAAAA':\n\nSQLSTATE[HY000]: General error: 1 near \"MUUHAAAAHAAAA\""); $connection = DriverManager::getConnection([ 'driver' => 'pdo_sqlite', 'memory' => true, ]); $connection->$method('MUUHAAAAHAAAA'); } /** * @return array> */ public static function getQueryMethods() : iterable { return [ ['exec'], ['query'], ['executeQuery'], ['executeUpdate'], ['prepare'], ]; } /** * Pretty dumb test, however we want to check that the EchoSQLLogger correctly implements the interface. * * @group DBAL-11 */ public function testEchoSQLLogger() : void { $logger = new EchoSQLLogger(); $this->connection->getConfiguration()->setSQLLogger($logger); self::assertSame($logger, $this->connection->getConfiguration()->getSQLLogger()); } /** * Pretty dumb test, however we want to check that the DebugStack correctly implements the interface. * * @group DBAL-11 */ public function testDebugSQLStack() : void { $logger = new DebugStack(); $this->connection->getConfiguration()->setSQLLogger($logger); self::assertSame($logger, $this->connection->getConfiguration()->getSQLLogger()); } /** * @group DBAL-81 */ public function testIsAutoCommit() : void { self::assertTrue($this->connection->isAutoCommit()); } /** * @group DBAL-81 */ public function testSetAutoCommit() : void { $this->connection->setAutoCommit(false); self::assertFalse($this->connection->isAutoCommit()); $this->connection->setAutoCommit(0); self::assertFalse($this->connection->isAutoCommit()); } /** * @group DBAL-81 */ public function testConnectStartsTransactionInNoAutoCommitMode() : void { $driverMock = $this->createMock(Driver::class); $driverMock->expects($this->any()) ->method('connect') ->will($this->returnValue( $this->createMock(DriverConnection::class) )); $conn = new Connection([], $driverMock); $conn->setAutoCommit(false); self::assertFalse($conn->isTransactionActive()); $conn->connect(); self::assertTrue($conn->isTransactionActive()); } /** * @group DBAL-81 */ public function testCommitStartsTransactionInNoAutoCommitMode() : void { $driverMock = $this->createMock(Driver::class); $driverMock->expects($this->any()) ->method('connect') ->will($this->returnValue( $this->createMock(DriverConnection::class) )); $conn = new Connection([], $driverMock); $conn->setAutoCommit(false); $conn->connect(); $conn->commit(); self::assertTrue($conn->isTransactionActive()); } /** * @dataProvider resultProvider */ public function testCommitReturn(bool $expectedResult) : void { $driverConnection = $this->createMock(DriverConnection::class); $driverConnection->expects($this->once()) ->method('commit')->willReturn($expectedResult); $driverMock = $this->createMock(Driver::class); $driverMock->expects($this->any()) ->method('connect') ->will($this->returnValue($driverConnection)); $conn = new Connection([], $driverMock); $conn->connect(); $conn->beginTransaction(); self::assertSame($expectedResult, $conn->commit()); } /** * @return bool[][] */ public function resultProvider() : array { return [[true], [false]]; } /** * @group DBAL-81 */ public function testRollBackStartsTransactionInNoAutoCommitMode() : void { $driverMock = $this->createMock(Driver::class); $driverMock->expects($this->any()) ->method('connect') ->will($this->returnValue( $this->createMock(DriverConnection::class) )); $conn = new Connection([], $driverMock); $conn->setAutoCommit(false); $conn->connect(); $conn->rollBack(); self::assertTrue($conn->isTransactionActive()); } /** * @group DBAL-81 */ public function testSwitchingAutoCommitModeCommitsAllCurrentTransactions() : void { $driverMock = $this->createMock(Driver::class); $driverMock->expects($this->any()) ->method('connect') ->will($this->returnValue( $this->createMock(DriverConnection::class) )); $conn = new Connection([], $driverMock); $conn->connect(); $conn->beginTransaction(); $conn->beginTransaction(); $conn->setAutoCommit(false); self::assertSame(1, $conn->getTransactionNestingLevel()); $conn->beginTransaction(); $conn->beginTransaction(); $conn->setAutoCommit(true); self::assertFalse($conn->isTransactionActive()); } public function testEmptyInsert() : void { $conn = $this->getExecuteUpdateMockConnection(); $conn->expects($this->once()) ->method('executeUpdate') ->with('INSERT INTO footable () VALUES ()'); $conn->insert('footable', []); } /** * @group DBAL-2511 */ public function testUpdateWithDifferentColumnsInDataAndIdentifiers() : void { $conn = $this->getExecuteUpdateMockConnection(); $conn->expects($this->once()) ->method('executeUpdate') ->with( 'UPDATE TestTable SET text = ?, is_edited = ? WHERE id = ? AND name = ?', [ 'some text', true, 1, 'foo', ], [ 'string', 'boolean', 'integer', 'string', ] ); $conn->update( 'TestTable', [ 'text' => 'some text', 'is_edited' => true, ], [ 'id' => 1, 'name' => 'foo', ], [ 'text' => 'string', 'is_edited' => 'boolean', 'id' => 'integer', 'name' => 'string', ] ); } /** * @group DBAL-2511 */ public function testUpdateWithSameColumnInDataAndIdentifiers() : void { $conn = $this->getExecuteUpdateMockConnection(); $conn->expects($this->once()) ->method('executeUpdate') ->with( 'UPDATE TestTable SET text = ?, is_edited = ? WHERE id = ? AND is_edited = ?', [ 'some text', true, 1, false, ], [ 'string', 'boolean', 'integer', 'boolean', ] ); $conn->update( 'TestTable', [ 'text' => 'some text', 'is_edited' => true, ], [ 'id' => 1, 'is_edited' => false, ], [ 'text' => 'string', 'is_edited' => 'boolean', 'id' => 'integer', ] ); } /** * @group DBAL-2688 */ public function testUpdateWithIsNull() : void { $conn = $this->getExecuteUpdateMockConnection(); $conn->expects($this->once()) ->method('executeUpdate') ->with( 'UPDATE TestTable SET text = ?, is_edited = ? WHERE id IS NULL AND name = ?', [ 'some text', null, 'foo', ], [ 'string', 'boolean', 'string', ] ); $conn->update( 'TestTable', [ 'text' => 'some text', 'is_edited' => null, ], [ 'id' => null, 'name' => 'foo', ], [ 'text' => 'string', 'is_edited' => 'boolean', 'id' => 'integer', 'name' => 'string', ] ); } /** * @group DBAL-2688 */ public function testDeleteWithIsNull() : void { $conn = $this->getExecuteUpdateMockConnection(); $conn->expects($this->once()) ->method('executeUpdate') ->with( 'DELETE FROM TestTable WHERE id IS NULL AND name = ?', ['foo'], ['string'] ); $conn->delete( 'TestTable', [ 'id' => null, 'name' => 'foo', ], [ 'id' => 'integer', 'name' => 'string', ] ); } public function testFetchAssoc() : void { $statement = 'SELECT * FROM foo WHERE bar = ?'; $params = [666]; $types = [ParameterType::INTEGER]; $result = []; $driverMock = $this->createMock(Driver::class); $driverMock->expects($this->any()) ->method('connect') ->will($this->returnValue( $this->createMock(DriverConnection::class) )); $driverStatementMock = $this->createMock(Statement::class); $driverStatementMock->expects($this->once()) ->method('fetch') ->with(FetchMode::ASSOCIATIVE) ->will($this->returnValue($result)); /** @var Connection|MockObject $conn */ $conn = $this->getMockBuilder(Connection::class) ->onlyMethods(['executeQuery']) ->setConstructorArgs([[], $driverMock]) ->getMock(); $conn->expects($this->once()) ->method('executeQuery') ->with($statement, $params, $types) ->will($this->returnValue($driverStatementMock)); self::assertSame($result, $conn->fetchAssoc($statement, $params, $types)); } public function testFetchArray() : void { $statement = 'SELECT * FROM foo WHERE bar = ?'; $params = [666]; $types = [ParameterType::INTEGER]; $result = []; $driverMock = $this->createMock(Driver::class); $driverMock->expects($this->any()) ->method('connect') ->will($this->returnValue( $this->createMock(DriverConnection::class) )); $driverStatementMock = $this->createMock(Statement::class); $driverStatementMock->expects($this->once()) ->method('fetch') ->with(FetchMode::NUMERIC) ->will($this->returnValue($result)); /** @var Connection|MockObject $conn */ $conn = $this->getMockBuilder(Connection::class) ->onlyMethods(['executeQuery']) ->setConstructorArgs([[], $driverMock]) ->getMock(); $conn->expects($this->once()) ->method('executeQuery') ->with($statement, $params, $types) ->will($this->returnValue($driverStatementMock)); self::assertSame($result, $conn->fetchArray($statement, $params, $types)); } public function testFetchColumn() : void { $statement = 'SELECT * FROM foo WHERE bar = ?'; $params = [666]; $types = [ParameterType::INTEGER]; $column = 0; $result = []; $driverMock = $this->createMock(Driver::class); $driverMock->expects($this->any()) ->method('connect') ->will($this->returnValue( $this->createMock(DriverConnection::class) )); $driverStatementMock = $this->createMock(Statement::class); $driverStatementMock->expects($this->once()) ->method('fetchColumn') ->with($column) ->will($this->returnValue($result)); /** @var Connection|MockObject $conn */ $conn = $this->getMockBuilder(Connection::class) ->onlyMethods(['executeQuery']) ->setConstructorArgs([[], $driverMock]) ->getMock(); $conn->expects($this->once()) ->method('executeQuery') ->with($statement, $params, $types) ->will($this->returnValue($driverStatementMock)); self::assertSame($result, $conn->fetchColumn($statement, $params, $column, $types)); } public function testFetchAll() : void { $statement = 'SELECT * FROM foo WHERE bar = ?'; $params = [666]; $types = [ParameterType::INTEGER]; $result = []; $driverMock = $this->createMock(Driver::class); $driverMock->expects($this->any()) ->method('connect') ->will($this->returnValue( $this->createMock(DriverConnection::class) )); $driverStatementMock = $this->createMock(Statement::class); $driverStatementMock->expects($this->once()) ->method('fetchAll') ->will($this->returnValue($result)); /** @var Connection|MockObject $conn */ $conn = $this->getMockBuilder(Connection::class) ->onlyMethods(['executeQuery']) ->setConstructorArgs([[], $driverMock]) ->getMock(); $conn->expects($this->once()) ->method('executeQuery') ->with($statement, $params, $types) ->will($this->returnValue($driverStatementMock)); self::assertSame($result, $conn->fetchAll($statement, $params, $types)); } public function testConnectionDoesNotMaintainTwoReferencesToExternalPDO() : void { $params['pdo'] = new stdClass(); $driverMock = $this->createMock(Driver::class); $conn = new Connection($params, $driverMock); self::assertArrayNotHasKey('pdo', $conn->getParams(), 'Connection is maintaining additional reference to the PDO connection'); } public function testPassingExternalPDOMeansConnectionIsConnected() : void { $params['pdo'] = new stdClass(); $driverMock = $this->createMock(Driver::class); $conn = new Connection($params, $driverMock); self::assertTrue($conn->isConnected(), 'Connection is not connected after passing external PDO'); } public function testCallingDeleteWithNoDeletionCriteriaResultsInInvalidArgumentException() : void { /** @var Driver $driver */ $driver = $this->createMock(Driver::class); $pdoMock = $this->createMock(\Doctrine\DBAL\Driver\Connection::class); // should never execute queries with invalid arguments $pdoMock->expects($this->never())->method('exec'); $pdoMock->expects($this->never())->method('prepare'); $conn = new Connection(['pdo' => $pdoMock], $driver); $this->expectException(InvalidArgumentException::class); $conn->delete('kittens', []); } /** * @return array> */ public static function dataCallConnectOnce() : iterable { return [ ['delete', ['tbl', ['id' => 12345]]], ['insert', ['tbl', ['data' => 'foo']]], ['update', ['tbl', ['data' => 'bar'], ['id' => 12345]]], ['prepare', ['select * from dual']], ['executeUpdate', ['insert into tbl (id) values (?)'], [123]], ]; } /** * @param array $params * * @dataProvider dataCallConnectOnce */ public function testCallConnectOnce(string $method, array $params) : void { $driverMock = $this->createMock(Driver::class); $pdoMock = $this->createMock(Connection::class); $platformMock = $this->createMock(AbstractPlatform::class); $stmtMock = $this->createMock(Statement::class); $pdoMock->expects($this->any()) ->method('prepare') ->will($this->returnValue($stmtMock)); $conn = $this->getMockBuilder(Connection::class) ->setConstructorArgs([['pdo' => $pdoMock, 'platform' => $platformMock], $driverMock]) ->onlyMethods(['connect']) ->getMock(); $conn->expects($this->once())->method('connect'); call_user_func_array([$conn, $method], $params); } /** * @group DBAL-1127 */ public function testPlatformDetectionIsTriggerOnlyOnceOnRetrievingPlatform() : void { /** @var Driver|VersionAwarePlatformDriver|MockObject $driverMock */ $driverMock = $this->createMock([Driver::class, VersionAwarePlatformDriver::class]); /** @var ServerInfoAwareConnection|MockObject $driverConnectionMock */ $driverConnectionMock = $this->createMock(ServerInfoAwareConnection::class); /** @var AbstractPlatform|MockObject $platformMock */ $platformMock = $this->getMockForAbstractClass(AbstractPlatform::class); $connection = new Connection([], $driverMock); $driverMock->expects($this->once()) ->method('connect') ->will($this->returnValue($driverConnectionMock)); $driverConnectionMock->expects($this->once()) ->method('requiresQueryForServerVersion') ->will($this->returnValue(false)); $driverConnectionMock->expects($this->once()) ->method('getServerVersion') ->will($this->returnValue('6.6.6')); $driverMock->expects($this->once()) ->method('createDatabasePlatformForVersion') ->with('6.6.6') ->will($this->returnValue($platformMock)); self::assertSame($platformMock, $connection->getDatabasePlatform()); } public function testConnectionParamsArePassedToTheQueryCacheProfileInExecuteCacheQuery() : void { $resultCacheDriverMock = $this->createMock(Cache::class); $resultCacheDriverMock ->expects($this->atLeastOnce()) ->method('fetch') ->with('cacheKey') ->will($this->returnValue(['realKey' => []])); $query = 'SELECT * FROM foo WHERE bar = ?'; $params = [666]; $types = [ParameterType::INTEGER]; /** @var QueryCacheProfile|MockObject $queryCacheProfileMock */ $queryCacheProfileMock = $this->createMock(QueryCacheProfile::class); $queryCacheProfileMock ->expects($this->any()) ->method('getResultCacheDriver') ->will($this->returnValue($resultCacheDriverMock)); // This is our main expectation $queryCacheProfileMock ->expects($this->once()) ->method('generateCacheKeys') ->with($query, $params, $types, $this->params) ->will($this->returnValue(['cacheKey', 'realKey'])); /** @var Driver $driver */ $driver = $this->createMock(Driver::class); self::assertInstanceOf( ArrayStatement::class, (new Connection($this->params, $driver))->executeCacheQuery($query, $params, $types, $queryCacheProfileMock) ); } /** * @group #2821 */ public function testShouldNotPassPlatformInParamsToTheQueryCacheProfileInExecuteCacheQuery() : void { $resultCacheDriverMock = $this->createMock(Cache::class); $resultCacheDriverMock ->expects($this->atLeastOnce()) ->method('fetch') ->with('cacheKey') ->will($this->returnValue(['realKey' => []])); /** @var QueryCacheProfile|MockObject $queryCacheProfileMock */ $queryCacheProfileMock = $this->createMock(QueryCacheProfile::class); $queryCacheProfileMock ->expects($this->any()) ->method('getResultCacheDriver') ->will($this->returnValue($resultCacheDriverMock)); $query = 'SELECT 1'; $connectionParams = $this->params; $queryCacheProfileMock ->expects($this->once()) ->method('generateCacheKeys') ->with($query, [], [], $connectionParams) ->will($this->returnValue(['cacheKey', 'realKey'])); $connectionParams['platform'] = $this->createMock(AbstractPlatform::class); /** @var Driver $driver */ $driver = $this->createMock(Driver::class); (new Connection($connectionParams, $driver))->executeCacheQuery($query, [], [], $queryCacheProfileMock); } /** * @group #2821 */ public function testThrowsExceptionWhenInValidPlatformSpecified() : void { $connectionParams = $this->params; $connectionParams['platform'] = new stdClass(); /** @var Driver $driver */ $driver = $this->createMock(Driver::class); $this->expectException(DBALException::class); new Connection($connectionParams, $driver); } /** * @group DBAL-990 */ public function testRethrowsOriginalExceptionOnDeterminingPlatformWhenConnectingToNonExistentDatabase() : void { /** @var Driver|VersionAwarePlatformDriver|MockObject $driverMock */ $driverMock = $this->createMock([Driver::class, VersionAwarePlatformDriver::class]); $connection = new Connection(['dbname' => 'foo'], $driverMock); $originalException = new Exception('Original exception'); $fallbackException = new Exception('Fallback exception'); $driverMock->expects($this->at(0)) ->method('connect') ->willThrowException($originalException); $driverMock->expects($this->at(1)) ->method('connect') ->willThrowException($fallbackException); $this->expectExceptionMessage($originalException->getMessage()); $connection->getDatabasePlatform(); } /** * @group #3194 */ public function testExecuteCacheQueryStripsPlatformFromConnectionParamsBeforeGeneratingCacheKeys() : void { /** @var Driver|MockObject $driver */ $driver = $this->createMock(Driver::class); /** @var AbstractPlatform|MockObject $platform */ $platform = $this->createMock(AbstractPlatform::class); /** @var QueryCacheProfile|MockObject $queryCacheProfile */ $queryCacheProfile = $this->createMock(QueryCacheProfile::class); /** @var Cache|MockObject $resultCacheDriver */ $resultCacheDriver = $this->createMock(Cache::class); $queryCacheProfile ->expects($this->any()) ->method('getResultCacheDriver') ->will($this->returnValue($resultCacheDriver)); $resultCacheDriver ->expects($this->atLeastOnce()) ->method('fetch') ->with('cacheKey') ->will($this->returnValue(['realKey' => []])); $query = 'SELECT 1'; $params = [ 'dbname' => 'foo', 'platform' => $platform, ]; $paramsWithoutPlatform = $params; unset($paramsWithoutPlatform['platform']); $queryCacheProfile ->expects($this->once()) ->method('generateCacheKeys') ->with($query, [], [], $paramsWithoutPlatform) ->will($this->returnValue(['cacheKey', 'realKey'])); $connection = new Connection($params, $driver); self::assertSame($params, $connection->getParams()); $connection->executeCacheQuery($query, [], [], $queryCacheProfile); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/DBALExceptionTest.php000066400000000000000000000055441360544566000255570ustar00rootroot00000000000000createMock(Driver::class); $e = DBALException::driverExceptionDuringQuery($driver, new Exception(), '', ['ABC', chr(128)]); self::assertStringContainsString('with params ["ABC", "\x80"]', $e->getMessage()); } public function testDriverExceptionDuringQueryAcceptsResource() : void { /** @var Driver $driver */ $driver = $this->createMock(Driver::class); $e = DBALException::driverExceptionDuringQuery($driver, new Exception(), 'INSERT INTO file (`content`) VALUES (?)', [1 => fopen(__FILE__, 'r')]); self::assertStringContainsString('Resource', $e->getMessage()); } public function testAvoidOverWrappingOnDriverException() : void { /** @var Driver $driver */ $driver = $this->createMock(Driver::class); /** @var InnerDriverException $inner */ $inner = $this->createMock(InnerDriverException::class); $ex = new DriverException('', $inner); $e = DBALException::driverExceptionDuringQuery($driver, $ex, ''); self::assertSame($ex, $e); } public function testDriverRequiredWithUrl() : void { $url = 'mysql://localhost'; $exception = DBALException::driverRequired($url); self::assertInstanceOf(DBALException::class, $exception); self::assertSame( sprintf( "The options 'driver' or 'driverClass' are mandatory if a connection URL without scheme " . 'is given to DriverManager::getConnection(). Given URL: %s', $url ), $exception->getMessage() ); } /** * @group #2821 */ public function testInvalidPlatformTypeObject() : void { $exception = DBALException::invalidPlatformType(new stdClass()); self::assertSame( "Option 'platform' must be a subtype of 'Doctrine\DBAL\Platforms\AbstractPlatform', instance of 'stdClass' given", $exception->getMessage() ); } /** * @group #2821 */ public function testInvalidPlatformTypeScalar() : void { $exception = DBALException::invalidPlatformType('some string'); self::assertSame( "Option 'platform' must be an object and subtype of 'Doctrine\DBAL\Platforms\AbstractPlatform'. Got 'string'", $exception->getMessage() ); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Driver/000077500000000000000000000000001360544566000230505ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Driver/AbstractDB2DriverTest.php000066400000000000000000000014101360544566000276240ustar00rootroot00000000000000getMockForAbstractClass(AbstractDB2Driver::class); } protected function createPlatform() : AbstractPlatform { return new DB2Platform(); } protected function createSchemaManager(Connection $connection) : AbstractSchemaManager { return new DB2SchemaManager($connection); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Driver/AbstractDriverTest.php000066400000000000000000000216641360544566000273510ustar00rootroot00000000000000driver = $this->createDriver(); } /** * @param int|string $errorCode * * @dataProvider exceptionConversionProvider */ public function testConvertsException($errorCode, ?string $sqlState, ?string $message, string $expectedClass) : void { if (! $this->driver instanceof ExceptionConverterDriver) { $this->markTestSkipped('This test is only intended for exception converter drivers.'); } /** @var DriverExceptionInterface|MockObject $driverException */ $driverException = $this->getMockBuilder(DriverExceptionInterface::class) ->setConstructorArgs([$message]) ->getMock(); $driverException->method('getErrorCode') ->willReturn($errorCode); $driverException->method('getSQLState') ->willReturn($sqlState); $dbalMessage = 'DBAL exception message'; $dbalException = $this->driver->convertException($dbalMessage, $driverException); self::assertInstanceOf($expectedClass, $dbalException); self::assertSame($driverException->getErrorCode(), $dbalException->getErrorCode()); self::assertSame($driverException->getSQLState(), $dbalException->getSQLState()); self::assertSame($driverException, $dbalException->getPrevious()); self::assertSame($dbalMessage, $dbalException->getMessage()); } public function testCreatesDatabasePlatformForVersion() : void { if (! $this->driver instanceof VersionAwarePlatformDriver) { $this->markTestSkipped('This test is only intended for version aware platform drivers.'); } $data = $this->getDatabasePlatformsForVersions(); self::assertNotEmpty( $data, sprintf( 'No test data found for test %s. You have to return test data from %s.', static::class . '::' . __FUNCTION__, static::class . '::getDatabasePlatformsForVersions' ) ); foreach ($data as $item) { $generatedVersion = get_class($this->driver->createDatabasePlatformForVersion($item[0])); self::assertSame( $item[1], $generatedVersion, sprintf( 'Expected platform for version "%s" should be "%s", "%s" given', $item[0], $item[1], $generatedVersion ) ); } } public function testThrowsExceptionOnCreatingDatabasePlatformsForInvalidVersion() : void { if (! $this->driver instanceof VersionAwarePlatformDriver) { $this->markTestSkipped('This test is only intended for version aware platform drivers.'); } $this->expectException(DBALException::class); $this->driver->createDatabasePlatformForVersion('foo'); } public function testReturnsDatabaseName() : void { $params = [ 'user' => 'foo', 'password' => 'bar', 'dbname' => 'baz', ]; $connection = $this->getConnectionMock(); $connection->expects($this->once()) ->method('getParams') ->will($this->returnValue($params)); self::assertSame($params['dbname'], $this->driver->getDatabase($connection)); } public function testReturnsDatabasePlatform() : void { self::assertEquals($this->createPlatform(), $this->driver->getDatabasePlatform()); } public function testReturnsSchemaManager() : void { $connection = $this->getConnectionMock(); $schemaManager = $this->driver->getSchemaManager($connection); self::assertEquals($this->createSchemaManager($connection), $schemaManager); $re = new ReflectionProperty($schemaManager, '_conn'); $re->setAccessible(true); self::assertSame($connection, $re->getValue($schemaManager)); } /** * Factory method for creating the driver instance under test. */ abstract protected function createDriver() : Driver; /** * Factory method for creating the the platform instance return by the driver under test. * * The platform instance returned by this method must be the same as returned by * the driver's getDatabasePlatform() method. */ abstract protected function createPlatform() : AbstractPlatform; /** * Factory method for creating the the schema manager instance return by the driver under test. * * The schema manager instance returned by this method must be the same as returned by * the driver's getSchemaManager() method. * * @param Connection $connection The underlying connection to use. */ abstract protected function createSchemaManager(Connection $connection) : AbstractSchemaManager; protected function getConnectionMock() : Connection { return $this->getMockBuilder(Connection::class) ->disableOriginalConstructor() ->getMock(); } /** * @return array> */ protected function getDatabasePlatformsForVersions() : array { return []; } /** * @return mixed[][] */ public static function exceptionConversionProvider() : iterable { foreach (static::getExceptionConversionData() as $expectedClass => $items) { foreach ($items as $item) { yield array_merge($item, [$expectedClass]); } } yield ['foo', 'bar', 'baz', self::EXCEPTION_DRIVER]; } /** * @return array */ protected static function getExceptionConversionData() : array { return []; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Driver/AbstractMySQLDriverTest.php000066400000000000000000000130421360544566000302260ustar00rootroot00000000000000 'foo', 'password' => 'bar', ]; $statement = $this->createMock(ResultStatement::class); $statement->expects($this->once()) ->method('fetchColumn') ->will($this->returnValue($database)); $connection = $this->getConnectionMock(); $connection->expects($this->once()) ->method('getParams') ->will($this->returnValue($params)); $connection->expects($this->once()) ->method('query') ->will($this->returnValue($statement)); self::assertSame($database, $this->driver->getDatabase($connection)); } protected function createDriver() : Driver { return $this->getMockForAbstractClass(AbstractMySQLDriver::class); } protected function createPlatform() : AbstractPlatform { return new MySqlPlatform(); } protected function createSchemaManager(Connection $connection) : AbstractSchemaManager { return new MySqlSchemaManager($connection); } /** * {@inheritDoc} */ protected function getDatabasePlatformsForVersions() : array { return [ ['5.6.9', MySqlPlatform::class], ['5.7', MySQL57Platform::class], ['5.7.0', MySqlPlatform::class], ['5.7.8', MySqlPlatform::class], ['5.7.9', MySQL57Platform::class], ['5.7.10', MySQL57Platform::class], ['8', MySQL80Platform::class], ['8.0', MySQL80Platform::class], ['8.0.11', MySQL80Platform::class], ['6', MySQL57Platform::class], ['10.0.15-MariaDB-1~wheezy', MySqlPlatform::class], ['5.5.5-10.1.25-MariaDB', MySqlPlatform::class], ['10.1.2a-MariaDB-a1~lenny-log', MySqlPlatform::class], ['5.5.40-MariaDB-1~wheezy', MySqlPlatform::class], ['5.5.5-MariaDB-10.2.8+maria~xenial-log', MariaDb1027Platform::class], ['10.2.8-MariaDB-10.2.8+maria~xenial-log', MariaDb1027Platform::class], ['10.2.8-MariaDB-1~lenny-log', MariaDb1027Platform::class], ]; } /** * {@inheritDoc} */ protected static function getExceptionConversionData() : array { return [ self::EXCEPTION_CONNECTION => [ ['1044', null, null], ['1045', null, null], ['1046', null, null], ['1049', null, null], ['1095', null, null], ['1142', null, null], ['1143', null, null], ['1227', null, null], ['1370', null, null], ['2002', null, null], ['2005', null, null], ], self::EXCEPTION_FOREIGN_KEY_CONSTRAINT_VIOLATION => [ ['1216', null, null], ['1217', null, null], ['1451', null, null], ['1452', null, null], ], self::EXCEPTION_INVALID_FIELD_NAME => [ ['1054', null, null], ['1166', null, null], ['1611', null, null], ], self::EXCEPTION_NON_UNIQUE_FIELD_NAME => [ ['1052', null, null], ['1060', null, null], ['1110', null, null], ], self::EXCEPTION_NOT_NULL_CONSTRAINT_VIOLATION => [ ['1048', null, null], ['1121', null, null], ['1138', null, null], ['1171', null, null], ['1252', null, null], ['1263', null, null], ['1364', null, null], ['1566', null, null], ], self::EXCEPTION_SYNTAX_ERROR => [ ['1064', null, null], ['1149', null, null], ['1287', null, null], ['1341', null, null], ['1342', null, null], ['1343', null, null], ['1344', null, null], ['1382', null, null], ['1479', null, null], ['1541', null, null], ['1554', null, null], ['1626', null, null], ], self::EXCEPTION_TABLE_EXISTS => [ ['1050', null, null], ], self::EXCEPTION_TABLE_NOT_FOUND => [ ['1051', null, null], ['1146', null, null], ], self::EXCEPTION_UNIQUE_CONSTRAINT_VIOLATION => [ ['1062', null, null], ['1557', null, null], ['1569', null, null], ['1586', null, null], ], self::EXCEPTION_DEADLOCK => [ ['1213', null, null], ], self::EXCEPTION_LOCK_WAIT_TIMEOUT => [ ['1205', null, null], ], ]; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Driver/AbstractOracleDriver/000077500000000000000000000000001360544566000271155ustar00rootroot00000000000000EasyConnectStringTest.php000066400000000000000000000037641360544566000340230ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Driver/AbstractOracleDriverassertSame($expected, (string) $string); } /** * @return mixed[] */ public static function connectionParametersProvider() : iterable { return [ 'empty-params' => [[],''], 'common-params' => [ [ 'host' => 'oracle.example.com', 'port' => 1521, 'dbname' => 'XE', ], '(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=oracle.example.com)(PORT=1521))(CONNECT_DATA=(SID=XE)))', ], 'no-db-name' => [ ['host' => 'localhost'], '(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521)))', ], 'service' => [ [ 'host' => 'localhost', 'port' => 1521, 'service' => true, 'servicename' => 'BILLING', ], '(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=BILLING)))', ], 'advanced-params' => [ [ 'host' => 'localhost', 'port' => 41521, 'dbname' => 'XE', 'instancename' => 'SALES', 'pooled' => true, ], '(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=41521))(CONNECT_DATA=(SID=XE)(INSTANCE_NAME=SALES)(SERVER=POOLED)))', ], ]; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Driver/AbstractOracleDriverTest.php000066400000000000000000000061141360544566000304700ustar00rootroot00000000000000 'foo', 'password' => 'bar', 'dbname' => 'baz', ]; $connection = $this->getConnectionMock(); $connection->expects($this->once()) ->method('getParams') ->will($this->returnValue($params)); self::assertSame($params['user'], $this->driver->getDatabase($connection)); } public function testReturnsDatabaseNameWithConnectDescriptor() : void { $params = [ 'user' => 'foo', 'password' => 'bar', 'connectionstring' => '(DESCRIPTION=' . '(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521))' . '(CONNECT_DATA=(SERVICE_NAME=baz)))', ]; $connection = $this->getConnectionMock(); $connection->expects($this->once()) ->method('getParams') ->will($this->returnValue($params)); self::assertSame($params['user'], $this->driver->getDatabase($connection)); } protected function createDriver() : Driver { return $this->getMockForAbstractClass(AbstractOracleDriver::class); } protected function createPlatform() : AbstractPlatform { return new OraclePlatform(); } protected function createSchemaManager(Connection $connection) : AbstractSchemaManager { return new OracleSchemaManager($connection); } /** * {@inheritDoc} */ protected static function getExceptionConversionData() : array { return [ self::EXCEPTION_CONNECTION => [ ['1017', null, null], ['12545', null, null], ], self::EXCEPTION_FOREIGN_KEY_CONSTRAINT_VIOLATION => [ ['2292', null, null], ], self::EXCEPTION_INVALID_FIELD_NAME => [ ['904', null, null], ], self::EXCEPTION_NON_UNIQUE_FIELD_NAME => [ ['918', null, null], ['960', null, null], ], self::EXCEPTION_NOT_NULL_CONSTRAINT_VIOLATION => [ ['1400', null, null], ], self::EXCEPTION_SYNTAX_ERROR => [ ['923', null, null], ], self::EXCEPTION_TABLE_EXISTS => [ ['955', null, null], ], self::EXCEPTION_TABLE_NOT_FOUND => [ ['942', null, null], ], self::EXCEPTION_UNIQUE_CONSTRAINT_VIOLATION => [ ['1', null, null], ['2299', null, null], ['38911', null, null], ], ]; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Driver/AbstractPostgreSQLDriverTest.php000066400000000000000000000075601360544566000312740ustar00rootroot00000000000000 'foo', 'password' => 'bar', ]; $statement = $this->createMock(ResultStatement::class); $statement->expects($this->once()) ->method('fetchColumn') ->will($this->returnValue($database)); $connection = $this->getConnectionMock(); $connection->expects($this->once()) ->method('getParams') ->will($this->returnValue($params)); $connection->expects($this->once()) ->method('query') ->will($this->returnValue($statement)); self::assertSame($database, $this->driver->getDatabase($connection)); } protected function createDriver() : Driver { return $this->getMockForAbstractClass(AbstractPostgreSQLDriver::class); } protected function createPlatform() : AbstractPlatform { return new PostgreSqlPlatform(); } protected function createSchemaManager(Connection $connection) : AbstractSchemaManager { return new PostgreSqlSchemaManager($connection); } /** * {@inheritDoc} */ protected function getDatabasePlatformsForVersions() : array { return [ ['9.0.9', PostgreSqlPlatform::class], ['9.1', PostgreSQL91Platform::class], ['9.1.0', PostgreSQL91Platform::class], ['9.1.1', PostgreSQL91Platform::class], ['9.1.9', PostgreSQL91Platform::class], ['9.2', PostgreSQL92Platform::class], ['9.2.0', PostgreSQL92Platform::class], ['9.2.1', PostgreSQL92Platform::class], ['9.3.6', PostgreSQL92Platform::class], ['9.4', PostgreSQL94Platform::class], ['9.4.0', PostgreSQL94Platform::class], ['9.4.1', PostgreSQL94Platform::class], ['10', PostgreSQL100Platform::class], ]; } /** * {@inheritDoc} */ protected static function getExceptionConversionData() : array { return [ self::EXCEPTION_CONNECTION => [ [null, '7', 'SQLSTATE[08006]'], ], self::EXCEPTION_FOREIGN_KEY_CONSTRAINT_VIOLATION => [ [null, '23503', null], ], self::EXCEPTION_INVALID_FIELD_NAME => [ [null, '42703', null], ], self::EXCEPTION_NON_UNIQUE_FIELD_NAME => [ [null, '42702', null], ], self::EXCEPTION_NOT_NULL_CONSTRAINT_VIOLATION => [ [null, '23502', null], ], self::EXCEPTION_SYNTAX_ERROR => [ [null, '42601', null], ], self::EXCEPTION_TABLE_EXISTS => [ [null, '42P07', null], ], self::EXCEPTION_TABLE_NOT_FOUND => [ [null, '42P01', null], ], self::EXCEPTION_UNIQUE_CONSTRAINT_VIOLATION => [ [null, '23505', null], ], self::EXCEPTION_DEADLOCK => [ [null, '40001', null], [null, '40P01', null], ], ]; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Driver/AbstractSQLAnywhereDriverTest.php000066400000000000000000000103361360544566000314260ustar00rootroot00000000000000getMockForAbstractClass(AbstractSQLAnywhereDriver::class); } protected function createPlatform() : AbstractPlatform { return new SQLAnywhere12Platform(); } protected function createSchemaManager(Connection $connection) : AbstractSchemaManager { return new SQLAnywhereSchemaManager($connection); } /** * {@inheritDoc} */ protected function getDatabasePlatformsForVersions() : array { return [ ['10', SQLAnywherePlatform::class], ['10.0', SQLAnywherePlatform::class], ['10.0.0', SQLAnywherePlatform::class], ['10.0.0.0', SQLAnywherePlatform::class], ['10.1.2.3', SQLAnywherePlatform::class], ['10.9.9.9', SQLAnywherePlatform::class], ['11', SQLAnywhere11Platform::class], ['11.0', SQLAnywhere11Platform::class], ['11.0.0', SQLAnywhere11Platform::class], ['11.0.0.0', SQLAnywhere11Platform::class], ['11.1.2.3', SQLAnywhere11Platform::class], ['11.9.9.9', SQLAnywhere11Platform::class], ['12', SQLAnywhere12Platform::class], ['12.0', SQLAnywhere12Platform::class], ['12.0.0', SQLAnywhere12Platform::class], ['12.0.0.0', SQLAnywhere12Platform::class], ['12.1.2.3', SQLAnywhere12Platform::class], ['12.9.9.9', SQLAnywhere12Platform::class], ['13', SQLAnywhere12Platform::class], ['14', SQLAnywhere12Platform::class], ['15', SQLAnywhere12Platform::class], ['15.9.9.9', SQLAnywhere12Platform::class], ['16', SQLAnywhere16Platform::class], ['16.0', SQLAnywhere16Platform::class], ['16.0.0', SQLAnywhere16Platform::class], ['16.0.0.0', SQLAnywhere16Platform::class], ['16.1.2.3', SQLAnywhere16Platform::class], ['16.9.9.9', SQLAnywhere16Platform::class], ['17', SQLAnywhere16Platform::class], ]; } /** * {@inheritDoc} */ protected static function getExceptionConversionData() : array { return [ self::EXCEPTION_CONNECTION => [ ['-100', null, null], ['-103', null, null], ['-832', null, null], ], self::EXCEPTION_FOREIGN_KEY_CONSTRAINT_VIOLATION => [ ['-198', null, null], ], self::EXCEPTION_INVALID_FIELD_NAME => [ ['-143', null, null], ], self::EXCEPTION_NON_UNIQUE_FIELD_NAME => [ ['-144', null, null], ], self::EXCEPTION_NOT_NULL_CONSTRAINT_VIOLATION => [ ['-184', null, null], ['-195', null, null], ], self::EXCEPTION_SYNTAX_ERROR => [ ['-131', null, null], ], self::EXCEPTION_TABLE_EXISTS => [ ['-110', null, null], ], self::EXCEPTION_TABLE_NOT_FOUND => [ ['-141', null, null], ['-1041', null, null], ], self::EXCEPTION_UNIQUE_CONSTRAINT_VIOLATION => [ ['-193', null, null], ['-196', null, null], ], self::EXCEPTION_DEADLOCK => [ ['-306', null, null], ['-307', null, null], ['-684', null, null], ], self::EXCEPTION_LOCK_WAIT_TIMEOUT => [ ['-210', null, null], ['-1175', null, null], ['-1281', null, null], ], ]; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Driver/AbstractSQLServerDriverTest.php000066400000000000000000000050311360544566000311060ustar00rootroot00000000000000getMockForAbstractClass(AbstractSQLServerDriver::class); } protected function createPlatform() : AbstractPlatform { return new SQLServer2008Platform(); } protected function createSchemaManager(Connection $connection) : AbstractSchemaManager { return new SQLServerSchemaManager($connection); } /** * {@inheritDoc} */ protected function getDatabasePlatformsForVersions() : array { return [ ['9', SQLServerPlatform::class], ['9.00', SQLServerPlatform::class], ['9.00.0', SQLServerPlatform::class], ['9.00.1398', SQLServerPlatform::class], ['9.00.1398.99', SQLServerPlatform::class], ['9.00.1399', SQLServer2005Platform::class], ['9.00.1399.0', SQLServer2005Platform::class], ['9.00.1399.99', SQLServer2005Platform::class], ['9.00.1400', SQLServer2005Platform::class], ['9.10', SQLServer2005Platform::class], ['9.10.9999', SQLServer2005Platform::class], ['10.00.1599', SQLServer2005Platform::class], ['10.00.1599.99', SQLServer2005Platform::class], ['10.00.1600', SQLServer2008Platform::class], ['10.00.1600.0', SQLServer2008Platform::class], ['10.00.1600.99', SQLServer2008Platform::class], ['10.00.1601', SQLServer2008Platform::class], ['10.10', SQLServer2008Platform::class], ['10.10.9999', SQLServer2008Platform::class], ['11.00.2099', SQLServer2008Platform::class], ['11.00.2099.99', SQLServer2008Platform::class], ['11.00.2100', SQLServer2012Platform::class], ['11.00.2100.0', SQLServer2012Platform::class], ['11.00.2100.99', SQLServer2012Platform::class], ['11.00.2101', SQLServer2012Platform::class], ['12', SQLServer2012Platform::class], ]; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Driver/AbstractSQLiteDriverTest.php000066400000000000000000000052421360544566000304250ustar00rootroot00000000000000 'foo', 'password' => 'bar', 'dbname' => 'baz', 'path' => 'bloo', ]; $connection = $this->getConnectionMock(); $connection->expects($this->once()) ->method('getParams') ->will($this->returnValue($params)); self::assertSame($params['path'], $this->driver->getDatabase($connection)); } protected function createDriver() : Driver { return $this->getMockForAbstractClass(AbstractSQLiteDriver::class); } protected function createPlatform() : AbstractPlatform { return new SqlitePlatform(); } protected function createSchemaManager(Connection $connection) : AbstractSchemaManager { return new SqliteSchemaManager($connection); } /** * {@inheritDoc} */ protected static function getExceptionConversionData() : array { return [ self::EXCEPTION_CONNECTION => [ [null, null, 'unable to open database file'], ], self::EXCEPTION_INVALID_FIELD_NAME => [ [null, null, 'has no column named'], ], self::EXCEPTION_NON_UNIQUE_FIELD_NAME => [ [null, null, 'ambiguous column name'], ], self::EXCEPTION_NOT_NULL_CONSTRAINT_VIOLATION => [ [null, null, 'may not be NULL'], ], self::EXCEPTION_READ_ONLY => [ [null, null, 'attempt to write a readonly database'], ], self::EXCEPTION_SYNTAX_ERROR => [ [null, null, 'syntax error'], ], self::EXCEPTION_TABLE_EXISTS => [ [null, null, 'already exists'], ], self::EXCEPTION_TABLE_NOT_FOUND => [ [null, null, 'no such table:'], ], self::EXCEPTION_UNIQUE_CONSTRAINT_VIOLATION => [ [null, null, 'must be unique'], [null, null, 'is not unique'], [null, null, 'are not unique'], ], self::EXCEPTION_LOCK_WAIT_TIMEOUT => [ [null, null, 'database is locked'], ], ]; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Driver/DrizzlePDOMySql/000077500000000000000000000000001360544566000260245ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Driver/DrizzlePDOMySql/DriverTest.php000066400000000000000000000027051360544566000306340ustar00rootroot00000000000000driver->getName()); } public function testThrowsExceptionOnCreatingDatabasePlatformsForInvalidVersion() : void { $this->markTestSkipped('This test does not work on Drizzle as it is not version aware.'); } protected function createDriver() : DriverInterface { return new Driver(); } protected function createPlatform() : AbstractPlatform { return new DrizzlePlatform(); } protected function createSchemaManager(Connection $connection) : AbstractSchemaManager { return new DrizzleSchemaManager($connection); } /** * @return mixed[][] */ protected function getDatabasePlatformsForVersions() : array { return [ ['foo', DrizzlePlatform::class], ['bar', DrizzlePlatform::class], ['baz', DrizzlePlatform::class], ]; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Driver/IBMDB2/000077500000000000000000000000001360544566000237475ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Driver/IBMDB2/DB2ConnectionTest.php000066400000000000000000000016351360544566000277140ustar00rootroot00000000000000markTestSkipped('ibm_db2 is not installed.'); } parent::setUp(); $this->connectionMock = $this->getMockBuilder(DB2Connection::class) ->disableOriginalConstructor() ->getMockForAbstractClass(); } public function testDoesNotRequireQueryForServerVersion() : void { self::assertFalse($this->connectionMock->requiresQueryForServerVersion()); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Driver/IBMDB2/DB2DriverTest.php000066400000000000000000000007271360544566000270510ustar00rootroot00000000000000driver->getName()); } protected function createDriver() : DriverInterface { return new DB2Driver(); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Driver/Mysqli/000077500000000000000000000000001360544566000243265ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Driver/Mysqli/DriverTest.php000066400000000000000000000007211360544566000271320ustar00rootroot00000000000000driver->getName()); } protected function createDriver() : DriverInterface { return new Driver(); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Driver/Mysqli/MysqliConnectionTest.php000066400000000000000000000037001360544566000311750ustar00rootroot00000000000000markTestSkipped('mysqli is not installed.'); } parent::setUp(); if (! $this->connection->getDatabasePlatform() instanceof MySqlPlatform) { $this->markTestSkipped('MySQL only test.'); } $this->connectionMock = $this->getMockBuilder(MysqliConnection::class) ->disableOriginalConstructor() ->getMockForAbstractClass(); } public function testDoesNotRequireQueryForServerVersion() : void { self::assertFalse($this->connectionMock->requiresQueryForServerVersion()); } public function testRestoresErrorHandlerOnException() : void { $handler = static function () : bool { self::fail('Never expected this to be called'); }; $default_handler = set_error_handler($handler); try { new MysqliConnection(['host' => '255.255.255.255'], 'user', 'pass'); self::fail('An exception was supposed to be raised'); } catch (MysqliException $e) { self::assertSame('Network is unreachable', $e->getMessage()); } self::assertSame($handler, set_error_handler($default_handler), 'Restoring error handler failed.'); restore_error_handler(); restore_error_handler(); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Driver/OCI8/000077500000000000000000000000001360544566000235525ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Driver/OCI8/DriverTest.php000066400000000000000000000007151360544566000263610ustar00rootroot00000000000000driver->getName()); } protected function createDriver() : DriverInterface { return new Driver(); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Driver/OCI8/OCI8ConnectionTest.php000066400000000000000000000016241360544566000276500ustar00rootroot00000000000000markTestSkipped('oci8 is not installed.'); } parent::setUp(); $this->connectionMock = $this->getMockBuilder(OCI8Connection::class) ->disableOriginalConstructor() ->getMockForAbstractClass(); } public function testDoesNotRequireQueryForServerVersion() : void { self::assertFalse($this->connectionMock->requiresQueryForServerVersion()); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Driver/OCI8/OCI8StatementTest.php000066400000000000000000000077121360544566000275210ustar00rootroot00000000000000markTestSkipped('oci8 is not installed.'); } parent::setUp(); } /** * This scenario shows that when the first parameter is not null * it properly sets $hasZeroIndex to 1 and calls bindValue starting at 1. * * This also verifies that the statement will check with the connection to * see what the current execution mode is. * * The expected exception is due to oci_execute failing due to no valid connection. * * @param mixed[] $params * * @dataProvider executeDataProvider */ public function testExecute(array $params) : void { $statement = $this->getMockBuilder(OCI8Statement::class) ->onlyMethods(['bindValue', 'errorInfo']) ->disableOriginalConstructor() ->getMock(); $statement->expects($this->at(0)) ->method('bindValue') ->with( $this->equalTo(1), $this->equalTo($params[0]) ); $statement->expects($this->at(1)) ->method('bindValue') ->with( $this->equalTo(2), $this->equalTo($params[1]) ); $statement->expects($this->at(2)) ->method('bindValue') ->with( $this->equalTo(3), $this->equalTo($params[2]) ); // the return value is irrelevant to the test // but it has to be compatible with the method signature $statement->method('errorInfo') ->willReturn(false); // can't pass to constructor since we don't have a real database handle, // but execute must check the connection for the executeMode $conn = $this->getMockBuilder(OCI8Connection::class) ->onlyMethods(['getExecuteMode']) ->disableOriginalConstructor() ->getMock(); $conn->expects($this->once()) ->method('getExecuteMode'); $reflProperty = new ReflectionProperty($statement, '_conn'); $reflProperty->setAccessible(true); $reflProperty->setValue($statement, $conn); $this->expectException(OCI8Exception::class); $statement->execute($params); } /** * @return array> */ public static function executeDataProvider() : iterable { return [ // $hasZeroIndex = isset($params[0]); == true [ [0 => 'test', 1 => null, 2 => 'value'], ], // $hasZeroIndex = isset($params[0]); == false [ [0 => null, 1 => 'test', 2 => 'value'], ], ]; } /** * @dataProvider nonTerminatedLiteralProvider */ public function testConvertNonTerminatedLiteral(string $sql, string $message) : void { $this->expectException(OCI8Exception::class); $this->expectExceptionMessageRegExp($message); OCI8Statement::convertPositionalToNamedPlaceholders($sql); } /** * @return array> */ public static function nonTerminatedLiteralProvider() : iterable { return [ 'no-matching-quote' => [ "SELECT 'literal FROM DUAL", '/offset 7/', ], 'no-matching-double-quote' => [ 'SELECT 1 "COL1 FROM DUAL', '/offset 9/', ], 'incorrect-escaping-syntax' => [ "SELECT 'quoted \\'string' FROM DUAL", '/offset 23/', ], ]; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Driver/PDOExceptionTest.php000066400000000000000000000033051360544566000267230ustar00rootroot00000000000000markTestSkipped('PDO is not installed.'); } parent::setUp(); $this->wrappedException = new \PDOException(self::MESSAGE, self::SQLSTATE); $this->wrappedException->errorInfo = [self::SQLSTATE, self::ERROR_CODE]; $this->exception = new PDOException($this->wrappedException); } public function testReturnsCode() : void { self::assertSame(self::SQLSTATE, $this->exception->getCode()); } public function testReturnsErrorCode() : void { self::assertSame(self::ERROR_CODE, $this->exception->getErrorCode()); } public function testReturnsMessage() : void { self::assertSame(self::MESSAGE, $this->exception->getMessage()); } public function testReturnsSQLState() : void { self::assertSame(self::SQLSTATE, $this->exception->getSQLState()); } public function testOriginalExceptionIsInChain() : void { self::assertSame($this->wrappedException, $this->exception->getPrevious()); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Driver/PDOIbm/000077500000000000000000000000001360544566000241225ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Driver/PDOIbm/DriverTest.php000066400000000000000000000007161360544566000267320ustar00rootroot00000000000000driver->getName()); } protected function createDriver() : DriverInterface { return new Driver(); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Driver/PDOMySql/000077500000000000000000000000001360544566000244605ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Driver/PDOMySql/DriverTest.php000066400000000000000000000007301360544566000272640ustar00rootroot00000000000000driver->getName()); } protected function createDriver() : DriverInterface { return new Driver(); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Driver/PDOOracle/000077500000000000000000000000001360544566000246205ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Driver/PDOOracle/DriverTest.php000066400000000000000000000007351360544566000274310ustar00rootroot00000000000000driver->getName()); } protected function createDriver() : DriverInterface { return new Driver(); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Driver/PDOPgSql/000077500000000000000000000000001360544566000244415ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Driver/PDOPgSql/DriverTest.php000066400000000000000000000070511360544566000272500ustar00rootroot00000000000000driver->getName()); } /** * @group DBAL-920 */ public function testConnectionDisablesPreparesOnPhp56() : void { $this->skipWhenNotUsingPhp56AndPdoPgsql(); $connection = $this->createDriver()->connect( [ 'host' => $GLOBALS['db_host'], 'port' => $GLOBALS['db_port'], ], $GLOBALS['db_username'], $GLOBALS['db_password'] ); self::assertInstanceOf(PDOConnection::class, $connection); try { self::assertTrue($connection->getAttribute(PDO::PGSQL_ATTR_DISABLE_PREPARES)); } catch (PDOException $ignored) { /** @link https://bugs.php.net/bug.php?id=68371 */ $this->markTestIncomplete('See https://bugs.php.net/bug.php?id=68371'); } } /** * @group DBAL-920 */ public function testConnectionDoesNotDisablePreparesOnPhp56WhenAttributeDefined() : void { $this->skipWhenNotUsingPhp56AndPdoPgsql(); $connection = $this->createDriver()->connect( [ 'host' => $GLOBALS['db_host'], 'port' => $GLOBALS['db_port'], ], $GLOBALS['db_username'], $GLOBALS['db_password'], [PDO::PGSQL_ATTR_DISABLE_PREPARES => false] ); self::assertInstanceOf(PDOConnection::class, $connection); try { self::assertNotSame(true, $connection->getAttribute(PDO::PGSQL_ATTR_DISABLE_PREPARES)); } catch (PDOException $ignored) { /** @link https://bugs.php.net/bug.php?id=68371 */ $this->markTestIncomplete('See https://bugs.php.net/bug.php?id=68371'); } } /** * @group DBAL-920 */ public function testConnectionDisablePreparesOnPhp56WhenDisablePreparesIsExplicitlyDefined() : void { $this->skipWhenNotUsingPhp56AndPdoPgsql(); $connection = $this->createDriver()->connect( [ 'host' => $GLOBALS['db_host'], 'port' => $GLOBALS['db_port'], ], $GLOBALS['db_username'], $GLOBALS['db_password'], [PDO::PGSQL_ATTR_DISABLE_PREPARES => true] ); self::assertInstanceOf(PDOConnection::class, $connection); try { self::assertTrue($connection->getAttribute(PDO::PGSQL_ATTR_DISABLE_PREPARES)); } catch (PDOException $ignored) { /** @link https://bugs.php.net/bug.php?id=68371 */ $this->markTestIncomplete('See https://bugs.php.net/bug.php?id=68371'); } } /** * {@inheritDoc} */ protected function createDriver() : DriverInterface { return new Driver(); } private function skipWhenNotUsingPhp56AndPdoPgsql() : void { if (! defined('PDO::PGSQL_ATTR_DISABLE_PREPARES')) { $this->markTestSkipped('Test requires PHP 5.6+'); } if (isset($GLOBALS['db_type']) && $GLOBALS['db_type'] === 'pdo_pgsql') { return; } $this->markTestSkipped('Test enabled only when using pdo_pgsql specific phpunit.xml'); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Driver/PDOSqlite/000077500000000000000000000000001360544566000246545ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Driver/PDOSqlite/DriverTest.php000066400000000000000000000007351360544566000274650ustar00rootroot00000000000000driver->getName()); } protected function createDriver() : DriverInterface { return new Driver(); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Driver/PDOSqlsrv/000077500000000000000000000000001360544566000247055ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Driver/PDOSqlsrv/DriverTest.php000066400000000000000000000007431360544566000275150ustar00rootroot00000000000000driver->getName()); } protected function createDriver() : DriverInterface { return new Driver(); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Driver/SQLAnywhere/000077500000000000000000000000001360544566000252125ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Driver/SQLAnywhere/DriverTest.php000066400000000000000000000007541360544566000300240ustar00rootroot00000000000000driver->getName()); } protected function createDriver() : DriverInterface { return new Driver(); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Driver/SQLAnywhere/SQLAnywhereConnectionTest.php000066400000000000000000000017141360544566000327500ustar00rootroot00000000000000markTestSkipped('sqlanywhere is not installed.'); } parent::setUp(); $this->connectionMock = $this->getMockBuilder(SQLAnywhereConnection::class) ->disableOriginalConstructor() ->getMockForAbstractClass(); } public function testRequiresQueryForServerVersion() : void { self::assertTrue($this->connectionMock->requiresQueryForServerVersion()); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Driver/SQLSrv/000077500000000000000000000000001360544566000242025ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Driver/SQLSrv/DriverTest.php000066400000000000000000000007311360544566000270070ustar00rootroot00000000000000driver->getName()); } protected function createDriver() : DriverInterface { return new Driver(); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Driver/SQLSrv/SQLSrvConnectionTest.php000066400000000000000000000016461360544566000307340ustar00rootroot00000000000000markTestSkipped('sqlsrv is not installed.'); } parent::setUp(); $this->connectionMock = $this->getMockBuilder(SQLSrvConnection::class) ->disableOriginalConstructor() ->getMockForAbstractClass(); } public function testDoesNotRequireQueryForServerVersion() : void { self::assertFalse($this->connectionMock->requiresQueryForServerVersion()); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Driver/StatementIteratorTest.php000066400000000000000000000057611360544566000301100ustar00rootroot00000000000000createPartialMock($class, ['fetch', 'fetchAll', 'fetchColumn']); $stmt->expects($this->never())->method('fetch'); $stmt->expects($this->never())->method('fetchAll'); $stmt->expects($this->never())->method('fetchColumn'); $stmt->getIterator(); } public function testIteratorIterationCallsFetchOncePerStep() : void { $stmt = $this->createMock(Statement::class); $calls = 0; $this->configureStatement($stmt, $calls); $stmtIterator = new StatementIterator($stmt); $this->assertIterationCallsFetchOncePerStep($stmtIterator, $calls); } /** * @dataProvider statementProvider() */ public function testStatementIterationCallsFetchOncePerStep(string $class) : void { $stmt = $this->createPartialMock($class, ['fetch']); $calls = 0; $this->configureStatement($stmt, $calls); $this->assertIterationCallsFetchOncePerStep($stmt, $calls); } private function configureStatement(MockObject $stmt, int &$calls) : void { $values = ['foo', '', 'bar', '0', 'baz', 0, 'qux', null, 'quz', false, 'impossible']; $calls = 0; $stmt->expects($this->exactly(10)) ->method('fetch') ->willReturnCallback(static function () use ($values, &$calls) { $value = $values[$calls]; $calls++; return $value; }); } private function assertIterationCallsFetchOncePerStep(Traversable $iterator, int &$calls) : void { foreach ($iterator as $i => $_) { $this->assertEquals($i + 1, $calls); } } /** * @return string[][] */ public static function statementProvider() : iterable { if (extension_loaded('ibm_db2')) { yield [DB2Statement::class]; } yield [MysqliStatement::class]; if (extension_loaded('oci8')) { yield [OCI8Statement::class]; } yield [PortabilityStatement::class]; yield [SQLAnywhereStatement::class]; if (extension_loaded('sqlsrv')) { yield [SQLSrvStatement::class]; } } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/DriverManagerTest.php000066400000000000000000000436151360544566000257250ustar00rootroot00000000000000expectException(DBALException::class); DriverManager::getConnection(['pdo' => 'test']); } /** * @requires extension pdo_sqlite */ public function testValidPdoInstance() : void { $conn = DriverManager::getConnection([ 'pdo' => new PDO('sqlite::memory:'), ]); self::assertEquals('sqlite', $conn->getDatabasePlatform()->getName()); } /** * @group DBAL-32 * @requires extension pdo_sqlite */ public function testPdoInstanceSetErrorMode() : void { $pdo = new PDO('sqlite::memory:'); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT); $options = ['pdo' => $pdo]; DriverManager::getConnection($options); self::assertEquals(PDO::ERRMODE_EXCEPTION, $pdo->getAttribute(PDO::ATTR_ERRMODE)); } public function testCheckParams() : void { $this->expectException(DBALException::class); DriverManager::getConnection([]); } public function testInvalidDriver() : void { $this->expectException(DBALException::class); DriverManager::getConnection(['driver' => 'invalid_driver']); } /** * @requires extension pdo_sqlite */ public function testCustomPlatform() : void { $platform = $this->createMock(AbstractPlatform::class); $options = [ 'pdo' => new PDO('sqlite::memory:'), 'platform' => $platform, ]; $conn = DriverManager::getConnection($options); self::assertSame($platform, $conn->getDatabasePlatform()); } /** * @requires extension pdo_sqlite */ public function testCustomWrapper() : void { $wrapper = $this->createMock(Connection::class); $wrapperClass = get_class($wrapper); $options = [ 'pdo' => new PDO('sqlite::memory:'), 'wrapperClass' => $wrapperClass, ]; $conn = DriverManager::getConnection($options); self::assertInstanceOf($wrapperClass, $conn); } /** * @requires extension pdo_sqlite */ public function testInvalidWrapperClass() : void { $this->expectException(DBALException::class); $options = [ 'pdo' => new PDO('sqlite::memory:'), 'wrapperClass' => stdClass::class, ]; DriverManager::getConnection($options); } public function testInvalidDriverClass() : void { $this->expectException(DBALException::class); $options = ['driverClass' => stdClass::class]; DriverManager::getConnection($options); } public function testValidDriverClass() : void { $options = ['driverClass' => PDOMySQLDriver::class]; $conn = DriverManager::getConnection($options); self::assertInstanceOf(PDOMySQLDriver::class, $conn->getDriver()); } public function testDatabaseUrlMasterSlave() : void { $options = [ 'driver' => 'pdo_mysql', 'master' => ['url' => 'mysql://foo:bar@localhost:11211/baz'], 'slaves' => [ 'slave1' => ['url' => 'mysql://foo:bar@localhost:11211/baz_slave'], ], 'wrapperClass' => MasterSlaveConnection::class, ]; $conn = DriverManager::getConnection($options); $params = $conn->getParams(); self::assertInstanceOf(PDOMySQLDriver::class, $conn->getDriver()); $expected = [ 'user' => 'foo', 'password' => 'bar', 'host' => 'localhost', 'port' => 11211, ]; foreach ($expected as $key => $value) { self::assertEquals($value, $params['master'][$key]); self::assertEquals($value, $params['slaves']['slave1'][$key]); } self::assertEquals('baz', $params['master']['dbname']); self::assertEquals('baz_slave', $params['slaves']['slave1']['dbname']); } public function testDatabaseUrlShard() : void { $options = [ 'driver' => 'pdo_mysql', 'shardChoser' => MultiTenantShardChoser::class, 'global' => ['url' => 'mysql://foo:bar@localhost:11211/baz'], 'shards' => [ [ 'id' => 1, 'url' => 'mysql://foo:bar@localhost:11211/baz_slave', ], ], 'wrapperClass' => PoolingShardConnection::class, ]; $conn = DriverManager::getConnection($options); $params = $conn->getParams(); self::assertInstanceOf(PDOMySQLDriver::class, $conn->getDriver()); $expected = [ 'user' => 'foo', 'password' => 'bar', 'host' => 'localhost', 'port' => 11211, ]; foreach ($expected as $key => $value) { self::assertEquals($value, $params['global'][$key]); self::assertEquals($value, $params['shards'][0][$key]); } self::assertEquals('baz', $params['global']['dbname']); self::assertEquals('baz_slave', $params['shards'][0]['dbname']); } /** * @param mixed $url * @param mixed $expected * * @dataProvider databaseUrls */ public function testDatabaseUrl($url, $expected) : void { $options = is_array($url) ? $url : ['url' => $url]; if (isset($options['pdo'])) { if (! extension_loaded('pdo')) { $this->markTestSkipped('PDO is not installed'); } $options['pdo'] = $this->createMock(PDO::class); } $options = is_array($url) ? $url : ['url' => $url]; if ($expected === false) { $this->expectException(DBALException::class); } $conn = DriverManager::getConnection($options); $params = $conn->getParams(); foreach ($expected as $key => $value) { if (in_array($key, ['pdo', 'driver', 'driverClass'], true)) { self::assertInstanceOf($value, $conn->getDriver()); } else { self::assertEquals($value, $params[$key]); } } } /** * @return array> */ public function databaseUrls() : iterable { $driver = $this->createMock(Driver::class); $driverClass = get_class($driver); return [ 'simple URL' => [ 'mysql://foo:bar@localhost/baz', [ 'user' => 'foo', 'password' => 'bar', 'host' => 'localhost', 'dbname' => 'baz', 'driver' => PDOMySQLDriver::class, ], ], 'simple URL with port' => [ 'mysql://foo:bar@localhost:11211/baz', [ 'user' => 'foo', 'password' => 'bar', 'host' => 'localhost', 'port' => 11211, 'dbname' => 'baz', 'driver' => PDOMySQLDriver::class, ], ], 'sqlite relative URL with host' => [ 'sqlite://localhost/foo/dbname.sqlite', [ 'path' => 'foo/dbname.sqlite', 'driver' => PDOSqliteDriver::class, ], ], 'sqlite absolute URL with host' => [ 'sqlite://localhost//tmp/dbname.sqlite', [ 'path' => '/tmp/dbname.sqlite', 'driver' => PDOSqliteDriver::class, ], ], 'sqlite relative URL without host' => [ 'sqlite:///foo/dbname.sqlite', [ 'path' => 'foo/dbname.sqlite', 'driver' => PDOSqliteDriver::class, ], ], 'sqlite absolute URL without host' => [ 'sqlite:////tmp/dbname.sqlite', [ 'path' => '/tmp/dbname.sqlite', 'driver' => PDOSqliteDriver::class, ], ], 'sqlite memory' => [ 'sqlite:///:memory:', [ 'memory' => true, 'driver' => PDOSqliteDriver::class, ], ], 'sqlite memory with host' => [ 'sqlite://localhost/:memory:', [ 'memory' => true, 'driver' => PDOSqliteDriver::class, ], ], 'params parsed from URL override individual params' => [ [ 'url' => 'mysql://foo:bar@localhost/baz', 'password' => 'lulz', ], [ 'user' => 'foo', 'password' => 'bar', 'host' => 'localhost', 'dbname' => 'baz', 'driver' => PDOMySQLDriver::class, ], ], 'params not parsed from URL but individual params are preserved' => [ [ 'url' => 'mysql://foo:bar@localhost/baz', 'port' => 1234, ], [ 'user' => 'foo', 'password' => 'bar', 'host' => 'localhost', 'port' => 1234, 'dbname' => 'baz', 'driver' => PDOMySQLDriver::class, ], ], 'query params from URL are used as extra params' => [ 'url' => 'mysql://foo:bar@localhost/dbname?charset=UTF-8', ['charset' => 'UTF-8'], ], 'simple URL with fallthrough scheme not defined in map' => [ 'sqlsrv://foo:bar@localhost/baz', [ 'user' => 'foo', 'password' => 'bar', 'host' => 'localhost', 'dbname' => 'baz', 'driver' => SQLSrvDriver::class, ], ], 'simple URL with fallthrough scheme containing underscores fails' => [ 'drizzle_pdo_mysql://foo:bar@localhost/baz', false, ], 'simple URL with fallthrough scheme containing dashes works' => [ 'drizzle-pdo-mysql://foo:bar@localhost/baz', [ 'user' => 'foo', 'password' => 'bar', 'host' => 'localhost', 'dbname' => 'baz', 'driver' => DrizzlePDOMySqlDriver::class, ], ], 'simple URL with percent encoding' => [ 'mysql://foo%3A:bar%2F@localhost/baz+baz%40', [ 'user' => 'foo:', 'password' => 'bar/', 'host' => 'localhost', 'dbname' => 'baz+baz@', 'driver' => PDOMySQLDriver::class, ], ], 'simple URL with percent sign in password' => [ 'mysql://foo:bar%25bar@localhost/baz', [ 'user' => 'foo', 'password' => 'bar%bar', 'host' => 'localhost', 'dbname' => 'baz', 'driver' => PDOMySQLDriver::class, ], ], // DBAL-1234 'URL without scheme and without any driver information' => [ ['url' => '//foo:bar@localhost/baz'], false, ], 'URL without scheme but default PDO driver' => [ [ 'url' => '//foo:bar@localhost/baz', 'pdo' => true, ], false, ], 'URL without scheme but default driver' => [ [ 'url' => '//foo:bar@localhost/baz', 'driver' => 'pdo_mysql', ], [ 'user' => 'foo', 'password' => 'bar', 'host' => 'localhost', 'dbname' => 'baz', 'driver' => PDOMySQLDriver::class, ], ], 'URL without scheme but custom driver' => [ [ 'url' => '//foo:bar@localhost/baz', 'driverClass' => $driverClass, ], [ 'user' => 'foo', 'password' => 'bar', 'host' => 'localhost', 'dbname' => 'baz', 'driverClass' => $driverClass, ], ], 'URL without scheme but default PDO driver and default driver' => [ [ 'url' => '//foo:bar@localhost/baz', 'pdo' => true, 'driver' => 'pdo_mysql', ], [ 'user' => 'foo', 'password' => 'bar', 'host' => 'localhost', 'dbname' => 'baz', 'driver' => PDOMySQLDriver::class, ], ], 'URL without scheme but driver and custom driver' => [ [ 'url' => '//foo:bar@localhost/baz', 'driver' => 'pdo_mysql', 'driverClass' => $driverClass, ], [ 'user' => 'foo', 'password' => 'bar', 'host' => 'localhost', 'dbname' => 'baz', 'driverClass' => $driverClass, ], ], 'URL with default PDO driver' => [ [ 'url' => 'mysql://foo:bar@localhost/baz', 'pdo' => true, ], [ 'user' => 'foo', 'password' => 'bar', 'host' => 'localhost', 'dbname' => 'baz', 'driver' => PDOMySQLDriver::class, ], ], 'URL with default driver' => [ [ 'url' => 'mysql://foo:bar@localhost/baz', 'driver' => 'sqlite', ], [ 'user' => 'foo', 'password' => 'bar', 'host' => 'localhost', 'dbname' => 'baz', 'driver' => PDOMySQLDriver::class, ], ], 'URL with default custom driver' => [ [ 'url' => 'mysql://foo:bar@localhost/baz', 'driverClass' => $driverClass, ], [ 'user' => 'foo', 'password' => 'bar', 'host' => 'localhost', 'dbname' => 'baz', 'driver' => PDOMySQLDriver::class, ], ], 'URL with default PDO driver and default driver' => [ [ 'url' => 'mysql://foo:bar@localhost/baz', 'pdo' => true, 'driver' => 'sqlite', ], [ 'user' => 'foo', 'password' => 'bar', 'host' => 'localhost', 'dbname' => 'baz', 'driver' => PDOMySQLDriver::class, ], ], 'URL with default driver and default custom driver' => [ [ 'url' => 'mysql://foo:bar@localhost/baz', 'driver' => 'sqlite', 'driverClass' => $driverClass, ], [ 'user' => 'foo', 'password' => 'bar', 'host' => 'localhost', 'dbname' => 'baz', 'driver' => PDOMySQLDriver::class, ], ], 'URL with default PDO driver and default driver and default custom driver' => [ [ 'url' => 'mysql://foo:bar@localhost/baz', 'pdo' => true, 'driver' => 'sqlite', 'driverClass' => $driverClass, ], [ 'user' => 'foo', 'password' => 'bar', 'host' => 'localhost', 'dbname' => 'baz', 'driver' => PDOMySQLDriver::class, ], ], ]; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Events/000077500000000000000000000000001360544566000230615ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Events/MysqlSessionInitTest.php000066400000000000000000000016531360544566000277340ustar00rootroot00000000000000createMock(Connection::class); $connectionMock->expects($this->once()) ->method('executeUpdate') ->with($this->equalTo('SET NAMES foo COLLATE bar')); $eventArgs = new ConnectionEventArgs($connectionMock); $listener = new MysqlSessionInit('foo', 'bar'); $listener->postConnect($eventArgs); } public function testGetSubscribedEvents() : void { $listener = new MysqlSessionInit(); self::assertEquals([Events::postConnect], $listener->getSubscribedEvents()); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Events/OracleSessionInitTest.php000066400000000000000000000034701360544566000300330ustar00rootroot00000000000000createMock(Connection::class); $connectionMock->expects($this->once()) ->method('executeUpdate') ->with($this->isType('string')); $eventArgs = new ConnectionEventArgs($connectionMock); $listener = new OracleSessionInit(); $listener->postConnect($eventArgs); } /** * @group DBAL-1824 * @dataProvider getPostConnectWithSessionParameterValuesData */ public function testPostConnectQuotesSessionParameterValues(string $name, string $value) : void { $connectionMock = $this->getMockBuilder(Connection::class) ->disableOriginalConstructor() ->getMock(); $connectionMock->expects($this->once()) ->method('executeUpdate') ->with($this->stringContains(sprintf('%s = %s', $name, $value))); $eventArgs = new ConnectionEventArgs($connectionMock); $listener = new OracleSessionInit([$name => $value]); $listener->postConnect($eventArgs); } /** * @return array> */ public static function getPostConnectWithSessionParameterValuesData() : iterable { return [ ['CURRENT_SCHEMA', 'foo'], ]; } public function testGetSubscribedEvents() : void { $listener = new OracleSessionInit(); self::assertEquals([Events::postConnect], $listener->getSubscribedEvents()); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Events/SQLSessionInitTest.php000066400000000000000000000021051360544566000272570ustar00rootroot00000000000000createMock(Connection::class); $connectionMock->expects($this->once()) ->method('exec') ->with($this->equalTo("SET SEARCH_PATH TO foo, public, TIMEZONE TO 'Europe/Berlin'")); $eventArgs = new ConnectionEventArgs($connectionMock); $listener = new SQLSessionInit("SET SEARCH_PATH TO foo, public, TIMEZONE TO 'Europe/Berlin'"); $listener->postConnect($eventArgs); } public function testGetSubscribedEvents() : void { $listener = new SQLSessionInit("SET SEARCH_PATH TO foo, public, TIMEZONE TO 'Europe/Berlin'"); self::assertEquals([Events::postConnect], $listener->getSubscribedEvents()); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Exception/000077500000000000000000000000001360544566000235535ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Exception/InvalidArgumentExceptionTest.php000066400000000000000000000012131360544566000320710ustar00rootroot00000000000000getMessage()); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/000077500000000000000000000000001360544566000237175ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/BlobTest.php000066400000000000000000000124331360544566000261510ustar00rootroot00000000000000connection->getDriver() instanceof PDOOracleDriver) { // inserting BLOBs as streams on Oracle requires Oracle-specific SQL syntax which is currently not supported // see http://php.net/manual/en/pdo.lobs.php#example-1035 $this->markTestSkipped('DBAL doesn\'t support storing LOBs represented as streams using PDO_OCI'); } $table = new Table('blob_table'); $table->addColumn('id', 'integer'); $table->addColumn('clobfield', 'text'); $table->addColumn('blobfield', 'blob'); $table->setPrimaryKey(['id']); $sm = $this->connection->getSchemaManager(); $sm->dropAndCreateTable($table); } public function testInsert() : void { $ret = $this->connection->insert('blob_table', [ 'id' => 1, 'clobfield' => 'test', 'blobfield' => 'test', ], [ ParameterType::INTEGER, ParameterType::STRING, ParameterType::LARGE_OBJECT, ]); self::assertEquals(1, $ret); } public function testInsertProcessesStream() : void { // https://github.com/doctrine/dbal/issues/3290 if ($this->connection->getDriver() instanceof OCI8Driver) { $this->markTestIncomplete('The oci8 driver does not support stream resources as parameters'); } $longBlob = str_repeat('x', 4 * 8192); // send 4 chunks $this->connection->insert('blob_table', [ 'id' => 1, 'clobfield' => 'ignored', 'blobfield' => fopen('data://text/plain,' . $longBlob, 'r'), ], [ ParameterType::INTEGER, ParameterType::STRING, ParameterType::LARGE_OBJECT, ]); $this->assertBlobContains($longBlob); } public function testSelect() : void { $this->connection->insert('blob_table', [ 'id' => 1, 'clobfield' => 'test', 'blobfield' => 'test', ], [ ParameterType::INTEGER, ParameterType::STRING, ParameterType::LARGE_OBJECT, ]); $this->assertBlobContains('test'); } public function testUpdate() : void { $this->connection->insert('blob_table', [ 'id' => 1, 'clobfield' => 'test', 'blobfield' => 'test', ], [ ParameterType::INTEGER, ParameterType::STRING, ParameterType::LARGE_OBJECT, ]); $this->connection->update('blob_table', ['blobfield' => 'test2'], ['id' => 1], [ ParameterType::LARGE_OBJECT, ParameterType::INTEGER, ]); $this->assertBlobContains('test2'); } public function testUpdateProcessesStream() : void { // https://github.com/doctrine/dbal/issues/3290 if ($this->connection->getDriver() instanceof OCI8Driver) { $this->markTestIncomplete('The oci8 driver does not support stream resources as parameters'); } $this->connection->insert('blob_table', [ 'id' => 1, 'clobfield' => 'ignored', 'blobfield' => 'test', ], [ ParameterType::INTEGER, ParameterType::STRING, ParameterType::LARGE_OBJECT, ]); $this->connection->update('blob_table', [ 'id' => 1, 'blobfield' => fopen('data://text/plain,test2', 'r'), ], ['id' => 1], [ ParameterType::INTEGER, ParameterType::LARGE_OBJECT, ]); $this->assertBlobContains('test2'); } public function testBindParamProcessesStream() : void { if ($this->connection->getDriver() instanceof OCI8Driver) { $this->markTestIncomplete('The oci8 driver does not support stream resources as parameters'); } $stmt = $this->connection->prepare("INSERT INTO blob_table(id, clobfield, blobfield) VALUES (1, 'ignored', ?)"); $stream = null; $stmt->bindParam(1, $stream, ParameterType::LARGE_OBJECT); // Bind param does late binding (bind by reference), so create the stream only now: $stream = fopen('data://text/plain,test', 'r'); $stmt->execute(); $this->assertBlobContains('test'); } private function assertBlobContains(string $text) : void { $rows = $this->connection->query('SELECT blobfield FROM blob_table')->fetchAll(FetchMode::COLUMN); self::assertCount(1, $rows); $blobValue = Type::getType('blob')->convertToPHPValue($rows[0], $this->connection->getDatabasePlatform()); self::assertIsResource($blobValue); self::assertEquals($text, stream_get_contents($blobValue)); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/ConnectionTest.php000066400000000000000000000320071360544566000273710ustar00rootroot00000000000000resetSharedConn(); parent::setUp(); } protected function tearDown() : void { if (file_exists('/tmp/test_nesting.sqlite')) { unlink('/tmp/test_nesting.sqlite'); } parent::tearDown(); $this->resetSharedConn(); } public function testGetWrappedConnection() : void { self::assertInstanceOf(DriverConnection::class, $this->connection->getWrappedConnection()); } public function testCommitWithRollbackOnlyThrowsException() : void { $this->connection->beginTransaction(); $this->connection->setRollbackOnly(); $this->expectException(ConnectionException::class); $this->connection->commit(); } public function testTransactionNestingBehavior() : void { try { $this->connection->beginTransaction(); self::assertEquals(1, $this->connection->getTransactionNestingLevel()); try { $this->connection->beginTransaction(); self::assertEquals(2, $this->connection->getTransactionNestingLevel()); throw new Exception(); $this->connection->commit(); // never reached } catch (Throwable $e) { $this->connection->rollBack(); self::assertEquals(1, $this->connection->getTransactionNestingLevel()); //no rethrow } self::assertTrue($this->connection->isRollbackOnly()); $this->connection->commit(); // should throw exception $this->fail('Transaction commit after failed nested transaction should fail.'); } catch (ConnectionException $e) { self::assertEquals(1, $this->connection->getTransactionNestingLevel()); $this->connection->rollBack(); self::assertEquals(0, $this->connection->getTransactionNestingLevel()); } $this->connection->beginTransaction(); $this->connection->close(); $this->connection->beginTransaction(); self::assertEquals(1, $this->connection->getTransactionNestingLevel()); } public function testTransactionNestingLevelIsResetOnReconnect() : void { if ($this->connection->getDatabasePlatform()->getName() === 'sqlite') { $params = $this->connection->getParams(); $params['memory'] = false; $params['path'] = '/tmp/test_nesting.sqlite'; $connection = DriverManager::getConnection( $params, $this->connection->getConfiguration(), $this->connection->getEventManager() ); } else { $connection = $this->connection; } $connection->executeQuery('CREATE TABLE test_nesting(test int not null)'); $this->connection->beginTransaction(); $this->connection->beginTransaction(); $connection->close(); // connection closed in runtime (for example if lost or another application logic) $connection->beginTransaction(); $connection->executeQuery('insert into test_nesting values (33)'); $connection->rollback(); self::assertEquals(0, $connection->fetchColumn('select count(*) from test_nesting')); } public function testTransactionNestingBehaviorWithSavepoints() : void { if (! $this->connection->getDatabasePlatform()->supportsSavepoints()) { $this->markTestSkipped('This test requires the platform to support savepoints.'); } $this->connection->setNestTransactionsWithSavepoints(true); try { $this->connection->beginTransaction(); self::assertEquals(1, $this->connection->getTransactionNestingLevel()); try { $this->connection->beginTransaction(); self::assertEquals(2, $this->connection->getTransactionNestingLevel()); $this->connection->beginTransaction(); self::assertEquals(3, $this->connection->getTransactionNestingLevel()); self::assertTrue($this->connection->commit()); self::assertEquals(2, $this->connection->getTransactionNestingLevel()); throw new Exception(); $this->connection->commit(); // never reached } catch (Throwable $e) { $this->connection->rollBack(); self::assertEquals(1, $this->connection->getTransactionNestingLevel()); //no rethrow } self::assertFalse($this->connection->isRollbackOnly()); try { $this->connection->setNestTransactionsWithSavepoints(false); $this->fail('Should not be able to disable savepoints in usage for nested transactions inside an open transaction.'); } catch (ConnectionException $e) { self::assertTrue($this->connection->getNestTransactionsWithSavepoints()); } $this->connection->commit(); // should not throw exception } catch (ConnectionException $e) { $this->fail('Transaction commit after failed nested transaction should not fail when using savepoints.'); $this->connection->rollBack(); } } public function testTransactionNestingBehaviorCantBeChangedInActiveTransaction() : void { if (! $this->connection->getDatabasePlatform()->supportsSavepoints()) { $this->markTestSkipped('This test requires the platform to support savepoints.'); } $this->connection->beginTransaction(); $this->expectException(ConnectionException::class); $this->connection->setNestTransactionsWithSavepoints(true); } public function testSetNestedTransactionsThroughSavepointsNotSupportedThrowsException() : void { if ($this->connection->getDatabasePlatform()->supportsSavepoints()) { $this->markTestSkipped('This test requires the platform not to support savepoints.'); } $this->expectException(ConnectionException::class); $this->expectExceptionMessage('Savepoints are not supported by this driver.'); $this->connection->setNestTransactionsWithSavepoints(true); } public function testCreateSavepointsNotSupportedThrowsException() : void { if ($this->connection->getDatabasePlatform()->supportsSavepoints()) { $this->markTestSkipped('This test requires the platform not to support savepoints.'); } $this->expectException(ConnectionException::class); $this->expectExceptionMessage('Savepoints are not supported by this driver.'); $this->connection->createSavepoint('foo'); } public function testReleaseSavepointsNotSupportedThrowsException() : void { if ($this->connection->getDatabasePlatform()->supportsSavepoints()) { $this->markTestSkipped('This test requires the platform not to support savepoints.'); } $this->expectException(ConnectionException::class); $this->expectExceptionMessage('Savepoints are not supported by this driver.'); $this->connection->releaseSavepoint('foo'); } public function testRollbackSavepointsNotSupportedThrowsException() : void { if ($this->connection->getDatabasePlatform()->supportsSavepoints()) { $this->markTestSkipped('This test requires the platform not to support savepoints.'); } $this->expectException(ConnectionException::class); $this->expectExceptionMessage('Savepoints are not supported by this driver.'); $this->connection->rollbackSavepoint('foo'); } public function testTransactionBehaviorWithRollback() : void { try { $this->connection->beginTransaction(); self::assertEquals(1, $this->connection->getTransactionNestingLevel()); throw new Exception(); $this->connection->commit(); // never reached } catch (Throwable $e) { self::assertEquals(1, $this->connection->getTransactionNestingLevel()); $this->connection->rollBack(); self::assertEquals(0, $this->connection->getTransactionNestingLevel()); } } public function testTransactionBehaviour() : void { try { $this->connection->beginTransaction(); self::assertEquals(1, $this->connection->getTransactionNestingLevel()); $this->connection->commit(); } catch (Throwable $e) { $this->connection->rollBack(); self::assertEquals(0, $this->connection->getTransactionNestingLevel()); } self::assertEquals(0, $this->connection->getTransactionNestingLevel()); } public function testTransactionalWithException() : void { try { $this->connection->transactional(static function ($conn) : void { /** @var Connection $conn */ $conn->executeQuery($conn->getDatabasePlatform()->getDummySelectSQL()); throw new RuntimeException('Ooops!'); }); $this->fail('Expected exception'); } catch (RuntimeException $expected) { self::assertEquals(0, $this->connection->getTransactionNestingLevel()); } } public function testTransactionalWithThrowable() : void { try { $this->connection->transactional(static function ($conn) : void { /** @var Connection $conn */ $conn->executeQuery($conn->getDatabasePlatform()->getDummySelectSQL()); throw new Error('Ooops!'); }); $this->fail('Expected exception'); } catch (Error $expected) { self::assertEquals(0, $this->connection->getTransactionNestingLevel()); } } public function testTransactional() : void { $res = $this->connection->transactional(static function ($conn) : void { /** @var Connection $conn */ $conn->executeQuery($conn->getDatabasePlatform()->getDummySelectSQL()); }); self::assertNull($res); } public function testTransactionalReturnValue() : void { $res = $this->connection->transactional(static function () { return 42; }); self::assertEquals(42, $res); } /** * Tests that the quote function accepts DBAL and PDO types. */ public function testQuote() : void { self::assertEquals( $this->connection->quote('foo', Types::STRING), $this->connection->quote('foo', ParameterType::STRING) ); } public function testPingDoesTriggersConnect() : void { self::assertTrue($this->connection->ping()); self::assertTrue($this->connection->isConnected()); } /** * @group DBAL-1025 */ public function testConnectWithoutExplicitDatabaseName() : void { if (in_array($this->connection->getDatabasePlatform()->getName(), ['oracle', 'db2'], true)) { $this->markTestSkipped('Platform does not support connecting without database name.'); } $params = $this->connection->getParams(); unset($params['dbname']); $connection = DriverManager::getConnection( $params, $this->connection->getConfiguration(), $this->connection->getEventManager() ); self::assertTrue($connection->connect()); $connection->close(); } /** * @group DBAL-990 */ public function testDeterminesDatabasePlatformWhenConnectingToNonExistentDatabase() : void { if (in_array($this->connection->getDatabasePlatform()->getName(), ['oracle', 'db2'], true)) { $this->markTestSkipped('Platform does not support connecting without database name.'); } $params = $this->connection->getParams(); $params['dbname'] = 'foo_bar'; $connection = DriverManager::getConnection( $params, $this->connection->getConfiguration(), $this->connection->getEventManager() ); self::assertInstanceOf(AbstractPlatform::class, $connection->getDatabasePlatform()); self::assertFalse($connection->isConnected()); self::assertSame($params, $connection->getParams()); $connection->close(); } /** * @requires extension pdo_sqlite */ public function testUserProvidedPDOConnection() : void { self::assertTrue( DriverManager::getConnection([ 'pdo' => new PDO('sqlite::memory:'), ])->ping() ); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/DataAccessTest.php000066400000000000000000001063121360544566000272660ustar00rootroot00000000000000addColumn('test_int', 'integer'); $table->addColumn('test_string', 'string'); $table->addColumn('test_datetime', 'datetime', ['notnull' => false]); $table->setPrimaryKey(['test_int']); $sm = $this->connection->getSchemaManager(); $sm->createTable($table); $this->connection->insert('fetch_table', ['test_int' => 1, 'test_string' => 'foo', 'test_datetime' => '2010-01-01 10:10:10']); self::$generated = true; } public function testPrepareWithBindValue() : void { $sql = 'SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?'; $stmt = $this->connection->prepare($sql); self::assertInstanceOf(Statement::class, $stmt); $stmt->bindValue(1, 1); $stmt->bindValue(2, 'foo'); $stmt->execute(); $row = $stmt->fetch(FetchMode::ASSOCIATIVE); $row = array_change_key_case($row, CASE_LOWER); self::assertEquals(['test_int' => 1, 'test_string' => 'foo'], $row); } public function testPrepareWithBindParam() : void { $paramInt = 1; $paramStr = 'foo'; $sql = 'SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?'; $stmt = $this->connection->prepare($sql); self::assertInstanceOf(Statement::class, $stmt); $stmt->bindParam(1, $paramInt); $stmt->bindParam(2, $paramStr); $stmt->execute(); $row = $stmt->fetch(FetchMode::ASSOCIATIVE); $row = array_change_key_case($row, CASE_LOWER); self::assertEquals(['test_int' => 1, 'test_string' => 'foo'], $row); } public function testPrepareWithFetchAll() : void { $paramInt = 1; $paramStr = 'foo'; $sql = 'SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?'; $stmt = $this->connection->prepare($sql); self::assertInstanceOf(Statement::class, $stmt); $stmt->bindParam(1, $paramInt); $stmt->bindParam(2, $paramStr); $stmt->execute(); $rows = $stmt->fetchAll(FetchMode::ASSOCIATIVE); $rows[0] = array_change_key_case($rows[0], CASE_LOWER); self::assertEquals(['test_int' => 1, 'test_string' => 'foo'], $rows[0]); } /** * @group DBAL-228 */ public function testPrepareWithFetchAllBoth() : void { $paramInt = 1; $paramStr = 'foo'; $sql = 'SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?'; $stmt = $this->connection->prepare($sql); self::assertInstanceOf(Statement::class, $stmt); $stmt->bindParam(1, $paramInt); $stmt->bindParam(2, $paramStr); $stmt->execute(); $rows = $stmt->fetchAll(FetchMode::MIXED); $rows[0] = array_change_key_case($rows[0], CASE_LOWER); self::assertEquals(['test_int' => 1, 'test_string' => 'foo', 0 => 1, 1 => 'foo'], $rows[0]); } public function testPrepareWithFetchColumn() : void { $paramInt = 1; $paramStr = 'foo'; $sql = 'SELECT test_int FROM fetch_table WHERE test_int = ? AND test_string = ?'; $stmt = $this->connection->prepare($sql); self::assertInstanceOf(Statement::class, $stmt); $stmt->bindParam(1, $paramInt); $stmt->bindParam(2, $paramStr); $stmt->execute(); $column = $stmt->fetchColumn(); self::assertEquals(1, $column); } public function testPrepareWithIterator() : void { $paramInt = 1; $paramStr = 'foo'; $sql = 'SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?'; $stmt = $this->connection->prepare($sql); self::assertInstanceOf(Statement::class, $stmt); $stmt->bindParam(1, $paramInt); $stmt->bindParam(2, $paramStr); $stmt->execute(); $rows = []; $stmt->setFetchMode(FetchMode::ASSOCIATIVE); foreach ($stmt as $row) { $rows[] = array_change_key_case($row, CASE_LOWER); } self::assertEquals(['test_int' => 1, 'test_string' => 'foo'], $rows[0]); } public function testPrepareWithQuoted() : void { $table = 'fetch_table'; $paramInt = 1; $paramStr = 'foo'; $stmt = $this->connection->prepare(sprintf( 'SELECT test_int, test_string FROM %s WHERE test_int = %s AND test_string = %s', $this->connection->quoteIdentifier($table), $this->connection->quote($paramInt), $this->connection->quote($paramStr) )); self::assertInstanceOf(Statement::class, $stmt); } public function testPrepareWithExecuteParams() : void { $paramInt = 1; $paramStr = 'foo'; $sql = 'SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?'; $stmt = $this->connection->prepare($sql); self::assertInstanceOf(Statement::class, $stmt); $stmt->execute([$paramInt, $paramStr]); $row = $stmt->fetch(FetchMode::ASSOCIATIVE); self::assertNotFalse($row); $row = array_change_key_case($row, CASE_LOWER); self::assertEquals(['test_int' => 1, 'test_string' => 'foo'], $row); } public function testFetchAll() : void { $sql = 'SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?'; $data = $this->connection->fetchAll($sql, [1, 'foo']); self::assertCount(1, $data); $row = $data[0]; self::assertCount(2, $row); $row = array_change_key_case($row, CASE_LOWER); self::assertEquals(1, $row['test_int']); self::assertEquals('foo', $row['test_string']); } /** * @group DBAL-209 */ public function testFetchAllWithTypes() : void { $datetimeString = '2010-01-01 10:10:10'; $datetime = new DateTime($datetimeString); $sql = 'SELECT test_int, test_datetime FROM fetch_table WHERE test_int = ? AND test_datetime = ?'; $data = $this->connection->fetchAll( $sql, [1, $datetime], [ParameterType::STRING, Types::DATETIME_MUTABLE] ); self::assertCount(1, $data); $row = $data[0]; self::assertCount(2, $row); $row = array_change_key_case($row, CASE_LOWER); self::assertEquals(1, $row['test_int']); self::assertStringStartsWith($datetimeString, $row['test_datetime']); } /** * @group DBAL-209 */ public function testFetchAllWithMissingTypes() : void { if ($this->connection->getDriver() instanceof MySQLiDriver || $this->connection->getDriver() instanceof SQLSrvDriver) { $this->markTestSkipped('mysqli and sqlsrv actually supports this'); } $datetimeString = '2010-01-01 10:10:10'; $datetime = new DateTime($datetimeString); $sql = 'SELECT test_int, test_datetime FROM fetch_table WHERE test_int = ? AND test_datetime = ?'; $this->expectException(DBALException::class); $this->connection->fetchAll($sql, [1, $datetime]); } public function testFetchBoth() : void { $sql = 'SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?'; $row = $this->connection->executeQuery($sql, [1, 'foo'])->fetch(FetchMode::MIXED); self::assertNotFalse($row); $row = array_change_key_case($row, CASE_LOWER); self::assertEquals(1, $row['test_int']); self::assertEquals('foo', $row['test_string']); self::assertEquals(1, $row[0]); self::assertEquals('foo', $row[1]); } public function testFetchNoResult() : void { self::assertFalse( $this->connection->executeQuery('SELECT test_int FROM fetch_table WHERE test_int = ?', [-1])->fetch() ); } public function testFetchAssoc() : void { $sql = 'SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?'; $row = $this->connection->fetchAssoc($sql, [1, 'foo']); self::assertNotFalse($row); $row = array_change_key_case($row, CASE_LOWER); self::assertEquals(1, $row['test_int']); self::assertEquals('foo', $row['test_string']); } public function testFetchAssocWithTypes() : void { $datetimeString = '2010-01-01 10:10:10'; $datetime = new DateTime($datetimeString); $sql = 'SELECT test_int, test_datetime FROM fetch_table WHERE test_int = ? AND test_datetime = ?'; $row = $this->connection->fetchAssoc( $sql, [1, $datetime], [ParameterType::STRING, Types::DATETIME_MUTABLE] ); self::assertNotFalse($row); $row = array_change_key_case($row, CASE_LOWER); self::assertEquals(1, $row['test_int']); self::assertStringStartsWith($datetimeString, $row['test_datetime']); } public function testFetchAssocWithMissingTypes() : void { if ($this->connection->getDriver() instanceof MySQLiDriver || $this->connection->getDriver() instanceof SQLSrvDriver) { $this->markTestSkipped('mysqli and sqlsrv actually supports this'); } $datetimeString = '2010-01-01 10:10:10'; $datetime = new DateTime($datetimeString); $sql = 'SELECT test_int, test_datetime FROM fetch_table WHERE test_int = ? AND test_datetime = ?'; $this->expectException(DBALException::class); $this->connection->fetchAssoc($sql, [1, $datetime]); } public function testFetchArray() : void { $sql = 'SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?'; $row = $this->connection->fetchArray($sql, [1, 'foo']); self::assertEquals(1, $row[0]); self::assertEquals('foo', $row[1]); } public function testFetchArrayWithTypes() : void { $datetimeString = '2010-01-01 10:10:10'; $datetime = new DateTime($datetimeString); $sql = 'SELECT test_int, test_datetime FROM fetch_table WHERE test_int = ? AND test_datetime = ?'; $row = $this->connection->fetchArray( $sql, [1, $datetime], [ParameterType::STRING, Types::DATETIME_MUTABLE] ); self::assertNotFalse($row); $row = array_change_key_case($row, CASE_LOWER); self::assertEquals(1, $row[0]); self::assertStringStartsWith($datetimeString, $row[1]); } public function testFetchArrayWithMissingTypes() : void { if ($this->connection->getDriver() instanceof MySQLiDriver || $this->connection->getDriver() instanceof SQLSrvDriver) { $this->markTestSkipped('mysqli and sqlsrv actually supports this'); } $datetimeString = '2010-01-01 10:10:10'; $datetime = new DateTime($datetimeString); $sql = 'SELECT test_int, test_datetime FROM fetch_table WHERE test_int = ? AND test_datetime = ?'; $this->expectException(DBALException::class); $this->connection->fetchArray($sql, [1, $datetime]); } public function testFetchColumn() : void { $sql = 'SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?'; $testInt = $this->connection->fetchColumn($sql, [1, 'foo'], 0); self::assertEquals(1, $testInt); $sql = 'SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?'; $testString = $this->connection->fetchColumn($sql, [1, 'foo'], 1); self::assertEquals('foo', $testString); } public function testFetchColumnWithTypes() : void { $datetimeString = '2010-01-01 10:10:10'; $datetime = new DateTime($datetimeString); $sql = 'SELECT test_int, test_datetime FROM fetch_table WHERE test_int = ? AND test_datetime = ?'; $column = $this->connection->fetchColumn( $sql, [1, $datetime], 1, [ParameterType::STRING, Types::DATETIME_MUTABLE] ); self::assertNotFalse($column); self::assertStringStartsWith($datetimeString, $column); } public function testFetchColumnWithMissingTypes() : void { if ($this->connection->getDriver() instanceof MySQLiDriver || $this->connection->getDriver() instanceof SQLSrvDriver) { $this->markTestSkipped('mysqli and sqlsrv actually supports this'); } $datetimeString = '2010-01-01 10:10:10'; $datetime = new DateTime($datetimeString); $sql = 'SELECT test_int, test_datetime FROM fetch_table WHERE test_int = ? AND test_datetime = ?'; $this->expectException(DBALException::class); $this->connection->fetchColumn($sql, [1, $datetime], 1); } /** * @group DDC-697 */ public function testExecuteQueryBindDateTimeType() : void { $sql = 'SELECT count(*) AS c FROM fetch_table WHERE test_datetime = ?'; $stmt = $this->connection->executeQuery( $sql, [1 => new DateTime('2010-01-01 10:10:10')], [1 => Types::DATETIME_MUTABLE] ); self::assertEquals(1, $stmt->fetchColumn()); } /** * @group DDC-697 */ public function testExecuteUpdateBindDateTimeType() : void { $datetime = new DateTime('2010-02-02 20:20:20'); $sql = 'INSERT INTO fetch_table (test_int, test_string, test_datetime) VALUES (?, ?, ?)'; $affectedRows = $this->connection->executeUpdate($sql, [ 1 => 50, 2 => 'foo', 3 => $datetime, ], [ 1 => ParameterType::INTEGER, 2 => ParameterType::STRING, 3 => Types::DATETIME_MUTABLE, ]); self::assertEquals(1, $affectedRows); self::assertEquals(1, $this->connection->executeQuery( 'SELECT count(*) AS c FROM fetch_table WHERE test_datetime = ?', [1 => $datetime], [1 => Types::DATETIME_MUTABLE] )->fetchColumn()); } /** * @group DDC-697 */ public function testPrepareQueryBindValueDateTimeType() : void { $sql = 'SELECT count(*) AS c FROM fetch_table WHERE test_datetime = ?'; $stmt = $this->connection->prepare($sql); $stmt->bindValue(1, new DateTime('2010-01-01 10:10:10'), Types::DATETIME_MUTABLE); $stmt->execute(); self::assertEquals(1, $stmt->fetchColumn()); } /** * @group DBAL-78 */ public function testNativeArrayListSupport() : void { for ($i = 100; $i < 110; $i++) { $this->connection->insert('fetch_table', ['test_int' => $i, 'test_string' => 'foo' . $i, 'test_datetime' => '2010-01-01 10:10:10']); } $stmt = $this->connection->executeQuery( 'SELECT test_int FROM fetch_table WHERE test_int IN (?)', [[100, 101, 102, 103, 104]], [Connection::PARAM_INT_ARRAY] ); $data = $stmt->fetchAll(FetchMode::NUMERIC); self::assertCount(5, $data); self::assertEquals([[100], [101], [102], [103], [104]], $data); $stmt = $this->connection->executeQuery( 'SELECT test_int FROM fetch_table WHERE test_string IN (?)', [['foo100', 'foo101', 'foo102', 'foo103', 'foo104']], [Connection::PARAM_STR_ARRAY] ); $data = $stmt->fetchAll(FetchMode::NUMERIC); self::assertCount(5, $data); self::assertEquals([[100], [101], [102], [103], [104]], $data); } /** * @param string|false $char * * @dataProvider getTrimExpressionData */ public function testTrimExpression(string $value, int $position, $char, string $expectedResult) : void { $sql = 'SELECT ' . $this->connection->getDatabasePlatform()->getTrimExpression($value, $position, $char) . ' AS trimmed ' . 'FROM fetch_table'; $row = $this->connection->fetchAssoc($sql); $row = array_change_key_case($row, CASE_LOWER); self::assertEquals($expectedResult, $row['trimmed']); } /** * @return array> */ public static function getTrimExpressionData() : iterable { return [ ['test_string', TrimMode::UNSPECIFIED, false, 'foo'], ['test_string', TrimMode::LEADING, false, 'foo'], ['test_string', TrimMode::TRAILING, false, 'foo'], ['test_string', TrimMode::BOTH, false, 'foo'], ['test_string', TrimMode::UNSPECIFIED, "'f'", 'oo'], ['test_string', TrimMode::UNSPECIFIED, "'o'", 'f'], ['test_string', TrimMode::UNSPECIFIED, "'.'", 'foo'], ['test_string', TrimMode::LEADING, "'f'", 'oo'], ['test_string', TrimMode::LEADING, "'o'", 'foo'], ['test_string', TrimMode::LEADING, "'.'", 'foo'], ['test_string', TrimMode::TRAILING, "'f'", 'foo'], ['test_string', TrimMode::TRAILING, "'o'", 'f'], ['test_string', TrimMode::TRAILING, "'.'", 'foo'], ['test_string', TrimMode::BOTH, "'f'", 'oo'], ['test_string', TrimMode::BOTH, "'o'", 'f'], ['test_string', TrimMode::BOTH, "'.'", 'foo'], ["' foo '", TrimMode::UNSPECIFIED, false, 'foo'], ["' foo '", TrimMode::LEADING, false, 'foo '], ["' foo '", TrimMode::TRAILING, false, ' foo'], ["' foo '", TrimMode::BOTH, false, 'foo'], ["' foo '", TrimMode::UNSPECIFIED, "'f'", ' foo '], ["' foo '", TrimMode::UNSPECIFIED, "'o'", ' foo '], ["' foo '", TrimMode::UNSPECIFIED, "'.'", ' foo '], ["' foo '", TrimMode::UNSPECIFIED, "' '", 'foo'], ["' foo '", TrimMode::LEADING, "'f'", ' foo '], ["' foo '", TrimMode::LEADING, "'o'", ' foo '], ["' foo '", TrimMode::LEADING, "'.'", ' foo '], ["' foo '", TrimMode::LEADING, "' '", 'foo '], ["' foo '", TrimMode::TRAILING, "'f'", ' foo '], ["' foo '", TrimMode::TRAILING, "'o'", ' foo '], ["' foo '", TrimMode::TRAILING, "'.'", ' foo '], ["' foo '", TrimMode::TRAILING, "' '", ' foo'], ["' foo '", TrimMode::BOTH, "'f'", ' foo '], ["' foo '", TrimMode::BOTH, "'o'", ' foo '], ["' foo '", TrimMode::BOTH, "'.'", ' foo '], ["' foo '", TrimMode::BOTH, "' '", 'foo'], ]; } /** * @group DDC-1014 */ public function testDateArithmetics() : void { $p = $this->connection->getDatabasePlatform(); $sql = 'SELECT '; $sql .= $p->getDateAddSecondsExpression('test_datetime', 1) . ' AS add_seconds, '; $sql .= $p->getDateSubSecondsExpression('test_datetime', 1) . ' AS sub_seconds, '; $sql .= $p->getDateAddMinutesExpression('test_datetime', 5) . ' AS add_minutes, '; $sql .= $p->getDateSubMinutesExpression('test_datetime', 5) . ' AS sub_minutes, '; $sql .= $p->getDateAddHourExpression('test_datetime', 3) . ' AS add_hour, '; $sql .= $p->getDateSubHourExpression('test_datetime', 3) . ' AS sub_hour, '; $sql .= $p->getDateAddDaysExpression('test_datetime', 10) . ' AS add_days, '; $sql .= $p->getDateSubDaysExpression('test_datetime', 10) . ' AS sub_days, '; $sql .= $p->getDateAddWeeksExpression('test_datetime', 1) . ' AS add_weeks, '; $sql .= $p->getDateSubWeeksExpression('test_datetime', 1) . ' AS sub_weeks, '; $sql .= $p->getDateAddMonthExpression('test_datetime', 2) . ' AS add_month, '; $sql .= $p->getDateSubMonthExpression('test_datetime', 2) . ' AS sub_month, '; $sql .= $p->getDateAddQuartersExpression('test_datetime', 3) . ' AS add_quarters, '; $sql .= $p->getDateSubQuartersExpression('test_datetime', 3) . ' AS sub_quarters, '; $sql .= $p->getDateAddYearsExpression('test_datetime', 6) . ' AS add_years, '; $sql .= $p->getDateSubYearsExpression('test_datetime', 6) . ' AS sub_years '; $sql .= 'FROM fetch_table'; $row = $this->connection->fetchAssoc($sql); $row = array_change_key_case($row, CASE_LOWER); self::assertEquals('2010-01-01 10:10:11', date('Y-m-d H:i:s', strtotime($row['add_seconds'])), 'Adding second should end up on 2010-01-01 10:10:11'); self::assertEquals('2010-01-01 10:10:09', date('Y-m-d H:i:s', strtotime($row['sub_seconds'])), 'Subtracting second should end up on 2010-01-01 10:10:09'); self::assertEquals('2010-01-01 10:15:10', date('Y-m-d H:i:s', strtotime($row['add_minutes'])), 'Adding minutes should end up on 2010-01-01 10:15:10'); self::assertEquals('2010-01-01 10:05:10', date('Y-m-d H:i:s', strtotime($row['sub_minutes'])), 'Subtracting minutes should end up on 2010-01-01 10:05:10'); self::assertEquals('2010-01-01 13:10', date('Y-m-d H:i', strtotime($row['add_hour'])), 'Adding date should end up on 2010-01-01 13:10'); self::assertEquals('2010-01-01 07:10', date('Y-m-d H:i', strtotime($row['sub_hour'])), 'Subtracting date should end up on 2010-01-01 07:10'); self::assertEquals('2010-01-11', date('Y-m-d', strtotime($row['add_days'])), 'Adding date should end up on 2010-01-11'); self::assertEquals('2009-12-22', date('Y-m-d', strtotime($row['sub_days'])), 'Subtracting date should end up on 2009-12-22'); self::assertEquals('2010-01-08', date('Y-m-d', strtotime($row['add_weeks'])), 'Adding week should end up on 2010-01-08'); self::assertEquals('2009-12-25', date('Y-m-d', strtotime($row['sub_weeks'])), 'Subtracting week should end up on 2009-12-25'); self::assertEquals('2010-03-01', date('Y-m-d', strtotime($row['add_month'])), 'Adding month should end up on 2010-03-01'); self::assertEquals('2009-11-01', date('Y-m-d', strtotime($row['sub_month'])), 'Subtracting month should end up on 2009-11-01'); self::assertEquals('2010-10-01', date('Y-m-d', strtotime($row['add_quarters'])), 'Adding quarters should end up on 2010-04-01'); self::assertEquals('2009-04-01', date('Y-m-d', strtotime($row['sub_quarters'])), 'Subtracting quarters should end up on 2009-10-01'); self::assertEquals('2016-01-01', date('Y-m-d', strtotime($row['add_years'])), 'Adding years should end up on 2016-01-01'); self::assertEquals('2004-01-01', date('Y-m-d', strtotime($row['sub_years'])), 'Subtracting years should end up on 2004-01-01'); } public function testSqliteDateArithmeticWithDynamicInterval() : void { $platform = $this->connection->getDatabasePlatform(); if (! $platform instanceof SqlitePlatform) { $this->markTestSkipped('test is for sqlite only'); } $table = new Table('fetch_table_date_math'); $table->addColumn('test_date', 'date'); $table->addColumn('test_days', 'integer'); $table->setPrimaryKey(['test_date']); $sm = $this->connection->getSchemaManager(); $sm->createTable($table); $this->connection->insert('fetch_table_date_math', ['test_date' => '2010-01-01', 'test_days' => 10]); $this->connection->insert('fetch_table_date_math', ['test_date' => '2010-06-01', 'test_days' => 20]); $sql = 'SELECT COUNT(*) FROM fetch_table_date_math WHERE '; $sql .= $platform->getDateSubDaysExpression('test_date', 'test_days') . " < '2010-05-12'"; $rowCount = $this->connection->fetchColumn($sql, [], 0); $this->assertEquals(1, $rowCount); } public function testLocateExpression() : void { $platform = $this->connection->getDatabasePlatform(); $sql = 'SELECT '; $sql .= $platform->getLocateExpression('test_string', "'oo'") . ' AS locate1, '; $sql .= $platform->getLocateExpression('test_string', "'foo'") . ' AS locate2, '; $sql .= $platform->getLocateExpression('test_string', "'bar'") . ' AS locate3, '; $sql .= $platform->getLocateExpression('test_string', 'test_string') . ' AS locate4, '; $sql .= $platform->getLocateExpression("'foo'", 'test_string') . ' AS locate5, '; $sql .= $platform->getLocateExpression("'barfoobaz'", 'test_string') . ' AS locate6, '; $sql .= $platform->getLocateExpression("'bar'", 'test_string') . ' AS locate7, '; $sql .= $platform->getLocateExpression('test_string', "'oo'", 2) . ' AS locate8, '; $sql .= $platform->getLocateExpression('test_string', "'oo'", 3) . ' AS locate9 '; $sql .= 'FROM fetch_table'; $row = $this->connection->fetchAssoc($sql); $row = array_change_key_case($row, CASE_LOWER); self::assertEquals(2, $row['locate1']); self::assertEquals(1, $row['locate2']); self::assertEquals(0, $row['locate3']); self::assertEquals(1, $row['locate4']); self::assertEquals(1, $row['locate5']); self::assertEquals(4, $row['locate6']); self::assertEquals(0, $row['locate7']); self::assertEquals(2, $row['locate8']); self::assertEquals(0, $row['locate9']); } public function testQuoteSQLInjection() : void { $sql = 'SELECT * FROM fetch_table WHERE test_string = ' . $this->connection->quote("bar' OR '1'='1"); $rows = $this->connection->fetchAll($sql); self::assertCount(0, $rows, 'no result should be returned, otherwise SQL injection is possible'); } /** * @group DDC-1213 */ public function testBitComparisonExpressionSupport() : void { $this->connection->exec('DELETE FROM fetch_table'); $platform = $this->connection->getDatabasePlatform(); $bitmap = []; for ($i = 2; $i < 9; $i += 2) { $bitmap[$i] = [ 'bit_or' => ($i | 2), 'bit_and' => ($i & 2), ]; $this->connection->insert('fetch_table', [ 'test_int' => $i, 'test_string' => json_encode($bitmap[$i]), 'test_datetime' => '2010-01-01 10:10:10', ]); } $sql[] = 'SELECT '; $sql[] = 'test_int, '; $sql[] = 'test_string, '; $sql[] = $platform->getBitOrComparisonExpression('test_int', 2) . ' AS bit_or, '; $sql[] = $platform->getBitAndComparisonExpression('test_int', 2) . ' AS bit_and '; $sql[] = 'FROM fetch_table'; $stmt = $this->connection->executeQuery(implode(PHP_EOL, $sql)); $data = $stmt->fetchAll(FetchMode::ASSOCIATIVE); self::assertCount(4, $data); self::assertEquals(count($bitmap), count($data)); foreach ($data as $row) { $row = array_change_key_case($row, CASE_LOWER); self::assertArrayHasKey('test_int', $row); $id = $row['test_int']; self::assertArrayHasKey($id, $bitmap); self::assertArrayHasKey($id, $bitmap); self::assertArrayHasKey('bit_or', $row); self::assertArrayHasKey('bit_and', $row); self::assertEquals($row['bit_or'], $bitmap[$id]['bit_or']); self::assertEquals($row['bit_and'], $bitmap[$id]['bit_and']); } } public function testSetDefaultFetchMode() : void { $stmt = $this->connection->query('SELECT * FROM fetch_table'); $stmt->setFetchMode(FetchMode::NUMERIC); $row = array_keys($stmt->fetch()); self::assertCount(0, array_filter($row, static function ($v) { return ! is_numeric($v); }), 'should be no non-numerical elements in the result.'); } /** * @group DBAL-1091 */ public function testFetchAllStyleObject() : void { $this->setupFixture(); $sql = 'SELECT test_int, test_string, test_datetime FROM fetch_table'; $stmt = $this->connection->prepare($sql); $stmt->execute(); $results = $stmt->fetchAll(FetchMode::STANDARD_OBJECT); self::assertCount(1, $results); self::assertInstanceOf('stdClass', $results[0]); self::assertEquals( 1, property_exists($results[0], 'test_int') ? $results[0]->test_int : $results[0]->TEST_INT ); self::assertEquals( 'foo', property_exists($results[0], 'test_string') ? $results[0]->test_string : $results[0]->TEST_STRING ); self::assertStringStartsWith( '2010-01-01 10:10:10', property_exists($results[0], 'test_datetime') ? $results[0]->test_datetime : $results[0]->TEST_DATETIME ); } /** * @group DBAL-196 */ public function testFetchAllSupportFetchClass() : void { $this->beforeFetchClassTest(); $this->setupFixture(); $sql = 'SELECT test_int, test_string, test_datetime FROM fetch_table'; $stmt = $this->connection->prepare($sql); $stmt->execute(); $results = $stmt->fetchAll( FetchMode::CUSTOM_OBJECT, MyFetchClass::class ); self::assertCount(1, $results); self::assertInstanceOf(MyFetchClass::class, $results[0]); self::assertEquals(1, $results[0]->test_int); self::assertEquals('foo', $results[0]->test_string); self::assertStringStartsWith('2010-01-01 10:10:10', $results[0]->test_datetime); } /** * @group DBAL-241 */ public function testFetchAllStyleColumn() : void { $sql = 'DELETE FROM fetch_table'; $this->connection->executeUpdate($sql); $this->connection->insert('fetch_table', ['test_int' => 1, 'test_string' => 'foo']); $this->connection->insert('fetch_table', ['test_int' => 10, 'test_string' => 'foo']); $sql = 'SELECT test_int FROM fetch_table'; $rows = $this->connection->query($sql)->fetchAll(FetchMode::COLUMN); self::assertEquals([1, 10], $rows); } /** * @group DBAL-214 */ public function testSetFetchModeClassFetchAll() : void { $this->beforeFetchClassTest(); $this->setupFixture(); $sql = 'SELECT * FROM fetch_table'; $stmt = $this->connection->query($sql); $stmt->setFetchMode(FetchMode::CUSTOM_OBJECT, MyFetchClass::class); $results = $stmt->fetchAll(); self::assertCount(1, $results); self::assertInstanceOf(MyFetchClass::class, $results[0]); self::assertEquals(1, $results[0]->test_int); self::assertEquals('foo', $results[0]->test_string); self::assertStringStartsWith('2010-01-01 10:10:10', $results[0]->test_datetime); } /** * @group DBAL-214 */ public function testSetFetchModeClassFetch() : void { $this->beforeFetchClassTest(); $this->setupFixture(); $sql = 'SELECT * FROM fetch_table'; $stmt = $this->connection->query($sql); $stmt->setFetchMode(FetchMode::CUSTOM_OBJECT, MyFetchClass::class); $results = []; while ($row = $stmt->fetch()) { $results[] = $row; } self::assertCount(1, $results); self::assertInstanceOf(MyFetchClass::class, $results[0]); self::assertEquals(1, $results[0]->test_int); self::assertEquals('foo', $results[0]->test_string); self::assertStringStartsWith('2010-01-01 10:10:10', $results[0]->test_datetime); } /** * @group DBAL-257 */ public function testEmptyFetchColumnReturnsFalse() : void { $this->connection->beginTransaction(); $this->connection->exec('DELETE FROM fetch_table'); self::assertFalse($this->connection->fetchColumn('SELECT test_int FROM fetch_table')); self::assertFalse($this->connection->query('SELECT test_int FROM fetch_table')->fetchColumn()); $this->connection->rollBack(); } /** * @group DBAL-339 */ public function testSetFetchModeOnDbalStatement() : void { $sql = 'SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?'; $stmt = $this->connection->executeQuery($sql, [1, 'foo']); $stmt->setFetchMode(FetchMode::NUMERIC); $row = $stmt->fetch(); self::assertArrayHasKey(0, $row); self::assertArrayHasKey(1, $row); self::assertFalse($stmt->fetch()); } /** * @group DBAL-435 */ public function testEmptyParameters() : void { $sql = 'SELECT * FROM fetch_table WHERE test_int IN (?)'; $stmt = $this->connection->executeQuery($sql, [[]], [Connection::PARAM_INT_ARRAY]); $rows = $stmt->fetchAll(); self::assertEquals([], $rows); } /** * @group DBAL-1028 */ public function testFetchColumnNullValue() : void { $this->connection->executeUpdate( 'INSERT INTO fetch_table (test_int, test_string) VALUES (?, ?)', [2, 'foo'] ); self::assertNull( $this->connection->fetchColumn('SELECT test_datetime FROM fetch_table WHERE test_int = ?', [2]) ); } /** * @group DBAL-1028 */ public function testFetchColumnNoResult() : void { self::assertFalse( $this->connection->fetchColumn('SELECT test_int FROM fetch_table WHERE test_int = ?', [-1]) ); } private function setupFixture() : void { $this->connection->exec('DELETE FROM fetch_table'); $this->connection->insert('fetch_table', [ 'test_int' => 1, 'test_string' => 'foo', 'test_datetime' => '2010-01-01 10:10:10', ]); } private function beforeFetchClassTest() : void { $driver = $this->connection->getDriver(); if ($driver instanceof Oci8Driver) { $this->markTestSkipped('Not supported by OCI8'); } if ($driver instanceof MySQLiDriver) { $this->markTestSkipped('Mysqli driver dont support this feature.'); } if (! $driver instanceof PDOOracleDriver) { return; } /** @var PDOConnection $connection */ $connection = $this->connection->getWrappedConnection(); $connection->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER); } } class MyFetchClass { /** @var int */ public $test_int; /** @var string */ public $test_string; /** @var string */ public $test_datetime; } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Driver/000077500000000000000000000000001360544566000251525ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Driver/AbstractDriverTest.php000066400000000000000000000033301360544566000314410ustar00rootroot00000000000000driver = $this->createDriver(); } /** * @group DBAL-1215 */ public function testConnectsWithoutDatabaseNameParameter() : void { $params = $this->connection->getParams(); unset($params['dbname']); $user = $params['user'] ?? null; $password = $params['password'] ?? null; $connection = $this->driver->connect($params, $user, $password); self::assertInstanceOf(DriverConnection::class, $connection); } /** * @group DBAL-1215 */ public function testReturnsDatabaseNameWithoutDatabaseNameParameter() : void { $params = $this->connection->getParams(); unset($params['dbname']); $connection = new Connection( $params, $this->connection->getDriver(), $this->connection->getConfiguration(), $this->connection->getEventManager() ); self::assertSame( static::getDatabaseNameForConnectionWithoutDatabaseNameParameter(), $this->driver->getDatabase($connection) ); } abstract protected function createDriver() : Driver; protected static function getDatabaseNameForConnectionWithoutDatabaseNameParameter() : ?string { return null; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Driver/IBMDB2/000077500000000000000000000000001360544566000260515ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Driver/IBMDB2/DB2DriverTest.php000066400000000000000000000022531360544566000311470ustar00rootroot00000000000000markTestSkipped('ibm_db2 is not installed.'); } parent::setUp(); if ($this->connection->getDriver() instanceof DB2Driver) { return; } $this->markTestSkipped('ibm_db2 only test.'); } /** * {@inheritdoc} */ public function testConnectsWithoutDatabaseNameParameter() : void { $this->markTestSkipped('IBM DB2 does not support connecting without database name.'); } /** * {@inheritdoc} */ public function testReturnsDatabaseNameWithoutDatabaseNameParameter() : void { $this->markTestSkipped('IBM DB2 does not support connecting without database name.'); } /** * {@inheritdoc} */ protected function createDriver() : Driver { return new DB2Driver(); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Driver/IBMDB2/DB2StatementTest.php000066400000000000000000000020521360544566000316550ustar00rootroot00000000000000markTestSkipped('ibm_db2 is not installed.'); } parent::setUp(); if ($this->connection->getDriver() instanceof DB2Driver) { return; } $this->markTestSkipped('ibm_db2 only test.'); } public function testExecutionErrorsAreNotSuppressed() : void { $stmt = $this->connection->prepare('SELECT * FROM SYSIBM.SYSDUMMY1 WHERE \'foo\' = ?'); // unwrap the statement to prevent the wrapper from handling the PHPUnit-originated exception $wrappedStmt = $stmt->getWrappedStatement(); $this->expectException(Notice::class); $wrappedStmt->execute([[]]); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Driver/Mysqli/000077500000000000000000000000001360544566000264305ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Driver/Mysqli/ConnectionTest.php000066400000000000000000000034641360544566000321070ustar00rootroot00000000000000markTestSkipped('mysqli is not installed.'); } parent::setUp(); if ($this->connection->getDriver() instanceof Driver) { return; } $this->markTestSkipped('MySQLi only test.'); } protected function tearDown() : void { parent::tearDown(); } public function testDriverOptions() : void { $driverOptions = [MYSQLI_OPT_CONNECT_TIMEOUT => 1]; $connection = $this->getConnection($driverOptions); self::assertInstanceOf(MysqliConnection::class, $connection); } public function testUnsupportedDriverOption() : void { $this->expectException(MysqliException::class); $this->getConnection(['hello' => 'world']); // use local infile } public function testPing() : void { $conn = $this->getConnection([]); self::assertTrue($conn->ping()); } /** * @param mixed[] $driverOptions */ private function getConnection(array $driverOptions) : MysqliConnection { return new MysqliConnection( [ 'host' => $GLOBALS['db_host'], 'dbname' => $GLOBALS['db_name'], 'port' => $GLOBALS['db_port'], ], $GLOBALS['db_username'], $GLOBALS['db_password'], $driverOptions ); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Driver/Mysqli/DriverTest.php000066400000000000000000000014011360544566000312300ustar00rootroot00000000000000markTestSkipped('mysqli is not installed.'); } parent::setUp(); if ($this->connection->getDriver() instanceof Driver) { return; } $this->markTestSkipped('MySQLi only test.'); } /** * {@inheritdoc} */ protected function createDriver() : DriverInterface { return new Driver(); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Driver/OCI8/000077500000000000000000000000001360544566000256545ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Driver/OCI8/DriverTest.php000066400000000000000000000022541360544566000304630ustar00rootroot00000000000000markTestSkipped('oci8 is not installed.'); } parent::setUp(); if ($this->connection->getDriver() instanceof Driver) { return; } $this->markTestSkipped('oci8 only test.'); } /** * {@inheritdoc} */ public function testConnectsWithoutDatabaseNameParameter() : void { $this->markTestSkipped('Oracle does not support connecting without database name.'); } /** * {@inheritdoc} */ public function testReturnsDatabaseNameWithoutDatabaseNameParameter() : void { $this->markTestSkipped('Oracle does not support connecting without database name.'); } /** * {@inheritdoc} */ protected function createDriver() : DriverInterface { return new Driver(); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Driver/OCI8/OCI8ConnectionTest.php000066400000000000000000000027741360544566000317610ustar00rootroot00000000000000markTestSkipped('oci8 is not installed.'); } parent::setUp(); if (! $this->connection->getDriver() instanceof Driver) { $this->markTestSkipped('oci8 only test.'); } $this->driverConnection = $this->connection->getWrappedConnection(); } /** * @group DBAL-2595 */ public function testLastInsertIdAcceptsFqn() : void { $platform = $this->connection->getDatabasePlatform(); $schemaManager = $this->connection->getSchemaManager(); $table = new Table('DBAL2595'); $table->addColumn('id', 'integer', ['autoincrement' => true]); $table->addColumn('foo', 'integer'); $schemaManager->dropAndCreateTable($table); $this->connection->executeUpdate('INSERT INTO DBAL2595 (foo) VALUES (1)'); $schema = $this->connection->getDatabase(); $sequence = $platform->getIdentitySequenceName($schema . '.DBAL2595', 'id'); self::assertSame(1, $this->driverConnection->lastInsertId($sequence)); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Driver/OCI8/StatementTest.php000066400000000000000000000055321360544566000311760ustar00rootroot00000000000000markTestSkipped('oci8 is not installed.'); } parent::setUp(); if ($this->connection->getDriver() instanceof Driver) { return; } $this->markTestSkipped('oci8 only test.'); } /** * @param mixed[] $params * @param mixed[] $expected * * @dataProvider queryConversionProvider */ public function testQueryConversion(string $query, array $params, array $expected) : void { self::assertEquals( $expected, $this->connection->executeQuery($query, $params)->fetch() ); } /** * Low-level approach to working with parameter binding * * @param mixed[] $params * @param mixed[] $expected * * @dataProvider queryConversionProvider */ public function testStatementBindParameters(string $query, array $params, array $expected) : void { $stmt = $this->connection->prepare($query); $stmt->execute($params); self::assertEquals( $expected, $stmt->fetch() ); } /** * @return array> */ public static function queryConversionProvider() : iterable { return [ 'positional' => [ 'SELECT ? COL1 FROM DUAL', [1], ['COL1' => 1], ], 'named' => [ 'SELECT :COL COL1 FROM DUAL', [':COL' => 1], ['COL1' => 1], ], 'literal-with-placeholder' => [ "SELECT '?' COL1, ? COL2 FROM DUAL", [2], [ 'COL1' => '?', 'COL2' => 2, ], ], 'literal-with-quotes' => [ "SELECT ? COL1, '?\"?''?' \"COL?\" FROM DUAL", [3], [ 'COL1' => 3, 'COL?' => '?"?\'?', ], ], 'placeholder-at-the-end' => [ 'SELECT ? COL1 FROM DUAL WHERE 1 = ?', [4, 1], ['COL1' => 4], ], 'multi-line-literal' => [ "SELECT 'Hello, World?!' COL1 FROM DUAL WHERE 1 = ?", [1], [ 'COL1' => 'Hello, World?!', ], ], 'empty-literal' => [ "SELECT '' COL1 FROM DUAL", [], ['COL1' => ''], ], ]; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOConnectionTest.php000066400000000000000000000060111360544566000311630ustar00rootroot00000000000000markTestSkipped('PDO is not installed.'); } parent::setUp(); $this->driverConnection = $this->connection->getWrappedConnection(); if ($this->driverConnection instanceof PDOConnection) { return; } $this->markTestSkipped('PDO connection only test.'); } protected function tearDown() : void { $this->resetSharedConn(); parent::tearDown(); } public function testDoesNotRequireQueryForServerVersion() : void { self::assertFalse($this->driverConnection->requiresQueryForServerVersion()); } public function testThrowsWrappedExceptionOnConstruct() : void { $this->expectException(PDOException::class); new PDOConnection('foo'); } /** * @group DBAL-1022 */ public function testThrowsWrappedExceptionOnExec() : void { $this->expectException(PDOException::class); $this->driverConnection->exec('foo'); } public function testThrowsWrappedExceptionOnPrepare() : void { $driver = $this->connection->getDriver(); if ($driver instanceof PDOSQLSRVDriver) { $this->markTestSkipped('pdo_sqlsrv does not allow setting PDO::ATTR_EMULATE_PREPARES at connection level.'); } // Some PDO adapters do not check the query server-side // even though emulated prepared statements are disabled, // so an exception is thrown only eventually. if ($driver instanceof PDOOracleDriver || $driver instanceof PDOPgSQLDriver ) { self::markTestSkipped(sprintf( 'The underlying implementation of the %s driver does not check the query to be prepared server-side.', get_class($driver) )); } // Emulated prepared statements have to be disabled for this test // so that PDO actually communicates with the database server to check the query. $this->driverConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); $this->expectException(PDOException::class); $this->driverConnection->prepare('foo'); } public function testThrowsWrappedExceptionOnQuery() : void { $this->expectException(PDOException::class); $this->driverConnection->query('foo'); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOMySql/000077500000000000000000000000001360544566000265625ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOMySql/DriverTest.php000066400000000000000000000014161360544566000313700ustar00rootroot00000000000000markTestSkipped('pdo_mysql is not installed.'); } parent::setUp(); if ($this->connection->getDriver() instanceof Driver) { return; } $this->markTestSkipped('pdo_mysql only test.'); } /** * {@inheritdoc} */ protected function createDriver() : DriverInterface { return new Driver(); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOOracle/000077500000000000000000000000001360544566000267225ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOOracle/DriverTest.php000066400000000000000000000022771360544566000315360ustar00rootroot00000000000000markTestSkipped('PDO_OCI is not installed.'); } parent::setUp(); if ($this->connection->getDriver() instanceof Driver) { return; } $this->markTestSkipped('PDO_OCI only test.'); } /** * {@inheritdoc} */ public function testConnectsWithoutDatabaseNameParameter() : void { $this->markTestSkipped('Oracle does not support connecting without database name.'); } /** * {@inheritdoc} */ public function testReturnsDatabaseNameWithoutDatabaseNameParameter() : void { $this->markTestSkipped('Oracle does not support connecting without database name.'); } /** * {@inheritdoc} */ protected function createDriver() : DriverInterface { return new Driver(); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOPgSql/000077500000000000000000000000001360544566000265435ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOPgSql/DriverTest.php000066400000000000000000000071471360544566000313600ustar00rootroot00000000000000markTestSkipped('pdo_pgsql is not installed.'); } parent::setUp(); if ($this->connection->getDriver() instanceof Driver) { return; } $this->markTestSkipped('pdo_pgsql only test.'); } /** * @dataProvider getDatabaseParameter */ public function testDatabaseParameters(?string $databaseName, ?string $defaultDatabaseName, ?string $expectedDatabaseName) : void { $params = $this->connection->getParams(); $params['dbname'] = $databaseName; $params['default_dbname'] = $defaultDatabaseName; $connection = new Connection( $params, $this->connection->getDriver(), $this->connection->getConfiguration(), $this->connection->getEventManager() ); self::assertSame( $expectedDatabaseName, $this->driver->getDatabase($connection) ); } /** * @return mixed[][] */ public static function getDatabaseParameter() : iterable { $params = TestUtil::getConnectionParams(); $realDatabaseName = $params['dbname'] ?? ''; $dummyDatabaseName = $realDatabaseName . 'a'; return [ // dbname, default_dbname, expected [$realDatabaseName, null, $realDatabaseName], [$realDatabaseName, $dummyDatabaseName, $realDatabaseName], [null, $realDatabaseName, $realDatabaseName], [null, null, static::getDatabaseNameForConnectionWithoutDatabaseNameParameter()], ]; } /** * @group DBAL-1146 */ public function testConnectsWithApplicationNameParameter() : void { $parameters = $this->connection->getParams(); $parameters['application_name'] = 'doctrine'; $user = $parameters['user'] ?? null; $password = $parameters['password'] ?? null; $connection = $this->driver->connect($parameters, $user, $password); $hash = microtime(true); // required to identify the record in the results uniquely $sql = sprintf('SELECT * FROM pg_stat_activity WHERE %d = %d', $hash, $hash); $statement = $connection->query($sql); $records = $statement->fetchAll(); foreach ($records as $record) { // The query column is named "current_query" on PostgreSQL < 9.2 $queryColumnName = array_key_exists('current_query', $record) ? 'current_query' : 'query'; if ($record[$queryColumnName] === $sql) { self::assertSame('doctrine', $record['application_name']); return; } } $this->fail(sprintf('Query result does not contain a record where column "query" equals "%s".', $sql)); } /** * {@inheritdoc} */ protected function createDriver() : DriverInterface { return new Driver(); } /** * {@inheritdoc} */ protected static function getDatabaseNameForConnectionWithoutDatabaseNameParameter() : ?string { return 'postgres'; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOPgsqlConnectionTest.php000066400000000000000000000027341360544566000322020ustar00rootroot00000000000000markTestSkipped('pdo_pgsql is not loaded.'); } parent::setUp(); if ($this->connection->getDatabasePlatform() instanceof PostgreSqlPlatform) { return; } $this->markTestSkipped('PDOPgsql only test.'); } /** * @group DBAL-1183 * @group DBAL-1189 * @dataProvider getValidCharsets */ public function testConnectsWithValidCharsetOption(string $charset) : void { $params = $this->connection->getParams(); $params['charset'] = $charset; $connection = DriverManager::getConnection( $params, $this->connection->getConfiguration(), $this->connection->getEventManager() ); self::assertEquals( $charset, $connection->query('SHOW client_encoding') ->fetch(FetchMode::COLUMN) ); } /** * @return mixed[][] */ public static function getValidCharsets() : iterable { return [ ['UTF8'], ['LATIN1'], ]; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOSqlite/000077500000000000000000000000001360544566000267565ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOSqlite/DriverTest.php000066400000000000000000000014231360544566000315620ustar00rootroot00000000000000markTestSkipped('pdo_sqlite is not installed.'); } parent::setUp(); if ($this->connection->getDriver() instanceof Driver) { return; } $this->markTestSkipped('pdo_sqlite only test.'); } /** * {@inheritdoc} */ protected function createDriver() : DriverInterface { return new Driver(); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOSqlsrv/000077500000000000000000000000001360544566000270075ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Driver/PDOSqlsrv/DriverTest.php000066400000000000000000000036101360544566000316130ustar00rootroot00000000000000markTestSkipped('pdo_sqlsrv is not installed.'); } parent::setUp(); if ($this->connection->getDriver() instanceof Driver) { return; } $this->markTestSkipped('pdo_sqlsrv only test.'); } /** * {@inheritdoc} */ protected function createDriver() : DriverInterface { return new Driver(); } /** * {@inheritdoc} */ protected static function getDatabaseNameForConnectionWithoutDatabaseNameParameter() : ?string { return 'master'; } /** * @param int[]|string[] $driverOptions */ protected function getConnection(array $driverOptions) : Connection { return $this->connection->getDriver()->connect( [ 'host' => $GLOBALS['db_host'], 'port' => $GLOBALS['db_port'], ], $GLOBALS['db_username'], $GLOBALS['db_password'], $driverOptions ); } public function testConnectionOptions() : void { $connection = $this->getConnection(['APP' => 'APP_NAME']); $result = $connection->query('SELECT APP_NAME()')->fetchColumn(); self::assertSame('APP_NAME', $result); } public function testDriverOptions() : void { $connection = $this->getConnection([PDO::ATTR_CASE => PDO::CASE_UPPER]); self::assertSame(PDO::CASE_UPPER, $connection->getAttribute(PDO::ATTR_CASE)); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Driver/SQLAnywhere/000077500000000000000000000000001360544566000273145ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Driver/SQLAnywhere/ConnectionTest.php000066400000000000000000000025051360544566000327660ustar00rootroot00000000000000markTestSkipped('sqlanywhere is not installed.'); } parent::setUp(); if ($this->connection->getDriver() instanceof Driver) { return; } $this->markTestSkipped('sqlanywhere only test.'); } public function testNonPersistentConnection() : void { $params = $this->connection->getParams(); $params['persistent'] = false; $conn = DriverManager::getConnection($params); $conn->connect(); self::assertTrue($conn->isConnected(), 'No SQLAnywhere-nonpersistent connection established'); } public function testPersistentConnection() : void { $params = $this->connection->getParams(); $params['persistent'] = true; $conn = DriverManager::getConnection($params); $conn->connect(); self::assertTrue($conn->isConnected(), 'No SQLAnywhere-persistent connection established'); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Driver/SQLAnywhere/DriverTest.php000066400000000000000000000026451360544566000321270ustar00rootroot00000000000000markTestSkipped('sqlanywhere is not installed.'); } parent::setUp(); if ($this->connection->getDriver() instanceof Driver) { return; } $this->markTestSkipped('sqlanywhere only test.'); } public function testReturnsDatabaseNameWithoutDatabaseNameParameter() : void { $params = $this->connection->getParams(); unset($params['dbname']); $connection = new Connection( $params, $this->connection->getDriver(), $this->connection->getConfiguration(), $this->connection->getEventManager() ); // SQL Anywhere has no "default" database. The name of the default database // is defined on server startup and therefore can be arbitrary. self::assertIsString($this->driver->getDatabase($connection)); } /** * {@inheritdoc} */ protected function createDriver() : DriverInterface { return new Driver(); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Driver/SQLAnywhere/StatementTest.php000066400000000000000000000030571360544566000326360ustar00rootroot00000000000000markTestSkipped('sqlanywhere is not installed.'); } parent::setUp(); if ($this->connection->getDriver() instanceof Driver) { return; } $this->markTestSkipped('sqlanywhere only test.'); } public function testNonPersistentStatement() : void { $params = $this->connection->getParams(); $params['persistent'] = false; $conn = DriverManager::getConnection($params); $conn->connect(); self::assertTrue($conn->isConnected(), 'No SQLAnywhere-Connection established'); $prepStmt = $conn->prepare('SELECT 1'); self::assertTrue($prepStmt->execute(), ' Statement non-persistent failed'); } public function testPersistentStatement() : void { $params = $this->connection->getParams(); $params['persistent'] = true; $conn = DriverManager::getConnection($params); $conn->connect(); self::assertTrue($conn->isConnected(), 'No SQLAnywhere-Connection established'); $prepStmt = $conn->prepare('SELECT 1'); self::assertTrue($prepStmt->execute(), ' Statement persistent failed'); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Driver/SQLSrv/000077500000000000000000000000001360544566000263045ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Driver/SQLSrv/DriverTest.php000066400000000000000000000016571360544566000311210ustar00rootroot00000000000000markTestSkipped('sqlsrv is not installed.'); } parent::setUp(); if ($this->connection->getDriver() instanceof Driver) { return; } $this->markTestSkipped('sqlsrv only test.'); } /** * {@inheritdoc} */ protected function createDriver() : DriverInterface { return new Driver(); } /** * {@inheritdoc} */ protected static function getDatabaseNameForConnectionWithoutDatabaseNameParameter() : ?string { return 'master'; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Driver/SQLSrv/StatementTest.php000066400000000000000000000021561360544566000316250ustar00rootroot00000000000000connection->getDriver() instanceof Driver) { return; } self::markTestSkipped('sqlsrv only test'); } public function testFailureToPrepareResultsInException() : void { // use the driver connection directly to avoid having exception wrapped $stmt = $this->connection->getWrappedConnection()->prepare(null); // it's impossible to prepare the statement without bound variables for SQL Server, // so the preparation happens before the first execution when variables are already in place $this->expectException(SQLSrvException::class); $stmt->execute(); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/ExceptionTest.php000066400000000000000000000357061360544566000272410ustar00rootroot00000000000000connection->getDriver() instanceof ExceptionConverterDriver) { return; } $this->markTestSkipped('Driver does not support special exception handling.'); } public function testPrimaryConstraintViolationException() : void { $table = new Table('duplicatekey_table'); $table->addColumn('id', 'integer', []); $table->setPrimaryKey(['id']); $this->connection->getSchemaManager()->createTable($table); $this->connection->insert('duplicatekey_table', ['id' => 1]); $this->expectException(Exception\UniqueConstraintViolationException::class); $this->connection->insert('duplicatekey_table', ['id' => 1]); } public function testTableNotFoundException() : void { $sql = 'SELECT * FROM unknown_table'; $this->expectException(Exception\TableNotFoundException::class); $this->connection->executeQuery($sql); } public function testTableExistsException() : void { $schemaManager = $this->connection->getSchemaManager(); $table = new Table('alreadyexist_table'); $table->addColumn('id', 'integer', []); $table->setPrimaryKey(['id']); $this->expectException(Exception\TableExistsException::class); $schemaManager->createTable($table); $schemaManager->createTable($table); } public function testForeignKeyConstraintViolationExceptionOnInsert() : void { if (! $this->connection->getDatabasePlatform()->supportsForeignKeyConstraints()) { $this->markTestSkipped('Only fails on platforms with foreign key constraints.'); } $this->setUpForeignKeyConstraintViolationExceptionTest(); try { $this->connection->insert('constraint_error_table', ['id' => 1]); $this->connection->insert('owning_table', ['id' => 1, 'constraint_id' => 1]); } catch (Throwable $exception) { $this->tearDownForeignKeyConstraintViolationExceptionTest(); throw $exception; } $this->expectException(Exception\ForeignKeyConstraintViolationException::class); try { $this->connection->insert('owning_table', ['id' => 2, 'constraint_id' => 2]); } catch (Exception\ForeignKeyConstraintViolationException $exception) { $this->tearDownForeignKeyConstraintViolationExceptionTest(); throw $exception; } catch (Throwable $exception) { $this->tearDownForeignKeyConstraintViolationExceptionTest(); throw $exception; } $this->tearDownForeignKeyConstraintViolationExceptionTest(); } public function testForeignKeyConstraintViolationExceptionOnUpdate() : void { if (! $this->connection->getDatabasePlatform()->supportsForeignKeyConstraints()) { $this->markTestSkipped('Only fails on platforms with foreign key constraints.'); } $this->setUpForeignKeyConstraintViolationExceptionTest(); try { $this->connection->insert('constraint_error_table', ['id' => 1]); $this->connection->insert('owning_table', ['id' => 1, 'constraint_id' => 1]); } catch (Throwable $exception) { $this->tearDownForeignKeyConstraintViolationExceptionTest(); throw $exception; } $this->expectException(Exception\ForeignKeyConstraintViolationException::class); try { $this->connection->update('constraint_error_table', ['id' => 2], ['id' => 1]); } catch (Exception\ForeignKeyConstraintViolationException $exception) { $this->tearDownForeignKeyConstraintViolationExceptionTest(); throw $exception; } catch (Throwable $exception) { $this->tearDownForeignKeyConstraintViolationExceptionTest(); throw $exception; } $this->tearDownForeignKeyConstraintViolationExceptionTest(); } public function testForeignKeyConstraintViolationExceptionOnDelete() : void { if (! $this->connection->getDatabasePlatform()->supportsForeignKeyConstraints()) { $this->markTestSkipped('Only fails on platforms with foreign key constraints.'); } $this->setUpForeignKeyConstraintViolationExceptionTest(); try { $this->connection->insert('constraint_error_table', ['id' => 1]); $this->connection->insert('owning_table', ['id' => 1, 'constraint_id' => 1]); } catch (Throwable $exception) { $this->tearDownForeignKeyConstraintViolationExceptionTest(); throw $exception; } $this->expectException(Exception\ForeignKeyConstraintViolationException::class); try { $this->connection->delete('constraint_error_table', ['id' => 1]); } catch (Exception\ForeignKeyConstraintViolationException $exception) { $this->tearDownForeignKeyConstraintViolationExceptionTest(); throw $exception; } catch (Throwable $exception) { $this->tearDownForeignKeyConstraintViolationExceptionTest(); throw $exception; } $this->tearDownForeignKeyConstraintViolationExceptionTest(); } public function testForeignKeyConstraintViolationExceptionOnTruncate() : void { $platform = $this->connection->getDatabasePlatform(); if (! $platform->supportsForeignKeyConstraints()) { $this->markTestSkipped('Only fails on platforms with foreign key constraints.'); } $this->setUpForeignKeyConstraintViolationExceptionTest(); try { $this->connection->insert('constraint_error_table', ['id' => 1]); $this->connection->insert('owning_table', ['id' => 1, 'constraint_id' => 1]); } catch (Throwable $exception) { $this->tearDownForeignKeyConstraintViolationExceptionTest(); throw $exception; } $this->expectException(Exception\ForeignKeyConstraintViolationException::class); try { $this->connection->executeUpdate($platform->getTruncateTableSQL('constraint_error_table')); } catch (Exception\ForeignKeyConstraintViolationException $exception) { $this->tearDownForeignKeyConstraintViolationExceptionTest(); throw $exception; } catch (Throwable $exception) { $this->tearDownForeignKeyConstraintViolationExceptionTest(); throw $exception; } $this->tearDownForeignKeyConstraintViolationExceptionTest(); } public function testNotNullConstraintViolationException() : void { $schema = new Schema(); $table = $schema->createTable('notnull_table'); $table->addColumn('id', 'integer', []); $table->addColumn('value', 'integer', ['notnull' => true]); $table->setPrimaryKey(['id']); foreach ($schema->toSql($this->connection->getDatabasePlatform()) as $sql) { $this->connection->exec($sql); } $this->expectException(Exception\NotNullConstraintViolationException::class); $this->connection->insert('notnull_table', ['id' => 1, 'value' => null]); } public function testInvalidFieldNameException() : void { $schema = new Schema(); $table = $schema->createTable('bad_fieldname_table'); $table->addColumn('id', 'integer', []); foreach ($schema->toSql($this->connection->getDatabasePlatform()) as $sql) { $this->connection->exec($sql); } $this->expectException(Exception\InvalidFieldNameException::class); $this->connection->insert('bad_fieldname_table', ['name' => 5]); } public function testNonUniqueFieldNameException() : void { $schema = new Schema(); $table = $schema->createTable('ambiguous_list_table'); $table->addColumn('id', 'integer'); $table2 = $schema->createTable('ambiguous_list_table_2'); $table2->addColumn('id', 'integer'); foreach ($schema->toSql($this->connection->getDatabasePlatform()) as $sql) { $this->connection->exec($sql); } $sql = 'SELECT id FROM ambiguous_list_table, ambiguous_list_table_2'; $this->expectException(Exception\NonUniqueFieldNameException::class); $this->connection->executeQuery($sql); } public function testUniqueConstraintViolationException() : void { $schema = new Schema(); $table = $schema->createTable('unique_field_table'); $table->addColumn('id', 'integer'); $table->addUniqueIndex(['id']); foreach ($schema->toSql($this->connection->getDatabasePlatform()) as $sql) { $this->connection->exec($sql); } $this->connection->insert('unique_field_table', ['id' => 5]); $this->expectException(Exception\UniqueConstraintViolationException::class); $this->connection->insert('unique_field_table', ['id' => 5]); } public function testSyntaxErrorException() : void { $table = new Table('syntax_error_table'); $table->addColumn('id', 'integer', []); $table->setPrimaryKey(['id']); $this->connection->getSchemaManager()->createTable($table); $sql = 'SELECT id FRO syntax_error_table'; $this->expectException(Exception\SyntaxErrorException::class); $this->connection->executeQuery($sql); } public function testConnectionExceptionSqLite() : void { if (! ($this->connection->getDatabasePlatform() instanceof SqlitePlatform)) { $this->markTestSkipped('Only fails this way on sqlite'); } // mode 0 is considered read-only on Windows $mode = PHP_OS === 'Linux' ? 0444 : 0000; $filename = sprintf('%s/%s', sys_get_temp_dir(), 'doctrine_failed_connection_' . $mode . '.db'); if (file_exists($filename)) { $this->cleanupReadOnlyFile($filename); } touch($filename); chmod($filename, $mode); if ($this->isLinuxRoot()) { exec(sprintf('chattr +i %s', $filename)); } $params = [ 'driver' => 'pdo_sqlite', 'path' => $filename, ]; $conn = DriverManager::getConnection($params); $schema = new Schema(); $table = $schema->createTable('no_connection'); $table->addColumn('id', 'integer'); $this->expectException(Exception\ReadOnlyException::class); $this->expectExceptionMessage( <<toSql($conn->getDatabasePlatform()) as $sql) { $conn->exec($sql); } } finally { $this->cleanupReadOnlyFile($filename); } } /** * @param array $params * * @dataProvider getConnectionParams */ public function testConnectionException(array $params) : void { $platform = $this->connection->getDatabasePlatform(); if ($platform instanceof SqlitePlatform) { $this->markTestSkipped('Only skipped if platform is not sqlite'); } if ($platform instanceof DrizzlePlatform) { $this->markTestSkipped('Drizzle does not always support authentication'); } if ($platform instanceof PostgreSqlPlatform && isset($params['password'])) { $this->markTestSkipped('Does not work on Travis'); } if ($platform instanceof MySqlPlatform && isset($params['user'])) { $wrappedConnection = $this->connection->getWrappedConnection(); assert($wrappedConnection instanceof ServerInfoAwareConnection); if (version_compare($wrappedConnection->getServerVersion(), '8', '>=')) { $this->markTestIncomplete('PHP currently does not completely support MySQL 8'); } } $defaultParams = $this->connection->getParams(); $params = array_merge($defaultParams, $params); $conn = DriverManager::getConnection($params); $schema = new Schema(); $table = $schema->createTable('no_connection'); $table->addColumn('id', 'integer'); $this->expectException(Exception\ConnectionException::class); foreach ($schema->toSql($conn->getDatabasePlatform()) as $sql) { $conn->exec($sql); } } /** * @return array> */ public static function getConnectionParams() : iterable { return [ [['user' => 'not_existing']], [['password' => 'really_not']], [['host' => 'localnope']], ]; } private function setUpForeignKeyConstraintViolationExceptionTest() : void { $schemaManager = $this->connection->getSchemaManager(); $table = new Table('constraint_error_table'); $table->addColumn('id', 'integer', []); $table->setPrimaryKey(['id']); $owningTable = new Table('owning_table'); $owningTable->addColumn('id', 'integer', []); $owningTable->addColumn('constraint_id', 'integer', []); $owningTable->setPrimaryKey(['id']); $owningTable->addForeignKeyConstraint($table, ['constraint_id'], ['id']); $schemaManager->createTable($table); $schemaManager->createTable($owningTable); } private function tearDownForeignKeyConstraintViolationExceptionTest() : void { $schemaManager = $this->connection->getSchemaManager(); $schemaManager->dropTable('owning_table'); $schemaManager->dropTable('constraint_error_table'); } private function isLinuxRoot() : bool { return PHP_OS === 'Linux' && posix_getpwuid(posix_geteuid())['name'] === 'root'; } private function cleanupReadOnlyFile(string $filename) : void { if ($this->isLinuxRoot()) { exec(sprintf('chattr -i %s', $filename)); } chmod($filename, 0200); // make the file writable again, so it can be removed on Windows unlink($filename); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/LikeWildcardsEscapingTest.php000066400000000000000000000016551360544566000314720ustar00rootroot00000000000000connection->getDatabasePlatform(); $stmt = $this->connection->prepare( $databasePlatform->getDummySelectSQL( sprintf( "(CASE WHEN '%s' LIKE '%s' ESCAPE '%s' THEN 1 ELSE 0 END)", $string, $databasePlatform->escapeStringForLike($string, $escapeChar), $escapeChar ) ) ); $stmt->execute(); $this->assertTrue((bool) $stmt->fetchColumn()); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/LoggingTest.php000066400000000000000000000037161360544566000266650ustar00rootroot00000000000000connection->getDatabasePlatform()->getDummySelectSQL(); $logMock = $this->createMock(SQLLogger::class); $logMock->expects($this->at(0)) ->method('startQuery') ->with($this->equalTo($sql), $this->equalTo([]), $this->equalTo([])); $logMock->expects($this->at(1)) ->method('stopQuery'); $this->connection->getConfiguration()->setSQLLogger($logMock); $this->connection->executeQuery($sql, []); } public function testLogExecuteUpdate() : void { $this->markTestSkipped('Test breaks MySQL but works on all other platforms (Unbuffered Queries stuff).'); $sql = $this->connection->getDatabasePlatform()->getDummySelectSQL(); $logMock = $this->createMock(SQLLogger::class); $logMock->expects($this->at(0)) ->method('startQuery') ->with($this->equalTo($sql), $this->equalTo([]), $this->equalTo([])); $logMock->expects($this->at(1)) ->method('stopQuery'); $this->connection->getConfiguration()->setSQLLogger($logMock); $this->connection->executeUpdate($sql, []); } public function testLogPrepareExecute() : void { $sql = $this->connection->getDatabasePlatform()->getDummySelectSQL(); $logMock = $this->createMock(SQLLogger::class); $logMock->expects($this->once()) ->method('startQuery') ->with($this->equalTo($sql), $this->equalTo([])); $logMock->expects($this->at(1)) ->method('stopQuery'); $this->connection->getConfiguration()->setSQLLogger($logMock); $stmt = $this->connection->prepare($sql); $stmt->execute(); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/MasterSlaveConnectionTest.php000066400000000000000000000162111360544566000315370ustar00rootroot00000000000000connection->getDatabasePlatform()->getName(); // This is a MySQL specific test, skip other vendors. if ($platformName !== 'mysql') { $this->markTestSkipped(sprintf('Test does not work on %s.', $platformName)); } try { $table = new Table('master_slave_table'); $table->addColumn('test_int', 'integer'); $table->setPrimaryKey(['test_int']); $sm = $this->connection->getSchemaManager(); $sm->createTable($table); } catch (Throwable $e) { } $this->connection->executeUpdate('DELETE FROM master_slave_table'); $this->connection->insert('master_slave_table', ['test_int' => 1]); } private function createMasterSlaveConnection(bool $keepSlave = false) : MasterSlaveConnection { return DriverManager::getConnection($this->createMasterSlaveConnectionParams($keepSlave)); } /** * @return mixed[] */ private function createMasterSlaveConnectionParams(bool $keepSlave = false) : array { $params = $this->connection->getParams(); $params['master'] = $params; $params['slaves'] = [$params, $params]; $params['keepSlave'] = $keepSlave; $params['wrapperClass'] = MasterSlaveConnection::class; return $params; } public function testInheritCharsetFromMaster() : void { $charsets = [ 'utf8', 'latin1', ]; foreach ($charsets as $charset) { $params = $this->createMasterSlaveConnectionParams(); $params['master']['charset'] = $charset; foreach ($params['slaves'] as $index => $slaveParams) { if (! isset($slaveParams['charset'])) { continue; } unset($params['slaves'][$index]['charset']); } /** @var MasterSlaveConnection $conn */ $conn = DriverManager::getConnection($params); $conn->connect('slave'); self::assertFalse($conn->isConnectedToMaster()); $clientCharset = $conn->fetchColumn('select @@character_set_client as c'); self::assertSame( $charset, substr(strtolower($clientCharset), 0, strlen($charset)) ); } } public function testMasterOnConnect() : void { $conn = $this->createMasterSlaveConnection(); self::assertFalse($conn->isConnectedToMaster()); $conn->connect('slave'); self::assertFalse($conn->isConnectedToMaster()); $conn->connect('master'); self::assertTrue($conn->isConnectedToMaster()); } public function testNoMasterOnExecuteQuery() : void { $conn = $this->createMasterSlaveConnection(); $sql = 'SELECT count(*) as num FROM master_slave_table'; $data = $conn->fetchAll($sql); $data[0] = array_change_key_case($data[0], CASE_LOWER); self::assertEquals(1, $data[0]['num']); self::assertFalse($conn->isConnectedToMaster()); } public function testMasterOnWriteOperation() : void { $conn = $this->createMasterSlaveConnection(); $conn->insert('master_slave_table', ['test_int' => 30]); self::assertTrue($conn->isConnectedToMaster()); $sql = 'SELECT count(*) as num FROM master_slave_table'; $data = $conn->fetchAll($sql); $data[0] = array_change_key_case($data[0], CASE_LOWER); self::assertEquals(2, $data[0]['num']); self::assertTrue($conn->isConnectedToMaster()); } /** * @group DBAL-335 */ public function testKeepSlaveBeginTransactionStaysOnMaster() : void { $conn = $this->createMasterSlaveConnection($keepSlave = true); $conn->connect('slave'); $conn->beginTransaction(); $conn->insert('master_slave_table', ['test_int' => 30]); $conn->commit(); self::assertTrue($conn->isConnectedToMaster()); $conn->connect(); self::assertTrue($conn->isConnectedToMaster()); $conn->connect('slave'); self::assertFalse($conn->isConnectedToMaster()); } /** * @group DBAL-335 */ public function testKeepSlaveInsertStaysOnMaster() : void { $conn = $this->createMasterSlaveConnection($keepSlave = true); $conn->connect('slave'); $conn->insert('master_slave_table', ['test_int' => 30]); self::assertTrue($conn->isConnectedToMaster()); $conn->connect(); self::assertTrue($conn->isConnectedToMaster()); $conn->connect('slave'); self::assertFalse($conn->isConnectedToMaster()); } public function testMasterSlaveConnectionCloseAndReconnect() : void { $conn = $this->createMasterSlaveConnection(); $conn->connect('master'); self::assertTrue($conn->isConnectedToMaster()); $conn->close(); self::assertFalse($conn->isConnectedToMaster()); $conn->connect('master'); self::assertTrue($conn->isConnectedToMaster()); } public function testQueryOnMaster() : void { $conn = $this->createMasterSlaveConnection(); $query = 'SELECT count(*) as num FROM master_slave_table'; $statement = $conn->query($query); self::assertInstanceOf(Statement::class, $statement); //Query must be executed only on Master self::assertTrue($conn->isConnectedToMaster()); $data = $statement->fetchAll(); //Default fetchmode is FetchMode::ASSOCIATIVE self::assertArrayHasKey(0, $data); self::assertArrayHasKey('num', $data[0]); //Could be set in other fetchmodes self::assertArrayNotHasKey(0, $data[0]); self::assertEquals(1, $data[0]['num']); } public function testQueryOnSlave() : void { $conn = $this->createMasterSlaveConnection(); $conn->connect('slave'); $query = 'SELECT count(*) as num FROM master_slave_table'; $statement = $conn->query($query); self::assertInstanceOf(Statement::class, $statement); //Query must be executed only on Master, even when we connect to the slave self::assertTrue($conn->isConnectedToMaster()); $data = $statement->fetchAll(); //Default fetchmode is FetchMode::ASSOCIATIVE self::assertArrayHasKey(0, $data); self::assertArrayHasKey('num', $data[0]); //Could be set in other fetchmodes self::assertArrayNotHasKey(0, $data[0]); self::assertEquals(1, $data[0]['num']); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/ModifyLimitQueryTest.php000066400000000000000000000166151360544566000305550ustar00rootroot00000000000000addColumn('test_int', 'integer'); $table->setPrimaryKey(['test_int']); $table2 = new Table('modify_limit_table2'); $table2->addColumn('id', 'integer', ['autoincrement' => true]); $table2->addColumn('test_int', 'integer'); $table2->setPrimaryKey(['id']); $sm = $this->connection->getSchemaManager(); $sm->createTable($table); $sm->createTable($table2); self::$tableCreated = true; } $this->connection->exec($this->connection->getDatabasePlatform()->getTruncateTableSQL('modify_limit_table')); $this->connection->exec($this->connection->getDatabasePlatform()->getTruncateTableSQL('modify_limit_table2')); } public function testModifyLimitQuerySimpleQuery() : void { $this->connection->insert('modify_limit_table', ['test_int' => 1]); $this->connection->insert('modify_limit_table', ['test_int' => 2]); $this->connection->insert('modify_limit_table', ['test_int' => 3]); $this->connection->insert('modify_limit_table', ['test_int' => 4]); $sql = 'SELECT * FROM modify_limit_table ORDER BY test_int ASC'; $this->assertLimitResult([1, 2, 3, 4], $sql, 10, 0); $this->assertLimitResult([1, 2], $sql, 2, 0); $this->assertLimitResult([3, 4], $sql, 2, 2); $this->assertLimitResult([2, 3, 4], $sql, null, 1); } public function testModifyLimitQueryJoinQuery() : void { $this->connection->insert('modify_limit_table', ['test_int' => 1]); $this->connection->insert('modify_limit_table', ['test_int' => 2]); $this->connection->insert('modify_limit_table2', ['test_int' => 1]); $this->connection->insert('modify_limit_table2', ['test_int' => 1]); $this->connection->insert('modify_limit_table2', ['test_int' => 1]); $this->connection->insert('modify_limit_table2', ['test_int' => 2]); $this->connection->insert('modify_limit_table2', ['test_int' => 2]); $sql = 'SELECT modify_limit_table.test_int FROM modify_limit_table INNER JOIN modify_limit_table2 ON modify_limit_table.test_int = modify_limit_table2.test_int ORDER BY modify_limit_table.test_int DESC'; $this->assertLimitResult([2, 2, 1, 1, 1], $sql, 10, 0); $this->assertLimitResult([1, 1, 1], $sql, 3, 2); $this->assertLimitResult([2, 2], $sql, 2, 0); } public function testModifyLimitQueryNonDeterministic() : void { $this->connection->insert('modify_limit_table', ['test_int' => 1]); $this->connection->insert('modify_limit_table', ['test_int' => 2]); $this->connection->insert('modify_limit_table', ['test_int' => 3]); $this->connection->insert('modify_limit_table', ['test_int' => 4]); $sql = 'SELECT * FROM modify_limit_table'; $this->assertLimitResult([4, 3, 2, 1], $sql, 10, 0, false); $this->assertLimitResult([4, 3], $sql, 2, 0, false); $this->assertLimitResult([2, 1], $sql, 2, 2, false); } public function testModifyLimitQueryGroupBy() : void { $this->connection->insert('modify_limit_table', ['test_int' => 1]); $this->connection->insert('modify_limit_table', ['test_int' => 2]); $this->connection->insert('modify_limit_table2', ['test_int' => 1]); $this->connection->insert('modify_limit_table2', ['test_int' => 1]); $this->connection->insert('modify_limit_table2', ['test_int' => 1]); $this->connection->insert('modify_limit_table2', ['test_int' => 2]); $this->connection->insert('modify_limit_table2', ['test_int' => 2]); $sql = 'SELECT modify_limit_table.test_int FROM modify_limit_table ' . 'INNER JOIN modify_limit_table2 ON modify_limit_table.test_int = modify_limit_table2.test_int ' . 'GROUP BY modify_limit_table.test_int ' . 'ORDER BY modify_limit_table.test_int ASC'; $this->assertLimitResult([1, 2], $sql, 10, 0); $this->assertLimitResult([1], $sql, 1, 0); $this->assertLimitResult([2], $sql, 1, 1); } public function testModifyLimitQuerySubSelect() : void { $this->connection->insert('modify_limit_table', ['test_int' => 1]); $this->connection->insert('modify_limit_table', ['test_int' => 2]); $this->connection->insert('modify_limit_table', ['test_int' => 3]); $this->connection->insert('modify_limit_table', ['test_int' => 4]); $sql = 'SELECT modify_limit_table.*, (SELECT COUNT(*) FROM modify_limit_table) AS cnt FROM modify_limit_table ORDER BY test_int DESC'; $this->assertLimitResult([4, 3, 2, 1], $sql, 10, 0); $this->assertLimitResult([4, 3], $sql, 2, 0); $this->assertLimitResult([2, 1], $sql, 2, 2); } public function testModifyLimitQueryFromSubSelect() : void { $this->connection->insert('modify_limit_table', ['test_int' => 1]); $this->connection->insert('modify_limit_table', ['test_int' => 2]); $this->connection->insert('modify_limit_table', ['test_int' => 3]); $this->connection->insert('modify_limit_table', ['test_int' => 4]); $sql = 'SELECT * FROM (SELECT * FROM modify_limit_table) sub ORDER BY test_int DESC'; $this->assertLimitResult([4, 3, 2, 1], $sql, 10, 0); $this->assertLimitResult([4, 3], $sql, 2, 0); $this->assertLimitResult([2, 1], $sql, 2, 2); } public function testModifyLimitQueryLineBreaks() : void { $this->connection->insert('modify_limit_table', ['test_int' => 1]); $this->connection->insert('modify_limit_table', ['test_int' => 2]); $this->connection->insert('modify_limit_table', ['test_int' => 3]); $sql = <<assertLimitResult([2], $sql, 1, 1); } public function testModifyLimitQueryZeroOffsetNoLimit() : void { $this->connection->insert('modify_limit_table', ['test_int' => 1]); $this->connection->insert('modify_limit_table', ['test_int' => 2]); $sql = 'SELECT test_int FROM modify_limit_table ORDER BY test_int ASC'; $this->assertLimitResult([1, 2], $sql, null, 0); } /** * @param array $expectedResults */ private function assertLimitResult(array $expectedResults, string $sql, ?int $limit, int $offset, bool $deterministic = true) : void { $p = $this->connection->getDatabasePlatform(); $data = []; foreach ($this->connection->fetchAll($p->modifyLimitQuery($sql, $limit, $offset)) as $row) { $row = array_change_key_case($row, CASE_LOWER); $data[] = $row['test_int']; } /** * Do not assert the order of results when results are non-deterministic */ if ($deterministic) { self::assertEquals($expectedResults, $data); } else { self::assertCount(count($expectedResults), $data); } } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/NamedParametersTest.php000066400000000000000000000153751360544566000303530ustar00rootroot00000000000000> */ public static function ticketProvider() : iterable { return [ [ 'SELECT * FROM ddc1372_foobar f WHERE f.foo = :foo AND f.bar IN (:bar)', [ 'foo' => 1, 'bar' => [1, 2, 3], ], [ 'foo' => ParameterType::INTEGER, 'bar' => Connection::PARAM_INT_ARRAY, ], [ ['id' => 1, 'foo' => 1, 'bar' => 1], ['id' => 2, 'foo' => 1, 'bar' => 2], ['id' => 3, 'foo' => 1, 'bar' => 3], ], ], [ 'SELECT * FROM ddc1372_foobar f WHERE f.foo = :foo AND f.bar IN (:bar)', [ 'foo' => 1, 'bar' => [1, 2, 3], ], [ 'bar' => Connection::PARAM_INT_ARRAY, 'foo' => ParameterType::INTEGER, ], [ ['id' => 1, 'foo' => 1, 'bar' => 1], ['id' => 2, 'foo' => 1, 'bar' => 2], ['id' => 3, 'foo' => 1, 'bar' => 3], ], ], [ 'SELECT * FROM ddc1372_foobar f WHERE f.bar IN (:bar) AND f.foo = :foo', [ 'foo' => 1, 'bar' => [1, 2, 3], ], [ 'bar' => Connection::PARAM_INT_ARRAY, 'foo' => ParameterType::INTEGER, ], [ ['id' => 1, 'foo' => 1, 'bar' => 1], ['id' => 2, 'foo' => 1, 'bar' => 2], ['id' => 3, 'foo' => 1, 'bar' => 3], ], ], [ 'SELECT * FROM ddc1372_foobar f WHERE f.bar IN (:bar) AND f.foo = :foo', [ 'foo' => 1, 'bar' => ['1', '2', '3'], ], [ 'bar' => Connection::PARAM_STR_ARRAY, 'foo' => ParameterType::INTEGER, ], [ ['id' => 1, 'foo' => 1, 'bar' => 1], ['id' => 2, 'foo' => 1, 'bar' => 2], ['id' => 3, 'foo' => 1, 'bar' => 3], ], ], [ 'SELECT * FROM ddc1372_foobar f WHERE f.bar IN (:bar) AND f.foo IN (:foo)', [ 'foo' => ['1'], 'bar' => [1, 2, 3, 4], ], [ 'bar' => Connection::PARAM_STR_ARRAY, 'foo' => Connection::PARAM_INT_ARRAY, ], [ ['id' => 1, 'foo' => 1, 'bar' => 1], ['id' => 2, 'foo' => 1, 'bar' => 2], ['id' => 3, 'foo' => 1, 'bar' => 3], ['id' => 4, 'foo' => 1, 'bar' => 4], ], ], [ 'SELECT * FROM ddc1372_foobar f WHERE f.bar IN (:bar) AND f.foo IN (:foo)', [ 'foo' => 1, 'bar' => 2, ], [ 'bar' => ParameterType::INTEGER, 'foo' => ParameterType::INTEGER, ], [ ['id' => 2, 'foo' => 1, 'bar' => 2], ], ], [ 'SELECT * FROM ddc1372_foobar f WHERE f.bar = :arg AND f.foo <> :arg', ['arg' => '1'], [ 'arg' => ParameterType::STRING, ], [ ['id' => 5, 'foo' => 2, 'bar' => 1], ], ], [ 'SELECT * FROM ddc1372_foobar f WHERE f.bar NOT IN (:arg) AND f.foo IN (:arg)', [ 'arg' => [1, 2], ], [ 'arg' => Connection::PARAM_INT_ARRAY, ], [ ['id' => 3, 'foo' => 1, 'bar' => 3], ['id' => 4, 'foo' => 1, 'bar' => 4], ], ], ]; } protected function setUp() : void { parent::setUp(); if ($this->connection->getSchemaManager()->tablesExist('ddc1372_foobar')) { return; } try { $table = new Table('ddc1372_foobar'); $table->addColumn('id', 'integer'); $table->addColumn('foo', 'string'); $table->addColumn('bar', 'string'); $table->setPrimaryKey(['id']); $sm = $this->connection->getSchemaManager(); $sm->createTable($table); $this->connection->insert('ddc1372_foobar', [ 'id' => 1, 'foo' => 1, 'bar' => 1, ]); $this->connection->insert('ddc1372_foobar', [ 'id' => 2, 'foo' => 1, 'bar' => 2, ]); $this->connection->insert('ddc1372_foobar', [ 'id' => 3, 'foo' => 1, 'bar' => 3, ]); $this->connection->insert('ddc1372_foobar', [ 'id' => 4, 'foo' => 1, 'bar' => 4, ]); $this->connection->insert('ddc1372_foobar', [ 'id' => 5, 'foo' => 2, 'bar' => 1, ]); $this->connection->insert('ddc1372_foobar', [ 'id' => 6, 'foo' => 2, 'bar' => 2, ]); } catch (Throwable $e) { $this->fail($e->getMessage()); } } /** * @param mixed[] $params * @param int[] $types * @param int[] $expected * * @dataProvider ticketProvider */ public function testTicket(string $query, array $params, array $types, array $expected) : void { $stmt = $this->connection->executeQuery($query, $params, $types); $result = $stmt->fetchAll(FetchMode::ASSOCIATIVE); foreach ($result as $k => $v) { $result[$k] = array_change_key_case($v, CASE_LOWER); } self::assertEquals($result, $expected); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/PDOStatementTest.php000066400000000000000000000027521360544566000276050ustar00rootroot00000000000000markTestSkipped('PDO is not installed'); } parent::setUp(); if (! $this->connection->getWrappedConnection() instanceof PDOConnection) { $this->markTestSkipped('PDO-only test'); } $table = new Table('stmt_test'); $table->addColumn('id', 'integer'); $table->addColumn('name', 'string'); $this->connection->getSchemaManager()->dropAndCreateTable($table); } /** * @group legacy * @expectedDeprecation Using a PDO fetch mode or their combination (%d given) is deprecated and will cause an error in Doctrine DBAL 3.0 */ public function testPDOSpecificModeIsAccepted() : void { $this->connection->insert('stmt_test', [ 'id' => 1, 'name' => 'Alice', ]); $this->connection->insert('stmt_test', [ 'id' => 2, 'name' => 'Bob', ]); $data = $this->connection->query('SELECT id, name FROM stmt_test ORDER BY id') ->fetchAll(PDO::FETCH_KEY_PAIR); self::assertSame([ 1 => 'Alice', 2 => 'Bob', ], $data); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Platform/000077500000000000000000000000001360544566000255035ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Platform/DateExpressionTest.php000066400000000000000000000032621360544566000320140ustar00rootroot00000000000000addColumn('date1', 'datetime'); $table->addColumn('date2', 'datetime'); $this->connection->getSchemaManager()->dropAndCreateTable($table); $this->connection->insert('date_expr_test', [ 'date1' => $date1, 'date2' => $date2, ]); $platform = $this->connection->getDatabasePlatform(); $sql = sprintf('SELECT %s FROM date_expr_test', $platform->getDateDiffExpression('date1', 'date2')); $diff = $this->connection->query($sql)->fetchColumn(); self::assertEquals($expected, $diff); } /** * @return string[][]|int[][] */ public static function differenceProvider() : iterable { $date1 = new DateTimeImmutable(); $date2 = new DateTimeImmutable('2018-04-10 10:10:10'); $expected = $date1->modify('midnight')->diff( $date2->modify('midnight') )->days; return [ 'dynamic' => [ $date1->format('Y-m-d H:i:s'), $date2->format('Y-m-d H:i:s'), $expected, ], 'same day' => ['2018-04-14 23:59:59', '2018-04-14 00:00:00', 0], 'midnight' => ['2018-04-14 00:00:00', '2018-04-13 23:59:59', 1], ]; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Platform/DefaultExpressionTest.php000066400000000000000000000047641360544566000325330ustar00rootroot00000000000000connection->getDatabasePlatform(); if ($platform instanceof MySqlPlatform) { self::markTestSkipped('Not supported on MySQL'); } $this->assertDefaultExpression(Types::DATE_MUTABLE, static function (AbstractPlatform $platform) : string { return $platform->getCurrentDateSQL(); }); } public function testCurrentTime() : void { $platform = $this->connection->getDatabasePlatform(); if ($platform instanceof MySqlPlatform) { self::markTestSkipped('Not supported on MySQL'); } if ($platform instanceof OraclePlatform) { self::markTestSkipped('Not supported on Oracle'); } $this->assertDefaultExpression(Types::TIME_MUTABLE, static function (AbstractPlatform $platform) : string { return $platform->getCurrentTimeSQL(); }); } public function testCurrentTimestamp() : void { $this->assertDefaultExpression(Types::DATETIME_MUTABLE, static function (AbstractPlatform $platform) : string { return $platform->getCurrentTimestampSQL(); }); } private function assertDefaultExpression(string $type, callable $expression) : void { $platform = $this->connection->getDatabasePlatform(); $defaultSql = $expression($platform, $this); $table = new Table('default_expr_test'); $table->addColumn('actual_value', $type); $table->addColumn('default_value', $type, ['default' => $defaultSql]); $this->connection->getSchemaManager()->dropAndCreateTable($table); $this->connection->exec( sprintf( 'INSERT INTO default_expr_test (actual_value) VALUES (%s)', $defaultSql ) ); [$actualValue, $defaultValue] = $this->connection->query( 'SELECT default_value, actual_value FROM default_expr_test' )->fetch(FetchMode::NUMERIC); self::assertEquals($actualValue, $defaultValue); } } NewPrimaryKeyWithNewAutoIncrementColumnTest.php000066400000000000000000000046041360544566000367310ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/PlatformgetPlatform()->getName(), ['mysql'])) { return; } $this->markTestSkipped('Restricted to MySQL.'); } /** * Ensures that the primary key is created within the same "alter table" statement that an auto-increment column * is added to the table as part of the new primary key. * * Before the fix for this problem this resulted in a database error: (at least on mysql) * SQLSTATE[42000]: Syntax error or access violation: 1075 Incorrect table definition; there can be only one auto * column and it must be defined as a key */ public function testAlterPrimaryKeyToAutoIncrementColumn() : void { $schemaManager = $this->connection->getSchemaManager(); $schema = $schemaManager->createSchema(); $table = $schema->createTable('dbal2807'); $table->addColumn('initial_id', 'integer'); $table->setPrimaryKey(['initial_id']); $schemaManager->dropAndCreateTable($table); $newSchema = clone $schema; $newTable = $newSchema->getTable($table->getName()); $newTable->addColumn('new_id', 'integer', ['autoincrement' => true]); $newTable->dropPrimaryKey(); $newTable->setPrimaryKey(['new_id']); $diff = (new Comparator())->compare($schema, $newSchema); foreach ($diff->toSql($this->getPlatform()) as $sql) { $this->connection->exec($sql); } $validationSchema = $schemaManager->createSchema(); $validationTable = $validationSchema->getTable($table->getName()); $this->assertTrue($validationTable->hasColumn('new_id')); $this->assertTrue($validationTable->getColumn('new_id')->getAutoincrement()); $this->assertTrue($validationTable->hasPrimaryKey()); $this->assertSame(['new_id'], $validationTable->getPrimaryKeyColumns()); } private function getPlatform() : AbstractPlatform { return $this->connection->getDatabasePlatform(); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Platform/QuotingTest.php000066400000000000000000000013671360544566000305110ustar00rootroot00000000000000connection->getDatabasePlatform(); $query = $platform->getDummySelectSQL( $platform->quoteStringLiteral($string) ); self::assertSame($string, $this->connection->fetchColumn($query)); } /** * @return mixed[][] */ public static function stringLiteralProvider() : iterable { return [ 'backslash' => ['\\'], 'single-quote' => ["'"], ]; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/PortabilityTest.php000066400000000000000000000131551360544566000275770ustar00rootroot00000000000000portableConnection) { $this->portableConnection->close(); } parent::tearDown(); } private function getPortableConnection( int $portabilityMode = ConnectionPortability::PORTABILITY_ALL, int $case = ColumnCase::LOWER ) : Connection { if (! $this->portableConnection) { $params = $this->connection->getParams(); $params['wrapperClass'] = ConnectionPortability::class; $params['portability'] = $portabilityMode; $params['fetch_case'] = $case; $this->portableConnection = DriverManager::getConnection($params, $this->connection->getConfiguration(), $this->connection->getEventManager()); try { $table = new Table('portability_table'); $table->addColumn('Test_Int', 'integer'); $table->addColumn('Test_String', 'string', ['fixed' => true, 'length' => 32]); $table->addColumn('Test_Null', 'string', ['notnull' => false]); $table->setPrimaryKey(['Test_Int']); $sm = $this->portableConnection->getSchemaManager(); $sm->createTable($table); $this->portableConnection->insert('portability_table', ['Test_Int' => 1, 'Test_String' => 'foo', 'Test_Null' => '']); $this->portableConnection->insert('portability_table', ['Test_Int' => 2, 'Test_String' => 'foo ', 'Test_Null' => null]); } catch (Throwable $e) { } } return $this->portableConnection; } public function testFullFetchMode() : void { $rows = $this->getPortableConnection()->fetchAll('SELECT * FROM portability_table'); $this->assertFetchResultRows($rows); $stmt = $this->getPortableConnection()->query('SELECT * FROM portability_table'); $stmt->setFetchMode(FetchMode::ASSOCIATIVE); foreach ($stmt as $row) { $this->assertFetchResultRow($row); } $stmt = $this->getPortableConnection()->query('SELECT * FROM portability_table'); while (($row = $stmt->fetch(FetchMode::ASSOCIATIVE))) { $this->assertFetchResultRow($row); } $stmt = $this->getPortableConnection()->prepare('SELECT * FROM portability_table'); $stmt->execute(); while (($row = $stmt->fetch(FetchMode::ASSOCIATIVE))) { $this->assertFetchResultRow($row); } } public function testConnFetchMode() : void { $conn = $this->getPortableConnection(); $conn->setFetchMode(FetchMode::ASSOCIATIVE); $rows = $conn->fetchAll('SELECT * FROM portability_table'); $this->assertFetchResultRows($rows); $stmt = $conn->query('SELECT * FROM portability_table'); foreach ($stmt as $row) { $this->assertFetchResultRow($row); } $stmt = $conn->query('SELECT * FROM portability_table'); while (($row = $stmt->fetch())) { $this->assertFetchResultRow($row); } $stmt = $conn->prepare('SELECT * FROM portability_table'); $stmt->execute(); while (($row = $stmt->fetch())) { $this->assertFetchResultRow($row); } } /** * @param array> $rows */ private function assertFetchResultRows(array $rows) : void { self::assertCount(2, $rows); foreach ($rows as $row) { $this->assertFetchResultRow($row); } } /** * @param array $row */ public function assertFetchResultRow(array $row) : void { self::assertContains($row['test_int'], [1, 2], 'Primary key test_int should either be 1 or 2.'); self::assertArrayHasKey('test_string', $row, 'Case should be lowered.'); self::assertEquals(3, strlen($row['test_string']), 'test_string should be rtrimed to length of three for CHAR(32) column.'); self::assertNull($row['test_null']); self::assertArrayNotHasKey(0, $row, 'The row should not contain numerical keys.'); } /** * @param mixed[] $expected * * @dataProvider fetchAllColumnProvider */ public function testFetchAllColumn(string $field, array $expected) : void { $conn = $this->getPortableConnection(); $stmt = $conn->query('SELECT ' . $field . ' FROM portability_table'); $column = $stmt->fetchAll(FetchMode::COLUMN); self::assertEquals($expected, $column); } /** * @return iterable> */ public static function fetchAllColumnProvider() : iterable { return [ 'int' => [ 'Test_Int', [1, 2], ], 'string' => [ 'Test_String', ['foo', 'foo'], ], ]; } public function testFetchAllNullColumn() : void { $conn = $this->getPortableConnection(); $stmt = $conn->query('SELECT Test_Null FROM portability_table'); $column = $stmt->fetchAll(FetchMode::COLUMN); self::assertSame([null, null], $column); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/ResultCacheTest.php000066400000000000000000000223271360544566000275000ustar00rootroot00000000000000> */ private $expectedResult = [['test_int' => 100, 'test_string' => 'foo'], ['test_int' => 200, 'test_string' => 'bar'], ['test_int' => 300, 'test_string' => 'baz']]; /** @var DebugStack */ private $sqlLogger; protected function setUp() : void { parent::setUp(); $table = new Table('caching'); $table->addColumn('test_int', 'integer'); $table->addColumn('test_string', 'string', ['notnull' => false]); $table->setPrimaryKey(['test_int']); $sm = $this->connection->getSchemaManager(); $sm->createTable($table); foreach ($this->expectedResult as $row) { $this->connection->insert('caching', $row); } $config = $this->connection->getConfiguration(); $config->setSQLLogger($this->sqlLogger = new DebugStack()); $cache = new ArrayCache(); $config->setResultCacheImpl($cache); } protected function tearDown() : void { $this->connection->getSchemaManager()->dropTable('caching'); parent::tearDown(); } public function testCacheFetchAssoc() : void { $this->assertCacheNonCacheSelectSameFetchModeAreEqual( $this->expectedResult, FetchMode::ASSOCIATIVE ); } public function testFetchNum() : void { $expectedResult = []; foreach ($this->expectedResult as $v) { $expectedResult[] = array_values($v); } $this->assertCacheNonCacheSelectSameFetchModeAreEqual($expectedResult, FetchMode::NUMERIC); } public function testFetchBoth() : void { $expectedResult = []; foreach ($this->expectedResult as $v) { $expectedResult[] = array_merge($v, array_values($v)); } $this->assertCacheNonCacheSelectSameFetchModeAreEqual($expectedResult, FetchMode::MIXED); } public function testFetchColumn() : void { $expectedResult = []; foreach ($this->expectedResult as $v) { $expectedResult[] = array_shift($v); } $this->assertCacheNonCacheSelectSameFetchModeAreEqual($expectedResult, FetchMode::COLUMN); } public function testMixingFetch() : void { $numExpectedResult = []; foreach ($this->expectedResult as $v) { $numExpectedResult[] = array_values($v); } $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(10, 'testcachekey')); $data = $this->hydrateStmt($stmt, FetchMode::ASSOCIATIVE); self::assertEquals($this->expectedResult, $data); $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(10, 'testcachekey')); $data = $this->hydrateStmt($stmt, FetchMode::NUMERIC); self::assertEquals($numExpectedResult, $data); } public function testIteratorFetch() : void { self::assertStandardAndIteratorFetchAreEqual(FetchMode::MIXED); self::assertStandardAndIteratorFetchAreEqual(FetchMode::ASSOCIATIVE); self::assertStandardAndIteratorFetchAreEqual(FetchMode::NUMERIC); } private function assertStandardAndIteratorFetchAreEqual(int $fetchMode) : void { $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(10, 'testcachekey')); $data = $this->hydrateStmt($stmt, $fetchMode); $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(10, 'testcachekey')); $data_iterator = $this->hydrateStmtIterator($stmt, $fetchMode); self::assertEquals($data, $data_iterator); } public function testDontCloseNoCache() : void { $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(10, 'testcachekey')); $data = []; while ($row = $stmt->fetch(FetchMode::ASSOCIATIVE)) { $data[] = $row; } $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(10, 'testcachekey')); $data = []; while ($row = $stmt->fetch(FetchMode::NUMERIC)) { $data[] = $row; } self::assertCount(2, $this->sqlLogger->queries); } public function testDontFinishNoCache() : void { $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(10, 'testcachekey')); $stmt->fetch(FetchMode::ASSOCIATIVE); $stmt->closeCursor(); $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(10, 'testcachekey')); $this->hydrateStmt($stmt, FetchMode::NUMERIC); self::assertCount(2, $this->sqlLogger->queries); } public function testFetchAllAndFinishSavesCache() : void { $layerCache = new ArrayCache(); $stmt = $this->connection->executeQuery('SELECT * FROM caching WHERE test_int > 500', [], [], new QueryCacheProfile(10, 'testcachekey', $layerCache)); $stmt->fetchAll(); $stmt->closeCursor(); self::assertCount(1, $layerCache->fetch('testcachekey')); } public function testFetchAllColumn() : void { $query = $this->connection->getDatabasePlatform() ->getDummySelectSQL('1'); $qcp = new QueryCacheProfile(0, 0, new ArrayCache()); $stmt = $this->connection->executeCacheQuery($query, [], [], $qcp); $stmt->fetchAll(FetchMode::COLUMN); $stmt->closeCursor(); $stmt = $this->connection->executeCacheQuery($query, [], [], $qcp); self::assertEquals([1], $stmt->fetchAll(FetchMode::COLUMN)); } /** * @param array> $expectedResult */ private function assertCacheNonCacheSelectSameFetchModeAreEqual(array $expectedResult, int $fetchMode) : void { $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(10, 'testcachekey')); self::assertEquals(2, $stmt->columnCount()); $data = $this->hydrateStmt($stmt, $fetchMode); self::assertEquals($expectedResult, $data); $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(10, 'testcachekey')); self::assertEquals(2, $stmt->columnCount()); $data = $this->hydrateStmt($stmt, $fetchMode); self::assertEquals($expectedResult, $data); self::assertCount(1, $this->sqlLogger->queries, 'just one dbal hit'); } public function testEmptyResultCache() : void { $stmt = $this->connection->executeQuery('SELECT * FROM caching WHERE test_int > 500', [], [], new QueryCacheProfile(10, 'emptycachekey')); $data = $this->hydrateStmt($stmt); $stmt = $this->connection->executeQuery('SELECT * FROM caching WHERE test_int > 500', [], [], new QueryCacheProfile(10, 'emptycachekey')); $data = $this->hydrateStmt($stmt); self::assertCount(1, $this->sqlLogger->queries, 'just one dbal hit'); } public function testChangeCacheImpl() : void { $stmt = $this->connection->executeQuery('SELECT * FROM caching WHERE test_int > 500', [], [], new QueryCacheProfile(10, 'emptycachekey')); $data = $this->hydrateStmt($stmt); $secondCache = new ArrayCache(); $stmt = $this->connection->executeQuery('SELECT * FROM caching WHERE test_int > 500', [], [], new QueryCacheProfile(10, 'emptycachekey', $secondCache)); $data = $this->hydrateStmt($stmt); self::assertCount(2, $this->sqlLogger->queries, 'two hits'); self::assertCount(1, $secondCache->fetch('emptycachekey')); } /** * @return array */ private function hydrateStmt(ResultStatement $stmt, int $fetchMode = FetchMode::ASSOCIATIVE) : array { $data = []; while ($row = $stmt->fetch($fetchMode)) { $data[] = is_array($row) ? array_change_key_case($row, CASE_LOWER) : $row; } $stmt->closeCursor(); return $data; } /** * @return array */ private function hydrateStmtIterator(ResultStatement $stmt, int $fetchMode = FetchMode::ASSOCIATIVE) : array { $data = []; $stmt->setFetchMode($fetchMode); foreach ($stmt as $row) { $data[] = is_array($row) ? array_change_key_case($row, CASE_LOWER) : $row; } $stmt->closeCursor(); return $data; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Schema/000077500000000000000000000000001360544566000251175ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Schema/ComparatorTest.php000066400000000000000000000024611360544566000306020ustar00rootroot00000000000000schemaManager = $this->connection->getSchemaManager(); $this->comparator = new Comparator(); } /** * @param mixed $value * * @dataProvider defaultValueProvider */ public function testDefaultValueComparison(string $type, $value) : void { $table = new Table('default_value'); $table->addColumn('test', $type, ['default' => $value]); $this->schemaManager->dropAndCreateTable($table); $onlineTable = $this->schemaManager->listTableDetails('default_value'); self::assertFalse($this->comparator->diffTable($table, $onlineTable)); } /** * @return mixed[][] */ public static function defaultValueProvider() : iterable { return [ ['integer', 1], ['boolean', false], ]; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Schema/Db2SchemaManagerTest.php000066400000000000000000000021111360544566000315060ustar00rootroot00000000000000addColumn('bool', 'boolean'); $table->addColumn('bool_commented', 'boolean', ['comment' => "That's a comment"]); $this->schemaManager->createTable($table); $columns = $this->schemaManager->listTableColumns('boolean_column_test'); self::assertInstanceOf(BooleanType::class, $columns['bool']->getType()); self::assertInstanceOf(BooleanType::class, $columns['bool_commented']->getType()); self::assertNull($columns['bool']->getComment()); self::assertSame("That's a comment", $columns['bool_commented']->getComment()); } public function testListTableWithBinary() : void { self::markTestSkipped('Binary data type is currently not supported on DB2 LUW'); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Schema/DefaultValueTest.php000066400000000000000000000077611360544566000310640ustar00rootroot00000000000000addColumn('id', 'integer'); foreach (self::columnProvider() as [$name, $default]) { $table->addColumn($name, 'string', [ 'default' => $default, 'notnull' => false, ]); } $this->connection->getSchemaManager() ->dropAndCreateTable($table); $this->connection->insert('default_value', ['id' => 1]); } /** * @param mixed $expectedDefault * * @dataProvider columnProvider */ public function testEscapedDefaultValueCanBeIntrospected(string $name, ?string $expectedDefault) : void { self::assertSame( $expectedDefault, $this->connection ->getSchemaManager() ->listTableDetails('default_value') ->getColumn($name) ->getDefault() ); } /** * @param mixed $expectedDefault * * @dataProvider columnProvider */ public function testEscapedDefaultValueCanBeInserted(string $name, ?string $expectedDefault) : void { $value = $this->connection->fetchColumn( sprintf('SELECT %s FROM default_value', $name) ); self::assertSame($expectedDefault, $value); } /** * Returns potential escaped literals from all platforms combined. * * @see https://dev.mysql.com/doc/refman/5.7/en/string-literals.html * @see http://www.sqlite.org/lang_expr.html * @see https://www.postgresql.org/docs/9.6/static/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS-ESCAPE * * @return mixed[][] */ public static function columnProvider() : iterable { return [ 'Single quote' => [ 'single_quote', "foo'bar", ], 'Single quote, doubled' => [ 'single_quote_doubled', "foo''bar", ], 'Double quote' => [ 'double_quote', 'foo"bar', ], 'Double quote, doubled' => [ 'double_quote_doubled', 'foo""bar', ], 'Backspace' => [ 'backspace', "foo\x08bar", ], 'New line' => [ 'new_line', "foo\nbar", ], 'Carriage return' => [ 'carriage_return', "foo\rbar", ], 'Tab' => [ 'tab', "foo\tbar", ], 'Substitute' => [ 'substitute', "foo\x1abar", ], 'Backslash' => [ 'backslash', 'foo\\bar', ], 'Backslash, doubled' => [ 'backslash_doubled', 'foo\\\\bar', ], 'Percent' => [ 'percent_sign', 'foo%bar', ], 'Underscore' => [ 'underscore', 'foo_bar', ], 'NULL string' => [ 'null_string', 'NULL', ], 'NULL value' => [ 'null_value', null, ], 'SQL expression' => [ 'sql_expression', "'; DROP DATABASE doctrine --", ], 'No double conversion' => [ 'no_double_conversion', "\\'", ], ]; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Schema/DrizzleSchemaManagerTest.php000066400000000000000000000037671360544566000325440ustar00rootroot00000000000000addColumn('id', 'integer'); $table->addColumn('column_varbinary', 'binary', []); $table->addColumn('column_binary', 'binary', ['fixed' => true]); $table->setPrimaryKey(['id']); $this->schemaManager->createTable($table); $table = $this->schemaManager->listTableDetails($tableName); self::assertInstanceOf(BinaryType::class, $table->getColumn('column_varbinary')->getType()); self::assertFalse($table->getColumn('column_varbinary')->getFixed()); self::assertInstanceOf(BinaryType::class, $table->getColumn('column_binary')->getType()); self::assertFalse($table->getColumn('column_binary')->getFixed()); } public function testColumnCollation() : void { $table = new Table('test_collation'); $table->addOption('collate', $collation = 'utf8_unicode_ci'); $table->addColumn('id', 'integer'); $table->addColumn('text', 'text'); $table->addColumn('foo', 'text')->setPlatformOption('collation', 'utf8_swedish_ci'); $table->addColumn('bar', 'text')->setPlatformOption('collation', 'utf8_general_ci'); $this->schemaManager->dropAndCreateTable($table); $columns = $this->schemaManager->listTableColumns('test_collation'); self::assertArrayNotHasKey('collation', $columns['id']->getPlatformOptions()); self::assertEquals('utf8_unicode_ci', $columns['text']->getPlatformOption('collation')); self::assertEquals('utf8_swedish_ci', $columns['foo']->getPlatformOption('collation')); self::assertEquals('utf8_general_ci', $columns['bar']->getPlatformOption('collation')); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Schema/MySqlSchemaManagerTest.php000066400000000000000000000556661360544566000321730ustar00rootroot00000000000000resetSharedConn(); Type::addType('point', MySqlPointType::class); } public function testSwitchPrimaryKeyColumns() : void { $tableOld = new Table('switch_primary_key_columns'); $tableOld->addColumn('foo_id', 'integer'); $tableOld->addColumn('bar_id', 'integer'); $this->schemaManager->createTable($tableOld); $tableFetched = $this->schemaManager->listTableDetails('switch_primary_key_columns'); $tableNew = clone $tableFetched; $tableNew->setPrimaryKey(['bar_id', 'foo_id']); $comparator = new Comparator(); $this->schemaManager->alterTable($comparator->diffTable($tableFetched, $tableNew)); $table = $this->schemaManager->listTableDetails('switch_primary_key_columns'); $primaryKey = $table->getPrimaryKeyColumns(); self::assertCount(2, $primaryKey); self::assertContains('bar_id', $primaryKey); self::assertContains('foo_id', $primaryKey); } public function testDiffTableBug() : void { $schema = new Schema(); $table = $schema->createTable('diffbug_routing_translations'); $table->addColumn('id', 'integer'); $table->addColumn('route', 'string'); $table->addColumn('locale', 'string'); $table->addColumn('attribute', 'string'); $table->addColumn('localized_value', 'string'); $table->addColumn('original_value', 'string'); $table->setPrimaryKey(['id']); $table->addUniqueIndex(['route', 'locale', 'attribute']); $table->addIndex(['localized_value']); // this is much more selective than the unique index $this->schemaManager->createTable($table); $tableFetched = $this->schemaManager->listTableDetails('diffbug_routing_translations'); $comparator = new Comparator(); $diff = $comparator->diffTable($tableFetched, $table); self::assertFalse($diff, 'no changes expected.'); } public function testFulltextIndex() : void { $table = new Table('fulltext_index'); $table->addColumn('text', 'text'); $table->addIndex(['text'], 'f_index'); $table->addOption('engine', 'MyISAM'); $index = $table->getIndex('f_index'); $index->addFlag('fulltext'); $this->schemaManager->dropAndCreateTable($table); $indexes = $this->schemaManager->listTableIndexes('fulltext_index'); self::assertArrayHasKey('f_index', $indexes); self::assertTrue($indexes['f_index']->hasFlag('fulltext')); } public function testSpatialIndex() : void { $table = new Table('spatial_index'); $table->addColumn('point', 'point'); $table->addIndex(['point'], 's_index'); $table->addOption('engine', 'MyISAM'); $index = $table->getIndex('s_index'); $index->addFlag('spatial'); $this->schemaManager->dropAndCreateTable($table); $indexes = $this->schemaManager->listTableIndexes('spatial_index'); self::assertArrayHasKey('s_index', $indexes); self::assertTrue($indexes['s_index']->hasFlag('spatial')); } public function testIndexWithLength() : void { $table = new Table('index_length'); $table->addColumn('text', 'string', ['length' => 255]); $table->addIndex(['text'], 'text_index', [], ['lengths' => [128]]); $this->schemaManager->dropAndCreateTable($table); $indexes = $this->schemaManager->listTableIndexes('index_length'); self::assertArrayHasKey('text_index', $indexes); self::assertSame([128], $indexes['text_index']->getOption('lengths')); } /** * @group DBAL-400 */ public function testAlterTableAddPrimaryKey() : void { $table = new Table('alter_table_add_pk'); $table->addColumn('id', 'integer'); $table->addColumn('foo', 'integer'); $table->addIndex(['id'], 'idx_id'); $this->schemaManager->createTable($table); $comparator = new Comparator(); $diffTable = clone $table; $diffTable->dropIndex('idx_id'); $diffTable->setPrimaryKey(['id']); $this->schemaManager->alterTable($comparator->diffTable($table, $diffTable)); $table = $this->schemaManager->listTableDetails('alter_table_add_pk'); self::assertFalse($table->hasIndex('idx_id')); self::assertTrue($table->hasPrimaryKey()); } /** * @group DBAL-464 */ public function testDropPrimaryKeyWithAutoincrementColumn() : void { $table = new Table('drop_primary_key'); $table->addColumn('id', 'integer', ['autoincrement' => true]); $table->addColumn('foo', 'integer'); $table->setPrimaryKey(['id', 'foo']); $this->schemaManager->dropAndCreateTable($table); $diffTable = clone $table; $diffTable->dropPrimaryKey(); $comparator = new Comparator(); $this->schemaManager->alterTable($comparator->diffTable($table, $diffTable)); $table = $this->schemaManager->listTableDetails('drop_primary_key'); self::assertFalse($table->hasPrimaryKey()); self::assertFalse($table->getColumn('id')->getAutoincrement()); } /** * @group DBAL-789 */ public function testDoesNotPropagateDefaultValuesForUnsupportedColumnTypes() : void { if ($this->schemaManager->getDatabasePlatform() instanceof MariaDb1027Platform) { $this->markTestSkipped( 'MariaDb102Platform supports default values for BLOB and TEXT columns and will propagate values' ); } $table = new Table('text_blob_default_value'); $table->addColumn('def_text', 'text', ['default' => 'def']); $table->addColumn('def_text_null', 'text', ['notnull' => false, 'default' => 'def']); $table->addColumn('def_blob', 'blob', ['default' => 'def']); $table->addColumn('def_blob_null', 'blob', ['notnull' => false, 'default' => 'def']); $this->schemaManager->dropAndCreateTable($table); $onlineTable = $this->schemaManager->listTableDetails('text_blob_default_value'); self::assertNull($onlineTable->getColumn('def_text')->getDefault()); self::assertNull($onlineTable->getColumn('def_text_null')->getDefault()); self::assertFalse($onlineTable->getColumn('def_text_null')->getNotnull()); self::assertNull($onlineTable->getColumn('def_blob')->getDefault()); self::assertNull($onlineTable->getColumn('def_blob_null')->getDefault()); self::assertFalse($onlineTable->getColumn('def_blob_null')->getNotnull()); $comparator = new Comparator(); $this->schemaManager->alterTable($comparator->diffTable($table, $onlineTable)); $onlineTable = $this->schemaManager->listTableDetails('text_blob_default_value'); self::assertNull($onlineTable->getColumn('def_text')->getDefault()); self::assertNull($onlineTable->getColumn('def_text_null')->getDefault()); self::assertFalse($onlineTable->getColumn('def_text_null')->getNotnull()); self::assertNull($onlineTable->getColumn('def_blob')->getDefault()); self::assertNull($onlineTable->getColumn('def_blob_null')->getDefault()); self::assertFalse($onlineTable->getColumn('def_blob_null')->getNotnull()); } public function testColumnCharset() : void { $table = new Table('test_column_charset'); $table->addColumn('id', 'integer'); $table->addColumn('no_charset', 'text'); $table->addColumn('foo', 'text')->setPlatformOption('charset', 'ascii'); $table->addColumn('bar', 'text')->setPlatformOption('charset', 'latin1'); $this->schemaManager->dropAndCreateTable($table); $columns = $this->schemaManager->listTableColumns('test_column_charset'); self::assertFalse($columns['id']->hasPlatformOption('charset')); self::assertEquals('utf8', $columns['no_charset']->getPlatformOption('charset')); self::assertEquals('ascii', $columns['foo']->getPlatformOption('charset')); self::assertEquals('latin1', $columns['bar']->getPlatformOption('charset')); } public function testAlterColumnCharset() : void { $tableName = 'test_alter_column_charset'; $table = new Table($tableName); $table->addColumn('col_text', 'text')->setPlatformOption('charset', 'utf8'); $this->schemaManager->dropAndCreateTable($table); $diffTable = clone $table; $diffTable->getColumn('col_text')->setPlatformOption('charset', 'ascii'); $comparator = new Comparator(); $this->schemaManager->alterTable($comparator->diffTable($table, $diffTable)); $table = $this->schemaManager->listTableDetails($tableName); self::assertEquals('ascii', $table->getColumn('col_text')->getPlatformOption('charset')); } public function testColumnCharsetChange() : void { $table = new Table('test_column_charset_change'); $table->addColumn('col_string', 'string')->setLength(100)->setNotnull(true)->setPlatformOption('charset', 'utf8'); $diffTable = clone $table; $diffTable->getColumn('col_string')->setPlatformOption('charset', 'ascii'); $fromSchema = new Schema([$table]); $toSchema = new Schema([$diffTable]); $diff = $fromSchema->getMigrateToSql($toSchema, $this->connection->getDatabasePlatform()); self::assertContains('ALTER TABLE test_column_charset_change CHANGE col_string col_string VARCHAR(100) CHARACTER SET ascii NOT NULL', $diff); } public function testColumnCollation() : void { $table = new Table('test_collation'); $table->addOption('collate', $collation = 'latin1_swedish_ci'); $table->addOption('charset', 'latin1'); $table->addColumn('id', 'integer'); $table->addColumn('text', 'text'); $table->addColumn('foo', 'text')->setPlatformOption('collation', 'latin1_swedish_ci'); $table->addColumn('bar', 'text')->setPlatformOption('collation', 'utf8_general_ci'); $table->addColumn('baz', 'text')->setPlatformOption('collation', 'binary'); $this->schemaManager->dropAndCreateTable($table); $columns = $this->schemaManager->listTableColumns('test_collation'); self::assertArrayNotHasKey('collation', $columns['id']->getPlatformOptions()); self::assertEquals('latin1_swedish_ci', $columns['text']->getPlatformOption('collation')); self::assertEquals('latin1_swedish_ci', $columns['foo']->getPlatformOption('collation')); self::assertEquals('utf8_general_ci', $columns['bar']->getPlatformOption('collation')); self::assertInstanceOf(BlobType::class, $columns['baz']->getType()); } /** * @group DBAL-843 */ public function testListLobTypeColumns() : void { $tableName = 'lob_type_columns'; $table = new Table($tableName); $table->addColumn('col_tinytext', 'text', ['length' => MySqlPlatform::LENGTH_LIMIT_TINYTEXT]); $table->addColumn('col_text', 'text', ['length' => MySqlPlatform::LENGTH_LIMIT_TEXT]); $table->addColumn('col_mediumtext', 'text', ['length' => MySqlPlatform::LENGTH_LIMIT_MEDIUMTEXT]); $table->addColumn('col_longtext', 'text'); $table->addColumn('col_tinyblob', 'text', ['length' => MySqlPlatform::LENGTH_LIMIT_TINYBLOB]); $table->addColumn('col_blob', 'blob', ['length' => MySqlPlatform::LENGTH_LIMIT_BLOB]); $table->addColumn('col_mediumblob', 'blob', ['length' => MySqlPlatform::LENGTH_LIMIT_MEDIUMBLOB]); $table->addColumn('col_longblob', 'blob'); $this->schemaManager->dropAndCreateTable($table); $platform = $this->schemaManager->getDatabasePlatform(); $offlineColumns = $table->getColumns(); $onlineColumns = $this->schemaManager->listTableColumns($tableName); self::assertSame( $platform->getClobTypeDeclarationSQL($offlineColumns['col_tinytext']->toArray()), $platform->getClobTypeDeclarationSQL($onlineColumns['col_tinytext']->toArray()) ); self::assertSame( $platform->getClobTypeDeclarationSQL($offlineColumns['col_text']->toArray()), $platform->getClobTypeDeclarationSQL($onlineColumns['col_text']->toArray()) ); self::assertSame( $platform->getClobTypeDeclarationSQL($offlineColumns['col_mediumtext']->toArray()), $platform->getClobTypeDeclarationSQL($onlineColumns['col_mediumtext']->toArray()) ); self::assertSame( $platform->getClobTypeDeclarationSQL($offlineColumns['col_longtext']->toArray()), $platform->getClobTypeDeclarationSQL($onlineColumns['col_longtext']->toArray()) ); self::assertSame( $platform->getBlobTypeDeclarationSQL($offlineColumns['col_tinyblob']->toArray()), $platform->getBlobTypeDeclarationSQL($onlineColumns['col_tinyblob']->toArray()) ); self::assertSame( $platform->getBlobTypeDeclarationSQL($offlineColumns['col_blob']->toArray()), $platform->getBlobTypeDeclarationSQL($onlineColumns['col_blob']->toArray()) ); self::assertSame( $platform->getBlobTypeDeclarationSQL($offlineColumns['col_mediumblob']->toArray()), $platform->getBlobTypeDeclarationSQL($onlineColumns['col_mediumblob']->toArray()) ); self::assertSame( $platform->getBlobTypeDeclarationSQL($offlineColumns['col_longblob']->toArray()), $platform->getBlobTypeDeclarationSQL($onlineColumns['col_longblob']->toArray()) ); } /** * @group DBAL-423 */ public function testDiffListGuidTableColumn() : void { $offlineTable = new Table('list_guid_table_column'); $offlineTable->addColumn('col_guid', 'guid'); $this->schemaManager->dropAndCreateTable($offlineTable); $onlineTable = $this->schemaManager->listTableDetails('list_guid_table_column'); $comparator = new Comparator(); self::assertFalse( $comparator->diffTable($offlineTable, $onlineTable), 'No differences should be detected with the offline vs online schema.' ); } /** * @group DBAL-1082 */ public function testListDecimalTypeColumns() : void { $tableName = 'test_list_decimal_columns'; $table = new Table($tableName); $table->addColumn('col', 'decimal'); $table->addColumn('col_unsigned', 'decimal', ['unsigned' => true]); $this->schemaManager->dropAndCreateTable($table); $columns = $this->schemaManager->listTableColumns($tableName); self::assertArrayHasKey('col', $columns); self::assertArrayHasKey('col_unsigned', $columns); self::assertFalse($columns['col']->getUnsigned()); self::assertTrue($columns['col_unsigned']->getUnsigned()); } /** * @group DBAL-1082 */ public function testListFloatTypeColumns() : void { $tableName = 'test_list_float_columns'; $table = new Table($tableName); $table->addColumn('col', 'float'); $table->addColumn('col_unsigned', 'float', ['unsigned' => true]); $this->schemaManager->dropAndCreateTable($table); $columns = $this->schemaManager->listTableColumns($tableName); self::assertArrayHasKey('col', $columns); self::assertArrayHasKey('col_unsigned', $columns); self::assertFalse($columns['col']->getUnsigned()); self::assertTrue($columns['col_unsigned']->getUnsigned()); } public function testJsonColumnType() : void { $table = new Table('test_mysql_json'); $table->addColumn('col_json', 'json'); $this->schemaManager->dropAndCreateTable($table); $columns = $this->schemaManager->listTableColumns('test_mysql_json'); self::assertSame(Types::JSON, $columns['col_json']->getType()->getName()); } public function testColumnDefaultCurrentTimestamp() : void { $platform = $this->schemaManager->getDatabasePlatform(); $table = new Table('test_column_defaults_current_timestamp'); $currentTimeStampSql = $platform->getCurrentTimestampSQL(); $table->addColumn('col_datetime', 'datetime', ['notnull' => true, 'default' => $currentTimeStampSql]); $table->addColumn('col_datetime_nullable', 'datetime', ['default' => $currentTimeStampSql]); $this->schemaManager->dropAndCreateTable($table); $onlineTable = $this->schemaManager->listTableDetails('test_column_defaults_current_timestamp'); self::assertSame($currentTimeStampSql, $onlineTable->getColumn('col_datetime')->getDefault()); self::assertSame($currentTimeStampSql, $onlineTable->getColumn('col_datetime_nullable')->getDefault()); $comparator = new Comparator(); $diff = $comparator->diffTable($table, $onlineTable); self::assertFalse($diff, 'Tables should be identical with column defaults.'); } public function testColumnDefaultsAreValid() : void { $table = new Table('test_column_defaults_are_valid'); $currentTimeStampSql = $this->schemaManager->getDatabasePlatform()->getCurrentTimestampSQL(); $table->addColumn('col_datetime', 'datetime', ['default' => $currentTimeStampSql]); $table->addColumn('col_datetime_null', 'datetime', ['notnull' => false, 'default' => null]); $table->addColumn('col_int', 'integer', ['default' => 1]); $table->addColumn('col_neg_int', 'integer', ['default' => -1]); $table->addColumn('col_string', 'string', ['default' => 'A']); $table->addColumn('col_decimal', 'decimal', ['scale' => 3, 'precision' => 6, 'default' => -2.3]); $table->addColumn('col_date', 'date', ['default' => '2012-12-12']); $this->schemaManager->dropAndCreateTable($table); $this->connection->executeUpdate( 'INSERT INTO test_column_defaults_are_valid () VALUES()' ); $row = $this->connection->fetchAssoc( 'SELECT *, DATEDIFF(CURRENT_TIMESTAMP(), col_datetime) as diff_seconds FROM test_column_defaults_are_valid' ); self::assertInstanceOf(DateTime::class, DateTime::createFromFormat('Y-m-d H:i:s', $row['col_datetime'])); self::assertNull($row['col_datetime_null']); self::assertSame('2012-12-12', $row['col_date']); self::assertSame('A', $row['col_string']); self::assertEquals(1, $row['col_int']); self::assertEquals(-1, $row['col_neg_int']); self::assertEquals('-2.300', $row['col_decimal']); self::assertLessThan(5, $row['diff_seconds']); } /** * MariaDB 10.2+ does support CURRENT_TIME and CURRENT_DATE as * column default values for time and date columns. * (Not supported on Mysql as of 5.7.19) * * Note that MariaDB 10.2+, when storing default in information_schema, * silently change CURRENT_TIMESTAMP as 'current_timestamp()', * CURRENT_TIME as 'currtime()' and CURRENT_DATE as 'currdate()'. * This test also ensure proper aliasing to not trigger a table diff. */ public function testColumnDefaultValuesCurrentTimeAndDate() : void { if (! $this->schemaManager->getDatabasePlatform() instanceof MariaDb1027Platform) { $this->markTestSkipped('Only relevant for MariaDb102Platform.'); } $platform = $this->schemaManager->getDatabasePlatform(); $table = new Table('test_column_defaults_current_time_and_date'); $currentTimestampSql = $platform->getCurrentTimestampSQL(); $currentTimeSql = $platform->getCurrentTimeSQL(); $currentDateSql = $platform->getCurrentDateSQL(); $table->addColumn('col_datetime', 'datetime', ['default' => $currentTimestampSql]); $table->addColumn('col_date', 'date', ['default' => $currentDateSql]); $table->addColumn('col_time', 'time', ['default' => $currentTimeSql]); $this->schemaManager->dropAndCreateTable($table); $onlineTable = $this->schemaManager->listTableDetails('test_column_defaults_current_time_and_date'); self::assertSame($currentTimestampSql, $onlineTable->getColumn('col_datetime')->getDefault()); self::assertSame($currentDateSql, $onlineTable->getColumn('col_date')->getDefault()); self::assertSame($currentTimeSql, $onlineTable->getColumn('col_time')->getDefault()); $comparator = new Comparator(); $diff = $comparator->diffTable($table, $onlineTable); self::assertFalse($diff, 'Tables should be identical with column defauts time and date.'); } public function testEnsureTableOptionsAreReflectedInMetadata() : void { $this->connection->query('DROP TABLE IF EXISTS test_table_metadata'); $sql = <<<'SQL' CREATE TABLE test_table_metadata( col1 INT NOT NULL AUTO_INCREMENT PRIMARY KEY ) COLLATE utf8_general_ci ENGINE InnoDB ROW_FORMAT COMPRESSED COMMENT 'This is a test' AUTO_INCREMENT=42 PARTITION BY HASH (col1) SQL; $this->connection->query($sql); $onlineTable = $this->schemaManager->listTableDetails('test_table_metadata'); self::assertEquals('InnoDB', $onlineTable->getOption('engine')); self::assertEquals('utf8_general_ci', $onlineTable->getOption('collation')); self::assertEquals(42, $onlineTable->getOption('autoincrement')); self::assertEquals('This is a test', $onlineTable->getOption('comment')); self::assertEquals([ 'row_format' => 'COMPRESSED', 'partitioned' => true, ], $onlineTable->getOption('create_options')); } public function testEnsureTableWithoutOptionsAreReflectedInMetadata() : void { $this->connection->query('DROP TABLE IF EXISTS test_table_empty_metadata'); $this->connection->query('CREATE TABLE test_table_empty_metadata(col1 INT NOT NULL)'); $onlineTable = $this->schemaManager->listTableDetails('test_table_empty_metadata'); self::assertNotEmpty($onlineTable->getOption('engine')); // collation could be set to default or not set, information_schema indicate a possibly null value self::assertFalse($onlineTable->hasOption('autoincrement')); self::assertEquals('', $onlineTable->getOption('comment')); self::assertEquals([], $onlineTable->getOption('create_options')); } public function testParseNullCreateOptions() : void { $table = $this->schemaManager->listTableDetails('sys.processlist'); self::assertEquals([], $table->getOption('create_options')); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Schema/OracleSchemaManagerTest.php000066400000000000000000000300471360544566000323150ustar00rootroot00000000000000exec('GRANT ALL PRIVILEGES TO ' . $GLOBALS['db_username']); self::$privilegesGranted = true; } public function testRenameTable() : void { $this->schemaManager->tryMethod('DropTable', 'list_tables_test'); $this->schemaManager->tryMethod('DropTable', 'list_tables_test_new_name'); $this->createTestTable('list_tables_test'); $this->schemaManager->renameTable('list_tables_test', 'list_tables_test_new_name'); $tables = $this->schemaManager->listTables(); self::assertHasTable($tables, 'list_tables_test_new_name'); } public function testListTableWithBinary() : void { $tableName = 'test_binary_table'; $table = new Table($tableName); $table->addColumn('id', 'integer'); $table->addColumn('column_varbinary', 'binary', []); $table->addColumn('column_binary', 'binary', ['fixed' => true]); $table->setPrimaryKey(['id']); $this->schemaManager->createTable($table); $table = $this->schemaManager->listTableDetails($tableName); self::assertInstanceOf(BinaryType::class, $table->getColumn('column_varbinary')->getType()); self::assertFalse($table->getColumn('column_varbinary')->getFixed()); self::assertInstanceOf(BinaryType::class, $table->getColumn('column_binary')->getType()); self::assertFalse($table->getColumn('column_binary')->getFixed()); } /** * @group DBAL-472 * @group DBAL-1001 */ public function testAlterTableColumnNotNull() : void { $comparator = new Schema\Comparator(); $tableName = 'list_table_column_notnull'; $table = new Schema\Table($tableName); $table->addColumn('id', 'integer'); $table->addColumn('foo', 'integer'); $table->addColumn('bar', 'string'); $table->setPrimaryKey(['id']); $this->schemaManager->dropAndCreateTable($table); $columns = $this->schemaManager->listTableColumns($tableName); self::assertTrue($columns['id']->getNotnull()); self::assertTrue($columns['foo']->getNotnull()); self::assertTrue($columns['bar']->getNotnull()); $diffTable = clone $table; $diffTable->changeColumn('foo', ['notnull' => false]); $diffTable->changeColumn('bar', ['length' => 1024]); $this->schemaManager->alterTable($comparator->diffTable($table, $diffTable)); $columns = $this->schemaManager->listTableColumns($tableName); self::assertTrue($columns['id']->getNotnull()); self::assertFalse($columns['foo']->getNotnull()); self::assertTrue($columns['bar']->getNotnull()); } public function testListDatabases() : void { // We need the temp connection that has privileges to create a database. $sm = TestUtil::getTempConnection()->getSchemaManager(); $sm->dropAndCreateDatabase('c##test_create_database'); $databases = $this->schemaManager->listDatabases(); $databases = array_map('strtolower', $databases); self::assertContains('c##test_create_database', $databases); } /** * @group DBAL-831 */ public function testListTableDetailsWithDifferentIdentifierQuotingRequirements() : void { $primaryTableName = '"Primary_Table"'; $offlinePrimaryTable = new Schema\Table($primaryTableName); $offlinePrimaryTable->addColumn( '"Id"', 'integer', ['autoincrement' => true, 'comment' => 'Explicit casing.'] ); $offlinePrimaryTable->addColumn('select', 'integer', ['comment' => 'Reserved keyword.']); $offlinePrimaryTable->addColumn('foo', 'integer', ['comment' => 'Implicit uppercasing.']); $offlinePrimaryTable->addColumn('BAR', 'integer'); $offlinePrimaryTable->addColumn('"BAZ"', 'integer'); $offlinePrimaryTable->addIndex(['select'], 'from'); $offlinePrimaryTable->addIndex(['foo'], 'foo_index'); $offlinePrimaryTable->addIndex(['BAR'], 'BAR_INDEX'); $offlinePrimaryTable->addIndex(['"BAZ"'], 'BAZ_INDEX'); $offlinePrimaryTable->setPrimaryKey(['"Id"']); $foreignTableName = 'foreign'; $offlineForeignTable = new Schema\Table($foreignTableName); $offlineForeignTable->addColumn('id', 'integer', ['autoincrement' => true]); $offlineForeignTable->addColumn('"Fk"', 'integer'); $offlineForeignTable->addIndex(['"Fk"'], '"Fk_index"'); $offlineForeignTable->addForeignKeyConstraint( $primaryTableName, ['"Fk"'], ['"Id"'], [], '"Primary_Table_Fk"' ); $offlineForeignTable->setPrimaryKey(['id']); $this->schemaManager->tryMethod('dropTable', $foreignTableName); $this->schemaManager->tryMethod('dropTable', $primaryTableName); $this->schemaManager->createTable($offlinePrimaryTable); $this->schemaManager->createTable($offlineForeignTable); $onlinePrimaryTable = $this->schemaManager->listTableDetails($primaryTableName); $onlineForeignTable = $this->schemaManager->listTableDetails($foreignTableName); $platform = $this->schemaManager->getDatabasePlatform(); // Primary table assertions self::assertSame($primaryTableName, $onlinePrimaryTable->getQuotedName($platform)); self::assertTrue($onlinePrimaryTable->hasColumn('"Id"')); self::assertSame('"Id"', $onlinePrimaryTable->getColumn('"Id"')->getQuotedName($platform)); self::assertTrue($onlinePrimaryTable->hasPrimaryKey()); self::assertSame(['"Id"'], $onlinePrimaryTable->getPrimaryKey()->getQuotedColumns($platform)); self::assertTrue($onlinePrimaryTable->hasColumn('select')); self::assertSame('"select"', $onlinePrimaryTable->getColumn('select')->getQuotedName($platform)); self::assertTrue($onlinePrimaryTable->hasColumn('foo')); self::assertSame('FOO', $onlinePrimaryTable->getColumn('foo')->getQuotedName($platform)); self::assertTrue($onlinePrimaryTable->hasColumn('BAR')); self::assertSame('BAR', $onlinePrimaryTable->getColumn('BAR')->getQuotedName($platform)); self::assertTrue($onlinePrimaryTable->hasColumn('"BAZ"')); self::assertSame('BAZ', $onlinePrimaryTable->getColumn('"BAZ"')->getQuotedName($platform)); self::assertTrue($onlinePrimaryTable->hasIndex('from')); self::assertTrue($onlinePrimaryTable->getIndex('from')->hasColumnAtPosition('"select"')); self::assertSame(['"select"'], $onlinePrimaryTable->getIndex('from')->getQuotedColumns($platform)); self::assertTrue($onlinePrimaryTable->hasIndex('foo_index')); self::assertTrue($onlinePrimaryTable->getIndex('foo_index')->hasColumnAtPosition('foo')); self::assertSame(['FOO'], $onlinePrimaryTable->getIndex('foo_index')->getQuotedColumns($platform)); self::assertTrue($onlinePrimaryTable->hasIndex('BAR_INDEX')); self::assertTrue($onlinePrimaryTable->getIndex('BAR_INDEX')->hasColumnAtPosition('BAR')); self::assertSame(['BAR'], $onlinePrimaryTable->getIndex('BAR_INDEX')->getQuotedColumns($platform)); self::assertTrue($onlinePrimaryTable->hasIndex('BAZ_INDEX')); self::assertTrue($onlinePrimaryTable->getIndex('BAZ_INDEX')->hasColumnAtPosition('"BAZ"')); self::assertSame(['BAZ'], $onlinePrimaryTable->getIndex('BAZ_INDEX')->getQuotedColumns($platform)); // Foreign table assertions self::assertTrue($onlineForeignTable->hasColumn('id')); self::assertSame('ID', $onlineForeignTable->getColumn('id')->getQuotedName($platform)); self::assertTrue($onlineForeignTable->hasPrimaryKey()); self::assertSame(['ID'], $onlineForeignTable->getPrimaryKey()->getQuotedColumns($platform)); self::assertTrue($onlineForeignTable->hasColumn('"Fk"')); self::assertSame('"Fk"', $onlineForeignTable->getColumn('"Fk"')->getQuotedName($platform)); self::assertTrue($onlineForeignTable->hasIndex('"Fk_index"')); self::assertTrue($onlineForeignTable->getIndex('"Fk_index"')->hasColumnAtPosition('"Fk"')); self::assertSame(['"Fk"'], $onlineForeignTable->getIndex('"Fk_index"')->getQuotedColumns($platform)); self::assertTrue($onlineForeignTable->hasForeignKey('"Primary_Table_Fk"')); self::assertSame( $primaryTableName, $onlineForeignTable->getForeignKey('"Primary_Table_Fk"')->getQuotedForeignTableName($platform) ); self::assertSame( ['"Fk"'], $onlineForeignTable->getForeignKey('"Primary_Table_Fk"')->getQuotedLocalColumns($platform) ); self::assertSame( ['"Id"'], $onlineForeignTable->getForeignKey('"Primary_Table_Fk"')->getQuotedForeignColumns($platform) ); } public function testListTableColumnsSameTableNamesInDifferentSchemas() : void { $table = $this->createListTableColumns(); $this->schemaManager->dropAndCreateTable($table); $otherTable = new Table($table->getName()); $otherTable->addColumn('id', Types::STRING); TestUtil::getTempConnection()->getSchemaManager()->dropAndCreateTable($otherTable); $columns = $this->schemaManager->listTableColumns($table->getName(), $this->connection->getUsername()); self::assertCount(7, $columns); } /** * @group DBAL-1234 */ public function testListTableIndexesPrimaryKeyConstraintNameDiffersFromIndexName() : void { $table = new Table('list_table_indexes_pk_id_test'); $table->setSchemaConfig($this->schemaManager->createSchemaConfig()); $table->addColumn('id', 'integer', ['notnull' => true]); $table->addUniqueIndex(['id'], 'id_unique_index'); $this->schemaManager->dropAndCreateTable($table); // Adding a primary key on already indexed columns // Oracle will reuse the unique index, which cause a constraint name differing from the index name $this->schemaManager->createConstraint(new Schema\Index('id_pk_id_index', ['id'], true, true), 'list_table_indexes_pk_id_test'); $tableIndexes = $this->schemaManager->listTableIndexes('list_table_indexes_pk_id_test'); self::assertArrayHasKey('primary', $tableIndexes, 'listTableIndexes() has to return a "primary" array key.'); self::assertEquals(['id'], array_map('strtolower', $tableIndexes['primary']->getColumns())); self::assertTrue($tableIndexes['primary']->isUnique()); self::assertTrue($tableIndexes['primary']->isPrimary()); } /** * @group DBAL-2555 */ public function testListTableDateTypeColumns() : void { $table = new Table('tbl_date'); $table->addColumn('col_date', 'date'); $table->addColumn('col_datetime', 'datetime'); $table->addColumn('col_datetimetz', 'datetimetz'); $this->schemaManager->dropAndCreateTable($table); $columns = $this->schemaManager->listTableColumns('tbl_date'); self::assertSame('date', $columns['col_date']->getType()->getName()); self::assertSame('datetime', $columns['col_datetime']->getType()->getName()); self::assertSame('datetimetz', $columns['col_datetimetz']->getType()->getName()); } public function testCreateAndListSequences() : void { self::markTestSkipped("Skipped for uppercase letters are contained in sequences' names. Fix the schema manager in 3.0."); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Schema/PostgreSqlSchemaManagerTest.php000066400000000000000000000476511360544566000332240ustar00rootroot00000000000000connection) { return; } $this->connection->getConfiguration()->setFilterSchemaAssetsExpression(null); } /** * @group DBAL-177 */ public function testGetSearchPath() : void { $params = $this->connection->getParams(); $paths = $this->schemaManager->getSchemaSearchPaths(); self::assertEquals([$params['user'], 'public'], $paths); } /** * @group DBAL-244 */ public function testGetSchemaNames() : void { $names = $this->schemaManager->getSchemaNames(); self::assertIsArray($names); self::assertNotEmpty($names); self::assertContains('public', $names, 'The public schema should be found.'); } /** * @group DBAL-21 */ public function testSupportDomainTypeFallback() : void { $createDomainTypeSQL = 'CREATE DOMAIN MyMoney AS DECIMAL(18,2)'; $this->connection->exec($createDomainTypeSQL); $createTableSQL = 'CREATE TABLE domain_type_test (id INT PRIMARY KEY, value MyMoney)'; $this->connection->exec($createTableSQL); $table = $this->connection->getSchemaManager()->listTableDetails('domain_type_test'); self::assertInstanceOf(DecimalType::class, $table->getColumn('value')->getType()); Type::addType('MyMoney', MoneyType::class); $this->connection->getDatabasePlatform()->registerDoctrineTypeMapping('MyMoney', 'MyMoney'); $table = $this->connection->getSchemaManager()->listTableDetails('domain_type_test'); self::assertInstanceOf(MoneyType::class, $table->getColumn('value')->getType()); } /** * @group DBAL-37 */ public function testDetectsAutoIncrement() : void { $autoincTable = new Table('autoinc_table'); $column = $autoincTable->addColumn('id', 'integer'); $column->setAutoincrement(true); $this->schemaManager->createTable($autoincTable); $autoincTable = $this->schemaManager->listTableDetails('autoinc_table'); self::assertTrue($autoincTable->getColumn('id')->getAutoincrement()); } /** * @group DBAL-37 */ public function testAlterTableAutoIncrementAdd() : void { $tableFrom = new Table('autoinc_table_add'); $column = $tableFrom->addColumn('id', 'integer'); $this->schemaManager->createTable($tableFrom); $tableFrom = $this->schemaManager->listTableDetails('autoinc_table_add'); self::assertFalse($tableFrom->getColumn('id')->getAutoincrement()); $tableTo = new Table('autoinc_table_add'); $column = $tableTo->addColumn('id', 'integer'); $column->setAutoincrement(true); $c = new Comparator(); $diff = $c->diffTable($tableFrom, $tableTo); $sql = $this->connection->getDatabasePlatform()->getAlterTableSQL($diff); self::assertEquals([ 'CREATE SEQUENCE autoinc_table_add_id_seq', "SELECT setval('autoinc_table_add_id_seq', (SELECT MAX(id) FROM autoinc_table_add))", "ALTER TABLE autoinc_table_add ALTER id SET DEFAULT nextval('autoinc_table_add_id_seq')", ], $sql); $this->schemaManager->alterTable($diff); $tableFinal = $this->schemaManager->listTableDetails('autoinc_table_add'); self::assertTrue($tableFinal->getColumn('id')->getAutoincrement()); } /** * @group DBAL-37 */ public function testAlterTableAutoIncrementDrop() : void { $tableFrom = new Table('autoinc_table_drop'); $column = $tableFrom->addColumn('id', 'integer'); $column->setAutoincrement(true); $this->schemaManager->createTable($tableFrom); $tableFrom = $this->schemaManager->listTableDetails('autoinc_table_drop'); self::assertTrue($tableFrom->getColumn('id')->getAutoincrement()); $tableTo = new Table('autoinc_table_drop'); $column = $tableTo->addColumn('id', 'integer'); $c = new Comparator(); $diff = $c->diffTable($tableFrom, $tableTo); self::assertInstanceOf(TableDiff::class, $diff, 'There should be a difference and not false being returned from the table comparison'); self::assertEquals(['ALTER TABLE autoinc_table_drop ALTER id DROP DEFAULT'], $this->connection->getDatabasePlatform()->getAlterTableSQL($diff)); $this->schemaManager->alterTable($diff); $tableFinal = $this->schemaManager->listTableDetails('autoinc_table_drop'); self::assertFalse($tableFinal->getColumn('id')->getAutoincrement()); } /** * @group DBAL-75 */ public function testTableWithSchema() : void { $this->connection->exec('CREATE SCHEMA nested'); $nestedRelatedTable = new Table('nested.schemarelated'); $column = $nestedRelatedTable->addColumn('id', 'integer'); $column->setAutoincrement(true); $nestedRelatedTable->setPrimaryKey(['id']); $nestedSchemaTable = new Table('nested.schematable'); $column = $nestedSchemaTable->addColumn('id', 'integer'); $column->setAutoincrement(true); $nestedSchemaTable->setPrimaryKey(['id']); $nestedSchemaTable->addUnnamedForeignKeyConstraint($nestedRelatedTable, ['id'], ['id']); $this->schemaManager->createTable($nestedRelatedTable); $this->schemaManager->createTable($nestedSchemaTable); $tables = $this->schemaManager->listTableNames(); self::assertContains('nested.schematable', $tables, 'The table should be detected with its non-public schema.'); $nestedSchemaTable = $this->schemaManager->listTableDetails('nested.schematable'); self::assertTrue($nestedSchemaTable->hasColumn('id')); self::assertEquals(['id'], $nestedSchemaTable->getPrimaryKey()->getColumns()); $relatedFks = $nestedSchemaTable->getForeignKeys(); self::assertCount(1, $relatedFks); $relatedFk = array_pop($relatedFks); self::assertEquals('nested.schemarelated', $relatedFk->getForeignTableName()); } /** * @group DBAL-91 * @group DBAL-88 */ public function testReturnQuotedAssets() : void { $sql = 'create table dbal91_something ( id integer CONSTRAINT id_something PRIMARY KEY NOT NULL ,"table" integer );'; $this->connection->exec($sql); $sql = 'ALTER TABLE dbal91_something ADD CONSTRAINT something_input FOREIGN KEY( "table" ) REFERENCES dbal91_something ON UPDATE CASCADE;'; $this->connection->exec($sql); $table = $this->schemaManager->listTableDetails('dbal91_something'); self::assertEquals( [ 'CREATE TABLE dbal91_something (id INT NOT NULL, "table" INT DEFAULT NULL, PRIMARY KEY(id))', 'CREATE INDEX IDX_A9401304ECA7352B ON dbal91_something ("table")', ], $this->connection->getDatabasePlatform()->getCreateTableSQL($table) ); } /** * @group DBAL-204 */ public function testFilterSchemaExpression() : void { $testTable = new Table('dbal204_test_prefix'); $column = $testTable->addColumn('id', 'integer'); $this->schemaManager->createTable($testTable); $testTable = new Table('dbal204_without_prefix'); $column = $testTable->addColumn('id', 'integer'); $this->schemaManager->createTable($testTable); $this->connection->getConfiguration()->setFilterSchemaAssetsExpression('#^dbal204_#'); $names = $this->schemaManager->listTableNames(); self::assertCount(2, $names); $this->connection->getConfiguration()->setFilterSchemaAssetsExpression('#^dbal204_test#'); $names = $this->schemaManager->listTableNames(); self::assertCount(1, $names); } public function testListForeignKeys() : void { if (! $this->connection->getDatabasePlatform()->supportsForeignKeyConstraints()) { $this->markTestSkipped('Does not support foreign key constraints.'); } $fkOptions = ['SET NULL', 'SET DEFAULT', 'NO ACTION','CASCADE', 'RESTRICT']; $foreignKeys = []; $fkTable = $this->getTestTable('test_create_fk1'); for ($i = 0; $i < count($fkOptions); $i++) { $fkTable->addColumn('foreign_key_test' . $i, 'integer'); $foreignKeys[] = new ForeignKeyConstraint( ['foreign_key_test' . $i], 'test_create_fk2', ['id'], 'foreign_key_test' . $i . '_fk', ['onDelete' => $fkOptions[$i]] ); } $this->schemaManager->dropAndCreateTable($fkTable); $this->createTestTable('test_create_fk2'); foreach ($foreignKeys as $foreignKey) { $this->schemaManager->createForeignKey($foreignKey, 'test_create_fk1'); } $fkeys = $this->schemaManager->listTableForeignKeys('test_create_fk1'); self::assertEquals(count($foreignKeys), count($fkeys), "Table 'test_create_fk1' has to have " . count($foreignKeys) . ' foreign keys.'); for ($i = 0; $i < count($fkeys); $i++) { self::assertEquals(['foreign_key_test' . $i], array_map('strtolower', $fkeys[$i]->getLocalColumns())); self::assertEquals(['id'], array_map('strtolower', $fkeys[$i]->getForeignColumns())); self::assertEquals('test_create_fk2', strtolower($fkeys[0]->getForeignTableName())); if ($foreignKeys[$i]->getOption('onDelete') === 'NO ACTION') { self::assertFalse($fkeys[$i]->hasOption('onDelete'), 'Unexpected option: ' . $fkeys[$i]->getOption('onDelete')); } else { self::assertEquals($foreignKeys[$i]->getOption('onDelete'), $fkeys[$i]->getOption('onDelete')); } } } /** * @group DBAL-511 */ public function testDefaultValueCharacterVarying() : void { $testTable = new Table('dbal511_default'); $testTable->addColumn('id', 'integer'); $testTable->addColumn('def', 'string', ['default' => 'foo']); $testTable->setPrimaryKey(['id']); $this->schemaManager->createTable($testTable); $databaseTable = $this->schemaManager->listTableDetails($testTable->getName()); self::assertEquals('foo', $databaseTable->getColumn('def')->getDefault()); } /** * @group DDC-2843 */ public function testBooleanDefault() : void { $table = new Table('ddc2843_bools'); $table->addColumn('id', 'integer'); $table->addColumn('checked', 'boolean', ['default' => false]); $this->schemaManager->createTable($table); $databaseTable = $this->schemaManager->listTableDetails($table->getName()); $c = new Comparator(); $diff = $c->diffTable($table, $databaseTable); self::assertFalse($diff); } public function testListTableWithBinary() : void { $tableName = 'test_binary_table'; $table = new Table($tableName); $table->addColumn('id', 'integer'); $table->addColumn('column_varbinary', 'binary', []); $table->addColumn('column_binary', 'binary', ['fixed' => true]); $table->setPrimaryKey(['id']); $this->schemaManager->createTable($table); $table = $this->schemaManager->listTableDetails($tableName); self::assertInstanceOf(BlobType::class, $table->getColumn('column_varbinary')->getType()); self::assertFalse($table->getColumn('column_varbinary')->getFixed()); self::assertInstanceOf(BlobType::class, $table->getColumn('column_binary')->getType()); self::assertFalse($table->getColumn('column_binary')->getFixed()); } public function testListQuotedTable() : void { $offlineTable = new Schema\Table('user'); $offlineTable->addColumn('id', 'integer'); $offlineTable->addColumn('username', 'string'); $offlineTable->addColumn('fk', 'integer'); $offlineTable->setPrimaryKey(['id']); $offlineTable->addForeignKeyConstraint($offlineTable, ['fk'], ['id']); $this->schemaManager->dropAndCreateTable($offlineTable); $onlineTable = $this->schemaManager->listTableDetails('"user"'); $comparator = new Schema\Comparator(); self::assertFalse($comparator->diffTable($offlineTable, $onlineTable)); } public function testListTablesExcludesViews() : void { $this->createTestTable('list_tables_excludes_views'); $name = 'list_tables_excludes_views_test_view'; $sql = 'SELECT * from list_tables_excludes_views'; $view = new Schema\View($name, $sql); $this->schemaManager->dropAndCreateView($view); $tables = $this->schemaManager->listTables(); $foundTable = false; foreach ($tables as $table) { self::assertInstanceOf(Table::class, $table, 'No Table instance was found in tables array.'); if (strtolower($table->getName()) !== 'list_tables_excludes_views_test_view') { continue; } $foundTable = true; } self::assertFalse($foundTable, 'View "list_tables_excludes_views_test_view" must not be found in table list'); } /** * @group DBAL-1033 */ public function testPartialIndexes() : void { $offlineTable = new Schema\Table('person'); $offlineTable->addColumn('id', 'integer'); $offlineTable->addColumn('name', 'string'); $offlineTable->addColumn('email', 'string'); $offlineTable->addUniqueIndex(['id', 'name'], 'simple_partial_index', ['where' => '(id IS NULL)']); $this->schemaManager->dropAndCreateTable($offlineTable); $onlineTable = $this->schemaManager->listTableDetails('person'); $comparator = new Schema\Comparator(); self::assertFalse($comparator->diffTable($offlineTable, $onlineTable)); self::assertTrue($onlineTable->hasIndex('simple_partial_index')); self::assertTrue($onlineTable->getIndex('simple_partial_index')->hasOption('where')); self::assertSame('(id IS NULL)', $onlineTable->getIndex('simple_partial_index')->getOption('where')); } /** * @dataProvider jsonbColumnTypeProvider */ public function testJsonbColumn(string $type) : void { if (! $this->schemaManager->getDatabasePlatform() instanceof PostgreSQL94Platform) { $this->markTestSkipped('Requires PostgresSQL 9.4+'); return; } $table = new Schema\Table('test_jsonb'); $table->addColumn('foo', $type)->setPlatformOption('jsonb', true); $this->schemaManager->dropAndCreateTable($table); $columns = $this->schemaManager->listTableColumns('test_jsonb'); self::assertSame($type, $columns['foo']->getType()->getName()); self::assertTrue(true, $columns['foo']->getPlatformOption('jsonb')); } /** * @return mixed[][] */ public function jsonbColumnTypeProvider() : array { return [ [Types::JSON], [Types::JSON_ARRAY], ]; } /** * @group DBAL-2427 */ public function testListNegativeColumnDefaultValue() : void { $table = new Schema\Table('test_default_negative'); $table->addColumn('col_smallint', 'smallint', ['default' => -1]); $table->addColumn('col_integer', 'integer', ['default' => -1]); $table->addColumn('col_bigint', 'bigint', ['default' => -1]); $table->addColumn('col_float', 'float', ['default' => -1.1]); $table->addColumn('col_decimal', 'decimal', ['default' => -1.1]); $table->addColumn('col_string', 'string', ['default' => '(-1)']); $this->schemaManager->dropAndCreateTable($table); $columns = $this->schemaManager->listTableColumns('test_default_negative'); self::assertEquals(-1, $columns['col_smallint']->getDefault()); self::assertEquals(-1, $columns['col_integer']->getDefault()); self::assertEquals(-1, $columns['col_bigint']->getDefault()); self::assertEquals(-1.1, $columns['col_float']->getDefault()); self::assertEquals(-1.1, $columns['col_decimal']->getDefault()); self::assertEquals('(-1)', $columns['col_string']->getDefault()); } /** * @return mixed[][] */ public static function serialTypes() : iterable { return [ ['integer'], ['bigint'], ]; } /** * @dataProvider serialTypes * @group 2906 */ public function testAutoIncrementCreatesSerialDataTypesWithoutADefaultValue(string $type) : void { $tableName = 'test_serial_type_' . $type; $table = new Schema\Table($tableName); $table->addColumn('id', $type, ['autoincrement' => true, 'notnull' => false]); $this->schemaManager->dropAndCreateTable($table); $columns = $this->schemaManager->listTableColumns($tableName); self::assertNull($columns['id']->getDefault()); } /** * @dataProvider serialTypes * @group 2906 */ public function testAutoIncrementCreatesSerialDataTypesWithoutADefaultValueEvenWhenDefaultIsSet(string $type) : void { $tableName = 'test_serial_type_with_default_' . $type; $table = new Schema\Table($tableName); $table->addColumn('id', $type, ['autoincrement' => true, 'notnull' => false, 'default' => 1]); $this->schemaManager->dropAndCreateTable($table); $columns = $this->schemaManager->listTableColumns($tableName); self::assertNull($columns['id']->getDefault()); } /** * @group 2916 * @dataProvider autoIncrementTypeMigrations */ public function testAlterTableAutoIncrementIntToBigInt(string $from, string $to, string $expected) : void { $tableFrom = new Table('autoinc_type_modification'); $column = $tableFrom->addColumn('id', $from); $column->setAutoincrement(true); $this->schemaManager->dropAndCreateTable($tableFrom); $tableFrom = $this->schemaManager->listTableDetails('autoinc_type_modification'); self::assertTrue($tableFrom->getColumn('id')->getAutoincrement()); $tableTo = new Table('autoinc_type_modification'); $column = $tableTo->addColumn('id', $to); $column->setAutoincrement(true); $c = new Comparator(); $diff = $c->diffTable($tableFrom, $tableTo); self::assertInstanceOf(TableDiff::class, $diff, 'There should be a difference and not false being returned from the table comparison'); self::assertSame(['ALTER TABLE autoinc_type_modification ALTER id TYPE ' . $expected], $this->connection->getDatabasePlatform()->getAlterTableSQL($diff)); $this->schemaManager->alterTable($diff); $tableFinal = $this->schemaManager->listTableDetails('autoinc_type_modification'); self::assertTrue($tableFinal->getColumn('id')->getAutoincrement()); } /** * @return mixed[][] */ public static function autoIncrementTypeMigrations() : iterable { return [ 'int->bigint' => ['integer', 'bigint', 'BIGINT'], 'bigint->int' => ['bigint', 'integer', 'INT'], ]; } } class MoneyType extends Type { /** * {@inheritDoc} */ public function getName() { return 'MyMoney'; } /** * {@inheritDoc} */ public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform) { return 'MyMoney'; } } SQLAnywhereSchemaManagerTest.php000066400000000000000000000051331360544566000331710ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/SchemacreateTestTable('view_test_table'); $name = 'doctrine_test_view'; $sql = 'SELECT * from DBA.view_test_table'; $view = new View($name, $sql); $this->schemaManager->dropAndCreateView($view); $views = $this->schemaManager->listViews(); self::assertCount(1, $views, 'Database has to have one view.'); self::assertInstanceOf(View::class, $views[$name]); self::assertEquals($name, $views[$name]->getName()); self::assertRegExp('/^SELECT \* from "?DBA"?\."?view_test_table"?$/', $views[$name]->getSql()); } public function testDropAndCreateAdvancedIndex() : void { $table = $this->getTestTable('test_create_advanced_index'); $this->schemaManager->dropAndCreateTable($table); $this->schemaManager->dropAndCreateIndex( new Index('test', ['test'], true, false, ['clustered', 'with_nulls_not_distinct', 'for_olap_workload']), $table->getName() ); $tableIndexes = $this->schemaManager->listTableIndexes('test_create_advanced_index'); self::assertIsArray($tableIndexes); self::assertEquals('test', $tableIndexes['test']->getName()); self::assertEquals(['test'], $tableIndexes['test']->getColumns()); self::assertTrue($tableIndexes['test']->isUnique()); self::assertFalse($tableIndexes['test']->isPrimary()); self::assertTrue($tableIndexes['test']->hasFlag('clustered')); self::assertTrue($tableIndexes['test']->hasFlag('with_nulls_not_distinct')); self::assertTrue($tableIndexes['test']->hasFlag('for_olap_workload')); } public function testListTableColumnsWithFixedStringTypeColumn() : void { $table = new Table('list_table_columns_char'); $table->addColumn('id', 'integer', ['notnull' => true]); $table->addColumn('test', 'string', ['fixed' => true]); $table->setPrimaryKey(['id']); $this->schemaManager->dropAndCreateTable($table); $columns = $this->schemaManager->listTableColumns('list_table_columns_char'); self::assertArrayHasKey('test', $columns); self::assertTrue($columns['test']->getFixed()); } public function testCommentInTable() : void { self::markTestSkipped('Table level comments are not supported on SQLAnywhere'); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Schema/SQLServerSchemaManagerTest.php000066400000000000000000000434331360544566000327410ustar00rootroot00000000000000addColumn('id', 'integer'); $table->addColumn('todrop', 'decimal', ['default' => 10.2]); $this->schemaManager->createTable($table); $diff = new TableDiff('sqlsrv_drop_column', [], [], [new Column('todrop', Type::getType('decimal'))]); $this->schemaManager->alterTable($diff); $columns = $this->schemaManager->listTableColumns('sqlsrv_drop_column'); self::assertCount(1, $columns); } public function testColumnCollation() : void { $table = new Table($tableName = 'test_collation'); $column = $table->addColumn($columnName = 'test', 'string'); $this->schemaManager->dropAndCreateTable($table); $columns = $this->schemaManager->listTableColumns($tableName); self::assertTrue($columns[$columnName]->hasPlatformOption('collation')); // SQL Server should report a default collation on the column $column->setPlatformOption('collation', $collation = 'Icelandic_CS_AS'); $this->schemaManager->dropAndCreateTable($table); $columns = $this->schemaManager->listTableColumns($tableName); self::assertEquals($collation, $columns[$columnName]->getPlatformOption('collation')); } public function testDefaultConstraints() : void { $table = new Table('sqlsrv_default_constraints'); $table->addColumn('no_default', 'string'); $table->addColumn('df_integer', 'integer', ['default' => 666]); $table->addColumn('df_string_1', 'string', ['default' => 'foobar']); $table->addColumn('df_string_2', 'string', ['default' => 'Doctrine rocks!!!']); $table->addColumn('df_string_3', 'string', ['default' => 'another default value']); $table->addColumn('df_string_4', 'string', ['default' => 'column to rename']); $table->addColumn('df_boolean', 'boolean', ['default' => true]); $this->schemaManager->createTable($table); $columns = $this->schemaManager->listTableColumns('sqlsrv_default_constraints'); self::assertNull($columns['no_default']->getDefault()); self::assertEquals(666, $columns['df_integer']->getDefault()); self::assertEquals('foobar', $columns['df_string_1']->getDefault()); self::assertEquals('Doctrine rocks!!!', $columns['df_string_2']->getDefault()); self::assertEquals('another default value', $columns['df_string_3']->getDefault()); self::assertEquals(1, $columns['df_boolean']->getDefault()); $diff = new TableDiff( 'sqlsrv_default_constraints', [], [ 'df_integer' => new ColumnDiff( 'df_integer', new Column('df_integer', Type::getType('integer'), ['default' => 0]), ['default'], new Column('df_integer', Type::getType('integer'), ['default' => 666]) ), 'df_string_2' => new ColumnDiff( 'df_string_2', new Column('df_string_2', Type::getType('string')), ['default'], new Column('df_string_2', Type::getType('string'), ['default' => 'Doctrine rocks!!!']) ), 'df_string_3' => new ColumnDiff( 'df_string_3', new Column('df_string_3', Type::getType('string'), ['length' => 50, 'default' => 'another default value']), ['length'], new Column('df_string_3', Type::getType('string'), ['length' => 50, 'default' => 'another default value']) ), 'df_boolean' => new ColumnDiff( 'df_boolean', new Column('df_boolean', Type::getType('boolean'), ['default' => false]), ['default'], new Column('df_boolean', Type::getType('boolean'), ['default' => true]) ), ], [ 'df_string_1' => new Column('df_string_1', Type::getType('string')), ], [], [], [], $table ); $diff->newName = 'sqlsrv_default_constraints'; $diff->renamedColumns['df_string_4'] = new Column( 'df_string_renamed', Type::getType('string'), ['default' => 'column to rename'] ); $this->schemaManager->alterTable($diff); $columns = $this->schemaManager->listTableColumns('sqlsrv_default_constraints'); self::assertNull($columns['no_default']->getDefault()); self::assertEquals(0, $columns['df_integer']->getDefault()); self::assertNull($columns['df_string_2']->getDefault()); self::assertEquals('another default value', $columns['df_string_3']->getDefault()); self::assertEquals(0, $columns['df_boolean']->getDefault()); self::assertEquals('column to rename', $columns['df_string_renamed']->getDefault()); /** * Test that column default constraints can still be referenced after table rename */ $diff = new TableDiff( 'sqlsrv_default_constraints', [], [ 'df_integer' => new ColumnDiff( 'df_integer', new Column('df_integer', Type::getType('integer'), ['default' => 666]), ['default'], new Column('df_integer', Type::getType('integer'), ['default' => 0]) ), ], [], [], [], [], $table ); $this->schemaManager->alterTable($diff); $columns = $this->schemaManager->listTableColumns('sqlsrv_default_constraints'); self::assertEquals(666, $columns['df_integer']->getDefault()); } /** * @group DBAL-543 */ public function testColumnComments() : void { $table = new Table('sqlsrv_column_comment'); $table->addColumn('id', 'integer', ['autoincrement' => true]); $table->addColumn('comment_null', 'integer', ['comment' => null]); $table->addColumn('comment_false', 'integer', ['comment' => false]); $table->addColumn('comment_empty_string', 'integer', ['comment' => '']); $table->addColumn('comment_integer_0', 'integer', ['comment' => 0]); $table->addColumn('comment_float_0', 'integer', ['comment' => 0.0]); $table->addColumn('comment_string_0', 'integer', ['comment' => '0']); $table->addColumn('comment', 'integer', ['comment' => 'Doctrine 0wnz you!']); $table->addColumn('`comment_quoted`', 'integer', ['comment' => 'Doctrine 0wnz comments for explicitly quoted columns!']); $table->addColumn('create', 'integer', ['comment' => 'Doctrine 0wnz comments for reserved keyword columns!']); $table->addColumn('commented_type', 'object'); $table->addColumn('commented_type_with_comment', 'array', ['comment' => 'Doctrine array type.']); $table->setPrimaryKey(['id']); $this->schemaManager->createTable($table); $columns = $this->schemaManager->listTableColumns('sqlsrv_column_comment'); self::assertCount(12, $columns); self::assertNull($columns['id']->getComment()); self::assertNull($columns['comment_null']->getComment()); self::assertNull($columns['comment_false']->getComment()); self::assertNull($columns['comment_empty_string']->getComment()); self::assertEquals('0', $columns['comment_integer_0']->getComment()); self::assertEquals('0', $columns['comment_float_0']->getComment()); self::assertEquals('0', $columns['comment_string_0']->getComment()); self::assertEquals('Doctrine 0wnz you!', $columns['comment']->getComment()); self::assertEquals('Doctrine 0wnz comments for explicitly quoted columns!', $columns['comment_quoted']->getComment()); self::assertEquals('Doctrine 0wnz comments for reserved keyword columns!', $columns['[create]']->getComment()); self::assertNull($columns['commented_type']->getComment()); self::assertEquals('Doctrine array type.', $columns['commented_type_with_comment']->getComment()); $tableDiff = new TableDiff('sqlsrv_column_comment'); $tableDiff->fromTable = $table; $tableDiff->addedColumns['added_comment_none'] = new Column('added_comment_none', Type::getType('integer')); $tableDiff->addedColumns['added_comment_null'] = new Column('added_comment_null', Type::getType('integer'), ['comment' => null]); $tableDiff->addedColumns['added_comment_false'] = new Column('added_comment_false', Type::getType('integer'), ['comment' => false]); $tableDiff->addedColumns['added_comment_empty_string'] = new Column('added_comment_empty_string', Type::getType('integer'), ['comment' => '']); $tableDiff->addedColumns['added_comment_integer_0'] = new Column('added_comment_integer_0', Type::getType('integer'), ['comment' => 0]); $tableDiff->addedColumns['added_comment_float_0'] = new Column('added_comment_float_0', Type::getType('integer'), ['comment' => 0.0]); $tableDiff->addedColumns['added_comment_string_0'] = new Column('added_comment_string_0', Type::getType('integer'), ['comment' => '0']); $tableDiff->addedColumns['added_comment'] = new Column('added_comment', Type::getType('integer'), ['comment' => 'Doctrine']); $tableDiff->addedColumns['`added_comment_quoted`'] = new Column('`added_comment_quoted`', Type::getType('integer'), ['comment' => 'rulez']); $tableDiff->addedColumns['select'] = new Column('select', Type::getType('integer'), ['comment' => '666']); $tableDiff->addedColumns['added_commented_type'] = new Column('added_commented_type', Type::getType('object')); $tableDiff->addedColumns['added_commented_type_with_comment'] = new Column('added_commented_type_with_comment', Type::getType('array'), ['comment' => '666']); $tableDiff->renamedColumns['comment_float_0'] = new Column('comment_double_0', Type::getType('decimal'), ['comment' => 'Double for real!']); // Add comment to non-commented column. $tableDiff->changedColumns['id'] = new ColumnDiff( 'id', new Column('id', Type::getType('integer'), ['autoincrement' => true, 'comment' => 'primary']), ['comment'], new Column('id', Type::getType('integer'), ['autoincrement' => true]) ); // Remove comment from null-commented column. $tableDiff->changedColumns['comment_null'] = new ColumnDiff( 'comment_null', new Column('comment_null', Type::getType('string')), ['type'], new Column('comment_null', Type::getType('integer'), ['comment' => null]) ); // Add comment to false-commented column. $tableDiff->changedColumns['comment_false'] = new ColumnDiff( 'comment_false', new Column('comment_false', Type::getType('integer'), ['comment' => 'false']), ['comment'], new Column('comment_false', Type::getType('integer'), ['comment' => false]) ); // Change type to custom type from empty string commented column. $tableDiff->changedColumns['comment_empty_string'] = new ColumnDiff( 'comment_empty_string', new Column('comment_empty_string', Type::getType('object')), ['type'], new Column('comment_empty_string', Type::getType('integer'), ['comment' => '']) ); // Change comment to false-comment from zero-string commented column. $tableDiff->changedColumns['comment_string_0'] = new ColumnDiff( 'comment_string_0', new Column('comment_string_0', Type::getType('integer'), ['comment' => false]), ['comment'], new Column('comment_string_0', Type::getType('integer'), ['comment' => '0']) ); // Remove comment from regular commented column. $tableDiff->changedColumns['comment'] = new ColumnDiff( 'comment', new Column('comment', Type::getType('integer')), ['comment'], new Column('comment', Type::getType('integer'), ['comment' => 'Doctrine 0wnz you!']) ); // Change comment and change type to custom type from regular commented column. $tableDiff->changedColumns['`comment_quoted`'] = new ColumnDiff( '`comment_quoted`', new Column('`comment_quoted`', Type::getType('array'), ['comment' => 'Doctrine array.']), ['comment', 'type'], new Column('`comment_quoted`', Type::getType('integer'), ['comment' => 'Doctrine 0wnz you!']) ); // Remove comment and change type to custom type from regular commented column. $tableDiff->changedColumns['create'] = new ColumnDiff( 'create', new Column('create', Type::getType('object')), ['comment', 'type'], new Column('create', Type::getType('integer'), ['comment' => 'Doctrine 0wnz comments for reserved keyword columns!']) ); // Add comment and change custom type to regular type from non-commented column. $tableDiff->changedColumns['commented_type'] = new ColumnDiff( 'commented_type', new Column('commented_type', Type::getType('integer'), ['comment' => 'foo']), ['comment', 'type'], new Column('commented_type', Type::getType('object')) ); // Remove comment from commented custom type column. $tableDiff->changedColumns['commented_type_with_comment'] = new ColumnDiff( 'commented_type_with_comment', new Column('commented_type_with_comment', Type::getType('array')), ['comment'], new Column('commented_type_with_comment', Type::getType('array'), ['comment' => 'Doctrine array type.']) ); $tableDiff->removedColumns['comment_integer_0'] = new Column('comment_integer_0', Type::getType('integer'), ['comment' => 0]); $this->schemaManager->alterTable($tableDiff); $columns = $this->schemaManager->listTableColumns('sqlsrv_column_comment'); self::assertCount(23, $columns); self::assertEquals('primary', $columns['id']->getComment()); self::assertNull($columns['comment_null']->getComment()); self::assertEquals('false', $columns['comment_false']->getComment()); self::assertNull($columns['comment_empty_string']->getComment()); self::assertEquals('0', $columns['comment_double_0']->getComment()); self::assertNull($columns['comment_string_0']->getComment()); self::assertNull($columns['comment']->getComment()); self::assertEquals('Doctrine array.', $columns['comment_quoted']->getComment()); self::assertNull($columns['[create]']->getComment()); self::assertEquals('foo', $columns['commented_type']->getComment()); self::assertNull($columns['commented_type_with_comment']->getComment()); self::assertNull($columns['added_comment_none']->getComment()); self::assertNull($columns['added_comment_null']->getComment()); self::assertNull($columns['added_comment_false']->getComment()); self::assertNull($columns['added_comment_empty_string']->getComment()); self::assertEquals('0', $columns['added_comment_integer_0']->getComment()); self::assertEquals('0', $columns['added_comment_float_0']->getComment()); self::assertEquals('0', $columns['added_comment_string_0']->getComment()); self::assertEquals('Doctrine', $columns['added_comment']->getComment()); self::assertEquals('rulez', $columns['added_comment_quoted']->getComment()); self::assertEquals('666', $columns['[select]']->getComment()); self::assertNull($columns['added_commented_type']->getComment()); self::assertEquals('666', $columns['added_commented_type_with_comment']->getComment()); } public function testPkOrdering() : void { // SQL Server stores index column information in a system table with two // columns that almost always have the same value: index_column_id and key_ordinal. // The only situation when the two values doesn't match up is when a clustered index // is declared that references columns in a different order from which they are // declared in the table. In that case, key_ordinal != index_column_id. // key_ordinal holds the index ordering. index_column_id is just a unique identifier // for index columns within the given index. $table = new Table('sqlsrv_pk_ordering'); $table->addColumn('colA', 'integer', ['notnull' => true]); $table->addColumn('colB', 'integer', ['notnull' => true]); $table->setPrimaryKey(['colB', 'colA']); $this->schemaManager->createTable($table); $indexes = $this->schemaManager->listTableIndexes('sqlsrv_pk_ordering'); self::assertCount(1, $indexes); $firstIndex = current($indexes); $columns = $firstIndex->getColumns(); self::assertCount(2, $columns); self::assertEquals('colB', $columns[0]); self::assertEquals('colA', $columns[1]); } } SchemaManagerFunctionalTestCase.php000066400000000000000000002017131360544566000337270ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/SchemagetPlatformName(); if ($this->connection->getDatabasePlatform()->getName() !== $dbms) { $this->markTestSkipped(static::class . ' requires the use of ' . $dbms); } $this->schemaManager = $this->connection->getSchemaManager(); } protected function tearDown() : void { parent::tearDown(); $this->schemaManager->tryMethod('dropTable', 'testschema.my_table_in_namespace'); //TODO: SchemaDiff does not drop removed namespaces? try { //sql server versions below 2016 do not support 'IF EXISTS' so we have to catch the exception here $this->connection->exec('DROP SCHEMA testschema'); } catch (DBALException $e) { return; } } /** * @group DBAL-1220 */ public function testDropsDatabaseWithActiveConnections() : void { if (! $this->schemaManager->getDatabasePlatform()->supportsCreateDropDatabase()) { $this->markTestSkipped('Cannot drop Database client side with this Driver.'); } $this->schemaManager->dropAndCreateDatabase('test_drop_database'); $knownDatabases = $this->schemaManager->listDatabases(); if ($this->connection->getDatabasePlatform() instanceof OraclePlatform) { self::assertContains('TEST_DROP_DATABASE', $knownDatabases); } else { self::assertContains('test_drop_database', $knownDatabases); } $params = $this->connection->getParams(); if ($this->connection->getDatabasePlatform() instanceof OraclePlatform) { $params['user'] = 'test_drop_database'; } else { $params['dbname'] = 'test_drop_database'; } $user = $params['user'] ?? null; $password = $params['password'] ?? null; $connection = $this->connection->getDriver()->connect($params, $user, $password); self::assertInstanceOf(Connection::class, $connection); $this->schemaManager->dropDatabase('test_drop_database'); self::assertNotContains('test_drop_database', $this->schemaManager->listDatabases()); } /** * @group DBAL-195 */ public function testDropAndCreateSequence() : void { $platform = $this->connection->getDatabasePlatform(); if (! $platform->supportsSequences()) { $this->markTestSkipped( sprintf('The "%s" platform does not support sequences.', $platform->getName()) ); } $name = 'dropcreate_sequences_test_seq'; $this->schemaManager->dropAndCreateSequence(new Sequence($name, 20, 10)); self::assertTrue($this->hasElementWithName($this->schemaManager->listSequences(), $name)); } /** * @param AbstractAsset[] $items */ private function hasElementWithName(array $items, string $name) : bool { $filteredList = array_filter( $items, static function (AbstractAsset $item) use ($name) : bool { return $item->getShortestName($item->getNamespaceName()) === $name; } ); return count($filteredList) === 1; } public function testListSequences() : void { $platform = $this->connection->getDatabasePlatform(); if (! $platform->supportsSequences()) { $this->markTestSkipped( sprintf('The "%s" platform does not support sequences.', $platform->getName()) ); } $sequence = new Sequence('list_sequences_test_seq', 20, 10); $this->schemaManager->createSequence($sequence); $sequences = $this->schemaManager->listSequences(); self::assertIsArray($sequences, 'listSequences() should return an array.'); $foundSequence = null; foreach ($sequences as $sequence) { self::assertInstanceOf(Sequence::class, $sequence, 'Array elements of listSequences() should be Sequence instances.'); if (strtolower($sequence->getName()) !== 'list_sequences_test_seq') { continue; } $foundSequence = $sequence; } self::assertNotNull($foundSequence, "Sequence with name 'list_sequences_test_seq' was not found."); self::assertSame(20, $foundSequence->getAllocationSize(), 'Allocation Size is expected to be 20.'); self::assertSame(10, $foundSequence->getInitialValue(), 'Initial Value is expected to be 10.'); } public function testListDatabases() : void { if (! $this->schemaManager->getDatabasePlatform()->supportsCreateDropDatabase()) { $this->markTestSkipped('Cannot drop Database client side with this Driver.'); } $this->schemaManager->dropAndCreateDatabase('test_create_database'); $databases = $this->schemaManager->listDatabases(); $databases = array_map('strtolower', $databases); self::assertContains('test_create_database', $databases); } /** * @group DBAL-1058 */ public function testListNamespaceNames() : void { if (! $this->schemaManager->getDatabasePlatform()->supportsSchemas()) { $this->markTestSkipped('Platform does not support schemas.'); } // Currently dropping schemas is not supported, so we have to workaround here. $namespaces = $this->schemaManager->listNamespaceNames(); $namespaces = array_map('strtolower', $namespaces); if (! in_array('test_create_schema', $namespaces)) { $this->connection->executeUpdate($this->schemaManager->getDatabasePlatform()->getCreateSchemaSQL('test_create_schema')); $namespaces = $this->schemaManager->listNamespaceNames(); $namespaces = array_map('strtolower', $namespaces); } self::assertContains('test_create_schema', $namespaces); } public function testListTables() : void { $this->createTestTable('list_tables_test'); $tables = $this->schemaManager->listTables(); self::assertIsArray($tables); self::assertTrue(count($tables) > 0, "List Tables has to find at least one table named 'list_tables_test'."); $foundTable = false; foreach ($tables as $table) { self::assertInstanceOf(Table::class, $table); if (strtolower($table->getName()) !== 'list_tables_test') { continue; } $foundTable = true; self::assertTrue($table->hasColumn('id')); self::assertTrue($table->hasColumn('test')); self::assertTrue($table->hasColumn('foreign_key_test')); } self::assertTrue($foundTable, "The 'list_tables_test' table has to be found."); } public function createListTableColumns() : Table { $table = new Table('list_table_columns'); $table->addColumn('id', 'integer', ['notnull' => true]); $table->addColumn('test', 'string', ['length' => 255, 'notnull' => false, 'default' => 'expected default']); $table->addColumn('foo', 'text', ['notnull' => true]); $table->addColumn('bar', 'decimal', ['precision' => 10, 'scale' => 4, 'notnull' => false]); $table->addColumn('baz1', 'datetime'); $table->addColumn('baz2', 'time'); $table->addColumn('baz3', 'date'); $table->setPrimaryKey(['id']); return $table; } public function testListTableColumns() : void { $table = $this->createListTableColumns(); $this->schemaManager->dropAndCreateTable($table); $columns = $this->schemaManager->listTableColumns('list_table_columns'); $columnsKeys = array_keys($columns); self::assertArrayHasKey('id', $columns); self::assertEquals(0, array_search('id', $columnsKeys)); self::assertEquals('id', strtolower($columns['id']->getname())); self::assertInstanceOf(IntegerType::class, $columns['id']->gettype()); self::assertEquals(false, $columns['id']->getunsigned()); self::assertEquals(true, $columns['id']->getnotnull()); self::assertEquals(null, $columns['id']->getdefault()); self::assertIsArray($columns['id']->getPlatformOptions()); self::assertArrayHasKey('test', $columns); self::assertEquals(1, array_search('test', $columnsKeys)); self::assertEquals('test', strtolower($columns['test']->getname())); self::assertInstanceOf(StringType::class, $columns['test']->gettype()); self::assertEquals(255, $columns['test']->getlength()); self::assertEquals(false, $columns['test']->getfixed()); self::assertEquals(false, $columns['test']->getnotnull()); self::assertEquals('expected default', $columns['test']->getdefault()); self::assertIsArray($columns['test']->getPlatformOptions()); self::assertEquals('foo', strtolower($columns['foo']->getname())); self::assertEquals(2, array_search('foo', $columnsKeys)); self::assertInstanceOf(TextType::class, $columns['foo']->gettype()); self::assertEquals(false, $columns['foo']->getunsigned()); self::assertEquals(false, $columns['foo']->getfixed()); self::assertEquals(true, $columns['foo']->getnotnull()); self::assertEquals(null, $columns['foo']->getdefault()); self::assertIsArray($columns['foo']->getPlatformOptions()); self::assertEquals('bar', strtolower($columns['bar']->getname())); self::assertEquals(3, array_search('bar', $columnsKeys)); self::assertInstanceOf(DecimalType::class, $columns['bar']->gettype()); self::assertEquals(null, $columns['bar']->getlength()); self::assertEquals(10, $columns['bar']->getprecision()); self::assertEquals(4, $columns['bar']->getscale()); self::assertEquals(false, $columns['bar']->getunsigned()); self::assertEquals(false, $columns['bar']->getfixed()); self::assertEquals(false, $columns['bar']->getnotnull()); self::assertEquals(null, $columns['bar']->getdefault()); self::assertIsArray($columns['bar']->getPlatformOptions()); self::assertEquals('baz1', strtolower($columns['baz1']->getname())); self::assertEquals(4, array_search('baz1', $columnsKeys)); self::assertInstanceOf(DateTimeType::class, $columns['baz1']->gettype()); self::assertEquals(true, $columns['baz1']->getnotnull()); self::assertEquals(null, $columns['baz1']->getdefault()); self::assertIsArray($columns['baz1']->getPlatformOptions()); self::assertEquals('baz2', strtolower($columns['baz2']->getname())); self::assertEquals(5, array_search('baz2', $columnsKeys)); self::assertContains($columns['baz2']->gettype()->getName(), ['time', 'date', 'datetime']); self::assertEquals(true, $columns['baz2']->getnotnull()); self::assertEquals(null, $columns['baz2']->getdefault()); self::assertIsArray($columns['baz2']->getPlatformOptions()); self::assertEquals('baz3', strtolower($columns['baz3']->getname())); self::assertEquals(6, array_search('baz3', $columnsKeys)); self::assertContains($columns['baz3']->gettype()->getName(), ['time', 'date', 'datetime']); self::assertEquals(true, $columns['baz3']->getnotnull()); self::assertEquals(null, $columns['baz3']->getdefault()); self::assertIsArray($columns['baz3']->getPlatformOptions()); } /** * @group DBAL-1078 */ public function testListTableColumnsWithFixedStringColumn() : void { $tableName = 'test_list_table_fixed_string'; $table = new Table($tableName); $table->addColumn('column_char', 'string', ['fixed' => true, 'length' => 2]); $this->schemaManager->createTable($table); $columns = $this->schemaManager->listTableColumns($tableName); self::assertArrayHasKey('column_char', $columns); self::assertInstanceOf(StringType::class, $columns['column_char']->getType()); self::assertTrue($columns['column_char']->getFixed()); self::assertSame(2, $columns['column_char']->getLength()); } public function testListTableColumnsDispatchEvent() : void { $table = $this->createListTableColumns(); $this->schemaManager->dropAndCreateTable($table); $listenerMock = $this->getMockBuilder($this->getMockClass('ListTableColumnsDispatchEventListener')) ->addMethods(['onSchemaColumnDefinition']) ->getMock(); $listenerMock ->expects($this->exactly(7)) ->method('onSchemaColumnDefinition'); $oldEventManager = $this->schemaManager->getDatabasePlatform()->getEventManager(); $eventManager = new EventManager(); $eventManager->addEventListener([Events::onSchemaColumnDefinition], $listenerMock); $this->schemaManager->getDatabasePlatform()->setEventManager($eventManager); $this->schemaManager->listTableColumns('list_table_columns'); $this->schemaManager->getDatabasePlatform()->setEventManager($oldEventManager); } public function testListTableIndexesDispatchEvent() : void { $table = $this->getTestTable('list_table_indexes_test'); $table->addUniqueIndex(['test'], 'test_index_name'); $table->addIndex(['id', 'test'], 'test_composite_idx'); $this->schemaManager->dropAndCreateTable($table); $listenerMock = $this->getMockBuilder($this->getMockClass('ListTableIndexesDispatchEventListener')) ->addMethods(['onSchemaIndexDefinition']) ->getMock(); $listenerMock ->expects($this->exactly(3)) ->method('onSchemaIndexDefinition'); $oldEventManager = $this->schemaManager->getDatabasePlatform()->getEventManager(); $eventManager = new EventManager(); $eventManager->addEventListener([Events::onSchemaIndexDefinition], $listenerMock); $this->schemaManager->getDatabasePlatform()->setEventManager($eventManager); $this->schemaManager->listTableIndexes('list_table_indexes_test'); $this->schemaManager->getDatabasePlatform()->setEventManager($oldEventManager); } public function testDiffListTableColumns() : void { if ($this->schemaManager->getDatabasePlatform()->getName() === 'oracle') { $this->markTestSkipped('Does not work with Oracle, since it cannot detect DateTime, Date and Time differenecs (at the moment).'); } $offlineTable = $this->createListTableColumns(); $this->schemaManager->dropAndCreateTable($offlineTable); $onlineTable = $this->schemaManager->listTableDetails('list_table_columns'); $comparator = new Comparator(); $diff = $comparator->diffTable($offlineTable, $onlineTable); self::assertFalse($diff, 'No differences should be detected with the offline vs online schema.'); } public function testListTableIndexes() : void { $table = $this->getTestCompositeTable('list_table_indexes_test'); $table->addUniqueIndex(['test'], 'test_index_name'); $table->addIndex(['id', 'test'], 'test_composite_idx'); $this->schemaManager->dropAndCreateTable($table); $tableIndexes = $this->schemaManager->listTableIndexes('list_table_indexes_test'); self::assertEquals(3, count($tableIndexes)); self::assertArrayHasKey('primary', $tableIndexes, 'listTableIndexes() has to return a "primary" array key.'); self::assertEquals(['id', 'other_id'], array_map('strtolower', $tableIndexes['primary']->getColumns())); self::assertTrue($tableIndexes['primary']->isUnique()); self::assertTrue($tableIndexes['primary']->isPrimary()); self::assertEquals('test_index_name', strtolower($tableIndexes['test_index_name']->getName())); self::assertEquals(['test'], array_map('strtolower', $tableIndexes['test_index_name']->getColumns())); self::assertTrue($tableIndexes['test_index_name']->isUnique()); self::assertFalse($tableIndexes['test_index_name']->isPrimary()); self::assertEquals('test_composite_idx', strtolower($tableIndexes['test_composite_idx']->getName())); self::assertEquals(['id', 'test'], array_map('strtolower', $tableIndexes['test_composite_idx']->getColumns())); self::assertFalse($tableIndexes['test_composite_idx']->isUnique()); self::assertFalse($tableIndexes['test_composite_idx']->isPrimary()); } public function testDropAndCreateIndex() : void { $table = $this->getTestTable('test_create_index'); $table->addUniqueIndex(['test'], 'test'); $this->schemaManager->dropAndCreateTable($table); $this->schemaManager->dropAndCreateIndex($table->getIndex('test'), $table); $tableIndexes = $this->schemaManager->listTableIndexes('test_create_index'); self::assertIsArray($tableIndexes); self::assertEquals('test', strtolower($tableIndexes['test']->getName())); self::assertEquals(['test'], array_map('strtolower', $tableIndexes['test']->getColumns())); self::assertTrue($tableIndexes['test']->isUnique()); self::assertFalse($tableIndexes['test']->isPrimary()); } public function testCreateTableWithForeignKeys() : void { if (! $this->schemaManager->getDatabasePlatform()->supportsForeignKeyConstraints()) { $this->markTestSkipped('Platform does not support foreign keys.'); } $tableB = $this->getTestTable('test_foreign'); $this->schemaManager->dropAndCreateTable($tableB); $tableA = $this->getTestTable('test_create_fk'); $tableA->addForeignKeyConstraint('test_foreign', ['foreign_key_test'], ['id']); $this->schemaManager->dropAndCreateTable($tableA); $fkTable = $this->schemaManager->listTableDetails('test_create_fk'); $fkConstraints = $fkTable->getForeignKeys(); self::assertEquals(1, count($fkConstraints), "Table 'test_create_fk1' has to have one foreign key."); $fkConstraint = current($fkConstraints); self::assertInstanceOf(ForeignKeyConstraint::class, $fkConstraint); self::assertEquals('test_foreign', strtolower($fkConstraint->getForeignTableName())); self::assertEquals(['foreign_key_test'], array_map('strtolower', $fkConstraint->getColumns())); self::assertEquals(['id'], array_map('strtolower', $fkConstraint->getForeignColumns())); self::assertTrue($fkTable->columnsAreIndexed($fkConstraint->getColumns()), 'The columns of a foreign key constraint should always be indexed.'); } public function testListForeignKeys() : void { if (! $this->connection->getDatabasePlatform()->supportsForeignKeyConstraints()) { $this->markTestSkipped('Does not support foreign key constraints.'); } $this->createTestTable('test_create_fk1'); $this->createTestTable('test_create_fk2'); $foreignKey = new ForeignKeyConstraint( ['foreign_key_test'], 'test_create_fk2', ['id'], 'foreign_key_test_fk', ['onDelete' => 'CASCADE'] ); $this->schemaManager->createForeignKey($foreignKey, 'test_create_fk1'); $fkeys = $this->schemaManager->listTableForeignKeys('test_create_fk1'); self::assertEquals(1, count($fkeys), "Table 'test_create_fk1' has to have one foreign key."); self::assertInstanceOf(ForeignKeyConstraint::class, $fkeys[0]); self::assertEquals(['foreign_key_test'], array_map('strtolower', $fkeys[0]->getLocalColumns())); self::assertEquals(['id'], array_map('strtolower', $fkeys[0]->getForeignColumns())); self::assertEquals('test_create_fk2', strtolower($fkeys[0]->getForeignTableName())); if (! $fkeys[0]->hasOption('onDelete')) { return; } self::assertEquals('CASCADE', $fkeys[0]->getOption('onDelete')); } protected function getCreateExampleViewSql() : void { $this->markTestSkipped('No Create Example View SQL was defined for this SchemaManager'); } public function testCreateSchema() : void { $this->createTestTable('test_table'); $schema = $this->schemaManager->createSchema(); self::assertTrue($schema->hasTable('test_table')); } public function testAlterTableScenario() : void { if (! $this->schemaManager->getDatabasePlatform()->supportsAlterTable()) { $this->markTestSkipped('Alter Table is not supported by this platform.'); } $alterTable = $this->createTestTable('alter_table'); $this->createTestTable('alter_table_foreign'); $table = $this->schemaManager->listTableDetails('alter_table'); self::assertTrue($table->hasColumn('id')); self::assertTrue($table->hasColumn('test')); self::assertTrue($table->hasColumn('foreign_key_test')); self::assertEquals(0, count($table->getForeignKeys())); self::assertEquals(1, count($table->getIndexes())); $tableDiff = new TableDiff('alter_table'); $tableDiff->fromTable = $alterTable; $tableDiff->addedColumns['foo'] = new Column('foo', Type::getType('integer')); $tableDiff->removedColumns['test'] = $table->getColumn('test'); $this->schemaManager->alterTable($tableDiff); $table = $this->schemaManager->listTableDetails('alter_table'); self::assertFalse($table->hasColumn('test')); self::assertTrue($table->hasColumn('foo')); $tableDiff = new TableDiff('alter_table'); $tableDiff->fromTable = $table; $tableDiff->addedIndexes[] = new Index('foo_idx', ['foo']); $this->schemaManager->alterTable($tableDiff); $table = $this->schemaManager->listTableDetails('alter_table'); self::assertEquals(2, count($table->getIndexes())); self::assertTrue($table->hasIndex('foo_idx')); self::assertEquals(['foo'], array_map('strtolower', $table->getIndex('foo_idx')->getColumns())); self::assertFalse($table->getIndex('foo_idx')->isPrimary()); self::assertFalse($table->getIndex('foo_idx')->isUnique()); $tableDiff = new TableDiff('alter_table'); $tableDiff->fromTable = $table; $tableDiff->changedIndexes[] = new Index('foo_idx', ['foo', 'foreign_key_test']); $this->schemaManager->alterTable($tableDiff); $table = $this->schemaManager->listTableDetails('alter_table'); self::assertEquals(2, count($table->getIndexes())); self::assertTrue($table->hasIndex('foo_idx')); self::assertEquals(['foo', 'foreign_key_test'], array_map('strtolower', $table->getIndex('foo_idx')->getColumns())); $tableDiff = new TableDiff('alter_table'); $tableDiff->fromTable = $table; $tableDiff->renamedIndexes['foo_idx'] = new Index('bar_idx', ['foo', 'foreign_key_test']); $this->schemaManager->alterTable($tableDiff); $table = $this->schemaManager->listTableDetails('alter_table'); self::assertEquals(2, count($table->getIndexes())); self::assertTrue($table->hasIndex('bar_idx')); self::assertFalse($table->hasIndex('foo_idx')); self::assertEquals(['foo', 'foreign_key_test'], array_map('strtolower', $table->getIndex('bar_idx')->getColumns())); self::assertFalse($table->getIndex('bar_idx')->isPrimary()); self::assertFalse($table->getIndex('bar_idx')->isUnique()); $tableDiff = new TableDiff('alter_table'); $tableDiff->fromTable = $table; $tableDiff->removedIndexes[] = new Index('bar_idx', ['foo', 'foreign_key_test']); $fk = new ForeignKeyConstraint(['foreign_key_test'], 'alter_table_foreign', ['id']); $tableDiff->addedForeignKeys[] = $fk; $this->schemaManager->alterTable($tableDiff); $table = $this->schemaManager->listTableDetails('alter_table'); // dont check for index size here, some platforms automatically add indexes for foreign keys. self::assertFalse($table->hasIndex('bar_idx')); if (! $this->schemaManager->getDatabasePlatform()->supportsForeignKeyConstraints()) { return; } $fks = $table->getForeignKeys(); self::assertCount(1, $fks); $foreignKey = current($fks); self::assertEquals('alter_table_foreign', strtolower($foreignKey->getForeignTableName())); self::assertEquals(['foreign_key_test'], array_map('strtolower', $foreignKey->getColumns())); self::assertEquals(['id'], array_map('strtolower', $foreignKey->getForeignColumns())); } public function testTableInNamespace() : void { if (! $this->schemaManager->getDatabasePlatform()->supportsSchemas()) { $this->markTestSkipped('Schema definition is not supported by this platform.'); } //create schema $diff = new SchemaDiff(); $diff->newNamespaces[] = 'testschema'; foreach ($diff->toSql($this->schemaManager->getDatabasePlatform()) as $sql) { $this->connection->exec($sql); } //test if table is create in namespace $this->createTestTable('testschema.my_table_in_namespace'); self::assertContains('testschema.my_table_in_namespace', $this->schemaManager->listTableNames()); //tables without namespace should be created in default namespace //default namespaces are ignored in table listings $this->createTestTable('my_table_not_in_namespace'); self::assertContains('my_table_not_in_namespace', $this->schemaManager->listTableNames()); } public function testCreateAndListViews() : void { if (! $this->schemaManager->getDatabasePlatform()->supportsViews()) { $this->markTestSkipped('Views is not supported by this platform.'); } $this->createTestTable('view_test_table'); $name = 'doctrine_test_view'; $sql = 'SELECT * FROM view_test_table'; $view = new View($name, $sql); $this->schemaManager->dropAndCreateView($view); self::assertTrue($this->hasElementWithName($this->schemaManager->listViews(), $name)); } public function testAutoincrementDetection() : void { if (! $this->schemaManager->getDatabasePlatform()->supportsIdentityColumns()) { $this->markTestSkipped('This test is only supported on platforms that have autoincrement'); } $table = new Table('test_autoincrement'); $table->setSchemaConfig($this->schemaManager->createSchemaConfig()); $table->addColumn('id', 'integer', ['autoincrement' => true]); $table->setPrimaryKey(['id']); $this->schemaManager->createTable($table); $inferredTable = $this->schemaManager->listTableDetails('test_autoincrement'); self::assertTrue($inferredTable->hasColumn('id')); self::assertTrue($inferredTable->getColumn('id')->getAutoincrement()); } /** * @group DBAL-792 */ public function testAutoincrementDetectionMulticolumns() : void { if (! $this->schemaManager->getDatabasePlatform()->supportsIdentityColumns()) { $this->markTestSkipped('This test is only supported on platforms that have autoincrement'); } $table = new Table('test_not_autoincrement'); $table->setSchemaConfig($this->schemaManager->createSchemaConfig()); $table->addColumn('id', 'integer'); $table->addColumn('other_id', 'integer'); $table->setPrimaryKey(['id', 'other_id']); $this->schemaManager->createTable($table); $inferredTable = $this->schemaManager->listTableDetails('test_not_autoincrement'); self::assertTrue($inferredTable->hasColumn('id')); self::assertFalse($inferredTable->getColumn('id')->getAutoincrement()); } /** * @group DDC-887 */ public function testUpdateSchemaWithForeignKeyRenaming() : void { if (! $this->schemaManager->getDatabasePlatform()->supportsForeignKeyConstraints()) { $this->markTestSkipped('This test is only supported on platforms that have foreign keys.'); } $table = new Table('test_fk_base'); $table->addColumn('id', 'integer'); $table->setPrimaryKey(['id']); $tableFK = new Table('test_fk_rename'); $tableFK->setSchemaConfig($this->schemaManager->createSchemaConfig()); $tableFK->addColumn('id', 'integer'); $tableFK->addColumn('fk_id', 'integer'); $tableFK->setPrimaryKey(['id']); $tableFK->addIndex(['fk_id'], 'fk_idx'); $tableFK->addForeignKeyConstraint('test_fk_base', ['fk_id'], ['id']); $this->schemaManager->createTable($table); $this->schemaManager->createTable($tableFK); $tableFKNew = new Table('test_fk_rename'); $tableFKNew->setSchemaConfig($this->schemaManager->createSchemaConfig()); $tableFKNew->addColumn('id', 'integer'); $tableFKNew->addColumn('rename_fk_id', 'integer'); $tableFKNew->setPrimaryKey(['id']); $tableFKNew->addIndex(['rename_fk_id'], 'fk_idx'); $tableFKNew->addForeignKeyConstraint('test_fk_base', ['rename_fk_id'], ['id']); $c = new Comparator(); $tableDiff = $c->diffTable($tableFK, $tableFKNew); $this->schemaManager->alterTable($tableDiff); $table = $this->schemaManager->listTableDetails('test_fk_rename'); $foreignKeys = $table->getForeignKeys(); self::assertTrue($table->hasColumn('rename_fk_id')); self::assertCount(1, $foreignKeys); self::assertSame(['rename_fk_id'], array_map('strtolower', current($foreignKeys)->getColumns())); } /** * @group DBAL-1062 */ public function testRenameIndexUsedInForeignKeyConstraint() : void { if (! $this->schemaManager->getDatabasePlatform()->supportsForeignKeyConstraints()) { $this->markTestSkipped('This test is only supported on platforms that have foreign keys.'); } $primaryTable = new Table('test_rename_index_primary'); $primaryTable->addColumn('id', 'integer'); $primaryTable->setPrimaryKey(['id']); $foreignTable = new Table('test_rename_index_foreign'); $foreignTable->addColumn('fk', 'integer'); $foreignTable->addIndex(['fk'], 'rename_index_fk_idx'); $foreignTable->addForeignKeyConstraint( 'test_rename_index_primary', ['fk'], ['id'], [], 'fk_constraint' ); $this->schemaManager->dropAndCreateTable($primaryTable); $this->schemaManager->dropAndCreateTable($foreignTable); $foreignTable2 = clone $foreignTable; $foreignTable2->renameIndex('rename_index_fk_idx', 'renamed_index_fk_idx'); $comparator = new Comparator(); $this->schemaManager->alterTable($comparator->diffTable($foreignTable, $foreignTable2)); $foreignTable = $this->schemaManager->listTableDetails('test_rename_index_foreign'); self::assertFalse($foreignTable->hasIndex('rename_index_fk_idx')); self::assertTrue($foreignTable->hasIndex('renamed_index_fk_idx')); self::assertTrue($foreignTable->hasForeignKey('fk_constraint')); } /** * @group DBAL-42 */ public function testGetColumnComment() : void { if (! $this->connection->getDatabasePlatform()->supportsInlineColumnComments() && ! $this->connection->getDatabasePlatform()->supportsCommentOnStatement() && $this->connection->getDatabasePlatform()->getName() !== 'mssql') { $this->markTestSkipped('Database does not support column comments.'); } $table = new Table('column_comment_test'); $table->addColumn('id', 'integer', ['comment' => 'This is a comment']); $table->setPrimaryKey(['id']); $this->schemaManager->createTable($table); $columns = $this->schemaManager->listTableColumns('column_comment_test'); self::assertEquals(1, count($columns)); self::assertEquals('This is a comment', $columns['id']->getComment()); $tableDiff = new TableDiff('column_comment_test'); $tableDiff->fromTable = $table; $tableDiff->changedColumns['id'] = new ColumnDiff( 'id', new Column( 'id', Type::getType('integer') ), ['comment'], new Column( 'id', Type::getType('integer'), ['comment' => 'This is a comment'] ) ); $this->schemaManager->alterTable($tableDiff); $columns = $this->schemaManager->listTableColumns('column_comment_test'); self::assertEquals(1, count($columns)); self::assertEmpty($columns['id']->getComment()); } /** * @group DBAL-42 */ public function testAutomaticallyAppendCommentOnMarkedColumns() : void { if (! $this->connection->getDatabasePlatform()->supportsInlineColumnComments() && ! $this->connection->getDatabasePlatform()->supportsCommentOnStatement() && $this->connection->getDatabasePlatform()->getName() !== 'mssql') { $this->markTestSkipped('Database does not support column comments.'); } $table = new Table('column_comment_test2'); $table->addColumn('id', 'integer', ['comment' => 'This is a comment']); $table->addColumn('obj', 'object', ['comment' => 'This is a comment']); $table->addColumn('arr', 'array', ['comment' => 'This is a comment']); $table->setPrimaryKey(['id']); $this->schemaManager->createTable($table); $columns = $this->schemaManager->listTableColumns('column_comment_test2'); self::assertEquals(3, count($columns)); self::assertEquals('This is a comment', $columns['id']->getComment()); self::assertEquals('This is a comment', $columns['obj']->getComment(), 'The Doctrine2 Typehint should be stripped from comment.'); self::assertInstanceOf(ObjectType::class, $columns['obj']->getType(), 'The Doctrine2 should be detected from comment hint.'); self::assertEquals('This is a comment', $columns['arr']->getComment(), 'The Doctrine2 Typehint should be stripped from comment.'); self::assertInstanceOf(ArrayType::class, $columns['arr']->getType(), 'The Doctrine2 should be detected from comment hint.'); } /** * @group DBAL-1228 */ public function testCommentHintOnDateIntervalTypeColumn() : void { if (! $this->connection->getDatabasePlatform()->supportsInlineColumnComments() && ! $this->connection->getDatabasePlatform()->supportsCommentOnStatement() && $this->connection->getDatabasePlatform()->getName() !== 'mssql') { $this->markTestSkipped('Database does not support column comments.'); } $table = new Table('column_dateinterval_comment'); $table->addColumn('id', 'integer', ['comment' => 'This is a comment']); $table->addColumn('date_interval', 'dateinterval', ['comment' => 'This is a comment']); $table->setPrimaryKey(['id']); $this->schemaManager->createTable($table); $columns = $this->schemaManager->listTableColumns('column_dateinterval_comment'); self::assertEquals(2, count($columns)); self::assertEquals('This is a comment', $columns['id']->getComment()); self::assertEquals('This is a comment', $columns['date_interval']->getComment(), 'The Doctrine2 Typehint should be stripped from comment.'); self::assertInstanceOf(DateIntervalType::class, $columns['date_interval']->getType(), 'The Doctrine2 should be detected from comment hint.'); } /** * @group DBAL-825 */ public function testChangeColumnsTypeWithDefaultValue() : void { $tableName = 'column_def_change_type'; $table = new Table($tableName); $table->addColumn('col_int', 'smallint', ['default' => 666]); $table->addColumn('col_string', 'string', ['default' => 'foo']); $this->schemaManager->dropAndCreateTable($table); $tableDiff = new TableDiff($tableName); $tableDiff->fromTable = $table; $tableDiff->changedColumns['col_int'] = new ColumnDiff( 'col_int', new Column('col_int', Type::getType('integer'), ['default' => 666]), ['type'], new Column('col_int', Type::getType('smallint'), ['default' => 666]) ); $tableDiff->changedColumns['col_string'] = new ColumnDiff( 'col_string', new Column('col_string', Type::getType('string'), ['default' => 'foo', 'fixed' => true]), ['fixed'], new Column('col_string', Type::getType('string'), ['default' => 'foo']) ); $this->schemaManager->alterTable($tableDiff); $columns = $this->schemaManager->listTableColumns($tableName); self::assertInstanceOf(IntegerType::class, $columns['col_int']->getType()); self::assertEquals(666, $columns['col_int']->getDefault()); self::assertInstanceOf(StringType::class, $columns['col_string']->getType()); self::assertEquals('foo', $columns['col_string']->getDefault()); } /** * @group DBAL-197 */ public function testListTableWithBlob() : void { $table = new Table('test_blob_table'); $table->addColumn('id', 'integer', ['comment' => 'This is a comment']); $table->addColumn('binarydata', 'blob', []); $table->setPrimaryKey(['id']); $this->schemaManager->createTable($table); $created = $this->schemaManager->listTableDetails('test_blob_table'); self::assertTrue($created->hasColumn('id')); self::assertTrue($created->hasColumn('binarydata')); self::assertTrue($created->hasPrimaryKey()); } /** * @param mixed[] $data */ protected function createTestTable(string $name = 'test_table', array $data = []) : Table { $options = $data['options'] ?? []; $table = $this->getTestTable($name, $options); $this->schemaManager->dropAndCreateTable($table); return $table; } /** * @param mixed[] $options */ protected function getTestTable(string $name, array $options = []) : Table { $table = new Table($name, [], [], [], false, $options); $table->setSchemaConfig($this->schemaManager->createSchemaConfig()); $table->addColumn('id', 'integer', ['notnull' => true]); $table->setPrimaryKey(['id']); $table->addColumn('test', 'string', ['length' => 255]); $table->addColumn('foreign_key_test', 'integer'); return $table; } protected function getTestCompositeTable(string $name) : Table { $table = new Table($name, [], [], [], false, []); $table->setSchemaConfig($this->schemaManager->createSchemaConfig()); $table->addColumn('id', 'integer', ['notnull' => true]); $table->addColumn('other_id', 'integer', ['notnull' => true]); $table->setPrimaryKey(['id', 'other_id']); $table->addColumn('test', 'string', ['length' => 255]); return $table; } /** * @param Table[] $tables */ protected function assertHasTable(array $tables) : void { $foundTable = false; foreach ($tables as $table) { self::assertInstanceOf(Table::class, $table, 'No Table instance was found in tables array.'); if (strtolower($table->getName()) !== 'list_tables_test_new_name') { continue; } $foundTable = true; } self::assertTrue($foundTable, 'Could not find new table'); } public function testListForeignKeysComposite() : void { if (! $this->connection->getDatabasePlatform()->supportsForeignKeyConstraints()) { $this->markTestSkipped('Does not support foreign key constraints.'); } $this->schemaManager->createTable($this->getTestTable('test_create_fk3')); $this->schemaManager->createTable($this->getTestCompositeTable('test_create_fk4')); $foreignKey = new ForeignKeyConstraint( ['id', 'foreign_key_test'], 'test_create_fk4', ['id', 'other_id'], 'foreign_key_test_fk2' ); $this->schemaManager->createForeignKey($foreignKey, 'test_create_fk3'); $fkeys = $this->schemaManager->listTableForeignKeys('test_create_fk3'); self::assertEquals(1, count($fkeys), "Table 'test_create_fk3' has to have one foreign key."); self::assertInstanceOf(ForeignKeyConstraint::class, $fkeys[0]); self::assertEquals(['id', 'foreign_key_test'], array_map('strtolower', $fkeys[0]->getLocalColumns())); self::assertEquals(['id', 'other_id'], array_map('strtolower', $fkeys[0]->getForeignColumns())); } /** * @group DBAL-44 */ public function testColumnDefaultLifecycle() : void { $table = new Table('col_def_lifecycle'); $table->addColumn('id', 'integer', ['autoincrement' => true]); $table->addColumn('column1', 'string', ['default' => null]); $table->addColumn('column2', 'string', ['default' => false]); $table->addColumn('column3', 'string', ['default' => true]); $table->addColumn('column4', 'string', ['default' => 0]); $table->addColumn('column5', 'string', ['default' => '']); $table->addColumn('column6', 'string', ['default' => 'def']); $table->addColumn('column7', 'integer', ['default' => 0]); $table->setPrimaryKey(['id']); $this->schemaManager->dropAndCreateTable($table); $columns = $this->schemaManager->listTableColumns('col_def_lifecycle'); self::assertNull($columns['id']->getDefault()); self::assertNull($columns['column1']->getDefault()); self::assertSame('', $columns['column2']->getDefault()); self::assertSame('1', $columns['column3']->getDefault()); self::assertSame('0', $columns['column4']->getDefault()); self::assertSame('', $columns['column5']->getDefault()); self::assertSame('def', $columns['column6']->getDefault()); self::assertSame('0', $columns['column7']->getDefault()); $diffTable = clone $table; $diffTable->changeColumn('column1', ['default' => false]); $diffTable->changeColumn('column2', ['default' => null]); $diffTable->changeColumn('column3', ['default' => false]); $diffTable->changeColumn('column4', ['default' => null]); $diffTable->changeColumn('column5', ['default' => false]); $diffTable->changeColumn('column6', ['default' => 666]); $diffTable->changeColumn('column7', ['default' => null]); $comparator = new Comparator(); $this->schemaManager->alterTable($comparator->diffTable($table, $diffTable)); $columns = $this->schemaManager->listTableColumns('col_def_lifecycle'); self::assertSame('', $columns['column1']->getDefault()); self::assertNull($columns['column2']->getDefault()); self::assertSame('', $columns['column3']->getDefault()); self::assertNull($columns['column4']->getDefault()); self::assertSame('', $columns['column5']->getDefault()); self::assertSame('666', $columns['column6']->getDefault()); self::assertNull($columns['column7']->getDefault()); } public function testListTableWithBinary() : void { $tableName = 'test_binary_table'; $table = new Table($tableName); $table->addColumn('id', 'integer'); $table->addColumn('column_varbinary', 'binary', []); $table->addColumn('column_binary', 'binary', ['fixed' => true]); $table->setPrimaryKey(['id']); $this->schemaManager->createTable($table); $table = $this->schemaManager->listTableDetails($tableName); self::assertInstanceOf(BinaryType::class, $table->getColumn('column_varbinary')->getType()); self::assertFalse($table->getColumn('column_varbinary')->getFixed()); self::assertInstanceOf(BinaryType::class, $table->getColumn('column_binary')->getType()); self::assertTrue($table->getColumn('column_binary')->getFixed()); } public function testListTableDetailsWithFullQualifiedTableName() : void { if (! $this->schemaManager->getDatabasePlatform()->supportsSchemas()) { $this->markTestSkipped('Test only works on platforms that support schemas.'); } $defaultSchemaName = $this->schemaManager->getDatabasePlatform()->getDefaultSchemaName(); $primaryTableName = 'primary_table'; $foreignTableName = 'foreign_table'; $table = new Table($foreignTableName); $table->addColumn('id', 'integer', ['autoincrement' => true]); $table->setPrimaryKey(['id']); $this->schemaManager->dropAndCreateTable($table); $table = new Table($primaryTableName); $table->addColumn('id', 'integer', ['autoincrement' => true]); $table->addColumn('foo', 'integer'); $table->addColumn('bar', 'string'); $table->addForeignKeyConstraint($foreignTableName, ['foo'], ['id']); $table->addIndex(['bar']); $table->setPrimaryKey(['id']); $this->schemaManager->dropAndCreateTable($table); self::assertEquals( $this->schemaManager->listTableColumns($primaryTableName), $this->schemaManager->listTableColumns($defaultSchemaName . '.' . $primaryTableName) ); self::assertEquals( $this->schemaManager->listTableIndexes($primaryTableName), $this->schemaManager->listTableIndexes($defaultSchemaName . '.' . $primaryTableName) ); self::assertEquals( $this->schemaManager->listTableForeignKeys($primaryTableName), $this->schemaManager->listTableForeignKeys($defaultSchemaName . '.' . $primaryTableName) ); } public function testCommentStringsAreQuoted() : void { if (! $this->connection->getDatabasePlatform()->supportsInlineColumnComments() && ! $this->connection->getDatabasePlatform()->supportsCommentOnStatement() && $this->connection->getDatabasePlatform()->getName() !== 'mssql') { $this->markTestSkipped('Database does not support column comments.'); } $table = new Table('my_table'); $table->addColumn('id', 'integer', ['comment' => "It's a comment with a quote"]); $table->setPrimaryKey(['id']); $this->schemaManager->createTable($table); $columns = $this->schemaManager->listTableColumns('my_table'); self::assertEquals("It's a comment with a quote", $columns['id']->getComment()); } public function testCommentNotDuplicated() : void { if (! $this->connection->getDatabasePlatform()->supportsInlineColumnComments()) { $this->markTestSkipped('Database does not support column comments.'); } $options = [ 'type' => Type::getType('integer'), 'default' => 0, 'notnull' => true, 'comment' => 'expected+column+comment', ]; $columnDefinition = substr($this->connection->getDatabasePlatform()->getColumnDeclarationSQL('id', $options), strlen('id') + 1); $table = new Table('my_table'); $table->addColumn('id', 'integer', ['columnDefinition' => $columnDefinition, 'comment' => 'unexpected_column_comment']); $sql = $this->connection->getDatabasePlatform()->getCreateTableSQL($table); self::assertStringContainsString('expected+column+comment', $sql[0]); self::assertStringNotContainsString('unexpected_column_comment', $sql[0]); } /** * @group DBAL-1009 * @dataProvider getAlterColumnComment */ public function testAlterColumnComment( ?string $comment1, ?string $expectedComment1, ?string $comment2, ?string $expectedComment2 ) : void { if (! $this->connection->getDatabasePlatform()->supportsInlineColumnComments() && ! $this->connection->getDatabasePlatform()->supportsCommentOnStatement() && $this->connection->getDatabasePlatform()->getName() !== 'mssql') { $this->markTestSkipped('Database does not support column comments.'); } $offlineTable = new Table('alter_column_comment_test'); $offlineTable->addColumn('comment1', 'integer', ['comment' => $comment1]); $offlineTable->addColumn('comment2', 'integer', ['comment' => $comment2]); $offlineTable->addColumn('no_comment1', 'integer'); $offlineTable->addColumn('no_comment2', 'integer'); $this->schemaManager->dropAndCreateTable($offlineTable); $onlineTable = $this->schemaManager->listTableDetails('alter_column_comment_test'); self::assertSame($expectedComment1, $onlineTable->getColumn('comment1')->getComment()); self::assertSame($expectedComment2, $onlineTable->getColumn('comment2')->getComment()); self::assertNull($onlineTable->getColumn('no_comment1')->getComment()); self::assertNull($onlineTable->getColumn('no_comment2')->getComment()); $onlineTable->changeColumn('comment1', ['comment' => $comment2]); $onlineTable->changeColumn('comment2', ['comment' => $comment1]); $onlineTable->changeColumn('no_comment1', ['comment' => $comment1]); $onlineTable->changeColumn('no_comment2', ['comment' => $comment2]); $comparator = new Comparator(); $tableDiff = $comparator->diffTable($offlineTable, $onlineTable); self::assertInstanceOf(TableDiff::class, $tableDiff); $this->schemaManager->alterTable($tableDiff); $onlineTable = $this->schemaManager->listTableDetails('alter_column_comment_test'); self::assertSame($expectedComment2, $onlineTable->getColumn('comment1')->getComment()); self::assertSame($expectedComment1, $onlineTable->getColumn('comment2')->getComment()); self::assertSame($expectedComment1, $onlineTable->getColumn('no_comment1')->getComment()); self::assertSame($expectedComment2, $onlineTable->getColumn('no_comment2')->getComment()); } /** * @return mixed[][] */ public static function getAlterColumnComment() : iterable { return [ [null, null, ' ', ' '], [null, null, '0', '0'], [null, null, 'foo', 'foo'], ['', null, ' ', ' '], ['', null, '0', '0'], ['', null, 'foo', 'foo'], [' ', ' ', '0', '0'], [' ', ' ', 'foo', 'foo'], ['0', '0', 'foo', 'foo'], ]; } /** * @group DBAL-1095 */ public function testDoesNotListIndexesImplicitlyCreatedByForeignKeys() : void { if (! $this->schemaManager->getDatabasePlatform()->supportsForeignKeyConstraints()) { $this->markTestSkipped('This test is only supported on platforms that have foreign keys.'); } $primaryTable = new Table('test_list_index_impl_primary'); $primaryTable->addColumn('id', 'integer'); $primaryTable->setPrimaryKey(['id']); $foreignTable = new Table('test_list_index_impl_foreign'); $foreignTable->addColumn('fk1', 'integer'); $foreignTable->addColumn('fk2', 'integer'); $foreignTable->addIndex(['fk1'], 'explicit_fk1_idx'); $foreignTable->addForeignKeyConstraint('test_list_index_impl_primary', ['fk1'], ['id']); $foreignTable->addForeignKeyConstraint('test_list_index_impl_primary', ['fk2'], ['id']); $this->schemaManager->dropAndCreateTable($primaryTable); $this->schemaManager->dropAndCreateTable($foreignTable); $indexes = $this->schemaManager->listTableIndexes('test_list_index_impl_foreign'); self::assertCount(2, $indexes); self::assertArrayHasKey('explicit_fk1_idx', $indexes); self::assertArrayHasKey('idx_3d6c147fdc58d6c', $indexes); } /** * @after */ public function removeJsonArrayTable() : void { if (! $this->schemaManager->tablesExist(['json_array_test'])) { return; } $this->schemaManager->dropTable('json_array_test'); } /** * @group 2782 * @group 6654 */ public function testComparatorShouldReturnFalseWhenLegacyJsonArrayColumnHasComment() : void { $table = new Table('json_array_test'); $table->addColumn('parameters', 'json_array'); $this->schemaManager->createTable($table); $comparator = new Comparator(); $tableDiff = $comparator->diffTable($this->schemaManager->listTableDetails('json_array_test'), $table); self::assertFalse($tableDiff); } /** * @group 2782 * @group 6654 */ public function testComparatorShouldModifyOnlyTheCommentWhenUpdatingFromJsonArrayTypeOnLegacyPlatforms() : void { if ($this->schemaManager->getDatabasePlatform()->hasNativeJsonType()) { $this->markTestSkipped('This test is only supported on platforms that do not have native JSON type.'); } $table = new Table('json_array_test'); $table->addColumn('parameters', 'json_array'); $this->schemaManager->createTable($table); $table = new Table('json_array_test'); $table->addColumn('parameters', 'json'); $comparator = new Comparator(); $tableDiff = $comparator->diffTable($this->schemaManager->listTableDetails('json_array_test'), $table); self::assertInstanceOf(TableDiff::class, $tableDiff); $changedColumn = $tableDiff->changedColumns['parameters'] ?? $tableDiff->changedColumns['PARAMETERS']; self::assertSame(['comment'], $changedColumn->changedProperties); } /** * @group 2782 * @group 6654 */ public function testComparatorShouldAddCommentToLegacyJsonArrayTypeThatDoesNotHaveIt() : void { if (! $this->schemaManager->getDatabasePlatform()->hasNativeJsonType()) { $this->markTestSkipped('This test is only supported on platforms that have native JSON type.'); } $this->connection->executeQuery('CREATE TABLE json_array_test (parameters JSON NOT NULL)'); $table = new Table('json_array_test'); $table->addColumn('parameters', 'json_array'); $comparator = new Comparator(); $tableDiff = $comparator->diffTable($this->schemaManager->listTableDetails('json_array_test'), $table); self::assertInstanceOf(TableDiff::class, $tableDiff); self::assertSame(['comment'], $tableDiff->changedColumns['parameters']->changedProperties); } /** * @group 2782 * @group 6654 */ public function testComparatorShouldReturnAllChangesWhenUsingLegacyJsonArrayType() : void { if (! $this->schemaManager->getDatabasePlatform()->hasNativeJsonType()) { $this->markTestSkipped('This test is only supported on platforms that have native JSON type.'); } $this->connection->executeQuery('CREATE TABLE json_array_test (parameters JSON DEFAULT NULL)'); $table = new Table('json_array_test'); $table->addColumn('parameters', 'json_array'); $comparator = new Comparator(); $tableDiff = $comparator->diffTable($this->schemaManager->listTableDetails('json_array_test'), $table); self::assertInstanceOf(TableDiff::class, $tableDiff); self::assertSame(['notnull', 'comment'], $tableDiff->changedColumns['parameters']->changedProperties); } /** * @group 2782 * @group 6654 */ public function testComparatorShouldReturnAllChangesWhenUsingLegacyJsonArrayTypeEvenWhenPlatformHasJsonSupport() : void { if (! $this->schemaManager->getDatabasePlatform()->hasNativeJsonType()) { $this->markTestSkipped('This test is only supported on platforms that have native JSON type.'); } $this->connection->executeQuery('CREATE TABLE json_array_test (parameters JSON DEFAULT NULL)'); $table = new Table('json_array_test'); $table->addColumn('parameters', 'json_array'); $comparator = new Comparator(); $tableDiff = $comparator->diffTable($this->schemaManager->listTableDetails('json_array_test'), $table); self::assertInstanceOf(TableDiff::class, $tableDiff); self::assertSame(['notnull', 'comment'], $tableDiff->changedColumns['parameters']->changedProperties); } /** * @group 2782 * @group 6654 */ public function testComparatorShouldNotAddCommentToJsonTypeSinceItIsTheDefaultNow() : void { if (! $this->schemaManager->getDatabasePlatform()->hasNativeJsonType()) { $this->markTestSkipped('This test is only supported on platforms that have native JSON type.'); } $this->connection->executeQuery('CREATE TABLE json_test (parameters JSON NOT NULL)'); $table = new Table('json_test'); $table->addColumn('parameters', 'json'); $comparator = new Comparator(); $tableDiff = $comparator->diffTable($this->schemaManager->listTableDetails('json_test'), $table); self::assertFalse($tableDiff); } /** * @dataProvider commentsProvider * @group 2596 */ public function testExtractDoctrineTypeFromComment(string $comment, string $expected, string $currentType) : void { $result = $this->schemaManager->extractDoctrineTypeFromComment($comment, $currentType); self::assertSame($expected, $result); } /** * @return string[][] */ public function commentsProvider() : array { $currentType = 'current type'; return [ 'invalid custom type comments' => ['should.return.current.type', $currentType, $currentType], 'valid doctrine type' => ['(DC2Type:guid)', 'guid', $currentType], 'valid with dots' => ['(DC2Type:type.should.return)', 'type.should.return', $currentType], 'valid with namespace' => ['(DC2Type:Namespace\Class)', 'Namespace\Class', $currentType], 'valid with extra closing bracket' => ['(DC2Type:should.stop)).before)', 'should.stop', $currentType], 'valid with extra opening brackets' => ['(DC2Type:should((.stop)).before)', 'should((.stop', $currentType], ]; } public function testCreateAndListSequences() : void { if (! $this->schemaManager->getDatabasePlatform()->supportsSequences()) { self::markTestSkipped('This test is only supported on platforms that support sequences.'); } $sequence1Name = 'sequence_1'; $sequence1AllocationSize = 1; $sequence1InitialValue = 2; $sequence2Name = 'sequence_2'; $sequence2AllocationSize = 3; $sequence2InitialValue = 4; $sequence1 = new Sequence($sequence1Name, $sequence1AllocationSize, $sequence1InitialValue); $sequence2 = new Sequence($sequence2Name, $sequence2AllocationSize, $sequence2InitialValue); $this->schemaManager->createSequence($sequence1); $this->schemaManager->createSequence($sequence2); /** @var Sequence[] $actualSequences */ $actualSequences = []; foreach ($this->schemaManager->listSequences() as $sequence) { $actualSequences[$sequence->getName()] = $sequence; } $actualSequence1 = $actualSequences[$sequence1Name]; $actualSequence2 = $actualSequences[$sequence2Name]; self::assertSame($sequence1Name, $actualSequence1->getName()); self::assertEquals($sequence1AllocationSize, $actualSequence1->getAllocationSize()); self::assertEquals($sequence1InitialValue, $actualSequence1->getInitialValue()); self::assertSame($sequence2Name, $actualSequence2->getName()); self::assertEquals($sequence2AllocationSize, $actualSequence2->getAllocationSize()); self::assertEquals($sequence2InitialValue, $actualSequence2->getInitialValue()); } /** * @group #3086 */ public function testComparisonWithAutoDetectedSequenceDefinition() : void { if (! $this->schemaManager->getDatabasePlatform()->supportsSequences()) { self::markTestSkipped('This test is only supported on platforms that support sequences.'); } $sequenceName = 'sequence_auto_detect_test'; $sequenceAllocationSize = 5; $sequenceInitialValue = 10; $sequence = new Sequence($sequenceName, $sequenceAllocationSize, $sequenceInitialValue); $this->schemaManager->dropAndCreateSequence($sequence); $createdSequence = array_values( array_filter( $this->schemaManager->listSequences(), static function (Sequence $sequence) use ($sequenceName) : bool { return strcasecmp($sequence->getName(), $sequenceName) === 0; } ) )[0] ?? null; self::assertNotNull($createdSequence); $comparator = new Comparator(); $tableDiff = $comparator->diffSequence($createdSequence, $sequence); self::assertFalse($tableDiff); } /** * @group DBAL-2921 */ public function testPrimaryKeyAutoIncrement() : void { $table = new Table('test_pk_auto_increment'); $table->addColumn('id', 'integer', ['autoincrement' => true]); $table->addColumn('text', 'string'); $table->setPrimaryKey(['id']); $this->schemaManager->dropAndCreateTable($table); $this->connection->insert('test_pk_auto_increment', ['text' => '1']); $query = $this->connection->query('SELECT id FROM test_pk_auto_increment WHERE text = \'1\''); $query->execute(); $lastUsedIdBeforeDelete = (int) $query->fetchColumn(); $this->connection->query('DELETE FROM test_pk_auto_increment'); $this->connection->insert('test_pk_auto_increment', ['text' => '2']); $query = $this->connection->query('SELECT id FROM test_pk_auto_increment WHERE text = \'2\''); $query->execute(); $lastUsedIdAfterDelete = (int) $query->fetchColumn(); $this->assertGreaterThan($lastUsedIdBeforeDelete, $lastUsedIdAfterDelete); } public function testGenerateAnIndexWithPartialColumnLength() : void { if (! $this->schemaManager->getDatabasePlatform()->supportsColumnLengthIndexes()) { self::markTestSkipped('This test is only supported on platforms that support indexes with column length definitions.'); } $table = new Table('test_partial_column_index'); $table->addColumn('long_column', 'string', ['length' => 40]); $table->addColumn('standard_column', 'integer'); $table->addIndex(['long_column'], 'partial_long_column_idx', [], ['lengths' => [4]]); $table->addIndex(['standard_column', 'long_column'], 'standard_and_partial_idx', [], ['lengths' => [null, 2]]); $expected = $table->getIndexes(); $this->schemaManager->dropAndCreateTable($table); $onlineTable = $this->schemaManager->listTableDetails('test_partial_column_index'); self::assertEquals($expected, $onlineTable->getIndexes()); } public function testCommentInTable() : void { $table = new Table('table_with_comment'); $table->addColumn('id', 'integer'); $table->setComment('Foo with control characters \'\\'); $this->schemaManager->dropAndCreateTable($table); $table = $this->schemaManager->listTableDetails('table_with_comment'); self::assertSame('Foo with control characters \'\\', $table->getComment()); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Schema/SqliteSchemaManagerTest.php000066400000000000000000000223211360544566000323450ustar00rootroot00000000000000expectException(DBALException::class); $this->schemaManager->listDatabases(); } public function testCreateAndDropDatabase() : void { $path = dirname(__FILE__) . '/test_create_and_drop_sqlite_database.sqlite'; $this->schemaManager->createDatabase($path); self::assertFileExists($path); $this->schemaManager->dropDatabase($path); self::assertFileNotExists($path); } /** * @group DBAL-1220 */ public function testDropsDatabaseWithActiveConnections() : void { $this->schemaManager->dropAndCreateDatabase('test_drop_database'); self::assertFileExists('test_drop_database'); $params = $this->connection->getParams(); $params['dbname'] = 'test_drop_database'; $user = $params['user'] ?? null; $password = $params['password'] ?? null; $connection = $this->connection->getDriver()->connect($params, $user, $password); self::assertInstanceOf(Connection::class, $connection); $this->schemaManager->dropDatabase('test_drop_database'); self::assertFileNotExists('test_drop_database'); unset($connection); } public function testRenameTable() : void { $this->createTestTable('oldname'); $this->schemaManager->renameTable('oldname', 'newname'); $tables = $this->schemaManager->listTableNames(); self::assertContains('newname', $tables); self::assertNotContains('oldname', $tables); } public function createListTableColumns() : Table { $table = parent::createListTableColumns(); $table->getColumn('id')->setAutoincrement(true); return $table; } public function testListForeignKeysFromExistingDatabase() : void { $this->connection->exec(<< 'SET NULL', 'onDelete' => 'NO ACTION', 'deferrable' => false, 'deferred' => false] ), new Schema\ForeignKeyConstraint( ['parent'], 'user', ['id'], '1', ['onUpdate' => 'NO ACTION', 'onDelete' => 'CASCADE', 'deferrable' => false, 'deferred' => false] ), new Schema\ForeignKeyConstraint( ['page'], 'page', ['key'], 'FK_1', ['onUpdate' => 'NO ACTION', 'onDelete' => 'NO ACTION', 'deferrable' => true, 'deferred' => true] ), ]; self::assertEquals($expected, $this->schemaManager->listTableForeignKeys('user')); } public function testColumnCollation() : void { $table = new Schema\Table('test_collation'); $table->addColumn('id', 'integer'); $table->addColumn('text', 'text'); $table->addColumn('foo', 'text')->setPlatformOption('collation', 'BINARY'); $table->addColumn('bar', 'text')->setPlatformOption('collation', 'NOCASE'); $this->schemaManager->dropAndCreateTable($table); $columns = $this->schemaManager->listTableColumns('test_collation'); self::assertArrayNotHasKey('collation', $columns['id']->getPlatformOptions()); self::assertEquals('BINARY', $columns['text']->getPlatformOption('collation')); self::assertEquals('BINARY', $columns['foo']->getPlatformOption('collation')); self::assertEquals('NOCASE', $columns['bar']->getPlatformOption('collation')); } public function testListTableWithBinary() : void { $tableName = 'test_binary_table'; $table = new Table($tableName); $table->addColumn('id', 'integer'); $table->addColumn('column_varbinary', 'binary', []); $table->addColumn('column_binary', 'binary', ['fixed' => true]); $table->setPrimaryKey(['id']); $this->schemaManager->createTable($table); $table = $this->schemaManager->listTableDetails($tableName); self::assertInstanceOf(BlobType::class, $table->getColumn('column_varbinary')->getType()); self::assertFalse($table->getColumn('column_varbinary')->getFixed()); self::assertInstanceOf(BlobType::class, $table->getColumn('column_binary')->getType()); self::assertFalse($table->getColumn('column_binary')->getFixed()); } public function testNonDefaultPKOrder() : void { if (! extension_loaded('sqlite3')) { $this->markTestSkipped('This test requires the SQLite3 extension.'); } $version = SQLite3::version(); if (version_compare($version['versionString'], '3.7.16', '<')) { $this->markTestSkipped('This version of sqlite doesn\'t return the order of the Primary Key.'); } $this->connection->exec(<<schemaManager->listTableIndexes('non_default_pk_order'); self::assertCount(1, $tableIndexes); self::assertArrayHasKey('primary', $tableIndexes, 'listTableIndexes() has to return a "primary" array key.'); self::assertEquals(['other_id', 'id'], array_map('strtolower', $tableIndexes['primary']->getColumns())); } /** * @group DBAL-1779 */ public function testListTableColumnsWithWhitespacesInTypeDeclarations() : void { $sql = <<connection->exec($sql); $columns = $this->schemaManager->listTableColumns('dbal_1779'); self::assertCount(2, $columns); self::assertArrayHasKey('foo', $columns); self::assertArrayHasKey('bar', $columns); self::assertSame(Type::getType(Types::STRING), $columns['foo']->getType()); self::assertSame(Type::getType(Types::TEXT), $columns['bar']->getType()); self::assertSame(64, $columns['foo']->getLength()); self::assertSame(100, $columns['bar']->getLength()); } /** * @dataProvider getDiffListIntegerAutoincrementTableColumnsData * @group DBAL-924 */ public function testDiffListIntegerAutoincrementTableColumns(string $integerType, bool $unsigned, bool $expectedComparatorDiff) : void { $tableName = 'test_int_autoincrement_table'; $offlineTable = new Table($tableName); $offlineTable->addColumn('id', $integerType, ['autoincrement' => true, 'unsigned' => $unsigned]); $offlineTable->setPrimaryKey(['id']); $this->schemaManager->dropAndCreateTable($offlineTable); $onlineTable = $this->schemaManager->listTableDetails($tableName); $comparator = new Schema\Comparator(); $diff = $comparator->diffTable($offlineTable, $onlineTable); if ($expectedComparatorDiff) { self::assertEmpty($this->schemaManager->getDatabasePlatform()->getAlterTableSQL($diff)); } else { self::assertFalse($diff); } } /** * @return mixed[][] */ public static function getDiffListIntegerAutoincrementTableColumnsData() : iterable { return [ ['smallint', false, true], ['smallint', true, true], ['integer', false, false], ['integer', true, true], ['bigint', false, true], ['bigint', true, true], ]; } /** * @group DBAL-2921 */ public function testPrimaryKeyNoAutoIncrement() : void { $table = new Schema\Table('test_pk_auto_increment'); $table->addColumn('id', 'integer'); $table->addColumn('text', 'text'); $table->setPrimaryKey(['id']); $this->schemaManager->dropAndCreateTable($table); $this->connection->insert('test_pk_auto_increment', ['text' => '1']); $this->connection->query('DELETE FROM test_pk_auto_increment'); $this->connection->insert('test_pk_auto_increment', ['text' => '2']); $query = $this->connection->query('SELECT id FROM test_pk_auto_increment WHERE text = "2"'); $query->execute(); $lastUsedIdAfterDelete = (int) $query->fetchColumn(); // with an empty table, non autoincrement rowid is always 1 $this->assertEquals(1, $lastUsedIdAfterDelete); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/StatementTest.php000066400000000000000000000245371360544566000272470ustar00rootroot00000000000000addColumn('id', 'integer'); $table->addColumn('name', 'text', ['notnull' => false]); $this->connection->getSchemaManager()->dropAndCreateTable($table); } public function testStatementIsReusableAfterClosingCursor() : void { if ($this->connection->getDriver() instanceof PDOOracleDriver) { $this->markTestIncomplete('See https://bugs.php.net/bug.php?id=77181'); } $this->connection->insert('stmt_test', ['id' => 1]); $this->connection->insert('stmt_test', ['id' => 2]); $stmt = $this->connection->prepare('SELECT id FROM stmt_test ORDER BY id'); $stmt->execute(); $id = $stmt->fetchColumn(); self::assertEquals(1, $id); $stmt->closeCursor(); $stmt->execute(); $id = $stmt->fetchColumn(); self::assertEquals(1, $id); $id = $stmt->fetchColumn(); self::assertEquals(2, $id); } public function testReuseStatementWithLongerResults() : void { if ($this->connection->getDriver() instanceof PDOOracleDriver) { $this->markTestIncomplete('PDO_OCI doesn\'t support fetching blobs via PDOStatement::fetchAll()'); } $sm = $this->connection->getSchemaManager(); $table = new Table('stmt_longer_results'); $table->addColumn('param', 'string'); $table->addColumn('val', 'text'); $sm->createTable($table); $row1 = [ 'param' => 'param1', 'val' => 'X', ]; $this->connection->insert('stmt_longer_results', $row1); $stmt = $this->connection->prepare('SELECT param, val FROM stmt_longer_results ORDER BY param'); $stmt->execute(); self::assertEquals([ ['param1', 'X'], ], $stmt->fetchAll(FetchMode::NUMERIC)); $row2 = [ 'param' => 'param2', 'val' => 'A bit longer value', ]; $this->connection->insert('stmt_longer_results', $row2); $stmt->execute(); self::assertEquals([ ['param1', 'X'], ['param2', 'A bit longer value'], ], $stmt->fetchAll(FetchMode::NUMERIC)); } public function testFetchLongBlob() : void { if ($this->connection->getDriver() instanceof PDOOracleDriver) { // inserting BLOBs as streams on Oracle requires Oracle-specific SQL syntax which is currently not supported // see http://php.net/manual/en/pdo.lobs.php#example-1035 $this->markTestSkipped('DBAL doesn\'t support storing LOBs represented as streams using PDO_OCI'); } // make sure memory limit is large enough to not cause false positives, // but is still not enough to store a LONGBLOB of the max possible size $this->iniSet('memory_limit', '4G'); $sm = $this->connection->getSchemaManager(); $table = new Table('stmt_long_blob'); $table->addColumn('contents', 'blob', ['length' => 0xFFFFFFFF]); $sm->createTable($table); $contents = base64_decode(<<connection->insert('stmt_long_blob', ['contents' => $contents], [ParameterType::LARGE_OBJECT]); $stmt = $this->connection->prepare('SELECT contents FROM stmt_long_blob'); $stmt->execute(); $stream = Type::getType('blob') ->convertToPHPValue( $stmt->fetchColumn(), $this->connection->getDatabasePlatform() ); self::assertSame($contents, stream_get_contents($stream)); } public function testIncompletelyFetchedStatementDoesNotBlockConnection() : void { $this->connection->insert('stmt_test', ['id' => 1]); $this->connection->insert('stmt_test', ['id' => 2]); $stmt1 = $this->connection->prepare('SELECT id FROM stmt_test'); $stmt1->execute(); $stmt1->fetch(); $stmt1->execute(); // fetching only one record out of two $stmt1->fetch(); $stmt2 = $this->connection->prepare('SELECT id FROM stmt_test WHERE id = ?'); $stmt2->execute([1]); self::assertEquals(1, $stmt2->fetchColumn()); } public function testReuseStatementAfterClosingCursor() : void { if ($this->connection->getDriver() instanceof PDOOracleDriver) { $this->markTestIncomplete('See https://bugs.php.net/bug.php?id=77181'); } $this->connection->insert('stmt_test', ['id' => 1]); $this->connection->insert('stmt_test', ['id' => 2]); $stmt = $this->connection->prepare('SELECT id FROM stmt_test WHERE id = ?'); $stmt->execute([1]); $id = $stmt->fetchColumn(); self::assertEquals(1, $id); $stmt->closeCursor(); $stmt->execute([2]); $id = $stmt->fetchColumn(); self::assertEquals(2, $id); } public function testReuseStatementWithParameterBoundByReference() : void { $this->connection->insert('stmt_test', ['id' => 1]); $this->connection->insert('stmt_test', ['id' => 2]); $stmt = $this->connection->prepare('SELECT id FROM stmt_test WHERE id = ?'); $stmt->bindParam(1, $id); $id = 1; $stmt->execute(); self::assertEquals(1, $stmt->fetchColumn()); $id = 2; $stmt->execute(); self::assertEquals(2, $stmt->fetchColumn()); } public function testReuseStatementWithReboundValue() : void { $this->connection->insert('stmt_test', ['id' => 1]); $this->connection->insert('stmt_test', ['id' => 2]); $stmt = $this->connection->prepare('SELECT id FROM stmt_test WHERE id = ?'); $stmt->bindValue(1, 1); $stmt->execute(); self::assertEquals(1, $stmt->fetchColumn()); $stmt->bindValue(1, 2); $stmt->execute(); self::assertEquals(2, $stmt->fetchColumn()); } public function testReuseStatementWithReboundParam() : void { $this->connection->insert('stmt_test', ['id' => 1]); $this->connection->insert('stmt_test', ['id' => 2]); $stmt = $this->connection->prepare('SELECT id FROM stmt_test WHERE id = ?'); $x = 1; $stmt->bindParam(1, $x); $stmt->execute(); self::assertEquals(1, $stmt->fetchColumn()); $y = 2; $stmt->bindParam(1, $y); $stmt->execute(); self::assertEquals(2, $stmt->fetchColumn()); } /** * @param mixed $expected * * @dataProvider emptyFetchProvider */ public function testFetchFromNonExecutedStatement(callable $fetch, $expected) : void { $stmt = $this->connection->prepare('SELECT id FROM stmt_test'); self::assertSame($expected, $fetch($stmt)); } public function testCloseCursorOnNonExecutedStatement() : void { $stmt = $this->connection->prepare('SELECT id FROM stmt_test'); self::assertTrue($stmt->closeCursor()); } /** * @group DBAL-2637 */ public function testCloseCursorAfterCursorEnd() : void { $stmt = $this->connection->prepare('SELECT name FROM stmt_test'); $stmt->execute(); $stmt->fetch(); self::assertTrue($stmt->closeCursor()); } /** * @param mixed $expected * * @dataProvider emptyFetchProvider */ public function testFetchFromNonExecutedStatementWithClosedCursor(callable $fetch, $expected) : void { $stmt = $this->connection->prepare('SELECT id FROM stmt_test'); $stmt->closeCursor(); self::assertSame($expected, $fetch($stmt)); } /** * @param mixed $expected * * @dataProvider emptyFetchProvider */ public function testFetchFromExecutedStatementWithClosedCursor(callable $fetch, $expected) : void { $this->connection->insert('stmt_test', ['id' => 1]); $stmt = $this->connection->prepare('SELECT id FROM stmt_test'); $stmt->execute(); $stmt->closeCursor(); self::assertSame($expected, $fetch($stmt)); } /** * @return mixed[][] */ public static function emptyFetchProvider() : iterable { return [ 'fetch' => [ static function (Statement $stmt) { return $stmt->fetch(); }, false, ], 'fetch-column' => [ static function (Statement $stmt) { return $stmt->fetchColumn(); }, false, ], 'fetch-all' => [ static function (Statement $stmt) { return $stmt->fetchAll(); }, [], ], ]; } public function testFetchInColumnMode() : void { $platform = $this->connection->getDatabasePlatform(); $query = $platform->getDummySelectSQL(); $result = $this->connection->executeQuery($query)->fetch(FetchMode::COLUMN); self::assertEquals(1, $result); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/TableGeneratorTest.php000066400000000000000000000036071360544566000301740ustar00rootroot00000000000000connection->getDatabasePlatform(); if ($platform->getName() === 'sqlite') { $this->markTestSkipped('TableGenerator does not work with SQLite'); } try { $schema = new Schema(); $visitor = new TableGeneratorSchemaVisitor(); $schema->visit($visitor); foreach ($schema->toSql($platform) as $sql) { $this->connection->exec($sql); } } catch (Throwable $e) { } $this->generator = new TableGenerator($this->connection); } public function testNextVal() : void { $id1 = $this->generator->nextValue('tbl1'); $id2 = $this->generator->nextValue('tbl1'); $id3 = $this->generator->nextValue('tbl2'); self::assertGreaterThan(0, $id1, 'First id has to be larger than 0'); self::assertEquals($id1 + 1, $id2, 'Second id is one larger than first one.'); self::assertEquals($id1, $id3, 'First ids from different tables are equal.'); } public function testNextValNotAffectedByOuterTransactions() : void { $this->connection->beginTransaction(); $id1 = $this->generator->nextValue('tbl1'); $this->connection->rollBack(); $id2 = $this->generator->nextValue('tbl1'); self::assertGreaterThan(0, $id1, 'First id has to be larger than 0'); self::assertEquals($id1 + 1, $id2, 'Second id is one larger than first one.'); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/TemporaryTableTest.php000066400000000000000000000100251360544566000302200ustar00rootroot00000000000000connection->exec($this->connection->getDatabasePlatform()->getDropTableSQL('nontemporary')); } catch (Throwable $e) { } } protected function tearDown() : void { if ($this->connection) { try { $tempTable = $this->connection->getDatabasePlatform()->getTemporaryTableName('my_temporary'); $this->connection->exec($this->connection->getDatabasePlatform()->getDropTemporaryTableSQL($tempTable)); } catch (Throwable $e) { } } parent::tearDown(); } /** * @group DDC-1337 */ public function testDropTemporaryTableNotAutoCommitTransaction() : void { if ($this->connection->getDatabasePlatform()->getName() === 'sqlanywhere' || $this->connection->getDatabasePlatform()->getName() === 'oracle') { $this->markTestSkipped('Test does not work on Oracle and SQL Anywhere.'); } $platform = $this->connection->getDatabasePlatform(); $columnDefinitions = ['id' => ['type' => Type::getType('integer'), 'notnull' => true]]; $tempTable = $platform->getTemporaryTableName('my_temporary'); $createTempTableSQL = $platform->getCreateTemporaryTableSnippetSQL() . ' ' . $tempTable . ' (' . $platform->getColumnDeclarationListSQL($columnDefinitions) . ')'; $this->connection->executeUpdate($createTempTableSQL); $table = new Table('nontemporary'); $table->addColumn('id', 'integer'); $table->setPrimaryKey(['id']); $this->connection->getSchemaManager()->createTable($table); $this->connection->beginTransaction(); $this->connection->insert('nontemporary', ['id' => 1]); $this->connection->exec($platform->getDropTemporaryTableSQL($tempTable)); $this->connection->insert('nontemporary', ['id' => 2]); $this->connection->rollBack(); $rows = $this->connection->fetchAll('SELECT * FROM nontemporary'); self::assertEquals([], $rows, 'In an event of an error this result has one row, because of an implicit commit.'); } /** * @group DDC-1337 */ public function testCreateTemporaryTableNotAutoCommitTransaction() : void { if ($this->connection->getDatabasePlatform()->getName() === 'sqlanywhere' || $this->connection->getDatabasePlatform()->getName() === 'oracle') { $this->markTestSkipped('Test does not work on Oracle and SQL Anywhere.'); } $platform = $this->connection->getDatabasePlatform(); $columnDefinitions = ['id' => ['type' => Type::getType('integer'), 'notnull' => true]]; $tempTable = $platform->getTemporaryTableName('my_temporary'); $createTempTableSQL = $platform->getCreateTemporaryTableSnippetSQL() . ' ' . $tempTable . ' (' . $platform->getColumnDeclarationListSQL($columnDefinitions) . ')'; $table = new Table('nontemporary'); $table->addColumn('id', 'integer'); $table->setPrimaryKey(['id']); $this->connection->getSchemaManager()->createTable($table); $this->connection->beginTransaction(); $this->connection->insert('nontemporary', ['id' => 1]); $this->connection->exec($createTempTableSQL); $this->connection->insert('nontemporary', ['id' => 2]); $this->connection->rollBack(); try { $this->connection->exec($platform->getDropTemporaryTableSQL($tempTable)); } catch (Throwable $e) { } $rows = $this->connection->fetchAll('SELECT * FROM nontemporary'); self::assertEquals([], $rows, 'In an event of an error this result has one row, because of an implicit commit.'); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Ticket/000077500000000000000000000000001360544566000251425ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL168Test.php000066400000000000000000000015671360544566000274650ustar00rootroot00000000000000connection->getDatabasePlatform()->getName() !== 'postgresql') { $this->markTestSkipped('PostgreSQL only test'); } $table = new Table('domains'); $table->addColumn('id', 'integer'); $table->addColumn('parent_id', 'integer'); $table->setPrimaryKey(['id']); $table->addForeignKeyConstraint('domains', ['parent_id'], ['id']); $this->connection->getSchemaManager()->createTable($table); $table = $this->connection->getSchemaManager()->listTableDetails('domains'); self::assertEquals('domains', $table->getName()); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL202Test.php000066400000000000000000000027571360544566000274540ustar00rootroot00000000000000connection->getDatabasePlatform()->getName() !== 'oracle') { $this->markTestSkipped('OCI8 only test'); } if ($this->connection->getSchemaManager()->tablesExist('DBAL202')) { $this->connection->exec('DELETE FROM DBAL202'); } else { $table = new Table('DBAL202'); $table->addColumn('id', 'integer'); $table->setPrimaryKey(['id']); $this->connection->getSchemaManager()->createTable($table); } } public function testStatementRollback() : void { $stmt = $this->connection->prepare('INSERT INTO DBAL202 VALUES (8)'); $this->connection->beginTransaction(); $stmt->execute(); $this->connection->rollBack(); self::assertEquals(0, $this->connection->query('SELECT COUNT(1) FROM DBAL202')->fetchColumn()); } public function testStatementCommit() : void { $stmt = $this->connection->prepare('INSERT INTO DBAL202 VALUES (8)'); $this->connection->beginTransaction(); $stmt->execute(); $this->connection->commit(); self::assertEquals(1, $this->connection->query('SELECT COUNT(1) FROM DBAL202')->fetchColumn()); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL421Test.php000066400000000000000000000031421360544566000274440ustar00rootroot00000000000000connection->getDatabasePlatform()->getName(); if (in_array($platform, ['mysql', 'sqlite'])) { return; } $this->markTestSkipped('Currently restricted to MySQL and SQLite.'); } public function testGuidShouldMatchPattern() : void { $guid = $this->connection->query($this->getSelectGuidSql())->fetchColumn(); $pattern = '/[0-9A-F]{8}\-[0-9A-F]{4}\-[0-9A-F]{4}\-[8-9A-B][0-9A-F]{3}\-[0-9A-F]{12}/i'; self::assertEquals(1, preg_match($pattern, $guid), 'GUID does not match pattern'); } /** * This test does (of course) not proof that all generated GUIDs are * random, it should however provide some basic confidence. */ public function testGuidShouldBeRandom() : void { $statement = $this->connection->prepare($this->getSelectGuidSql()); $guids = []; for ($i = 0; $i < 99; $i++) { $statement->execute(); $guid = $statement->fetchColumn(); self::assertNotContains($guid, $guids, 'Duplicate GUID detected'); $guids[] = $guid; } $statement->closeCursor(); } private function getSelectGuidSql() : string { return 'SELECT ' . $this->connection->getDatabasePlatform()->getGuidExpression(); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL461Test.php000066400000000000000000000023541360544566000274540ustar00rootroot00000000000000createMock(Connection::class); $platform = $this->getMockForAbstractClass(AbstractPlatform::class); $platform->registerDoctrineTypeMapping('numeric', 'decimal'); $schemaManager = new SQLServerSchemaManager($conn, $platform); $reflectionMethod = new ReflectionMethod($schemaManager, '_getPortableTableColumnDefinition'); $reflectionMethod->setAccessible(true); $column = $reflectionMethod->invoke($schemaManager, [ 'type' => 'numeric(18,0)', 'length' => null, 'default' => null, 'notnull' => false, 'scale' => 18, 'precision' => 0, 'autoincrement' => false, 'collation' => 'foo', 'comment' => null, ]); $this->assertInstanceOf(DecimalType::class, $column->getType()); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL510Test.php000066400000000000000000000017501360544566000274460ustar00rootroot00000000000000connection->getDatabasePlatform()->getName() === 'postgresql') { return; } $this->markTestSkipped('PostgreSQL Only test'); } public function testSearchPathSchemaChanges() : void { $table = new Table('dbal510tbl'); $table->addColumn('id', 'integer'); $table->setPrimaryKey(['id']); $this->connection->getSchemaManager()->createTable($table); $onlineTable = $this->connection->getSchemaManager()->listTableDetails('dbal510tbl'); $comparator = new Comparator(); $diff = $comparator->diffTable($onlineTable, $table); self::assertFalse($diff); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL630Test.php000066400000000000000000000124471360544566000274560ustar00rootroot00000000000000connection->getDatabasePlatform()->getName(); if (! in_array($platform, ['postgresql'])) { $this->markTestSkipped('Currently restricted to PostgreSQL'); } try { $this->connection->exec('CREATE TABLE dbal630 (id SERIAL, bool_col BOOLEAN NOT NULL);'); $this->connection->exec('CREATE TABLE dbal630_allow_nulls (id SERIAL, bool_col BOOLEAN);'); } catch (DBALException $e) { } $this->running = true; } protected function tearDown() : void { if ($this->running) { $this->connection->getWrappedConnection()->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); } parent::tearDown(); } public function testBooleanConversionSqlLiteral() : void { $this->connection->executeUpdate('INSERT INTO dbal630 (bool_col) VALUES(false)'); $id = $this->connection->lastInsertId('dbal630_id_seq'); self::assertNotEmpty($id); $row = $this->connection->fetchAssoc('SELECT bool_col FROM dbal630 WHERE id = ?', [$id]); self::assertFalse($row['bool_col']); } public function testBooleanConversionBoolParamRealPrepares() : void { $this->connection->executeUpdate( 'INSERT INTO dbal630 (bool_col) VALUES(?)', ['false'], [ParameterType::BOOLEAN] ); $id = $this->connection->lastInsertId('dbal630_id_seq'); self::assertNotEmpty($id); $row = $this->connection->fetchAssoc('SELECT bool_col FROM dbal630 WHERE id = ?', [$id]); self::assertFalse($row['bool_col']); } public function testBooleanConversionBoolParamEmulatedPrepares() : void { $this->connection->getWrappedConnection()->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); $platform = $this->connection->getDatabasePlatform(); $stmt = $this->connection->prepare('INSERT INTO dbal630 (bool_col) VALUES(?)'); $stmt->bindValue(1, $platform->convertBooleansToDatabaseValue('false'), ParameterType::BOOLEAN); $stmt->execute(); $id = $this->connection->lastInsertId('dbal630_id_seq'); self::assertNotEmpty($id); $row = $this->connection->fetchAssoc('SELECT bool_col FROM dbal630 WHERE id = ?', [$id]); self::assertFalse($row['bool_col']); } /** * @dataProvider booleanTypeConversionWithoutPdoTypeProvider */ public function testBooleanConversionNullParamEmulatedPrepares( ?bool $statementValue, ?bool $databaseConvertedValue ) : void { $this->connection->getWrappedConnection()->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); $platform = $this->connection->getDatabasePlatform(); $stmt = $this->connection->prepare('INSERT INTO dbal630_allow_nulls (bool_col) VALUES(?)'); $stmt->bindValue(1, $platform->convertBooleansToDatabaseValue($statementValue)); $stmt->execute(); $id = $this->connection->lastInsertId('dbal630_allow_nulls_id_seq'); self::assertNotEmpty($id); $row = $this->connection->fetchAssoc('SELECT bool_col FROM dbal630_allow_nulls WHERE id = ?', [$id]); self::assertSame($databaseConvertedValue, $row['bool_col']); } /** * @dataProvider booleanTypeConversionUsingBooleanTypeProvider */ public function testBooleanConversionNullParamEmulatedPreparesWithBooleanTypeInBindValue( ?bool $statementValue, bool $databaseConvertedValue ) : void { $this->connection->getWrappedConnection()->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); $platform = $this->connection->getDatabasePlatform(); $stmt = $this->connection->prepare('INSERT INTO dbal630_allow_nulls (bool_col) VALUES(?)'); $stmt->bindValue( 1, $platform->convertBooleansToDatabaseValue($statementValue), ParameterType::BOOLEAN ); $stmt->execute(); $id = $this->connection->lastInsertId('dbal630_allow_nulls_id_seq'); self::assertNotEmpty($id); $row = $this->connection->fetchAssoc('SELECT bool_col FROM dbal630_allow_nulls WHERE id = ?', [$id]); self::assertSame($databaseConvertedValue, $row['bool_col']); } /** * Boolean conversion mapping provider * * @return mixed[][] */ public static function booleanTypeConversionUsingBooleanTypeProvider() : iterable { return [ // statement value, database converted value result [true, true], [false, false], [null, false], ]; } /** * Boolean conversion mapping provider * * @return mixed[][] */ public static function booleanTypeConversionWithoutPdoTypeProvider() : iterable { return [ // statement value, database converted value result [true, true], [false, false], [null, null], ]; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Ticket/DBAL752Test.php000066400000000000000000000046661360544566000274670ustar00rootroot00000000000000connection->getDatabasePlatform()->getName(); if (in_array($platform, ['sqlite'])) { return; } $this->markTestSkipped('Related to SQLite only'); } public function testUnsignedIntegerDetection() : void { $this->connection->exec(<<connection->getSchemaManager(); $fetchedTable = $schemaManager->listTableDetails('dbal752_unsigneds'); self::assertEquals('smallint', $fetchedTable->getColumn('small')->getType()->getName()); self::assertEquals('smallint', $fetchedTable->getColumn('small_unsigned')->getType()->getName()); self::assertEquals('integer', $fetchedTable->getColumn('medium')->getType()->getName()); self::assertEquals('integer', $fetchedTable->getColumn('medium_unsigned')->getType()->getName()); self::assertEquals('integer', $fetchedTable->getColumn('integer')->getType()->getName()); self::assertEquals('integer', $fetchedTable->getColumn('integer_unsigned')->getType()->getName()); self::assertEquals('bigint', $fetchedTable->getColumn('big')->getType()->getName()); self::assertEquals('bigint', $fetchedTable->getColumn('big_unsigned')->getType()->getName()); self::assertTrue($fetchedTable->getColumn('small_unsigned')->getUnsigned()); self::assertTrue($fetchedTable->getColumn('medium_unsigned')->getUnsigned()); self::assertTrue($fetchedTable->getColumn('integer_unsigned')->getUnsigned()); self::assertTrue($fetchedTable->getColumn('big_unsigned')->getUnsigned()); self::assertFalse($fetchedTable->getColumn('small')->getUnsigned()); self::assertFalse($fetchedTable->getColumn('medium')->getUnsigned()); self::assertFalse($fetchedTable->getColumn('integer')->getUnsigned()); self::assertFalse($fetchedTable->getColumn('big')->getUnsigned()); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/TransactionTest.php000066400000000000000000000016661360544566000275660ustar00rootroot00000000000000connection->getDatabasePlatform() instanceof MySqlPlatform) { return; } $this->markTestSkipped('Restricted to MySQL.'); } protected function tearDown() : void { $this->resetSharedConn(); parent::tearDown(); } public function testCommitFalse() : void { $this->connection->query('SET SESSION wait_timeout=1'); $this->assertTrue($this->connection->beginTransaction()); sleep(2); // during the sleep mysql will close the connection $this->assertFalse(@$this->connection->commit()); // we will ignore `MySQL server has gone away` warnings } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/TypeConversionTest.php000066400000000000000000000165061360544566000302670ustar00rootroot00000000000000addColumn('id', 'integer', ['notnull' => false]); $table->addColumn('test_string', 'string', ['notnull' => false]); $table->addColumn('test_boolean', 'boolean', ['notnull' => false]); $table->addColumn('test_bigint', 'bigint', ['notnull' => false]); $table->addColumn('test_smallint', 'bigint', ['notnull' => false]); $table->addColumn('test_datetime', 'datetime', ['notnull' => false]); $table->addColumn('test_datetimetz', 'datetimetz', ['notnull' => false]); $table->addColumn('test_date', 'date', ['notnull' => false]); $table->addColumn('test_time', 'time', ['notnull' => false]); $table->addColumn('test_text', 'text', ['notnull' => false]); $table->addColumn('test_array', 'array', ['notnull' => false]); $table->addColumn('test_json_array', 'json_array', ['notnull' => false]); $table->addColumn('test_object', 'object', ['notnull' => false]); $table->addColumn('test_float', 'float', ['notnull' => false]); $table->addColumn('test_decimal', 'decimal', ['notnull' => false, 'scale' => 2, 'precision' => 10]); $table->setPrimaryKey(['id']); $this->connection ->getSchemaManager() ->dropAndCreateTable($table); } /** * @param mixed $originalValue * * @dataProvider booleanProvider */ public function testIdempotentConversionToBoolean(string $type, $originalValue) : void { $dbValue = $this->processValue($type, $originalValue); self::assertIsBool($dbValue); self::assertEquals($originalValue, $dbValue); } /** * @return mixed[][] */ public static function booleanProvider() : iterable { return [ 'true' => ['boolean', true], 'false' => ['boolean', false], ]; } /** * @param mixed $originalValue * * @dataProvider integerProvider */ public function testIdempotentConversionToInteger(string $type, $originalValue) : void { $dbValue = $this->processValue($type, $originalValue); self::assertIsInt($dbValue); self::assertEquals($originalValue, $dbValue); } /** * @return mixed[][] */ public static function integerProvider() : iterable { return [ 'smallint' => ['smallint', 123], ]; } /** * @param mixed $originalValue * * @dataProvider floatProvider */ public function testIdempotentConversionToFloat(string $type, $originalValue) : void { $dbValue = $this->processValue($type, $originalValue); self::assertIsFloat($dbValue); self::assertEquals($originalValue, $dbValue); } /** * @return mixed[][] */ public static function floatProvider() : iterable { return [ 'float' => ['float', 1.5], ]; } /** * @param mixed $originalValue * * @dataProvider toStringProvider */ public function testIdempotentConversionToString(string $type, $originalValue) : void { if ($type === 'text' && $this->connection->getDriver() instanceof PDOOracleDriver) { // inserting BLOBs as streams on Oracle requires Oracle-specific SQL syntax which is currently not supported // see http://php.net/manual/en/pdo.lobs.php#example-1035 $this->markTestSkipped('DBAL doesn\'t support storing LOBs represented as streams using PDO_OCI'); } $dbValue = $this->processValue($type, $originalValue); self::assertIsString($dbValue); self::assertEquals($originalValue, $dbValue); } /** * @return mixed[][] */ public static function toStringProvider() : iterable { return [ 'string' => ['string', 'ABCDEFGabcdefg'], 'bigint' => ['bigint', 12345678], 'text' => ['text', str_repeat('foo ', 1000)], 'decimal' => ['decimal', 1.55], ]; } /** * @param mixed $originalValue * * @dataProvider toArrayProvider */ public function testIdempotentConversionToArray(string $type, $originalValue) : void { $dbValue = $this->processValue($type, $originalValue); self::assertIsArray($dbValue); self::assertEquals($originalValue, $dbValue); } /** * @return mixed[][] */ public static function toArrayProvider() : iterable { return [ 'array' => ['array', ['foo' => 'bar']], 'json_array' => ['json_array', ['foo' => 'bar']], ]; } /** * @param mixed $originalValue * * @dataProvider toObjectProvider */ public function testIdempotentConversionToObject(string $type, $originalValue) : void { $dbValue = $this->processValue($type, $originalValue); self::assertIsObject($dbValue); self::assertEquals($originalValue, $dbValue); } /** * @return mixed[][] */ public static function toObjectProvider() : iterable { $obj = new stdClass(); $obj->foo = 'bar'; $obj->bar = 'baz'; return [ 'object' => ['object', $obj], ]; } /** * @dataProvider toDateTimeProvider */ public function testIdempotentConversionToDateTime(string $type, DateTime $originalValue) : void { $dbValue = $this->processValue($type, $originalValue); self::assertInstanceOf(DateTime::class, $dbValue); if ($type === 'datetimetz') { return; } self::assertEquals($originalValue, $dbValue); self::assertEquals( $originalValue->getTimezone(), $dbValue->getTimezone() ); } /** * @return mixed[][] */ public static function toDateTimeProvider() : iterable { return [ 'datetime' => ['datetime', new DateTime('2010-04-05 10:10:10')], 'datetimetz' => ['datetimetz', new DateTime('2010-04-05 10:10:10')], 'date' => ['date', new DateTime('2010-04-05')], 'time' => ['time', new DateTime('1970-01-01 10:10:10')], ]; } /** * @param mixed $originalValue * * @return mixed */ private function processValue(string $type, $originalValue) { $columnName = 'test_' . $type; $typeInstance = Type::getType($type); $insertionValue = $typeInstance->convertToDatabaseValue($originalValue, $this->connection->getDatabasePlatform()); $this->connection->insert('type_conversion', ['id' => ++self::$typeCounter, $columnName => $insertionValue]); $sql = 'SELECT ' . $columnName . ' FROM type_conversion WHERE id = ' . self::$typeCounter; return $typeInstance->convertToPHPValue( $this->connection->fetchColumn($sql), $this->connection->getDatabasePlatform() ); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Types/000077500000000000000000000000001360544566000250235ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/Types/BinaryTest.php000066400000000000000000000053551360544566000276300ustar00rootroot00000000000000connection->getDriver() instanceof PDOOracleDriver) { $this->markTestSkipped('PDO_OCI doesn\'t support binding binary values'); } $table = new Table('binary_table'); $table->addColumn('id', 'binary', [ 'length' => 16, 'fixed' => true, ]); $table->addColumn('val', 'binary', ['length' => 64]); $table->setPrimaryKey(['id']); $sm = $this->connection->getSchemaManager(); $sm->dropAndCreateTable($table); } public function testInsertAndSelect() : void { $id1 = random_bytes(16); $id2 = random_bytes(16); $value1 = random_bytes(64); $value2 = random_bytes(64); /** @see https://bugs.php.net/bug.php?id=76322 */ if ($this->connection->getDriver() instanceof DB2Driver) { $value1 = str_replace("\x00", "\xFF", $value1); $value2 = str_replace("\x00", "\xFF", $value2); } $this->insert($id1, $value1); $this->insert($id2, $value2); $this->assertSame($value1, $this->select($id1)); $this->assertSame($value2, $this->select($id2)); } private function insert(string $id, string $value) : void { $result = $this->connection->insert('binary_table', [ 'id' => $id, 'val' => $value, ], [ ParameterType::BINARY, ParameterType::BINARY, ]); self::assertSame(1, $result); } /** * @return mixed */ private function select(string $id) { $value = $this->connection->fetchColumn( 'SELECT val FROM binary_table WHERE id = ?', [$id], 0, [ParameterType::BINARY] ); // Currently, `BinaryType` mistakenly converts string values fetched from the DB to a stream. // It should be the opposite. Streams should be used to represent large objects, not binary // strings. The confusion comes from the PostgreSQL's type system where binary strings and // large objects are represented by the same BYTEA type if (is_resource($value)) { $value = stream_get_contents($value); } return $value; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Functional/WriteTest.php000066400000000000000000000301331360544566000263620ustar00rootroot00000000000000addColumn('id', 'integer', ['autoincrement' => true]); $table->addColumn('test_int', 'integer'); $table->addColumn('test_string', 'string', ['notnull' => false]); $table->setPrimaryKey(['id']); $this->connection->getSchemaManager()->createTable($table); } catch (Throwable $e) { } $this->connection->executeUpdate('DELETE FROM write_table'); } /** * @group DBAL-80 */ public function testExecuteUpdateFirstTypeIsNull() : void { $sql = 'INSERT INTO write_table (test_string, test_int) VALUES (?, ?)'; $this->connection->executeUpdate($sql, ['text', 1111], [null, ParameterType::INTEGER]); $sql = 'SELECT * FROM write_table WHERE test_string = ? AND test_int = ?'; self::assertTrue((bool) $this->connection->fetchColumn($sql, ['text', 1111])); } public function testExecuteUpdate() : void { $sql = 'INSERT INTO write_table (test_int) VALUES ( ' . $this->connection->quote(1) . ')'; $affected = $this->connection->executeUpdate($sql); self::assertEquals(1, $affected, 'executeUpdate() should return the number of affected rows!'); } public function testExecuteUpdateWithTypes() : void { $sql = 'INSERT INTO write_table (test_int, test_string) VALUES (?, ?)'; $affected = $this->connection->executeUpdate( $sql, [1, 'foo'], [ParameterType::INTEGER, ParameterType::STRING] ); self::assertEquals(1, $affected, 'executeUpdate() should return the number of affected rows!'); } public function testPrepareRowCountReturnsAffectedRows() : void { $sql = 'INSERT INTO write_table (test_int, test_string) VALUES (?, ?)'; $stmt = $this->connection->prepare($sql); $stmt->bindValue(1, 1); $stmt->bindValue(2, 'foo'); $stmt->execute(); self::assertEquals(1, $stmt->rowCount()); } public function testPrepareWithPdoTypes() : void { $sql = 'INSERT INTO write_table (test_int, test_string) VALUES (?, ?)'; $stmt = $this->connection->prepare($sql); $stmt->bindValue(1, 1, ParameterType::INTEGER); $stmt->bindValue(2, 'foo', ParameterType::STRING); $stmt->execute(); self::assertEquals(1, $stmt->rowCount()); } public function testPrepareWithDbalTypes() : void { $sql = 'INSERT INTO write_table (test_int, test_string) VALUES (?, ?)'; $stmt = $this->connection->prepare($sql); $stmt->bindValue(1, 1, Type::getType('integer')); $stmt->bindValue(2, 'foo', Type::getType('string')); $stmt->execute(); self::assertEquals(1, $stmt->rowCount()); } public function testPrepareWithDbalTypeNames() : void { $sql = 'INSERT INTO write_table (test_int, test_string) VALUES (?, ?)'; $stmt = $this->connection->prepare($sql); $stmt->bindValue(1, 1, 'integer'); $stmt->bindValue(2, 'foo', 'string'); $stmt->execute(); self::assertEquals(1, $stmt->rowCount()); } public function insertRows() : void { self::assertEquals(1, $this->connection->insert('write_table', ['test_int' => 1, 'test_string' => 'foo'])); self::assertEquals(1, $this->connection->insert('write_table', ['test_int' => 2, 'test_string' => 'bar'])); } public function testInsert() : void { $this->insertRows(); } public function testDelete() : void { $this->insertRows(); self::assertEquals(1, $this->connection->delete('write_table', ['test_int' => 2])); self::assertCount(1, $this->connection->fetchAll('SELECT * FROM write_table')); self::assertEquals(1, $this->connection->delete('write_table', ['test_int' => 1])); self::assertCount(0, $this->connection->fetchAll('SELECT * FROM write_table')); } public function testUpdate() : void { $this->insertRows(); self::assertEquals(1, $this->connection->update('write_table', ['test_string' => 'bar'], ['test_string' => 'foo'])); self::assertEquals(2, $this->connection->update('write_table', ['test_string' => 'baz'], ['test_string' => 'bar'])); self::assertEquals(0, $this->connection->update('write_table', ['test_string' => 'baz'], ['test_string' => 'bar'])); } public function testLastInsertId() : void { if (! $this->connection->getDatabasePlatform()->prefersIdentityColumns()) { $this->markTestSkipped('Test only works on platforms with identity columns.'); } self::assertEquals(1, $this->connection->insert('write_table', ['test_int' => 2, 'test_string' => 'bar'])); $num = $this->lastInsertId(); self::assertNotNull($num, 'LastInsertId() should not be null.'); self::assertGreaterThan(0, $num, 'LastInsertId() should be non-negative number.'); } public function testLastInsertIdSequence() : void { if (! $this->connection->getDatabasePlatform()->supportsSequences()) { $this->markTestSkipped('Test only works on platforms with sequences.'); } $sequence = new Sequence('write_table_id_seq'); try { $this->connection->getSchemaManager()->createSequence($sequence); } catch (Throwable $e) { } $sequences = $this->connection->getSchemaManager()->listSequences(); self::assertCount(1, array_filter($sequences, static function ($sequence) { return strtolower($sequence->getName()) === 'write_table_id_seq'; })); $stmt = $this->connection->query($this->connection->getDatabasePlatform()->getSequenceNextValSQL('write_table_id_seq')); $nextSequenceVal = $stmt->fetchColumn(); $lastInsertId = $this->lastInsertId('write_table_id_seq'); self::assertGreaterThan(0, $lastInsertId); self::assertEquals($nextSequenceVal, $lastInsertId); } public function testLastInsertIdNoSequenceGiven() : void { if (! $this->connection->getDatabasePlatform()->supportsSequences() || $this->connection->getDatabasePlatform()->supportsIdentityColumns()) { $this->markTestSkipped("Test only works consistently on platforms that support sequences and don't support identity columns."); } self::assertFalse($this->lastInsertId()); } /** * @group DBAL-445 */ public function testInsertWithKeyValueTypes() : void { $testString = new DateTime('2013-04-14 10:10:10'); $this->connection->insert( 'write_table', ['test_int' => '30', 'test_string' => $testString], ['test_string' => 'datetime', 'test_int' => 'integer'] ); $data = $this->connection->fetchColumn('SELECT test_string FROM write_table WHERE test_int = 30'); self::assertEquals($testString->format($this->connection->getDatabasePlatform()->getDateTimeFormatString()), $data); } /** * @group DBAL-445 */ public function testUpdateWithKeyValueTypes() : void { $testString = new DateTime('2013-04-14 10:10:10'); $this->connection->insert( 'write_table', ['test_int' => '30', 'test_string' => $testString], ['test_string' => 'datetime', 'test_int' => 'integer'] ); $testString = new DateTime('2013-04-15 10:10:10'); $this->connection->update( 'write_table', ['test_string' => $testString], ['test_int' => '30'], ['test_string' => 'datetime', 'test_int' => 'integer'] ); $data = $this->connection->fetchColumn('SELECT test_string FROM write_table WHERE test_int = 30'); self::assertEquals($testString->format($this->connection->getDatabasePlatform()->getDateTimeFormatString()), $data); } /** * @group DBAL-445 */ public function testDeleteWithKeyValueTypes() : void { $val = new DateTime('2013-04-14 10:10:10'); $this->connection->insert( 'write_table', ['test_int' => '30', 'test_string' => $val], ['test_string' => 'datetime', 'test_int' => 'integer'] ); $this->connection->delete('write_table', ['test_int' => 30, 'test_string' => $val], ['test_string' => 'datetime', 'test_int' => 'integer']); $data = $this->connection->fetchColumn('SELECT test_string FROM write_table WHERE test_int = 30'); self::assertFalse($data); } public function testEmptyIdentityInsert() : void { $platform = $this->connection->getDatabasePlatform(); if (! ($platform->supportsIdentityColumns() || $platform->usesSequenceEmulatedIdentityColumns())) { $this->markTestSkipped( 'Test only works on platforms with identity columns or sequence emulated identity columns.' ); } $table = new Table('test_empty_identity'); $table->addColumn('id', 'integer', ['autoincrement' => true]); $table->setPrimaryKey(['id']); try { $this->connection->getSchemaManager()->dropTable($table->getQuotedName($platform)); } catch (Throwable $e) { } foreach ($platform->getCreateTableSQL($table) as $sql) { $this->connection->exec($sql); } $seqName = $platform->usesSequenceEmulatedIdentityColumns() ? $platform->getIdentitySequenceName('test_empty_identity', 'id') : null; $sql = $platform->getEmptyIdentityInsertSQL('test_empty_identity', 'id'); $this->connection->exec($sql); $firstId = $this->lastInsertId($seqName); $this->connection->exec($sql); $secondId = $this->lastInsertId($seqName); self::assertGreaterThan($firstId, $secondId); } /** * @group DBAL-2688 */ public function testUpdateWhereIsNull() : void { $this->connection->insert( 'write_table', ['test_int' => '30', 'test_string' => null], ['test_string' => 'string', 'test_int' => 'integer'] ); $data = $this->connection->fetchAll('SELECT * FROM write_table WHERE test_int = 30'); self::assertCount(1, $data); $this->connection->update('write_table', ['test_int' => 10], ['test_string' => null], ['test_string' => 'string', 'test_int' => 'integer']); $data = $this->connection->fetchAll('SELECT * FROM write_table WHERE test_int = 30'); self::assertCount(0, $data); } public function testDeleteWhereIsNull() : void { $this->connection->insert( 'write_table', ['test_int' => '30', 'test_string' => null], ['test_string' => 'string', 'test_int' => 'integer'] ); $data = $this->connection->fetchAll('SELECT * FROM write_table WHERE test_int = 30'); self::assertCount(1, $data); $this->connection->delete('write_table', ['test_string' => null], ['test_string' => 'string']); $data = $this->connection->fetchAll('SELECT * FROM write_table WHERE test_int = 30'); self::assertCount(0, $data); } /** * Returns the ID of the last inserted row or skips the test if the currently used driver * doesn't support this feature * * @return string|false * * @throws DriverException */ private function lastInsertId(?string $name = null) { try { return $this->connection->lastInsertId($name); } catch (DriverException $e) { if ($e->getCode() === 'IM001') { $this->markTestSkipped($e->getMessage()); } throw $e; } } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Logging/000077500000000000000000000000001360544566000232035ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Logging/DebugStackTest.php000066400000000000000000000023551360544566000265750ustar00rootroot00000000000000logger = new DebugStack(); } protected function tearDown() : void { unset($this->logger); } public function testLoggedQuery() : void { $this->logger->startQuery('SELECT column FROM table'); self::assertEquals( [ 1 => [ 'sql' => 'SELECT column FROM table', 'params' => null, 'types' => null, 'executionMS' => 0, ], ], $this->logger->queries ); $this->logger->stopQuery(); self::assertGreaterThan(0, $this->logger->queries[1]['executionMS']); } public function testLoggedQueryDisabled() : void { $this->logger->enabled = false; $this->logger->startQuery('SELECT column FROM table'); self::assertEquals([], $this->logger->queries); $this->logger->stopQuery(); self::assertEquals([], $this->logger->queries); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Logging/LoggerChainTest.php000066400000000000000000000024441360544566000267420ustar00rootroot00000000000000createChain('startQuery', $sql, $params, $types); $listener->startQuery($sql, $params, $types); } public function testStopQuery() : void { $listener = $this->createChain('stopQuery'); $listener->stopQuery(); } /** * @param mixed ...$args */ private function createChain(string $method, ...$args) : LoggerChain { $chain = new LoggerChain([ $this->createLogger($method, ...$args), ]); $chain->addLogger($this->createLogger($method, ...$args)); return $chain; } /** * @param mixed ...$args */ private function createLogger(string $method, ...$args) : SQLLogger { $logger = $this->createMock(SQLLogger::class); $logger->expects($this->once()) ->method($method) ->with(...$args); return $logger; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Performance/000077500000000000000000000000001360544566000240565ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Performance/TypeConversionPerformanceTest.php000066400000000000000000000020451360544566000326010ustar00rootroot00000000000000connection->getDatabasePlatform(); $this->startTiming(); for ($i = 0; $i < $count; $i++) { $type->convertToDatabaseValue($value, $platform); } $this->stopTiming(); } /** * @return mixed[][] */ public static function itemCountProvider() : iterable { return [ '100 items' => [100], '1000 items' => [1000], '10000 items' => [10000], '100000 items' => [100000], ]; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Platforms/000077500000000000000000000000001360544566000235645ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Platforms/AbstractMySQLPlatformTestCase.php000066400000000000000000001111571360544566000320750ustar00rootroot00000000000000platform->modifyLimitQuery('SELECT n FROM Foo', null, 10); self::assertEquals('SELECT n FROM Foo LIMIT 18446744073709551615 OFFSET 10', $sql); } public function testGenerateMixedCaseTableCreate() : void { $table = new Table('Foo'); $table->addColumn('Bar', 'integer'); $sql = $this->platform->getCreateTableSQL($table); self::assertEquals('CREATE TABLE Foo (Bar INT NOT NULL) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB', array_shift($sql)); } public function getGenerateTableSql() : string { return 'CREATE TABLE test (id INT AUTO_INCREMENT NOT NULL, test VARCHAR(255) DEFAULT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB'; } /** * @return string[] */ public function getGenerateTableWithMultiColumnUniqueIndexSql() : array { return ['CREATE TABLE test (foo VARCHAR(255) DEFAULT NULL, bar VARCHAR(255) DEFAULT NULL, UNIQUE INDEX UNIQ_D87F7E0C8C73652176FF8CAA (foo, bar)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB']; } /** * {@inheritDoc} */ public function getGenerateAlterTableSql() : array { return ["ALTER TABLE mytable RENAME TO userlist, ADD quota INT DEFAULT NULL, DROP foo, CHANGE bar baz VARCHAR(255) DEFAULT 'def' NOT NULL, CHANGE bloo bloo TINYINT(1) DEFAULT '0' NOT NULL"]; } public function testGeneratesSqlSnippets() : void { self::assertEquals('RLIKE', $this->platform->getRegexpExpression(), 'Regular expression operator is not correct'); self::assertEquals('`', $this->platform->getIdentifierQuoteCharacter(), 'Quote character is not correct'); self::assertEquals('CONCAT(column1, column2, column3)', $this->platform->getConcatExpression('column1', 'column2', 'column3'), 'Concatenation function is not correct'); } public function testGeneratesTransactionsCommands() : void { self::assertEquals( 'SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED', $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::READ_UNCOMMITTED), '' ); self::assertEquals( 'SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED', $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::READ_COMMITTED) ); self::assertEquals( 'SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ', $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::REPEATABLE_READ) ); self::assertEquals( 'SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE', $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::SERIALIZABLE) ); } public function testGeneratesDDLSnippets() : void { self::assertEquals('SHOW DATABASES', $this->platform->getListDatabasesSQL()); self::assertEquals('CREATE DATABASE foobar', $this->platform->getCreateDatabaseSQL('foobar')); self::assertEquals('DROP DATABASE foobar', $this->platform->getDropDatabaseSQL('foobar')); self::assertEquals('DROP TABLE foobar', $this->platform->getDropTableSQL('foobar')); } public function testGeneratesTypeDeclarationForIntegers() : void { self::assertEquals( 'INT', $this->platform->getIntegerTypeDeclarationSQL([]) ); self::assertEquals( 'INT AUTO_INCREMENT', $this->platform->getIntegerTypeDeclarationSQL(['autoincrement' => true]) ); self::assertEquals( 'INT AUTO_INCREMENT', $this->platform->getIntegerTypeDeclarationSQL( ['autoincrement' => true, 'primary' => true] ) ); } public function testGeneratesTypeDeclarationForStrings() : void { self::assertEquals( 'CHAR(10)', $this->platform->getVarcharTypeDeclarationSQL( ['length' => 10, 'fixed' => true] ) ); self::assertEquals( 'VARCHAR(50)', $this->platform->getVarcharTypeDeclarationSQL(['length' => 50]), 'Variable string declaration is not correct' ); self::assertEquals( 'VARCHAR(255)', $this->platform->getVarcharTypeDeclarationSQL([]), 'Long string declaration is not correct' ); } public function testPrefersIdentityColumns() : void { self::assertTrue($this->platform->prefersIdentityColumns()); } public function testSupportsIdentityColumns() : void { self::assertTrue($this->platform->supportsIdentityColumns()); } public function testDoesSupportSavePoints() : void { self::assertTrue($this->platform->supportsSavepoints()); } public function getGenerateIndexSql() : string { return 'CREATE INDEX my_idx ON mytable (user_name, last_login)'; } public function getGenerateUniqueIndexSql() : string { return 'CREATE UNIQUE INDEX index_name ON test (test, test2)'; } public function getGenerateForeignKeySql() : string { return 'ALTER TABLE test ADD FOREIGN KEY (fk_name_id) REFERENCES other_table (id)'; } /** * @group DBAL-126 */ public function testUniquePrimaryKey() : void { $keyTable = new Table('foo'); $keyTable->addColumn('bar', 'integer'); $keyTable->addColumn('baz', 'string'); $keyTable->setPrimaryKey(['bar']); $keyTable->addUniqueIndex(['baz']); $oldTable = new Table('foo'); $oldTable->addColumn('bar', 'integer'); $oldTable->addColumn('baz', 'string'); $c = new Comparator(); $diff = $c->diffTable($oldTable, $keyTable); $sql = $this->platform->getAlterTableSQL($diff); self::assertEquals([ 'ALTER TABLE foo ADD PRIMARY KEY (bar)', 'CREATE UNIQUE INDEX UNIQ_8C73652178240498 ON foo (baz)', ], $sql); } public function testModifyLimitQuery() : void { $sql = $this->platform->modifyLimitQuery('SELECT * FROM user', 10, 0); self::assertEquals('SELECT * FROM user LIMIT 10', $sql); } public function testModifyLimitQueryWithEmptyOffset() : void { $sql = $this->platform->modifyLimitQuery('SELECT * FROM user', 10); self::assertEquals('SELECT * FROM user LIMIT 10', $sql); } /** * @group DDC-118 */ public function testGetDateTimeTypeDeclarationSql() : void { self::assertEquals('DATETIME', $this->platform->getDateTimeTypeDeclarationSQL(['version' => false])); self::assertEquals('TIMESTAMP', $this->platform->getDateTimeTypeDeclarationSQL(['version' => true])); self::assertEquals('DATETIME', $this->platform->getDateTimeTypeDeclarationSQL([])); } /** * {@inheritDoc} */ public function getCreateTableColumnCommentsSQL() : array { return ["CREATE TABLE test (id INT NOT NULL COMMENT 'This is a comment', PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB"]; } /** * {@inheritDoc} */ public function getAlterTableColumnCommentsSQL() : array { return ["ALTER TABLE mytable ADD quota INT NOT NULL COMMENT 'A comment', CHANGE foo foo VARCHAR(255) NOT NULL, CHANGE bar baz VARCHAR(255) NOT NULL COMMENT 'B comment'"]; } /** * {@inheritDoc} */ public function getCreateTableColumnTypeCommentsSQL() : array { return ["CREATE TABLE test (id INT NOT NULL, data LONGTEXT NOT NULL COMMENT '(DC2Type:array)', PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB"]; } /** * @group DBAL-237 */ public function testChangeIndexWithForeignKeys() : void { $index = new Index('idx', ['col'], false); $unique = new Index('uniq', ['col'], true); $diff = new TableDiff('test', [], [], [], [$unique], [], [$index]); $sql = $this->platform->getAlterTableSQL($diff); self::assertEquals(['ALTER TABLE test DROP INDEX idx, ADD UNIQUE INDEX uniq (col)'], $sql); $diff = new TableDiff('test', [], [], [], [$index], [], [$unique]); $sql = $this->platform->getAlterTableSQL($diff); self::assertEquals(['ALTER TABLE test DROP INDEX uniq, ADD INDEX idx (col)'], $sql); } /** * @return string[] */ protected function getQuotedColumnInPrimaryKeySQL() : array { return ['CREATE TABLE `quoted` (`create` VARCHAR(255) NOT NULL, PRIMARY KEY(`create`)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB']; } /** * @return string[] */ protected function getQuotedColumnInIndexSQL() : array { return ['CREATE TABLE `quoted` (`create` VARCHAR(255) NOT NULL, INDEX IDX_22660D028FD6E0FB (`create`)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB']; } /** * @return string[] */ protected function getQuotedNameInIndexSQL() : array { return ['CREATE TABLE test (column1 VARCHAR(255) NOT NULL, INDEX `key` (column1)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB']; } /** * @return string[] */ protected function getQuotedColumnInForeignKeySQL() : array { return [ 'CREATE TABLE `quoted` (`create` VARCHAR(255) NOT NULL, foo VARCHAR(255) NOT NULL, `bar` VARCHAR(255) NOT NULL) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB', 'ALTER TABLE `quoted` ADD CONSTRAINT FK_WITH_RESERVED_KEYWORD FOREIGN KEY (`create`, foo, `bar`) REFERENCES `foreign` (`create`, bar, `foo-bar`)', 'ALTER TABLE `quoted` ADD CONSTRAINT FK_WITH_NON_RESERVED_KEYWORD FOREIGN KEY (`create`, foo, `bar`) REFERENCES foo (`create`, bar, `foo-bar`)', 'ALTER TABLE `quoted` ADD CONSTRAINT FK_WITH_INTENDED_QUOTATION FOREIGN KEY (`create`, foo, `bar`) REFERENCES `foo-bar` (`create`, bar, `foo-bar`)', ]; } public function testCreateTableWithFulltextIndex() : void { $table = new Table('fulltext_table'); $table->addOption('engine', 'MyISAM'); $table->addColumn('text', 'text'); $table->addIndex(['text'], 'fulltext_text'); $index = $table->getIndex('fulltext_text'); $index->addFlag('fulltext'); $sql = $this->platform->getCreateTableSQL($table); self::assertEquals(['CREATE TABLE fulltext_table (text LONGTEXT NOT NULL, FULLTEXT INDEX fulltext_text (text)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = MyISAM'], $sql); } public function testCreateTableWithSpatialIndex() : void { $table = new Table('spatial_table'); $table->addOption('engine', 'MyISAM'); $table->addColumn('point', 'text'); // This should be a point type $table->addIndex(['point'], 'spatial_text'); $index = $table->getIndex('spatial_text'); $index->addFlag('spatial'); $sql = $this->platform->getCreateTableSQL($table); self::assertEquals(['CREATE TABLE spatial_table (point LONGTEXT NOT NULL, SPATIAL INDEX spatial_text (point)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = MyISAM'], $sql); } public function testClobTypeDeclarationSQL() : void { self::assertEquals('TINYTEXT', $this->platform->getClobTypeDeclarationSQL(['length' => 1])); self::assertEquals('TINYTEXT', $this->platform->getClobTypeDeclarationSQL(['length' => 255])); self::assertEquals('TEXT', $this->platform->getClobTypeDeclarationSQL(['length' => 256])); self::assertEquals('TEXT', $this->platform->getClobTypeDeclarationSQL(['length' => 65535])); self::assertEquals('MEDIUMTEXT', $this->platform->getClobTypeDeclarationSQL(['length' => 65536])); self::assertEquals('MEDIUMTEXT', $this->platform->getClobTypeDeclarationSQL(['length' => 16777215])); self::assertEquals('LONGTEXT', $this->platform->getClobTypeDeclarationSQL(['length' => 16777216])); self::assertEquals('LONGTEXT', $this->platform->getClobTypeDeclarationSQL([])); } public function testBlobTypeDeclarationSQL() : void { self::assertEquals('TINYBLOB', $this->platform->getBlobTypeDeclarationSQL(['length' => 1])); self::assertEquals('TINYBLOB', $this->platform->getBlobTypeDeclarationSQL(['length' => 255])); self::assertEquals('BLOB', $this->platform->getBlobTypeDeclarationSQL(['length' => 256])); self::assertEquals('BLOB', $this->platform->getBlobTypeDeclarationSQL(['length' => 65535])); self::assertEquals('MEDIUMBLOB', $this->platform->getBlobTypeDeclarationSQL(['length' => 65536])); self::assertEquals('MEDIUMBLOB', $this->platform->getBlobTypeDeclarationSQL(['length' => 16777215])); self::assertEquals('LONGBLOB', $this->platform->getBlobTypeDeclarationSQL(['length' => 16777216])); self::assertEquals('LONGBLOB', $this->platform->getBlobTypeDeclarationSQL([])); } /** * @group DBAL-400 */ public function testAlterTableAddPrimaryKey() : void { $table = new Table('alter_table_add_pk'); $table->addColumn('id', 'integer'); $table->addColumn('foo', 'integer'); $table->addIndex(['id'], 'idx_id'); $comparator = new Comparator(); $diffTable = clone $table; $diffTable->dropIndex('idx_id'); $diffTable->setPrimaryKey(['id']); self::assertEquals( ['DROP INDEX idx_id ON alter_table_add_pk', 'ALTER TABLE alter_table_add_pk ADD PRIMARY KEY (id)'], $this->platform->getAlterTableSQL($comparator->diffTable($table, $diffTable)) ); } /** * @group DBAL-1132 */ public function testAlterPrimaryKeyWithAutoincrementColumn() : void { $table = new Table('alter_primary_key'); $table->addColumn('id', 'integer', ['autoincrement' => true]); $table->addColumn('foo', 'integer'); $table->setPrimaryKey(['id']); $comparator = new Comparator(); $diffTable = clone $table; $diffTable->dropPrimaryKey(); $diffTable->setPrimaryKey(['foo']); self::assertEquals( [ 'ALTER TABLE alter_primary_key MODIFY id INT NOT NULL', 'ALTER TABLE alter_primary_key DROP PRIMARY KEY', 'ALTER TABLE alter_primary_key ADD PRIMARY KEY (foo)', ], $this->platform->getAlterTableSQL($comparator->diffTable($table, $diffTable)) ); } /** * @group DBAL-464 */ public function testDropPrimaryKeyWithAutoincrementColumn() : void { $table = new Table('drop_primary_key'); $table->addColumn('id', 'integer', ['autoincrement' => true]); $table->addColumn('foo', 'integer'); $table->addColumn('bar', 'integer'); $table->setPrimaryKey(['id', 'foo']); $comparator = new Comparator(); $diffTable = clone $table; $diffTable->dropPrimaryKey(); self::assertEquals( [ 'ALTER TABLE drop_primary_key MODIFY id INT NOT NULL', 'ALTER TABLE drop_primary_key DROP PRIMARY KEY', ], $this->platform->getAlterTableSQL($comparator->diffTable($table, $diffTable)) ); } /** * @group DBAL-2302 */ public function testDropNonAutoincrementColumnFromCompositePrimaryKeyWithAutoincrementColumn() : void { $table = new Table('tbl'); $table->addColumn('id', 'integer', ['autoincrement' => true]); $table->addColumn('foo', 'integer'); $table->addColumn('bar', 'integer'); $table->setPrimaryKey(['id', 'foo']); $comparator = new Comparator(); $diffTable = clone $table; $diffTable->dropPrimaryKey(); $diffTable->setPrimaryKey(['id']); self::assertSame( [ 'ALTER TABLE tbl MODIFY id INT NOT NULL', 'ALTER TABLE tbl DROP PRIMARY KEY', 'ALTER TABLE tbl ADD PRIMARY KEY (id)', ], $this->platform->getAlterTableSQL($comparator->diffTable($table, $diffTable)) ); } /** * @group DBAL-2302 */ public function testAddNonAutoincrementColumnToPrimaryKeyWithAutoincrementColumn() : void { $table = new Table('tbl'); $table->addColumn('id', 'integer', ['autoincrement' => true]); $table->addColumn('foo', 'integer'); $table->addColumn('bar', 'integer'); $table->setPrimaryKey(['id']); $comparator = new Comparator(); $diffTable = clone $table; $diffTable->dropPrimaryKey(); $diffTable->setPrimaryKey(['id', 'foo']); self::assertSame( [ 'ALTER TABLE tbl MODIFY id INT NOT NULL', 'ALTER TABLE tbl DROP PRIMARY KEY', 'ALTER TABLE tbl ADD PRIMARY KEY (id, foo)', ], $this->platform->getAlterTableSQL($comparator->diffTable($table, $diffTable)) ); } /** * @group DBAL-586 */ public function testAddAutoIncrementPrimaryKey() : void { $keyTable = new Table('foo'); $keyTable->addColumn('id', 'integer', ['autoincrement' => true]); $keyTable->addColumn('baz', 'string'); $keyTable->setPrimaryKey(['id']); $oldTable = new Table('foo'); $oldTable->addColumn('baz', 'string'); $c = new Comparator(); $diff = $c->diffTable($oldTable, $keyTable); $sql = $this->platform->getAlterTableSQL($diff); self::assertEquals(['ALTER TABLE foo ADD id INT AUTO_INCREMENT NOT NULL, ADD PRIMARY KEY (id)'], $sql); } public function testNamedPrimaryKey() : void { $diff = new TableDiff('mytable'); $diff->changedIndexes['foo_index'] = new Index('foo_index', ['foo'], true, true); $sql = $this->platform->getAlterTableSQL($diff); self::assertEquals([ 'ALTER TABLE mytable DROP PRIMARY KEY', 'ALTER TABLE mytable ADD PRIMARY KEY (foo)', ], $sql); } public function testAlterPrimaryKeyWithNewColumn() : void { $table = new Table('yolo'); $table->addColumn('pkc1', 'integer'); $table->addColumn('col_a', 'integer'); $table->setPrimaryKey(['pkc1']); $comparator = new Comparator(); $diffTable = clone $table; $diffTable->addColumn('pkc2', 'integer'); $diffTable->dropPrimaryKey(); $diffTable->setPrimaryKey(['pkc1', 'pkc2']); self::assertSame( [ 'ALTER TABLE yolo DROP PRIMARY KEY', 'ALTER TABLE yolo ADD pkc2 INT NOT NULL', 'ALTER TABLE yolo ADD PRIMARY KEY (pkc1, pkc2)', ], $this->platform->getAlterTableSQL($comparator->diffTable($table, $diffTable)) ); } public function testInitializesDoctrineTypeMappings() : void { self::assertTrue($this->platform->hasDoctrineTypeMappingFor('binary')); self::assertSame('binary', $this->platform->getDoctrineTypeMapping('binary')); self::assertTrue($this->platform->hasDoctrineTypeMappingFor('varbinary')); self::assertSame('binary', $this->platform->getDoctrineTypeMapping('varbinary')); } protected function getBinaryMaxLength() : int { return 65535; } public function testReturnsBinaryTypeDeclarationSQL() : void { self::assertSame('VARBINARY(255)', $this->platform->getBinaryTypeDeclarationSQL([])); self::assertSame('VARBINARY(255)', $this->platform->getBinaryTypeDeclarationSQL(['length' => 0])); self::assertSame('VARBINARY(65535)', $this->platform->getBinaryTypeDeclarationSQL(['length' => 65535])); self::assertSame('BINARY(255)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true])); self::assertSame('BINARY(255)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 0])); self::assertSame('BINARY(65535)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 65535])); } /** * @group legacy * @expectedDeprecation Binary field length 65536 is greater than supported by the platform (65535). Reduce the field length or use a BLOB field instead. * @expectedDeprecation Binary field length 16777215 is greater than supported by the platform (65535). Reduce the field length or use a BLOB field instead. * @expectedDeprecation Binary field length 16777216 is greater than supported by the platform (65535). Reduce the field length or use a BLOB field instead. */ public function testReturnsBinaryTypeLongerThanMaxDeclarationSQL() : void { self::assertSame('MEDIUMBLOB', $this->platform->getBinaryTypeDeclarationSQL(['length' => 65536])); self::assertSame('MEDIUMBLOB', $this->platform->getBinaryTypeDeclarationSQL(['length' => 16777215])); self::assertSame('LONGBLOB', $this->platform->getBinaryTypeDeclarationSQL(['length' => 16777216])); self::assertSame('MEDIUMBLOB', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 65536])); self::assertSame('MEDIUMBLOB', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 16777215])); self::assertSame('LONGBLOB', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 16777216])); } public function testDoesNotPropagateForeignKeyCreationForNonSupportingEngines() : void { $table = new Table('foreign_table'); $table->addColumn('id', 'integer'); $table->addColumn('fk_id', 'integer'); $table->addForeignKeyConstraint('foreign_table', ['fk_id'], ['id']); $table->setPrimaryKey(['id']); $table->addOption('engine', 'MyISAM'); self::assertSame( ['CREATE TABLE foreign_table (id INT NOT NULL, fk_id INT NOT NULL, INDEX IDX_5690FFE2A57719D0 (fk_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = MyISAM'], $this->platform->getCreateTableSQL( $table, AbstractPlatform::CREATE_INDEXES|AbstractPlatform::CREATE_FOREIGNKEYS ) ); $table = clone $table; $table->addOption('engine', 'InnoDB'); self::assertSame( [ 'CREATE TABLE foreign_table (id INT NOT NULL, fk_id INT NOT NULL, INDEX IDX_5690FFE2A57719D0 (fk_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB', 'ALTER TABLE foreign_table ADD CONSTRAINT FK_5690FFE2A57719D0 FOREIGN KEY (fk_id) REFERENCES foreign_table (id)', ], $this->platform->getCreateTableSQL( $table, AbstractPlatform::CREATE_INDEXES|AbstractPlatform::CREATE_FOREIGNKEYS ) ); } public function testDoesNotPropagateForeignKeyAlterationForNonSupportingEngines() : void { $table = new Table('foreign_table'); $table->addColumn('id', 'integer'); $table->addColumn('fk_id', 'integer'); $table->addForeignKeyConstraint('foreign_table', ['fk_id'], ['id']); $table->setPrimaryKey(['id']); $table->addOption('engine', 'MyISAM'); $addedForeignKeys = [new ForeignKeyConstraint(['fk_id'], 'foo', ['id'], 'fk_add')]; $changedForeignKeys = [new ForeignKeyConstraint(['fk_id'], 'bar', ['id'], 'fk_change')]; $removedForeignKeys = [new ForeignKeyConstraint(['fk_id'], 'baz', ['id'], 'fk_remove')]; $tableDiff = new TableDiff('foreign_table'); $tableDiff->fromTable = $table; $tableDiff->addedForeignKeys = $addedForeignKeys; $tableDiff->changedForeignKeys = $changedForeignKeys; $tableDiff->removedForeignKeys = $removedForeignKeys; self::assertEmpty($this->platform->getAlterTableSQL($tableDiff)); $table->addOption('engine', 'InnoDB'); $tableDiff = new TableDiff('foreign_table'); $tableDiff->fromTable = $table; $tableDiff->addedForeignKeys = $addedForeignKeys; $tableDiff->changedForeignKeys = $changedForeignKeys; $tableDiff->removedForeignKeys = $removedForeignKeys; self::assertSame( [ 'ALTER TABLE foreign_table DROP FOREIGN KEY fk_remove', 'ALTER TABLE foreign_table DROP FOREIGN KEY fk_change', 'ALTER TABLE foreign_table ADD CONSTRAINT fk_add FOREIGN KEY (fk_id) REFERENCES foo (id)', 'ALTER TABLE foreign_table ADD CONSTRAINT fk_change FOREIGN KEY (fk_id) REFERENCES bar (id)', ], $this->platform->getAlterTableSQL($tableDiff) ); } /** * @return string[] * * @group DBAL-234 */ protected function getAlterTableRenameIndexSQL() : array { return [ 'DROP INDEX idx_foo ON mytable', 'CREATE INDEX idx_bar ON mytable (id)', ]; } /** * @return string[] * * @group DBAL-234 */ protected function getQuotedAlterTableRenameIndexSQL() : array { return [ 'DROP INDEX `create` ON `table`', 'CREATE INDEX `select` ON `table` (id)', 'DROP INDEX `foo` ON `table`', 'CREATE INDEX `bar` ON `table` (id)', ]; } /** * @return string[] * * @group DBAL-807 */ protected function getAlterTableRenameIndexInSchemaSQL() : array { return [ 'DROP INDEX idx_foo ON myschema.mytable', 'CREATE INDEX idx_bar ON myschema.mytable (id)', ]; } /** * @return string[] * * @group DBAL-807 */ protected function getQuotedAlterTableRenameIndexInSchemaSQL() : array { return [ 'DROP INDEX `create` ON `schema`.`table`', 'CREATE INDEX `select` ON `schema`.`table` (id)', 'DROP INDEX `foo` ON `schema`.`table`', 'CREATE INDEX `bar` ON `schema`.`table` (id)', ]; } protected function getQuotesDropForeignKeySQL() : string { return 'ALTER TABLE `table` DROP FOREIGN KEY `select`'; } protected function getQuotesDropConstraintSQL() : string { return 'ALTER TABLE `table` DROP CONSTRAINT `select`'; } public function testDoesNotPropagateDefaultValuesForUnsupportedColumnTypes() : void { $table = new Table('text_blob_default_value'); $table->addColumn('def_text', 'text', ['default' => 'def']); $table->addColumn('def_text_null', 'text', ['notnull' => false, 'default' => 'def']); $table->addColumn('def_blob', 'blob', ['default' => 'def']); $table->addColumn('def_blob_null', 'blob', ['notnull' => false, 'default' => 'def']); self::assertSame( ['CREATE TABLE text_blob_default_value (def_text LONGTEXT NOT NULL, def_text_null LONGTEXT DEFAULT NULL, def_blob LONGBLOB NOT NULL, def_blob_null LONGBLOB DEFAULT NULL) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB'], $this->platform->getCreateTableSQL($table) ); $diffTable = clone $table; $diffTable->changeColumn('def_text', ['default' => null]); $diffTable->changeColumn('def_text_null', ['default' => null]); $diffTable->changeColumn('def_blob', ['default' => null]); $diffTable->changeColumn('def_blob_null', ['default' => null]); $comparator = new Comparator(); self::assertEmpty($this->platform->getAlterTableSQL($comparator->diffTable($table, $diffTable))); } /** * {@inheritdoc} */ protected function getQuotedAlterTableRenameColumnSQL() : array { return ['ALTER TABLE mytable ' . "CHANGE unquoted1 unquoted INT NOT NULL COMMENT 'Unquoted 1', " . "CHANGE unquoted2 `where` INT NOT NULL COMMENT 'Unquoted 2', " . "CHANGE unquoted3 `foo` INT NOT NULL COMMENT 'Unquoted 3', " . "CHANGE `create` reserved_keyword INT NOT NULL COMMENT 'Reserved keyword 1', " . "CHANGE `table` `from` INT NOT NULL COMMENT 'Reserved keyword 2', " . "CHANGE `select` `bar` INT NOT NULL COMMENT 'Reserved keyword 3', " . "CHANGE quoted1 quoted INT NOT NULL COMMENT 'Quoted 1', " . "CHANGE quoted2 `and` INT NOT NULL COMMENT 'Quoted 2', " . "CHANGE quoted3 `baz` INT NOT NULL COMMENT 'Quoted 3'", ]; } /** * {@inheritdoc} */ protected function getQuotedAlterTableChangeColumnLengthSQL() : array { return ['ALTER TABLE mytable ' . "CHANGE unquoted1 unquoted1 VARCHAR(255) NOT NULL COMMENT 'Unquoted 1', " . "CHANGE unquoted2 unquoted2 VARCHAR(255) NOT NULL COMMENT 'Unquoted 2', " . "CHANGE unquoted3 unquoted3 VARCHAR(255) NOT NULL COMMENT 'Unquoted 3', " . "CHANGE `create` `create` VARCHAR(255) NOT NULL COMMENT 'Reserved keyword 1', " . "CHANGE `table` `table` VARCHAR(255) NOT NULL COMMENT 'Reserved keyword 2', " . "CHANGE `select` `select` VARCHAR(255) NOT NULL COMMENT 'Reserved keyword 3'", ]; } /** * @group DBAL-423 */ public function testReturnsGuidTypeDeclarationSQL() : void { self::assertSame('CHAR(36)', $this->platform->getGuidTypeDeclarationSQL([])); } /** * {@inheritdoc} */ public function getAlterTableRenameColumnSQL() : array { return ["ALTER TABLE foo CHANGE bar baz INT DEFAULT 666 NOT NULL COMMENT 'rename test'"]; } /** * {@inheritdoc} */ protected function getQuotesTableIdentifiersInAlterTableSQL() : array { return [ 'ALTER TABLE `foo` DROP FOREIGN KEY fk1', 'ALTER TABLE `foo` DROP FOREIGN KEY fk2', 'ALTER TABLE `foo` RENAME TO `table`, ADD bloo INT NOT NULL, DROP baz, CHANGE bar bar INT DEFAULT NULL, ' . 'CHANGE id war INT NOT NULL', 'ALTER TABLE `table` ADD CONSTRAINT fk_add FOREIGN KEY (fk3) REFERENCES fk_table (id)', 'ALTER TABLE `table` ADD CONSTRAINT fk2 FOREIGN KEY (fk2) REFERENCES fk_table2 (id)', ]; } /** * {@inheritdoc} */ protected function getCommentOnColumnSQL() : array { return [ "COMMENT ON COLUMN foo.bar IS 'comment'", "COMMENT ON COLUMN `Foo`.`BAR` IS 'comment'", "COMMENT ON COLUMN `select`.`from` IS 'comment'", ]; } /** * {@inheritdoc} */ protected function getQuotesReservedKeywordInUniqueConstraintDeclarationSQL() : string { return 'CONSTRAINT `select` UNIQUE (foo)'; } /** * {@inheritdoc} */ protected function getQuotesReservedKeywordInIndexDeclarationSQL() : string { return 'INDEX `select` (foo)'; } /** * {@inheritdoc} */ protected function getQuotesReservedKeywordInTruncateTableSQL() : string { return 'TRUNCATE `select`'; } /** * {@inheritdoc} */ protected function getAlterStringToFixedStringSQL() : array { return ['ALTER TABLE mytable CHANGE name name CHAR(2) NOT NULL']; } /** * {@inheritdoc} */ protected function getGeneratesAlterTableRenameIndexUsedByForeignKeySQL() : array { return [ 'ALTER TABLE mytable DROP FOREIGN KEY fk_foo', 'DROP INDEX idx_foo ON mytable', 'CREATE INDEX idx_foo_renamed ON mytable (foo)', 'ALTER TABLE mytable ADD CONSTRAINT fk_foo FOREIGN KEY (foo) REFERENCES foreign_table (id)', ]; } /** * {@inheritdoc} */ public static function getGeneratesDecimalTypeDeclarationSQL() : iterable { return [ [[], 'NUMERIC(10, 0)'], [['unsigned' => true], 'NUMERIC(10, 0) UNSIGNED'], [['unsigned' => false], 'NUMERIC(10, 0)'], [['precision' => 5], 'NUMERIC(5, 0)'], [['scale' => 5], 'NUMERIC(10, 5)'], [['precision' => 8, 'scale' => 2], 'NUMERIC(8, 2)'], ]; } /** * {@inheritdoc} */ public static function getGeneratesFloatDeclarationSQL() : iterable { return [ [[], 'DOUBLE PRECISION'], [['unsigned' => true], 'DOUBLE PRECISION UNSIGNED'], [['unsigned' => false], 'DOUBLE PRECISION'], [['precision' => 5], 'DOUBLE PRECISION'], [['scale' => 5], 'DOUBLE PRECISION'], [['precision' => 8, 'scale' => 2], 'DOUBLE PRECISION'], ]; } /** * @group DBAL-2436 */ public function testQuotesTableNameInListTableIndexesSQL() : void { self::assertStringContainsStringIgnoringCase( "'Foo''Bar\\\\'", $this->platform->getListTableIndexesSQL("Foo'Bar\\", 'foo_db') ); } /** * @group DBAL-2436 */ public function testQuotesDatabaseNameInListTableIndexesSQL() : void { self::assertStringContainsStringIgnoringCase( "'Foo''Bar\\\\'", $this->platform->getListTableIndexesSQL('foo_table', "Foo'Bar\\") ); } /** * @group DBAL-2436 */ public function testQuotesDatabaseNameInListViewsSQL() : void { self::assertStringContainsStringIgnoringCase( "'Foo''Bar\\\\'", $this->platform->getListViewsSQL("Foo'Bar\\") ); } /** * @group DBAL-2436 */ public function testQuotesTableNameInListTableForeignKeysSQL() : void { self::assertStringContainsStringIgnoringCase( "'Foo''Bar\\\\'", $this->platform->getListTableForeignKeysSQL("Foo'Bar\\") ); } /** * @group DBAL-2436 */ public function testQuotesDatabaseNameInListTableForeignKeysSQL() : void { self::assertStringContainsStringIgnoringCase( "'Foo''Bar\\\\'", $this->platform->getListTableForeignKeysSQL('foo_table', "Foo'Bar\\") ); } /** * @group DBAL-2436 */ public function testQuotesTableNameInListTableColumnsSQL() : void { self::assertStringContainsStringIgnoringCase( "'Foo''Bar\\\\'", $this->platform->getListTableColumnsSQL("Foo'Bar\\") ); } /** * @group DBAL-2436 */ public function testQuotesDatabaseNameInListTableColumnsSQL() : void { self::assertStringContainsStringIgnoringCase( "'Foo''Bar\\\\'", $this->platform->getListTableColumnsSQL('foo_table', "Foo'Bar\\") ); } public function testListTableForeignKeysSQLEvaluatesDatabase() : void { $sql = $this->platform->getListTableForeignKeysSQL('foo'); self::assertStringContainsString('DATABASE()', $sql); $sql = $this->platform->getListTableForeignKeysSQL('foo', 'bar'); self::assertStringContainsString('bar', $sql); self::assertStringNotContainsString('DATABASE()', $sql); } public function testColumnCharsetDeclarationSQL() : void { self::assertSame( 'CHARACTER SET ascii', $this->platform->getColumnCharsetDeclarationSQL('ascii') ); } public function testSupportsColumnCollation() : void { self::assertTrue($this->platform->supportsColumnCollation()); } public function testColumnCollationDeclarationSQL() : void { self::assertSame( 'COLLATE `ascii_general_ci`', $this->platform->getColumnCollationDeclarationSQL('ascii_general_ci') ); } public function testGetCreateTableSQLWithColumnCollation() : void { $table = new Table('foo'); $table->addColumn('no_collation', 'string'); $table->addColumn('column_collation', 'string')->setPlatformOption('collation', 'ascii_general_ci'); self::assertSame( ['CREATE TABLE foo (no_collation VARCHAR(255) NOT NULL, column_collation VARCHAR(255) NOT NULL COLLATE `ascii_general_ci`) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB'], $this->platform->getCreateTableSQL($table), 'Column "no_collation" will use the default collation from the table/database and "column_collation" overwrites the collation on this column' ); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Platforms/AbstractPlatformTestCase.php000066400000000000000000001462531360544566000312140ustar00rootroot00000000000000platform = $this->createPlatform(); } /** * @group DDC-1360 */ public function testQuoteIdentifier() : void { if ($this->platform->getName() === 'mssql') { $this->markTestSkipped('Not working this way on mssql.'); } $c = $this->platform->getIdentifierQuoteCharacter(); self::assertEquals($c . 'test' . $c, $this->platform->quoteIdentifier('test')); self::assertEquals($c . 'test' . $c . '.' . $c . 'test' . $c, $this->platform->quoteIdentifier('test.test')); self::assertEquals(str_repeat($c, 4), $this->platform->quoteIdentifier($c)); } /** * @group DDC-1360 */ public function testQuoteSingleIdentifier() : void { if ($this->platform->getName() === 'mssql') { $this->markTestSkipped('Not working this way on mssql.'); } $c = $this->platform->getIdentifierQuoteCharacter(); self::assertEquals($c . 'test' . $c, $this->platform->quoteSingleIdentifier('test')); self::assertEquals($c . 'test.test' . $c, $this->platform->quoteSingleIdentifier('test.test')); self::assertEquals(str_repeat($c, 4), $this->platform->quoteSingleIdentifier($c)); } /** * @group DBAL-1029 * @dataProvider getReturnsForeignKeyReferentialActionSQL */ public function testReturnsForeignKeyReferentialActionSQL(string $action, string $expectedSQL) : void { self::assertSame($expectedSQL, $this->platform->getForeignKeyReferentialActionSQL($action)); } /** * @return mixed[][] */ public static function getReturnsForeignKeyReferentialActionSQL() : iterable { return [ ['CASCADE', 'CASCADE'], ['SET NULL', 'SET NULL'], ['NO ACTION', 'NO ACTION'], ['RESTRICT', 'RESTRICT'], ['SET DEFAULT', 'SET DEFAULT'], ['CaScAdE', 'CASCADE'], ]; } public function testGetInvalidForeignKeyReferentialActionSQL() : void { $this->expectException('InvalidArgumentException'); $this->platform->getForeignKeyReferentialActionSQL('unknown'); } public function testGetUnknownDoctrineMappingType() : void { $this->expectException(DBALException::class); $this->platform->getDoctrineTypeMapping('foobar'); } public function testRegisterDoctrineMappingType() : void { $this->platform->registerDoctrineTypeMapping('foo', 'integer'); self::assertEquals('integer', $this->platform->getDoctrineTypeMapping('foo')); } public function testRegisterUnknownDoctrineMappingType() : void { $this->expectException(DBALException::class); $this->platform->registerDoctrineTypeMapping('foo', 'bar'); } /** * @group DBAL-2594 */ public function testRegistersCommentedDoctrineMappingTypeImplicitly() : void { if (! Type::hasType('my_commented')) { Type::addType('my_commented', CommentedType::class); } $type = Type::getType('my_commented'); $this->platform->registerDoctrineTypeMapping('foo', 'my_commented'); self::assertTrue($this->platform->isCommentedDoctrineType($type)); } /** * @group DBAL-939 * @dataProvider getIsCommentedDoctrineType */ public function testIsCommentedDoctrineType(Type $type, bool $commented) : void { self::assertSame($commented, $this->platform->isCommentedDoctrineType($type)); } /** * @return mixed[] */ public function getIsCommentedDoctrineType() : iterable { $this->setUp(); $data = []; foreach (Type::getTypesMap() as $typeName => $className) { $type = Type::getType($typeName); $data[$typeName] = [ $type, $type->requiresSQLCommentHint($this->platform), ]; } return $data; } public function testCreateWithNoColumns() : void { $table = new Table('test'); $this->expectException(DBALException::class); $sql = $this->platform->getCreateTableSQL($table); } public function testGeneratesTableCreationSql() : void { $table = new Table('test'); $table->addColumn('id', 'integer', ['notnull' => true, 'autoincrement' => true]); $table->addColumn('test', 'string', ['notnull' => false, 'length' => 255]); $table->setPrimaryKey(['id']); $sql = $this->platform->getCreateTableSQL($table); self::assertEquals($this->getGenerateTableSql(), $sql[0]); } abstract public function getGenerateTableSql() : string; public function testGenerateTableWithMultiColumnUniqueIndex() : void { $table = new Table('test'); $table->addColumn('foo', 'string', ['notnull' => false, 'length' => 255]); $table->addColumn('bar', 'string', ['notnull' => false, 'length' => 255]); $table->addUniqueIndex(['foo', 'bar']); $sql = $this->platform->getCreateTableSQL($table); self::assertEquals($this->getGenerateTableWithMultiColumnUniqueIndexSql(), $sql); } /** * @return string[] */ abstract public function getGenerateTableWithMultiColumnUniqueIndexSql() : array; public function testGeneratesIndexCreationSql() : void { $indexDef = new Index('my_idx', ['user_name', 'last_login']); self::assertEquals( $this->getGenerateIndexSql(), $this->platform->getCreateIndexSQL($indexDef, 'mytable') ); } abstract public function getGenerateIndexSql() : string; public function testGeneratesUniqueIndexCreationSql() : void { $indexDef = new Index('index_name', ['test', 'test2'], true); $sql = $this->platform->getCreateIndexSQL($indexDef, 'test'); self::assertEquals($this->getGenerateUniqueIndexSql(), $sql); } abstract public function getGenerateUniqueIndexSql() : string; public function testGeneratesPartialIndexesSqlOnlyWhenSupportingPartialIndexes() : void { $where = 'test IS NULL AND test2 IS NOT NULL'; $indexDef = new Index('name', ['test', 'test2'], false, false, [], ['where' => $where]); $uniqueIndex = new Index('name', ['test', 'test2'], true, false, [], ['where' => $where]); $expected = ' WHERE ' . $where; $actuals = []; if ($this->supportsInlineIndexDeclaration()) { $actuals[] = $this->platform->getIndexDeclarationSQL('name', $indexDef); } $actuals[] = $this->platform->getUniqueConstraintDeclarationSQL('name', $uniqueIndex); $actuals[] = $this->platform->getCreateIndexSQL($indexDef, 'table'); foreach ($actuals as $actual) { if ($this->platform->supportsPartialIndexes()) { self::assertStringEndsWith($expected, $actual, 'WHERE clause should be present'); } else { self::assertStringEndsNotWith($expected, $actual, 'WHERE clause should NOT be present'); } } } public function testGeneratesForeignKeyCreationSql() : void { $fk = new ForeignKeyConstraint(['fk_name_id'], 'other_table', ['id'], ''); $sql = $this->platform->getCreateForeignKeySQL($fk, 'test'); self::assertEquals($sql, $this->getGenerateForeignKeySql()); } abstract public function getGenerateForeignKeySql() : string; public function testGeneratesConstraintCreationSql() : void { $idx = new Index('constraint_name', ['test'], true, false); $sql = $this->platform->getCreateConstraintSQL($idx, 'test'); self::assertEquals($this->getGenerateConstraintUniqueIndexSql(), $sql); $pk = new Index('constraint_name', ['test'], true, true); $sql = $this->platform->getCreateConstraintSQL($pk, 'test'); self::assertEquals($this->getGenerateConstraintPrimaryIndexSql(), $sql); $fk = new ForeignKeyConstraint(['fk_name'], 'foreign', ['id'], 'constraint_fk'); $sql = $this->platform->getCreateConstraintSQL($fk, 'test'); self::assertEquals($this->getGenerateConstraintForeignKeySql($fk), $sql); } public function testGeneratesForeignKeySqlOnlyWhenSupportingForeignKeys() : void { $fk = new ForeignKeyConstraint(['fk_name'], 'foreign', ['id'], 'constraint_fk'); if ($this->platform->supportsForeignKeyConstraints()) { self::assertIsString($this->platform->getCreateForeignKeySQL($fk, 'test')); } else { $this->expectException(DBALException::class); $this->platform->getCreateForeignKeySQL($fk, 'test'); } } protected function getBitAndComparisonExpressionSql(string $value1, string $value2) : string { return '(' . $value1 . ' & ' . $value2 . ')'; } /** * @group DDC-1213 */ public function testGeneratesBitAndComparisonExpressionSql() : void { $sql = $this->platform->getBitAndComparisonExpression(2, 4); self::assertEquals($this->getBitAndComparisonExpressionSql(2, 4), $sql); } protected function getBitOrComparisonExpressionSql(string $value1, string $value2) : string { return '(' . $value1 . ' | ' . $value2 . ')'; } /** * @group DDC-1213 */ public function testGeneratesBitOrComparisonExpressionSql() : void { $sql = $this->platform->getBitOrComparisonExpression(2, 4); self::assertEquals($this->getBitOrComparisonExpressionSql(2, 4), $sql); } public function getGenerateConstraintUniqueIndexSql() : string { return 'ALTER TABLE test ADD CONSTRAINT constraint_name UNIQUE (test)'; } public function getGenerateConstraintPrimaryIndexSql() : string { return 'ALTER TABLE test ADD CONSTRAINT constraint_name PRIMARY KEY (test)'; } public function getGenerateConstraintForeignKeySql(ForeignKeyConstraint $fk) : string { $quotedForeignTable = $fk->getQuotedForeignTableName($this->platform); return sprintf( 'ALTER TABLE test ADD CONSTRAINT constraint_fk FOREIGN KEY (fk_name) REFERENCES %s (id)', $quotedForeignTable ); } /** * @return string[] */ abstract public function getGenerateAlterTableSql() : array; public function testGeneratesTableAlterationSql() : void { $expectedSql = $this->getGenerateAlterTableSql(); $table = new Table('mytable'); $table->addColumn('id', 'integer', ['autoincrement' => true]); $table->addColumn('foo', 'integer'); $table->addColumn('bar', 'string'); $table->addColumn('bloo', 'boolean'); $table->setPrimaryKey(['id']); $tableDiff = new TableDiff('mytable'); $tableDiff->fromTable = $table; $tableDiff->newName = 'userlist'; $tableDiff->addedColumns['quota'] = new Column('quota', Type::getType('integer'), ['notnull' => false]); $tableDiff->removedColumns['foo'] = new Column('foo', Type::getType('integer')); $tableDiff->changedColumns['bar'] = new ColumnDiff( 'bar', new Column( 'baz', Type::getType('string'), ['default' => 'def'] ), ['type', 'notnull', 'default'] ); $tableDiff->changedColumns['bloo'] = new ColumnDiff( 'bloo', new Column( 'bloo', Type::getType('boolean'), ['default' => false] ), ['type', 'notnull', 'default'] ); $sql = $this->platform->getAlterTableSQL($tableDiff); self::assertEquals($expectedSql, $sql); } public function testGetCustomColumnDeclarationSql() : void { $field = ['columnDefinition' => 'MEDIUMINT(6) UNSIGNED']; self::assertEquals('foo MEDIUMINT(6) UNSIGNED', $this->platform->getColumnDeclarationSQL('foo', $field)); } public function testGetCreateTableSqlDispatchEvent() : void { $listenerMock = $this->getMockBuilder($this->getMockClass('GetCreateTableSqlDispatchEvenListener')) ->addMethods(['onSchemaCreateTable', 'onSchemaCreateTableColumn']) ->getMock(); $listenerMock ->expects($this->once()) ->method('onSchemaCreateTable'); $listenerMock ->expects($this->exactly(2)) ->method('onSchemaCreateTableColumn'); $eventManager = new EventManager(); $eventManager->addEventListener([Events::onSchemaCreateTable, Events::onSchemaCreateTableColumn], $listenerMock); $this->platform->setEventManager($eventManager); $table = new Table('test'); $table->addColumn('foo', 'string', ['notnull' => false, 'length' => 255]); $table->addColumn('bar', 'string', ['notnull' => false, 'length' => 255]); $this->platform->getCreateTableSQL($table); } public function testGetDropTableSqlDispatchEvent() : void { $listenerMock = $this->getMockBuilder($this->getMockClass('GetDropTableSqlDispatchEventListener')) ->addMethods(['onSchemaDropTable']) ->getMock(); $listenerMock ->expects($this->once()) ->method('onSchemaDropTable'); $eventManager = new EventManager(); $eventManager->addEventListener([Events::onSchemaDropTable], $listenerMock); $this->platform->setEventManager($eventManager); $this->platform->getDropTableSQL('TABLE'); } public function testGetAlterTableSqlDispatchEvent() : void { $events = [ 'onSchemaAlterTable', 'onSchemaAlterTableAddColumn', 'onSchemaAlterTableRemoveColumn', 'onSchemaAlterTableChangeColumn', 'onSchemaAlterTableRenameColumn', ]; $listenerMock = $this->getMockBuilder($this->getMockClass('GetAlterTableSqlDispatchEvenListener')) ->addMethods($events) ->getMock(); $listenerMock ->expects($this->once()) ->method('onSchemaAlterTable'); $listenerMock ->expects($this->once()) ->method('onSchemaAlterTableAddColumn'); $listenerMock ->expects($this->once()) ->method('onSchemaAlterTableRemoveColumn'); $listenerMock ->expects($this->once()) ->method('onSchemaAlterTableChangeColumn'); $listenerMock ->expects($this->once()) ->method('onSchemaAlterTableRenameColumn'); $eventManager = new EventManager(); $events = [ Events::onSchemaAlterTable, Events::onSchemaAlterTableAddColumn, Events::onSchemaAlterTableRemoveColumn, Events::onSchemaAlterTableChangeColumn, Events::onSchemaAlterTableRenameColumn, ]; $eventManager->addEventListener($events, $listenerMock); $this->platform->setEventManager($eventManager); $table = new Table('mytable'); $table->addColumn('removed', 'integer'); $table->addColumn('changed', 'integer'); $table->addColumn('renamed', 'integer'); $tableDiff = new TableDiff('mytable'); $tableDiff->fromTable = $table; $tableDiff->addedColumns['added'] = new Column('added', Type::getType('integer'), []); $tableDiff->removedColumns['removed'] = new Column('removed', Type::getType('integer'), []); $tableDiff->changedColumns['changed'] = new ColumnDiff( 'changed', new Column( 'changed2', Type::getType('string'), [] ), [] ); $tableDiff->renamedColumns['renamed'] = new Column('renamed2', Type::getType('integer'), []); $this->platform->getAlterTableSQL($tableDiff); } /** * @group DBAL-42 */ public function testCreateTableColumnComments() : void { $table = new Table('test'); $table->addColumn('id', 'integer', ['comment' => 'This is a comment']); $table->setPrimaryKey(['id']); self::assertEquals($this->getCreateTableColumnCommentsSQL(), $this->platform->getCreateTableSQL($table)); } /** * @group DBAL-42 */ public function testAlterTableColumnComments() : void { $tableDiff = new TableDiff('mytable'); $tableDiff->addedColumns['quota'] = new Column('quota', Type::getType('integer'), ['comment' => 'A comment']); $tableDiff->changedColumns['foo'] = new ColumnDiff( 'foo', new Column( 'foo', Type::getType('string') ), ['comment'] ); $tableDiff->changedColumns['bar'] = new ColumnDiff( 'bar', new Column( 'baz', Type::getType('string'), ['comment' => 'B comment'] ), ['comment'] ); self::assertEquals($this->getAlterTableColumnCommentsSQL(), $this->platform->getAlterTableSQL($tableDiff)); } public function testCreateTableColumnTypeComments() : void { $table = new Table('test'); $table->addColumn('id', 'integer'); $table->addColumn('data', 'array'); $table->setPrimaryKey(['id']); self::assertEquals($this->getCreateTableColumnTypeCommentsSQL(), $this->platform->getCreateTableSQL($table)); } /** * @return string[] */ public function getCreateTableColumnCommentsSQL() : array { $this->markTestSkipped('Platform does not support Column comments.'); } /** * @return string[] */ public function getAlterTableColumnCommentsSQL() : array { $this->markTestSkipped('Platform does not support Column comments.'); } /** * @return string[] */ public function getCreateTableColumnTypeCommentsSQL() : array { $this->markTestSkipped('Platform does not support Column comments.'); } public function testGetDefaultValueDeclarationSQL() : void { // non-timestamp value will get single quotes $field = [ 'type' => Type::getType('string'), 'default' => 'non_timestamp', ]; self::assertEquals(" DEFAULT 'non_timestamp'", $this->platform->getDefaultValueDeclarationSQL($field)); } /** * @group 2859 */ public function testGetDefaultValueDeclarationSQLDateTime() : void { // timestamps on datetime types should not be quoted foreach (['datetime', 'datetimetz', 'datetime_immutable', 'datetimetz_immutable'] as $type) { $field = [ 'type' => Type::getType($type), 'default' => $this->platform->getCurrentTimestampSQL(), ]; self::assertSame( ' DEFAULT ' . $this->platform->getCurrentTimestampSQL(), $this->platform->getDefaultValueDeclarationSQL($field) ); } } public function testGetDefaultValueDeclarationSQLForIntegerTypes() : void { foreach (['bigint', 'integer', 'smallint'] as $type) { $field = [ 'type' => Type::getType($type), 'default' => 1, ]; self::assertEquals( ' DEFAULT 1', $this->platform->getDefaultValueDeclarationSQL($field) ); } } /** * @group 2859 */ public function testGetDefaultValueDeclarationSQLForDateType() : void { $currentDateSql = $this->platform->getCurrentDateSQL(); foreach (['date', 'date_immutable'] as $type) { $field = [ 'type' => Type::getType($type), 'default' => $currentDateSql, ]; self::assertSame( ' DEFAULT ' . $currentDateSql, $this->platform->getDefaultValueDeclarationSQL($field) ); } } /** * @group DBAL-45 */ public function testKeywordList() : void { $keywordList = $this->platform->getReservedKeywordsList(); self::assertInstanceOf(KeywordList::class, $keywordList); self::assertTrue($keywordList->isKeyword('table')); } /** * @group DBAL-374 */ public function testQuotedColumnInPrimaryKeyPropagation() : void { $table = new Table('`quoted`'); $table->addColumn('create', 'string'); $table->setPrimaryKey(['create']); $sql = $this->platform->getCreateTableSQL($table); self::assertEquals($this->getQuotedColumnInPrimaryKeySQL(), $sql); } /** * @return string[] */ abstract protected function getQuotedColumnInPrimaryKeySQL() : array; /** * @return string[] */ abstract protected function getQuotedColumnInIndexSQL() : array; /** * @return string[] */ abstract protected function getQuotedNameInIndexSQL() : array; /** * @return string[] */ abstract protected function getQuotedColumnInForeignKeySQL() : array; /** * @group DBAL-374 */ public function testQuotedColumnInIndexPropagation() : void { $table = new Table('`quoted`'); $table->addColumn('create', 'string'); $table->addIndex(['create']); $sql = $this->platform->getCreateTableSQL($table); self::assertEquals($this->getQuotedColumnInIndexSQL(), $sql); } public function testQuotedNameInIndexSQL() : void { $table = new Table('test'); $table->addColumn('column1', 'string'); $table->addIndex(['column1'], '`key`'); $sql = $this->platform->getCreateTableSQL($table); self::assertEquals($this->getQuotedNameInIndexSQL(), $sql); } /** * @group DBAL-374 */ public function testQuotedColumnInForeignKeyPropagation() : void { $table = new Table('`quoted`'); $table->addColumn('create', 'string'); $table->addColumn('foo', 'string'); $table->addColumn('`bar`', 'string'); // Foreign table with reserved keyword as name (needs quotation). $foreignTable = new Table('foreign'); $foreignTable->addColumn('create', 'string'); // Foreign column with reserved keyword as name (needs quotation). $foreignTable->addColumn('bar', 'string'); // Foreign column with non-reserved keyword as name (does not need quotation). $foreignTable->addColumn('`foo-bar`', 'string'); // Foreign table with special character in name (needs quotation on some platforms, e.g. Sqlite). $table->addForeignKeyConstraint($foreignTable, ['create', 'foo', '`bar`'], ['create', 'bar', '`foo-bar`'], [], 'FK_WITH_RESERVED_KEYWORD'); // Foreign table with non-reserved keyword as name (does not need quotation). $foreignTable = new Table('foo'); $foreignTable->addColumn('create', 'string'); // Foreign column with reserved keyword as name (needs quotation). $foreignTable->addColumn('bar', 'string'); // Foreign column with non-reserved keyword as name (does not need quotation). $foreignTable->addColumn('`foo-bar`', 'string'); // Foreign table with special character in name (needs quotation on some platforms, e.g. Sqlite). $table->addForeignKeyConstraint($foreignTable, ['create', 'foo', '`bar`'], ['create', 'bar', '`foo-bar`'], [], 'FK_WITH_NON_RESERVED_KEYWORD'); // Foreign table with special character in name (needs quotation on some platforms, e.g. Sqlite). $foreignTable = new Table('`foo-bar`'); $foreignTable->addColumn('create', 'string'); // Foreign column with reserved keyword as name (needs quotation). $foreignTable->addColumn('bar', 'string'); // Foreign column with non-reserved keyword as name (does not need quotation). $foreignTable->addColumn('`foo-bar`', 'string'); // Foreign table with special character in name (needs quotation on some platforms, e.g. Sqlite). $table->addForeignKeyConstraint($foreignTable, ['create', 'foo', '`bar`'], ['create', 'bar', '`foo-bar`'], [], 'FK_WITH_INTENDED_QUOTATION'); $sql = $this->platform->getCreateTableSQL($table, AbstractPlatform::CREATE_FOREIGNKEYS); self::assertEquals($this->getQuotedColumnInForeignKeySQL(), $sql); } /** * @group DBAL-1051 */ public function testQuotesReservedKeywordInUniqueConstraintDeclarationSQL() : void { $index = new Index('select', ['foo'], true); self::assertSame( $this->getQuotesReservedKeywordInUniqueConstraintDeclarationSQL(), $this->platform->getUniqueConstraintDeclarationSQL('select', $index) ); } abstract protected function getQuotesReservedKeywordInUniqueConstraintDeclarationSQL() : string; /** * @group DBAL-2270 */ public function testQuotesReservedKeywordInTruncateTableSQL() : void { self::assertSame( $this->getQuotesReservedKeywordInTruncateTableSQL(), $this->platform->getTruncateTableSQL('select') ); } abstract protected function getQuotesReservedKeywordInTruncateTableSQL() : string; /** * @group DBAL-1051 */ public function testQuotesReservedKeywordInIndexDeclarationSQL() : void { $index = new Index('select', ['foo']); if (! $this->supportsInlineIndexDeclaration()) { $this->expectException(DBALException::class); } self::assertSame( $this->getQuotesReservedKeywordInIndexDeclarationSQL(), $this->platform->getIndexDeclarationSQL('select', $index) ); } abstract protected function getQuotesReservedKeywordInIndexDeclarationSQL() : string; protected function supportsInlineIndexDeclaration() : bool { return true; } public function testSupportsCommentOnStatement() : void { self::assertSame($this->supportsCommentOnStatement(), $this->platform->supportsCommentOnStatement()); } protected function supportsCommentOnStatement() : bool { return false; } public function testGetCreateSchemaSQL() : void { $this->expectException(DBALException::class); $this->platform->getCreateSchemaSQL('schema'); } /** * @group DBAL-585 */ public function testAlterTableChangeQuotedColumn() : void { $tableDiff = new TableDiff('mytable'); $tableDiff->fromTable = new Table('mytable'); $tableDiff->changedColumns['foo'] = new ColumnDiff( 'select', new Column( 'select', Type::getType('string') ), ['type'] ); self::assertStringContainsString( $this->platform->quoteIdentifier('select'), implode(';', $this->platform->getAlterTableSQL($tableDiff)) ); } /** * @group DBAL-563 */ public function testUsesSequenceEmulatedIdentityColumns() : void { self::assertFalse($this->platform->usesSequenceEmulatedIdentityColumns()); } /** * @group DBAL-563 */ public function testReturnsIdentitySequenceName() : void { $this->expectException(DBALException::class); $this->platform->getIdentitySequenceName('mytable', 'mycolumn'); } public function testReturnsBinaryDefaultLength() : void { self::assertSame($this->getBinaryDefaultLength(), $this->platform->getBinaryDefaultLength()); } protected function getBinaryDefaultLength() : int { return 255; } public function testReturnsBinaryMaxLength() : void { self::assertSame($this->getBinaryMaxLength(), $this->platform->getBinaryMaxLength()); } protected function getBinaryMaxLength() : int { return 4000; } public function testReturnsBinaryTypeDeclarationSQL() : void { $this->expectException(DBALException::class); $this->platform->getBinaryTypeDeclarationSQL([]); } public function testReturnsBinaryTypeLongerThanMaxDeclarationSQL() : void { $this->markTestSkipped('Not applicable to the platform'); } /** * @group DBAL-553 */ public function hasNativeJsonType() : void { self::assertFalse($this->platform->hasNativeJsonType()); } /** * @group DBAL-553 */ public function testReturnsJsonTypeDeclarationSQL() : void { $column = [ 'length' => 666, 'notnull' => true, 'type' => Type::getType('json_array'), ]; self::assertSame( $this->platform->getClobTypeDeclarationSQL($column), $this->platform->getJsonTypeDeclarationSQL($column) ); } /** * @group DBAL-234 */ public function testAlterTableRenameIndex() : void { $tableDiff = new TableDiff('mytable'); $tableDiff->fromTable = new Table('mytable'); $tableDiff->fromTable->addColumn('id', 'integer'); $tableDiff->fromTable->setPrimaryKey(['id']); $tableDiff->renamedIndexes = [ 'idx_foo' => new Index('idx_bar', ['id']), ]; self::assertSame( $this->getAlterTableRenameIndexSQL(), $this->platform->getAlterTableSQL($tableDiff) ); } /** * @return string[] * * @group DBAL-234 */ protected function getAlterTableRenameIndexSQL() : array { return [ 'DROP INDEX idx_foo', 'CREATE INDEX idx_bar ON mytable (id)', ]; } /** * @group DBAL-234 */ public function testQuotesAlterTableRenameIndex() : void { $tableDiff = new TableDiff('table'); $tableDiff->fromTable = new Table('table'); $tableDiff->fromTable->addColumn('id', 'integer'); $tableDiff->fromTable->setPrimaryKey(['id']); $tableDiff->renamedIndexes = [ 'create' => new Index('select', ['id']), '`foo`' => new Index('`bar`', ['id']), ]; self::assertSame( $this->getQuotedAlterTableRenameIndexSQL(), $this->platform->getAlterTableSQL($tableDiff) ); } /** * @return string[] * * @group DBAL-234 */ protected function getQuotedAlterTableRenameIndexSQL() : array { return [ 'DROP INDEX "create"', 'CREATE INDEX "select" ON "table" (id)', 'DROP INDEX "foo"', 'CREATE INDEX "bar" ON "table" (id)', ]; } /** * @group DBAL-835 */ public function testQuotesAlterTableRenameColumn() : void { $fromTable = new Table('mytable'); $fromTable->addColumn('unquoted1', 'integer', ['comment' => 'Unquoted 1']); $fromTable->addColumn('unquoted2', 'integer', ['comment' => 'Unquoted 2']); $fromTable->addColumn('unquoted3', 'integer', ['comment' => 'Unquoted 3']); $fromTable->addColumn('create', 'integer', ['comment' => 'Reserved keyword 1']); $fromTable->addColumn('table', 'integer', ['comment' => 'Reserved keyword 2']); $fromTable->addColumn('select', 'integer', ['comment' => 'Reserved keyword 3']); $fromTable->addColumn('`quoted1`', 'integer', ['comment' => 'Quoted 1']); $fromTable->addColumn('`quoted2`', 'integer', ['comment' => 'Quoted 2']); $fromTable->addColumn('`quoted3`', 'integer', ['comment' => 'Quoted 3']); $toTable = new Table('mytable'); $toTable->addColumn('unquoted', 'integer', ['comment' => 'Unquoted 1']); // unquoted -> unquoted $toTable->addColumn('where', 'integer', ['comment' => 'Unquoted 2']); // unquoted -> reserved keyword $toTable->addColumn('`foo`', 'integer', ['comment' => 'Unquoted 3']); // unquoted -> quoted $toTable->addColumn('reserved_keyword', 'integer', ['comment' => 'Reserved keyword 1']); // reserved keyword -> unquoted $toTable->addColumn('from', 'integer', ['comment' => 'Reserved keyword 2']); // reserved keyword -> reserved keyword $toTable->addColumn('`bar`', 'integer', ['comment' => 'Reserved keyword 3']); // reserved keyword -> quoted $toTable->addColumn('quoted', 'integer', ['comment' => 'Quoted 1']); // quoted -> unquoted $toTable->addColumn('and', 'integer', ['comment' => 'Quoted 2']); // quoted -> reserved keyword $toTable->addColumn('`baz`', 'integer', ['comment' => 'Quoted 3']); // quoted -> quoted $comparator = new Comparator(); self::assertEquals( $this->getQuotedAlterTableRenameColumnSQL(), $this->platform->getAlterTableSQL($comparator->diffTable($fromTable, $toTable)) ); } /** * Returns SQL statements for {@link testQuotesAlterTableRenameColumn}. * * @return string[] * * @group DBAL-835 */ abstract protected function getQuotedAlterTableRenameColumnSQL() : array; /** * @group DBAL-835 */ public function testQuotesAlterTableChangeColumnLength() : void { $fromTable = new Table('mytable'); $fromTable->addColumn('unquoted1', 'string', ['comment' => 'Unquoted 1', 'length' => 10]); $fromTable->addColumn('unquoted2', 'string', ['comment' => 'Unquoted 2', 'length' => 10]); $fromTable->addColumn('unquoted3', 'string', ['comment' => 'Unquoted 3', 'length' => 10]); $fromTable->addColumn('create', 'string', ['comment' => 'Reserved keyword 1', 'length' => 10]); $fromTable->addColumn('table', 'string', ['comment' => 'Reserved keyword 2', 'length' => 10]); $fromTable->addColumn('select', 'string', ['comment' => 'Reserved keyword 3', 'length' => 10]); $toTable = new Table('mytable'); $toTable->addColumn('unquoted1', 'string', ['comment' => 'Unquoted 1', 'length' => 255]); $toTable->addColumn('unquoted2', 'string', ['comment' => 'Unquoted 2', 'length' => 255]); $toTable->addColumn('unquoted3', 'string', ['comment' => 'Unquoted 3', 'length' => 255]); $toTable->addColumn('create', 'string', ['comment' => 'Reserved keyword 1', 'length' => 255]); $toTable->addColumn('table', 'string', ['comment' => 'Reserved keyword 2', 'length' => 255]); $toTable->addColumn('select', 'string', ['comment' => 'Reserved keyword 3', 'length' => 255]); $comparator = new Comparator(); self::assertEquals( $this->getQuotedAlterTableChangeColumnLengthSQL(), $this->platform->getAlterTableSQL($comparator->diffTable($fromTable, $toTable)) ); } /** * Returns SQL statements for {@link testQuotesAlterTableChangeColumnLength}. * * @return string[] * * @group DBAL-835 */ abstract protected function getQuotedAlterTableChangeColumnLengthSQL() : array; /** * @group DBAL-807 */ public function testAlterTableRenameIndexInSchema() : void { $tableDiff = new TableDiff('myschema.mytable'); $tableDiff->fromTable = new Table('myschema.mytable'); $tableDiff->fromTable->addColumn('id', 'integer'); $tableDiff->fromTable->setPrimaryKey(['id']); $tableDiff->renamedIndexes = [ 'idx_foo' => new Index('idx_bar', ['id']), ]; self::assertSame( $this->getAlterTableRenameIndexInSchemaSQL(), $this->platform->getAlterTableSQL($tableDiff) ); } /** * @return string[] * * @group DBAL-807 */ protected function getAlterTableRenameIndexInSchemaSQL() : array { return [ 'DROP INDEX idx_foo', 'CREATE INDEX idx_bar ON myschema.mytable (id)', ]; } /** * @group DBAL-807 */ public function testQuotesAlterTableRenameIndexInSchema() : void { $tableDiff = new TableDiff('`schema`.table'); $tableDiff->fromTable = new Table('`schema`.table'); $tableDiff->fromTable->addColumn('id', 'integer'); $tableDiff->fromTable->setPrimaryKey(['id']); $tableDiff->renamedIndexes = [ 'create' => new Index('select', ['id']), '`foo`' => new Index('`bar`', ['id']), ]; self::assertSame( $this->getQuotedAlterTableRenameIndexInSchemaSQL(), $this->platform->getAlterTableSQL($tableDiff) ); } /** * @return string[] * * @group DBAL-234 */ protected function getQuotedAlterTableRenameIndexInSchemaSQL() : array { return [ 'DROP INDEX "schema"."create"', 'CREATE INDEX "select" ON "schema"."table" (id)', 'DROP INDEX "schema"."foo"', 'CREATE INDEX "bar" ON "schema"."table" (id)', ]; } /** * @group DBAL-1237 */ public function testQuotesDropForeignKeySQL() : void { if (! $this->platform->supportsForeignKeyConstraints()) { $this->markTestSkipped( sprintf('%s does not support foreign key constraints.', get_class($this->platform)) ); } $tableName = 'table'; $table = new Table($tableName); $foreignKeyName = 'select'; $foreignKey = new ForeignKeyConstraint([], 'foo', [], 'select'); $expectedSql = $this->getQuotesDropForeignKeySQL(); self::assertSame($expectedSql, $this->platform->getDropForeignKeySQL($foreignKeyName, $tableName)); self::assertSame($expectedSql, $this->platform->getDropForeignKeySQL($foreignKey, $table)); } protected function getQuotesDropForeignKeySQL() : string { return 'ALTER TABLE "table" DROP FOREIGN KEY "select"'; } /** * @group DBAL-1237 */ public function testQuotesDropConstraintSQL() : void { $tableName = 'table'; $table = new Table($tableName); $constraintName = 'select'; $constraint = new ForeignKeyConstraint([], 'foo', [], 'select'); $expectedSql = $this->getQuotesDropConstraintSQL(); self::assertSame($expectedSql, $this->platform->getDropConstraintSQL($constraintName, $tableName)); self::assertSame($expectedSql, $this->platform->getDropConstraintSQL($constraint, $table)); } protected function getQuotesDropConstraintSQL() : string { return 'ALTER TABLE "table" DROP CONSTRAINT "select"'; } protected function getStringLiteralQuoteCharacter() : string { return "'"; } public function testGetStringLiteralQuoteCharacter() : void { self::assertSame($this->getStringLiteralQuoteCharacter(), $this->platform->getStringLiteralQuoteCharacter()); } protected function getQuotedCommentOnColumnSQLWithoutQuoteCharacter() : string { return "COMMENT ON COLUMN mytable.id IS 'This is a comment'"; } public function testGetCommentOnColumnSQLWithoutQuoteCharacter() : void { self::assertEquals( $this->getQuotedCommentOnColumnSQLWithoutQuoteCharacter(), $this->platform->getCommentOnColumnSQL('mytable', 'id', 'This is a comment') ); } protected function getQuotedCommentOnColumnSQLWithQuoteCharacter() : string { return "COMMENT ON COLUMN mytable.id IS 'It''s a quote !'"; } public function testGetCommentOnColumnSQLWithQuoteCharacter() : void { $c = $this->getStringLiteralQuoteCharacter(); self::assertEquals( $this->getQuotedCommentOnColumnSQLWithQuoteCharacter(), $this->platform->getCommentOnColumnSQL('mytable', 'id', 'It' . $c . 's a quote !') ); } /** * @see testGetCommentOnColumnSQL * * @return string[] */ abstract protected function getCommentOnColumnSQL() : array; /** * @group DBAL-1004 */ public function testGetCommentOnColumnSQL() : void { self::assertSame( $this->getCommentOnColumnSQL(), [ $this->platform->getCommentOnColumnSQL('foo', 'bar', 'comment'), // regular identifiers $this->platform->getCommentOnColumnSQL('`Foo`', '`BAR`', 'comment'), // explicitly quoted identifiers $this->platform->getCommentOnColumnSQL('select', 'from', 'comment'), // reserved keyword identifiers ] ); } /** * @group DBAL-1176 * @dataProvider getGeneratesInlineColumnCommentSQL */ public function testGeneratesInlineColumnCommentSQL(?string $comment, string $expectedSql) : void { if (! $this->platform->supportsInlineColumnComments()) { $this->markTestSkipped(sprintf('%s does not support inline column comments.', get_class($this->platform))); } self::assertSame($expectedSql, $this->platform->getInlineColumnCommentSQL($comment)); } /** * @return mixed[][] */ public static function getGeneratesInlineColumnCommentSQL() : iterable { return [ 'regular comment' => ['Regular comment', static::getInlineColumnRegularCommentSQL()], 'comment requiring escaping' => [ sprintf( 'Using inline comment delimiter %s works', static::getInlineColumnCommentDelimiter() ), static::getInlineColumnCommentRequiringEscapingSQL(), ], 'empty comment' => ['', static::getInlineColumnEmptyCommentSQL()], ]; } protected static function getInlineColumnCommentDelimiter() : string { return "'"; } protected static function getInlineColumnRegularCommentSQL() : string { return "COMMENT 'Regular comment'"; } protected static function getInlineColumnCommentRequiringEscapingSQL() : string { return "COMMENT 'Using inline comment delimiter '' works'"; } protected static function getInlineColumnEmptyCommentSQL() : string { return "COMMENT ''"; } protected function getQuotedStringLiteralWithoutQuoteCharacter() : string { return "'No quote'"; } protected function getQuotedStringLiteralWithQuoteCharacter() : string { return "'It''s a quote'"; } protected function getQuotedStringLiteralQuoteCharacter() : string { return "''''"; } /** * @group DBAL-1176 */ public function testThrowsExceptionOnGeneratingInlineColumnCommentSQLIfUnsupported() : void { if ($this->platform->supportsInlineColumnComments()) { $this->markTestSkipped(sprintf('%s supports inline column comments.', get_class($this->platform))); } $this->expectException(DBALException::class); $this->expectExceptionMessage("Operation 'Doctrine\\DBAL\\Platforms\\AbstractPlatform::getInlineColumnCommentSQL' is not supported by platform."); $this->expectExceptionCode(0); $this->platform->getInlineColumnCommentSQL('unsupported'); } public function testQuoteStringLiteral() : void { $c = $this->getStringLiteralQuoteCharacter(); self::assertEquals( $this->getQuotedStringLiteralWithoutQuoteCharacter(), $this->platform->quoteStringLiteral('No quote') ); self::assertEquals( $this->getQuotedStringLiteralWithQuoteCharacter(), $this->platform->quoteStringLiteral('It' . $c . 's a quote') ); self::assertEquals( $this->getQuotedStringLiteralQuoteCharacter(), $this->platform->quoteStringLiteral($c) ); } /** * @group DBAL-423 */ public function testReturnsGuidTypeDeclarationSQL() : void { $this->expectException(DBALException::class); $this->platform->getGuidTypeDeclarationSQL([]); } /** * @group DBAL-1010 */ public function testGeneratesAlterTableRenameColumnSQL() : void { $table = new Table('foo'); $table->addColumn( 'bar', 'integer', ['notnull' => true, 'default' => 666, 'comment' => 'rename test'] ); $tableDiff = new TableDiff('foo'); $tableDiff->fromTable = $table; $tableDiff->renamedColumns['bar'] = new Column( 'baz', Type::getType('integer'), ['notnull' => true, 'default' => 666, 'comment' => 'rename test'] ); self::assertSame($this->getAlterTableRenameColumnSQL(), $this->platform->getAlterTableSQL($tableDiff)); } /** * @return string[] */ abstract public function getAlterTableRenameColumnSQL() : array; /** * @group DBAL-1016 */ public function testQuotesTableIdentifiersInAlterTableSQL() : void { $table = new Table('"foo"'); $table->addColumn('id', 'integer'); $table->addColumn('fk', 'integer'); $table->addColumn('fk2', 'integer'); $table->addColumn('fk3', 'integer'); $table->addColumn('bar', 'integer'); $table->addColumn('baz', 'integer'); $table->addForeignKeyConstraint('fk_table', ['fk'], ['id'], [], 'fk1'); $table->addForeignKeyConstraint('fk_table', ['fk2'], ['id'], [], 'fk2'); $tableDiff = new TableDiff('"foo"'); $tableDiff->fromTable = $table; $tableDiff->newName = 'table'; $tableDiff->addedColumns['bloo'] = new Column('bloo', Type::getType('integer')); $tableDiff->changedColumns['bar'] = new ColumnDiff( 'bar', new Column('bar', Type::getType('integer'), ['notnull' => false]), ['notnull'], $table->getColumn('bar') ); $tableDiff->renamedColumns['id'] = new Column('war', Type::getType('integer')); $tableDiff->removedColumns['baz'] = new Column('baz', Type::getType('integer')); $tableDiff->addedForeignKeys[] = new ForeignKeyConstraint(['fk3'], 'fk_table', ['id'], 'fk_add'); $tableDiff->changedForeignKeys[] = new ForeignKeyConstraint(['fk2'], 'fk_table2', ['id'], 'fk2'); $tableDiff->removedForeignKeys[] = new ForeignKeyConstraint(['fk'], 'fk_table', ['id'], 'fk1'); self::assertSame( $this->getQuotesTableIdentifiersInAlterTableSQL(), $this->platform->getAlterTableSQL($tableDiff) ); } /** * @return string[] */ abstract protected function getQuotesTableIdentifiersInAlterTableSQL() : array; /** * @group DBAL-1090 */ public function testAlterStringToFixedString() : void { $table = new Table('mytable'); $table->addColumn('name', 'string', ['length' => 2]); $tableDiff = new TableDiff('mytable'); $tableDiff->fromTable = $table; $tableDiff->changedColumns['name'] = new ColumnDiff( 'name', new Column( 'name', Type::getType('string'), ['fixed' => true, 'length' => 2] ), ['fixed'] ); $sql = $this->platform->getAlterTableSQL($tableDiff); $expectedSql = $this->getAlterStringToFixedStringSQL(); self::assertEquals($expectedSql, $sql); } /** * @return string[] */ abstract protected function getAlterStringToFixedStringSQL() : array; /** * @group DBAL-1062 */ public function testGeneratesAlterTableRenameIndexUsedByForeignKeySQL() : void { $foreignTable = new Table('foreign_table'); $foreignTable->addColumn('id', 'integer'); $foreignTable->setPrimaryKey(['id']); $primaryTable = new Table('mytable'); $primaryTable->addColumn('foo', 'integer'); $primaryTable->addColumn('bar', 'integer'); $primaryTable->addColumn('baz', 'integer'); $primaryTable->addIndex(['foo'], 'idx_foo'); $primaryTable->addIndex(['bar'], 'idx_bar'); $primaryTable->addForeignKeyConstraint($foreignTable, ['foo'], ['id'], [], 'fk_foo'); $primaryTable->addForeignKeyConstraint($foreignTable, ['bar'], ['id'], [], 'fk_bar'); $tableDiff = new TableDiff('mytable'); $tableDiff->fromTable = $primaryTable; $tableDiff->renamedIndexes['idx_foo'] = new Index('idx_foo_renamed', ['foo']); self::assertSame( $this->getGeneratesAlterTableRenameIndexUsedByForeignKeySQL(), $this->platform->getAlterTableSQL($tableDiff) ); } /** * @return string[] */ abstract protected function getGeneratesAlterTableRenameIndexUsedByForeignKeySQL() : array; /** * @param mixed[] $column * * @group DBAL-1082 * @dataProvider getGeneratesDecimalTypeDeclarationSQL */ public function testGeneratesDecimalTypeDeclarationSQL(array $column, string $expectedSql) : void { self::assertSame($expectedSql, $this->platform->getDecimalTypeDeclarationSQL($column)); } /** * @return mixed[][] */ public static function getGeneratesDecimalTypeDeclarationSQL() : iterable { return [ [[], 'NUMERIC(10, 0)'], [['unsigned' => true], 'NUMERIC(10, 0)'], [['unsigned' => false], 'NUMERIC(10, 0)'], [['precision' => 5], 'NUMERIC(5, 0)'], [['scale' => 5], 'NUMERIC(10, 5)'], [['precision' => 8, 'scale' => 2], 'NUMERIC(8, 2)'], ]; } /** * @param mixed[] $column * * @group DBAL-1082 * @dataProvider getGeneratesFloatDeclarationSQL */ public function testGeneratesFloatDeclarationSQL(array $column, string $expectedSql) : void { self::assertSame($expectedSql, $this->platform->getFloatDeclarationSQL($column)); } /** * @return mixed[][] */ public static function getGeneratesFloatDeclarationSQL() : iterable { return [ [[], 'DOUBLE PRECISION'], [['unsigned' => true], 'DOUBLE PRECISION'], [['unsigned' => false], 'DOUBLE PRECISION'], [['precision' => 5], 'DOUBLE PRECISION'], [['scale' => 5], 'DOUBLE PRECISION'], [['precision' => 8, 'scale' => 2], 'DOUBLE PRECISION'], ]; } public function testItEscapesStringsForLike() : void { self::assertSame( '\_25\% off\_ your next purchase \\\\o/', $this->platform->escapeStringForLike('_25% off_ your next purchase \o/', '\\') ); } public function testZeroOffsetWithoutLimitIsIgnored() : void { $query = 'SELECT * FROM user'; self::assertSame( $query, $this->platform->modifyLimitQuery($query, null, 0) ); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Platforms/AbstractPostgreSqlPlatformTestCase.php000066400000000000000000001033331360544566000332300ustar00rootroot00000000000000 'CASCADE'] ); self::assertEquals( 'CONSTRAINT my_fk FOREIGN KEY (foreign_id) REFERENCES my_table (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE', $this->platform->getForeignKeyDeclarationSQL($foreignKey) ); $foreignKey = new ForeignKeyConstraint( ['foreign_id'], 'my_table', ['id'], 'my_fk', ['match' => 'full'] ); self::assertEquals( 'CONSTRAINT my_fk FOREIGN KEY (foreign_id) REFERENCES my_table (id) MATCH full NOT DEFERRABLE INITIALLY IMMEDIATE', $this->platform->getForeignKeyDeclarationSQL($foreignKey) ); $foreignKey = new ForeignKeyConstraint( ['foreign_id'], 'my_table', ['id'], 'my_fk', ['deferrable' => true] ); self::assertEquals( 'CONSTRAINT my_fk FOREIGN KEY (foreign_id) REFERENCES my_table (id) DEFERRABLE INITIALLY IMMEDIATE', $this->platform->getForeignKeyDeclarationSQL($foreignKey) ); $foreignKey = new ForeignKeyConstraint( ['foreign_id'], 'my_table', ['id'], 'my_fk', ['deferred' => true] ); self::assertEquals( 'CONSTRAINT my_fk FOREIGN KEY (foreign_id) REFERENCES my_table (id) NOT DEFERRABLE INITIALLY DEFERRED', $this->platform->getForeignKeyDeclarationSQL($foreignKey) ); $foreignKey = new ForeignKeyConstraint( ['foreign_id'], 'my_table', ['id'], 'my_fk', ['feferred' => true] ); self::assertEquals( 'CONSTRAINT my_fk FOREIGN KEY (foreign_id) REFERENCES my_table (id) NOT DEFERRABLE INITIALLY DEFERRED', $this->platform->getForeignKeyDeclarationSQL($foreignKey) ); $foreignKey = new ForeignKeyConstraint( ['foreign_id'], 'my_table', ['id'], 'my_fk', ['deferrable' => true, 'deferred' => true, 'match' => 'full'] ); self::assertEquals( 'CONSTRAINT my_fk FOREIGN KEY (foreign_id) REFERENCES my_table (id) MATCH full DEFERRABLE INITIALLY DEFERRED', $this->platform->getForeignKeyDeclarationSQL($foreignKey) ); } public function testGeneratesSqlSnippets() : void { self::assertEquals('SIMILAR TO', $this->platform->getRegexpExpression(), 'Regular expression operator is not correct'); self::assertEquals('"', $this->platform->getIdentifierQuoteCharacter(), 'Identifier quote character is not correct'); self::assertEquals('column1 || column2 || column3', $this->platform->getConcatExpression('column1', 'column2', 'column3'), 'Concatenation expression is not correct'); self::assertEquals('SUBSTRING(column FROM 5)', $this->platform->getSubstringExpression('column', 5), 'Substring expression without length is not correct'); self::assertEquals('SUBSTRING(column FROM 1 FOR 5)', $this->platform->getSubstringExpression('column', 1, 5), 'Substring expression with length is not correct'); } public function testGeneratesTransactionCommands() : void { self::assertEquals( 'SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL READ UNCOMMITTED', $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::READ_UNCOMMITTED) ); self::assertEquals( 'SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL READ COMMITTED', $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::READ_COMMITTED) ); self::assertEquals( 'SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL REPEATABLE READ', $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::REPEATABLE_READ) ); self::assertEquals( 'SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE', $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::SERIALIZABLE) ); } public function testGeneratesDDLSnippets() : void { self::assertEquals('CREATE DATABASE foobar', $this->platform->getCreateDatabaseSQL('foobar')); self::assertEquals('DROP DATABASE foobar', $this->platform->getDropDatabaseSQL('foobar')); self::assertEquals('DROP TABLE foobar', $this->platform->getDropTableSQL('foobar')); } public function testGenerateTableWithAutoincrement() : void { $table = new Table('autoinc_table'); $column = $table->addColumn('id', 'integer'); $column->setAutoincrement(true); self::assertEquals(['CREATE TABLE autoinc_table (id SERIAL NOT NULL)'], $this->platform->getCreateTableSQL($table)); } /** * @return mixed[][] */ public static function serialTypes() : iterable { return [ ['integer', 'SERIAL'], ['bigint', 'BIGSERIAL'], ]; } /** * @dataProvider serialTypes * @group 2906 */ public function testGenerateTableWithAutoincrementDoesNotSetDefault(string $type, string $definition) : void { $table = new Table('autoinc_table_notnull'); $column = $table->addColumn('id', $type); $column->setAutoIncrement(true); $column->setNotNull(false); $sql = $this->platform->getCreateTableSQL($table); self::assertEquals([sprintf('CREATE TABLE autoinc_table_notnull (id %s)', $definition)], $sql); } /** * @dataProvider serialTypes * @group 2906 */ public function testCreateTableWithAutoincrementAndNotNullAddsConstraint(string $type, string $definition) : void { $table = new Table('autoinc_table_notnull_enabled'); $column = $table->addColumn('id', $type); $column->setAutoIncrement(true); $column->setNotNull(true); $sql = $this->platform->getCreateTableSQL($table); self::assertEquals([sprintf('CREATE TABLE autoinc_table_notnull_enabled (id %s NOT NULL)', $definition)], $sql); } /** * @dataProvider serialTypes * @group 2906 */ public function testGetDefaultValueDeclarationSQLIgnoresTheDefaultKeyWhenTheFieldIsSerial(string $type) : void { $sql = $this->platform->getDefaultValueDeclarationSQL( [ 'autoincrement' => true, 'type' => Type::getType($type), 'default' => 1, ] ); self::assertSame('', $sql); } public function testGeneratesTypeDeclarationForIntegers() : void { self::assertEquals( 'INT', $this->platform->getIntegerTypeDeclarationSQL([]) ); self::assertEquals( 'SERIAL', $this->platform->getIntegerTypeDeclarationSQL(['autoincrement' => true]) ); self::assertEquals( 'SERIAL', $this->platform->getIntegerTypeDeclarationSQL( ['autoincrement' => true, 'primary' => true] ) ); } public function testGeneratesTypeDeclarationForStrings() : void { self::assertEquals( 'CHAR(10)', $this->platform->getVarcharTypeDeclarationSQL( ['length' => 10, 'fixed' => true] ) ); self::assertEquals( 'VARCHAR(50)', $this->platform->getVarcharTypeDeclarationSQL(['length' => 50]), 'Variable string declaration is not correct' ); self::assertEquals( 'VARCHAR(255)', $this->platform->getVarcharTypeDeclarationSQL([]), 'Long string declaration is not correct' ); } public function getGenerateUniqueIndexSql() : string { return 'CREATE UNIQUE INDEX index_name ON test (test, test2)'; } public function testGeneratesSequenceSqlCommands() : void { $sequence = new Sequence('myseq', 20, 1); self::assertEquals( 'CREATE SEQUENCE myseq INCREMENT BY 20 MINVALUE 1 START 1', $this->platform->getCreateSequenceSQL($sequence) ); self::assertEquals( 'DROP SEQUENCE myseq CASCADE', $this->platform->getDropSequenceSQL('myseq') ); self::assertEquals( "SELECT NEXTVAL('myseq')", $this->platform->getSequenceNextValSQL('myseq') ); } public function testDoesNotPreferIdentityColumns() : void { self::assertFalse($this->platform->prefersIdentityColumns()); } public function testPrefersSequences() : void { self::assertTrue($this->platform->prefersSequences()); } public function testSupportsIdentityColumns() : void { self::assertTrue($this->platform->supportsIdentityColumns()); } public function testSupportsSavePoints() : void { self::assertTrue($this->platform->supportsSavepoints()); } public function testSupportsSequences() : void { self::assertTrue($this->platform->supportsSequences()); } /** * {@inheritdoc} */ protected function supportsCommentOnStatement() : bool { return true; } public function testModifyLimitQuery() : void { $sql = $this->platform->modifyLimitQuery('SELECT * FROM user', 10, 0); self::assertEquals('SELECT * FROM user LIMIT 10', $sql); } public function testModifyLimitQueryWithEmptyOffset() : void { $sql = $this->platform->modifyLimitQuery('SELECT * FROM user', 10); self::assertEquals('SELECT * FROM user LIMIT 10', $sql); } /** * {@inheritDoc} */ public function getCreateTableColumnCommentsSQL() : array { return [ 'CREATE TABLE test (id INT NOT NULL, PRIMARY KEY(id))', "COMMENT ON COLUMN test.id IS 'This is a comment'", ]; } /** * {@inheritDoc} */ public function getAlterTableColumnCommentsSQL() : array { return [ 'ALTER TABLE mytable ADD quota INT NOT NULL', "COMMENT ON COLUMN mytable.quota IS 'A comment'", 'COMMENT ON COLUMN mytable.foo IS NULL', "COMMENT ON COLUMN mytable.baz IS 'B comment'", ]; } /** * {@inheritDoc} */ public function getCreateTableColumnTypeCommentsSQL() : array { return [ 'CREATE TABLE test (id INT NOT NULL, data TEXT NOT NULL, PRIMARY KEY(id))', "COMMENT ON COLUMN test.data IS '(DC2Type:array)'", ]; } /** * {@inheritDoc} */ protected function getQuotedColumnInPrimaryKeySQL() : array { return ['CREATE TABLE "quoted" ("create" VARCHAR(255) NOT NULL, PRIMARY KEY("create"))']; } /** * {@inheritDoc} */ protected function getQuotedColumnInIndexSQL() : array { return [ 'CREATE TABLE "quoted" ("create" VARCHAR(255) NOT NULL)', 'CREATE INDEX IDX_22660D028FD6E0FB ON "quoted" ("create")', ]; } /** * {@inheritDoc} */ protected function getQuotedNameInIndexSQL() : array { return [ 'CREATE TABLE test (column1 VARCHAR(255) NOT NULL)', 'CREATE INDEX "key" ON test (column1)', ]; } /** * {@inheritDoc} */ protected function getQuotedColumnInForeignKeySQL() : array { return [ 'CREATE TABLE "quoted" ("create" VARCHAR(255) NOT NULL, foo VARCHAR(255) NOT NULL, "bar" VARCHAR(255) NOT NULL)', 'ALTER TABLE "quoted" ADD CONSTRAINT FK_WITH_RESERVED_KEYWORD FOREIGN KEY ("create", foo, "bar") REFERENCES "foreign" ("create", bar, "foo-bar") NOT DEFERRABLE INITIALLY IMMEDIATE', 'ALTER TABLE "quoted" ADD CONSTRAINT FK_WITH_NON_RESERVED_KEYWORD FOREIGN KEY ("create", foo, "bar") REFERENCES foo ("create", bar, "foo-bar") NOT DEFERRABLE INITIALLY IMMEDIATE', 'ALTER TABLE "quoted" ADD CONSTRAINT FK_WITH_INTENDED_QUOTATION FOREIGN KEY ("create", foo, "bar") REFERENCES "foo-bar" ("create", bar, "foo-bar") NOT DEFERRABLE INITIALLY IMMEDIATE', ]; } /** * @param string|bool $databaseValue * * @group DBAL-457 * @dataProvider pgBooleanProvider */ public function testConvertBooleanAsLiteralStrings( $databaseValue, string $preparedStatementValue, ?int $integerValue, ?bool $booleanValue ) : void { $platform = $this->createPlatform(); self::assertEquals($preparedStatementValue, $platform->convertBooleans($databaseValue)); } /** * @group DBAL-457 */ public function testConvertBooleanAsLiteralIntegers() : void { $platform = $this->createPlatform(); $platform->setUseBooleanTrueFalseStrings(false); self::assertEquals(1, $platform->convertBooleans(true)); self::assertEquals(1, $platform->convertBooleans('1')); self::assertEquals(0, $platform->convertBooleans(false)); self::assertEquals(0, $platform->convertBooleans('0')); } /** * @param string|bool $databaseValue * * @group DBAL-630 * @dataProvider pgBooleanProvider */ public function testConvertBooleanAsDatabaseValueStrings( $databaseValue, string $preparedStatementValue, ?int $integerValue, ?bool $booleanValue ) : void { $platform = $this->createPlatform(); self::assertSame($integerValue, $platform->convertBooleansToDatabaseValue($booleanValue)); } /** * @group DBAL-630 */ public function testConvertBooleanAsDatabaseValueIntegers() : void { $platform = $this->createPlatform(); $platform->setUseBooleanTrueFalseStrings(false); self::assertSame(1, $platform->convertBooleansToDatabaseValue(true)); self::assertSame(0, $platform->convertBooleansToDatabaseValue(false)); } /** * @param string|bool $databaseValue * * @dataProvider pgBooleanProvider */ public function testConvertFromBoolean($databaseValue, string $prepareStatementValue, ?int $integerValue, ?bool $booleanValue) : void { $platform = $this->createPlatform(); self::assertSame($booleanValue, $platform->convertFromBoolean($databaseValue)); } public function testThrowsExceptionWithInvalidBooleanLiteral() : void { $platform = $this->createPlatform(); $this->expectException(UnexpectedValueException::class); $this->expectExceptionMessage("Unrecognized boolean literal 'my-bool'"); $platform->convertBooleansToDatabaseValue('my-bool'); } public function testGetCreateSchemaSQL() : void { $schemaName = 'schema'; $sql = $this->platform->getCreateSchemaSQL($schemaName); self::assertEquals('CREATE SCHEMA ' . $schemaName, $sql); } public function testAlterDecimalPrecisionScale() : void { $table = new Table('mytable'); $table->addColumn('dfoo1', 'decimal'); $table->addColumn('dfoo2', 'decimal', ['precision' => 10, 'scale' => 6]); $table->addColumn('dfoo3', 'decimal', ['precision' => 10, 'scale' => 6]); $table->addColumn('dfoo4', 'decimal', ['precision' => 10, 'scale' => 6]); $tableDiff = new TableDiff('mytable'); $tableDiff->fromTable = $table; $tableDiff->changedColumns['dloo1'] = new ColumnDiff( 'dloo1', new Column( 'dloo1', Type::getType('decimal'), ['precision' => 16, 'scale' => 6] ), ['precision'] ); $tableDiff->changedColumns['dloo2'] = new ColumnDiff( 'dloo2', new Column( 'dloo2', Type::getType('decimal'), ['precision' => 10, 'scale' => 4] ), ['scale'] ); $tableDiff->changedColumns['dloo3'] = new ColumnDiff( 'dloo3', new Column( 'dloo3', Type::getType('decimal'), ['precision' => 10, 'scale' => 6] ), [] ); $tableDiff->changedColumns['dloo4'] = new ColumnDiff( 'dloo4', new Column( 'dloo4', Type::getType('decimal'), ['precision' => 16, 'scale' => 8] ), ['precision', 'scale'] ); $sql = $this->platform->getAlterTableSQL($tableDiff); $expectedSql = [ 'ALTER TABLE mytable ALTER dloo1 TYPE NUMERIC(16, 6)', 'ALTER TABLE mytable ALTER dloo2 TYPE NUMERIC(10, 4)', 'ALTER TABLE mytable ALTER dloo4 TYPE NUMERIC(16, 8)', ]; self::assertEquals($expectedSql, $sql); } /** * @group DBAL-365 */ public function testDroppingConstraintsBeforeColumns() : void { $newTable = new Table('mytable'); $newTable->addColumn('id', 'integer'); $newTable->setPrimaryKey(['id']); $oldTable = clone $newTable; $oldTable->addColumn('parent_id', 'integer'); $oldTable->addUnnamedForeignKeyConstraint('mytable', ['parent_id'], ['id']); $comparator = new Comparator(); $tableDiff = $comparator->diffTable($oldTable, $newTable); $sql = $this->platform->getAlterTableSQL($tableDiff); $expectedSql = [ 'ALTER TABLE mytable DROP CONSTRAINT FK_6B2BD609727ACA70', 'DROP INDEX IDX_6B2BD609727ACA70', 'ALTER TABLE mytable DROP parent_id', ]; self::assertEquals($expectedSql, $sql); } /** * @group DBAL-563 */ public function testUsesSequenceEmulatedIdentityColumns() : void { self::assertTrue($this->platform->usesSequenceEmulatedIdentityColumns()); } /** * @group DBAL-563 */ public function testReturnsIdentitySequenceName() : void { self::assertSame('mytable_mycolumn_seq', $this->platform->getIdentitySequenceName('mytable', 'mycolumn')); } /** * @dataProvider dataCreateSequenceWithCache * @group DBAL-139 */ public function testCreateSequenceWithCache(int $cacheSize, string $expectedSql) : void { $sequence = new Sequence('foo', 1, 1, $cacheSize); self::assertStringContainsString($expectedSql, $this->platform->getCreateSequenceSQL($sequence)); } /** * @return mixed[][] */ public static function dataCreateSequenceWithCache() : iterable { return [ [3, 'CACHE 3'], ]; } protected function getBinaryDefaultLength() : int { return 0; } protected function getBinaryMaxLength() : int { return 0; } public function testReturnsBinaryTypeDeclarationSQL() : void { self::assertSame('BYTEA', $this->platform->getBinaryTypeDeclarationSQL([])); self::assertSame('BYTEA', $this->platform->getBinaryTypeDeclarationSQL(['length' => 0])); self::assertSame('BYTEA', $this->platform->getBinaryTypeDeclarationSQL(['length' => 9999999])); self::assertSame('BYTEA', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true])); self::assertSame('BYTEA', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 0])); self::assertSame('BYTEA', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 9999999])); } public function testDoesNotPropagateUnnecessaryTableAlterationOnBinaryType() : void { $table1 = new Table('mytable'); $table1->addColumn('column_varbinary', 'binary'); $table1->addColumn('column_binary', 'binary', ['fixed' => true]); $table1->addColumn('column_blob', 'blob'); $table2 = new Table('mytable'); $table2->addColumn('column_varbinary', 'binary', ['fixed' => true]); $table2->addColumn('column_binary', 'binary'); $table2->addColumn('column_blob', 'binary'); $comparator = new Comparator(); // VARBINARY -> BINARY // BINARY -> VARBINARY // BLOB -> VARBINARY self::assertEmpty($this->platform->getAlterTableSQL($comparator->diffTable($table1, $table2))); $table2 = new Table('mytable'); $table2->addColumn('column_varbinary', 'binary', ['length' => 42]); $table2->addColumn('column_binary', 'blob'); $table2->addColumn('column_blob', 'binary', ['length' => 11, 'fixed' => true]); // VARBINARY -> VARBINARY with changed length // BINARY -> BLOB // BLOB -> BINARY self::assertEmpty($this->platform->getAlterTableSQL($comparator->diffTable($table1, $table2))); $table2 = new Table('mytable'); $table2->addColumn('column_varbinary', 'blob'); $table2->addColumn('column_binary', 'binary', ['length' => 42, 'fixed' => true]); $table2->addColumn('column_blob', 'blob'); // VARBINARY -> BLOB // BINARY -> BINARY with changed length // BLOB -> BLOB self::assertEmpty($this->platform->getAlterTableSQL($comparator->diffTable($table1, $table2))); } /** * {@inheritDoc} * * @group DBAL-234 */ protected function getAlterTableRenameIndexSQL() : array { return ['ALTER INDEX idx_foo RENAME TO idx_bar']; } /** * {@inheritDoc} * * @group DBAL-234 */ protected function getQuotedAlterTableRenameIndexSQL() : array { return [ 'ALTER INDEX "create" RENAME TO "select"', 'ALTER INDEX "foo" RENAME TO "bar"', ]; } /** * PostgreSQL boolean strings provider * * @return mixed[][] */ public static function pgBooleanProvider() : iterable { return [ // Database value, prepared statement value, boolean integer value, boolean value. [true, 'true', 1, true], ['t', 'true', 1, true], ['true', 'true', 1, true], ['y', 'true', 1, true], ['yes', 'true', 1, true], ['on', 'true', 1, true], ['1', 'true', 1, true], [false, 'false', 0, false], ['f', 'false', 0, false], ['false', 'false', 0, false], [ 'n', 'false', 0, false], ['no', 'false', 0, false], ['off', 'false', 0, false], ['0', 'false', 0, false], [null, 'NULL', null, null], ]; } /** * {@inheritdoc} */ protected function getQuotedAlterTableRenameColumnSQL() : array { return [ 'ALTER TABLE mytable RENAME COLUMN unquoted1 TO unquoted', 'ALTER TABLE mytable RENAME COLUMN unquoted2 TO "where"', 'ALTER TABLE mytable RENAME COLUMN unquoted3 TO "foo"', 'ALTER TABLE mytable RENAME COLUMN "create" TO reserved_keyword', 'ALTER TABLE mytable RENAME COLUMN "table" TO "from"', 'ALTER TABLE mytable RENAME COLUMN "select" TO "bar"', 'ALTER TABLE mytable RENAME COLUMN quoted1 TO quoted', 'ALTER TABLE mytable RENAME COLUMN quoted2 TO "and"', 'ALTER TABLE mytable RENAME COLUMN quoted3 TO "baz"', ]; } /** * {@inheritdoc} */ protected function getQuotedAlterTableChangeColumnLengthSQL() : array { return [ 'ALTER TABLE mytable ALTER unquoted1 TYPE VARCHAR(255)', 'ALTER TABLE mytable ALTER unquoted2 TYPE VARCHAR(255)', 'ALTER TABLE mytable ALTER unquoted3 TYPE VARCHAR(255)', 'ALTER TABLE mytable ALTER "create" TYPE VARCHAR(255)', 'ALTER TABLE mytable ALTER "table" TYPE VARCHAR(255)', 'ALTER TABLE mytable ALTER "select" TYPE VARCHAR(255)', ]; } /** * {@inheritDoc} * * @group DBAL-807 */ protected function getAlterTableRenameIndexInSchemaSQL() : array { return ['ALTER INDEX myschema.idx_foo RENAME TO idx_bar']; } /** * {@inheritDoc} * * @group DBAL-807 */ protected function getQuotedAlterTableRenameIndexInSchemaSQL() : array { return [ 'ALTER INDEX "schema"."create" RENAME TO "select"', 'ALTER INDEX "schema"."foo" RENAME TO "bar"', ]; } protected function getQuotesDropForeignKeySQL() : string { return 'ALTER TABLE "table" DROP CONSTRAINT "select"'; } public function testGetNullCommentOnColumnSQL() : void { self::assertEquals( 'COMMENT ON COLUMN mytable.id IS NULL', $this->platform->getCommentOnColumnSQL('mytable', 'id', null) ); } /** * @group DBAL-423 */ public function testReturnsGuidTypeDeclarationSQL() : void { self::assertSame('UUID', $this->platform->getGuidTypeDeclarationSQL([])); } /** * {@inheritdoc} */ public function getAlterTableRenameColumnSQL() : array { return ['ALTER TABLE foo RENAME COLUMN bar TO baz']; } /** * {@inheritdoc} */ protected function getQuotesTableIdentifiersInAlterTableSQL() : array { return [ 'ALTER TABLE "foo" DROP CONSTRAINT fk1', 'ALTER TABLE "foo" DROP CONSTRAINT fk2', 'ALTER TABLE "foo" ADD bloo INT NOT NULL', 'ALTER TABLE "foo" DROP baz', 'ALTER TABLE "foo" ALTER bar DROP NOT NULL', 'ALTER TABLE "foo" RENAME COLUMN id TO war', 'ALTER TABLE "foo" RENAME TO "table"', 'ALTER TABLE "table" ADD CONSTRAINT fk_add FOREIGN KEY (fk3) REFERENCES fk_table (id) NOT DEFERRABLE ' . 'INITIALLY IMMEDIATE', 'ALTER TABLE "table" ADD CONSTRAINT fk2 FOREIGN KEY (fk2) REFERENCES fk_table2 (id) NOT DEFERRABLE ' . 'INITIALLY IMMEDIATE', ]; } /** * {@inheritdoc} */ protected function getCommentOnColumnSQL() : array { return [ 'COMMENT ON COLUMN foo.bar IS \'comment\'', 'COMMENT ON COLUMN "Foo"."BAR" IS \'comment\'', 'COMMENT ON COLUMN "select"."from" IS \'comment\'', ]; } /** * @group DBAL-1004 */ public function testAltersTableColumnCommentWithExplicitlyQuotedIdentifiers() : void { $table1 = new Table('"foo"', [new Column('"bar"', Type::getType('integer'))]); $table2 = new Table('"foo"', [new Column('"bar"', Type::getType('integer'), ['comment' => 'baz'])]); $comparator = new Comparator(); $tableDiff = $comparator->diffTable($table1, $table2); self::assertInstanceOf(TableDiff::class, $tableDiff); self::assertSame( ['COMMENT ON COLUMN "foo"."bar" IS \'baz\''], $this->platform->getAlterTableSQL($tableDiff) ); } /** * @group 3158 */ public function testAltersTableColumnCommentIfRequiredByType() : void { $table1 = new Table('"foo"', [new Column('"bar"', Type::getType('datetime'))]); $table2 = new Table('"foo"', [new Column('"bar"', Type::getType('datetime_immutable'))]); $comparator = new Comparator(); $tableDiff = $comparator->diffTable($table1, $table2); $this->assertInstanceOf('Doctrine\DBAL\Schema\TableDiff', $tableDiff); $this->assertSame( [ 'ALTER TABLE "foo" ALTER "bar" TYPE TIMESTAMP(0) WITHOUT TIME ZONE', 'ALTER TABLE "foo" ALTER "bar" DROP DEFAULT', 'COMMENT ON COLUMN "foo"."bar" IS \'(DC2Type:datetime_immutable)\'', ], $this->platform->getAlterTableSQL($tableDiff) ); } /** * {@inheritdoc} */ protected function getQuotesReservedKeywordInUniqueConstraintDeclarationSQL() : string { return 'CONSTRAINT "select" UNIQUE (foo)'; } /** * {@inheritdoc} */ protected function getQuotesReservedKeywordInIndexDeclarationSQL() : string { return 'INDEX "select" (foo)'; } /** * {@inheritdoc} */ protected function getQuotesReservedKeywordInTruncateTableSQL() : string { return 'TRUNCATE "select"'; } /** * {@inheritdoc} */ protected function getAlterStringToFixedStringSQL() : array { return ['ALTER TABLE mytable ALTER name TYPE CHAR(2)']; } /** * {@inheritdoc} */ protected function getGeneratesAlterTableRenameIndexUsedByForeignKeySQL() : array { return ['ALTER INDEX idx_foo RENAME TO idx_foo_renamed']; } /** * @group DBAL-1142 */ public function testInitializesTsvectorTypeMapping() : void { self::assertTrue($this->platform->hasDoctrineTypeMappingFor('tsvector')); self::assertEquals('text', $this->platform->getDoctrineTypeMapping('tsvector')); } /** * @group DBAL-1220 */ public function testReturnsDisallowDatabaseConnectionsSQL() : void { self::assertSame( "UPDATE pg_database SET datallowconn = 'false' WHERE datname = 'foo'", $this->platform->getDisallowDatabaseConnectionsSQL('foo') ); } /** * @group DBAL-1220 */ public function testReturnsCloseActiveDatabaseConnectionsSQL() : void { self::assertSame( "SELECT pg_terminate_backend(procpid) FROM pg_stat_activity WHERE datname = 'foo'", $this->platform->getCloseActiveDatabaseConnectionsSQL('foo') ); } /** * @group DBAL-2436 */ public function testQuotesTableNameInListTableForeignKeysSQL() : void { self::assertStringContainsStringIgnoringCase( "'Foo''Bar\\'", $this->platform->getListTableForeignKeysSQL("Foo'Bar\\") ); } /** * @group DBAL-2436 */ public function testQuotesSchemaNameInListTableForeignKeysSQL() : void { self::assertStringContainsStringIgnoringCase( "'Foo''Bar\\'", $this->platform->getListTableForeignKeysSQL("Foo'Bar\\.baz_table") ); } /** * @group DBAL-2436 */ public function testQuotesTableNameInListTableConstraintsSQL() : void { self::assertStringContainsStringIgnoringCase( "'Foo''Bar\\'", $this->platform->getListTableConstraintsSQL("Foo'Bar\\") ); } /** * @group DBAL-2436 */ public function testQuotesTableNameInListTableIndexesSQL() : void { self::assertStringContainsStringIgnoringCase( "'Foo''Bar\\'", $this->platform->getListTableIndexesSQL("Foo'Bar\\") ); } /** * @group DBAL-2436 */ public function testQuotesSchemaNameInListTableIndexesSQL() : void { self::assertStringContainsStringIgnoringCase( "'Foo''Bar\\'", $this->platform->getListTableIndexesSQL("Foo'Bar\\.baz_table") ); } /** * @group DBAL-2436 */ public function testQuotesTableNameInListTableColumnsSQL() : void { self::assertStringContainsStringIgnoringCase( "'Foo''Bar\\'", $this->platform->getListTableColumnsSQL("Foo'Bar\\") ); } /** * @group DBAL-2436 */ public function testQuotesSchemaNameInListTableColumnsSQL() : void { self::assertStringContainsStringIgnoringCase( "'Foo''Bar\\'", $this->platform->getListTableColumnsSQL("Foo'Bar\\.baz_table") ); } /** * @group DBAL-2436 */ public function testQuotesDatabaseNameInCloseActiveDatabaseConnectionsSQL() : void { self::assertStringContainsStringIgnoringCase( "'Foo''Bar\\'", $this->platform->getCloseActiveDatabaseConnectionsSQL("Foo'Bar\\") ); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Platforms/AbstractSQLServerPlatformTestCase.php000066400000000000000000002212761360544566000327620ustar00rootroot00000000000000expectException(DBALException::class); $this->platform->getRegexpExpression(); } public function testGeneratesSqlSnippets() : void { self::assertEquals('CONVERT(date, GETDATE())', $this->platform->getCurrentDateSQL()); self::assertEquals('CONVERT(time, GETDATE())', $this->platform->getCurrentTimeSQL()); self::assertEquals('CURRENT_TIMESTAMP', $this->platform->getCurrentTimestampSQL()); self::assertEquals('"', $this->platform->getIdentifierQuoteCharacter(), 'Identifier quote character is not correct'); self::assertEquals('(column1 + column2 + column3)', $this->platform->getConcatExpression('column1', 'column2', 'column3'), 'Concatenation expression is not correct'); } public function testGeneratesTransactionsCommands() : void { self::assertEquals( 'SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED', $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::READ_UNCOMMITTED) ); self::assertEquals( 'SET TRANSACTION ISOLATION LEVEL READ COMMITTED', $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::READ_COMMITTED) ); self::assertEquals( 'SET TRANSACTION ISOLATION LEVEL REPEATABLE READ', $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::REPEATABLE_READ) ); self::assertEquals( 'SET TRANSACTION ISOLATION LEVEL SERIALIZABLE', $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::SERIALIZABLE) ); } public function testGeneratesDDLSnippets() : void { $dropDatabaseExpectation = 'DROP DATABASE foobar'; self::assertEquals('SELECT * FROM sys.databases', $this->platform->getListDatabasesSQL()); self::assertEquals('CREATE DATABASE foobar', $this->platform->getCreateDatabaseSQL('foobar')); self::assertEquals($dropDatabaseExpectation, $this->platform->getDropDatabaseSQL('foobar')); self::assertEquals('DROP TABLE foobar', $this->platform->getDropTableSQL('foobar')); } public function testGeneratesTypeDeclarationForIntegers() : void { self::assertEquals( 'INT', $this->platform->getIntegerTypeDeclarationSQL([]) ); self::assertEquals( 'INT IDENTITY', $this->platform->getIntegerTypeDeclarationSQL(['autoincrement' => true]) ); self::assertEquals( 'INT IDENTITY', $this->platform->getIntegerTypeDeclarationSQL( ['autoincrement' => true, 'primary' => true] ) ); } public function testGeneratesTypeDeclarationsForStrings() : void { self::assertEquals( 'NCHAR(10)', $this->platform->getVarcharTypeDeclarationSQL( ['length' => 10, 'fixed' => true] ) ); self::assertEquals( 'NVARCHAR(50)', $this->platform->getVarcharTypeDeclarationSQL(['length' => 50]), 'Variable string declaration is not correct' ); self::assertEquals( 'NVARCHAR(255)', $this->platform->getVarcharTypeDeclarationSQL([]), 'Long string declaration is not correct' ); self::assertSame('VARCHAR(MAX)', $this->platform->getClobTypeDeclarationSQL([])); self::assertSame( 'VARCHAR(MAX)', $this->platform->getClobTypeDeclarationSQL(['length' => 5, 'fixed' => true]) ); } public function testPrefersIdentityColumns() : void { self::assertTrue($this->platform->prefersIdentityColumns()); } public function testSupportsIdentityColumns() : void { self::assertTrue($this->platform->supportsIdentityColumns()); } public function testSupportsCreateDropDatabase() : void { self::assertTrue($this->platform->supportsCreateDropDatabase()); } public function testSupportsSchemas() : void { self::assertTrue($this->platform->supportsSchemas()); } public function testDoesNotSupportSavePoints() : void { self::assertTrue($this->platform->supportsSavepoints()); } public function getGenerateIndexSql() : string { return 'CREATE INDEX my_idx ON mytable (user_name, last_login)'; } public function getGenerateUniqueIndexSql() : string { return 'CREATE UNIQUE INDEX index_name ON test (test, test2) WHERE test IS NOT NULL AND test2 IS NOT NULL'; } public function getGenerateForeignKeySql() : string { return 'ALTER TABLE test ADD FOREIGN KEY (fk_name_id) REFERENCES other_table (id)'; } public function testModifyLimitQuery() : void { $querySql = 'SELECT * FROM user'; $alteredSql = 'SELECT TOP 10 * FROM user'; $sql = $this->platform->modifyLimitQuery($querySql, 10, 0); $this->expectCteWithMaxRowNum($alteredSql, 10, $sql); } public function testModifyLimitQueryWithEmptyOffset() : void { $querySql = 'SELECT * FROM user'; $alteredSql = 'SELECT TOP 10 * FROM user'; $sql = $this->platform->modifyLimitQuery($querySql, 10); $this->expectCteWithMaxRowNum($alteredSql, 10, $sql); } public function testModifyLimitQueryWithOffset() : void { if (! $this->platform->supportsLimitOffset()) { $this->markTestSkipped(sprintf('Platform "%s" does not support offsets in result limiting.', $this->platform->getName())); } $querySql = 'SELECT * FROM user ORDER BY username DESC'; $alteredSql = 'SELECT TOP 15 * FROM user ORDER BY username DESC'; $sql = $this->platform->modifyLimitQuery($querySql, 10, 5); $this->expectCteWithMinAndMaxRowNums($alteredSql, 6, 15, $sql); } public function testModifyLimitQueryWithAscOrderBy() : void { $querySql = 'SELECT * FROM user ORDER BY username ASC'; $alteredSql = 'SELECT TOP 10 * FROM user ORDER BY username ASC'; $sql = $this->platform->modifyLimitQuery($querySql, 10); $this->expectCteWithMaxRowNum($alteredSql, 10, $sql); } public function testModifyLimitQueryWithLowercaseOrderBy() : void { $querySql = 'SELECT * FROM user order by username'; $alteredSql = 'SELECT TOP 10 * FROM user order by username'; $sql = $this->platform->modifyLimitQuery($querySql, 10); $this->expectCteWithMaxRowNum($alteredSql, 10, $sql); } public function testModifyLimitQueryWithDescOrderBy() : void { $querySql = 'SELECT * FROM user ORDER BY username DESC'; $alteredSql = 'SELECT TOP 10 * FROM user ORDER BY username DESC'; $sql = $this->platform->modifyLimitQuery($querySql, 10); $this->expectCteWithMaxRowNum($alteredSql, 10, $sql); } public function testModifyLimitQueryWithMultipleOrderBy() : void { $querySql = 'SELECT * FROM user ORDER BY username DESC, usereamil ASC'; $alteredSql = 'SELECT TOP 10 * FROM user ORDER BY username DESC, usereamil ASC'; $sql = $this->platform->modifyLimitQuery($querySql, 10); $this->expectCteWithMaxRowNum($alteredSql, 10, $sql); } public function testModifyLimitQueryWithSubSelect() : void { $querySql = 'SELECT * FROM (SELECT u.id as uid, u.name as uname) dctrn_result'; $alteredSql = 'SELECT TOP 10 * FROM (SELECT u.id as uid, u.name as uname) dctrn_result'; $sql = $this->platform->modifyLimitQuery($querySql, 10); $this->expectCteWithMaxRowNum($alteredSql, 10, $sql); } public function testModifyLimitQueryWithSubSelectAndOrder() : void { $querySql = 'SELECT * FROM (SELECT u.id as uid, u.name as uname ORDER BY u.name DESC) dctrn_result'; $alteredSql = 'SELECT TOP 10 * FROM (SELECT u.id as uid, u.name as uname) dctrn_result'; $sql = $this->platform->modifyLimitQuery($querySql, 10); $this->expectCteWithMaxRowNum($alteredSql, 10, $sql); $querySql = 'SELECT * FROM (SELECT u.id, u.name ORDER BY u.name DESC) dctrn_result'; $alteredSql = 'SELECT TOP 10 * FROM (SELECT u.id, u.name) dctrn_result'; $sql = $this->platform->modifyLimitQuery($querySql, 10); $this->expectCteWithMaxRowNum($alteredSql, 10, $sql); } public function testModifyLimitQueryWithSubSelectAndMultipleOrder() : void { if (! $this->platform->supportsLimitOffset()) { $this->markTestSkipped(sprintf('Platform "%s" does not support offsets in result limiting.', $this->platform->getName())); } $querySql = 'SELECT * FROM (SELECT u.id as uid, u.name as uname ORDER BY u.name DESC, id ASC) dctrn_result'; $alteredSql = 'SELECT TOP 15 * FROM (SELECT u.id as uid, u.name as uname) dctrn_result'; $sql = $this->platform->modifyLimitQuery($querySql, 10, 5); $this->expectCteWithMinAndMaxRowNums($alteredSql, 6, 15, $sql); $querySql = 'SELECT * FROM (SELECT u.id uid, u.name uname ORDER BY u.name DESC, id ASC) dctrn_result'; $alteredSql = 'SELECT TOP 15 * FROM (SELECT u.id uid, u.name uname) dctrn_result'; $sql = $this->platform->modifyLimitQuery($querySql, 10, 5); $this->expectCteWithMinAndMaxRowNums($alteredSql, 6, 15, $sql); $querySql = 'SELECT * FROM (SELECT u.id, u.name ORDER BY u.name DESC, id ASC) dctrn_result'; $alteredSql = 'SELECT TOP 15 * FROM (SELECT u.id, u.name) dctrn_result'; $sql = $this->platform->modifyLimitQuery($querySql, 10, 5); $this->expectCteWithMinAndMaxRowNums($alteredSql, 6, 15, $sql); } public function testModifyLimitQueryWithFromColumnNames() : void { $querySql = 'SELECT a.fromFoo, fromBar FROM foo'; $alteredSql = 'SELECT TOP 10 a.fromFoo, fromBar FROM foo'; $sql = $this->platform->modifyLimitQuery($querySql, 10); $this->expectCteWithMaxRowNum($alteredSql, 10, $sql); } /** * @group DBAL-927 */ public function testModifyLimitQueryWithExtraLongQuery() : void { $query = 'SELECT table1.column1, table2.column2, table3.column3, table4.column4, table5.column5, table6.column6, table7.column7, table8.column8 FROM table1, table2, table3, table4, table5, table6, table7, table8 '; $query .= 'WHERE (table1.column1 = table2.column2) AND (table1.column1 = table3.column3) AND (table1.column1 = table4.column4) AND (table1.column1 = table5.column5) AND (table1.column1 = table6.column6) AND (table1.column1 = table7.column7) AND (table1.column1 = table8.column8) AND (table2.column2 = table3.column3) AND (table2.column2 = table4.column4) AND (table2.column2 = table5.column5) AND (table2.column2 = table6.column6) '; $query .= 'AND (table2.column2 = table7.column7) AND (table2.column2 = table8.column8) AND (table3.column3 = table4.column4) AND (table3.column3 = table5.column5) AND (table3.column3 = table6.column6) AND (table3.column3 = table7.column7) AND (table3.column3 = table8.column8) AND (table4.column4 = table5.column5) AND (table4.column4 = table6.column6) AND (table4.column4 = table7.column7) AND (table4.column4 = table8.column8) '; $query .= 'AND (table5.column5 = table6.column6) AND (table5.column5 = table7.column7) AND (table5.column5 = table8.column8) AND (table6.column6 = table7.column7) AND (table6.column6 = table8.column8) AND (table7.column7 = table8.column8)'; $alteredSql = 'SELECT TOP 10 table1.column1, table2.column2, table3.column3, table4.column4, table5.column5, table6.column6, table7.column7, table8.column8 FROM table1, table2, table3, table4, table5, table6, table7, table8 '; $alteredSql .= 'WHERE (table1.column1 = table2.column2) AND (table1.column1 = table3.column3) AND (table1.column1 = table4.column4) AND (table1.column1 = table5.column5) AND (table1.column1 = table6.column6) AND (table1.column1 = table7.column7) AND (table1.column1 = table8.column8) AND (table2.column2 = table3.column3) AND (table2.column2 = table4.column4) AND (table2.column2 = table5.column5) AND (table2.column2 = table6.column6) '; $alteredSql .= 'AND (table2.column2 = table7.column7) AND (table2.column2 = table8.column8) AND (table3.column3 = table4.column4) AND (table3.column3 = table5.column5) AND (table3.column3 = table6.column6) AND (table3.column3 = table7.column7) AND (table3.column3 = table8.column8) AND (table4.column4 = table5.column5) AND (table4.column4 = table6.column6) AND (table4.column4 = table7.column7) AND (table4.column4 = table8.column8) '; $alteredSql .= 'AND (table5.column5 = table6.column6) AND (table5.column5 = table7.column7) AND (table5.column5 = table8.column8) AND (table6.column6 = table7.column7) AND (table6.column6 = table8.column8) AND (table7.column7 = table8.column8)'; $sql = $this->platform->modifyLimitQuery($query, 10); $this->expectCteWithMaxRowNum($alteredSql, 10, $sql); } /** * @group DDC-2470 */ public function testModifyLimitQueryWithOrderByClause() : void { if (! $this->platform->supportsLimitOffset()) { $this->markTestSkipped(sprintf('Platform "%s" does not support offsets in result limiting.', $this->platform->getName())); } $sql = 'SELECT m0_.NOMBRE AS NOMBRE0, m0_.FECHAINICIO AS FECHAINICIO1, m0_.FECHAFIN AS FECHAFIN2 FROM MEDICION m0_ WITH (NOLOCK) INNER JOIN ESTUDIO e1_ ON m0_.ESTUDIO_ID = e1_.ID INNER JOIN CLIENTE c2_ ON e1_.CLIENTE_ID = c2_.ID INNER JOIN USUARIO u3_ ON c2_.ID = u3_.CLIENTE_ID WHERE u3_.ID = ? ORDER BY m0_.FECHAINICIO DESC'; $alteredSql = 'SELECT TOP 15 m0_.NOMBRE AS NOMBRE0, m0_.FECHAINICIO AS FECHAINICIO1, m0_.FECHAFIN AS FECHAFIN2 FROM MEDICION m0_ WITH (NOLOCK) INNER JOIN ESTUDIO e1_ ON m0_.ESTUDIO_ID = e1_.ID INNER JOIN CLIENTE c2_ ON e1_.CLIENTE_ID = c2_.ID INNER JOIN USUARIO u3_ ON c2_.ID = u3_.CLIENTE_ID WHERE u3_.ID = ? ORDER BY m0_.FECHAINICIO DESC'; $actual = $this->platform->modifyLimitQuery($sql, 10, 5); $this->expectCteWithMinAndMaxRowNums($alteredSql, 6, 15, $actual); } /** * @group DBAL-713 */ public function testModifyLimitQueryWithSubSelectInSelectList() : void { $querySql = 'SELECT ' . 'u.id, ' . '(u.foo/2) foodiv, ' . 'CONCAT(u.bar, u.baz) barbaz, ' . '(SELECT (SELECT COUNT(*) FROM login l WHERE l.profile_id = p.id) FROM profile p WHERE p.user_id = u.id) login_count ' . 'FROM user u ' . "WHERE u.status = 'disabled'"; $alteredSql = 'SELECT TOP 10 ' . 'u.id, ' . '(u.foo/2) foodiv, ' . 'CONCAT(u.bar, u.baz) barbaz, ' . '(SELECT (SELECT COUNT(*) FROM login l WHERE l.profile_id = p.id) FROM profile p WHERE p.user_id = u.id) login_count ' . 'FROM user u ' . "WHERE u.status = 'disabled'"; $sql = $this->platform->modifyLimitQuery($querySql, 10); $this->expectCteWithMaxRowNum($alteredSql, 10, $sql); } /** * @group DBAL-713 */ public function testModifyLimitQueryWithSubSelectInSelectListAndOrderByClause() : void { if (! $this->platform->supportsLimitOffset()) { $this->markTestSkipped(sprintf('Platform "%s" does not support offsets in result limiting.', $this->platform->getName())); } $querySql = 'SELECT ' . 'u.id, ' . '(u.foo/2) foodiv, ' . 'CONCAT(u.bar, u.baz) barbaz, ' . '(SELECT (SELECT COUNT(*) FROM login l WHERE l.profile_id = p.id) FROM profile p WHERE p.user_id = u.id) login_count ' . 'FROM user u ' . "WHERE u.status = 'disabled' " . 'ORDER BY u.username DESC'; $alteredSql = 'SELECT TOP 15 ' . 'u.id, ' . '(u.foo/2) foodiv, ' . 'CONCAT(u.bar, u.baz) barbaz, ' . '(SELECT (SELECT COUNT(*) FROM login l WHERE l.profile_id = p.id) FROM profile p WHERE p.user_id = u.id) login_count ' . 'FROM user u ' . "WHERE u.status = 'disabled' " . 'ORDER BY u.username DESC'; $sql = $this->platform->modifyLimitQuery($querySql, 10, 5); $this->expectCteWithMinAndMaxRowNums($alteredSql, 6, 15, $sql); } /** * @group DBAL-834 */ public function testModifyLimitQueryWithAggregateFunctionInOrderByClause() : void { $querySql = 'SELECT ' . 'MAX(heading_id) aliased, ' . 'code ' . 'FROM operator_model_operator ' . 'GROUP BY code ' . 'ORDER BY MAX(heading_id) DESC'; $alteredSql = 'SELECT TOP 1 ' . 'MAX(heading_id) aliased, ' . 'code ' . 'FROM operator_model_operator ' . 'GROUP BY code ' . 'ORDER BY MAX(heading_id) DESC'; $sql = $this->platform->modifyLimitQuery($querySql, 1, 0); $this->expectCteWithMaxRowNum($alteredSql, 1, $sql); } /** * @throws DBALException */ public function testModifyLimitSubqueryWithJoinAndSubqueryOrderedByColumnFromBaseTable() : void { $querySql = 'SELECT DISTINCT id_0, name_1 ' . 'FROM (' . 'SELECT t1.id AS id_0, t2.name AS name_1 ' . 'FROM table_parent t1 ' . 'LEFT JOIN join_table t2 ON t1.id = t2.table_id ' . 'ORDER BY t1.id ASC' . ') dctrn_result ' . 'ORDER BY id_0 ASC'; $alteredSql = 'SELECT DISTINCT TOP 5 id_0, name_1 ' . 'FROM (' . 'SELECT t1.id AS id_0, t2.name AS name_1 ' . 'FROM table_parent t1 ' . 'LEFT JOIN join_table t2 ON t1.id = t2.table_id' . ') dctrn_result ' . 'ORDER BY id_0 ASC'; $sql = $this->platform->modifyLimitQuery($querySql, 5); $this->expectCteWithMaxRowNum($alteredSql, 5, $sql); } /** * @throws DBALException */ public function testModifyLimitSubqueryWithJoinAndSubqueryOrderedByColumnFromJoinTable() : void { $querySql = 'SELECT DISTINCT id_0, name_1 ' . 'FROM (' . 'SELECT t1.id AS id_0, t2.name AS name_1 ' . 'FROM table_parent t1 ' . 'LEFT JOIN join_table t2 ON t1.id = t2.table_id ' . 'ORDER BY t2.name ASC' . ') dctrn_result ' . 'ORDER BY name_1 ASC'; $alteredSql = 'SELECT DISTINCT TOP 5 id_0, name_1 ' . 'FROM (' . 'SELECT t1.id AS id_0, t2.name AS name_1 ' . 'FROM table_parent t1 ' . 'LEFT JOIN join_table t2 ON t1.id = t2.table_id' . ') dctrn_result ' . 'ORDER BY name_1 ASC'; $sql = $this->platform->modifyLimitQuery($querySql, 5); $this->expectCteWithMaxRowNum($alteredSql, 5, $sql); } /** * @throws DBALException */ public function testModifyLimitSubqueryWithJoinAndSubqueryOrderedByColumnsFromBothTables() : void { $querySql = 'SELECT DISTINCT id_0, name_1, foo_2 ' . 'FROM (' . 'SELECT t1.id AS id_0, t2.name AS name_1, t2.foo AS foo_2 ' . 'FROM table_parent t1 ' . 'LEFT JOIN join_table t2 ON t1.id = t2.table_id ' . 'ORDER BY t2.name ASC, t2.foo DESC' . ') dctrn_result ' . 'ORDER BY name_1 ASC, foo_2 DESC'; $alteredSql = 'SELECT DISTINCT TOP 5 id_0, name_1, foo_2 ' . 'FROM (' . 'SELECT t1.id AS id_0, t2.name AS name_1, t2.foo AS foo_2 ' . 'FROM table_parent t1 ' . 'LEFT JOIN join_table t2 ON t1.id = t2.table_id' . ') dctrn_result ' . 'ORDER BY name_1 ASC, foo_2 DESC'; $sql = $this->platform->modifyLimitQuery($querySql, 5); $this->expectCteWithMaxRowNum($alteredSql, 5, $sql); } public function testModifyLimitSubquerySimple() : void { $querySql = 'SELECT DISTINCT id_0 FROM ' . '(SELECT k0_.id AS id_0, k0_.field AS field_1 ' . 'FROM key_table k0_ WHERE (k0_.where_field IN (1))) dctrn_result'; $alteredSql = 'SELECT DISTINCT TOP 20 id_0 FROM (SELECT k0_.id AS id_0, k0_.field AS field_1 ' . 'FROM key_table k0_ WHERE (k0_.where_field IN (1))) dctrn_result'; $sql = $this->platform->modifyLimitQuery($querySql, 20); $this->expectCteWithMaxRowNum($alteredSql, 20, $sql); } /** * @group DDC-1360 */ public function testQuoteIdentifier() : void { self::assertEquals('[fo][o]', $this->platform->quoteIdentifier('fo]o')); self::assertEquals('[test]', $this->platform->quoteIdentifier('test')); self::assertEquals('[test].[test]', $this->platform->quoteIdentifier('test.test')); } /** * @group DDC-1360 */ public function testQuoteSingleIdentifier() : void { self::assertEquals('[fo][o]', $this->platform->quoteSingleIdentifier('fo]o')); self::assertEquals('[test]', $this->platform->quoteSingleIdentifier('test')); self::assertEquals('[test.test]', $this->platform->quoteSingleIdentifier('test.test')); } /** * @group DBAL-220 */ public function testCreateClusteredIndex() : void { $idx = new Index('idx', ['id']); $idx->addFlag('clustered'); self::assertEquals('CREATE CLUSTERED INDEX idx ON tbl (id)', $this->platform->getCreateIndexSQL($idx, 'tbl')); } /** * @group DBAL-220 */ public function testCreateNonClusteredPrimaryKeyInTable() : void { $table = new Table('tbl'); $table->addColumn('id', 'integer'); $table->setPrimaryKey(['id']); $table->getIndex('primary')->addFlag('nonclustered'); self::assertEquals(['CREATE TABLE tbl (id INT NOT NULL, PRIMARY KEY NONCLUSTERED (id))'], $this->platform->getCreateTableSQL($table)); } /** * @group DBAL-220 */ public function testCreateNonClusteredPrimaryKey() : void { $idx = new Index('idx', ['id'], false, true); $idx->addFlag('nonclustered'); self::assertEquals('ALTER TABLE tbl ADD PRIMARY KEY NONCLUSTERED (id)', $this->platform->getCreatePrimaryKeySQL($idx, 'tbl')); } public function testAlterAddPrimaryKey() : void { $idx = new Index('idx', ['id'], false, true); self::assertEquals('ALTER TABLE tbl ADD PRIMARY KEY (id)', $this->platform->getCreateIndexSQL($idx, 'tbl')); } /** * {@inheritDoc} */ protected function getQuotedColumnInPrimaryKeySQL() : array { return ['CREATE TABLE [quoted] ([create] NVARCHAR(255) NOT NULL, PRIMARY KEY ([create]))']; } /** * {@inheritDoc} */ protected function getQuotedColumnInIndexSQL() : array { return [ 'CREATE TABLE [quoted] ([create] NVARCHAR(255) NOT NULL)', 'CREATE INDEX IDX_22660D028FD6E0FB ON [quoted] ([create])', ]; } /** * {@inheritDoc} */ protected function getQuotedNameInIndexSQL() : array { return [ 'CREATE TABLE test (column1 NVARCHAR(255) NOT NULL)', 'CREATE INDEX [key] ON test (column1)', ]; } /** * {@inheritDoc} */ protected function getQuotedColumnInForeignKeySQL() : array { return [ 'CREATE TABLE [quoted] ([create] NVARCHAR(255) NOT NULL, foo NVARCHAR(255) NOT NULL, [bar] NVARCHAR(255) NOT NULL)', 'ALTER TABLE [quoted] ADD CONSTRAINT FK_WITH_RESERVED_KEYWORD FOREIGN KEY ([create], foo, [bar]) REFERENCES [foreign] ([create], bar, [foo-bar])', 'ALTER TABLE [quoted] ADD CONSTRAINT FK_WITH_NON_RESERVED_KEYWORD FOREIGN KEY ([create], foo, [bar]) REFERENCES foo ([create], bar, [foo-bar])', 'ALTER TABLE [quoted] ADD CONSTRAINT FK_WITH_INTENDED_QUOTATION FOREIGN KEY ([create], foo, [bar]) REFERENCES [foo-bar] ([create], bar, [foo-bar])', ]; } public function testGetCreateSchemaSQL() : void { $schemaName = 'schema'; $sql = $this->platform->getCreateSchemaSQL($schemaName); self::assertEquals('CREATE SCHEMA ' . $schemaName, $sql); } public function testCreateTableWithSchemaColumnComments() : void { $table = new Table('testschema.test'); $table->addColumn('id', 'integer', ['comment' => 'This is a comment']); $table->setPrimaryKey(['id']); $expectedSql = [ 'CREATE TABLE testschema.test (id INT NOT NULL, PRIMARY KEY (id))', "EXEC sp_addextendedproperty N'MS_Description', N'This is a comment', N'SCHEMA', 'testschema', N'TABLE', 'test', N'COLUMN', id", ]; self::assertEquals($expectedSql, $this->platform->getCreateTableSQL($table)); } public function testAlterTableWithSchemaColumnComments() : void { $tableDiff = new TableDiff('testschema.mytable'); $tableDiff->addedColumns['quota'] = new Column('quota', Type::getType('integer'), ['comment' => 'A comment']); $expectedSql = [ 'ALTER TABLE testschema.mytable ADD quota INT NOT NULL', "EXEC sp_addextendedproperty N'MS_Description', N'A comment', N'SCHEMA', 'testschema', N'TABLE', 'mytable', N'COLUMN', quota", ]; self::assertEquals($expectedSql, $this->platform->getAlterTableSQL($tableDiff)); } public function testAlterTableWithSchemaDropColumnComments() : void { $tableDiff = new TableDiff('testschema.mytable'); $tableDiff->changedColumns['quota'] = new ColumnDiff( 'quota', new Column('quota', Type::getType('integer'), []), ['comment'], new Column('quota', Type::getType('integer'), ['comment' => 'A comment']) ); $expectedSql = ["EXEC sp_dropextendedproperty N'MS_Description', N'SCHEMA', 'testschema', N'TABLE', 'mytable', N'COLUMN', quota"]; self::assertEquals($expectedSql, $this->platform->getAlterTableSQL($tableDiff)); } public function testAlterTableWithSchemaUpdateColumnComments() : void { $tableDiff = new TableDiff('testschema.mytable'); $tableDiff->changedColumns['quota'] = new ColumnDiff( 'quota', new Column('quota', Type::getType('integer'), ['comment' => 'B comment']), ['comment'], new Column('quota', Type::getType('integer'), ['comment' => 'A comment']) ); $expectedSql = ["EXEC sp_updateextendedproperty N'MS_Description', N'B comment', N'SCHEMA', 'testschema', N'TABLE', 'mytable', N'COLUMN', quota"]; self::assertEquals($expectedSql, $this->platform->getAlterTableSQL($tableDiff)); } /** * {@inheritDoc} * * @group DBAL-543 */ public function getCreateTableColumnCommentsSQL() : array { return [ 'CREATE TABLE test (id INT NOT NULL, PRIMARY KEY (id))', "EXEC sp_addextendedproperty N'MS_Description', N'This is a comment', N'SCHEMA', 'dbo', N'TABLE', 'test', N'COLUMN', id", ]; } /** * {@inheritDoc} * * @group DBAL-543 */ public function getAlterTableColumnCommentsSQL() : array { return [ 'ALTER TABLE mytable ADD quota INT NOT NULL', "EXEC sp_addextendedproperty N'MS_Description', N'A comment', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', quota", // todo //"EXEC sp_addextendedproperty N'MS_Description', N'B comment', N'SCHEMA', dbo, N'TABLE', mytable, N'COLUMN', baz", ]; } /** * {@inheritDoc} * * @group DBAL-543 */ public function getCreateTableColumnTypeCommentsSQL() : array { return [ 'CREATE TABLE test (id INT NOT NULL, data VARCHAR(MAX) NOT NULL, PRIMARY KEY (id))', "EXEC sp_addextendedproperty N'MS_Description', N'(DC2Type:array)', N'SCHEMA', 'dbo', N'TABLE', 'test', N'COLUMN', data", ]; } /** * @group DBAL-543 */ public function testGeneratesCreateTableSQLWithColumnComments() : void { $table = new Table('mytable'); $table->addColumn('id', 'integer', ['autoincrement' => true]); $table->addColumn('comment_null', 'integer', ['comment' => null]); $table->addColumn('comment_false', 'integer', ['comment' => false]); $table->addColumn('comment_empty_string', 'integer', ['comment' => '']); $table->addColumn('comment_integer_0', 'integer', ['comment' => 0]); $table->addColumn('comment_float_0', 'integer', ['comment' => 0.0]); $table->addColumn('comment_string_0', 'integer', ['comment' => '0']); $table->addColumn('comment', 'integer', ['comment' => 'Doctrine 0wnz you!']); $table->addColumn('`comment_quoted`', 'integer', ['comment' => 'Doctrine 0wnz comments for explicitly quoted columns!']); $table->addColumn('create', 'integer', ['comment' => 'Doctrine 0wnz comments for reserved keyword columns!']); $table->addColumn('commented_type', 'object'); $table->addColumn('commented_type_with_comment', 'array', ['comment' => 'Doctrine array type.']); $table->addColumn('comment_with_string_literal_char', 'string', ['comment' => "O'Reilly"]); $table->setPrimaryKey(['id']); self::assertEquals( [ 'CREATE TABLE mytable (id INT IDENTITY NOT NULL, comment_null INT NOT NULL, comment_false INT NOT NULL, comment_empty_string INT NOT NULL, comment_integer_0 INT NOT NULL, comment_float_0 INT NOT NULL, comment_string_0 INT NOT NULL, comment INT NOT NULL, [comment_quoted] INT NOT NULL, [create] INT NOT NULL, commented_type VARCHAR(MAX) NOT NULL, commented_type_with_comment VARCHAR(MAX) NOT NULL, comment_with_string_literal_char NVARCHAR(255) NOT NULL, PRIMARY KEY (id))', "EXEC sp_addextendedproperty N'MS_Description', N'0', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', comment_integer_0", "EXEC sp_addextendedproperty N'MS_Description', N'0', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', comment_float_0", "EXEC sp_addextendedproperty N'MS_Description', N'0', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', comment_string_0", "EXEC sp_addextendedproperty N'MS_Description', N'Doctrine 0wnz you!', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', comment", "EXEC sp_addextendedproperty N'MS_Description', N'Doctrine 0wnz comments for explicitly quoted columns!', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', [comment_quoted]", "EXEC sp_addextendedproperty N'MS_Description', N'Doctrine 0wnz comments for reserved keyword columns!', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', [create]", "EXEC sp_addextendedproperty N'MS_Description', N'(DC2Type:object)', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', commented_type", "EXEC sp_addextendedproperty N'MS_Description', N'Doctrine array type.(DC2Type:array)', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', commented_type_with_comment", "EXEC sp_addextendedproperty N'MS_Description', N'O''Reilly', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', comment_with_string_literal_char", ], $this->platform->getCreateTableSQL($table) ); } /** * @group DBAL-543 * @group DBAL-1011 */ public function testGeneratesAlterTableSQLWithColumnComments() : void { $table = new Table('mytable'); $table->addColumn('id', 'integer', ['autoincrement' => true]); $table->addColumn('comment_null', 'integer', ['comment' => null]); $table->addColumn('comment_false', 'integer', ['comment' => false]); $table->addColumn('comment_empty_string', 'integer', ['comment' => '']); $table->addColumn('comment_integer_0', 'integer', ['comment' => 0]); $table->addColumn('comment_float_0', 'integer', ['comment' => 0.0]); $table->addColumn('comment_string_0', 'integer', ['comment' => '0']); $table->addColumn('comment', 'integer', ['comment' => 'Doctrine 0wnz you!']); $table->addColumn('`comment_quoted`', 'integer', ['comment' => 'Doctrine 0wnz comments for explicitly quoted columns!']); $table->addColumn('create', 'integer', ['comment' => 'Doctrine 0wnz comments for reserved keyword columns!']); $table->addColumn('commented_type', 'object'); $table->addColumn('commented_type_with_comment', 'array', ['comment' => 'Doctrine array type.']); $table->addColumn('comment_with_string_literal_quote_char', 'array', ['comment' => "O'Reilly"]); $table->setPrimaryKey(['id']); $tableDiff = new TableDiff('mytable'); $tableDiff->fromTable = $table; $tableDiff->addedColumns['added_comment_none'] = new Column('added_comment_none', Type::getType('integer')); $tableDiff->addedColumns['added_comment_null'] = new Column('added_comment_null', Type::getType('integer'), ['comment' => null]); $tableDiff->addedColumns['added_comment_false'] = new Column('added_comment_false', Type::getType('integer'), ['comment' => false]); $tableDiff->addedColumns['added_comment_empty_string'] = new Column('added_comment_empty_string', Type::getType('integer'), ['comment' => '']); $tableDiff->addedColumns['added_comment_integer_0'] = new Column('added_comment_integer_0', Type::getType('integer'), ['comment' => 0]); $tableDiff->addedColumns['added_comment_float_0'] = new Column('added_comment_float_0', Type::getType('integer'), ['comment' => 0.0]); $tableDiff->addedColumns['added_comment_string_0'] = new Column('added_comment_string_0', Type::getType('integer'), ['comment' => '0']); $tableDiff->addedColumns['added_comment'] = new Column('added_comment', Type::getType('integer'), ['comment' => 'Doctrine']); $tableDiff->addedColumns['`added_comment_quoted`'] = new Column('`added_comment_quoted`', Type::getType('integer'), ['comment' => 'rulez']); $tableDiff->addedColumns['select'] = new Column('select', Type::getType('integer'), ['comment' => '666']); $tableDiff->addedColumns['added_commented_type'] = new Column('added_commented_type', Type::getType('object')); $tableDiff->addedColumns['added_commented_type_with_comment'] = new Column('added_commented_type_with_comment', Type::getType('array'), ['comment' => '666']); $tableDiff->addedColumns['added_comment_with_string_literal_char'] = new Column('added_comment_with_string_literal_char', Type::getType('string'), ['comment' => "''"]); $tableDiff->renamedColumns['comment_float_0'] = new Column('comment_double_0', Type::getType('decimal'), ['comment' => 'Double for real!']); // Add comment to non-commented column. $tableDiff->changedColumns['id'] = new ColumnDiff( 'id', new Column('id', Type::getType('integer'), ['autoincrement' => true, 'comment' => 'primary']), ['comment'], new Column('id', Type::getType('integer'), ['autoincrement' => true]) ); // Remove comment from null-commented column. $tableDiff->changedColumns['comment_null'] = new ColumnDiff( 'comment_null', new Column('comment_null', Type::getType('string')), ['type'], new Column('comment_null', Type::getType('integer'), ['comment' => null]) ); // Add comment to false-commented column. $tableDiff->changedColumns['comment_false'] = new ColumnDiff( 'comment_false', new Column('comment_false', Type::getType('integer'), ['comment' => 'false']), ['comment'], new Column('comment_false', Type::getType('integer'), ['comment' => false]) ); // Change type to custom type from empty string commented column. $tableDiff->changedColumns['comment_empty_string'] = new ColumnDiff( 'comment_empty_string', new Column('comment_empty_string', Type::getType('object')), ['type'], new Column('comment_empty_string', Type::getType('integer'), ['comment' => '']) ); // Change comment to false-comment from zero-string commented column. $tableDiff->changedColumns['comment_string_0'] = new ColumnDiff( 'comment_string_0', new Column('comment_string_0', Type::getType('integer'), ['comment' => false]), ['comment'], new Column('comment_string_0', Type::getType('integer'), ['comment' => '0']) ); // Remove comment from regular commented column. $tableDiff->changedColumns['comment'] = new ColumnDiff( 'comment', new Column('comment', Type::getType('integer')), ['comment'], new Column('comment', Type::getType('integer'), ['comment' => 'Doctrine 0wnz you!']) ); // Change comment and change type to custom type from regular commented column. $tableDiff->changedColumns['`comment_quoted`'] = new ColumnDiff( '`comment_quoted`', new Column('`comment_quoted`', Type::getType('array'), ['comment' => 'Doctrine array.']), ['comment', 'type'], new Column('`comment_quoted`', Type::getType('integer'), ['comment' => 'Doctrine 0wnz you!']) ); // Remove comment and change type to custom type from regular commented column. $tableDiff->changedColumns['create'] = new ColumnDiff( 'create', new Column('create', Type::getType('object')), ['comment', 'type'], new Column('create', Type::getType('integer'), ['comment' => 'Doctrine 0wnz comments for reserved keyword columns!']) ); // Add comment and change custom type to regular type from non-commented column. $tableDiff->changedColumns['commented_type'] = new ColumnDiff( 'commented_type', new Column('commented_type', Type::getType('integer'), ['comment' => 'foo']), ['comment', 'type'], new Column('commented_type', Type::getType('object')) ); // Remove comment from commented custom type column. $tableDiff->changedColumns['commented_type_with_comment'] = new ColumnDiff( 'commented_type_with_comment', new Column('commented_type_with_comment', Type::getType('array')), ['comment'], new Column('commented_type_with_comment', Type::getType('array'), ['comment' => 'Doctrine array type.']) ); // Change comment from comment with string literal char column. $tableDiff->changedColumns['comment_with_string_literal_char'] = new ColumnDiff( 'comment_with_string_literal_char', new Column('comment_with_string_literal_char', Type::getType('string'), ['comment' => "'"]), ['comment'], new Column('comment_with_string_literal_char', Type::getType('array'), ['comment' => "O'Reilly"]) ); $tableDiff->removedColumns['comment_integer_0'] = new Column('comment_integer_0', Type::getType('integer'), ['comment' => 0]); self::assertEquals( [ // Renamed columns. "sp_RENAME 'mytable.comment_float_0', 'comment_double_0', 'COLUMN'", // Added columns. 'ALTER TABLE mytable ADD added_comment_none INT NOT NULL', 'ALTER TABLE mytable ADD added_comment_null INT NOT NULL', 'ALTER TABLE mytable ADD added_comment_false INT NOT NULL', 'ALTER TABLE mytable ADD added_comment_empty_string INT NOT NULL', 'ALTER TABLE mytable ADD added_comment_integer_0 INT NOT NULL', 'ALTER TABLE mytable ADD added_comment_float_0 INT NOT NULL', 'ALTER TABLE mytable ADD added_comment_string_0 INT NOT NULL', 'ALTER TABLE mytable ADD added_comment INT NOT NULL', 'ALTER TABLE mytable ADD [added_comment_quoted] INT NOT NULL', 'ALTER TABLE mytable ADD [select] INT NOT NULL', 'ALTER TABLE mytable ADD added_commented_type VARCHAR(MAX) NOT NULL', 'ALTER TABLE mytable ADD added_commented_type_with_comment VARCHAR(MAX) NOT NULL', 'ALTER TABLE mytable ADD added_comment_with_string_literal_char NVARCHAR(255) NOT NULL', 'ALTER TABLE mytable DROP COLUMN comment_integer_0', 'ALTER TABLE mytable ALTER COLUMN comment_null NVARCHAR(255) NOT NULL', 'ALTER TABLE mytable ALTER COLUMN comment_empty_string VARCHAR(MAX) NOT NULL', 'ALTER TABLE mytable ALTER COLUMN [comment_quoted] VARCHAR(MAX) NOT NULL', 'ALTER TABLE mytable ALTER COLUMN [create] VARCHAR(MAX) NOT NULL', 'ALTER TABLE mytable ALTER COLUMN commented_type INT NOT NULL', // Added columns. "EXEC sp_addextendedproperty N'MS_Description', N'0', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', added_comment_integer_0", "EXEC sp_addextendedproperty N'MS_Description', N'0', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', added_comment_float_0", "EXEC sp_addextendedproperty N'MS_Description', N'0', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', added_comment_string_0", "EXEC sp_addextendedproperty N'MS_Description', N'Doctrine', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', added_comment", "EXEC sp_addextendedproperty N'MS_Description', N'rulez', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', [added_comment_quoted]", "EXEC sp_addextendedproperty N'MS_Description', N'666', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', [select]", "EXEC sp_addextendedproperty N'MS_Description', N'(DC2Type:object)', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', added_commented_type", "EXEC sp_addextendedproperty N'MS_Description', N'666(DC2Type:array)', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', added_commented_type_with_comment", "EXEC sp_addextendedproperty N'MS_Description', N'''''', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', added_comment_with_string_literal_char", // Changed columns. "EXEC sp_addextendedproperty N'MS_Description', N'primary', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', id", "EXEC sp_addextendedproperty N'MS_Description', N'false', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', comment_false", "EXEC sp_addextendedproperty N'MS_Description', N'(DC2Type:object)', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', comment_empty_string", "EXEC sp_dropextendedproperty N'MS_Description', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', comment_string_0", "EXEC sp_dropextendedproperty N'MS_Description', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', comment", "EXEC sp_updateextendedproperty N'MS_Description', N'Doctrine array.(DC2Type:array)', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', [comment_quoted]", "EXEC sp_updateextendedproperty N'MS_Description', N'(DC2Type:object)', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', [create]", "EXEC sp_updateextendedproperty N'MS_Description', N'foo', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', commented_type", "EXEC sp_updateextendedproperty N'MS_Description', N'(DC2Type:array)', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', commented_type_with_comment", "EXEC sp_updateextendedproperty N'MS_Description', N'''', N'SCHEMA', 'dbo', N'TABLE', 'mytable', N'COLUMN', comment_with_string_literal_char", ], $this->platform->getAlterTableSQL($tableDiff) ); } /** * @group DBAL-122 */ public function testInitializesDoctrineTypeMappings() : void { self::assertTrue($this->platform->hasDoctrineTypeMappingFor('bigint')); self::assertSame('bigint', $this->platform->getDoctrineTypeMapping('bigint')); self::assertTrue($this->platform->hasDoctrineTypeMappingFor('numeric')); self::assertSame('decimal', $this->platform->getDoctrineTypeMapping('numeric')); self::assertTrue($this->platform->hasDoctrineTypeMappingFor('bit')); self::assertSame('boolean', $this->platform->getDoctrineTypeMapping('bit')); self::assertTrue($this->platform->hasDoctrineTypeMappingFor('smallint')); self::assertSame('smallint', $this->platform->getDoctrineTypeMapping('smallint')); self::assertTrue($this->platform->hasDoctrineTypeMappingFor('decimal')); self::assertSame('decimal', $this->platform->getDoctrineTypeMapping('decimal')); self::assertTrue($this->platform->hasDoctrineTypeMappingFor('smallmoney')); self::assertSame('integer', $this->platform->getDoctrineTypeMapping('smallmoney')); self::assertTrue($this->platform->hasDoctrineTypeMappingFor('int')); self::assertSame('integer', $this->platform->getDoctrineTypeMapping('int')); self::assertTrue($this->platform->hasDoctrineTypeMappingFor('tinyint')); self::assertSame('smallint', $this->platform->getDoctrineTypeMapping('tinyint')); self::assertTrue($this->platform->hasDoctrineTypeMappingFor('money')); self::assertSame('integer', $this->platform->getDoctrineTypeMapping('money')); self::assertTrue($this->platform->hasDoctrineTypeMappingFor('float')); self::assertSame('float', $this->platform->getDoctrineTypeMapping('float')); self::assertTrue($this->platform->hasDoctrineTypeMappingFor('real')); self::assertSame('float', $this->platform->getDoctrineTypeMapping('real')); self::assertTrue($this->platform->hasDoctrineTypeMappingFor('double')); self::assertSame('float', $this->platform->getDoctrineTypeMapping('double')); self::assertTrue($this->platform->hasDoctrineTypeMappingFor('double precision')); self::assertSame('float', $this->platform->getDoctrineTypeMapping('double precision')); self::assertTrue($this->platform->hasDoctrineTypeMappingFor('smalldatetime')); self::assertSame('datetime', $this->platform->getDoctrineTypeMapping('smalldatetime')); self::assertTrue($this->platform->hasDoctrineTypeMappingFor('datetime')); self::assertSame('datetime', $this->platform->getDoctrineTypeMapping('datetime')); self::assertTrue($this->platform->hasDoctrineTypeMappingFor('char')); self::assertSame('string', $this->platform->getDoctrineTypeMapping('char')); self::assertTrue($this->platform->hasDoctrineTypeMappingFor('varchar')); self::assertSame('string', $this->platform->getDoctrineTypeMapping('varchar')); self::assertTrue($this->platform->hasDoctrineTypeMappingFor('text')); self::assertSame('text', $this->platform->getDoctrineTypeMapping('text')); self::assertTrue($this->platform->hasDoctrineTypeMappingFor('nchar')); self::assertSame('string', $this->platform->getDoctrineTypeMapping('nchar')); self::assertTrue($this->platform->hasDoctrineTypeMappingFor('nvarchar')); self::assertSame('string', $this->platform->getDoctrineTypeMapping('nvarchar')); self::assertTrue($this->platform->hasDoctrineTypeMappingFor('ntext')); self::assertSame('text', $this->platform->getDoctrineTypeMapping('ntext')); self::assertTrue($this->platform->hasDoctrineTypeMappingFor('binary')); self::assertSame('binary', $this->platform->getDoctrineTypeMapping('binary')); self::assertTrue($this->platform->hasDoctrineTypeMappingFor('varbinary')); self::assertSame('binary', $this->platform->getDoctrineTypeMapping('varbinary')); self::assertTrue($this->platform->hasDoctrineTypeMappingFor('image')); self::assertSame('blob', $this->platform->getDoctrineTypeMapping('image')); self::assertTrue($this->platform->hasDoctrineTypeMappingFor('uniqueidentifier')); self::assertSame('guid', $this->platform->getDoctrineTypeMapping('uniqueidentifier')); } protected function getBinaryMaxLength() : int { return 8000; } public function testReturnsBinaryTypeDeclarationSQL() : void { self::assertSame('VARBINARY(255)', $this->platform->getBinaryTypeDeclarationSQL([])); self::assertSame('VARBINARY(255)', $this->platform->getBinaryTypeDeclarationSQL(['length' => 0])); self::assertSame('VARBINARY(8000)', $this->platform->getBinaryTypeDeclarationSQL(['length' => 8000])); self::assertSame('BINARY(255)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true])); self::assertSame('BINARY(255)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 0])); self::assertSame('BINARY(8000)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 8000])); } /** * @group legacy * @expectedDeprecation Binary field length 8001 is greater than supported by the platform (8000). Reduce the field length or use a BLOB field instead. */ public function testReturnsBinaryTypeLongerThanMaxDeclarationSQL() : void { self::assertSame('VARBINARY(MAX)', $this->platform->getBinaryTypeDeclarationSQL(['length' => 8001])); self::assertSame('VARBINARY(MAX)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 8001])); } /** * {@inheritDoc} * * @group DBAL-234 */ protected function getAlterTableRenameIndexSQL() : array { return ["EXEC sp_RENAME N'mytable.idx_foo', N'idx_bar', N'INDEX'"]; } /** * {@inheritDoc} * * @group DBAL-234 */ protected function getQuotedAlterTableRenameIndexSQL() : array { return [ "EXEC sp_RENAME N'[table].[create]', N'[select]', N'INDEX'", "EXEC sp_RENAME N'[table].[foo]', N'[bar]', N'INDEX'", ]; } /** * @group DBAL-825 */ public function testChangeColumnsTypeWithDefaultValue() : void { $tableName = 'column_def_change_type'; $table = new Table($tableName); $table->addColumn('col_int', 'smallint', ['default' => 666]); $table->addColumn('col_string', 'string', ['default' => 'foo']); $tableDiff = new TableDiff($tableName); $tableDiff->fromTable = $table; $tableDiff->changedColumns['col_int'] = new ColumnDiff( 'col_int', new Column('col_int', Type::getType('integer'), ['default' => 666]), ['type'], new Column('col_int', Type::getType('smallint'), ['default' => 666]) ); $tableDiff->changedColumns['col_string'] = new ColumnDiff( 'col_string', new Column('col_string', Type::getType('string'), ['default' => 666, 'fixed' => true]), ['fixed'], new Column('col_string', Type::getType('string'), ['default' => 666]) ); $expected = $this->platform->getAlterTableSQL($tableDiff); self::assertSame( $expected, [ 'ALTER TABLE column_def_change_type DROP CONSTRAINT DF_829302E0_FA2CB292', 'ALTER TABLE column_def_change_type ALTER COLUMN col_int INT NOT NULL', 'ALTER TABLE column_def_change_type ADD CONSTRAINT DF_829302E0_FA2CB292 DEFAULT 666 FOR col_int', 'ALTER TABLE column_def_change_type DROP CONSTRAINT DF_829302E0_2725A6D0', 'ALTER TABLE column_def_change_type ALTER COLUMN col_string NCHAR(255) NOT NULL', "ALTER TABLE column_def_change_type ADD CONSTRAINT DF_829302E0_2725A6D0 DEFAULT '666' FOR col_string", ] ); } /** * {@inheritdoc} */ protected function getQuotedAlterTableRenameColumnSQL() : array { return [ "sp_RENAME 'mytable.unquoted1', 'unquoted', 'COLUMN'", "sp_RENAME 'mytable.unquoted2', '[where]', 'COLUMN'", "sp_RENAME 'mytable.unquoted3', '[foo]', 'COLUMN'", "sp_RENAME 'mytable.[create]', 'reserved_keyword', 'COLUMN'", "sp_RENAME 'mytable.[table]', '[from]', 'COLUMN'", "sp_RENAME 'mytable.[select]', '[bar]', 'COLUMN'", "sp_RENAME 'mytable.quoted1', 'quoted', 'COLUMN'", "sp_RENAME 'mytable.quoted2', '[and]', 'COLUMN'", "sp_RENAME 'mytable.quoted3', '[baz]', 'COLUMN'", ]; } /** * {@inheritdoc} */ protected function getQuotedAlterTableChangeColumnLengthSQL() : array { $this->markTestIncomplete('Not implemented yet'); } /** * {@inheritDoc} * * @group DBAL-807 */ protected function getAlterTableRenameIndexInSchemaSQL() : array { return ["EXEC sp_RENAME N'myschema.mytable.idx_foo', N'idx_bar', N'INDEX'"]; } /** * {@inheritDoc} * * @group DBAL-807 */ protected function getQuotedAlterTableRenameIndexInSchemaSQL() : array { return [ "EXEC sp_RENAME N'[schema].[table].[create]', N'[select]', N'INDEX'", "EXEC sp_RENAME N'[schema].[table].[foo]', N'[bar]', N'INDEX'", ]; } protected function getQuotesDropForeignKeySQL() : string { return 'ALTER TABLE [table] DROP CONSTRAINT [select]'; } protected function getQuotesDropConstraintSQL() : string { return 'ALTER TABLE [table] DROP CONSTRAINT [select]'; } /** * @param mixed[] $column * * @dataProvider getGeneratesIdentifierNamesInDefaultConstraintDeclarationSQL * @group DBAL-830 */ public function testGeneratesIdentifierNamesInDefaultConstraintDeclarationSQL(string $table, array $column, string $expectedSql) : void { self::assertSame($expectedSql, $this->platform->getDefaultConstraintDeclarationSQL($table, $column)); } /** * @return mixed[][] */ public static function getGeneratesIdentifierNamesInDefaultConstraintDeclarationSQL() : iterable { return [ // Unquoted identifiers non-reserved keywords. ['mytable', ['name' => 'mycolumn', 'default' => 'foo'], " CONSTRAINT DF_6B2BD609_9BADD926 DEFAULT 'foo' FOR mycolumn"], // Quoted identifiers non-reserved keywords. ['`mytable`', ['name' => '`mycolumn`', 'default' => 'foo'], " CONSTRAINT DF_6B2BD609_9BADD926 DEFAULT 'foo' FOR [mycolumn]"], // Unquoted identifiers reserved keywords. ['table', ['name' => 'select', 'default' => 'foo'], " CONSTRAINT DF_F6298F46_4BF2EAC0 DEFAULT 'foo' FOR [select]"], // Quoted identifiers reserved keywords. ['`table`', ['name' => '`select`', 'default' => 'foo'], " CONSTRAINT DF_F6298F46_4BF2EAC0 DEFAULT 'foo' FOR [select]"], ]; } /** * @param string[] $expectedSql * * @dataProvider getGeneratesIdentifierNamesInCreateTableSQL * @group DBAL-830 */ public function testGeneratesIdentifierNamesInCreateTableSQL(Table $table, array $expectedSql) : void { self::assertSame($expectedSql, $this->platform->getCreateTableSQL($table)); } /** * @return mixed[][] */ public static function getGeneratesIdentifierNamesInCreateTableSQL() : iterable { return [ // Unquoted identifiers non-reserved keywords. [ new Table('mytable', [new Column('mycolumn', Type::getType('string'), ['default' => 'foo'])]), [ 'CREATE TABLE mytable (mycolumn NVARCHAR(255) NOT NULL)', "ALTER TABLE mytable ADD CONSTRAINT DF_6B2BD609_9BADD926 DEFAULT 'foo' FOR mycolumn", ], ], // Quoted identifiers reserved keywords. [ new Table('`mytable`', [new Column('`mycolumn`', Type::getType('string'), ['default' => 'foo'])]), [ 'CREATE TABLE [mytable] ([mycolumn] NVARCHAR(255) NOT NULL)', "ALTER TABLE [mytable] ADD CONSTRAINT DF_6B2BD609_9BADD926 DEFAULT 'foo' FOR [mycolumn]", ], ], // Unquoted identifiers reserved keywords. [ new Table('table', [new Column('select', Type::getType('string'), ['default' => 'foo'])]), [ 'CREATE TABLE [table] ([select] NVARCHAR(255) NOT NULL)', "ALTER TABLE [table] ADD CONSTRAINT DF_F6298F46_4BF2EAC0 DEFAULT 'foo' FOR [select]", ], ], // Quoted identifiers reserved keywords. [ new Table('`table`', [new Column('`select`', Type::getType('string'), ['default' => 'foo'])]), [ 'CREATE TABLE [table] ([select] NVARCHAR(255) NOT NULL)', "ALTER TABLE [table] ADD CONSTRAINT DF_F6298F46_4BF2EAC0 DEFAULT 'foo' FOR [select]", ], ], ]; } /** * @param string[] $expectedSql * * @dataProvider getGeneratesIdentifierNamesInAlterTableSQL * @group DBAL-830 */ public function testGeneratesIdentifierNamesInAlterTableSQL(TableDiff $tableDiff, array $expectedSql) : void { self::assertSame($expectedSql, $this->platform->getAlterTableSQL($tableDiff)); } /** * @return mixed[][] */ public static function getGeneratesIdentifierNamesInAlterTableSQL() : iterable { return [ // Unquoted identifiers non-reserved keywords. [ new TableDiff( 'mytable', [new Column('addcolumn', Type::getType('string'), ['default' => 'foo'])], [ 'mycolumn' => new ColumnDiff( 'mycolumn', new Column('mycolumn', Type::getType('string'), ['default' => 'bar']), ['default'], new Column('mycolumn', Type::getType('string'), ['default' => 'foo']) ), ], [new Column('removecolumn', Type::getType('string'), ['default' => 'foo'])] ), [ 'ALTER TABLE mytable ADD addcolumn NVARCHAR(255) NOT NULL', "ALTER TABLE mytable ADD CONSTRAINT DF_6B2BD609_4AD86123 DEFAULT 'foo' FOR addcolumn", 'ALTER TABLE mytable DROP COLUMN removecolumn', 'ALTER TABLE mytable DROP CONSTRAINT DF_6B2BD609_9BADD926', 'ALTER TABLE mytable ALTER COLUMN mycolumn NVARCHAR(255) NOT NULL', "ALTER TABLE mytable ADD CONSTRAINT DF_6B2BD609_9BADD926 DEFAULT 'bar' FOR mycolumn", ], ], // Quoted identifiers non-reserved keywords. [ new TableDiff( '`mytable`', [new Column('`addcolumn`', Type::getType('string'), ['default' => 'foo'])], [ 'mycolumn' => new ColumnDiff( '`mycolumn`', new Column('`mycolumn`', Type::getType('string'), ['default' => 'bar']), ['default'], new Column('`mycolumn`', Type::getType('string'), ['default' => 'foo']) ), ], [new Column('`removecolumn`', Type::getType('string'), ['default' => 'foo'])] ), [ 'ALTER TABLE [mytable] ADD [addcolumn] NVARCHAR(255) NOT NULL', "ALTER TABLE [mytable] ADD CONSTRAINT DF_6B2BD609_4AD86123 DEFAULT 'foo' FOR [addcolumn]", 'ALTER TABLE [mytable] DROP COLUMN [removecolumn]', 'ALTER TABLE [mytable] DROP CONSTRAINT DF_6B2BD609_9BADD926', 'ALTER TABLE [mytable] ALTER COLUMN [mycolumn] NVARCHAR(255) NOT NULL', "ALTER TABLE [mytable] ADD CONSTRAINT DF_6B2BD609_9BADD926 DEFAULT 'bar' FOR [mycolumn]", ], ], // Unquoted identifiers reserved keywords. [ new TableDiff( 'table', [new Column('add', Type::getType('string'), ['default' => 'foo'])], [ 'select' => new ColumnDiff( 'select', new Column('select', Type::getType('string'), ['default' => 'bar']), ['default'], new Column('select', Type::getType('string'), ['default' => 'foo']) ), ], [new Column('drop', Type::getType('string'), ['default' => 'foo'])] ), [ 'ALTER TABLE [table] ADD [add] NVARCHAR(255) NOT NULL', "ALTER TABLE [table] ADD CONSTRAINT DF_F6298F46_FD1A73E7 DEFAULT 'foo' FOR [add]", 'ALTER TABLE [table] DROP COLUMN [drop]', 'ALTER TABLE [table] DROP CONSTRAINT DF_F6298F46_4BF2EAC0', 'ALTER TABLE [table] ALTER COLUMN [select] NVARCHAR(255) NOT NULL', "ALTER TABLE [table] ADD CONSTRAINT DF_F6298F46_4BF2EAC0 DEFAULT 'bar' FOR [select]", ], ], // Quoted identifiers reserved keywords. [ new TableDiff( '`table`', [new Column('`add`', Type::getType('string'), ['default' => 'foo'])], [ 'select' => new ColumnDiff( '`select`', new Column('`select`', Type::getType('string'), ['default' => 'bar']), ['default'], new Column('`select`', Type::getType('string'), ['default' => 'foo']) ), ], [new Column('`drop`', Type::getType('string'), ['default' => 'foo'])] ), [ 'ALTER TABLE [table] ADD [add] NVARCHAR(255) NOT NULL', "ALTER TABLE [table] ADD CONSTRAINT DF_F6298F46_FD1A73E7 DEFAULT 'foo' FOR [add]", 'ALTER TABLE [table] DROP COLUMN [drop]', 'ALTER TABLE [table] DROP CONSTRAINT DF_F6298F46_4BF2EAC0', 'ALTER TABLE [table] ALTER COLUMN [select] NVARCHAR(255) NOT NULL', "ALTER TABLE [table] ADD CONSTRAINT DF_F6298F46_4BF2EAC0 DEFAULT 'bar' FOR [select]", ], ], ]; } /** * @group DBAL-423 */ public function testReturnsGuidTypeDeclarationSQL() : void { self::assertSame('UNIQUEIDENTIFIER', $this->platform->getGuidTypeDeclarationSQL([])); } /** * {@inheritdoc} */ public function getAlterTableRenameColumnSQL() : array { return [ "sp_RENAME 'foo.bar', 'baz', 'COLUMN'", 'ALTER TABLE foo DROP CONSTRAINT DF_8C736521_76FF8CAA', 'ALTER TABLE foo ADD CONSTRAINT DF_8C736521_78240498 DEFAULT 666 FOR baz', ]; } /** * {@inheritdoc} */ protected function getQuotesTableIdentifiersInAlterTableSQL() : array { return [ 'ALTER TABLE [foo] DROP CONSTRAINT fk1', 'ALTER TABLE [foo] DROP CONSTRAINT fk2', "sp_RENAME '[foo].id', 'war', 'COLUMN'", 'ALTER TABLE [foo] ADD bloo INT NOT NULL', 'ALTER TABLE [foo] DROP COLUMN baz', 'ALTER TABLE [foo] ALTER COLUMN bar INT', "sp_RENAME '[foo]', 'table'", "DECLARE @sql NVARCHAR(MAX) = N''; " . "SELECT @sql += N'EXEC sp_rename N''' + dc.name + ''', N''' + REPLACE(dc.name, '8C736521', 'F6298F46') + ''', " . "''OBJECT'';' FROM sys.default_constraints dc JOIN sys.tables tbl ON dc.parent_object_id = tbl.object_id " . "WHERE tbl.name = 'table';EXEC sp_executesql @sql", 'ALTER TABLE [table] ADD CONSTRAINT fk_add FOREIGN KEY (fk3) REFERENCES fk_table (id)', 'ALTER TABLE [table] ADD CONSTRAINT fk2 FOREIGN KEY (fk2) REFERENCES fk_table2 (id)', ]; } /** * {@inheritdoc} */ protected function getCommentOnColumnSQL() : array { return [ "COMMENT ON COLUMN foo.bar IS 'comment'", "COMMENT ON COLUMN [Foo].[BAR] IS 'comment'", "COMMENT ON COLUMN [select].[from] IS 'comment'", ]; } /** * {@inheritdoc} */ public static function getReturnsForeignKeyReferentialActionSQL() : iterable { return [ ['CASCADE', 'CASCADE'], ['SET NULL', 'SET NULL'], ['NO ACTION', 'NO ACTION'], ['RESTRICT', 'NO ACTION'], ['SET DEFAULT', 'SET DEFAULT'], ['CaScAdE', 'CASCADE'], ]; } /** * {@inheritdoc} */ protected function getQuotesReservedKeywordInUniqueConstraintDeclarationSQL() : string { return 'CONSTRAINT [select] UNIQUE (foo) WHERE foo IS NOT NULL'; } /** * {@inheritdoc} */ protected function getQuotesReservedKeywordInIndexDeclarationSQL() : string { return 'INDEX [select] (foo)'; } /** * {@inheritdoc} */ protected function getQuotesReservedKeywordInTruncateTableSQL() : string { return 'TRUNCATE TABLE [select]'; } /** * {@inheritdoc} */ protected function getAlterStringToFixedStringSQL() : array { return ['ALTER TABLE mytable ALTER COLUMN name NCHAR(2) NOT NULL']; } /** * {@inheritdoc} */ protected function getGeneratesAlterTableRenameIndexUsedByForeignKeySQL() : array { return ["EXEC sp_RENAME N'mytable.idx_foo', N'idx_foo_renamed', N'INDEX'"]; } public function testModifyLimitQueryWithTopNSubQueryWithOrderBy() : void { $querySql = 'SELECT * FROM test t WHERE t.id = (SELECT TOP 1 t2.id FROM test t2 ORDER BY t2.data DESC)'; $alteredSql = 'SELECT TOP 10 * FROM test t WHERE t.id = (SELECT TOP 1 t2.id FROM test t2 ORDER BY t2.data DESC)'; $sql = $this->platform->modifyLimitQuery($querySql, 10); $this->expectCteWithMaxRowNum($alteredSql, 10, $sql); $querySql = 'SELECT * FROM test t WHERE t.id = (SELECT TOP 1 t2.id FROM test t2 ORDER BY t2.data DESC) ORDER BY t.data2 DESC'; $alteredSql = 'SELECT TOP 10 * FROM test t WHERE t.id = (SELECT TOP 1 t2.id FROM test t2 ORDER BY t2.data DESC) ORDER BY t.data2 DESC'; $sql = $this->platform->modifyLimitQuery($querySql, 10); $this->expectCteWithMaxRowNum($alteredSql, 10, $sql); } /** * @group DBAL-2436 */ public function testQuotesTableNameInListTableColumnsSQL() : void { self::assertStringContainsStringIgnoringCase( "'Foo''Bar\\'", $this->platform->getListTableColumnsSQL("Foo'Bar\\") ); } /** * @group DBAL-2436 */ public function testQuotesSchemaNameInListTableColumnsSQL() : void { self::assertStringContainsStringIgnoringCase( "'Foo''Bar\\'", $this->platform->getListTableColumnsSQL("Foo'Bar\\.baz_table") ); } /** * @group DBAL-2436 */ public function testQuotesTableNameInListTableForeignKeysSQL() : void { self::assertStringContainsStringIgnoringCase( "'Foo''Bar\\'", $this->platform->getListTableForeignKeysSQL("Foo'Bar\\") ); } /** * @group DBAL-2436 */ public function testQuotesSchemaNameInListTableForeignKeysSQL() : void { self::assertStringContainsStringIgnoringCase( "'Foo''Bar\\'", $this->platform->getListTableForeignKeysSQL("Foo'Bar\\.baz_table") ); } /** * @group DBAL-2436 */ public function testQuotesTableNameInListTableIndexesSQL() : void { self::assertStringContainsStringIgnoringCase( "'Foo''Bar\\'", $this->platform->getListTableIndexesSQL("Foo'Bar\\") ); } /** * @group DBAL-2436 */ public function testQuotesSchemaNameInListTableIndexesSQL() : void { self::assertStringContainsStringIgnoringCase( "'Foo''Bar\\'", $this->platform->getListTableIndexesSQL("Foo'Bar\\.baz_table") ); } /** * @group 2859 */ public function testGetDefaultValueDeclarationSQLForDateType() : void { $currentDateSql = $this->platform->getCurrentDateSQL(); foreach (['date', 'date_immutable'] as $type) { $field = [ 'type' => Type::getType($type), 'default' => $currentDateSql, ]; self::assertSame( ' DEFAULT CONVERT(date, GETDATE())', $this->platform->getDefaultValueDeclarationSQL($field) ); } } public function testSupportsColumnCollation() : void { self::assertTrue($this->platform->supportsColumnCollation()); } public function testColumnCollationDeclarationSQL() : void { self::assertSame( 'COLLATE Latin1_General_CS_AS_KS_WS', $this->platform->getColumnCollationDeclarationSQL('Latin1_General_CS_AS_KS_WS') ); } public function testGetCreateTableSQLWithColumnCollation() : void { $table = new Table('foo'); $table->addColumn('no_collation', 'string'); $table->addColumn('column_collation', 'string')->setPlatformOption('collation', 'Latin1_General_CS_AS_KS_WS'); self::assertSame( ['CREATE TABLE foo (no_collation NVARCHAR(255) NOT NULL, column_collation NVARCHAR(255) COLLATE Latin1_General_CS_AS_KS_WS NOT NULL)'], $this->platform->getCreateTableSQL($table), 'Column "no_collation" will use the default collation from the table/database and "column_collation" overwrites the collation on this column' ); } private function expectCteWithMaxRowNum(string $expectedSql, int $expectedMax, string $sql) : void { $pattern = 'WITH dctrn_cte AS (%s) SELECT * FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS doctrine_rownum FROM dctrn_cte) AS doctrine_tbl WHERE doctrine_rownum <= %d ORDER BY doctrine_rownum ASC'; self::assertEquals(sprintf($pattern, $expectedSql, $expectedMax), $sql); } private function expectCteWithMinAndMaxRowNums(string $expectedSql, int $expectedMin, int $expectedMax, string $sql) : void { $pattern = 'WITH dctrn_cte AS (%s) SELECT * FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS doctrine_rownum FROM dctrn_cte) AS doctrine_tbl WHERE doctrine_rownum >= %d AND doctrine_rownum <= %d ORDER BY doctrine_rownum ASC'; self::assertEquals(sprintf($pattern, $expectedSql, $expectedMin, $expectedMax), $sql); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Platforms/DB2PlatformTest.php000066400000000000000000000704231360544566000272170ustar00rootroot00000000000000platform->getName()); } public function testGeneratesCreateTableSQLWithCommonIndexes() : void { $table = new Table('test'); $table->addColumn('id', 'integer'); $table->addColumn('name', 'string', ['length' => 50]); $table->setPrimaryKey(['id']); $table->addIndex(['name']); $table->addIndex(['id', 'name'], 'composite_idx'); self::assertEquals( [ 'CREATE TABLE test (id INTEGER NOT NULL, name VARCHAR(50) NOT NULL, PRIMARY KEY(id))', 'CREATE INDEX IDX_D87F7E0C5E237E06 ON test (name)', 'CREATE INDEX composite_idx ON test (id, name)', ], $this->platform->getCreateTableSQL($table) ); } public function testGeneratesCreateTableSQLWithForeignKeyConstraints() : void { $table = new Table('test'); $table->addColumn('id', 'integer'); $table->addColumn('fk_1', 'integer'); $table->addColumn('fk_2', 'integer'); $table->setPrimaryKey(['id']); $table->addForeignKeyConstraint('foreign_table', ['fk_1', 'fk_2'], ['pk_1', 'pk_2']); $table->addForeignKeyConstraint( 'foreign_table2', ['fk_1', 'fk_2'], ['pk_1', 'pk_2'], [], 'named_fk' ); self::assertEquals( [ 'CREATE TABLE test (id INTEGER NOT NULL, fk_1 INTEGER NOT NULL, fk_2 INTEGER NOT NULL)', 'ALTER TABLE test ADD CONSTRAINT FK_D87F7E0C177612A38E7F4319 FOREIGN KEY (fk_1, fk_2) REFERENCES foreign_table (pk_1, pk_2)', 'ALTER TABLE test ADD CONSTRAINT named_fk FOREIGN KEY (fk_1, fk_2) REFERENCES foreign_table2 (pk_1, pk_2)', ], $this->platform->getCreateTableSQL($table, AbstractPlatform::CREATE_FOREIGNKEYS) ); } public function testGeneratesCreateTableSQLWithCheckConstraints() : void { $table = new Table('test'); $table->addColumn('id', 'integer'); $table->addColumn('check_max', 'integer', ['platformOptions' => ['max' => 10]]); $table->addColumn('check_min', 'integer', ['platformOptions' => ['min' => 10]]); $table->setPrimaryKey(['id']); self::assertEquals( ['CREATE TABLE test (id INTEGER NOT NULL, check_max INTEGER NOT NULL, check_min INTEGER NOT NULL, PRIMARY KEY(id), CHECK (check_max <= 10), CHECK (check_min >= 10))'], $this->platform->getCreateTableSQL($table) ); } public function testGeneratesColumnTypesDeclarationSQL() : void { $fullColumnDef = [ 'length' => 10, 'fixed' => true, 'unsigned' => true, 'autoincrement' => true, ]; self::assertEquals('VARCHAR(255)', $this->platform->getVarcharTypeDeclarationSQL([])); self::assertEquals('VARCHAR(10)', $this->platform->getVarcharTypeDeclarationSQL(['length' => 10])); self::assertEquals('CHAR(254)', $this->platform->getVarcharTypeDeclarationSQL(['fixed' => true])); self::assertEquals('CHAR(10)', $this->platform->getVarcharTypeDeclarationSQL($fullColumnDef)); self::assertEquals('SMALLINT', $this->platform->getSmallIntTypeDeclarationSQL([])); self::assertEquals('SMALLINT', $this->platform->getSmallIntTypeDeclarationSQL(['unsigned' => true])); self::assertEquals('SMALLINT GENERATED BY DEFAULT AS IDENTITY', $this->platform->getSmallIntTypeDeclarationSQL($fullColumnDef)); self::assertEquals('INTEGER', $this->platform->getIntegerTypeDeclarationSQL([])); self::assertEquals('INTEGER', $this->platform->getIntegerTypeDeclarationSQL(['unsigned' => true])); self::assertEquals('INTEGER GENERATED BY DEFAULT AS IDENTITY', $this->platform->getIntegerTypeDeclarationSQL($fullColumnDef)); self::assertEquals('BIGINT', $this->platform->getBigIntTypeDeclarationSQL([])); self::assertEquals('BIGINT', $this->platform->getBigIntTypeDeclarationSQL(['unsigned' => true])); self::assertEquals('BIGINT GENERATED BY DEFAULT AS IDENTITY', $this->platform->getBigIntTypeDeclarationSQL($fullColumnDef)); self::assertEquals('BLOB(1M)', $this->platform->getBlobTypeDeclarationSQL($fullColumnDef)); self::assertEquals('SMALLINT', $this->platform->getBooleanTypeDeclarationSQL($fullColumnDef)); self::assertEquals('CLOB(1M)', $this->platform->getClobTypeDeclarationSQL($fullColumnDef)); self::assertEquals('DATE', $this->platform->getDateTypeDeclarationSQL($fullColumnDef)); self::assertEquals('TIMESTAMP(0) WITH DEFAULT', $this->platform->getDateTimeTypeDeclarationSQL(['version' => true])); self::assertEquals('TIMESTAMP(0)', $this->platform->getDateTimeTypeDeclarationSQL($fullColumnDef)); self::assertEquals('TIME', $this->platform->getTimeTypeDeclarationSQL($fullColumnDef)); } public function testInitializesDoctrineTypeMappings() : void { $this->platform->initializeDoctrineTypeMappings(); self::assertTrue($this->platform->hasDoctrineTypeMappingFor('smallint')); self::assertSame('smallint', $this->platform->getDoctrineTypeMapping('smallint')); self::assertTrue($this->platform->hasDoctrineTypeMappingFor('bigint')); self::assertSame('bigint', $this->platform->getDoctrineTypeMapping('bigint')); self::assertTrue($this->platform->hasDoctrineTypeMappingFor('integer')); self::assertSame('integer', $this->platform->getDoctrineTypeMapping('integer')); self::assertTrue($this->platform->hasDoctrineTypeMappingFor('time')); self::assertSame('time', $this->platform->getDoctrineTypeMapping('time')); self::assertTrue($this->platform->hasDoctrineTypeMappingFor('date')); self::assertSame('date', $this->platform->getDoctrineTypeMapping('date')); self::assertTrue($this->platform->hasDoctrineTypeMappingFor('varchar')); self::assertSame('string', $this->platform->getDoctrineTypeMapping('varchar')); self::assertTrue($this->platform->hasDoctrineTypeMappingFor('character')); self::assertSame('string', $this->platform->getDoctrineTypeMapping('character')); self::assertTrue($this->platform->hasDoctrineTypeMappingFor('clob')); self::assertSame('text', $this->platform->getDoctrineTypeMapping('clob')); self::assertTrue($this->platform->hasDoctrineTypeMappingFor('blob')); self::assertSame('blob', $this->platform->getDoctrineTypeMapping('blob')); self::assertTrue($this->platform->hasDoctrineTypeMappingFor('decimal')); self::assertSame('decimal', $this->platform->getDoctrineTypeMapping('decimal')); self::assertTrue($this->platform->hasDoctrineTypeMappingFor('double')); self::assertSame('float', $this->platform->getDoctrineTypeMapping('double')); self::assertTrue($this->platform->hasDoctrineTypeMappingFor('real')); self::assertSame('float', $this->platform->getDoctrineTypeMapping('real')); self::assertTrue($this->platform->hasDoctrineTypeMappingFor('timestamp')); self::assertSame('datetime', $this->platform->getDoctrineTypeMapping('timestamp')); } /** * {@inheritDoc} */ public function getIsCommentedDoctrineType() : array { $data = parent::getIsCommentedDoctrineType(); $data[Types::BOOLEAN] = [Type::getType(Types::BOOLEAN), true]; return $data; } public function testGeneratesDDLSnippets() : void { self::assertEquals('CREATE DATABASE foobar', $this->platform->getCreateDatabaseSQL('foobar')); self::assertEquals('DROP DATABASE foobar', $this->platform->getDropDatabaseSQL('foobar')); self::assertEquals('DECLARE GLOBAL TEMPORARY TABLE', $this->platform->getCreateTemporaryTableSnippetSQL()); self::assertEquals('TRUNCATE foobar IMMEDIATE', $this->platform->getTruncateTableSQL('foobar')); self::assertEquals('TRUNCATE foobar IMMEDIATE', $this->platform->getTruncateTableSQL('foobar'), true); $viewSql = 'SELECT * FROM footable'; self::assertEquals('CREATE VIEW fooview AS ' . $viewSql, $this->platform->getCreateViewSQL('fooview', $viewSql)); self::assertEquals('DROP VIEW fooview', $this->platform->getDropViewSQL('fooview')); } public function testGeneratesCreateUnnamedPrimaryKeySQL() : void { self::assertEquals( 'ALTER TABLE foo ADD PRIMARY KEY (a, b)', $this->platform->getCreatePrimaryKeySQL( new Index('any_pk_name', ['a', 'b'], true, true), 'foo' ) ); } public function testGeneratesSQLSnippets() : void { self::assertEquals('CURRENT DATE', $this->platform->getCurrentDateSQL()); self::assertEquals('CURRENT TIME', $this->platform->getCurrentTimeSQL()); self::assertEquals('CURRENT TIMESTAMP', $this->platform->getCurrentTimestampSQL()); self::assertEquals("'1987/05/02' + 4 DAY", $this->platform->getDateAddDaysExpression("'1987/05/02'", 4)); self::assertEquals("'1987/05/02' + 12 HOUR", $this->platform->getDateAddHourExpression("'1987/05/02'", 12)); self::assertEquals("'1987/05/02' + 2 MINUTE", $this->platform->getDateAddMinutesExpression("'1987/05/02'", 2)); self::assertEquals("'1987/05/02' + 102 MONTH", $this->platform->getDateAddMonthExpression("'1987/05/02'", 102)); self::assertEquals("'1987/05/02' + 15 MONTH", $this->platform->getDateAddQuartersExpression("'1987/05/02'", 5)); self::assertEquals("'1987/05/02' + 1 SECOND", $this->platform->getDateAddSecondsExpression("'1987/05/02'", 1)); self::assertEquals("'1987/05/02' + 21 DAY", $this->platform->getDateAddWeeksExpression("'1987/05/02'", 3)); self::assertEquals("'1987/05/02' + 10 YEAR", $this->platform->getDateAddYearsExpression("'1987/05/02'", 10)); self::assertEquals("DAYS('1987/05/02') - DAYS('1987/04/01')", $this->platform->getDateDiffExpression("'1987/05/02'", "'1987/04/01'")); self::assertEquals("'1987/05/02' - 4 DAY", $this->platform->getDateSubDaysExpression("'1987/05/02'", 4)); self::assertEquals("'1987/05/02' - 12 HOUR", $this->platform->getDateSubHourExpression("'1987/05/02'", 12)); self::assertEquals("'1987/05/02' - 2 MINUTE", $this->platform->getDateSubMinutesExpression("'1987/05/02'", 2)); self::assertEquals("'1987/05/02' - 102 MONTH", $this->platform->getDateSubMonthExpression("'1987/05/02'", 102)); self::assertEquals("'1987/05/02' - 15 MONTH", $this->platform->getDateSubQuartersExpression("'1987/05/02'", 5)); self::assertEquals("'1987/05/02' - 1 SECOND", $this->platform->getDateSubSecondsExpression("'1987/05/02'", 1)); self::assertEquals("'1987/05/02' - 21 DAY", $this->platform->getDateSubWeeksExpression("'1987/05/02'", 3)); self::assertEquals("'1987/05/02' - 10 YEAR", $this->platform->getDateSubYearsExpression("'1987/05/02'", 10)); self::assertEquals(' WITH RR USE AND KEEP UPDATE LOCKS', $this->platform->getForUpdateSQL()); self::assertEquals('LOCATE(substring_column, string_column)', $this->platform->getLocateExpression('string_column', 'substring_column')); self::assertEquals('LOCATE(substring_column, string_column)', $this->platform->getLocateExpression('string_column', 'substring_column')); self::assertEquals('LOCATE(substring_column, string_column, 1)', $this->platform->getLocateExpression('string_column', 'substring_column', 1)); self::assertEquals('SUBSTR(column, 5)', $this->platform->getSubstringExpression('column', 5)); self::assertEquals('SUBSTR(column, 5, 2)', $this->platform->getSubstringExpression('column', 5, 2)); } public function testModifiesLimitQuery() : void { self::assertEquals( 'SELECT * FROM user', $this->platform->modifyLimitQuery('SELECT * FROM user', null, null) ); self::assertEquals( 'SELECT db22.* FROM (SELECT db21.*, ROW_NUMBER() OVER() AS DC_ROWNUM FROM (SELECT * FROM user) db21) db22 WHERE db22.DC_ROWNUM <= 10', $this->platform->modifyLimitQuery('SELECT * FROM user', 10, 0) ); self::assertEquals( 'SELECT db22.* FROM (SELECT db21.*, ROW_NUMBER() OVER() AS DC_ROWNUM FROM (SELECT * FROM user) db21) db22 WHERE db22.DC_ROWNUM <= 10', $this->platform->modifyLimitQuery('SELECT * FROM user', 10) ); self::assertEquals( 'SELECT db22.* FROM (SELECT db21.*, ROW_NUMBER() OVER() AS DC_ROWNUM FROM (SELECT * FROM user) db21) db22 WHERE db22.DC_ROWNUM >= 6 AND db22.DC_ROWNUM <= 15', $this->platform->modifyLimitQuery('SELECT * FROM user', 10, 5) ); self::assertEquals( 'SELECT db22.* FROM (SELECT db21.*, ROW_NUMBER() OVER() AS DC_ROWNUM FROM (SELECT * FROM user) db21) db22 WHERE db22.DC_ROWNUM >= 6 AND db22.DC_ROWNUM <= 5', $this->platform->modifyLimitQuery('SELECT * FROM user', 0, 5) ); } public function testPrefersIdentityColumns() : void { self::assertTrue($this->platform->prefersIdentityColumns()); } public function testSupportsIdentityColumns() : void { self::assertTrue($this->platform->supportsIdentityColumns()); } public function testDoesNotSupportSavePoints() : void { self::assertFalse($this->platform->supportsSavepoints()); } public function testDoesNotSupportReleasePoints() : void { self::assertFalse($this->platform->supportsReleaseSavepoints()); } public function testDoesNotSupportCreateDropDatabase() : void { self::assertFalse($this->platform->supportsCreateDropDatabase()); } public function testReturnsSQLResultCasing() : void { self::assertSame('COL', $this->platform->getSQLResultCasing('cOl')); } protected function getBinaryDefaultLength() : int { return 1; } protected function getBinaryMaxLength() : int { return 32704; } public function testReturnsBinaryTypeDeclarationSQL() : void { self::assertSame('VARCHAR(1) FOR BIT DATA', $this->platform->getBinaryTypeDeclarationSQL([])); self::assertSame('VARCHAR(255) FOR BIT DATA', $this->platform->getBinaryTypeDeclarationSQL(['length' => 0])); self::assertSame('VARCHAR(32704) FOR BIT DATA', $this->platform->getBinaryTypeDeclarationSQL(['length' => 32704])); self::assertSame('CHAR(1) FOR BIT DATA', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true])); self::assertSame('CHAR(254) FOR BIT DATA', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 0])); } /** * @group legacy * @expectedDeprecation Binary field length 32705 is greater than supported by the platform (32704). Reduce the field length or use a BLOB field instead. */ public function testReturnsBinaryTypeLongerThanMaxDeclarationSQL() : void { self::assertSame('BLOB(1M)', $this->platform->getBinaryTypeDeclarationSQL(['length' => 32705])); self::assertSame('BLOB(1M)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 32705])); } /** * {@inheritDoc} * * @group DBAL-234 */ protected function getAlterTableRenameIndexSQL() : array { return ['RENAME INDEX idx_foo TO idx_bar']; } /** * {@inheritDoc} * * @group DBAL-234 */ protected function getQuotedAlterTableRenameIndexSQL() : array { return [ 'RENAME INDEX "create" TO "select"', 'RENAME INDEX "foo" TO "bar"', ]; } /** * {@inheritdoc} */ protected function getQuotedAlterTableRenameColumnSQL() : array { return ['ALTER TABLE mytable ' . 'RENAME COLUMN unquoted1 TO unquoted ' . 'RENAME COLUMN unquoted2 TO "where" ' . 'RENAME COLUMN unquoted3 TO "foo" ' . 'RENAME COLUMN "create" TO reserved_keyword ' . 'RENAME COLUMN "table" TO "from" ' . 'RENAME COLUMN "select" TO "bar" ' . 'RENAME COLUMN quoted1 TO quoted ' . 'RENAME COLUMN quoted2 TO "and" ' . 'RENAME COLUMN quoted3 TO "baz"', ]; } /** * {@inheritdoc} */ protected function getQuotedAlterTableChangeColumnLengthSQL() : array { $this->markTestIncomplete('Not implemented yet'); } /** * {@inheritDoc} * * @group DBAL-807 */ protected function getAlterTableRenameIndexInSchemaSQL() : array { return ['RENAME INDEX myschema.idx_foo TO idx_bar']; } /** * {@inheritDoc} * * @group DBAL-807 */ protected function getQuotedAlterTableRenameIndexInSchemaSQL() : array { return [ 'RENAME INDEX "schema"."create" TO "select"', 'RENAME INDEX "schema"."foo" TO "bar"', ]; } /** * @group DBAL-423 */ public function testReturnsGuidTypeDeclarationSQL() : void { self::assertSame('CHAR(36)', $this->platform->getGuidTypeDeclarationSQL([])); } /** * {@inheritdoc} */ public function getAlterTableRenameColumnSQL() : array { return ['ALTER TABLE foo RENAME COLUMN bar TO baz']; } /** * {@inheritdoc} */ protected function getQuotesTableIdentifiersInAlterTableSQL() : array { return [ 'ALTER TABLE "foo" DROP FOREIGN KEY fk1', 'ALTER TABLE "foo" DROP FOREIGN KEY fk2', 'ALTER TABLE "foo" ' . 'ADD COLUMN bloo INTEGER NOT NULL WITH DEFAULT ' . 'DROP COLUMN baz ' . 'ALTER COLUMN bar DROP NOT NULL ' . 'RENAME COLUMN id TO war', 'CALL SYSPROC.ADMIN_CMD (\'REORG TABLE "foo"\')', 'RENAME TABLE "foo" TO "table"', 'ALTER TABLE "table" ADD CONSTRAINT fk_add FOREIGN KEY (fk3) REFERENCES fk_table (id)', 'ALTER TABLE "table" ADD CONSTRAINT fk2 FOREIGN KEY (fk2) REFERENCES fk_table2 (id)', ]; } /** * {@inheritdoc} */ protected function getCommentOnColumnSQL() : array { return [ 'COMMENT ON COLUMN foo.bar IS \'comment\'', 'COMMENT ON COLUMN "Foo"."BAR" IS \'comment\'', 'COMMENT ON COLUMN "select"."from" IS \'comment\'', ]; } /** * @group DBAL-944 * @dataProvider getGeneratesAlterColumnSQL */ public function testGeneratesAlterColumnSQL(string $changedProperty, Column $column, ?string $expectedSQLClause = null) : void { $tableDiff = new TableDiff('foo'); $tableDiff->fromTable = new Table('foo'); $tableDiff->changedColumns['bar'] = new ColumnDiff('bar', $column, [$changedProperty]); $expectedSQL = []; if ($expectedSQLClause !== null) { $expectedSQL[] = 'ALTER TABLE foo ALTER COLUMN bar ' . $expectedSQLClause; } $expectedSQL[] = "CALL SYSPROC.ADMIN_CMD ('REORG TABLE foo')"; self::assertSame($expectedSQL, $this->platform->getAlterTableSQL($tableDiff)); } /** * @return mixed[][] */ public static function getGeneratesAlterColumnSQL() : iterable { return [ [ 'columnDefinition', new Column('bar', Type::getType('decimal'), ['columnDefinition' => 'MONEY NOT NULL']), 'MONEY NOT NULL', ], [ 'type', new Column('bar', Type::getType('integer')), 'SET DATA TYPE INTEGER', ], [ 'length', new Column('bar', Type::getType('string'), ['length' => 100]), 'SET DATA TYPE VARCHAR(100)', ], [ 'precision', new Column('bar', Type::getType('decimal'), ['precision' => 10, 'scale' => 2]), 'SET DATA TYPE NUMERIC(10, 2)', ], [ 'scale', new Column('bar', Type::getType('decimal'), ['precision' => 5, 'scale' => 4]), 'SET DATA TYPE NUMERIC(5, 4)', ], [ 'fixed', new Column('bar', Type::getType('string'), ['length' => 20, 'fixed' => true]), 'SET DATA TYPE CHAR(20)', ], [ 'notnull', new Column('bar', Type::getType('string'), ['notnull' => true]), 'SET NOT NULL', ], [ 'notnull', new Column('bar', Type::getType('string'), ['notnull' => false]), 'DROP NOT NULL', ], [ 'default', new Column('bar', Type::getType('string'), ['default' => 'foo']), "SET DEFAULT 'foo'", ], [ 'default', new Column('bar', Type::getType('integer'), ['autoincrement' => true, 'default' => 666]), null, ], [ 'default', new Column('bar', Type::getType('string')), 'DROP DEFAULT', ], ]; } /** * {@inheritdoc} */ protected function getQuotesReservedKeywordInUniqueConstraintDeclarationSQL() : string { return 'CONSTRAINT "select" UNIQUE (foo)'; } /** * {@inheritdoc} */ protected function getQuotesReservedKeywordInIndexDeclarationSQL() : string { return ''; // not supported by this platform } /** * {@inheritdoc} */ protected function getQuotesReservedKeywordInTruncateTableSQL() : string { return 'TRUNCATE "select" IMMEDIATE'; } /** * {@inheritdoc} */ protected function supportsInlineIndexDeclaration() : bool { return false; } /** * {@inheritdoc} */ protected function supportsCommentOnStatement() : bool { return true; } /** * {@inheritdoc} */ protected function getAlterStringToFixedStringSQL() : array { return [ 'ALTER TABLE mytable ALTER COLUMN name SET DATA TYPE CHAR(2)', 'CALL SYSPROC.ADMIN_CMD (\'REORG TABLE mytable\')', ]; } /** * {@inheritdoc} */ protected function getGeneratesAlterTableRenameIndexUsedByForeignKeySQL() : array { return ['RENAME INDEX idx_foo TO idx_foo_renamed']; } /** * @group DBAL-2436 */ public function testQuotesTableNameInListTableColumnsSQL() : void { self::assertStringContainsStringIgnoringCase( "'Foo''Bar\\'", $this->platform->getListTableColumnsSQL("Foo'Bar\\") ); } /** * @group DBAL-2436 */ public function testQuotesTableNameInListTableIndexesSQL() : void { self::assertStringContainsStringIgnoringCase( "'Foo''Bar\\'", $this->platform->getListTableIndexesSQL("Foo'Bar\\") ); } /** * @group DBAL-2436 */ public function testQuotesTableNameInListTableForeignKeysSQL() : void { self::assertStringContainsStringIgnoringCase( "'Foo''Bar\\'", $this->platform->getListTableForeignKeysSQL("Foo'Bar\\") ); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Platforms/MariaDb1027PlatformTest.php000066400000000000000000000030371360544566000304560ustar00rootroot00000000000000platform->hasNativeJsonType()); } /** * From MariaDB 10.2.7, JSON type is an alias to LONGTEXT * * @link https://mariadb.com/kb/en/library/json-data-type/ */ public function testReturnsJsonTypeDeclarationSQL() : void { self::assertSame('LONGTEXT', $this->platform->getJsonTypeDeclarationSQL([])); } public function testInitializesJsonTypeMapping() : void { self::assertTrue($this->platform->hasDoctrineTypeMappingFor('json')); self::assertSame(Types::JSON, $this->platform->getDoctrineTypeMapping('json')); } /** * Overrides and skips AbstractMySQLPlatformTestCase test regarding propagation * of unsupported default values for Blob and Text columns. * * @see AbstractMySQLPlatformTestCase::testDoesNotPropagateDefaultValuesForUnsupportedColumnTypes() */ public function testDoesNotPropagateDefaultValuesForUnsupportedColumnTypes() : void { $this->markTestSkipped('MariaDB102Platform support propagation of default values for BLOB and TEXT columns'); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Platforms/MySQL57PlatformTest.php000066400000000000000000000042531360544566000277670ustar00rootroot00000000000000platform->hasNativeJsonType()); } public function testReturnsJsonTypeDeclarationSQL() : void { self::assertSame('JSON', $this->platform->getJsonTypeDeclarationSQL([])); } public function testInitializesJsonTypeMapping() : void { self::assertTrue($this->platform->hasDoctrineTypeMappingFor('json')); self::assertSame(Types::JSON, $this->platform->getDoctrineTypeMapping('json')); } /** * @return string[] * * @group DBAL-234 */ protected function getAlterTableRenameIndexSQL() : array { return ['ALTER TABLE mytable RENAME INDEX idx_foo TO idx_bar']; } /** * @return string[] * * @group DBAL-234 */ protected function getQuotedAlterTableRenameIndexSQL() : array { return [ 'ALTER TABLE `table` RENAME INDEX `create` TO `select`', 'ALTER TABLE `table` RENAME INDEX `foo` TO `bar`', ]; } /** * @return string[] * * @group DBAL-807 */ protected function getAlterTableRenameIndexInSchemaSQL() : array { return ['ALTER TABLE myschema.mytable RENAME INDEX idx_foo TO idx_bar']; } /** * @return string[] * * @group DBAL-807 */ protected function getQuotedAlterTableRenameIndexInSchemaSQL() : array { return [ 'ALTER TABLE `schema`.`table` RENAME INDEX `create` TO `select`', 'ALTER TABLE `schema`.`table` RENAME INDEX `foo` TO `bar`', ]; } /** * {@inheritdoc} */ protected function getGeneratesAlterTableRenameIndexUsedByForeignKeySQL() : array { return ['ALTER TABLE mytable RENAME INDEX idx_foo TO idx_foo_renamed']; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Platforms/MySqlPlatformTest.php000066400000000000000000000011351360544566000277070ustar00rootroot00000000000000platform->getDefaultTransactionIsolationLevel() ); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Platforms/OraclePlatformTest.php000066400000000000000000000763401360544566000300610ustar00rootroot00000000000000createPlatform(); $platform->assertValidIdentifier($identifier); $this->addToAssertionCount(1); } /** * @return mixed[][] */ public static function dataInvalidIdentifiers() : iterable { return [ ['1'], ['abc&'], ['abc-def'], ['"'], ['"foo"bar"'], ]; } /** * @dataProvider dataInvalidIdentifiers */ public function testInvalidIdentifiers(string $identifier) : void { $this->expectException(DBALException::class); $platform = $this->createPlatform(); $platform->assertValidIdentifier($identifier); } public function createPlatform() : AbstractPlatform { return new OraclePlatform(); } public function getGenerateTableSql() : string { return 'CREATE TABLE test (id NUMBER(10) NOT NULL, test VARCHAR2(255) DEFAULT NULL NULL, PRIMARY KEY(id))'; } /** * @return mixed[] */ public function getGenerateTableWithMultiColumnUniqueIndexSql() : array { return [ 'CREATE TABLE test (foo VARCHAR2(255) DEFAULT NULL NULL, bar VARCHAR2(255) DEFAULT NULL NULL)', 'CREATE UNIQUE INDEX UNIQ_D87F7E0C8C73652176FF8CAA ON test (foo, bar)', ]; } /** * {@inheritDoc} */ public function getGenerateAlterTableSql() : array { return [ 'ALTER TABLE mytable ADD (quota NUMBER(10) DEFAULT NULL NULL)', "ALTER TABLE mytable MODIFY (baz VARCHAR2(255) DEFAULT 'def' NOT NULL, bloo NUMBER(1) DEFAULT '0' NOT NULL)", 'ALTER TABLE mytable DROP (foo)', 'ALTER TABLE mytable RENAME TO userlist', ]; } public function testRLike() : void { $this->expectException(DBALException::class); self::assertEquals('RLIKE', $this->platform->getRegexpExpression(), 'Regular expression operator is not correct'); } public function testGeneratesSqlSnippets() : void { self::assertEquals('"', $this->platform->getIdentifierQuoteCharacter(), 'Identifier quote character is not correct'); self::assertEquals('column1 || column2 || column3', $this->platform->getConcatExpression('column1', 'column2', 'column3'), 'Concatenation expression is not correct'); } public function testGeneratesTransactionsCommands() : void { self::assertEquals( 'SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED', $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::READ_UNCOMMITTED) ); self::assertEquals( 'SET TRANSACTION ISOLATION LEVEL READ COMMITTED', $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::READ_COMMITTED) ); self::assertEquals( 'SET TRANSACTION ISOLATION LEVEL SERIALIZABLE', $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::REPEATABLE_READ) ); self::assertEquals( 'SET TRANSACTION ISOLATION LEVEL SERIALIZABLE', $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::SERIALIZABLE) ); } public function testCreateDatabaseThrowsException() : void { $this->expectException(DBALException::class); self::assertEquals('CREATE DATABASE foobar', $this->platform->getCreateDatabaseSQL('foobar')); } public function testDropDatabaseThrowsException() : void { self::assertEquals('DROP USER foobar CASCADE', $this->platform->getDropDatabaseSQL('foobar')); } public function testDropTable() : void { self::assertEquals('DROP TABLE foobar', $this->platform->getDropTableSQL('foobar')); } public function testGeneratesTypeDeclarationForIntegers() : void { self::assertEquals( 'NUMBER(10)', $this->platform->getIntegerTypeDeclarationSQL([]) ); self::assertEquals( 'NUMBER(10)', $this->platform->getIntegerTypeDeclarationSQL(['autoincrement' => true]) ); self::assertEquals( 'NUMBER(10)', $this->platform->getIntegerTypeDeclarationSQL( ['autoincrement' => true, 'primary' => true] ) ); } public function testGeneratesTypeDeclarationsForStrings() : void { self::assertEquals( 'CHAR(10)', $this->platform->getVarcharTypeDeclarationSQL( ['length' => 10, 'fixed' => true] ) ); self::assertEquals( 'VARCHAR2(50)', $this->platform->getVarcharTypeDeclarationSQL(['length' => 50]), 'Variable string declaration is not correct' ); self::assertEquals( 'VARCHAR2(255)', $this->platform->getVarcharTypeDeclarationSQL([]), 'Long string declaration is not correct' ); } public function testPrefersIdentityColumns() : void { self::assertFalse($this->platform->prefersIdentityColumns()); } public function testSupportsIdentityColumns() : void { self::assertFalse($this->platform->supportsIdentityColumns()); } public function testSupportsSavePoints() : void { self::assertTrue($this->platform->supportsSavepoints()); } /** * {@inheritdoc} */ protected function supportsCommentOnStatement() : bool { return true; } public function getGenerateIndexSql() : string { return 'CREATE INDEX my_idx ON mytable (user_name, last_login)'; } public function getGenerateUniqueIndexSql() : string { return 'CREATE UNIQUE INDEX index_name ON test (test, test2)'; } public function getGenerateForeignKeySql() : string { return 'ALTER TABLE test ADD FOREIGN KEY (fk_name_id) REFERENCES other_table (id)'; } /** * @param mixed[] $options * * @group DBAL-1097 * @dataProvider getGeneratesAdvancedForeignKeyOptionsSQLData */ public function testGeneratesAdvancedForeignKeyOptionsSQL(array $options, string $expectedSql) : void { $foreignKey = new ForeignKeyConstraint(['foo'], 'foreign_table', ['bar'], null, $options); self::assertSame($expectedSql, $this->platform->getAdvancedForeignKeyOptionsSQL($foreignKey)); } /** * @return mixed[][] */ public static function getGeneratesAdvancedForeignKeyOptionsSQLData() : iterable { return [ [[], ''], [['onUpdate' => 'CASCADE'], ''], [['onDelete' => 'CASCADE'], ' ON DELETE CASCADE'], [['onDelete' => 'NO ACTION'], ''], [['onDelete' => 'RESTRICT'], ''], [['onUpdate' => 'SET NULL', 'onDelete' => 'SET NULL'], ' ON DELETE SET NULL'], ]; } /** * {@inheritdoc} */ public static function getReturnsForeignKeyReferentialActionSQL() : iterable { return [ ['CASCADE', 'CASCADE'], ['SET NULL', 'SET NULL'], ['NO ACTION', ''], ['RESTRICT', ''], ['CaScAdE', 'CASCADE'], ]; } public function testModifyLimitQuery() : void { $sql = $this->platform->modifyLimitQuery('SELECT * FROM user', 10, 0); self::assertEquals('SELECT a.* FROM (SELECT * FROM user) a WHERE ROWNUM <= 10', $sql); } public function testModifyLimitQueryWithEmptyOffset() : void { $sql = $this->platform->modifyLimitQuery('SELECT * FROM user', 10); self::assertEquals('SELECT a.* FROM (SELECT * FROM user) a WHERE ROWNUM <= 10', $sql); } public function testModifyLimitQueryWithNonEmptyOffset() : void { $sql = $this->platform->modifyLimitQuery('SELECT * FROM user', 10, 10); self::assertEquals('SELECT * FROM (SELECT a.*, ROWNUM AS doctrine_rownum FROM (SELECT * FROM user) a WHERE ROWNUM <= 20) WHERE doctrine_rownum >= 11', $sql); } public function testModifyLimitQueryWithEmptyLimit() : void { $sql = $this->platform->modifyLimitQuery('SELECT * FROM user', null, 10); self::assertEquals('SELECT * FROM (SELECT a.*, ROWNUM AS doctrine_rownum FROM (SELECT * FROM user) a) WHERE doctrine_rownum >= 11', $sql); } public function testModifyLimitQueryWithAscOrderBy() : void { $sql = $this->platform->modifyLimitQuery('SELECT * FROM user ORDER BY username ASC', 10); self::assertEquals('SELECT a.* FROM (SELECT * FROM user ORDER BY username ASC) a WHERE ROWNUM <= 10', $sql); } public function testModifyLimitQueryWithDescOrderBy() : void { $sql = $this->platform->modifyLimitQuery('SELECT * FROM user ORDER BY username DESC', 10); self::assertEquals('SELECT a.* FROM (SELECT * FROM user ORDER BY username DESC) a WHERE ROWNUM <= 10', $sql); } public function testGenerateTableWithAutoincrement() : void { $columnName = strtoupper('id' . uniqid()); $tableName = strtoupper('table' . uniqid()); $table = new Table($tableName); $column = $table->addColumn($columnName, 'integer'); $column->setAutoincrement(true); $targets = [ sprintf('CREATE TABLE %s (%s NUMBER(10) NOT NULL)', $tableName, $columnName), sprintf( "DECLARE constraints_Count NUMBER; BEGIN SELECT COUNT(CONSTRAINT_NAME) INTO constraints_Count FROM USER_CONSTRAINTS WHERE TABLE_NAME = '%s' AND CONSTRAINT_TYPE = 'P'; IF constraints_Count = 0 OR constraints_Count = '' THEN EXECUTE IMMEDIATE 'ALTER TABLE %s ADD CONSTRAINT %s_AI_PK PRIMARY KEY (%s)'; END IF; END;", $tableName, $tableName, $tableName, $columnName ), sprintf('CREATE SEQUENCE %s_SEQ START WITH 1 MINVALUE 1 INCREMENT BY 1', $tableName), sprintf( "CREATE TRIGGER %s_AI_PK BEFORE INSERT ON %s FOR EACH ROW DECLARE last_Sequence NUMBER; last_InsertID NUMBER; BEGIN SELECT %s_SEQ.NEXTVAL INTO :NEW.%s FROM DUAL; IF (:NEW.%s IS NULL OR :NEW.%s = 0) THEN SELECT %s_SEQ.NEXTVAL INTO :NEW.%s FROM DUAL; ELSE SELECT NVL(Last_Number, 0) INTO last_Sequence FROM User_Sequences WHERE Sequence_Name = '%s_SEQ'; SELECT :NEW.%s INTO last_InsertID FROM DUAL; WHILE (last_InsertID > last_Sequence) LOOP SELECT %s_SEQ.NEXTVAL INTO last_Sequence FROM DUAL; END LOOP; END IF; END;", $tableName, $tableName, $tableName, $columnName, $columnName, $columnName, $tableName, $columnName, $tableName, $columnName, $tableName ), ]; $statements = $this->platform->getCreateTableSQL($table); //strip all the whitespace from the statements array_walk($statements, static function (&$value) : void { $value = preg_replace('/\s+/', ' ', $value); }); foreach ($targets as $key => $sql) { self::assertArrayHasKey($key, $statements); self::assertEquals($sql, $statements[$key]); } } /** * {@inheritDoc} */ public function getCreateTableColumnCommentsSQL() : array { return [ 'CREATE TABLE test (id NUMBER(10) NOT NULL, PRIMARY KEY(id))', "COMMENT ON COLUMN test.id IS 'This is a comment'", ]; } /** * {@inheritDoc} */ public function getCreateTableColumnTypeCommentsSQL() : array { return [ 'CREATE TABLE test (id NUMBER(10) NOT NULL, data CLOB NOT NULL, PRIMARY KEY(id))', "COMMENT ON COLUMN test.data IS '(DC2Type:array)'", ]; } /** * {@inheritDoc} */ public function getAlterTableColumnCommentsSQL() : array { return [ 'ALTER TABLE mytable ADD (quota NUMBER(10) NOT NULL)', "COMMENT ON COLUMN mytable.quota IS 'A comment'", "COMMENT ON COLUMN mytable.foo IS ''", "COMMENT ON COLUMN mytable.baz IS 'B comment'", ]; } public function getBitAndComparisonExpressionSql(string $value1, string $value2) : string { return 'BITAND(' . $value1 . ', ' . $value2 . ')'; } public function getBitOrComparisonExpressionSql(string $value1, string $value2) : string { return '(' . $value1 . '-' . $this->getBitAndComparisonExpressionSql($value1, $value2) . '+' . $value2 . ')'; } /** * @return mixed[] */ protected function getQuotedColumnInPrimaryKeySQL() : array { return ['CREATE TABLE "quoted" ("create" VARCHAR2(255) NOT NULL, PRIMARY KEY("create"))']; } /** * @return mixed[] */ protected function getQuotedColumnInIndexSQL() : array { return [ 'CREATE TABLE "quoted" ("create" VARCHAR2(255) NOT NULL)', 'CREATE INDEX IDX_22660D028FD6E0FB ON "quoted" ("create")', ]; } /** * @return mixed[] */ protected function getQuotedNameInIndexSQL() : array { return [ 'CREATE TABLE test (column1 VARCHAR2(255) NOT NULL)', 'CREATE INDEX "key" ON test (column1)', ]; } /** * @return mixed[] */ protected function getQuotedColumnInForeignKeySQL() : array { return [ 'CREATE TABLE "quoted" ("create" VARCHAR2(255) NOT NULL, foo VARCHAR2(255) NOT NULL, "bar" VARCHAR2(255) NOT NULL)', 'ALTER TABLE "quoted" ADD CONSTRAINT FK_WITH_RESERVED_KEYWORD FOREIGN KEY ("create", foo, "bar") REFERENCES foreign ("create", bar, "foo-bar")', 'ALTER TABLE "quoted" ADD CONSTRAINT FK_WITH_NON_RESERVED_KEYWORD FOREIGN KEY ("create", foo, "bar") REFERENCES foo ("create", bar, "foo-bar")', 'ALTER TABLE "quoted" ADD CONSTRAINT FK_WITH_INTENDED_QUOTATION FOREIGN KEY ("create", foo, "bar") REFERENCES "foo-bar" ("create", bar, "foo-bar")', ]; } /** * @group DBAL-472 * @group DBAL-1001 */ public function testAlterTableNotNULL() : void { $tableDiff = new TableDiff('mytable'); $tableDiff->changedColumns['foo'] = new ColumnDiff( 'foo', new Column( 'foo', Type::getType('string'), ['default' => 'bla', 'notnull' => true] ), ['type'] ); $tableDiff->changedColumns['bar'] = new ColumnDiff( 'bar', new Column( 'baz', Type::getType('string'), ['default' => 'bla', 'notnull' => true] ), ['type', 'notnull'] ); $tableDiff->changedColumns['metar'] = new ColumnDiff( 'metar', new Column( 'metar', Type::getType('string'), ['length' => 2000, 'notnull' => false] ), ['notnull'] ); $expectedSql = ["ALTER TABLE mytable MODIFY (foo VARCHAR2(255) DEFAULT 'bla', baz VARCHAR2(255) DEFAULT 'bla' NOT NULL, metar VARCHAR2(2000) DEFAULT NULL NULL)"]; self::assertEquals($expectedSql, $this->platform->getAlterTableSQL($tableDiff)); } /** * @group DBAL-2555 */ public function testInitializesDoctrineTypeMappings() : void { self::assertTrue($this->platform->hasDoctrineTypeMappingFor('long raw')); self::assertSame('blob', $this->platform->getDoctrineTypeMapping('long raw')); self::assertTrue($this->platform->hasDoctrineTypeMappingFor('raw')); self::assertSame('binary', $this->platform->getDoctrineTypeMapping('raw')); self::assertTrue($this->platform->hasDoctrineTypeMappingFor('date')); self::assertSame('date', $this->platform->getDoctrineTypeMapping('date')); } protected function getBinaryMaxLength() : int { return 2000; } public function testReturnsBinaryTypeDeclarationSQL() : void { self::assertSame('RAW(255)', $this->platform->getBinaryTypeDeclarationSQL([])); self::assertSame('RAW(2000)', $this->platform->getBinaryTypeDeclarationSQL(['length' => 0])); self::assertSame('RAW(2000)', $this->platform->getBinaryTypeDeclarationSQL(['length' => 2000])); self::assertSame('RAW(255)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true])); self::assertSame('RAW(2000)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 0])); self::assertSame('RAW(2000)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 2000])); } /** * @group legacy * @expectedDeprecation Binary field length 2001 is greater than supported by the platform (2000). Reduce the field length or use a BLOB field instead. */ public function testReturnsBinaryTypeLongerThanMaxDeclarationSQL() : void { self::assertSame('BLOB', $this->platform->getBinaryTypeDeclarationSQL(['length' => 2001])); self::assertSame('BLOB', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 2001])); } public function testDoesNotPropagateUnnecessaryTableAlterationOnBinaryType() : void { $table1 = new Table('mytable'); $table1->addColumn('column_varbinary', 'binary'); $table1->addColumn('column_binary', 'binary', ['fixed' => true]); $table2 = new Table('mytable'); $table2->addColumn('column_varbinary', 'binary', ['fixed' => true]); $table2->addColumn('column_binary', 'binary'); $comparator = new Comparator(); // VARBINARY -> BINARY // BINARY -> VARBINARY self::assertEmpty($this->platform->getAlterTableSQL($comparator->diffTable($table1, $table2))); } /** * @group DBAL-563 */ public function testUsesSequenceEmulatedIdentityColumns() : void { self::assertTrue($this->platform->usesSequenceEmulatedIdentityColumns()); } /** * @group DBAL-563 * @group DBAL-831 */ public function testReturnsIdentitySequenceName() : void { self::assertSame('MYTABLE_SEQ', $this->platform->getIdentitySequenceName('mytable', 'mycolumn')); self::assertSame('"mytable_SEQ"', $this->platform->getIdentitySequenceName('"mytable"', 'mycolumn')); self::assertSame('MYTABLE_SEQ', $this->platform->getIdentitySequenceName('mytable', '"mycolumn"')); self::assertSame('"mytable_SEQ"', $this->platform->getIdentitySequenceName('"mytable"', '"mycolumn"')); } /** * @dataProvider dataCreateSequenceWithCache * @group DBAL-139 */ public function testCreateSequenceWithCache(int $cacheSize, string $expectedSql) : void { $sequence = new Sequence('foo', 1, 1, $cacheSize); self::assertStringContainsString($expectedSql, $this->platform->getCreateSequenceSQL($sequence)); } /** * @return mixed[][] */ public static function dataCreateSequenceWithCache() : iterable { return [ [1, 'NOCACHE'], [0, 'NOCACHE'], [3, 'CACHE 3'], ]; } /** * {@inheritDoc} * * @group DBAL-234 */ protected function getAlterTableRenameIndexSQL() : array { return ['ALTER INDEX idx_foo RENAME TO idx_bar']; } /** * {@inheritDoc} * * @group DBAL-234 */ protected function getQuotedAlterTableRenameIndexSQL() : array { return [ 'ALTER INDEX "create" RENAME TO "select"', 'ALTER INDEX "foo" RENAME TO "bar"', ]; } /** * {@inheritdoc} */ protected function getQuotedAlterTableRenameColumnSQL() : array { return [ 'ALTER TABLE mytable RENAME COLUMN unquoted1 TO unquoted', 'ALTER TABLE mytable RENAME COLUMN unquoted2 TO "where"', 'ALTER TABLE mytable RENAME COLUMN unquoted3 TO "foo"', 'ALTER TABLE mytable RENAME COLUMN "create" TO reserved_keyword', 'ALTER TABLE mytable RENAME COLUMN "table" TO "from"', 'ALTER TABLE mytable RENAME COLUMN "select" TO "bar"', 'ALTER TABLE mytable RENAME COLUMN quoted1 TO quoted', 'ALTER TABLE mytable RENAME COLUMN quoted2 TO "and"', 'ALTER TABLE mytable RENAME COLUMN quoted3 TO "baz"', ]; } /** * {@inheritdoc} */ protected function getQuotedAlterTableChangeColumnLengthSQL() : array { $this->markTestIncomplete('Not implemented yet'); } /** * {@inheritDoc} * * @group DBAL-807 */ protected function getAlterTableRenameIndexInSchemaSQL() : array { return ['ALTER INDEX myschema.idx_foo RENAME TO idx_bar']; } /** * {@inheritDoc} * * @group DBAL-807 */ protected function getQuotedAlterTableRenameIndexInSchemaSQL() : array { return [ 'ALTER INDEX "schema"."create" RENAME TO "select"', 'ALTER INDEX "schema"."foo" RENAME TO "bar"', ]; } protected function getQuotesDropForeignKeySQL() : string { return 'ALTER TABLE "table" DROP CONSTRAINT "select"'; } /** * @group DBAL-423 */ public function testReturnsGuidTypeDeclarationSQL() : void { self::assertSame('CHAR(36)', $this->platform->getGuidTypeDeclarationSQL([])); } /** * {@inheritdoc} */ public function getAlterTableRenameColumnSQL() : array { return ['ALTER TABLE foo RENAME COLUMN bar TO baz']; } /** * @param string[] $expectedSql * * @dataProvider getReturnsDropAutoincrementSQL * @group DBAL-831 */ public function testReturnsDropAutoincrementSQL(string $table, array $expectedSql) : void { self::assertSame($expectedSql, $this->platform->getDropAutoincrementSql($table)); } /** * @return mixed[][] */ public static function getReturnsDropAutoincrementSQL() : iterable { return [ [ 'myTable', [ 'DROP TRIGGER MYTABLE_AI_PK', 'DROP SEQUENCE MYTABLE_SEQ', 'ALTER TABLE MYTABLE DROP CONSTRAINT MYTABLE_AI_PK', ], ], [ '"myTable"', [ 'DROP TRIGGER "myTable_AI_PK"', 'DROP SEQUENCE "myTable_SEQ"', 'ALTER TABLE "myTable" DROP CONSTRAINT "myTable_AI_PK"', ], ], [ 'table', [ 'DROP TRIGGER TABLE_AI_PK', 'DROP SEQUENCE TABLE_SEQ', 'ALTER TABLE "TABLE" DROP CONSTRAINT TABLE_AI_PK', ], ], ]; } /** * {@inheritdoc} */ protected function getQuotesTableIdentifiersInAlterTableSQL() : array { return [ 'ALTER TABLE "foo" DROP CONSTRAINT fk1', 'ALTER TABLE "foo" DROP CONSTRAINT fk2', 'ALTER TABLE "foo" ADD (bloo NUMBER(10) NOT NULL)', 'ALTER TABLE "foo" MODIFY (bar NUMBER(10) DEFAULT NULL NULL)', 'ALTER TABLE "foo" RENAME COLUMN id TO war', 'ALTER TABLE "foo" DROP (baz)', 'ALTER TABLE "foo" RENAME TO "table"', 'ALTER TABLE "table" ADD CONSTRAINT fk_add FOREIGN KEY (fk3) REFERENCES fk_table (id)', 'ALTER TABLE "table" ADD CONSTRAINT fk2 FOREIGN KEY (fk2) REFERENCES fk_table2 (id)', ]; } /** * {@inheritdoc} */ protected function getCommentOnColumnSQL() : array { return [ 'COMMENT ON COLUMN foo.bar IS \'comment\'', 'COMMENT ON COLUMN "Foo"."BAR" IS \'comment\'', 'COMMENT ON COLUMN "select"."from" IS \'comment\'', ]; } /** * @group DBAL-1004 */ public function testAltersTableColumnCommentWithExplicitlyQuotedIdentifiers() : void { $table1 = new Table('"foo"', [new Column('"bar"', Type::getType('integer'))]); $table2 = new Table('"foo"', [new Column('"bar"', Type::getType('integer'), ['comment' => 'baz'])]); $comparator = new Comparator(); $tableDiff = $comparator->diffTable($table1, $table2); self::assertInstanceOf(TableDiff::class, $tableDiff); self::assertSame( ['COMMENT ON COLUMN "foo"."bar" IS \'baz\''], $this->platform->getAlterTableSQL($tableDiff) ); } public function testQuotedTableNames() : void { $table = new Table('"test"'); $table->addColumn('"id"', 'integer', ['autoincrement' => true]); // assert tabel self::assertTrue($table->isQuoted()); self::assertEquals('test', $table->getName()); self::assertEquals('"test"', $table->getQuotedName($this->platform)); $sql = $this->platform->getCreateTableSQL($table); self::assertEquals('CREATE TABLE "test" ("id" NUMBER(10) NOT NULL)', $sql[0]); self::assertEquals('CREATE SEQUENCE "test_SEQ" START WITH 1 MINVALUE 1 INCREMENT BY 1', $sql[2]); $createTriggerStatement = << last_Sequence) LOOP SELECT "test_SEQ".NEXTVAL INTO last_Sequence FROM DUAL; END LOOP; END IF; END; EOD; self::assertEquals($createTriggerStatement, $sql[3]); } /** * @dataProvider getReturnsGetListTableColumnsSQL * @group DBAL-831 */ public function testReturnsGetListTableColumnsSQL(?string $database, string $expectedSql) : void { // note: this assertion is a bit strict, as it compares a full SQL string. // Should this break in future, then please try to reduce the matching to substring matching while reworking // the tests self::assertEquals($expectedSql, $this->platform->getListTableColumnsSQL('"test"', $database)); } /** * @return mixed[][] */ public static function getReturnsGetListTableColumnsSQL() : iterable { return [ [ null, <<<'SQL' SELECT c.*, ( SELECT d.comments FROM user_col_comments d WHERE d.TABLE_NAME = c.TABLE_NAME AND d.COLUMN_NAME = c.COLUMN_NAME ) AS comments FROM user_tab_columns c WHERE c.table_name = 'test' ORDER BY c.column_id SQL , ], [ '/', <<<'SQL' SELECT c.*, ( SELECT d.comments FROM user_col_comments d WHERE d.TABLE_NAME = c.TABLE_NAME AND d.COLUMN_NAME = c.COLUMN_NAME ) AS comments FROM user_tab_columns c WHERE c.table_name = 'test' ORDER BY c.column_id SQL , ], [ 'scott', <<<'SQL' SELECT c.*, ( SELECT d.comments FROM all_col_comments d WHERE d.TABLE_NAME = c.TABLE_NAME AND d.OWNER = c.OWNER AND d.COLUMN_NAME = c.COLUMN_NAME ) AS comments FROM all_tab_columns c WHERE c.table_name = 'test' AND c.owner = 'SCOTT' ORDER BY c.column_id SQL , ], ]; } /** * {@inheritdoc} */ protected function getQuotesReservedKeywordInUniqueConstraintDeclarationSQL() : string { return 'CONSTRAINT "select" UNIQUE (foo)'; } /** * {@inheritdoc} */ protected function getQuotesReservedKeywordInIndexDeclarationSQL() : string { return 'INDEX "select" (foo)'; } /** * {@inheritdoc} */ protected function getQuotesReservedKeywordInTruncateTableSQL() : string { return 'TRUNCATE TABLE "select"'; } /** * {@inheritdoc} */ protected function getAlterStringToFixedStringSQL() : array { return ['ALTER TABLE mytable MODIFY (name CHAR(2) DEFAULT NULL)']; } /** * {@inheritdoc} */ protected function getGeneratesAlterTableRenameIndexUsedByForeignKeySQL() : array { return ['ALTER INDEX idx_foo RENAME TO idx_foo_renamed']; } /** * @group DBAL-2436 */ public function testQuotesDatabaseNameInListSequencesSQL() : void { self::assertStringContainsStringIgnoringCase( "'Foo''Bar\\'", $this->platform->getListSequencesSQL("Foo'Bar\\") ); } /** * @group DBAL-2436 */ public function testQuotesTableNameInListTableIndexesSQL() : void { self::assertStringContainsStringIgnoringCase( "'Foo''Bar\\'", $this->platform->getListTableIndexesSQL("Foo'Bar\\") ); } /** * @group DBAL-2436 */ public function testQuotesTableNameInListTableForeignKeysSQL() : void { self::assertStringContainsStringIgnoringCase( "'Foo''Bar\\'", $this->platform->getListTableForeignKeysSQL("Foo'Bar\\") ); } /** * @group DBAL-2436 */ public function testQuotesTableNameInListTableConstraintsSQL() : void { self::assertStringContainsStringIgnoringCase( "'Foo''Bar\\'", $this->platform->getListTableConstraintsSQL("Foo'Bar\\") ); } /** * @group DBAL-2436 */ public function testQuotesTableNameInListTableColumnsSQL() : void { self::assertStringContainsStringIgnoringCase( "'Foo''Bar\\'", $this->platform->getListTableColumnsSQL("Foo'Bar\\") ); } /** * @group DBAL-2436 */ public function testQuotesDatabaseNameInListTableColumnsSQL() : void { self::assertStringContainsStringIgnoringCase( "'Foo''Bar\\'", $this->platform->getListTableColumnsSQL('foo_table', "Foo'Bar\\") ); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Platforms/PostgreSQL100PlatformTest.php000066400000000000000000000017241360544566000310720ustar00rootroot00000000000000platform->getListSequencesSQL('test_db') ); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Platforms/PostgreSQL91PlatformTest.php000066400000000000000000000025421360544566000310220ustar00rootroot00000000000000platform->supportsColumnCollation()); } public function testColumnCollationDeclarationSQL() : void { self::assertSame( 'COLLATE "en_US.UTF-8"', $this->platform->getColumnCollationDeclarationSQL('en_US.UTF-8') ); } public function testGetCreateTableSQLWithColumnCollation() : void { $table = new Table('foo'); $table->addColumn('no_collation', 'string'); $table->addColumn('column_collation', 'string')->setPlatformOption('collation', 'en_US.UTF-8'); self::assertSame( ['CREATE TABLE foo (no_collation VARCHAR(255) NOT NULL, column_collation VARCHAR(255) NOT NULL COLLATE "en_US.UTF-8")'], $this->platform->getCreateTableSQL($table), 'Column "no_collation" will use the default collation from the table/database and "column_collation" overwrites the collation on this column' ); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Platforms/PostgreSQL92PlatformTest.php000066400000000000000000000035301360544566000310210ustar00rootroot00000000000000platform->hasNativeJsonType()); } /** * @group DBAL-553 */ public function testReturnsJsonTypeDeclarationSQL() : void { self::assertSame('JSON', $this->platform->getJsonTypeDeclarationSQL([])); } public function testReturnsSmallIntTypeDeclarationSQL() : void { self::assertSame( 'SMALLSERIAL', $this->platform->getSmallIntTypeDeclarationSQL(['autoincrement' => true]) ); self::assertSame( 'SMALLINT', $this->platform->getSmallIntTypeDeclarationSQL(['autoincrement' => false]) ); self::assertSame( 'SMALLINT', $this->platform->getSmallIntTypeDeclarationSQL([]) ); } /** * @group DBAL-553 */ public function testInitializesJsonTypeMapping() : void { self::assertTrue($this->platform->hasDoctrineTypeMappingFor('json')); self::assertEquals(Types::JSON, $this->platform->getDoctrineTypeMapping('json')); } /** * @group DBAL-1220 */ public function testReturnsCloseActiveDatabaseConnectionsSQL() : void { self::assertSame( "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = 'foo'", $this->platform->getCloseActiveDatabaseConnectionsSQL('foo') ); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Platforms/PostgreSQL94PlatformTest.php000066400000000000000000000017631360544566000310310ustar00rootroot00000000000000platform->getJsonTypeDeclarationSQL(['jsonb' => false])); self::assertSame('JSONB', $this->platform->getJsonTypeDeclarationSQL(['jsonb' => true])); } public function testInitializesJsonTypeMapping() : void { parent::testInitializesJsonTypeMapping(); self::assertTrue($this->platform->hasDoctrineTypeMappingFor('jsonb')); self::assertEquals(Types::JSON, $this->platform->getDoctrineTypeMapping('jsonb')); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Platforms/PostgreSqlPlatformTest.php000066400000000000000000000017261360544566000307530ustar00rootroot00000000000000platform->supportsPartialIndexes()); } public function testGetCreateTableSQLWithColumnCollation() : void { $table = new Table('foo'); $table->addColumn('id', 'string'); $table->addOption('comment', 'foo'); self::assertSame( [ 'CREATE TABLE foo (id VARCHAR(255) NOT NULL)', "COMMENT ON TABLE foo IS 'foo'", ], $this->platform->getCreateTableSQL($table), 'Comments are added to table.' ); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Platforms/ReservedKeywordsValidatorTest.php000066400000000000000000000021761360544566000323200ustar00rootroot00000000000000validator = new ReservedKeywordsValidator([new MySQLKeywords()]); } public function testReservedTableName() : void { $table = new Table('TABLE'); $this->validator->acceptTable($table); self::assertEquals( ['Table TABLE keyword violations: MySQL'], $this->validator->getViolations() ); } public function testReservedColumnName() : void { $table = new Table('TABLE'); $column = $table->addColumn('table', 'string'); $this->validator->acceptColumn($table, $column); self::assertEquals( ['Table TABLE column table keyword violations: MySQL'], $this->validator->getViolations() ); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywhere11PlatformTest.php000066400000000000000000000013151360544566000311460ustar00rootroot00000000000000markTestSkipped('This version of the platform now supports regular expressions.'); } public function testGeneratesRegularExpressionSQLSnippet() : void { self::assertEquals('REGEXP', $this->platform->getRegexpExpression()); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywhere12PlatformTest.php000066400000000000000000000110701360544566000311460ustar00rootroot00000000000000markTestSkipped('This version of the platform now supports sequences.'); } public function testSupportsSequences() : void { self::assertTrue($this->platform->supportsSequences()); } public function testGeneratesSequenceSqlCommands() : void { $sequence = new Sequence('myseq', 20, 1); self::assertEquals( 'CREATE SEQUENCE myseq INCREMENT BY 20 START WITH 1 MINVALUE 1', $this->platform->getCreateSequenceSQL($sequence) ); self::assertEquals( 'ALTER SEQUENCE myseq INCREMENT BY 20', $this->platform->getAlterSequenceSQL($sequence) ); self::assertEquals( 'DROP SEQUENCE myseq', $this->platform->getDropSequenceSQL('myseq') ); self::assertEquals( 'DROP SEQUENCE myseq', $this->platform->getDropSequenceSQL($sequence) ); self::assertEquals( 'SELECT myseq.NEXTVAL', $this->platform->getSequenceNextValSQL('myseq') ); self::assertEquals( 'SELECT sequence_name, increment_by, start_with, min_value FROM SYS.SYSSEQUENCE', $this->platform->getListSequencesSQL(null) ); } public function testGeneratesDateTimeTzColumnTypeDeclarationSQL() : void { self::assertEquals( 'TIMESTAMP WITH TIME ZONE', $this->platform->getDateTimeTzTypeDeclarationSQL([ 'length' => 10, 'fixed' => true, 'unsigned' => true, 'autoincrement' => true, ]) ); } public function testHasCorrectDateTimeTzFormatString() : void { self::assertEquals('Y-m-d H:i:s.uP', $this->platform->getDateTimeTzFormatString()); } public function testInitializesDateTimeTzTypeMapping() : void { self::assertTrue($this->platform->hasDoctrineTypeMappingFor('timestamp with time zone')); self::assertEquals('datetime', $this->platform->getDoctrineTypeMapping('timestamp with time zone')); } public function testGeneratesCreateIndexWithAdvancedPlatformOptionsSQL() : void { self::assertEquals( 'CREATE VIRTUAL UNIQUE CLUSTERED INDEX fooindex ON footable (a, b) WITH NULLS NOT DISTINCT FOR OLAP WORKLOAD', $this->platform->getCreateIndexSQL( new Index( 'fooindex', ['a', 'b'], true, false, ['virtual', 'clustered', 'with_nulls_not_distinct', 'for_olap_workload'] ), 'footable' ) ); self::assertEquals( 'CREATE VIRTUAL CLUSTERED INDEX fooindex ON footable (a, b) FOR OLAP WORKLOAD', $this->platform->getCreateIndexSQL( new Index( 'fooindex', ['a', 'b'], false, false, ['virtual', 'clustered', 'with_nulls_not_distinct', 'for_olap_workload'] ), 'footable' ) ); // WITH NULLS NOT DISTINCT clause not available on primary indexes. self::assertEquals( 'ALTER TABLE footable ADD PRIMARY KEY (a, b)', $this->platform->getCreateIndexSQL( new Index( 'fooindex', ['a', 'b'], false, true, ['with_nulls_not_distinct'] ), 'footable' ) ); // WITH NULLS NOT DISTINCT clause not available on non-unique indexes. self::assertEquals( 'CREATE INDEX fooindex ON footable (a, b)', $this->platform->getCreateIndexSQL( new Index( 'fooindex', ['a', 'b'], false, false, ['with_nulls_not_distinct'] ), 'footable' ) ); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywhere16PlatformTest.php000066400000000000000000000044371360544566000311630ustar00rootroot00000000000000platform->getCreateIndexSQL( new Index( 'fooindex', ['a', 'b'], true, false, ['with_nulls_distinct'] ), 'footable' ) ); // WITH NULLS DISTINCT clause not available on primary indexes. self::assertEquals( 'ALTER TABLE footable ADD PRIMARY KEY (a, b)', $this->platform->getCreateIndexSQL( new Index( 'fooindex', ['a', 'b'], false, true, ['with_nulls_distinct'] ), 'footable' ) ); // WITH NULLS DISTINCT clause not available on non-unique indexes. self::assertEquals( 'CREATE INDEX fooindex ON footable (a, b)', $this->platform->getCreateIndexSQL( new Index( 'fooindex', ['a', 'b'], false, false, ['with_nulls_distinct'] ), 'footable' ) ); parent::testGeneratesCreateIndexWithAdvancedPlatformOptionsSQL(); } public function testThrowsExceptionOnInvalidWithNullsNotDistinctIndexOptions() : void { $this->expectException('UnexpectedValueException'); $this->platform->getCreateIndexSQL( new Index( 'fooindex', ['a', 'b'], false, false, ['with_nulls_distinct', 'with_nulls_not_distinct'] ), 'footable' ); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Platforms/SQLAnywherePlatformTest.php000066400000000000000000001213011360544566000310020ustar00rootroot00000000000000platform->getName()); } public function testGeneratesCreateTableSQLWithCommonIndexes() : void { $table = new Table('test'); $table->addColumn('id', 'integer'); $table->addColumn('name', 'string', ['length' => 50]); $table->setPrimaryKey(['id']); $table->addIndex(['name']); $table->addIndex(['id', 'name'], 'composite_idx'); self::assertEquals( [ 'CREATE TABLE test (id INT NOT NULL, name VARCHAR(50) NOT NULL, PRIMARY KEY (id))', 'CREATE INDEX IDX_D87F7E0C5E237E06 ON test (name)', 'CREATE INDEX composite_idx ON test (id, name)', ], $this->platform->getCreateTableSQL($table) ); } public function testGeneratesCreateTableSQLWithForeignKeyConstraints() : void { $table = new Table('test'); $table->addColumn('id', 'integer'); $table->addColumn('fk_1', 'integer'); $table->addColumn('fk_2', 'integer'); $table->setPrimaryKey(['id']); $table->addForeignKeyConstraint('foreign_table', ['fk_1', 'fk_2'], ['pk_1', 'pk_2']); $table->addForeignKeyConstraint( 'foreign_table2', ['fk_1', 'fk_2'], ['pk_1', 'pk_2'], [], 'named_fk' ); self::assertEquals( ['CREATE TABLE test (id INT NOT NULL, fk_1 INT NOT NULL, fk_2 INT NOT NULL, ' . 'CONSTRAINT FK_D87F7E0C177612A38E7F4319 FOREIGN KEY (fk_1, fk_2) REFERENCES foreign_table (pk_1, pk_2), ' . 'CONSTRAINT named_fk FOREIGN KEY (fk_1, fk_2) REFERENCES foreign_table2 (pk_1, pk_2))', ], $this->platform->getCreateTableSQL($table, AbstractPlatform::CREATE_FOREIGNKEYS) ); } public function testGeneratesCreateTableSQLWithCheckConstraints() : void { $table = new Table('test'); $table->addColumn('id', 'integer'); $table->addColumn('check_max', 'integer', ['platformOptions' => ['max' => 10]]); $table->addColumn('check_min', 'integer', ['platformOptions' => ['min' => 10]]); $table->setPrimaryKey(['id']); self::assertEquals( ['CREATE TABLE test (id INT NOT NULL, check_max INT NOT NULL, check_min INT NOT NULL, PRIMARY KEY (id), CHECK (check_max <= 10), CHECK (check_min >= 10))'], $this->platform->getCreateTableSQL($table) ); } public function testGeneratesTableAlterationWithRemovedColumnCommentSql() : void { $table = new Table('mytable'); $table->addColumn('foo', 'string', ['comment' => 'foo comment']); $tableDiff = new TableDiff('mytable'); $tableDiff->fromTable = $table; $tableDiff->changedColumns['foo'] = new ColumnDiff( 'foo', new Column('foo', Type::getType('string')), ['comment'] ); self::assertEquals( ['COMMENT ON COLUMN mytable.foo IS NULL'], $this->platform->getAlterTableSQL($tableDiff) ); } /** * @param int|bool|null $lockMode * * @dataProvider getLockHints */ public function testAppendsLockHint($lockMode, string $lockHint) : void { $fromClause = 'FROM users'; $expectedResult = $fromClause . $lockHint; self::assertSame($expectedResult, $this->platform->appendLockHint($fromClause, $lockMode)); } /** * @return mixed[][] */ public static function getLockHints() : iterable { return [ [null, ''], [false, ''], [true, ''], [LockMode::NONE, ' WITH (NOLOCK)'], [LockMode::OPTIMISTIC, ''], [LockMode::PESSIMISTIC_READ, ' WITH (UPDLOCK)'], [LockMode::PESSIMISTIC_WRITE, ' WITH (XLOCK)'], ]; } public function testHasCorrectMaxIdentifierLength() : void { self::assertEquals(128, $this->platform->getMaxIdentifierLength()); } public function testFixesSchemaElementNames() : void { $maxIdentifierLength = $this->platform->getMaxIdentifierLength(); $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; $schemaElementName = ''; for ($i = 0; $i < $maxIdentifierLength + 100; $i++) { $schemaElementName .= $characters[mt_rand(0, strlen($characters) - 1)]; } $fixedSchemaElementName = substr($schemaElementName, 0, $maxIdentifierLength); self::assertEquals( $fixedSchemaElementName, $this->platform->fixSchemaElementName($schemaElementName) ); self::assertEquals( $fixedSchemaElementName, $this->platform->fixSchemaElementName($fixedSchemaElementName) ); } public function testGeneratesColumnTypesDeclarationSQL() : void { $fullColumnDef = [ 'length' => 10, 'fixed' => true, 'unsigned' => true, 'autoincrement' => true, ]; self::assertEquals('SMALLINT', $this->platform->getSmallIntTypeDeclarationSQL([])); self::assertEquals('UNSIGNED SMALLINT', $this->platform->getSmallIntTypeDeclarationSQL(['unsigned' => true])); self::assertEquals('UNSIGNED SMALLINT IDENTITY', $this->platform->getSmallIntTypeDeclarationSQL($fullColumnDef)); self::assertEquals('INT', $this->platform->getIntegerTypeDeclarationSQL([])); self::assertEquals('UNSIGNED INT', $this->platform->getIntegerTypeDeclarationSQL(['unsigned' => true])); self::assertEquals('UNSIGNED INT IDENTITY', $this->platform->getIntegerTypeDeclarationSQL($fullColumnDef)); self::assertEquals('BIGINT', $this->platform->getBigIntTypeDeclarationSQL([])); self::assertEquals('UNSIGNED BIGINT', $this->platform->getBigIntTypeDeclarationSQL(['unsigned' => true])); self::assertEquals('UNSIGNED BIGINT IDENTITY', $this->platform->getBigIntTypeDeclarationSQL($fullColumnDef)); self::assertEquals('LONG BINARY', $this->platform->getBlobTypeDeclarationSQL($fullColumnDef)); self::assertEquals('BIT', $this->platform->getBooleanTypeDeclarationSQL($fullColumnDef)); self::assertEquals('TEXT', $this->platform->getClobTypeDeclarationSQL($fullColumnDef)); self::assertEquals('DATE', $this->platform->getDateTypeDeclarationSQL($fullColumnDef)); self::assertEquals('DATETIME', $this->platform->getDateTimeTypeDeclarationSQL($fullColumnDef)); self::assertEquals('TIME', $this->platform->getTimeTypeDeclarationSQL($fullColumnDef)); self::assertEquals('UNIQUEIDENTIFIER', $this->platform->getGuidTypeDeclarationSQL($fullColumnDef)); self::assertEquals(1, $this->platform->getVarcharDefaultLength()); self::assertEquals(32767, $this->platform->getVarcharMaxLength()); } public function testHasNativeGuidType() : void { self::assertTrue($this->platform->hasNativeGuidType()); } public function testGeneratesDDLSnippets() : void { self::assertEquals("CREATE DATABASE 'foobar'", $this->platform->getCreateDatabaseSQL('foobar')); self::assertEquals("CREATE DATABASE 'foobar'", $this->platform->getCreateDatabaseSQL('"foobar"')); self::assertEquals("CREATE DATABASE 'create'", $this->platform->getCreateDatabaseSQL('create')); self::assertEquals("DROP DATABASE 'foobar'", $this->platform->getDropDatabaseSQL('foobar')); self::assertEquals("DROP DATABASE 'foobar'", $this->platform->getDropDatabaseSQL('"foobar"')); self::assertEquals("DROP DATABASE 'create'", $this->platform->getDropDatabaseSQL('create')); self::assertEquals('CREATE GLOBAL TEMPORARY TABLE', $this->platform->getCreateTemporaryTableSnippetSQL()); self::assertEquals("START DATABASE 'foobar' AUTOSTOP OFF", $this->platform->getStartDatabaseSQL('foobar')); self::assertEquals("START DATABASE 'foobar' AUTOSTOP OFF", $this->platform->getStartDatabaseSQL('"foobar"')); self::assertEquals("START DATABASE 'create' AUTOSTOP OFF", $this->platform->getStartDatabaseSQL('create')); self::assertEquals('STOP DATABASE "foobar" UNCONDITIONALLY', $this->platform->getStopDatabaseSQL('foobar')); self::assertEquals('STOP DATABASE "foobar" UNCONDITIONALLY', $this->platform->getStopDatabaseSQL('"foobar"')); self::assertEquals('STOP DATABASE "create" UNCONDITIONALLY', $this->platform->getStopDatabaseSQL('create')); self::assertEquals('TRUNCATE TABLE foobar', $this->platform->getTruncateTableSQL('foobar')); self::assertEquals('TRUNCATE TABLE foobar', $this->platform->getTruncateTableSQL('foobar'), true); $viewSql = 'SELECT * FROM footable'; self::assertEquals('CREATE VIEW fooview AS ' . $viewSql, $this->platform->getCreateViewSQL('fooview', $viewSql)); self::assertEquals('DROP VIEW fooview', $this->platform->getDropViewSQL('fooview')); } public function testGeneratesPrimaryKeyDeclarationSQL() : void { self::assertEquals( 'CONSTRAINT pk PRIMARY KEY CLUSTERED (a, b)', $this->platform->getPrimaryKeyDeclarationSQL( new Index(null, ['a', 'b'], true, true, ['clustered']), 'pk' ) ); self::assertEquals( 'PRIMARY KEY (a, b)', $this->platform->getPrimaryKeyDeclarationSQL( new Index(null, ['a', 'b'], true, true) ) ); } public function testCannotGeneratePrimaryKeyDeclarationSQLWithEmptyColumns() : void { $this->expectException(InvalidArgumentException::class); $this->platform->getPrimaryKeyDeclarationSQL(new Index('pk', [], true, true)); } public function testGeneratesCreateUnnamedPrimaryKeySQL() : void { self::assertEquals( 'ALTER TABLE foo ADD PRIMARY KEY CLUSTERED (a, b)', $this->platform->getCreatePrimaryKeySQL( new Index('pk', ['a', 'b'], true, true, ['clustered']), 'foo' ) ); self::assertEquals( 'ALTER TABLE foo ADD PRIMARY KEY (a, b)', $this->platform->getCreatePrimaryKeySQL( new Index('any_pk_name', ['a', 'b'], true, true), new Table('foo') ) ); } public function testGeneratesUniqueConstraintDeclarationSQL() : void { self::assertEquals( 'CONSTRAINT unique_constraint UNIQUE CLUSTERED (a, b)', $this->platform->getUniqueConstraintDeclarationSQL( 'unique_constraint', new Index(null, ['a', 'b'], true, false, ['clustered']) ) ); self::assertEquals( 'UNIQUE (a, b)', $this->platform->getUniqueConstraintDeclarationSQL(null, new Index(null, ['a', 'b'], true, false)) ); } public function testCannotGenerateUniqueConstraintDeclarationSQLWithEmptyColumns() : void { $this->expectException(InvalidArgumentException::class); $this->platform->getUniqueConstraintDeclarationSQL('constr', new Index('constr', [], true)); } public function testGeneratesForeignKeyConstraintsWithAdvancedPlatformOptionsSQL() : void { self::assertEquals( 'CONSTRAINT fk ' . 'NOT NULL FOREIGN KEY (a, b) ' . 'REFERENCES foreign_table (c, d) ' . 'MATCH UNIQUE SIMPLE ON UPDATE CASCADE ON DELETE SET NULL CHECK ON COMMIT CLUSTERED FOR OLAP WORKLOAD', $this->platform->getForeignKeyDeclarationSQL( new ForeignKeyConstraint(['a', 'b'], 'foreign_table', ['c', 'd'], 'fk', [ 'notnull' => true, 'match' => SQLAnywherePlatform::FOREIGN_KEY_MATCH_SIMPLE_UNIQUE, 'onUpdate' => 'CASCADE', 'onDelete' => 'SET NULL', 'check_on_commit' => true, 'clustered' => true, 'for_olap_workload' => true, ]) ) ); self::assertEquals( 'FOREIGN KEY (a, b) REFERENCES foreign_table (c, d)', $this->platform->getForeignKeyDeclarationSQL( new ForeignKeyConstraint(['a', 'b'], 'foreign_table', ['c', 'd']) ) ); } public function testGeneratesForeignKeyMatchClausesSQL() : void { self::assertEquals('SIMPLE', $this->platform->getForeignKeyMatchClauseSQL(1)); self::assertEquals('FULL', $this->platform->getForeignKeyMatchClauseSQL(2)); self::assertEquals('UNIQUE SIMPLE', $this->platform->getForeignKeyMatchClauseSQL(129)); self::assertEquals('UNIQUE FULL', $this->platform->getForeignKeyMatchClauseSQL(130)); } public function testCannotGenerateInvalidForeignKeyMatchClauseSQL() : void { $this->expectException(InvalidArgumentException::class); $this->platform->getForeignKeyMatchCLauseSQL(3); } public function testCannotGenerateForeignKeyConstraintSQLWithEmptyLocalColumns() : void { $this->expectException(InvalidArgumentException::class); $this->platform->getForeignKeyDeclarationSQL(new ForeignKeyConstraint([], 'foreign_tbl', ['c', 'd'])); } public function testCannotGenerateForeignKeyConstraintSQLWithEmptyForeignColumns() : void { $this->expectException(InvalidArgumentException::class); $this->platform->getForeignKeyDeclarationSQL(new ForeignKeyConstraint(['a', 'b'], 'foreign_tbl', [])); } public function testCannotGenerateForeignKeyConstraintSQLWithEmptyForeignTableName() : void { $this->expectException(InvalidArgumentException::class); $this->platform->getForeignKeyDeclarationSQL(new ForeignKeyConstraint(['a', 'b'], '', ['c', 'd'])); } public function testCannotGenerateCommonIndexWithCreateConstraintSQL() : void { $this->expectException(InvalidArgumentException::class); $this->platform->getCreateConstraintSQL(new Index('fooindex', []), new Table('footable')); } public function testCannotGenerateCustomConstraintWithCreateConstraintSQL() : void { $this->expectException(InvalidArgumentException::class); $this->platform->getCreateConstraintSQL($this->createMock(Constraint::class), 'footable'); } public function testGeneratesCreateIndexWithAdvancedPlatformOptionsSQL() : void { self::assertEquals( 'CREATE VIRTUAL UNIQUE CLUSTERED INDEX fooindex ON footable (a, b) FOR OLAP WORKLOAD', $this->platform->getCreateIndexSQL( new Index( 'fooindex', ['a', 'b'], true, false, ['virtual', 'clustered', 'for_olap_workload'] ), 'footable' ) ); } public function testDoesNotSupportIndexDeclarationInCreateAlterTableStatements() : void { $this->expectException(DBALException::class); $this->platform->getIndexDeclarationSQL('index', new Index('index', [])); } public function testGeneratesDropIndexSQL() : void { $index = new Index('fooindex', []); self::assertEquals('DROP INDEX fooindex', $this->platform->getDropIndexSQL($index)); self::assertEquals('DROP INDEX footable.fooindex', $this->platform->getDropIndexSQL($index, 'footable')); self::assertEquals('DROP INDEX footable.fooindex', $this->platform->getDropIndexSQL( $index, new Table('footable') )); } public function testCannotGenerateDropIndexSQLWithInvalidIndexParameter() : void { $this->expectException(InvalidArgumentException::class); $this->platform->getDropIndexSQL(['index'], 'table'); } public function testCannotGenerateDropIndexSQLWithInvalidTableParameter() : void { $this->expectException(InvalidArgumentException::class); $this->platform->getDropIndexSQL('index', ['table']); } public function testGeneratesSQLSnippets() : void { self::assertEquals('STRING(column1, "string1", column2, "string2")', $this->platform->getConcatExpression( 'column1', '"string1"', 'column2', '"string2"' )); self::assertEquals('CURRENT DATE', $this->platform->getCurrentDateSQL()); self::assertEquals('CURRENT TIME', $this->platform->getCurrentTimeSQL()); self::assertEquals('CURRENT TIMESTAMP', $this->platform->getCurrentTimestampSQL()); self::assertEquals("DATEADD(DAY, 4, '1987/05/02')", $this->platform->getDateAddDaysExpression("'1987/05/02'", 4)); self::assertEquals("DATEADD(HOUR, 12, '1987/05/02')", $this->platform->getDateAddHourExpression("'1987/05/02'", 12)); self::assertEquals("DATEADD(MINUTE, 2, '1987/05/02')", $this->platform->getDateAddMinutesExpression("'1987/05/02'", 2)); self::assertEquals("DATEADD(MONTH, 102, '1987/05/02')", $this->platform->getDateAddMonthExpression("'1987/05/02'", 102)); self::assertEquals("DATEADD(QUARTER, 5, '1987/05/02')", $this->platform->getDateAddQuartersExpression("'1987/05/02'", 5)); self::assertEquals("DATEADD(SECOND, 1, '1987/05/02')", $this->platform->getDateAddSecondsExpression("'1987/05/02'", 1)); self::assertEquals("DATEADD(WEEK, 3, '1987/05/02')", $this->platform->getDateAddWeeksExpression("'1987/05/02'", 3)); self::assertEquals("DATEADD(YEAR, 10, '1987/05/02')", $this->platform->getDateAddYearsExpression("'1987/05/02'", 10)); self::assertEquals("DATEDIFF(day, '1987/04/01', '1987/05/02')", $this->platform->getDateDiffExpression("'1987/05/02'", "'1987/04/01'")); self::assertEquals("DATEADD(DAY, -1 * 4, '1987/05/02')", $this->platform->getDateSubDaysExpression("'1987/05/02'", 4)); self::assertEquals("DATEADD(HOUR, -1 * 12, '1987/05/02')", $this->platform->getDateSubHourExpression("'1987/05/02'", 12)); self::assertEquals("DATEADD(MINUTE, -1 * 2, '1987/05/02')", $this->platform->getDateSubMinutesExpression("'1987/05/02'", 2)); self::assertEquals("DATEADD(MONTH, -1 * 102, '1987/05/02')", $this->platform->getDateSubMonthExpression("'1987/05/02'", 102)); self::assertEquals("DATEADD(QUARTER, -1 * 5, '1987/05/02')", $this->platform->getDateSubQuartersExpression("'1987/05/02'", 5)); self::assertEquals("DATEADD(SECOND, -1 * 1, '1987/05/02')", $this->platform->getDateSubSecondsExpression("'1987/05/02'", 1)); self::assertEquals("DATEADD(WEEK, -1 * 3, '1987/05/02')", $this->platform->getDateSubWeeksExpression("'1987/05/02'", 3)); self::assertEquals("DATEADD(YEAR, -1 * 10, '1987/05/02')", $this->platform->getDateSubYearsExpression("'1987/05/02'", 10)); self::assertEquals('Y-m-d H:i:s.u', $this->platform->getDateTimeFormatString()); self::assertEquals('H:i:s.u', $this->platform->getTimeFormatString()); self::assertEquals('', $this->platform->getForUpdateSQL()); self::assertEquals('NEWID()', $this->platform->getGuidExpression()); self::assertEquals('LOCATE(string_column, substring_column)', $this->platform->getLocateExpression('string_column', 'substring_column')); self::assertEquals('LOCATE(string_column, substring_column, 1)', $this->platform->getLocateExpression('string_column', 'substring_column', 1)); self::assertEquals("HASH(column, 'MD5')", $this->platform->getMd5Expression('column')); self::assertEquals('SUBSTRING(column, 5)', $this->platform->getSubstringExpression('column', 5)); self::assertEquals('SUBSTRING(column, 5, 2)', $this->platform->getSubstringExpression('column', 5, 2)); self::assertEquals('GLOBAL TEMPORARY', $this->platform->getTemporaryTableSQL()); self::assertEquals( 'LTRIM(column)', $this->platform->getTrimExpression('column', TrimMode::LEADING) ); self::assertEquals( 'RTRIM(column)', $this->platform->getTrimExpression('column', TrimMode::TRAILING) ); self::assertEquals( 'TRIM(column)', $this->platform->getTrimExpression('column') ); self::assertEquals( 'TRIM(column)', $this->platform->getTrimExpression('column', TrimMode::UNSPECIFIED) ); self::assertEquals( "SUBSTR(column, PATINDEX('%[^' + c + ']%', column))", $this->platform->getTrimExpression('column', TrimMode::LEADING, 'c') ); self::assertEquals( "REVERSE(SUBSTR(REVERSE(column), PATINDEX('%[^' + c + ']%', REVERSE(column))))", $this->platform->getTrimExpression('column', TrimMode::TRAILING, 'c') ); self::assertEquals( "REVERSE(SUBSTR(REVERSE(SUBSTR(column, PATINDEX('%[^' + c + ']%', column))), PATINDEX('%[^' + c + ']%', " . "REVERSE(SUBSTR(column, PATINDEX('%[^' + c + ']%', column))))))", $this->platform->getTrimExpression('column', null, 'c') ); self::assertEquals( "REVERSE(SUBSTR(REVERSE(SUBSTR(column, PATINDEX('%[^' + c + ']%', column))), PATINDEX('%[^' + c + ']%', " . "REVERSE(SUBSTR(column, PATINDEX('%[^' + c + ']%', column))))))", $this->platform->getTrimExpression('column', TrimMode::UNSPECIFIED, 'c') ); } public function testDoesNotSupportRegexp() : void { $this->expectException(DBALException::class); $this->platform->getRegexpExpression(); } public function testHasCorrectDateTimeTzFormatString() : void { // Date time type with timezone is not supported before version 12. // For versions before we have to ensure that the date time with timezone format // equals the normal date time format so that it corresponds to the declaration SQL equality (datetimetz -> datetime). self::assertEquals($this->platform->getDateTimeFormatString(), $this->platform->getDateTimeTzFormatString()); } public function testHasCorrectDefaultTransactionIsolationLevel() : void { self::assertEquals( TransactionIsolationLevel::READ_UNCOMMITTED, $this->platform->getDefaultTransactionIsolationLevel() ); } public function testGeneratesTransactionsCommands() : void { self::assertEquals( 'SET TEMPORARY OPTION isolation_level = 0', $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::READ_UNCOMMITTED) ); self::assertEquals( 'SET TEMPORARY OPTION isolation_level = 1', $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::READ_COMMITTED) ); self::assertEquals( 'SET TEMPORARY OPTION isolation_level = 2', $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::REPEATABLE_READ) ); self::assertEquals( 'SET TEMPORARY OPTION isolation_level = 3', $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::SERIALIZABLE) ); } public function testCannotGenerateTransactionCommandWithInvalidIsolationLevel() : void { $this->expectException(InvalidArgumentException::class); $this->platform->getSetTransactionIsolationSQL('invalid_transaction_isolation_level'); } public function testModifiesLimitQuery() : void { self::assertEquals( 'SELECT TOP 10 * FROM user', $this->platform->modifyLimitQuery('SELECT * FROM user', 10, 0) ); } public function testModifiesLimitQueryWithEmptyOffset() : void { self::assertEquals( 'SELECT TOP 10 * FROM user', $this->platform->modifyLimitQuery('SELECT * FROM user', 10) ); } public function testModifiesLimitQueryWithOffset() : void { self::assertEquals( 'SELECT TOP 10 START AT 6 * FROM user', $this->platform->modifyLimitQuery('SELECT * FROM user', 10, 5) ); self::assertEquals( 'SELECT TOP 0 START AT 6 * FROM user', $this->platform->modifyLimitQuery('SELECT * FROM user', 0, 5) ); } public function testModifiesLimitQueryWithSubSelect() : void { self::assertEquals( 'SELECT TOP 10 * FROM (SELECT u.id as uid, u.name as uname FROM user) AS doctrine_tbl', $this->platform->modifyLimitQuery('SELECT * FROM (SELECT u.id as uid, u.name as uname FROM user) AS doctrine_tbl', 10) ); } public function testModifiesLimitQueryWithoutLimit() : void { self::assertEquals( 'SELECT TOP ALL START AT 11 n FROM Foo', $this->platform->modifyLimitQuery('SELECT n FROM Foo', null, 10) ); } public function testPrefersIdentityColumns() : void { self::assertTrue($this->platform->prefersIdentityColumns()); } public function testDoesNotPreferSequences() : void { self::assertFalse($this->platform->prefersSequences()); } public function testSupportsIdentityColumns() : void { self::assertTrue($this->platform->supportsIdentityColumns()); } public function testSupportsPrimaryConstraints() : void { self::assertTrue($this->platform->supportsPrimaryConstraints()); } public function testSupportsForeignKeyConstraints() : void { self::assertTrue($this->platform->supportsForeignKeyConstraints()); } public function testSupportsForeignKeyOnUpdate() : void { self::assertTrue($this->platform->supportsForeignKeyOnUpdate()); } public function testSupportsAlterTable() : void { self::assertTrue($this->platform->supportsAlterTable()); } public function testSupportsTransactions() : void { self::assertTrue($this->platform->supportsTransactions()); } public function testSupportsSchemas() : void { self::assertFalse($this->platform->supportsSchemas()); } public function testSupportsIndexes() : void { self::assertTrue($this->platform->supportsIndexes()); } public function testSupportsCommentOnStatement() : void { self::assertTrue($this->platform->supportsCommentOnStatement()); } public function testSupportsSavePoints() : void { self::assertTrue($this->platform->supportsSavepoints()); } public function testSupportsReleasePoints() : void { self::assertTrue($this->platform->supportsReleaseSavepoints()); } public function testSupportsCreateDropDatabase() : void { self::assertTrue($this->platform->supportsCreateDropDatabase()); } public function testSupportsGettingAffectedRows() : void { self::assertTrue($this->platform->supportsGettingAffectedRows()); } public function testDoesNotSupportSequences() : void { self::assertFalse($this->platform->supportsSequences()); } public function testDoesNotSupportInlineColumnComments() : void { self::assertFalse($this->platform->supportsInlineColumnComments()); } public function testCannotEmulateSchemas() : void { self::assertFalse($this->platform->canEmulateSchemas()); } public function testInitializesDoctrineTypeMappings() : void { self::assertTrue($this->platform->hasDoctrineTypeMappingFor('integer')); self::assertSame('integer', $this->platform->getDoctrineTypeMapping('integer')); self::assertTrue($this->platform->hasDoctrineTypeMappingFor('binary')); self::assertSame('binary', $this->platform->getDoctrineTypeMapping('binary')); self::assertTrue($this->platform->hasDoctrineTypeMappingFor('varbinary')); self::assertSame('binary', $this->platform->getDoctrineTypeMapping('varbinary')); } protected function getBinaryDefaultLength() : int { return 1; } protected function getBinaryMaxLength() : int { return 32767; } public function testReturnsBinaryTypeDeclarationSQL() : void { self::assertSame('VARBINARY(1)', $this->platform->getBinaryTypeDeclarationSQL([])); self::assertSame('VARBINARY(1)', $this->platform->getBinaryTypeDeclarationSQL(['length' => 0])); self::assertSame('VARBINARY(32767)', $this->platform->getBinaryTypeDeclarationSQL(['length' => 32767])); self::assertSame('BINARY(1)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true])); self::assertSame('BINARY(1)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 0])); self::assertSame('BINARY(32767)', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 32767])); } /** * @group legacy * @expectedDeprecation Binary field length 32768 is greater than supported by the platform (32767). Reduce the field length or use a BLOB field instead. */ public function testReturnsBinaryTypeLongerThanMaxDeclarationSQL() : void { self::assertSame('LONG BINARY', $this->platform->getBinaryTypeDeclarationSQL(['length' => 32768])); self::assertSame('LONG BINARY', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 32768])); } /** * {@inheritDoc} * * @group DBAL-234 */ protected function getAlterTableRenameIndexSQL() : array { return ['ALTER INDEX idx_foo ON mytable RENAME TO idx_bar']; } /** * {@inheritDoc} * * @group DBAL-234 */ protected function getQuotedAlterTableRenameIndexSQL() : array { return [ 'ALTER INDEX "create" ON "table" RENAME TO "select"', 'ALTER INDEX "foo" ON "table" RENAME TO "bar"', ]; } /** * {@inheritdoc} */ protected function getQuotedAlterTableRenameColumnSQL() : array { return [ 'ALTER TABLE mytable RENAME unquoted1 TO unquoted', 'ALTER TABLE mytable RENAME unquoted2 TO "where"', 'ALTER TABLE mytable RENAME unquoted3 TO "foo"', 'ALTER TABLE mytable RENAME "create" TO reserved_keyword', 'ALTER TABLE mytable RENAME "table" TO "from"', 'ALTER TABLE mytable RENAME "select" TO "bar"', 'ALTER TABLE mytable RENAME quoted1 TO quoted', 'ALTER TABLE mytable RENAME quoted2 TO "and"', 'ALTER TABLE mytable RENAME quoted3 TO "baz"', ]; } /** * {@inheritdoc} */ protected function getQuotedAlterTableChangeColumnLengthSQL() : array { $this->markTestIncomplete('Not implemented yet'); } /** * {@inheritDoc} * * @group DBAL-807 */ protected function getAlterTableRenameIndexInSchemaSQL() : array { return ['ALTER INDEX idx_foo ON myschema.mytable RENAME TO idx_bar']; } /** * {@inheritDoc} * * @group DBAL-807 */ protected function getQuotedAlterTableRenameIndexInSchemaSQL() : array { return [ 'ALTER INDEX "create" ON "schema"."table" RENAME TO "select"', 'ALTER INDEX "foo" ON "schema"."table" RENAME TO "bar"', ]; } /** * @group DBAL-423 */ public function testReturnsGuidTypeDeclarationSQL() : void { self::assertSame('UNIQUEIDENTIFIER', $this->platform->getGuidTypeDeclarationSQL([])); } /** * {@inheritdoc} */ public function getAlterTableRenameColumnSQL() : array { return ['ALTER TABLE foo RENAME bar TO baz']; } /** * {@inheritdoc} */ protected function getQuotesTableIdentifiersInAlterTableSQL() : array { return [ 'ALTER TABLE "foo" DROP FOREIGN KEY fk1', 'ALTER TABLE "foo" DROP FOREIGN KEY fk2', 'ALTER TABLE "foo" RENAME id TO war', 'ALTER TABLE "foo" ADD bloo INT NOT NULL, DROP baz, ALTER bar INT DEFAULT NULL', 'ALTER TABLE "foo" RENAME "table"', 'ALTER TABLE "table" ADD CONSTRAINT fk_add FOREIGN KEY (fk3) REFERENCES fk_table (id)', 'ALTER TABLE "table" ADD CONSTRAINT fk2 FOREIGN KEY (fk2) REFERENCES fk_table2 (id)', ]; } /** * {@inheritdoc} */ protected function getCommentOnColumnSQL() : array { return [ 'COMMENT ON COLUMN foo.bar IS \'comment\'', 'COMMENT ON COLUMN "Foo"."BAR" IS \'comment\'', 'COMMENT ON COLUMN "select"."from" IS \'comment\'', ]; } /** * @group DBAL-1004 */ public function testAltersTableColumnCommentWithExplicitlyQuotedIdentifiers() : void { $table1 = new Table('"foo"', [new Column('"bar"', Type::getType('integer'))]); $table2 = new Table('"foo"', [new Column('"bar"', Type::getType('integer'), ['comment' => 'baz'])]); $comparator = new Comparator(); $tableDiff = $comparator->diffTable($table1, $table2); self::assertInstanceOf(TableDiff::class, $tableDiff); self::assertSame( ['COMMENT ON COLUMN "foo"."bar" IS \'baz\''], $this->platform->getAlterTableSQL($tableDiff) ); } /** * {@inheritdoc} */ public static function getReturnsForeignKeyReferentialActionSQL() : iterable { return [ ['CASCADE', 'CASCADE'], ['SET NULL', 'SET NULL'], ['NO ACTION', 'RESTRICT'], ['RESTRICT', 'RESTRICT'], ['SET DEFAULT', 'SET DEFAULT'], ['CaScAdE', 'CASCADE'], ]; } /** * {@inheritdoc} */ protected function getQuotesReservedKeywordInUniqueConstraintDeclarationSQL() : string { return 'CONSTRAINT "select" UNIQUE (foo)'; } /** * {@inheritdoc} */ protected function getQuotesReservedKeywordInIndexDeclarationSQL() : string { return ''; // not supported by this platform } /** * {@inheritdoc} */ protected function getQuotesReservedKeywordInTruncateTableSQL() : string { return 'TRUNCATE TABLE "select"'; } /** * {@inheritdoc} */ protected function supportsInlineIndexDeclaration() : bool { return false; } /** * {@inheritdoc} */ protected function getAlterStringToFixedStringSQL() : array { return ['ALTER TABLE mytable ALTER name CHAR(2) NOT NULL']; } /** * {@inheritdoc} */ protected function getGeneratesAlterTableRenameIndexUsedByForeignKeySQL() : array { return ['ALTER INDEX idx_foo ON mytable RENAME TO idx_foo_renamed']; } /** * @group DBAL-2436 */ public function testQuotesSchemaNameInListTableColumnsSQL() : void { self::assertStringContainsStringIgnoringCase( "'Foo''Bar\\'", $this->platform->getListTableColumnsSQL("Foo'Bar\\.baz_table") ); } /** * @group DBAL-2436 */ public function testQuotesTableNameInListTableConstraintsSQL() : void { self::assertStringContainsStringIgnoringCase("'Foo''Bar\\'", $this->platform->getListTableConstraintsSQL("Foo'Bar\\"), '', true); } /** * @group DBAL-2436 */ public function testQuotesSchemaNameInListTableConstraintsSQL() : void { self::assertStringContainsStringIgnoringCase( "'Foo''Bar\\'", $this->platform->getListTableConstraintsSQL("Foo'Bar\\.baz_table") ); } /** * @group DBAL-2436 */ public function testQuotesTableNameInListTableForeignKeysSQL() : void { self::assertStringContainsStringIgnoringCase( "'Foo''Bar\\'", $this->platform->getListTableForeignKeysSQL("Foo'Bar\\") ); } /** * @group DBAL-2436 */ public function testQuotesSchemaNameInListTableForeignKeysSQL() : void { self::assertStringContainsStringIgnoringCase( "'Foo''Bar\\'", $this->platform->getListTableForeignKeysSQL("Foo'Bar\\.baz_table") ); } /** * @group DBAL-2436 */ public function testQuotesTableNameInListTableIndexesSQL() : void { self::assertStringContainsStringIgnoringCase( "'Foo''Bar\\'", $this->platform->getListTableIndexesSQL("Foo'Bar\\") ); } /** * @group DBAL-2436 */ public function testQuotesSchemaNameInListTableIndexesSQL() : void { self::assertStringContainsStringIgnoringCase( "'Foo''Bar\\'", $this->platform->getListTableIndexesSQL("Foo'Bar\\.baz_table") ); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Platforms/SQLAzurePlatformTest.php000066400000000000000000000014651360544566000303160ustar00rootroot00000000000000platform = new SQLAzurePlatform(); } public function testCreateFederatedOnTable() : void { $table = new Table('tbl'); $table->addColumn('id', 'integer'); $table->addOption('azure.federatedOnDistributionName', 'TblId'); $table->addOption('azure.federatedOnColumnName', 'id'); self::assertEquals(['CREATE TABLE tbl (id INT NOT NULL) FEDERATED ON (TblId = id)'], $this->platform->getCreateTableSQL($table)); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Platforms/SQLServer2008PlatformTest.php000066400000000000000000000010141360544566000307760ustar00rootroot00000000000000platform->getDateTimeTzTypeDeclarationSQL([])); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Platforms/SQLServer2012PlatformTest.php000066400000000000000000000445121360544566000310030ustar00rootroot00000000000000platform->supportsSequences()); } public function testDoesNotPreferSequences() : void { self::assertFalse($this->platform->prefersSequences()); } public function testGeneratesSequenceSqlCommands() : void { $sequence = new Sequence('myseq', 20, 1); self::assertEquals( 'CREATE SEQUENCE myseq START WITH 1 INCREMENT BY 20 MINVALUE 1', $this->platform->getCreateSequenceSQL($sequence) ); self::assertEquals( 'ALTER SEQUENCE myseq INCREMENT BY 20', $this->platform->getAlterSequenceSQL($sequence) ); self::assertEquals( 'DROP SEQUENCE myseq', $this->platform->getDropSequenceSQL('myseq') ); self::assertEquals( 'SELECT NEXT VALUE FOR myseq', $this->platform->getSequenceNextValSQL('myseq') ); } public function testModifyLimitQuery() : void { $sql = $this->platform->modifyLimitQuery('SELECT * FROM user', 10, 0); self::assertEquals('SELECT * FROM user ORDER BY (SELECT 0) OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY', $sql); } public function testModifyLimitQueryWithEmptyOffset() : void { $sql = $this->platform->modifyLimitQuery('SELECT * FROM user', 10); self::assertEquals('SELECT * FROM user ORDER BY (SELECT 0) OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY', $sql); } public function testModifyLimitQueryWithOffset() : void { $sql = $this->platform->modifyLimitQuery('SELECT * FROM user ORDER BY username DESC', 10, 5); self::assertEquals('SELECT * FROM user ORDER BY username DESC OFFSET 5 ROWS FETCH NEXT 10 ROWS ONLY', $sql); } public function testModifyLimitQueryWithAscOrderBy() : void { $sql = $this->platform->modifyLimitQuery('SELECT * FROM user ORDER BY username ASC', 10); self::assertEquals('SELECT * FROM user ORDER BY username ASC OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY', $sql); } public function testModifyLimitQueryWithLowercaseOrderBy() : void { $sql = $this->platform->modifyLimitQuery('SELECT * FROM user order by username', 10); self::assertEquals('SELECT * FROM user order by username OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY', $sql); } public function testModifyLimitQueryWithDescOrderBy() : void { $sql = $this->platform->modifyLimitQuery('SELECT * FROM user ORDER BY username DESC', 10); self::assertEquals('SELECT * FROM user ORDER BY username DESC OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY', $sql); } public function testModifyLimitQueryWithMultipleOrderBy() : void { $sql = $this->platform->modifyLimitQuery('SELECT * FROM user ORDER BY username DESC, usereamil ASC', 10); self::assertEquals('SELECT * FROM user ORDER BY username DESC, usereamil ASC OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY', $sql); } public function testModifyLimitQueryWithSubSelect() : void { $sql = $this->platform->modifyLimitQuery('SELECT * FROM (SELECT u.id as uid, u.name as uname) dctrn_result', 10); self::assertEquals('SELECT * FROM (SELECT u.id as uid, u.name as uname) dctrn_result ORDER BY (SELECT 0) OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY', $sql); } public function testModifyLimitQueryWithSubSelectAndOrder() : void { $sql = $this->platform->modifyLimitQuery('SELECT * FROM (SELECT u.id as uid, u.name as uname) dctrn_result ORDER BY uname DESC', 10); self::assertEquals('SELECT * FROM (SELECT u.id as uid, u.name as uname) dctrn_result ORDER BY uname DESC OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY', $sql); $sql = $this->platform->modifyLimitQuery('SELECT * FROM (SELECT u.id, u.name) dctrn_result ORDER BY name DESC', 10); self::assertEquals('SELECT * FROM (SELECT u.id, u.name) dctrn_result ORDER BY name DESC OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY', $sql); } public function testModifyLimitQueryWithSubSelectAndMultipleOrder() : void { $sql = $this->platform->modifyLimitQuery('SELECT * FROM (SELECT u.id as uid, u.name as uname) dctrn_result ORDER BY uname DESC, uid ASC', 10, 5); self::assertEquals('SELECT * FROM (SELECT u.id as uid, u.name as uname) dctrn_result ORDER BY uname DESC, uid ASC OFFSET 5 ROWS FETCH NEXT 10 ROWS ONLY', $sql); $sql = $this->platform->modifyLimitQuery('SELECT * FROM (SELECT u.id uid, u.name uname) dctrn_result ORDER BY uname DESC, uid ASC', 10, 5); self::assertEquals('SELECT * FROM (SELECT u.id uid, u.name uname) dctrn_result ORDER BY uname DESC, uid ASC OFFSET 5 ROWS FETCH NEXT 10 ROWS ONLY', $sql); $sql = $this->platform->modifyLimitQuery('SELECT * FROM (SELECT u.id, u.name) dctrn_result ORDER BY name DESC, id ASC', 10, 5); self::assertEquals('SELECT * FROM (SELECT u.id, u.name) dctrn_result ORDER BY name DESC, id ASC OFFSET 5 ROWS FETCH NEXT 10 ROWS ONLY', $sql); } public function testModifyLimitQueryWithFromColumnNames() : void { $sql = $this->platform->modifyLimitQuery('SELECT a.fromFoo, fromBar FROM foo', 10); self::assertEquals('SELECT a.fromFoo, fromBar FROM foo ORDER BY (SELECT 0) OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY', $sql); } /** * @group DBAL-927 */ public function testModifyLimitQueryWithExtraLongQuery() : void { $query = 'SELECT table1.column1, table2.column2, table3.column3, table4.column4, table5.column5, table6.column6, table7.column7, table8.column8 FROM table1, table2, table3, table4, table5, table6, table7, table8 '; $query .= 'WHERE (table1.column1 = table2.column2) AND (table1.column1 = table3.column3) AND (table1.column1 = table4.column4) AND (table1.column1 = table5.column5) AND (table1.column1 = table6.column6) AND (table1.column1 = table7.column7) AND (table1.column1 = table8.column8) AND (table2.column2 = table3.column3) AND (table2.column2 = table4.column4) AND (table2.column2 = table5.column5) AND (table2.column2 = table6.column6) '; $query .= 'AND (table2.column2 = table7.column7) AND (table2.column2 = table8.column8) AND (table3.column3 = table4.column4) AND (table3.column3 = table5.column5) AND (table3.column3 = table6.column6) AND (table3.column3 = table7.column7) AND (table3.column3 = table8.column8) AND (table4.column4 = table5.column5) AND (table4.column4 = table6.column6) AND (table4.column4 = table7.column7) AND (table4.column4 = table8.column8) '; $query .= 'AND (table5.column5 = table6.column6) AND (table5.column5 = table7.column7) AND (table5.column5 = table8.column8) AND (table6.column6 = table7.column7) AND (table6.column6 = table8.column8) AND (table7.column7 = table8.column8)'; $sql = $this->platform->modifyLimitQuery($query, 10); $expected = 'SELECT table1.column1, table2.column2, table3.column3, table4.column4, table5.column5, table6.column6, table7.column7, table8.column8 FROM table1, table2, table3, table4, table5, table6, table7, table8 '; $expected .= 'WHERE (table1.column1 = table2.column2) AND (table1.column1 = table3.column3) AND (table1.column1 = table4.column4) AND (table1.column1 = table5.column5) AND (table1.column1 = table6.column6) AND (table1.column1 = table7.column7) AND (table1.column1 = table8.column8) AND (table2.column2 = table3.column3) AND (table2.column2 = table4.column4) AND (table2.column2 = table5.column5) AND (table2.column2 = table6.column6) '; $expected .= 'AND (table2.column2 = table7.column7) AND (table2.column2 = table8.column8) AND (table3.column3 = table4.column4) AND (table3.column3 = table5.column5) AND (table3.column3 = table6.column6) AND (table3.column3 = table7.column7) AND (table3.column3 = table8.column8) AND (table4.column4 = table5.column5) AND (table4.column4 = table6.column6) AND (table4.column4 = table7.column7) AND (table4.column4 = table8.column8) '; $expected .= 'AND (table5.column5 = table6.column6) AND (table5.column5 = table7.column7) AND (table5.column5 = table8.column8) AND (table6.column6 = table7.column7) AND (table6.column6 = table8.column8) AND (table7.column7 = table8.column8) '; $expected .= 'ORDER BY (SELECT 0) OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY'; self::assertEquals($expected, $sql); } /** * @group DDC-2470 */ public function testModifyLimitQueryWithOrderByClause() : void { $sql = 'SELECT m0_.NOMBRE AS NOMBRE0, m0_.FECHAINICIO AS FECHAINICIO1, m0_.FECHAFIN AS FECHAFIN2 FROM MEDICION m0_ WITH (NOLOCK) INNER JOIN ESTUDIO e1_ ON m0_.ESTUDIO_ID = e1_.ID INNER JOIN CLIENTE c2_ ON e1_.CLIENTE_ID = c2_.ID INNER JOIN USUARIO u3_ ON c2_.ID = u3_.CLIENTE_ID WHERE u3_.ID = ? ORDER BY m0_.FECHAINICIO DESC'; $expected = 'SELECT m0_.NOMBRE AS NOMBRE0, m0_.FECHAINICIO AS FECHAINICIO1, m0_.FECHAFIN AS FECHAFIN2 FROM MEDICION m0_ WITH (NOLOCK) INNER JOIN ESTUDIO e1_ ON m0_.ESTUDIO_ID = e1_.ID INNER JOIN CLIENTE c2_ ON e1_.CLIENTE_ID = c2_.ID INNER JOIN USUARIO u3_ ON c2_.ID = u3_.CLIENTE_ID WHERE u3_.ID = ? ORDER BY m0_.FECHAINICIO DESC OFFSET 5 ROWS FETCH NEXT 10 ROWS ONLY'; $actual = $this->platform->modifyLimitQuery($sql, 10, 5); self::assertEquals($expected, $actual); } /** * @group DBAL-713 */ public function testModifyLimitQueryWithSubSelectInSelectList() : void { $sql = $this->platform->modifyLimitQuery( 'SELECT ' . 'u.id, ' . '(u.foo/2) foodiv, ' . 'CONCAT(u.bar, u.baz) barbaz, ' . '(SELECT (SELECT COUNT(*) FROM login l WHERE l.profile_id = p.id) FROM profile p WHERE p.user_id = u.id) login_count ' . 'FROM user u ' . "WHERE u.status = 'disabled'", 10 ); self::assertEquals( 'SELECT ' . 'u.id, ' . '(u.foo/2) foodiv, ' . 'CONCAT(u.bar, u.baz) barbaz, ' . '(SELECT (SELECT COUNT(*) FROM login l WHERE l.profile_id = p.id) FROM profile p WHERE p.user_id = u.id) login_count ' . 'FROM user u ' . "WHERE u.status = 'disabled' " . 'ORDER BY (SELECT 0) OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY', $sql ); } /** * @group DBAL-713 */ public function testModifyLimitQueryWithSubSelectInSelectListAndOrderByClause() : void { $sql = $this->platform->modifyLimitQuery( 'SELECT ' . 'u.id, ' . '(u.foo/2) foodiv, ' . 'CONCAT(u.bar, u.baz) barbaz, ' . '(SELECT (SELECT COUNT(*) FROM login l WHERE l.profile_id = p.id) FROM profile p WHERE p.user_id = u.id) login_count ' . 'FROM user u ' . "WHERE u.status = 'disabled' " . 'ORDER BY u.username DESC', 10, 5 ); self::assertEquals( 'SELECT ' . 'u.id, ' . '(u.foo/2) foodiv, ' . 'CONCAT(u.bar, u.baz) barbaz, ' . '(SELECT (SELECT COUNT(*) FROM login l WHERE l.profile_id = p.id) FROM profile p WHERE p.user_id = u.id) login_count ' . 'FROM user u ' . "WHERE u.status = 'disabled' " . 'ORDER BY u.username DESC ' . 'OFFSET 5 ROWS FETCH NEXT 10 ROWS ONLY', $sql ); } /** * @group DBAL-834 */ public function testModifyLimitQueryWithAggregateFunctionInOrderByClause() : void { $sql = $this->platform->modifyLimitQuery( 'SELECT ' . 'MAX(heading_id) aliased, ' . 'code ' . 'FROM operator_model_operator ' . 'GROUP BY code ' . 'ORDER BY MAX(heading_id) DESC', 1, 0 ); self::assertEquals( 'SELECT ' . 'MAX(heading_id) aliased, ' . 'code ' . 'FROM operator_model_operator ' . 'GROUP BY code ' . 'ORDER BY MAX(heading_id) DESC ' . 'OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY', $sql ); } public function testModifyLimitQueryWithFromSubquery() : void { $sql = $this->platform->modifyLimitQuery('SELECT DISTINCT id_0 FROM (SELECT k0_.id AS id_0 FROM key_measure k0_ WHERE (k0_.id_zone in(2))) dctrn_result', 10); $expected = 'SELECT DISTINCT id_0 FROM (SELECT k0_.id AS id_0 FROM key_measure k0_ WHERE (k0_.id_zone in(2))) dctrn_result ORDER BY 1 OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY'; self::assertEquals($sql, $expected); } public function testModifyLimitQueryWithFromSubqueryAndOrder() : void { $sql = $this->platform->modifyLimitQuery('SELECT DISTINCT id_0, value_1 FROM (SELECT k0_.id AS id_0, k0_.value AS value_1 FROM key_measure k0_ WHERE (k0_.id_zone in(2))) dctrn_result ORDER BY value_1 DESC', 10); $expected = 'SELECT DISTINCT id_0, value_1 FROM (SELECT k0_.id AS id_0, k0_.value AS value_1 FROM key_measure k0_ WHERE (k0_.id_zone in(2))) dctrn_result ORDER BY value_1 DESC OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY'; self::assertEquals($sql, $expected); } public function testModifyLimitQueryWithComplexOrderByExpression() : void { $sql = $this->platform->modifyLimitQuery('SELECT * FROM table ORDER BY (table.x * table.y) DESC', 10); $expected = 'SELECT * FROM table ORDER BY (table.x * table.y) DESC OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY'; self::assertEquals($sql, $expected); } /** * @throws DBALException */ public function testModifyLimitSubqueryWithJoinAndSubqueryOrderedByColumnFromBaseTable() : void { $querySql = 'SELECT DISTINCT id_0, name_1 ' . 'FROM (' . 'SELECT t1.id AS id_0, t2.name AS name_1 ' . 'FROM table_parent t1 ' . 'LEFT JOIN join_table t2 ON t1.id = t2.table_id' . ') dctrn_result ' . 'ORDER BY id_0 ASC'; $alteredSql = 'SELECT DISTINCT id_0, name_1 ' . 'FROM (' . 'SELECT t1.id AS id_0, t2.name AS name_1 ' . 'FROM table_parent t1 ' . 'LEFT JOIN join_table t2 ON t1.id = t2.table_id' . ') dctrn_result ' . 'ORDER BY id_0 ASC OFFSET 0 ROWS FETCH NEXT 5 ROWS ONLY'; $sql = $this->platform->modifyLimitQuery($querySql, 5); self::assertEquals($alteredSql, $sql); } /** * @throws DBALException */ public function testModifyLimitSubqueryWithJoinAndSubqueryOrderedByColumnFromJoinTable() : void { $querySql = 'SELECT DISTINCT id_0, name_1 ' . 'FROM (' . 'SELECT t1.id AS id_0, t2.name AS name_1 ' . 'FROM table_parent t1 ' . 'LEFT JOIN join_table t2 ON t1.id = t2.table_id' . ') dctrn_result ' . 'ORDER BY name_1 ASC'; $alteredSql = 'SELECT DISTINCT id_0, name_1 ' . 'FROM (' . 'SELECT t1.id AS id_0, t2.name AS name_1 ' . 'FROM table_parent t1 ' . 'LEFT JOIN join_table t2 ON t1.id = t2.table_id' . ') dctrn_result ' . 'ORDER BY name_1 ASC OFFSET 0 ROWS FETCH NEXT 5 ROWS ONLY'; $sql = $this->platform->modifyLimitQuery($querySql, 5); self::assertEquals($alteredSql, $sql); } /** * @throws DBALException */ public function testModifyLimitSubqueryWithJoinAndSubqueryOrderedByColumnsFromBothTables() : void { $querySql = 'SELECT DISTINCT id_0, name_1, foo_2 ' . 'FROM (' . 'SELECT t1.id AS id_0, t2.name AS name_1, t2.foo AS foo_2 ' . 'FROM table_parent t1 ' . 'LEFT JOIN join_table t2 ON t1.id = t2.table_id' . ') dctrn_result ' . 'ORDER BY name_1 ASC, foo_2 DESC'; $alteredSql = 'SELECT DISTINCT id_0, name_1, foo_2 ' . 'FROM (' . 'SELECT t1.id AS id_0, t2.name AS name_1, t2.foo AS foo_2 ' . 'FROM table_parent t1 ' . 'LEFT JOIN join_table t2 ON t1.id = t2.table_id' . ') dctrn_result ' . 'ORDER BY name_1 ASC, foo_2 DESC OFFSET 0 ROWS FETCH NEXT 5 ROWS ONLY'; $sql = $this->platform->modifyLimitQuery($querySql, 5); self::assertEquals($alteredSql, $sql); } public function testModifyLimitSubquerySimple() : void { $querySql = 'SELECT DISTINCT id_0 FROM ' . '(SELECT k0_.id AS id_0, k0_.field AS field_1 ' . 'FROM key_table k0_ WHERE (k0_.where_field IN (1))) dctrn_result'; $alteredSql = 'SELECT DISTINCT id_0 FROM (SELECT k0_.id AS id_0, k0_.field AS field_1 ' . 'FROM key_table k0_ WHERE (k0_.where_field IN (1))) dctrn_result ORDER BY 1 OFFSET 0 ROWS FETCH NEXT 20 ROWS ONLY'; $sql = $this->platform->modifyLimitQuery($querySql, 20); self::assertEquals($alteredSql, $sql); } public function testModifyLimitQueryWithTopNSubQueryWithOrderBy() : void { $querySql = 'SELECT * FROM test t WHERE t.id = (SELECT TOP 1 t2.id FROM test t2 ORDER BY t2.data DESC)'; $expectedSql = 'SELECT * FROM test t WHERE t.id = (SELECT TOP 1 t2.id FROM test t2 ORDER BY t2.data DESC) ORDER BY (SELECT 0) OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY'; $sql = $this->platform->modifyLimitQuery($querySql, 10); self::assertEquals($expectedSql, $sql); $querySql = 'SELECT * FROM test t WHERE t.id = (SELECT TOP 1 t2.id FROM test t2 ORDER BY t2.data DESC) ORDER BY t.data2 DESC'; $expectedSql = 'SELECT * FROM test t WHERE t.id = (SELECT TOP 1 t2.id FROM test t2 ORDER BY t2.data DESC) ORDER BY t.data2 DESC OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY'; $sql = $this->platform->modifyLimitQuery($querySql, 10); self::assertEquals($expectedSql, $sql); } public function testModifyLimitQueryWithNewlineBeforeOrderBy() : void { $querySql = "SELECT * FROM test\nORDER BY col DESC"; $expectedSql = "SELECT * FROM test\nORDER BY col DESC OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY"; $sql = $this->platform->modifyLimitQuery($querySql, 10); self::assertEquals($expectedSql, $sql); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Platforms/SQLServerPlatformTest.php000066400000000000000000000064001360544566000304700ustar00rootroot00000000000000platform->appendLockHint($fromClause, $lockMode)); } /** * @group DBAL-2408 * @dataProvider getModifyLimitQueries */ public function testScrubInnerOrderBy(string $query, int $limit, ?int $offset, string $expectedResult) : void { self::assertSame($expectedResult, $this->platform->modifyLimitQuery($query, $limit, $offset)); } /** * @return mixed[][] */ public static function getLockHints() : iterable { return [ [null, ''], [false, ''], [true, ''], [LockMode::NONE, ' WITH (NOLOCK)'], [LockMode::OPTIMISTIC, ''], [LockMode::PESSIMISTIC_READ, ' WITH (HOLDLOCK, ROWLOCK)'], [LockMode::PESSIMISTIC_WRITE, ' WITH (UPDLOCK, ROWLOCK)'], ]; } /** * @return mixed[][] */ public static function getModifyLimitQueries() : iterable { return [ // Test re-ordered query with correctly-scrubbed ORDER BY clause [ 'SELECT id_0, MIN(sclr_2) AS dctrn_minrownum FROM (SELECT c0_.id AS id_0, c0_.title AS title_1, ROW_NUMBER() OVER(ORDER BY c0_.title ASC) AS sclr_2 FROM TestTable c0_ ORDER BY c0_.title ASC) dctrn_result GROUP BY id_0 ORDER BY dctrn_minrownum ASC', 30, null, 'WITH dctrn_cte AS (SELECT TOP 30 id_0, MIN(sclr_2) AS dctrn_minrownum FROM (SELECT c0_.id AS id_0, c0_.title AS title_1, ROW_NUMBER() OVER(ORDER BY c0_.title ASC) AS sclr_2 FROM TestTable c0_) dctrn_result GROUP BY id_0 ORDER BY dctrn_minrownum ASC) SELECT * FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS doctrine_rownum FROM dctrn_cte) AS doctrine_tbl WHERE doctrine_rownum <= 30 ORDER BY doctrine_rownum ASC', ], // Test re-ordered query with no scrubbed ORDER BY clause [ 'SELECT id_0, MIN(sclr_2) AS dctrn_minrownum FROM (SELECT c0_.id AS id_0, c0_.title AS title_1, ROW_NUMBER() OVER(ORDER BY c0_.title ASC) AS sclr_2 FROM TestTable c0_) dctrn_result GROUP BY id_0 ORDER BY dctrn_minrownum ASC', 30, null, 'WITH dctrn_cte AS (SELECT TOP 30 id_0, MIN(sclr_2) AS dctrn_minrownum FROM (SELECT c0_.id AS id_0, c0_.title AS title_1, ROW_NUMBER() OVER(ORDER BY c0_.title ASC) AS sclr_2 FROM TestTable c0_) dctrn_result GROUP BY id_0 ORDER BY dctrn_minrownum ASC) SELECT * FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS doctrine_rownum FROM dctrn_cte) AS doctrine_tbl WHERE doctrine_rownum <= 30 ORDER BY doctrine_rownum ASC', ], ]; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Platforms/SqlitePlatformTest.php000066400000000000000000000723311360544566000301110ustar00rootroot00000000000000platform->getRegexpExpression(), 'Regular expression operator is not correct'); self::assertEquals('SUBSTR(column, 5, LENGTH(column))', $this->platform->getSubstringExpression('column', 5), 'Substring expression without length is not correct'); self::assertEquals('SUBSTR(column, 0, 5)', $this->platform->getSubstringExpression('column', 0, 5), 'Substring expression with length is not correct'); } public function testGeneratesTransactionCommands() : void { self::assertEquals( 'PRAGMA read_uncommitted = 0', $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::READ_UNCOMMITTED) ); self::assertEquals( 'PRAGMA read_uncommitted = 1', $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::READ_COMMITTED) ); self::assertEquals( 'PRAGMA read_uncommitted = 1', $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::REPEATABLE_READ) ); self::assertEquals( 'PRAGMA read_uncommitted = 1', $this->platform->getSetTransactionIsolationSQL(TransactionIsolationLevel::SERIALIZABLE) ); } public function testPrefersIdentityColumns() : void { self::assertTrue($this->platform->prefersIdentityColumns()); } public function testIgnoresUnsignedIntegerDeclarationForAutoIncrementalIntegers() : void { self::assertSame( 'INTEGER PRIMARY KEY AUTOINCREMENT', $this->platform->getIntegerTypeDeclarationSQL(['autoincrement' => true, 'unsigned' => true]) ); } /** * @group DBAL-752 * @group DBAL-924 */ public function testGeneratesTypeDeclarationForTinyIntegers() : void { self::assertEquals( 'TINYINT', $this->platform->getTinyIntTypeDeclarationSQL([]) ); self::assertEquals( 'INTEGER PRIMARY KEY AUTOINCREMENT', $this->platform->getTinyIntTypeDeclarationSQL(['autoincrement' => true]) ); self::assertEquals( 'INTEGER PRIMARY KEY AUTOINCREMENT', $this->platform->getTinyIntTypeDeclarationSQL( ['autoincrement' => true, 'primary' => true] ) ); self::assertEquals( 'TINYINT', $this->platform->getTinyIntTypeDeclarationSQL(['unsigned' => false]) ); self::assertEquals( 'TINYINT UNSIGNED', $this->platform->getTinyIntTypeDeclarationSQL(['unsigned' => true]) ); } /** * @group DBAL-752 * @group DBAL-924 */ public function testGeneratesTypeDeclarationForSmallIntegers() : void { self::assertEquals( 'SMALLINT', $this->platform->getSmallIntTypeDeclarationSQL([]) ); self::assertEquals( 'INTEGER PRIMARY KEY AUTOINCREMENT', $this->platform->getSmallIntTypeDeclarationSQL(['autoincrement' => true]) ); self::assertEquals( 'INTEGER PRIMARY KEY AUTOINCREMENT', $this->platform->getTinyIntTypeDeclarationSQL(['autoincrement' => true, 'unsigned' => true]) ); self::assertEquals( 'INTEGER PRIMARY KEY AUTOINCREMENT', $this->platform->getSmallIntTypeDeclarationSQL( ['autoincrement' => true, 'primary' => true] ) ); self::assertEquals( 'SMALLINT', $this->platform->getSmallIntTypeDeclarationSQL(['unsigned' => false]) ); self::assertEquals( 'SMALLINT UNSIGNED', $this->platform->getSmallIntTypeDeclarationSQL(['unsigned' => true]) ); } /** * @group DBAL-752 * @group DBAL-924 */ public function testGeneratesTypeDeclarationForMediumIntegers() : void { self::assertEquals( 'MEDIUMINT', $this->platform->getMediumIntTypeDeclarationSQL([]) ); self::assertEquals( 'INTEGER PRIMARY KEY AUTOINCREMENT', $this->platform->getMediumIntTypeDeclarationSQL(['autoincrement' => true]) ); self::assertEquals( 'INTEGER PRIMARY KEY AUTOINCREMENT', $this->platform->getMediumIntTypeDeclarationSQL(['autoincrement' => true, 'unsigned' => true]) ); self::assertEquals( 'INTEGER PRIMARY KEY AUTOINCREMENT', $this->platform->getMediumIntTypeDeclarationSQL( ['autoincrement' => true, 'primary' => true] ) ); self::assertEquals( 'MEDIUMINT', $this->platform->getMediumIntTypeDeclarationSQL(['unsigned' => false]) ); self::assertEquals( 'MEDIUMINT UNSIGNED', $this->platform->getMediumIntTypeDeclarationSQL(['unsigned' => true]) ); } public function testGeneratesTypeDeclarationForIntegers() : void { self::assertEquals( 'INTEGER', $this->platform->getIntegerTypeDeclarationSQL([]) ); self::assertEquals( 'INTEGER PRIMARY KEY AUTOINCREMENT', $this->platform->getIntegerTypeDeclarationSQL(['autoincrement' => true]) ); self::assertEquals( 'INTEGER PRIMARY KEY AUTOINCREMENT', $this->platform->getIntegerTypeDeclarationSQL(['autoincrement' => true, 'unsigned' => true]) ); self::assertEquals( 'INTEGER PRIMARY KEY AUTOINCREMENT', $this->platform->getIntegerTypeDeclarationSQL( ['autoincrement' => true, 'primary' => true] ) ); self::assertEquals( 'INTEGER', $this->platform->getIntegerTypeDeclarationSQL(['unsigned' => false]) ); self::assertEquals( 'INTEGER UNSIGNED', $this->platform->getIntegerTypeDeclarationSQL(['unsigned' => true]) ); } /** * @group DBAL-752 * @group DBAL-924 */ public function testGeneratesTypeDeclarationForBigIntegers() : void { self::assertEquals( 'BIGINT', $this->platform->getBigIntTypeDeclarationSQL([]) ); self::assertEquals( 'INTEGER PRIMARY KEY AUTOINCREMENT', $this->platform->getBigIntTypeDeclarationSQL(['autoincrement' => true]) ); self::assertEquals( 'INTEGER PRIMARY KEY AUTOINCREMENT', $this->platform->getBigIntTypeDeclarationSQL(['autoincrement' => true, 'unsigned' => true]) ); self::assertEquals( 'INTEGER PRIMARY KEY AUTOINCREMENT', $this->platform->getBigIntTypeDeclarationSQL( ['autoincrement' => true, 'primary' => true] ) ); self::assertEquals( 'BIGINT', $this->platform->getBigIntTypeDeclarationSQL(['unsigned' => false]) ); self::assertEquals( 'BIGINT UNSIGNED', $this->platform->getBigIntTypeDeclarationSQL(['unsigned' => true]) ); } public function testGeneratesTypeDeclarationForStrings() : void { self::assertEquals( 'CHAR(10)', $this->platform->getVarcharTypeDeclarationSQL( ['length' => 10, 'fixed' => true] ) ); self::assertEquals( 'VARCHAR(50)', $this->platform->getVarcharTypeDeclarationSQL(['length' => 50]), 'Variable string declaration is not correct' ); self::assertEquals( 'VARCHAR(255)', $this->platform->getVarcharTypeDeclarationSQL([]), 'Long string declaration is not correct' ); } public function getGenerateIndexSql() : string { return 'CREATE INDEX my_idx ON mytable (user_name, last_login)'; } public function getGenerateUniqueIndexSql() : string { return 'CREATE UNIQUE INDEX index_name ON test (test, test2)'; } public function testGeneratesForeignKeyCreationSql() : void { $this->expectException(DBALException::class); parent::testGeneratesForeignKeyCreationSql(); } public function testGeneratesConstraintCreationSql() : void { $this->expectException(DBALException::class); parent::testGeneratesConstraintCreationSql(); } public function getGenerateForeignKeySql() : string { return null; } public function testModifyLimitQuery() : void { $sql = $this->platform->modifyLimitQuery('SELECT * FROM user', 10, 0); self::assertEquals('SELECT * FROM user LIMIT 10', $sql); } public function testModifyLimitQueryWithEmptyOffset() : void { $sql = $this->platform->modifyLimitQuery('SELECT * FROM user', 10); self::assertEquals('SELECT * FROM user LIMIT 10', $sql); } public function testModifyLimitQueryWithOffsetAndEmptyLimit() : void { $sql = $this->platform->modifyLimitQuery('SELECT * FROM user', null, 10); self::assertEquals('SELECT * FROM user LIMIT -1 OFFSET 10', $sql); } /** * {@inheritDoc} */ public function getGenerateAlterTableSql() : array { return [ 'CREATE TEMPORARY TABLE __temp__mytable AS SELECT id, bar, bloo FROM mytable', 'DROP TABLE mytable', "CREATE TABLE mytable (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, baz VARCHAR(255) DEFAULT 'def' NOT NULL, bloo BOOLEAN DEFAULT '0' NOT NULL, quota INTEGER DEFAULT NULL)", 'INSERT INTO mytable (id, baz, bloo) SELECT id, bar, bloo FROM __temp__mytable', 'DROP TABLE __temp__mytable', 'ALTER TABLE mytable RENAME TO userlist', ]; } /** * @group DDC-1845 */ public function testGenerateTableSqlShouldNotAutoQuotePrimaryKey() : void { $table = new Table('test'); $table->addColumn('"like"', 'integer', ['notnull' => true, 'autoincrement' => true]); $table->setPrimaryKey(['"like"']); $createTableSQL = $this->platform->getCreateTableSQL($table); self::assertEquals( 'CREATE TABLE test ("like" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)', $createTableSQL[0] ); } public function testAlterTableAddColumns() : void { $diff = new TableDiff('user'); $diff->addedColumns['foo'] = new Column('foo', Type::getType('string')); $diff->addedColumns['count'] = new Column('count', Type::getType('integer'), ['notnull' => false, 'default' => 1]); $expected = [ 'ALTER TABLE user ADD COLUMN foo VARCHAR(255) NOT NULL', 'ALTER TABLE user ADD COLUMN count INTEGER DEFAULT 1', ]; self::assertEquals($expected, $this->platform->getAlterTableSQL($diff)); } /** * @dataProvider complexDiffProvider */ public function testAlterTableAddComplexColumns(TableDiff $diff) : void { $this->expectException(DBALException::class); $this->platform->getAlterTableSQL($diff); } /** * @return mixed[][] */ public static function complexDiffProvider() : iterable { $date = new TableDiff('user'); $date->addedColumns['time'] = new Column('time', Type::getType('date'), ['default' => 'CURRENT_DATE']); $id = new TableDiff('user'); $id->addedColumns['id'] = new Column('id', Type::getType('integer'), ['autoincrement' => true]); return [ 'date column with default value' => [$date], 'id column with auto increment' => [$id], ]; } public function testCreateTableWithDeferredForeignKeys() : void { $table = new Table('user'); $table->addColumn('id', 'integer'); $table->addColumn('article', 'integer'); $table->addColumn('post', 'integer'); $table->addColumn('parent', 'integer'); $table->setPrimaryKey(['id']); $table->addForeignKeyConstraint('article', ['article'], ['id'], ['deferrable' => true]); $table->addForeignKeyConstraint('post', ['post'], ['id'], ['deferred' => true]); $table->addForeignKeyConstraint('user', ['parent'], ['id'], ['deferrable' => true, 'deferred' => true]); $sql = [ 'CREATE TABLE user (' . 'id INTEGER NOT NULL, article INTEGER NOT NULL, post INTEGER NOT NULL, parent INTEGER NOT NULL' . ', PRIMARY KEY(id)' . ', CONSTRAINT FK_8D93D64923A0E66 FOREIGN KEY (article) REFERENCES article (id) DEFERRABLE INITIALLY IMMEDIATE' . ', CONSTRAINT FK_8D93D6495A8A6C8D FOREIGN KEY (post) REFERENCES post (id) NOT DEFERRABLE INITIALLY DEFERRED' . ', CONSTRAINT FK_8D93D6493D8E604F FOREIGN KEY (parent) REFERENCES user (id) DEFERRABLE INITIALLY DEFERRED' . ')', 'CREATE INDEX IDX_8D93D64923A0E66 ON user (article)', 'CREATE INDEX IDX_8D93D6495A8A6C8D ON user (post)', 'CREATE INDEX IDX_8D93D6493D8E604F ON user (parent)', ]; self::assertEquals($sql, $this->platform->getCreateTableSQL($table)); } public function testAlterTable() : void { $table = new Table('user'); $table->addColumn('id', 'integer'); $table->addColumn('article', 'integer'); $table->addColumn('post', 'integer'); $table->addColumn('parent', 'integer'); $table->setPrimaryKey(['id']); $table->addForeignKeyConstraint('article', ['article'], ['id'], ['deferrable' => true]); $table->addForeignKeyConstraint('post', ['post'], ['id'], ['deferred' => true]); $table->addForeignKeyConstraint('user', ['parent'], ['id'], ['deferrable' => true, 'deferred' => true]); $table->addIndex(['article', 'post'], 'index1'); $diff = new TableDiff('user'); $diff->fromTable = $table; $diff->newName = 'client'; $diff->renamedColumns['id'] = new Column('key', Type::getType('integer'), []); $diff->renamedColumns['post'] = new Column('comment', Type::getType('integer'), []); $diff->removedColumns['parent'] = new Column('comment', Type::getType('integer'), []); $diff->removedIndexes['index1'] = $table->getIndex('index1'); $sql = [ 'DROP INDEX IDX_8D93D64923A0E66', 'DROP INDEX IDX_8D93D6495A8A6C8D', 'DROP INDEX IDX_8D93D6493D8E604F', 'DROP INDEX index1', 'CREATE TEMPORARY TABLE __temp__user AS SELECT id, article, post FROM user', 'DROP TABLE user', 'CREATE TABLE user (' . '"key" INTEGER NOT NULL, article INTEGER NOT NULL, comment INTEGER NOT NULL' . ', PRIMARY KEY("key")' . ', CONSTRAINT FK_8D93D64923A0E66 FOREIGN KEY (article) REFERENCES article (id) DEFERRABLE INITIALLY IMMEDIATE' . ', CONSTRAINT FK_8D93D6495A8A6C8D FOREIGN KEY (comment) REFERENCES post (id) NOT DEFERRABLE INITIALLY DEFERRED' . ')', 'INSERT INTO user ("key", article, comment) SELECT id, article, post FROM __temp__user', 'DROP TABLE __temp__user', 'ALTER TABLE user RENAME TO client', 'CREATE INDEX IDX_8D93D64923A0E66 ON client (article)', 'CREATE INDEX IDX_8D93D6495A8A6C8D ON client (comment)', ]; self::assertEquals($sql, $this->platform->getAlterTableSQL($diff)); } /** * {@inheritDoc} */ protected function getQuotedColumnInPrimaryKeySQL() : array { return ['CREATE TABLE "quoted" ("create" VARCHAR(255) NOT NULL, PRIMARY KEY("create"))']; } /** * {@inheritDoc} */ protected function getQuotedColumnInIndexSQL() : array { return [ 'CREATE TABLE "quoted" ("create" VARCHAR(255) NOT NULL)', 'CREATE INDEX IDX_22660D028FD6E0FB ON "quoted" ("create")', ]; } /** * {@inheritDoc} */ protected function getQuotedNameInIndexSQL() : array { return [ 'CREATE TABLE test (column1 VARCHAR(255) NOT NULL)', 'CREATE INDEX "key" ON test (column1)', ]; } /** * {@inheritDoc} */ protected function getQuotedColumnInForeignKeySQL() : array { return [ 'CREATE TABLE "quoted" (' . '"create" VARCHAR(255) NOT NULL, foo VARCHAR(255) NOT NULL, "bar" VARCHAR(255) NOT NULL, ' . 'CONSTRAINT FK_WITH_RESERVED_KEYWORD FOREIGN KEY ("create", foo, "bar") REFERENCES "foreign" ("create", bar, "foo-bar") NOT DEFERRABLE INITIALLY IMMEDIATE, ' . 'CONSTRAINT FK_WITH_NON_RESERVED_KEYWORD FOREIGN KEY ("create", foo, "bar") REFERENCES foo ("create", bar, "foo-bar") NOT DEFERRABLE INITIALLY IMMEDIATE, ' . 'CONSTRAINT FK_WITH_INTENDED_QUOTATION FOREIGN KEY ("create", foo, "bar") REFERENCES "foo-bar" ("create", bar, "foo-bar") NOT DEFERRABLE INITIALLY IMMEDIATE)', ]; } protected function getBinaryDefaultLength() : int { return 0; } protected function getBinaryMaxLength() : int { return 0; } public function testReturnsBinaryTypeDeclarationSQL() : void { self::assertSame('BLOB', $this->platform->getBinaryTypeDeclarationSQL([])); self::assertSame('BLOB', $this->platform->getBinaryTypeDeclarationSQL(['length' => 0])); self::assertSame('BLOB', $this->platform->getBinaryTypeDeclarationSQL(['length' => 9999999])); self::assertSame('BLOB', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true])); self::assertSame('BLOB', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 0])); self::assertSame('BLOB', $this->platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 9999999])); } /** * {@inheritDoc} * * @group DBAL-234 */ protected function getAlterTableRenameIndexSQL() : array { return [ 'CREATE TEMPORARY TABLE __temp__mytable AS SELECT id FROM mytable', 'DROP TABLE mytable', 'CREATE TABLE mytable (id INTEGER NOT NULL, PRIMARY KEY(id))', 'INSERT INTO mytable (id) SELECT id FROM __temp__mytable', 'DROP TABLE __temp__mytable', 'CREATE INDEX idx_bar ON mytable (id)', ]; } /** * {@inheritDoc} * * @group DBAL-234 */ protected function getQuotedAlterTableRenameIndexSQL() : array { return [ 'CREATE TEMPORARY TABLE __temp__table AS SELECT id FROM "table"', 'DROP TABLE "table"', 'CREATE TABLE "table" (id INTEGER NOT NULL, PRIMARY KEY(id))', 'INSERT INTO "table" (id) SELECT id FROM __temp__table', 'DROP TABLE __temp__table', 'CREATE INDEX "select" ON "table" (id)', 'CREATE INDEX "bar" ON "table" (id)', ]; } /** * {@inheritdoc} */ protected function getQuotedAlterTableRenameColumnSQL() : array { return [ 'CREATE TEMPORARY TABLE __temp__mytable AS SELECT unquoted1, unquoted2, unquoted3, "create", "table", "select", "quoted1", "quoted2", "quoted3" FROM mytable', 'DROP TABLE mytable', 'CREATE TABLE mytable (unquoted INTEGER NOT NULL --Unquoted 1 , "where" INTEGER NOT NULL --Unquoted 2 , "foo" INTEGER NOT NULL --Unquoted 3 , reserved_keyword INTEGER NOT NULL --Reserved keyword 1 , "from" INTEGER NOT NULL --Reserved keyword 2 , "bar" INTEGER NOT NULL --Reserved keyword 3 , quoted INTEGER NOT NULL --Quoted 1 , "and" INTEGER NOT NULL --Quoted 2 , "baz" INTEGER NOT NULL --Quoted 3 )', 'INSERT INTO mytable (unquoted, "where", "foo", reserved_keyword, "from", "bar", quoted, "and", "baz") SELECT unquoted1, unquoted2, unquoted3, "create", "table", "select", "quoted1", "quoted2", "quoted3" FROM __temp__mytable', 'DROP TABLE __temp__mytable', ]; } /** * {@inheritdoc} */ protected function getQuotedAlterTableChangeColumnLengthSQL() : array { return [ 'CREATE TEMPORARY TABLE __temp__mytable AS SELECT unquoted1, unquoted2, unquoted3, "create", "table", "select" FROM mytable', 'DROP TABLE mytable', 'CREATE TABLE mytable (unquoted1 VARCHAR(255) NOT NULL --Unquoted 1 , unquoted2 VARCHAR(255) NOT NULL --Unquoted 2 , unquoted3 VARCHAR(255) NOT NULL --Unquoted 3 , "create" VARCHAR(255) NOT NULL --Reserved keyword 1 , "table" VARCHAR(255) NOT NULL --Reserved keyword 2 , "select" VARCHAR(255) NOT NULL --Reserved keyword 3 )', 'INSERT INTO mytable (unquoted1, unquoted2, unquoted3, "create", "table", "select") SELECT unquoted1, unquoted2, unquoted3, "create", "table", "select" FROM __temp__mytable', 'DROP TABLE __temp__mytable', ]; } /** * @group DBAL-807 */ public function testAlterTableRenameIndexInSchema() : void { $this->markTestIncomplete( 'Test currently produces broken SQL due to SQLLitePlatform::getAlterTable being broken ' . 'when used with schemas.' ); } /** * @group DBAL-807 */ public function testQuotesAlterTableRenameIndexInSchema() : void { $this->markTestIncomplete( 'Test currently produces broken SQL due to SQLLitePlatform::getAlterTable being broken ' . 'when used with schemas.' ); } /** * @group DBAL-423 */ public function testReturnsGuidTypeDeclarationSQL() : void { self::assertSame('CHAR(36)', $this->platform->getGuidTypeDeclarationSQL([])); } /** * {@inheritdoc} */ public function getAlterTableRenameColumnSQL() : array { return [ 'CREATE TEMPORARY TABLE __temp__foo AS SELECT bar FROM foo', 'DROP TABLE foo', 'CREATE TABLE foo (baz INTEGER DEFAULT 666 NOT NULL --rename test )', 'INSERT INTO foo (baz) SELECT bar FROM __temp__foo', 'DROP TABLE __temp__foo', ]; } /** * {@inheritdoc} */ protected function getQuotesTableIdentifiersInAlterTableSQL() : array { return [ 'DROP INDEX IDX_8C736521A81E660E', 'DROP INDEX IDX_8C736521FDC58D6C', 'CREATE TEMPORARY TABLE __temp__foo AS SELECT fk, fk2, id, fk3, bar FROM "foo"', 'DROP TABLE "foo"', 'CREATE TABLE "foo" (fk2 INTEGER NOT NULL, fk3 INTEGER NOT NULL, fk INTEGER NOT NULL, war INTEGER NOT NULL, ' . 'bar INTEGER DEFAULT NULL, bloo INTEGER NOT NULL, ' . 'CONSTRAINT fk2 FOREIGN KEY (fk2) REFERENCES fk_table2 (id) NOT DEFERRABLE INITIALLY IMMEDIATE, ' . 'CONSTRAINT fk_add FOREIGN KEY (fk3) REFERENCES fk_table (id) NOT DEFERRABLE INITIALLY IMMEDIATE)', 'INSERT INTO "foo" (fk, fk2, war, fk3, bar) SELECT fk, fk2, id, fk3, bar FROM __temp__foo', 'DROP TABLE __temp__foo', 'ALTER TABLE "foo" RENAME TO "table"', 'CREATE INDEX IDX_8C736521A81E660E ON "table" (fk)', 'CREATE INDEX IDX_8C736521FDC58D6C ON "table" (fk2)', ]; } /** * {@inheritdoc} */ protected function getCommentOnColumnSQL() : array { return [ 'COMMENT ON COLUMN foo.bar IS \'comment\'', 'COMMENT ON COLUMN "Foo"."BAR" IS \'comment\'', 'COMMENT ON COLUMN "select"."from" IS \'comment\'', ]; } protected static function getInlineColumnCommentDelimiter() : string { return "\n"; } protected static function getInlineColumnRegularCommentSQL() : string { return "--Regular comment\n"; } protected static function getInlineColumnCommentRequiringEscapingSQL() : string { return "--Using inline comment delimiter \n-- works\n"; } protected static function getInlineColumnEmptyCommentSQL() : string { return "--\n"; } /** * {@inheritdoc} */ protected function getQuotesReservedKeywordInUniqueConstraintDeclarationSQL() : string { return 'CONSTRAINT "select" UNIQUE (foo)'; } /** * {@inheritdoc} */ protected function getQuotesReservedKeywordInIndexDeclarationSQL() : string { return 'INDEX "select" (foo)'; } /** * {@inheritdoc} */ protected function getQuotesReservedKeywordInTruncateTableSQL() : string { return 'DELETE FROM "select"'; } /** * {@inheritdoc} */ protected function getAlterStringToFixedStringSQL() : array { return [ 'CREATE TEMPORARY TABLE __temp__mytable AS SELECT name FROM mytable', 'DROP TABLE mytable', 'CREATE TABLE mytable (name CHAR(2) NOT NULL)', 'INSERT INTO mytable (name) SELECT name FROM __temp__mytable', 'DROP TABLE __temp__mytable', ]; } /** * {@inheritdoc} */ protected function getGeneratesAlterTableRenameIndexUsedByForeignKeySQL() : array { return [ 'DROP INDEX idx_foo', 'DROP INDEX idx_bar', 'CREATE TEMPORARY TABLE __temp__mytable AS SELECT foo, bar, baz FROM mytable', 'DROP TABLE mytable', 'CREATE TABLE mytable (foo INTEGER NOT NULL, bar INTEGER NOT NULL, baz INTEGER NOT NULL, CONSTRAINT fk_foo FOREIGN KEY (foo) REFERENCES foreign_table (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT fk_bar FOREIGN KEY (bar) REFERENCES foreign_table (id) NOT DEFERRABLE INITIALLY IMMEDIATE)', 'INSERT INTO mytable (foo, bar, baz) SELECT foo, bar, baz FROM __temp__mytable', 'DROP TABLE __temp__mytable', 'CREATE INDEX idx_bar ON mytable (bar)', 'CREATE INDEX idx_foo_renamed ON mytable (foo)', ]; } /** * @group DBAL-2436 */ public function testQuotesTableNameInListTableConstraintsSQL() : void { self::assertStringContainsStringIgnoringCase( "'Foo''Bar\\'", $this->platform->getListTableConstraintsSQL("Foo'Bar\\") ); } /** * @group DBAL-2436 */ public function testQuotesTableNameInListTableColumnsSQL() : void { self::assertStringContainsStringIgnoringCase( "'Foo''Bar\\'", $this->platform->getListTableColumnsSQL("Foo'Bar\\") ); } /** * @group DBAL-2436 */ public function testQuotesTableNameInListTableIndexesSQL() : void { self::assertStringContainsStringIgnoringCase( "'Foo''Bar\\'", $this->platform->getListTableIndexesSQL("Foo'Bar\\") ); } /** * @group DBAL-2436 */ public function testQuotesTableNameInListTableForeignKeysSQL() : void { self::assertStringContainsStringIgnoringCase( "'Foo''Bar\\'", $this->platform->getListTableForeignKeysSQL("Foo'Bar\\") ); } public function testDateAddStaticNumberOfDays() : void { self::assertSame("DATE(rentalBeginsOn,'+12 DAY')", $this->platform->getDateAddDaysExpression('rentalBeginsOn', 12)); } public function testDateAddNumberOfDaysFromColumn() : void { self::assertSame("DATE(rentalBeginsOn,'+' || duration || ' DAY')", $this->platform->getDateAddDaysExpression('rentalBeginsOn', 'duration')); } public function testSupportsColumnCollation() : void { self::assertTrue($this->platform->supportsColumnCollation()); } public function testColumnCollationDeclarationSQL() : void { self::assertSame( 'COLLATE NOCASE', $this->platform->getColumnCollationDeclarationSQL('NOCASE') ); } public function testGetCreateTableSQLWithColumnCollation() : void { $table = new Table('foo'); $table->addColumn('no_collation', 'string'); $table->addColumn('column_collation', 'string')->setPlatformOption('collation', 'NOCASE'); self::assertSame( ['CREATE TABLE foo (no_collation VARCHAR(255) NOT NULL, column_collation VARCHAR(255) NOT NULL COLLATE NOCASE)'], $this->platform->getCreateTableSQL($table), 'Column "no_collation" will use the default collation (BINARY) and "column_collation" overwrites the collation on this column' ); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Portability/000077500000000000000000000000001360544566000241175ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Portability/StatementTest.php000066400000000000000000000115261360544566000274410ustar00rootroot00000000000000wrappedStmt = $this->createMock(DriverStatement::class); $this->conn = $this->createConnection(); $this->stmt = $this->createStatement($this->wrappedStmt, $this->conn); } /** * @group DBAL-726 */ public function testBindParam() : void { $column = 'mycolumn'; $variable = 'myvalue'; $type = ParameterType::STRING; $length = 666; $this->wrappedStmt->expects($this->once()) ->method('bindParam') ->with($column, $variable, $type, $length) ->will($this->returnValue(true)); self::assertTrue($this->stmt->bindParam($column, $variable, $type, $length)); } public function testBindValue() : void { $param = 'myparam'; $value = 'myvalue'; $type = ParameterType::STRING; $this->wrappedStmt->expects($this->once()) ->method('bindValue') ->with($param, $value, $type) ->will($this->returnValue(true)); self::assertTrue($this->stmt->bindValue($param, $value, $type)); } public function testCloseCursor() : void { $this->wrappedStmt->expects($this->once()) ->method('closeCursor') ->will($this->returnValue(true)); self::assertTrue($this->stmt->closeCursor()); } public function testColumnCount() : void { $columnCount = 666; $this->wrappedStmt->expects($this->once()) ->method('columnCount') ->will($this->returnValue($columnCount)); self::assertSame($columnCount, $this->stmt->columnCount()); } public function testErrorCode() : void { $errorCode = '666'; $this->wrappedStmt->expects($this->once()) ->method('errorCode') ->will($this->returnValue($errorCode)); self::assertSame($errorCode, $this->stmt->errorCode()); } public function testErrorInfo() : void { $errorInfo = ['666', 'Evil error.']; $this->wrappedStmt->expects($this->once()) ->method('errorInfo') ->will($this->returnValue($errorInfo)); self::assertSame($errorInfo, $this->stmt->errorInfo()); } public function testExecute() : void { $params = [ 'foo', 'bar', ]; $this->wrappedStmt->expects($this->once()) ->method('execute') ->with($params) ->will($this->returnValue(true)); self::assertTrue($this->stmt->execute($params)); } public function testSetFetchMode() : void { $fetchMode = FetchMode::CUSTOM_OBJECT; $arg1 = 'MyClass'; $arg2 = [1, 2]; $this->wrappedStmt->expects($this->once()) ->method('setFetchMode') ->with($fetchMode, $arg1, $arg2) ->will($this->returnValue(true)); $re = new ReflectionProperty($this->stmt, 'defaultFetchMode'); $re->setAccessible(true); self::assertSame(FetchMode::MIXED, $re->getValue($this->stmt)); self::assertTrue($this->stmt->setFetchMode($fetchMode, $arg1, $arg2)); self::assertSame($fetchMode, $re->getValue($this->stmt)); } public function testGetIterator() : void { $this->wrappedStmt->expects($this->exactly(3)) ->method('fetch') ->willReturnOnConsecutiveCalls('foo', 'bar', false); self::assertSame(['foo', 'bar'], iterator_to_array($this->stmt->getIterator())); } public function testRowCount() : void { $rowCount = 666; $this->wrappedStmt->expects($this->once()) ->method('rowCount') ->will($this->returnValue($rowCount)); self::assertSame($rowCount, $this->stmt->rowCount()); } /** * @return Connection|MockObject */ protected function createConnection() { return $this->getMockBuilder(Connection::class) ->disableOriginalConstructor() ->getMock(); } protected function createStatement(DriverStatement $wrappedStatement, Connection $connection) : Statement { return new Statement($wrappedStatement, $connection); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Query/000077500000000000000000000000001360544566000227225ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Query/Expression/000077500000000000000000000000001360544566000250615ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Query/Expression/CompositeExpressionTest.php000066400000000000000000000057031360544566000324610ustar00rootroot00000000000000add('u.group_id = 2'); self::assertCount(2, $expr); } public function testAdd() : void { $expr = new CompositeExpression(CompositeExpression::TYPE_OR, ['u.group_id = 1']); self::assertCount(1, $expr); $expr->add(new CompositeExpression(CompositeExpression::TYPE_AND, [])); self::assertCount(1, $expr); $expr->add(new CompositeExpression(CompositeExpression::TYPE_OR, ['u.user_id = 1'])); self::assertCount(2, $expr); $expr->add(null); self::assertCount(2, $expr); $expr->add('u.user_id = 1'); self::assertCount(3, $expr); } /** * @param string[]|CompositeExpression[] $parts * * @dataProvider provideDataForConvertToString */ public function testCompositeUsageAndGeneration(string $type, array $parts, string $expects) : void { $expr = new CompositeExpression($type, $parts); self::assertEquals($expects, (string) $expr); } /** * @return mixed[][] */ public static function provideDataForConvertToString() : iterable { return [ [ CompositeExpression::TYPE_AND, ['u.user = 1'], 'u.user = 1', ], [ CompositeExpression::TYPE_AND, ['u.user = 1', 'u.group_id = 1'], '(u.user = 1) AND (u.group_id = 1)', ], [ CompositeExpression::TYPE_OR, ['u.user = 1'], 'u.user = 1', ], [ CompositeExpression::TYPE_OR, ['u.group_id = 1', 'u.group_id = 2'], '(u.group_id = 1) OR (u.group_id = 2)', ], [ CompositeExpression::TYPE_AND, [ 'u.user = 1', new CompositeExpression( CompositeExpression::TYPE_OR, ['u.group_id = 1', 'u.group_id = 2'] ), ], '(u.user = 1) AND ((u.group_id = 1) OR (u.group_id = 2))', ], [ CompositeExpression::TYPE_OR, [ 'u.group_id = 1', new CompositeExpression( CompositeExpression::TYPE_AND, ['u.user = 1', 'u.group_id = 2'] ), ], '(u.group_id = 1) OR ((u.user = 1) AND (u.group_id = 2))', ], ]; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Query/Expression/ExpressionBuilderTest.php000066400000000000000000000165171360544566000321120ustar00rootroot00000000000000createMock(Connection::class); $this->expr = new ExpressionBuilder($conn); $conn->expects($this->any()) ->method('getExpressionBuilder') ->will($this->returnValue($this->expr)); } /** * @param string[]|CompositeExpression[] $parts * * @dataProvider provideDataForAndX */ public function testAndX(array $parts, string $expected) : void { $composite = $this->expr->andX(); foreach ($parts as $part) { $composite->add($part); } self::assertEquals($expected, (string) $composite); } /** * @return mixed[][] */ public static function provideDataForAndX() : iterable { return [ [ ['u.user = 1'], 'u.user = 1', ], [ ['u.user = 1', 'u.group_id = 1'], '(u.user = 1) AND (u.group_id = 1)', ], [ ['u.user = 1'], 'u.user = 1', ], [ ['u.group_id = 1', 'u.group_id = 2'], '(u.group_id = 1) AND (u.group_id = 2)', ], [ [ 'u.user = 1', new CompositeExpression( CompositeExpression::TYPE_OR, ['u.group_id = 1', 'u.group_id = 2'] ), ], '(u.user = 1) AND ((u.group_id = 1) OR (u.group_id = 2))', ], [ [ 'u.group_id = 1', new CompositeExpression( CompositeExpression::TYPE_AND, ['u.user = 1', 'u.group_id = 2'] ), ], '(u.group_id = 1) AND ((u.user = 1) AND (u.group_id = 2))', ], ]; } /** * @param string[]|CompositeExpression[] $parts * * @dataProvider provideDataForOrX */ public function testOrX(array $parts, string $expected) : void { $composite = $this->expr->orX(); foreach ($parts as $part) { $composite->add($part); } self::assertEquals($expected, (string) $composite); } /** * @return mixed[][] */ public static function provideDataForOrX() : iterable { return [ [ ['u.user = 1'], 'u.user = 1', ], [ ['u.user = 1', 'u.group_id = 1'], '(u.user = 1) OR (u.group_id = 1)', ], [ ['u.user = 1'], 'u.user = 1', ], [ ['u.group_id = 1', 'u.group_id = 2'], '(u.group_id = 1) OR (u.group_id = 2)', ], [ [ 'u.user = 1', new CompositeExpression( CompositeExpression::TYPE_OR, ['u.group_id = 1', 'u.group_id = 2'] ), ], '(u.user = 1) OR ((u.group_id = 1) OR (u.group_id = 2))', ], [ [ 'u.group_id = 1', new CompositeExpression( CompositeExpression::TYPE_AND, ['u.user = 1', 'u.group_id = 2'] ), ], '(u.group_id = 1) OR ((u.user = 1) AND (u.group_id = 2))', ], ]; } /** * @dataProvider provideDataForComparison */ public function testComparison(string $leftExpr, string $operator, string $rightExpr, string $expected) : void { $part = $this->expr->comparison($leftExpr, $operator, $rightExpr); self::assertEquals($expected, (string) $part); } /** * @return mixed[][] */ public static function provideDataForComparison() : iterable { return [ ['u.user_id', ExpressionBuilder::EQ, '1', 'u.user_id = 1'], ['u.user_id', ExpressionBuilder::NEQ, '1', 'u.user_id <> 1'], ['u.salary', ExpressionBuilder::LT, '10000', 'u.salary < 10000'], ['u.salary', ExpressionBuilder::LTE, '10000', 'u.salary <= 10000'], ['u.salary', ExpressionBuilder::GT, '10000', 'u.salary > 10000'], ['u.salary', ExpressionBuilder::GTE, '10000', 'u.salary >= 10000'], ]; } public function testEq() : void { self::assertEquals('u.user_id = 1', $this->expr->eq('u.user_id', '1')); } public function testNeq() : void { self::assertEquals('u.user_id <> 1', $this->expr->neq('u.user_id', '1')); } public function testLt() : void { self::assertEquals('u.salary < 10000', $this->expr->lt('u.salary', '10000')); } public function testLte() : void { self::assertEquals('u.salary <= 10000', $this->expr->lte('u.salary', '10000')); } public function testGt() : void { self::assertEquals('u.salary > 10000', $this->expr->gt('u.salary', '10000')); } public function testGte() : void { self::assertEquals('u.salary >= 10000', $this->expr->gte('u.salary', '10000')); } public function testIsNull() : void { self::assertEquals('u.deleted IS NULL', $this->expr->isNull('u.deleted')); } public function testIsNotNull() : void { self::assertEquals('u.updated IS NOT NULL', $this->expr->isNotNull('u.updated')); } public function testIn() : void { self::assertEquals('u.groups IN (1, 3, 4, 7)', $this->expr->in('u.groups', [1, 3, 4, 7])); } public function testInWithPlaceholder() : void { self::assertEquals('u.groups IN (?)', $this->expr->in('u.groups', '?')); } public function testNotIn() : void { self::assertEquals('u.groups NOT IN (1, 3, 4, 7)', $this->expr->notIn('u.groups', [1, 3, 4, 7])); } public function testNotInWithPlaceholder() : void { self::assertEquals('u.groups NOT IN (:values)', $this->expr->notIn('u.groups', ':values')); } public function testLikeWithoutEscape() : void { self::assertEquals("a.song LIKE 'a virgin'", $this->expr->like('a.song', "'a virgin'")); } public function testLikeWithEscape() : void { self::assertEquals( "a.song LIKE 'a virgin' ESCAPE '💩'", $this->expr->like('a.song', "'a virgin'", "'💩'") ); } public function testNotLikeWithoutEscape() : void { self::assertEquals( "s.last_words NOT LIKE 'this'", $this->expr->notLike('s.last_words', "'this'") ); } public function testNotLikeWithEscape() : void { self::assertEquals( "p.description NOT LIKE '20💩%' ESCAPE '💩'", $this->expr->notLike('p.description', "'20💩%'", "'💩'") ); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Query/QueryBuilderTest.php000066400000000000000000000676041360544566000267240ustar00rootroot00000000000000conn = $this->createMock(Connection::class); $expressionBuilder = new ExpressionBuilder($this->conn); $this->conn->expects($this->any()) ->method('getExpressionBuilder') ->will($this->returnValue($expressionBuilder)); } /** * @group DBAL-2291 */ public function testSimpleSelectWithoutFrom() : void { $qb = new QueryBuilder($this->conn); $qb->select('some_function()'); self::assertEquals('SELECT some_function()', (string) $qb); } public function testSimpleSelect() : void { $qb = new QueryBuilder($this->conn); $qb->select('u.id') ->from('users', 'u'); self::assertEquals('SELECT u.id FROM users u', (string) $qb); } public function testSimpleSelectWithDistinct() : void { $qb = new QueryBuilder($this->conn); $qb->select('u.id') ->distinct() ->from('users', 'u'); self::assertEquals('SELECT DISTINCT u.id FROM users u', (string) $qb); } public function testSelectWithSimpleWhere() : void { $qb = new QueryBuilder($this->conn); $expr = $qb->expr(); $qb->select('u.id') ->from('users', 'u') ->where($expr->andX($expr->eq('u.nickname', '?'))); self::assertEquals('SELECT u.id FROM users u WHERE u.nickname = ?', (string) $qb); } public function testSelectWithLeftJoin() : void { $qb = new QueryBuilder($this->conn); $expr = $qb->expr(); $qb->select('u.*', 'p.*') ->from('users', 'u') ->leftJoin('u', 'phones', 'p', $expr->eq('p.user_id', 'u.id')); self::assertEquals('SELECT u.*, p.* FROM users u LEFT JOIN phones p ON p.user_id = u.id', (string) $qb); } public function testSelectWithJoin() : void { $qb = new QueryBuilder($this->conn); $expr = $qb->expr(); $qb->select('u.*', 'p.*') ->from('users', 'u') ->Join('u', 'phones', 'p', $expr->eq('p.user_id', 'u.id')); self::assertEquals('SELECT u.*, p.* FROM users u INNER JOIN phones p ON p.user_id = u.id', (string) $qb); } public function testSelectWithInnerJoin() : void { $qb = new QueryBuilder($this->conn); $expr = $qb->expr(); $qb->select('u.*', 'p.*') ->from('users', 'u') ->innerJoin('u', 'phones', 'p', $expr->eq('p.user_id', 'u.id')); self::assertEquals('SELECT u.*, p.* FROM users u INNER JOIN phones p ON p.user_id = u.id', (string) $qb); } public function testSelectWithRightJoin() : void { $qb = new QueryBuilder($this->conn); $expr = $qb->expr(); $qb->select('u.*', 'p.*') ->from('users', 'u') ->rightJoin('u', 'phones', 'p', $expr->eq('p.user_id', 'u.id')); self::assertEquals('SELECT u.*, p.* FROM users u RIGHT JOIN phones p ON p.user_id = u.id', (string) $qb); } public function testSelectWithAndWhereConditions() : void { $qb = new QueryBuilder($this->conn); $expr = $qb->expr(); $qb->select('u.*', 'p.*') ->from('users', 'u') ->where('u.username = ?') ->andWhere('u.name = ?'); self::assertEquals('SELECT u.*, p.* FROM users u WHERE (u.username = ?) AND (u.name = ?)', (string) $qb); } public function testSelectWithOrWhereConditions() : void { $qb = new QueryBuilder($this->conn); $expr = $qb->expr(); $qb->select('u.*', 'p.*') ->from('users', 'u') ->where('u.username = ?') ->orWhere('u.name = ?'); self::assertEquals('SELECT u.*, p.* FROM users u WHERE (u.username = ?) OR (u.name = ?)', (string) $qb); } public function testSelectWithOrOrWhereConditions() : void { $qb = new QueryBuilder($this->conn); $expr = $qb->expr(); $qb->select('u.*', 'p.*') ->from('users', 'u') ->orWhere('u.username = ?') ->orWhere('u.name = ?'); self::assertEquals('SELECT u.*, p.* FROM users u WHERE (u.username = ?) OR (u.name = ?)', (string) $qb); } public function testSelectWithAndOrWhereConditions() : void { $qb = new QueryBuilder($this->conn); $expr = $qb->expr(); $qb->select('u.*', 'p.*') ->from('users', 'u') ->where('u.username = ?') ->andWhere('u.username = ?') ->orWhere('u.name = ?') ->andWhere('u.name = ?'); self::assertEquals('SELECT u.*, p.* FROM users u WHERE (((u.username = ?) AND (u.username = ?)) OR (u.name = ?)) AND (u.name = ?)', (string) $qb); } public function testSelectGroupBy() : void { $qb = new QueryBuilder($this->conn); $expr = $qb->expr(); $qb->select('u.*', 'p.*') ->from('users', 'u') ->groupBy('u.id'); self::assertEquals('SELECT u.*, p.* FROM users u GROUP BY u.id', (string) $qb); } public function testSelectEmptyGroupBy() : void { $qb = new QueryBuilder($this->conn); $expr = $qb->expr(); $qb->select('u.*', 'p.*') ->groupBy([]) ->from('users', 'u'); self::assertEquals('SELECT u.*, p.* FROM users u', (string) $qb); } public function testSelectEmptyAddGroupBy() : void { $qb = new QueryBuilder($this->conn); $expr = $qb->expr(); $qb->select('u.*', 'p.*') ->addGroupBy([]) ->from('users', 'u'); self::assertEquals('SELECT u.*, p.* FROM users u', (string) $qb); } public function testSelectAddGroupBy() : void { $qb = new QueryBuilder($this->conn); $expr = $qb->expr(); $qb->select('u.*', 'p.*') ->from('users', 'u') ->groupBy('u.id') ->addGroupBy('u.foo'); self::assertEquals('SELECT u.*, p.* FROM users u GROUP BY u.id, u.foo', (string) $qb); } public function testSelectAddGroupBys() : void { $qb = new QueryBuilder($this->conn); $expr = $qb->expr(); $qb->select('u.*', 'p.*') ->from('users', 'u') ->groupBy('u.id') ->addGroupBy('u.foo', 'u.bar'); self::assertEquals('SELECT u.*, p.* FROM users u GROUP BY u.id, u.foo, u.bar', (string) $qb); } public function testSelectHaving() : void { $qb = new QueryBuilder($this->conn); $expr = $qb->expr(); $qb->select('u.*', 'p.*') ->from('users', 'u') ->groupBy('u.id') ->having('u.name = ?'); self::assertEquals('SELECT u.*, p.* FROM users u GROUP BY u.id HAVING u.name = ?', (string) $qb); } public function testSelectAndHaving() : void { $qb = new QueryBuilder($this->conn); $expr = $qb->expr(); $qb->select('u.*', 'p.*') ->from('users', 'u') ->groupBy('u.id') ->andHaving('u.name = ?'); self::assertEquals('SELECT u.*, p.* FROM users u GROUP BY u.id HAVING u.name = ?', (string) $qb); } public function testSelectHavingAndHaving() : void { $qb = new QueryBuilder($this->conn); $expr = $qb->expr(); $qb->select('u.*', 'p.*') ->from('users', 'u') ->groupBy('u.id') ->having('u.name = ?') ->andHaving('u.username = ?'); self::assertEquals('SELECT u.*, p.* FROM users u GROUP BY u.id HAVING (u.name = ?) AND (u.username = ?)', (string) $qb); } public function testSelectHavingOrHaving() : void { $qb = new QueryBuilder($this->conn); $expr = $qb->expr(); $qb->select('u.*', 'p.*') ->from('users', 'u') ->groupBy('u.id') ->having('u.name = ?') ->orHaving('u.username = ?'); self::assertEquals('SELECT u.*, p.* FROM users u GROUP BY u.id HAVING (u.name = ?) OR (u.username = ?)', (string) $qb); } public function testSelectOrHavingOrHaving() : void { $qb = new QueryBuilder($this->conn); $expr = $qb->expr(); $qb->select('u.*', 'p.*') ->from('users', 'u') ->groupBy('u.id') ->orHaving('u.name = ?') ->orHaving('u.username = ?'); self::assertEquals('SELECT u.*, p.* FROM users u GROUP BY u.id HAVING (u.name = ?) OR (u.username = ?)', (string) $qb); } public function testSelectHavingAndOrHaving() : void { $qb = new QueryBuilder($this->conn); $expr = $qb->expr(); $qb->select('u.*', 'p.*') ->from('users', 'u') ->groupBy('u.id') ->having('u.name = ?') ->orHaving('u.username = ?') ->andHaving('u.username = ?'); self::assertEquals('SELECT u.*, p.* FROM users u GROUP BY u.id HAVING ((u.name = ?) OR (u.username = ?)) AND (u.username = ?)', (string) $qb); } public function testSelectOrderBy() : void { $qb = new QueryBuilder($this->conn); $expr = $qb->expr(); $qb->select('u.*', 'p.*') ->from('users', 'u') ->orderBy('u.name'); self::assertEquals('SELECT u.*, p.* FROM users u ORDER BY u.name ASC', (string) $qb); } public function testSelectAddOrderBy() : void { $qb = new QueryBuilder($this->conn); $expr = $qb->expr(); $qb->select('u.*', 'p.*') ->from('users', 'u') ->orderBy('u.name') ->addOrderBy('u.username', 'DESC'); self::assertEquals('SELECT u.*, p.* FROM users u ORDER BY u.name ASC, u.username DESC', (string) $qb); } public function testSelectAddAddOrderBy() : void { $qb = new QueryBuilder($this->conn); $expr = $qb->expr(); $qb->select('u.*', 'p.*') ->from('users', 'u') ->addOrderBy('u.name') ->addOrderBy('u.username', 'DESC'); self::assertEquals('SELECT u.*, p.* FROM users u ORDER BY u.name ASC, u.username DESC', (string) $qb); } public function testEmptySelect() : void { $qb = new QueryBuilder($this->conn); $qb2 = $qb->select(); self::assertSame($qb, $qb2); self::assertEquals(QueryBuilder::SELECT, $qb->getType()); } public function testSelectAddSelect() : void { $qb = new QueryBuilder($this->conn); $expr = $qb->expr(); $qb->select('u.*') ->addSelect('p.*') ->from('users', 'u'); self::assertEquals('SELECT u.*, p.* FROM users u', (string) $qb); } public function testEmptyAddSelect() : void { $qb = new QueryBuilder($this->conn); $qb2 = $qb->addSelect(); self::assertSame($qb, $qb2); self::assertEquals(QueryBuilder::SELECT, $qb->getType()); } public function testSelectMultipleFrom() : void { $qb = new QueryBuilder($this->conn); $expr = $qb->expr(); $qb->select('u.*') ->addSelect('p.*') ->from('users', 'u') ->from('phonenumbers', 'p'); self::assertEquals('SELECT u.*, p.* FROM users u, phonenumbers p', (string) $qb); } public function testUpdate() : void { $qb = new QueryBuilder($this->conn); $qb->update('users', 'u') ->set('u.foo', '?') ->set('u.bar', '?'); self::assertEquals(QueryBuilder::UPDATE, $qb->getType()); self::assertEquals('UPDATE users u SET u.foo = ?, u.bar = ?', (string) $qb); } public function testUpdateWithoutAlias() : void { $qb = new QueryBuilder($this->conn); $qb->update('users') ->set('foo', '?') ->set('bar', '?'); self::assertEquals('UPDATE users SET foo = ?, bar = ?', (string) $qb); } public function testUpdateWhere() : void { $qb = new QueryBuilder($this->conn); $qb->update('users', 'u') ->set('u.foo', '?') ->where('u.foo = ?'); self::assertEquals('UPDATE users u SET u.foo = ? WHERE u.foo = ?', (string) $qb); } public function testEmptyUpdate() : void { $qb = new QueryBuilder($this->conn); $qb2 = $qb->update(); self::assertEquals(QueryBuilder::UPDATE, $qb->getType()); self::assertSame($qb2, $qb); } public function testDelete() : void { $qb = new QueryBuilder($this->conn); $qb->delete('users', 'u'); self::assertEquals(QueryBuilder::DELETE, $qb->getType()); self::assertEquals('DELETE FROM users u', (string) $qb); } public function testDeleteWithoutAlias() : void { $qb = new QueryBuilder($this->conn); $qb->delete('users'); self::assertEquals(QueryBuilder::DELETE, $qb->getType()); self::assertEquals('DELETE FROM users', (string) $qb); } public function testDeleteWhere() : void { $qb = new QueryBuilder($this->conn); $qb->delete('users', 'u') ->where('u.foo = ?'); self::assertEquals('DELETE FROM users u WHERE u.foo = ?', (string) $qb); } public function testEmptyDelete() : void { $qb = new QueryBuilder($this->conn); $qb2 = $qb->delete(); self::assertEquals(QueryBuilder::DELETE, $qb->getType()); self::assertSame($qb2, $qb); } public function testInsertValues() : void { $qb = new QueryBuilder($this->conn); $qb->insert('users') ->values( [ 'foo' => '?', 'bar' => '?', ] ); self::assertEquals(QueryBuilder::INSERT, $qb->getType()); self::assertEquals('INSERT INTO users (foo, bar) VALUES(?, ?)', (string) $qb); } public function testInsertReplaceValues() : void { $qb = new QueryBuilder($this->conn); $qb->insert('users') ->values( [ 'foo' => '?', 'bar' => '?', ] ) ->values( [ 'bar' => '?', 'foo' => '?', ] ); self::assertEquals(QueryBuilder::INSERT, $qb->getType()); self::assertEquals('INSERT INTO users (bar, foo) VALUES(?, ?)', (string) $qb); } public function testInsertSetValue() : void { $qb = new QueryBuilder($this->conn); $qb->insert('users') ->setValue('foo', 'bar') ->setValue('bar', '?') ->setValue('foo', '?'); self::assertEquals(QueryBuilder::INSERT, $qb->getType()); self::assertEquals('INSERT INTO users (foo, bar) VALUES(?, ?)', (string) $qb); } public function testInsertValuesSetValue() : void { $qb = new QueryBuilder($this->conn); $qb->insert('users') ->values( ['foo' => '?'] ) ->setValue('bar', '?'); self::assertEquals(QueryBuilder::INSERT, $qb->getType()); self::assertEquals('INSERT INTO users (foo, bar) VALUES(?, ?)', (string) $qb); } public function testEmptyInsert() : void { $qb = new QueryBuilder($this->conn); $qb2 = $qb->insert(); self::assertEquals(QueryBuilder::INSERT, $qb->getType()); self::assertSame($qb2, $qb); } public function testGetConnection() : void { $qb = new QueryBuilder($this->conn); self::assertSame($this->conn, $qb->getConnection()); } public function testGetState() : void { $qb = new QueryBuilder($this->conn); self::assertEquals(QueryBuilder::STATE_CLEAN, $qb->getState()); $qb->select('u.*')->from('users', 'u'); self::assertEquals(QueryBuilder::STATE_DIRTY, $qb->getState()); $sql1 = $qb->getSQL(); self::assertEquals(QueryBuilder::STATE_CLEAN, $qb->getState()); self::assertEquals($sql1, $qb->getSQL()); } public function testSetMaxResults() : void { $qb = new QueryBuilder($this->conn); $qb->setMaxResults(10); self::assertEquals(QueryBuilder::STATE_DIRTY, $qb->getState()); self::assertEquals(10, $qb->getMaxResults()); } public function testSetFirstResult() : void { $qb = new QueryBuilder($this->conn); $qb->setFirstResult(10); self::assertEquals(QueryBuilder::STATE_DIRTY, $qb->getState()); self::assertEquals(10, $qb->getFirstResult()); } public function testResetQueryPart() : void { $qb = new QueryBuilder($this->conn); $qb->select('u.*')->from('users', 'u')->where('u.name = ?'); self::assertEquals('SELECT u.* FROM users u WHERE u.name = ?', (string) $qb); $qb->resetQueryPart('where'); self::assertEquals('SELECT u.* FROM users u', (string) $qb); } public function testResetQueryParts() : void { $qb = new QueryBuilder($this->conn); $qb->select('u.*')->from('users', 'u')->where('u.name = ?')->orderBy('u.name'); self::assertEquals('SELECT u.* FROM users u WHERE u.name = ? ORDER BY u.name ASC', (string) $qb); $qb->resetQueryParts(['where', 'orderBy']); self::assertEquals('SELECT u.* FROM users u', (string) $qb); } public function testCreateNamedParameter() : void { $qb = new QueryBuilder($this->conn); $qb->select('u.*')->from('users', 'u')->where( $qb->expr()->eq('u.name', $qb->createNamedParameter(10, ParameterType::INTEGER)) ); self::assertEquals('SELECT u.* FROM users u WHERE u.name = :dcValue1', (string) $qb); self::assertEquals(10, $qb->getParameter('dcValue1')); self::assertEquals(ParameterType::INTEGER, $qb->getParameterType('dcValue1')); } public function testCreateNamedParameterCustomPlaceholder() : void { $qb = new QueryBuilder($this->conn); $qb->select('u.*')->from('users', 'u')->where( $qb->expr()->eq('u.name', $qb->createNamedParameter(10, ParameterType::INTEGER, ':test')) ); self::assertEquals('SELECT u.* FROM users u WHERE u.name = :test', (string) $qb); self::assertEquals(10, $qb->getParameter('test')); self::assertEquals(ParameterType::INTEGER, $qb->getParameterType('test')); } public function testCreatePositionalParameter() : void { $qb = new QueryBuilder($this->conn); $qb->select('u.*')->from('users', 'u')->where( $qb->expr()->eq('u.name', $qb->createPositionalParameter(10, ParameterType::INTEGER)) ); self::assertEquals('SELECT u.* FROM users u WHERE u.name = ?', (string) $qb); self::assertEquals(10, $qb->getParameter(1)); self::assertEquals(ParameterType::INTEGER, $qb->getParameterType(1)); } /** * @group DBAL-172 */ public function testReferenceJoinFromJoin() : void { $qb = new QueryBuilder($this->conn); $qb->select('COUNT(DISTINCT news.id)') ->from('cb_newspages', 'news') ->innerJoin('news', 'nodeversion', 'nv', 'nv.refId = news.id AND nv.refEntityname=\'News\'') ->innerJoin('invalid', 'nodetranslation', 'nt', 'nv.nodetranslation = nt.id') ->innerJoin('nt', 'node', 'n', 'nt.node = n.id') ->where('nt.lang = :lang AND n.deleted != 1'); $this->expectException(QueryException::class); $this->expectExceptionMessage("The given alias 'invalid' is not part of any FROM or JOIN clause table. The currently registered aliases are: news, nv."); self::assertEquals('', $qb->getSQL()); } /** * @group DBAL-172 */ public function testSelectFromMasterWithWhereOnJoinedTables() : void { $qb = new QueryBuilder($this->conn); $qb->select('COUNT(DISTINCT news.id)') ->from('newspages', 'news') ->innerJoin('news', 'nodeversion', 'nv', "nv.refId = news.id AND nv.refEntityname='Entity\\News'") ->innerJoin('nv', 'nodetranslation', 'nt', 'nv.nodetranslation = nt.id') ->innerJoin('nt', 'node', 'n', 'nt.node = n.id') ->where('nt.lang = ?') ->andWhere('n.deleted = 0'); self::assertEquals("SELECT COUNT(DISTINCT news.id) FROM newspages news INNER JOIN nodeversion nv ON nv.refId = news.id AND nv.refEntityname='Entity\\News' INNER JOIN nodetranslation nt ON nv.nodetranslation = nt.id INNER JOIN node n ON nt.node = n.id WHERE (nt.lang = ?) AND (n.deleted = 0)", $qb->getSQL()); } /** * @group DBAL-442 */ public function testSelectWithMultipleFromAndJoins() : void { $qb = new QueryBuilder($this->conn); $qb->select('DISTINCT u.id') ->from('users', 'u') ->from('articles', 'a') ->innerJoin('u', 'permissions', 'p', 'p.user_id = u.id') ->innerJoin('a', 'comments', 'c', 'c.article_id = a.id') ->where('u.id = a.user_id') ->andWhere('p.read = 1'); self::assertEquals('SELECT DISTINCT u.id FROM users u INNER JOIN permissions p ON p.user_id = u.id, articles a INNER JOIN comments c ON c.article_id = a.id WHERE (u.id = a.user_id) AND (p.read = 1)', $qb->getSQL()); } /** * @group DBAL-774 */ public function testSelectWithJoinsWithMultipleOnConditionsParseOrder() : void { $qb = new QueryBuilder($this->conn); $qb->select('a.id') ->from('table_a', 'a') ->join('a', 'table_b', 'b', 'a.fk_b = b.id') ->join('b', 'table_c', 'c', 'c.fk_b = b.id AND b.language = ?') ->join('a', 'table_d', 'd', 'a.fk_d = d.id') ->join('c', 'table_e', 'e', 'e.fk_c = c.id AND e.fk_d = d.id'); self::assertEquals( 'SELECT a.id ' . 'FROM table_a a ' . 'INNER JOIN table_b b ON a.fk_b = b.id ' . 'INNER JOIN table_d d ON a.fk_d = d.id ' . 'INNER JOIN table_c c ON c.fk_b = b.id AND b.language = ? ' . 'INNER JOIN table_e e ON e.fk_c = c.id AND e.fk_d = d.id', (string) $qb ); } /** * @group DBAL-774 */ public function testSelectWithMultipleFromsAndJoinsWithMultipleOnConditionsParseOrder() : void { $qb = new QueryBuilder($this->conn); $qb->select('a.id') ->from('table_a', 'a') ->from('table_f', 'f') ->join('a', 'table_b', 'b', 'a.fk_b = b.id') ->join('b', 'table_c', 'c', 'c.fk_b = b.id AND b.language = ?') ->join('a', 'table_d', 'd', 'a.fk_d = d.id') ->join('c', 'table_e', 'e', 'e.fk_c = c.id AND e.fk_d = d.id') ->join('f', 'table_g', 'g', 'f.fk_g = g.id'); self::assertEquals( 'SELECT a.id ' . 'FROM table_a a ' . 'INNER JOIN table_b b ON a.fk_b = b.id ' . 'INNER JOIN table_d d ON a.fk_d = d.id ' . 'INNER JOIN table_c c ON c.fk_b = b.id AND b.language = ? ' . 'INNER JOIN table_e e ON e.fk_c = c.id AND e.fk_d = d.id, ' . 'table_f f ' . 'INNER JOIN table_g g ON f.fk_g = g.id', (string) $qb ); } public function testClone() : void { $qb = new QueryBuilder($this->conn); $qb->select('u.id') ->from('users', 'u') ->where('u.id = :test'); $qb->setParameter(':test', (object) 1); $qb_clone = clone $qb; self::assertEquals((string) $qb, (string) $qb_clone); $qb->andWhere('u.id = 1'); self::assertNotSame($qb->getQueryParts(), $qb_clone->getQueryParts()); self::assertNotSame($qb->getParameters(), $qb_clone->getParameters()); } public function testSimpleSelectWithoutTableAlias() : void { $qb = new QueryBuilder($this->conn); $qb->select('id') ->from('users'); self::assertEquals('SELECT id FROM users', (string) $qb); } public function testSelectWithSimpleWhereWithoutTableAlias() : void { $qb = new QueryBuilder($this->conn); $qb->select('id', 'name') ->from('users') ->where('awesome=9001'); self::assertEquals('SELECT id, name FROM users WHERE awesome=9001', (string) $qb); } public function testComplexSelectWithoutTableAliases() : void { $qb = new QueryBuilder($this->conn); $qb->select('DISTINCT users.id') ->from('users') ->from('articles') ->innerJoin('users', 'permissions', 'p', 'p.user_id = users.id') ->innerJoin('articles', 'comments', 'c', 'c.article_id = articles.id') ->where('users.id = articles.user_id') ->andWhere('p.read = 1'); self::assertEquals('SELECT DISTINCT users.id FROM users INNER JOIN permissions p ON p.user_id = users.id, articles INNER JOIN comments c ON c.article_id = articles.id WHERE (users.id = articles.user_id) AND (p.read = 1)', $qb->getSQL()); } public function testComplexSelectWithSomeTableAliases() : void { $qb = new QueryBuilder($this->conn); $qb->select('u.id') ->from('users', 'u') ->from('articles') ->innerJoin('u', 'permissions', 'p', 'p.user_id = u.id') ->innerJoin('articles', 'comments', 'c', 'c.article_id = articles.id'); self::assertEquals('SELECT u.id FROM users u INNER JOIN permissions p ON p.user_id = u.id, articles INNER JOIN comments c ON c.article_id = articles.id', $qb->getSQL()); } public function testSelectAllFromTableWithoutTableAlias() : void { $qb = new QueryBuilder($this->conn); $qb->select('users.*') ->from('users'); self::assertEquals('SELECT users.* FROM users', (string) $qb); } public function testSelectAllWithoutTableAlias() : void { $qb = new QueryBuilder($this->conn); $qb->select('*') ->from('users'); self::assertEquals('SELECT * FROM users', (string) $qb); } /** * @group DBAL-959 */ public function testGetParameterType() : void { $qb = new QueryBuilder($this->conn); $qb->select('*')->from('users'); self::assertNull($qb->getParameterType('name')); $qb->where('name = :name'); $qb->setParameter('name', 'foo'); self::assertNull($qb->getParameterType('name')); $qb->setParameter('name', 'foo', ParameterType::STRING); self::assertSame(ParameterType::STRING, $qb->getParameterType('name')); } /** * @group DBAL-959 */ public function testGetParameterTypes() : void { $qb = new QueryBuilder($this->conn); $qb->select('*')->from('users'); self::assertSame([], $qb->getParameterTypes()); $qb->where('name = :name'); $qb->setParameter('name', 'foo'); self::assertSame([], $qb->getParameterTypes()); $qb->setParameter('name', 'foo', ParameterType::STRING); $qb->where('is_active = :isActive'); $qb->setParameter('isActive', true, ParameterType::BOOLEAN); self::assertSame([ 'name' => ParameterType::STRING, 'isActive' => ParameterType::BOOLEAN, ], $qb->getParameterTypes()); } /** * @group DBAL-1137 */ public function testJoinWithNonUniqueAliasThrowsException() : void { $qb = new QueryBuilder($this->conn); $qb->select('a.id') ->from('table_a', 'a') ->join('a', 'table_b', 'a', 'a.fk_b = a.id'); $this->expectException(QueryException::class); $this->expectExceptionMessage("The given alias 'a' is not unique in FROM and JOIN clause table. The currently registered aliases are: a."); $qb->getSQL(); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/SQLParserUtilsTest.php000066400000000000000000000572021360544566000260310ustar00rootroot00000000000000 42, 0 => 30]], // explicit keys // named ['SELECT :foo FROM :bar', false, [7 => 'foo', 17 => 'bar']], ['SELECT * FROM Foo WHERE bar IN (:name1, :name2)', false, [32 => 'name1', 40 => 'name2']], ['SELECT ":foo" FROM Foo WHERE bar IN (:name1, :name2)', false, [37 => 'name1', 45 => 'name2']], ["SELECT ':foo' FROM Foo WHERE bar IN (:name1, :name2)", false, [37 => 'name1', 45 => 'name2']], ['SELECT :foo_id', false, [7 => 'foo_id']], // Ticket DBAL-231 ['SELECT @rank := 1', false, []], // Ticket DBAL-398 ['SELECT @rank := 1 AS rank, :foo AS foo FROM :bar', false, [27 => 'foo', 44 => 'bar']], // Ticket DBAL-398 ['SELECT * FROM Foo WHERE bar > :start_date AND baz > :start_date', false, [30 => 'start_date', 52 => 'start_date']], // Ticket GH-113 ['SELECT foo::date as date FROM Foo WHERE bar > :start_date AND baz > :start_date', false, [46 => 'start_date', 68 => 'start_date']], // Ticket GH-259 ['SELECT `d.ns:col_name` FROM my_table d WHERE `d.date` >= :param1', false, [57 => 'param1']], // Ticket DBAL-552 ['SELECT [d.ns:col_name] FROM my_table d WHERE [d.date] >= :param1', false, [57 => 'param1']], // Ticket DBAL-552 ['SELECT * FROM foo WHERE jsonb_exists_any(foo.bar, ARRAY[:foo])', false, [56 => 'foo']], // Ticket GH-2295 ['SELECT * FROM foo WHERE jsonb_exists_any(foo.bar, array[:foo])', false, [56 => 'foo']], ['SELECT table.field1, ARRAY[\'3\'] FROM schema.table table WHERE table.f1 = :foo AND ARRAY[\'3\']', false, [73 => 'foo']], ['SELECT table.field1, ARRAY[\'3\']::integer[] FROM schema.table table WHERE table.f1 = :foo AND ARRAY[\'3\']::integer[]', false, [84 => 'foo']], ['SELECT table.field1, ARRAY[:foo] FROM schema.table table WHERE table.f1 = :bar AND ARRAY[\'3\']', false, [27 => 'foo', 74 => 'bar']], ['SELECT table.field1, ARRAY[:foo]::integer[] FROM schema.table table WHERE table.f1 = :bar AND ARRAY[\'3\']::integer[]', false, [27 => 'foo', 85 => 'bar']], [ <<<'SQLDATA' SELECT * FROM foo WHERE bar = ':not_a_param1 ''":not_a_param2"''' OR bar=:a_param1 OR bar=:a_param2||':not_a_param3' OR bar=':not_a_param4 '':not_a_param5'' :not_a_param6' OR bar='' OR bar=:a_param3 SQLDATA , false, [ 74 => 'a_param1', 91 => 'a_param2', 190 => 'a_param3', ], ], ["SELECT data.age AS age, data.id AS id, data.name AS name, data.id AS id FROM test_data data WHERE (data.description LIKE :condition_0 ESCAPE '\\\\') AND (data.description LIKE :condition_1 ESCAPE '\\\\') ORDER BY id ASC", false, [121 => 'condition_0', 174 => 'condition_1']], ['SELECT data.age AS age, data.id AS id, data.name AS name, data.id AS id FROM test_data data WHERE (data.description LIKE :condition_0 ESCAPE "\\\\") AND (data.description LIKE :condition_1 ESCAPE "\\\\") ORDER BY id ASC', false, [121 => 'condition_0', 174 => 'condition_1']], ['SELECT data.age AS age, data.id AS id, data.name AS name, data.id AS id FROM test_data data WHERE (data.description LIKE :condition_0 ESCAPE "\\\\") AND (data.description LIKE :condition_1 ESCAPE \'\\\\\') ORDER BY id ASC', false, [121 => 'condition_0', 174 => 'condition_1']], ['SELECT data.age AS age, data.id AS id, data.name AS name, data.id AS id FROM test_data data WHERE (data.description LIKE :condition_0 ESCAPE `\\\\`) AND (data.description LIKE :condition_1 ESCAPE `\\\\`) ORDER BY id ASC', false, [121 => 'condition_0', 174 => 'condition_1']], ['SELECT data.age AS age, data.id AS id, data.name AS name, data.id AS id FROM test_data data WHERE (data.description LIKE :condition_0 ESCAPE \'\\\\\') AND (data.description LIKE :condition_1 ESCAPE `\\\\`) ORDER BY id ASC', false, [121 => 'condition_0', 174 => 'condition_1']], ]; } /** * @param int[] $expectedParamPos * * @dataProvider dataGetPlaceholderPositions */ public function testGetPlaceholderPositions(string $query, bool $isPositional, array $expectedParamPos) : void { $actualParamPos = SQLParserUtils::getPlaceholderPositions($query, $isPositional); self::assertEquals($expectedParamPos, $actualParamPos); } /** * @return mixed[][] */ public static function dataExpandListParameters() : iterable { return [ // Positional: Very simple with one needle [ 'SELECT * FROM Foo WHERE foo IN (?)', [[1, 2, 3]], [Connection::PARAM_INT_ARRAY], 'SELECT * FROM Foo WHERE foo IN (?, ?, ?)', [1, 2, 3], [ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER], ], // Positional: One non-list before d one after list-needle [ 'SELECT * FROM Foo WHERE foo = ? AND bar IN (?)', ['string', [1, 2, 3]], [ParameterType::STRING, Connection::PARAM_INT_ARRAY], 'SELECT * FROM Foo WHERE foo = ? AND bar IN (?, ?, ?)', ['string', 1, 2, 3], [ParameterType::STRING, ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER], ], // Positional: One non-list after list-needle [ 'SELECT * FROM Foo WHERE bar IN (?) AND baz = ?', [[1, 2, 3], 'foo'], [Connection::PARAM_INT_ARRAY, ParameterType::STRING], 'SELECT * FROM Foo WHERE bar IN (?, ?, ?) AND baz = ?', [1, 2, 3, 'foo'], [ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::STRING], ], // Positional: One non-list before and one after list-needle [ 'SELECT * FROM Foo WHERE foo = ? AND bar IN (?) AND baz = ?', [1, [1, 2, 3], 4], [ParameterType::INTEGER, Connection::PARAM_INT_ARRAY, ParameterType::INTEGER], 'SELECT * FROM Foo WHERE foo = ? AND bar IN (?, ?, ?) AND baz = ?', [1, 1, 2, 3, 4], [ ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER, ], ], // Positional: Two lists [ 'SELECT * FROM Foo WHERE foo IN (?, ?)', [[1, 2, 3], [4, 5]], [Connection::PARAM_INT_ARRAY, Connection::PARAM_INT_ARRAY], 'SELECT * FROM Foo WHERE foo IN (?, ?, ?, ?, ?)', [1, 2, 3, 4, 5], [ ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER, ], ], // Positional: Empty "integer" array DDC-1978 [ 'SELECT * FROM Foo WHERE foo IN (?)', [[]], [Connection::PARAM_INT_ARRAY], 'SELECT * FROM Foo WHERE foo IN (NULL)', [], [], ], // Positional: Empty "str" array DDC-1978 [ 'SELECT * FROM Foo WHERE foo IN (?)', [[]], [Connection::PARAM_STR_ARRAY], 'SELECT * FROM Foo WHERE foo IN (NULL)', [], [], ], // Positional: explicit keys for params and types [ 'SELECT * FROM Foo WHERE foo = ? AND bar = ? AND baz = ?', [1 => 'bar', 2 => 'baz', 0 => 1], [2 => ParameterType::STRING, 1 => ParameterType::STRING], 'SELECT * FROM Foo WHERE foo = ? AND bar = ? AND baz = ?', [1 => 'bar', 0 => 1, 2 => 'baz'], [1 => ParameterType::STRING, 2 => ParameterType::STRING], ], // Positional: explicit keys for array params and array types [ 'SELECT * FROM Foo WHERE foo IN (?) AND bar IN (?) AND baz = ?', [1 => ['bar1', 'bar2'], 2 => true, 0 => [1, 2, 3]], [2 => ParameterType::BOOLEAN, 1 => Connection::PARAM_STR_ARRAY, 0 => Connection::PARAM_INT_ARRAY], 'SELECT * FROM Foo WHERE foo IN (?, ?, ?) AND bar IN (?, ?) AND baz = ?', [1, 2, 3, 'bar1', 'bar2', true], [ ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::STRING, ParameterType::STRING, ParameterType::BOOLEAN, ], ], // Positional starts from 1: One non-list before and one after list-needle [ 'SELECT * FROM Foo WHERE foo = ? AND bar IN (?) AND baz = ? AND foo IN (?)', [1 => 1, 2 => [1, 2, 3], 3 => 4, 4 => [5, 6]], [ 1 => ParameterType::INTEGER, 2 => Connection::PARAM_INT_ARRAY, 3 => ParameterType::INTEGER, 4 => Connection::PARAM_INT_ARRAY, ], 'SELECT * FROM Foo WHERE foo = ? AND bar IN (?, ?, ?) AND baz = ? AND foo IN (?, ?)', [1, 1, 2, 3, 4, 5, 6], [ ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER, ], ], // Named parameters : Very simple with param int [ 'SELECT * FROM Foo WHERE foo = :foo', ['foo' => 1], ['foo' => ParameterType::INTEGER], 'SELECT * FROM Foo WHERE foo = ?', [1], [ParameterType::INTEGER], ], // Named parameters : Very simple with param int and string [ 'SELECT * FROM Foo WHERE foo = :foo AND bar = :bar', ['bar' => 'Some String','foo' => 1], ['foo' => ParameterType::INTEGER, 'bar' => ParameterType::STRING], 'SELECT * FROM Foo WHERE foo = ? AND bar = ?', [1,'Some String'], [ParameterType::INTEGER, ParameterType::STRING], ], // Named parameters : Very simple with one needle [ 'SELECT * FROM Foo WHERE foo IN (:foo)', ['foo' => [1, 2, 3]], ['foo' => Connection::PARAM_INT_ARRAY], 'SELECT * FROM Foo WHERE foo IN (?, ?, ?)', [1, 2, 3], [ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER], ], // Named parameters: One non-list before d one after list-needle [ 'SELECT * FROM Foo WHERE foo = :foo AND bar IN (:bar)', ['foo' => 'string', 'bar' => [1, 2, 3]], ['foo' => ParameterType::STRING, 'bar' => Connection::PARAM_INT_ARRAY], 'SELECT * FROM Foo WHERE foo = ? AND bar IN (?, ?, ?)', ['string', 1, 2, 3], [ParameterType::STRING, ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER], ], // Named parameters: One non-list after list-needle [ 'SELECT * FROM Foo WHERE bar IN (:bar) AND baz = :baz', ['bar' => [1, 2, 3], 'baz' => 'foo'], ['bar' => Connection::PARAM_INT_ARRAY, 'baz' => ParameterType::STRING], 'SELECT * FROM Foo WHERE bar IN (?, ?, ?) AND baz = ?', [1, 2, 3, 'foo'], [ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::STRING], ], // Named parameters: One non-list before and one after list-needle [ 'SELECT * FROM Foo WHERE foo = :foo AND bar IN (:bar) AND baz = :baz', ['bar' => [1, 2, 3],'foo' => 1, 'baz' => 4], ['bar' => Connection::PARAM_INT_ARRAY, 'foo' => ParameterType::INTEGER, 'baz' => ParameterType::INTEGER], 'SELECT * FROM Foo WHERE foo = ? AND bar IN (?, ?, ?) AND baz = ?', [1, 1, 2, 3, 4], [ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER], ], // Named parameters: Two lists [ 'SELECT * FROM Foo WHERE foo IN (:a, :b)', ['b' => [4, 5],'a' => [1, 2, 3]], ['a' => Connection::PARAM_INT_ARRAY, 'b' => Connection::PARAM_INT_ARRAY], 'SELECT * FROM Foo WHERE foo IN (?, ?, ?, ?, ?)', [1, 2, 3, 4, 5], [ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER], ], // Named parameters : With the same name arg type string [ 'SELECT * FROM Foo WHERE foo <> :arg AND bar = :arg', ['arg' => 'Some String'], ['arg' => ParameterType::STRING], 'SELECT * FROM Foo WHERE foo <> ? AND bar = ?', ['Some String','Some String'], [ParameterType::STRING,ParameterType::STRING], ], // Named parameters : With the same name arg [ 'SELECT * FROM Foo WHERE foo IN (:arg) AND NOT bar IN (:arg)', ['arg' => [1, 2, 3]], ['arg' => Connection::PARAM_INT_ARRAY], 'SELECT * FROM Foo WHERE foo IN (?, ?, ?) AND NOT bar IN (?, ?, ?)', [1, 2, 3, 1, 2, 3], [ParameterType::INTEGER,ParameterType::INTEGER, ParameterType::INTEGER,ParameterType::INTEGER,ParameterType::INTEGER, ParameterType::INTEGER], ], // Named parameters : Same name, other name in between DBAL-299 [ 'SELECT * FROM Foo WHERE (:foo = 2) AND (:bar = 3) AND (:foo = 2)', ['foo' => 2,'bar' => 3], ['foo' => ParameterType::INTEGER,'bar' => ParameterType::INTEGER], 'SELECT * FROM Foo WHERE (? = 2) AND (? = 3) AND (? = 2)', [2, 3, 2], [ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::INTEGER], ], // Named parameters : Empty "integer" array DDC-1978 [ 'SELECT * FROM Foo WHERE foo IN (:foo)', ['foo' => []], ['foo' => Connection::PARAM_INT_ARRAY], 'SELECT * FROM Foo WHERE foo IN (NULL)', [], [], ], // Named parameters : Two empty "str" array DDC-1978 [ 'SELECT * FROM Foo WHERE foo IN (:foo) OR bar IN (:bar)', ['foo' => [], 'bar' => []], ['foo' => Connection::PARAM_STR_ARRAY, 'bar' => Connection::PARAM_STR_ARRAY], 'SELECT * FROM Foo WHERE foo IN (NULL) OR bar IN (NULL)', [], [], ], [ 'SELECT * FROM Foo WHERE foo IN (:foo) OR bar = :bar OR baz = :baz', ['foo' => [1, 2], 'bar' => 'bar', 'baz' => 'baz'], ['foo' => Connection::PARAM_INT_ARRAY, 'baz' => 'string'], 'SELECT * FROM Foo WHERE foo IN (?, ?) OR bar = ? OR baz = ?', [1, 2, 'bar', 'baz'], [ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::STRING, 'string'], ], [ 'SELECT * FROM Foo WHERE foo IN (:foo) OR bar = :bar', ['foo' => [1, 2], 'bar' => 'bar'], ['foo' => Connection::PARAM_INT_ARRAY], 'SELECT * FROM Foo WHERE foo IN (?, ?) OR bar = ?', [1, 2, 'bar'], [ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::STRING], ], // Params/types with colons [ 'SELECT * FROM Foo WHERE foo = :foo OR bar = :bar', [':foo' => 'foo', ':bar' => 'bar'], [':foo' => ParameterType::INTEGER], 'SELECT * FROM Foo WHERE foo = ? OR bar = ?', ['foo', 'bar'], [ParameterType::INTEGER, ParameterType::STRING], ], [ 'SELECT * FROM Foo WHERE foo = :foo OR bar = :bar', [':foo' => 'foo', ':bar' => 'bar'], [':foo' => ParameterType::INTEGER, 'bar' => ParameterType::INTEGER], 'SELECT * FROM Foo WHERE foo = ? OR bar = ?', ['foo', 'bar'], [ParameterType::INTEGER, ParameterType::INTEGER], ], [ 'SELECT * FROM Foo WHERE foo IN (:foo) OR bar = :bar', [':foo' => [1, 2], ':bar' => 'bar'], ['foo' => Connection::PARAM_INT_ARRAY], 'SELECT * FROM Foo WHERE foo IN (?, ?) OR bar = ?', [1, 2, 'bar'], [ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::STRING], ], [ 'SELECT * FROM Foo WHERE foo IN (:foo) OR bar = :bar', ['foo' => [1, 2], 'bar' => 'bar'], [':foo' => Connection::PARAM_INT_ARRAY], 'SELECT * FROM Foo WHERE foo IN (?, ?) OR bar = ?', [1, 2, 'bar'], [ParameterType::INTEGER, ParameterType::INTEGER, ParameterType::STRING], ], // DBAL-522 - null valued parameters are not considered [ 'INSERT INTO Foo (foo, bar) values (:foo, :bar)', ['foo' => 1, 'bar' => null], [':foo' => ParameterType::INTEGER, ':bar' => ParameterType::NULL], 'INSERT INTO Foo (foo, bar) values (?, ?)', [1, null], [ParameterType::INTEGER, ParameterType::NULL], ], [ 'INSERT INTO Foo (foo, bar) values (?, ?)', [1, null], [ParameterType::INTEGER, ParameterType::NULL], 'INSERT INTO Foo (foo, bar) values (?, ?)', [1, null], [ParameterType::INTEGER, ParameterType::NULL], ], // DBAL-1205 - Escaped single quotes SQL- and C-Style [ "SELECT * FROM Foo WHERE foo = :foo||''':not_a_param''\\'' OR bar = ''':not_a_param''\\'':bar", [':foo' => 1, ':bar' => 2], [':foo' => ParameterType::INTEGER, 'bar' => ParameterType::INTEGER], 'SELECT * FROM Foo WHERE foo = ?||\'\'\':not_a_param\'\'\\\'\' OR bar = \'\'\':not_a_param\'\'\\\'\'?', [1, 2], [ParameterType::INTEGER, ParameterType::INTEGER], ], ]; } /** * @param mixed[] $params * @param mixed[] $types * @param mixed[] $expectedParams * @param mixed[] $expectedTypes * * @dataProvider dataExpandListParameters */ public function testExpandListParameters( string $query, array $params, array $types, string $expectedQuery, array $expectedParams, array $expectedTypes ) : void { [$query, $params, $types] = SQLParserUtils::expandListParameters($query, $params, $types); self::assertEquals($expectedQuery, $query, 'Query was not rewritten correctly.'); self::assertEquals($expectedParams, $params, 'Params dont match'); self::assertEquals($expectedTypes, $types, 'Types dont match'); } /** * @return mixed[][] */ public static function dataQueryWithMissingParameters() : iterable { return [ [ 'SELECT * FROM foo WHERE bar = :param', ['other' => 'val'], [], ], [ 'SELECT * FROM foo WHERE bar = :param', [], [], ], [ 'SELECT * FROM foo WHERE bar = :param', [], ['param' => Connection::PARAM_INT_ARRAY], ], [ 'SELECT * FROM foo WHERE bar = :param', [], [':param' => Connection::PARAM_INT_ARRAY], ], [ 'SELECT * FROM foo WHERE bar = :param', [], ['bar' => Connection::PARAM_INT_ARRAY], ], [ 'SELECT * FROM foo WHERE bar = :param', ['bar' => 'value'], ['bar' => Connection::PARAM_INT_ARRAY], ], ]; } /** * @param mixed[] $params * @param mixed[] $types * * @dataProvider dataQueryWithMissingParameters */ public function testExceptionIsThrownForMissingParam(string $query, array $params, array $types = []) : void { $this->expectException(SQLParserUtilsException::class); $this->expectExceptionMessage('Value for :param not found in params array. Params array key should be "param"'); SQLParserUtils::expandListParameters($query, $params, $types); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Schema/000077500000000000000000000000001360544566000230155ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Schema/ColumnDiffTest.php000066400000000000000000000016551360544566000264230ustar00rootroot00000000000000getOldColumnName()->isQuoted()); $columnDiff = new ColumnDiff('"foo"', $toColumn, [], $fromColumn); self::assertTrue($columnDiff->getOldColumnName()->isQuoted()); $columnDiff = new ColumnDiff('foo', $toColumn, [], $fromColumn); self::assertTrue($columnDiff->getOldColumnName()->isQuoted()); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Schema/ColumnTest.php000066400000000000000000000124171360544566000256300ustar00rootroot00000000000000createColumn(); self::assertEquals('foo', $column->getName()); self::assertSame(Type::getType('string'), $column->getType()); self::assertEquals(200, $column->getLength()); self::assertEquals(5, $column->getPrecision()); self::assertEquals(2, $column->getScale()); self::assertTrue($column->getUnsigned()); self::assertFalse($column->getNotNull()); self::assertTrue($column->getFixed()); self::assertEquals('baz', $column->getDefault()); self::assertEquals(['foo' => 'bar'], $column->getPlatformOptions()); self::assertTrue($column->hasPlatformOption('foo')); self::assertEquals('bar', $column->getPlatformOption('foo')); self::assertFalse($column->hasPlatformOption('bar')); self::assertEquals(['bar' => 'baz'], $column->getCustomSchemaOptions()); self::assertTrue($column->hasCustomSchemaOption('bar')); self::assertEquals('baz', $column->getCustomSchemaOption('bar')); self::assertFalse($column->hasCustomSchemaOption('foo')); } public function testToArray() : void { $expected = [ 'name' => 'foo', 'type' => Type::getType('string'), 'default' => 'baz', 'notnull' => false, 'length' => 200, 'precision' => 5, 'scale' => 2, 'fixed' => true, 'unsigned' => true, 'autoincrement' => false, 'columnDefinition' => null, 'comment' => null, 'foo' => 'bar', 'bar' => 'baz', ]; self::assertEquals($expected, $this->createColumn()->toArray()); } /** * @group legacy * @expectedDeprecation The "unknown_option" column option is not supported, setting it is deprecated and will cause an error in Doctrine DBAL 3.0 */ public function testSettingUnknownOptionIsStillSupported() : void { $this->expectNotToPerformAssertions(); new Column('foo', $this->createMock(Type::class), ['unknown_option' => 'bar']); } /** * @group legacy * @expectedDeprecation The "unknown_option" column option is not supported, setting it is deprecated and will cause an error in Doctrine DBAL 3.0 */ public function testOptionsShouldNotBeIgnored() : void { $col1 = new Column('bar', Type::getType(Types::INTEGER), ['unknown_option' => 'bar', 'notnull' => true]); self::assertTrue($col1->getNotnull()); $col2 = new Column('bar', Type::getType(Types::INTEGER), ['unknown_option' => 'bar', 'notnull' => false]); self::assertFalse($col2->getNotnull()); } public function createColumn() : Column { $options = [ 'length' => 200, 'precision' => 5, 'scale' => 2, 'unsigned' => true, 'notnull' => false, 'fixed' => true, 'default' => 'baz', 'platformOptions' => ['foo' => 'bar'], 'customSchemaOptions' => ['bar' => 'baz'], ]; $string = Type::getType('string'); return new Column('foo', $string, $options); } /** * @group DBAL-64 * @group DBAL-830 */ public function testQuotedColumnName() : void { $string = Type::getType('string'); $column = new Column('`bar`', $string, []); $mysqlPlatform = new MySqlPlatform(); $sqlitePlatform = new SqlitePlatform(); self::assertEquals('bar', $column->getName()); self::assertEquals('`bar`', $column->getQuotedName($mysqlPlatform)); self::assertEquals('"bar"', $column->getQuotedName($sqlitePlatform)); $column = new Column('[bar]', $string); $sqlServerPlatform = new SQLServerPlatform(); self::assertEquals('bar', $column->getName()); self::assertEquals('[bar]', $column->getQuotedName($sqlServerPlatform)); } /** * @dataProvider getIsQuoted * @group DBAL-830 */ public function testIsQuoted(string $columnName, bool $isQuoted) : void { $type = Type::getType('string'); $column = new Column($columnName, $type); self::assertSame($isQuoted, $column->isQuoted()); } /** * @return mixed[][] */ public static function getIsQuoted() : iterable { return [ ['bar', false], ['`bar`', true], ['"bar"', true], ['[bar]', true], ]; } /** * @group DBAL-42 */ public function testColumnComment() : void { $column = new Column('bar', Type::getType('string')); self::assertNull($column->getComment()); $column->setComment('foo'); self::assertEquals('foo', $column->getComment()); $columnArray = $column->toArray(); self::assertArrayHasKey('comment', $columnArray); self::assertEquals('foo', $columnArray['comment']); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Schema/ComparatorTest.php000066400000000000000000001330251360544566000265010ustar00rootroot00000000000000 new Table( 'bugdb', [ 'integerfield1' => new Column('integerfield1', Type::getType('integer')), ] ), ]); $schema2 = new Schema([ 'bugdb' => new Table( 'bugdb', [ 'integerfield1' => new Column('integerfield1', Type::getType('integer')), ] ), ]); $expected = new SchemaDiff(); $expected->fromSchema = $schema1; self::assertEquals($expected, Comparator::compareSchemas($schema1, $schema2)); } public function testCompareSame2() : void { $schema1 = new Schema([ 'bugdb' => new Table( 'bugdb', [ 'integerfield1' => new Column('integerfield1', Type::getType('integer')), 'integerfield2' => new Column('integerfield2', Type::getType('integer')), ] ), ]); $schema2 = new Schema([ 'bugdb' => new Table( 'bugdb', [ 'integerfield2' => new Column('integerfield2', Type::getType('integer')), 'integerfield1' => new Column('integerfield1', Type::getType('integer')), ] ), ]); $expected = new SchemaDiff(); $expected->fromSchema = $schema1; self::assertEquals($expected, Comparator::compareSchemas($schema1, $schema2)); } public function testCompareMissingTable() : void { $schemaConfig = new SchemaConfig(); $table = new Table('bugdb', ['integerfield1' => new Column('integerfield1', Type::getType('integer'))]); $table->setSchemaConfig($schemaConfig); $schema1 = new Schema([$table], [], $schemaConfig); $schema2 = new Schema([], [], $schemaConfig); $expected = new SchemaDiff([], [], ['bugdb' => $table], $schema1); self::assertEquals($expected, Comparator::compareSchemas($schema1, $schema2)); } public function testCompareNewTable() : void { $schemaConfig = new SchemaConfig(); $table = new Table('bugdb', ['integerfield1' => new Column('integerfield1', Type::getType('integer'))]); $table->setSchemaConfig($schemaConfig); $schema1 = new Schema([], [], $schemaConfig); $schema2 = new Schema([$table], [], $schemaConfig); $expected = new SchemaDiff(['bugdb' => $table], [], [], $schema1); self::assertEquals($expected, Comparator::compareSchemas($schema1, $schema2)); } public function testCompareOnlyAutoincrementChanged() : void { $column1 = new Column('foo', Type::getType('integer'), ['autoincrement' => true]); $column2 = new Column('foo', Type::getType('integer'), ['autoincrement' => false]); $comparator = new Comparator(); $changedProperties = $comparator->diffColumn($column1, $column2); self::assertEquals(['autoincrement'], $changedProperties); } public function testCompareMissingField() : void { $missingColumn = new Column('integerfield1', Type::getType('integer')); $schema1 = new Schema([ 'bugdb' => new Table( 'bugdb', [ 'integerfield1' => $missingColumn, 'integerfield2' => new Column('integerfield2', Type::getType('integer')), ] ), ]); $schema2 = new Schema([ 'bugdb' => new Table( 'bugdb', [ 'integerfield2' => new Column('integerfield2', Type::getType('integer')), ] ), ]); $expected = new SchemaDiff( [], [ 'bugdb' => new TableDiff( 'bugdb', [], [], ['integerfield1' => $missingColumn] ), ] ); $expected->fromSchema = $schema1; $expected->changedTables['bugdb']->fromTable = $schema1->getTable('bugdb'); self::assertEquals($expected, Comparator::compareSchemas($schema1, $schema2)); } public function testCompareNewField() : void { $schema1 = new Schema([ 'bugdb' => new Table( 'bugdb', [ 'integerfield1' => new Column('integerfield1', Type::getType('integer')), ] ), ]); $schema2 = new Schema([ 'bugdb' => new Table( 'bugdb', [ 'integerfield1' => new Column('integerfield1', Type::getType('integer')), 'integerfield2' => new Column('integerfield2', Type::getType('integer')), ] ), ]); $expected = new SchemaDiff( [], [ 'bugdb' => new TableDiff( 'bugdb', [ 'integerfield2' => new Column('integerfield2', Type::getType('integer')), ] ), ] ); $expected->fromSchema = $schema1; $expected->changedTables['bugdb']->fromTable = $schema1->getTable('bugdb'); self::assertEquals($expected, Comparator::compareSchemas($schema1, $schema2)); } public function testCompareChangedColumnsChangeType() : void { $column1 = new Column('charfield1', Type::getType('string')); $column2 = new Column('charfield1', Type::getType('integer')); $c = new Comparator(); self::assertEquals(['type'], $c->diffColumn($column1, $column2)); self::assertEquals([], $c->diffColumn($column1, $column1)); } public function testCompareColumnsMultipleTypeInstances() : void { $integerType1 = Type::getType('integer'); Type::overrideType('integer', get_class($integerType1)); $integerType2 = Type::getType('integer'); $column1 = new Column('integerfield1', $integerType1); $column2 = new Column('integerfield1', $integerType2); $c = new Comparator(); self::assertEquals([], $c->diffColumn($column1, $column2)); } public function testCompareColumnsOverriddenType() : void { $oldStringInstance = Type::getType('string'); $integerType = Type::getType('integer'); Type::overrideType('string', get_class($integerType)); $overriddenStringType = Type::getType('string'); Type::overrideType('string', get_class($oldStringInstance)); $column1 = new Column('integerfield1', $integerType); $column2 = new Column('integerfield1', $overriddenStringType); $c = new Comparator(); self::assertEquals([], $c->diffColumn($column1, $column2)); } public function testCompareChangedColumnsChangeCustomSchemaOption() : void { $column1 = new Column('charfield1', Type::getType('string')); $column2 = new Column('charfield1', Type::getType('string')); $column1->setCustomSchemaOption('foo', 'bar'); $column2->setCustomSchemaOption('foo', 'bar'); $column1->setCustomSchemaOption('foo1', 'bar1'); $column2->setCustomSchemaOption('foo2', 'bar2'); $c = new Comparator(); self::assertEquals(['foo1', 'foo2'], $c->diffColumn($column1, $column2)); self::assertEquals([], $c->diffColumn($column1, $column1)); } public function testCompareChangeColumnsMultipleNewColumnsRename() : void { $tableA = new Table('foo'); $tableA->addColumn('datefield1', 'datetime'); $tableB = new Table('foo'); $tableB->addColumn('new_datefield1', 'datetime'); $tableB->addColumn('new_datefield2', 'datetime'); $c = new Comparator(); $tableDiff = $c->diffTable($tableA, $tableB); self::assertCount(1, $tableDiff->renamedColumns, 'we should have one rename datefield1 => new_datefield1.'); self::assertArrayHasKey('datefield1', $tableDiff->renamedColumns, "'datefield1' should be set to be renamed to new_datefield1"); self::assertCount(1, $tableDiff->addedColumns, "'new_datefield2' should be added"); self::assertArrayHasKey('new_datefield2', $tableDiff->addedColumns, "'new_datefield2' should be added, not created through renaming!"); self::assertCount(0, $tableDiff->removedColumns, 'Nothing should be removed.'); self::assertCount(0, $tableDiff->changedColumns, 'Nothing should be changed as all fields old & new have diff names.'); } public function testCompareRemovedIndex() : void { $schema1 = new Schema([ 'bugdb' => new Table( 'bugdb', [ 'integerfield1' => new Column('integerfield1', Type::getType('integer')), 'integerfield2' => new Column('integerfield2', Type::getType('integer')), ], [ 'primary' => new Index( 'primary', ['integerfield1'], true ), ] ), ]); $schema2 = new Schema([ 'bugdb' => new Table( 'bugdb', [ 'integerfield1' => new Column('integerfield1', Type::getType('integer')), 'integerfield2' => new Column('integerfield2', Type::getType('integer')), ] ), ]); $expected = new SchemaDiff( [], [ 'bugdb' => new TableDiff( 'bugdb', [], [], [], [], [], [ 'primary' => new Index( 'primary', ['integerfield1'], true ), ] ), ] ); $expected->fromSchema = $schema1; $expected->changedTables['bugdb']->fromTable = $schema1->getTable('bugdb'); self::assertEquals($expected, Comparator::compareSchemas($schema1, $schema2)); } public function testCompareNewIndex() : void { $schema1 = new Schema([ 'bugdb' => new Table( 'bugdb', [ 'integerfield1' => new Column('integerfield1', Type::getType('integer')), 'integerfield2' => new Column('integerfield2', Type::getType('integer')), ] ), ]); $schema2 = new Schema([ 'bugdb' => new Table( 'bugdb', [ 'integerfield1' => new Column('integerfield1', Type::getType('integer')), 'integerfield2' => new Column('integerfield2', Type::getType('integer')), ], [ 'primary' => new Index( 'primary', ['integerfield1'], true ), ] ), ]); $expected = new SchemaDiff( [], [ 'bugdb' => new TableDiff( 'bugdb', [], [], [], [ 'primary' => new Index( 'primary', ['integerfield1'], true ), ] ), ] ); $expected->fromSchema = $schema1; $expected->changedTables['bugdb']->fromTable = $schema1->getTable('bugdb'); self::assertEquals($expected, Comparator::compareSchemas($schema1, $schema2)); } public function testCompareChangedIndex() : void { $schema1 = new Schema([ 'bugdb' => new Table( 'bugdb', [ 'integerfield1' => new Column('integerfield1', Type::getType('integer')), 'integerfield2' => new Column('integerfield2', Type::getType('integer')), ], [ 'primary' => new Index( 'primary', ['integerfield1'], true ), ] ), ]); $schema2 = new Schema([ 'bugdb' => new Table( 'bugdb', [ 'integerfield1' => new Column('integerfield1', Type::getType('integer')), 'integerfield2' => new Column('integerfield2', Type::getType('integer')), ], [ 'primary' => new Index( 'primary', ['integerfield1', 'integerfield2'], true ), ] ), ]); $expected = new SchemaDiff( [], [ 'bugdb' => new TableDiff( 'bugdb', [], [], [], [], [ 'primary' => new Index( 'primary', [ 'integerfield1', 'integerfield2', ], true ), ] ), ] ); $expected->fromSchema = $schema1; $expected->changedTables['bugdb']->fromTable = $schema1->getTable('bugdb'); self::assertEquals($expected, Comparator::compareSchemas($schema1, $schema2)); } public function testCompareChangedIndexFieldPositions() : void { $schema1 = new Schema([ 'bugdb' => new Table( 'bugdb', [ 'integerfield1' => new Column('integerfield1', Type::getType('integer')), 'integerfield2' => new Column('integerfield2', Type::getType('integer')), ], [ 'primary' => new Index('primary', ['integerfield1', 'integerfield2'], true), ] ), ]); $schema2 = new Schema([ 'bugdb' => new Table( 'bugdb', [ 'integerfield1' => new Column('integerfield1', Type::getType('integer')), 'integerfield2' => new Column('integerfield2', Type::getType('integer')), ], [ 'primary' => new Index('primary', ['integerfield2', 'integerfield1'], true), ] ), ]); $expected = new SchemaDiff( [], [ 'bugdb' => new TableDiff( 'bugdb', [], [], [], [], [ 'primary' => new Index('primary', ['integerfield2', 'integerfield1'], true), ] ), ] ); $expected->fromSchema = $schema1; $expected->changedTables['bugdb']->fromTable = $schema1->getTable('bugdb'); self::assertEquals($expected, Comparator::compareSchemas($schema1, $schema2)); } public function testCompareSequences() : void { $seq1 = new Sequence('foo', 1, 1); $seq2 = new Sequence('foo', 1, 2); $seq3 = new Sequence('foo', 2, 1); $seq4 = new Sequence('foo', '1', '1'); $c = new Comparator(); self::assertTrue($c->diffSequence($seq1, $seq2)); self::assertTrue($c->diffSequence($seq1, $seq3)); self::assertFalse($c->diffSequence($seq1, $seq4)); } public function testRemovedSequence() : void { $schema1 = new Schema(); $seq = $schema1->createSequence('foo'); $schema2 = new Schema(); $c = new Comparator(); $diffSchema = $c->compare($schema1, $schema2); self::assertCount(1, $diffSchema->removedSequences); self::assertSame($seq, $diffSchema->removedSequences[0]); } public function testAddedSequence() : void { $schema1 = new Schema(); $schema2 = new Schema(); $seq = $schema2->createSequence('foo'); $c = new Comparator(); $diffSchema = $c->compare($schema1, $schema2); self::assertCount(1, $diffSchema->newSequences); self::assertSame($seq, $diffSchema->newSequences[0]); } public function testTableAddForeignKey() : void { $tableForeign = new Table('bar'); $tableForeign->addColumn('id', 'integer'); $table1 = new Table('foo'); $table1->addColumn('fk', 'integer'); $table2 = new Table('foo'); $table2->addColumn('fk', 'integer'); $table2->addForeignKeyConstraint($tableForeign, ['fk'], ['id']); $c = new Comparator(); $tableDiff = $c->diffTable($table1, $table2); self::assertInstanceOf(TableDiff::class, $tableDiff); self::assertCount(1, $tableDiff->addedForeignKeys); } public function testTableRemoveForeignKey() : void { $tableForeign = new Table('bar'); $tableForeign->addColumn('id', 'integer'); $table1 = new Table('foo'); $table1->addColumn('fk', 'integer'); $table2 = new Table('foo'); $table2->addColumn('fk', 'integer'); $table2->addForeignKeyConstraint($tableForeign, ['fk'], ['id']); $c = new Comparator(); $tableDiff = $c->diffTable($table2, $table1); self::assertInstanceOf(TableDiff::class, $tableDiff); self::assertCount(1, $tableDiff->removedForeignKeys); } public function testTableUpdateForeignKey() : void { $tableForeign = new Table('bar'); $tableForeign->addColumn('id', 'integer'); $table1 = new Table('foo'); $table1->addColumn('fk', 'integer'); $table1->addForeignKeyConstraint($tableForeign, ['fk'], ['id']); $table2 = new Table('foo'); $table2->addColumn('fk', 'integer'); $table2->addForeignKeyConstraint($tableForeign, ['fk'], ['id'], ['onUpdate' => 'CASCADE']); $c = new Comparator(); $tableDiff = $c->diffTable($table1, $table2); self::assertInstanceOf(TableDiff::class, $tableDiff); self::assertCount(1, $tableDiff->changedForeignKeys); } public function testMovedForeignKeyForeignTable() : void { $tableForeign = new Table('bar'); $tableForeign->addColumn('id', 'integer'); $tableForeign2 = new Table('bar2'); $tableForeign2->addColumn('id', 'integer'); $table1 = new Table('foo'); $table1->addColumn('fk', 'integer'); $table1->addForeignKeyConstraint($tableForeign, ['fk'], ['id']); $table2 = new Table('foo'); $table2->addColumn('fk', 'integer'); $table2->addForeignKeyConstraint($tableForeign2, ['fk'], ['id']); $c = new Comparator(); $tableDiff = $c->diffTable($table1, $table2); self::assertInstanceOf(TableDiff::class, $tableDiff); self::assertCount(1, $tableDiff->changedForeignKeys); } public function testTablesCaseInsensitive() : void { $schemaA = new Schema(); $schemaA->createTable('foo'); $schemaA->createTable('bAr'); $schemaA->createTable('BAZ'); $schemaA->createTable('new'); $schemaB = new Schema(); $schemaB->createTable('FOO'); $schemaB->createTable('bar'); $schemaB->createTable('Baz'); $schemaB->createTable('old'); $c = new Comparator(); $diff = $c->compare($schemaA, $schemaB); $this->assertSchemaTableChangeCount($diff, 1, 0, 1); } public function testSequencesCaseInsensitive() : void { $schemaA = new Schema(); $schemaA->createSequence('foo'); $schemaA->createSequence('BAR'); $schemaA->createSequence('Baz'); $schemaA->createSequence('new'); $schemaB = new Schema(); $schemaB->createSequence('FOO'); $schemaB->createSequence('Bar'); $schemaB->createSequence('baz'); $schemaB->createSequence('old'); $c = new Comparator(); $diff = $c->compare($schemaA, $schemaB); $this->assertSchemaSequenceChangeCount($diff, 1, 0, 1); } public function testCompareColumnCompareCaseInsensitive() : void { $tableA = new Table('foo'); $tableA->addColumn('id', 'integer'); $tableB = new Table('foo'); $tableB->addColumn('ID', 'integer'); $c = new Comparator(); $tableDiff = $c->diffTable($tableA, $tableB); self::assertFalse($tableDiff); } public function testCompareIndexBasedOnPropertiesNotName() : void { $tableA = new Table('foo'); $tableA->addColumn('id', 'integer'); $tableA->addIndex(['id'], 'foo_bar_idx'); $tableB = new Table('foo'); $tableB->addColumn('ID', 'integer'); $tableB->addIndex(['id'], 'bar_foo_idx'); $c = new Comparator(); $tableDiff = new TableDiff('foo'); $tableDiff->fromTable = $tableA; $tableDiff->renamedIndexes['foo_bar_idx'] = new Index('bar_foo_idx', ['id']); self::assertEquals( $tableDiff, $c->diffTable($tableA, $tableB) ); } public function testCompareForeignKeyBasedOnPropertiesNotName() : void { $tableA = new Table('foo'); $tableA->addColumn('id', 'integer'); $tableA->addNamedForeignKeyConstraint('foo_constraint', 'bar', ['id'], ['id']); $tableB = new Table('foo'); $tableB->addColumn('ID', 'integer'); $tableB->addNamedForeignKeyConstraint('bar_constraint', 'bar', ['id'], ['id']); $c = new Comparator(); $tableDiff = $c->diffTable($tableA, $tableB); self::assertFalse($tableDiff); } public function testCompareForeignKeyRestrictNoActionAreTheSame() : void { $fk1 = new ForeignKeyConstraint(['foo'], 'bar', ['baz'], 'fk1', ['onDelete' => 'NO ACTION']); $fk2 = new ForeignKeyConstraint(['foo'], 'bar', ['baz'], 'fk1', ['onDelete' => 'RESTRICT']); $c = new Comparator(); self::assertFalse($c->diffForeignKey($fk1, $fk2)); } /** * @group DBAL-492 */ public function testCompareForeignKeyNamesUnqualifiedAsNoSchemaInformationIsAvailable() : void { $fk1 = new ForeignKeyConstraint(['foo'], 'foo.bar', ['baz'], 'fk1'); $fk2 = new ForeignKeyConstraint(['foo'], 'baz.bar', ['baz'], 'fk1'); $c = new Comparator(); self::assertFalse($c->diffForeignKey($fk1, $fk2)); } public function testDetectRenameColumn() : void { $tableA = new Table('foo'); $tableA->addColumn('foo', 'integer'); $tableB = new Table('foo'); $tableB->addColumn('bar', 'integer'); $c = new Comparator(); $tableDiff = $c->diffTable($tableA, $tableB); self::assertCount(0, $tableDiff->addedColumns); self::assertCount(0, $tableDiff->removedColumns); self::assertArrayHasKey('foo', $tableDiff->renamedColumns); self::assertEquals('bar', $tableDiff->renamedColumns['foo']->getName()); } /** * You can easily have ambiguities in the column renaming. If these * are detected no renaming should take place, instead adding and dropping * should be used exclusively. * * @group DBAL-24 */ public function testDetectRenameColumnAmbiguous() : void { $tableA = new Table('foo'); $tableA->addColumn('foo', 'integer'); $tableA->addColumn('bar', 'integer'); $tableB = new Table('foo'); $tableB->addColumn('baz', 'integer'); $c = new Comparator(); $tableDiff = $c->diffTable($tableA, $tableB); self::assertCount(1, $tableDiff->addedColumns, "'baz' should be added, not created through renaming!"); self::assertArrayHasKey('baz', $tableDiff->addedColumns, "'baz' should be added, not created through renaming!"); self::assertCount(2, $tableDiff->removedColumns, "'foo' and 'bar' should both be dropped, an ambiguity exists which one could be renamed to 'baz'."); self::assertArrayHasKey('foo', $tableDiff->removedColumns, "'foo' should be removed."); self::assertArrayHasKey('bar', $tableDiff->removedColumns, "'bar' should be removed."); self::assertCount(0, $tableDiff->renamedColumns, 'no renamings should take place.'); } /** * @group DBAL-1063 */ public function testDetectRenameIndex() : void { $table1 = new Table('foo'); $table1->addColumn('foo', 'integer'); $table2 = clone $table1; $table1->addIndex(['foo'], 'idx_foo'); $table2->addIndex(['foo'], 'idx_bar'); $comparator = new Comparator(); $tableDiff = $comparator->diffTable($table1, $table2); self::assertCount(0, $tableDiff->addedIndexes); self::assertCount(0, $tableDiff->removedIndexes); self::assertArrayHasKey('idx_foo', $tableDiff->renamedIndexes); self::assertEquals('idx_bar', $tableDiff->renamedIndexes['idx_foo']->getName()); } /** * You can easily have ambiguities in the index renaming. If these * are detected no renaming should take place, instead adding and dropping * should be used exclusively. * * @group DBAL-1063 */ public function testDetectRenameIndexAmbiguous() : void { $table1 = new Table('foo'); $table1->addColumn('foo', 'integer'); $table2 = clone $table1; $table1->addIndex(['foo'], 'idx_foo'); $table1->addIndex(['foo'], 'idx_bar'); $table2->addIndex(['foo'], 'idx_baz'); $comparator = new Comparator(); $tableDiff = $comparator->diffTable($table1, $table2); self::assertCount(1, $tableDiff->addedIndexes); self::assertArrayHasKey('idx_baz', $tableDiff->addedIndexes); self::assertCount(2, $tableDiff->removedIndexes); self::assertArrayHasKey('idx_foo', $tableDiff->removedIndexes); self::assertArrayHasKey('idx_bar', $tableDiff->removedIndexes); self::assertCount(0, $tableDiff->renamedIndexes); } public function testDetectChangeIdentifierType() : void { $this->markTestSkipped('DBAL-2 was reopened, this test cannot work anymore.'); $tableA = new Table('foo'); $tableA->addColumn('id', 'integer', ['autoincrement' => false]); $tableB = new Table('foo'); $tableB->addColumn('id', 'integer', ['autoincrement' => true]); $c = new Comparator(); $tableDiff = $c->diffTable($tableA, $tableB); self::assertInstanceOf(TableDiff::class, $tableDiff); self::assertArrayHasKey('id', $tableDiff->changedColumns); } /** * @group DBAL-105 */ public function testDiff() : void { $table = new Table('twitter_users'); $table->addColumn('id', 'integer', ['autoincrement' => true]); $table->addColumn('twitterId', 'integer'); $table->addColumn('displayName', 'string'); $table->setPrimaryKey(['id']); $newtable = new Table('twitter_users'); $newtable->addColumn('id', 'integer', ['autoincrement' => true]); $newtable->addColumn('twitter_id', 'integer'); $newtable->addColumn('display_name', 'string'); $newtable->addColumn('logged_in_at', 'datetime'); $newtable->setPrimaryKey(['id']); $c = new Comparator(); $tableDiff = $c->diffTable($table, $newtable); self::assertInstanceOf(TableDiff::class, $tableDiff); self::assertEquals(['twitterid', 'displayname'], array_keys($tableDiff->renamedColumns)); self::assertEquals(['logged_in_at'], array_keys($tableDiff->addedColumns)); self::assertCount(0, $tableDiff->removedColumns); } /** * @group DBAL-112 */ public function testChangedSequence() : void { $schema = new Schema(); $sequence = $schema->createSequence('baz'); $schemaNew = clone $schema; $schemaNew->getSequence('baz')->setAllocationSize(20); $c = new Comparator(); $diff = $c->compare($schema, $schemaNew); self::assertSame($diff->changedSequences[0], $schemaNew->getSequence('baz')); } /** * @group DBAL-106 */ public function testDiffDecimalWithNullPrecision() : void { $column = new Column('foo', Type::getType('decimal')); $column->setPrecision(null); $column2 = new Column('foo', Type::getType('decimal')); $c = new Comparator(); self::assertEquals([], $c->diffColumn($column, $column2)); } /** * @group DBAL-204 */ public function testFqnSchemaComparison() : void { $config = new SchemaConfig(); $config->setName('foo'); $oldSchema = new Schema([], [], $config); $oldSchema->createTable('bar'); $newSchema = new Schema([], [], $config); $newSchema->createTable('foo.bar'); $expected = new SchemaDiff(); $expected->fromSchema = $oldSchema; self::assertEquals($expected, Comparator::compareSchemas($oldSchema, $newSchema)); } /** * @group DBAL-669 */ public function testNamespacesComparison() : void { $config = new SchemaConfig(); $config->setName('schemaName'); $oldSchema = new Schema([], [], $config); $oldSchema->createTable('taz'); $oldSchema->createTable('war.tab'); $newSchema = new Schema([], [], $config); $newSchema->createTable('bar.tab'); $newSchema->createTable('baz.tab'); $newSchema->createTable('war.tab'); $expected = new SchemaDiff(); $expected->fromSchema = $oldSchema; $expected->newNamespaces = ['bar' => 'bar', 'baz' => 'baz']; $diff = Comparator::compareSchemas($oldSchema, $newSchema); self::assertEquals(['bar' => 'bar', 'baz' => 'baz'], $diff->newNamespaces); self::assertCount(2, $diff->newTables); } /** * @group DBAL-204 */ public function testFqnSchemaComparisonDifferentSchemaNameButSameTableNoDiff() : void { $config = new SchemaConfig(); $config->setName('foo'); $oldSchema = new Schema([], [], $config); $oldSchema->createTable('foo.bar'); $newSchema = new Schema(); $newSchema->createTable('bar'); $expected = new SchemaDiff(); $expected->fromSchema = $oldSchema; self::assertEquals($expected, Comparator::compareSchemas($oldSchema, $newSchema)); } /** * @group DBAL-204 */ public function testFqnSchemaComparisonNoSchemaSame() : void { $config = new SchemaConfig(); $config->setName('foo'); $oldSchema = new Schema([], [], $config); $oldSchema->createTable('bar'); $newSchema = new Schema(); $newSchema->createTable('bar'); $expected = new SchemaDiff(); $expected->fromSchema = $oldSchema; self::assertEquals($expected, Comparator::compareSchemas($oldSchema, $newSchema)); } /** * @group DDC-1657 */ public function testAutoIncrementSequences() : void { $oldSchema = new Schema(); $table = $oldSchema->createTable('foo'); $table->addColumn('id', 'integer', ['autoincrement' => true]); $table->setPrimaryKey(['id']); $oldSchema->createSequence('foo_id_seq'); $newSchema = new Schema(); $table = $newSchema->createTable('foo'); $table->addColumn('id', 'integer', ['autoincrement' => true]); $table->setPrimaryKey(['id']); $c = new Comparator(); $diff = $c->compare($oldSchema, $newSchema); self::assertCount(0, $diff->removedSequences); } /** * Check that added autoincrement sequence is not populated in newSequences * * @group DBAL-562 */ public function testAutoIncrementNoSequences() : void { $oldSchema = new Schema(); $table = $oldSchema->createTable('foo'); $table->addColumn('id', 'integer', ['autoincrement' => true]); $table->setPrimaryKey(['id']); $newSchema = new Schema(); $table = $newSchema->createTable('foo'); $table->addColumn('id', 'integer', ['autoincrement' => true]); $table->setPrimaryKey(['id']); $newSchema->createSequence('foo_id_seq'); $c = new Comparator(); $diff = $c->compare($oldSchema, $newSchema); self::assertCount(0, $diff->newSequences); } /** * You can get multiple drops for a FK when a table referenced by a foreign * key is deleted, as this FK is referenced twice, once on the orphanedForeignKeys * array because of the dropped table, and once on changedTables array. We * now check that the key is present once. */ public function testAvoidMultipleDropForeignKey() : void { $oldSchema = new Schema(); $tableA = $oldSchema->createTable('table_a'); $tableA->addColumn('id', 'integer'); $tableB = $oldSchema->createTable('table_b'); $tableB->addColumn('id', 'integer'); $tableC = $oldSchema->createTable('table_c'); $tableC->addColumn('id', 'integer'); $tableC->addColumn('table_a_id', 'integer'); $tableC->addColumn('table_b_id', 'integer'); $tableC->addForeignKeyConstraint($tableA, ['table_a_id'], ['id']); $tableC->addForeignKeyConstraint($tableB, ['table_b_id'], ['id']); $newSchema = new Schema(); $tableB = $newSchema->createTable('table_b'); $tableB->addColumn('id', 'integer'); $tableC = $newSchema->createTable('table_c'); $tableC->addColumn('id', 'integer'); $comparator = new Comparator(); $schemaDiff = $comparator->compare($oldSchema, $newSchema); self::assertCount(1, $schemaDiff->changedTables['table_c']->removedForeignKeys); self::assertCount(1, $schemaDiff->orphanedForeignKeys); } public function testCompareChangedColumn() : void { $oldSchema = new Schema(); $tableFoo = $oldSchema->createTable('foo'); $tableFoo->addColumn('id', 'integer'); $newSchema = new Schema(); $table = $newSchema->createTable('foo'); $table->addColumn('id', 'string'); $expected = new SchemaDiff(); $expected->fromSchema = $oldSchema; $tableDiff = $expected->changedTables['foo'] = new TableDiff('foo'); $tableDiff->fromTable = $tableFoo; $columnDiff = $tableDiff->changedColumns['id'] = new ColumnDiff('id', $table->getColumn('id')); $columnDiff->fromColumn = $tableFoo->getColumn('id'); $columnDiff->changedProperties = ['type']; self::assertEquals($expected, Comparator::compareSchemas($oldSchema, $newSchema)); } public function testCompareChangedBinaryColumn() : void { $oldSchema = new Schema(); $tableFoo = $oldSchema->createTable('foo'); $tableFoo->addColumn('id', 'binary'); $newSchema = new Schema(); $table = $newSchema->createTable('foo'); $table->addColumn('id', 'binary', ['length' => 42, 'fixed' => true]); $expected = new SchemaDiff(); $expected->fromSchema = $oldSchema; $tableDiff = $expected->changedTables['foo'] = new TableDiff('foo'); $tableDiff->fromTable = $tableFoo; $columnDiff = $tableDiff->changedColumns['id'] = new ColumnDiff('id', $table->getColumn('id')); $columnDiff->fromColumn = $tableFoo->getColumn('id'); $columnDiff->changedProperties = ['length', 'fixed']; self::assertEquals($expected, Comparator::compareSchemas($oldSchema, $newSchema)); } /** * @group DBAL-617 */ public function testCompareQuotedAndUnquotedForeignKeyColumns() : void { $fk1 = new ForeignKeyConstraint(['foo'], 'bar', ['baz'], 'fk1', ['onDelete' => 'NO ACTION']); $fk2 = new ForeignKeyConstraint(['`foo`'], 'bar', ['`baz`'], 'fk1', ['onDelete' => 'NO ACTION']); $comparator = new Comparator(); $diff = $comparator->diffForeignKey($fk1, $fk2); self::assertFalse($diff); } public function assertSchemaTableChangeCount(SchemaDiff $diff, int $newTableCount = 0, int $changeTableCount = 0, int $removeTableCount = 0) : void { self::assertCount($newTableCount, $diff->newTables); self::assertCount($changeTableCount, $diff->changedTables); self::assertCount($removeTableCount, $diff->removedTables); } public function assertSchemaSequenceChangeCount( SchemaDiff $diff, int $newSequenceCount = 0, int $changeSequenceCount = 0, int $removeSequenceCount = 0 ) : void { self::assertCount($newSequenceCount, $diff->newSequences, 'Expected number of new sequences is wrong.'); self::assertCount($changeSequenceCount, $diff->changedSequences, 'Expected number of changed sequences is wrong.'); self::assertCount($removeSequenceCount, $diff->removedSequences, 'Expected number of removed sequences is wrong.'); } public function testDiffColumnPlatformOptions() : void { $column1 = new Column('foo', Type::getType('string'), ['platformOptions' => ['foo' => 'foo', 'bar' => 'bar']]); $column2 = new Column('foo', Type::getType('string'), ['platformOptions' => ['foo' => 'foo', 'foobar' => 'foobar']]); $column3 = new Column('foo', Type::getType('string'), ['platformOptions' => ['foo' => 'foo', 'bar' => 'rab']]); $column4 = new Column('foo', Type::getType('string')); $comparator = new Comparator(); self::assertEquals([], $comparator->diffColumn($column1, $column2)); self::assertEquals([], $comparator->diffColumn($column2, $column1)); self::assertEquals(['bar'], $comparator->diffColumn($column1, $column3)); self::assertEquals(['bar'], $comparator->diffColumn($column3, $column1)); self::assertEquals([], $comparator->diffColumn($column1, $column4)); self::assertEquals([], $comparator->diffColumn($column4, $column1)); } public function testComplexDiffColumn() : void { $column1 = new Column('foo', Type::getType('string'), [ 'platformOptions' => ['foo' => 'foo'], 'customSchemaOptions' => ['foo' => 'bar'], ]); $column2 = new Column('foo', Type::getType('string'), [ 'platformOptions' => ['foo' => 'bar'], ]); $comparator = new Comparator(); self::assertEquals([], $comparator->diffColumn($column1, $column2)); self::assertEquals([], $comparator->diffColumn($column2, $column1)); } /** * @group DBAL-669 */ public function testComparesNamespaces() : void { $comparator = new Comparator(); $fromSchema = $this->getMockBuilder(Schema::class) ->onlyMethods(['getNamespaces', 'hasNamespace']) ->getMock(); $toSchema = $this->getMockBuilder(Schema::class) ->onlyMethods(['getNamespaces', 'hasNamespace']) ->getMock(); $fromSchema->expects($this->once()) ->method('getNamespaces') ->will($this->returnValue(['foo', 'bar'])); $fromSchema->expects($this->at(0)) ->method('hasNamespace') ->with('bar') ->will($this->returnValue(true)); $fromSchema->expects($this->at(1)) ->method('hasNamespace') ->with('baz') ->will($this->returnValue(false)); $toSchema->expects($this->once()) ->method('getNamespaces') ->will($this->returnValue(['bar', 'baz'])); $toSchema->expects($this->at(1)) ->method('hasNamespace') ->with('foo') ->will($this->returnValue(false)); $toSchema->expects($this->at(2)) ->method('hasNamespace') ->with('bar') ->will($this->returnValue(true)); $expected = new SchemaDiff(); $expected->fromSchema = $fromSchema; $expected->newNamespaces = ['baz' => 'baz']; $expected->removedNamespaces = ['foo' => 'foo']; self::assertEquals($expected, $comparator->compare($fromSchema, $toSchema)); } public function testCompareGuidColumns() : void { $comparator = new Comparator(); $column1 = new Column('foo', Type::getType('guid'), ['comment' => 'GUID 1']); $column2 = new Column( 'foo', Type::getType('guid'), ['notnull' => false, 'length' => '36', 'fixed' => true, 'default' => 'NEWID()', 'comment' => 'GUID 2.'] ); self::assertEquals(['notnull', 'default', 'comment'], $comparator->diffColumn($column1, $column2)); self::assertEquals(['notnull', 'default', 'comment'], $comparator->diffColumn($column2, $column1)); } /** * @group DBAL-1009 * @dataProvider getCompareColumnComments */ public function testCompareColumnComments(?string $comment1, ?string $comment2, bool $equals) : void { $column1 = new Column('foo', Type::getType('integer'), ['comment' => $comment1]); $column2 = new Column('foo', Type::getType('integer'), ['comment' => $comment2]); $comparator = new Comparator(); $expectedDiff = $equals ? [] : ['comment']; $actualDiff = $comparator->diffColumn($column1, $column2); self::assertSame($expectedDiff, $actualDiff); $actualDiff = $comparator->diffColumn($column2, $column1); self::assertSame($expectedDiff, $actualDiff); } /** * @return mixed[][] */ public static function getCompareColumnComments() : iterable { return [ [null, null, true], ['', '', true], [' ', ' ', true], ['0', '0', true], ['foo', 'foo', true], [null, '', true], [null, ' ', false], [null, '0', false], [null, 'foo', false], ['', ' ', false], ['', '0', false], ['', 'foo', false], [' ', '0', false], [' ', 'foo', false], ['0', 'foo', false], ]; } public function testForeignKeyRemovalWithRenamedLocalColumn() : void { $fromSchema = new Schema([ 'table1' => new Table( 'table1', [ 'id' => new Column('id', Type::getType('integer')), ] ), 'table2' => new Table( 'table2', [ 'id' => new Column('id', Type::getType('integer')), 'id_table1' => new Column('id_table1', Type::getType('integer')), ], [], [ new ForeignKeyConstraint(['id_table1'], 'table1', ['id'], 'fk_table2_table1'), ] ), ]); $toSchema = new Schema([ 'table2' => new Table( 'table2', [ 'id' => new Column('id', Type::getType('integer')), 'id_table3' => new Column('id_table3', Type::getType('integer')), ], [], [ new ForeignKeyConstraint(['id_table3'], 'table3', ['id'], 'fk_table2_table3'), ] ), 'table3' => new Table( 'table3', [ 'id' => new Column('id', Type::getType('integer')), ] ), ]); $actual = Comparator::compareSchemas($fromSchema, $toSchema); self::assertArrayHasKey('table2', $actual->changedTables); self::assertCount(1, $actual->orphanedForeignKeys); self::assertEquals('fk_table2_table1', $actual->orphanedForeignKeys[0]->getName()); self::assertCount(1, $actual->changedTables['table2']->addedForeignKeys, 'FK to table3 should be added.'); self::assertEquals('table3', $actual->changedTables['table2']->addedForeignKeys[0]->getForeignTableName()); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Schema/DB2SchemaManagerTest.php000066400000000000000000000131511360544566000273520ustar00rootroot00000000000000createMock(Driver::class); $platform = $this->createMock(DB2Platform::class); $this->conn = $this ->getMockBuilder(Connection::class) ->onlyMethods(['fetchAll', 'quote']) ->setConstructorArgs([['platform' => $platform], $driverMock, new Configuration(), $eventManager]) ->getMock(); $this->manager = new DB2SchemaManager($this->conn); } /** * @see https://github.com/doctrine/dbal/issues/2701 * * @group DBAL-2701 */ public function testListTableNamesFiltersAssetNamesCorrectly() : void { $this->conn->getConfiguration()->setFilterSchemaAssetsExpression('/^(?!T_)/'); $this->conn->expects($this->once())->method('fetchAll')->will($this->returnValue([ ['name' => 'FOO'], ['name' => 'T_FOO'], ['name' => 'BAR'], ['name' => 'T_BAR'], ])); self::assertSame( [ 'FOO', 'BAR', ], $this->manager->listTableNames() ); } /** * @group DBAL-2701 */ public function testAssetFilteringSetsACallable() : void { $filterExpression = '/^(?!T_)/'; $this->conn->getConfiguration()->setFilterSchemaAssetsExpression($filterExpression); $this->conn->expects($this->once())->method('fetchAll')->will($this->returnValue([ ['name' => 'FOO'], ['name' => 'T_FOO'], ['name' => 'BAR'], ['name' => 'T_BAR'], ])); self::assertSame( [ 'FOO', 'BAR', ], $this->manager->listTableNames() ); $callable = $this->conn->getConfiguration()->getSchemaAssetsFilter(); self::assertIsCallable($callable); // BC check: Test that regexp expression is still preserved & accessible. $this->assertEquals($filterExpression, $this->conn->getConfiguration()->getFilterSchemaAssetsExpression()); } public function testListTableNamesFiltersAssetNamesCorrectlyWithCallable() : void { $accepted = ['T_FOO', 'T_BAR']; $this->conn->getConfiguration()->setSchemaAssetsFilter(static function ($assetName) use ($accepted) { return in_array($assetName, $accepted); }); $this->conn->expects($this->any())->method('quote'); $this->conn->expects($this->once())->method('fetchAll')->will($this->returnValue([ ['name' => 'FOO'], ['name' => 'T_FOO'], ['name' => 'BAR'], ['name' => 'T_BAR'], ])); self::assertSame( [ 'T_FOO', 'T_BAR', ], $this->manager->listTableNames() ); $this->assertNull($this->conn->getConfiguration()->getFilterSchemaAssetsExpression()); } public function testSettingNullExpressionWillResetCallable() : void { $accepted = ['T_FOO', 'T_BAR']; $this->conn->getConfiguration()->setSchemaAssetsFilter(static function ($assetName) use ($accepted) { return in_array($assetName, $accepted); }); $this->conn->expects($this->any())->method('quote'); $this->conn->expects($this->atLeastOnce())->method('fetchAll')->will($this->returnValue([ ['name' => 'FOO'], ['name' => 'T_FOO'], ['name' => 'BAR'], ['name' => 'T_BAR'], ])); self::assertSame( [ 'T_FOO', 'T_BAR', ], $this->manager->listTableNames() ); $this->conn->getConfiguration()->setFilterSchemaAssetsExpression(null); self::assertSame( [ 'FOO', 'T_FOO', 'BAR', 'T_BAR', ], $this->manager->listTableNames() ); $this->assertNull($this->conn->getConfiguration()->getSchemaAssetsFilter()); } public function testSettingNullAsCallableClearsExpression() : void { $filterExpression = '/^(?!T_)/'; $this->conn->getConfiguration()->setFilterSchemaAssetsExpression($filterExpression); $this->conn->expects($this->exactly(2))->method('fetchAll')->will($this->returnValue([ ['name' => 'FOO'], ['name' => 'T_FOO'], ['name' => 'BAR'], ['name' => 'T_BAR'], ])); self::assertSame( [ 'FOO', 'BAR', ], $this->manager->listTableNames() ); $this->conn->getConfiguration()->setSchemaAssetsFilter(null); self::assertSame( [ 'FOO', 'T_FOO', 'BAR', 'T_BAR', ], $this->manager->listTableNames() ); $this->assertNull($this->conn->getConfiguration()->getFilterSchemaAssetsExpression()); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Schema/ForeignKeyConstraintTest.php000066400000000000000000000030261360544566000304760ustar00rootroot00000000000000getMockBuilder(Index::class) ->disableOriginalConstructor() ->getMock(); $index->expects($this->once()) ->method('getColumns') ->will($this->returnValue($indexColumns)); self::assertSame($expectedResult, $foreignKey->intersectsIndexColumns($index)); } /** * @return mixed[][] */ public static function getIntersectsIndexColumnsData() : iterable { return [ [['baz'], false], [['baz', 'bloo'], false], [['foo'], true], [['bar'], true], [['foo', 'bar'], true], [['bar', 'foo'], true], [['foo', 'baz'], true], [['baz', 'foo'], true], [['bar', 'baz'], true], [['baz', 'bar'], true], [['foo', 'bloo', 'baz'], true], [['bloo', 'foo', 'baz'], true], [['bloo', 'baz', 'foo'], true], [['FOO'], true], ]; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Schema/IndexTest.php000066400000000000000000000144221360544566000254400ustar00rootroot00000000000000createIndex(); self::assertEquals('foo', $idx->getName()); $columns = $idx->getColumns(); self::assertCount(2, $columns); self::assertEquals(['bar', 'baz'], $columns); self::assertFalse($idx->isUnique()); self::assertFalse($idx->isPrimary()); } public function testCreatePrimary() : void { $idx = $this->createIndex(false, true); self::assertTrue($idx->isUnique()); self::assertTrue($idx->isPrimary()); } public function testCreateUnique() : void { $idx = $this->createIndex(true, false); self::assertTrue($idx->isUnique()); self::assertFalse($idx->isPrimary()); } /** * @group DBAL-50 */ public function testFulfilledByUnique() : void { $idx1 = $this->createIndex(true, false); $idx2 = $this->createIndex(true, false); $idx3 = $this->createIndex(); self::assertTrue($idx1->isFullfilledBy($idx2)); self::assertFalse($idx1->isFullfilledBy($idx3)); } /** * @group DBAL-50 */ public function testFulfilledByPrimary() : void { $idx1 = $this->createIndex(true, true); $idx2 = $this->createIndex(true, true); $idx3 = $this->createIndex(true, false); self::assertTrue($idx1->isFullfilledBy($idx2)); self::assertFalse($idx1->isFullfilledBy($idx3)); } /** * @group DBAL-50 */ public function testFulfilledByIndex() : void { $idx1 = $this->createIndex(); $idx2 = $this->createIndex(); $pri = $this->createIndex(true, true); $uniq = $this->createIndex(true); self::assertTrue($idx1->isFullfilledBy($idx2)); self::assertTrue($idx1->isFullfilledBy($pri)); self::assertTrue($idx1->isFullfilledBy($uniq)); } public function testFulfilledWithPartial() : void { $without = new Index('without', ['col1', 'col2'], true, false, [], []); $partial = new Index('partial', ['col1', 'col2'], true, false, [], ['where' => 'col1 IS NULL']); $another = new Index('another', ['col1', 'col2'], true, false, [], ['where' => 'col1 IS NULL']); self::assertFalse($partial->isFullfilledBy($without)); self::assertFalse($without->isFullfilledBy($partial)); self::assertTrue($partial->isFullfilledBy($partial)); self::assertTrue($partial->isFullfilledBy($another)); self::assertTrue($another->isFullfilledBy($partial)); } public function testOverrulesWithPartial() : void { $without = new Index('without', ['col1', 'col2'], true, false, [], []); $partial = new Index('partial', ['col1', 'col2'], true, false, [], ['where' => 'col1 IS NULL']); $another = new Index('another', ['col1', 'col2'], true, false, [], ['where' => 'col1 IS NULL']); self::assertFalse($partial->overrules($without)); self::assertFalse($without->overrules($partial)); self::assertTrue($partial->overrules($partial)); self::assertTrue($partial->overrules($another)); self::assertTrue($another->overrules($partial)); } /** * @param string[] $columns * @param int[]|null[] $lengths1 * @param int[]|null[] $lengths2 * * @dataProvider indexLengthProvider */ public function testFulfilledWithLength(array $columns, array $lengths1, array $lengths2, bool $expected) : void { $index1 = new Index('index1', $columns, false, false, [], ['lengths' => $lengths1]); $index2 = new Index('index2', $columns, false, false, [], ['lengths' => $lengths2]); self::assertSame($expected, $index1->isFullfilledBy($index2)); self::assertSame($expected, $index2->isFullfilledBy($index1)); } /** * @return mixed[][] */ public static function indexLengthProvider() : iterable { return [ 'empty' => [['column'], [], [], true], 'same' => [['column'], [64], [64], true], 'different' => [['column'], [32], [64], false], 'sparse-different-positions' => [['column1', 'column2'], [0 => 32], [1 => 32], false], 'sparse-same-positions' => [['column1', 'column2'], [null, 32], [1 => 32], true], ]; } /** * @group DBAL-220 */ public function testFlags() : void { $idx1 = $this->createIndex(); self::assertFalse($idx1->hasFlag('clustered')); self::assertEmpty($idx1->getFlags()); $idx1->addFlag('clustered'); self::assertTrue($idx1->hasFlag('clustered')); self::assertTrue($idx1->hasFlag('CLUSTERED')); self::assertSame(['clustered'], $idx1->getFlags()); $idx1->removeFlag('clustered'); self::assertFalse($idx1->hasFlag('clustered')); self::assertEmpty($idx1->getFlags()); } /** * @group DBAL-285 */ public function testIndexQuotes() : void { $index = new Index('foo', ['`bar`', '`baz`']); self::assertTrue($index->spansColumns(['bar', 'baz'])); self::assertTrue($index->hasColumnAtPosition('bar', 0)); self::assertTrue($index->hasColumnAtPosition('baz', 1)); self::assertFalse($index->hasColumnAtPosition('bar', 1)); self::assertFalse($index->hasColumnAtPosition('baz', 0)); } public function testOptions() : void { $idx1 = $this->createIndex(); self::assertFalse($idx1->hasOption('where')); self::assertEmpty($idx1->getOptions()); $idx2 = $this->createIndex(false, false, ['where' => 'name IS NULL']); self::assertTrue($idx2->hasOption('where')); self::assertTrue($idx2->hasOption('WHERE')); self::assertSame('name IS NULL', $idx2->getOption('where')); self::assertSame('name IS NULL', $idx2->getOption('WHERE')); self::assertSame(['where' => 'name IS NULL'], $idx2->getOptions()); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Schema/MySqlInheritCharsetTest.php000066400000000000000000000060551360544566000302760ustar00rootroot00000000000000getTableOptionsForOverride(); self::assertFalse(isset($options['charset'])); // explicit utf8 $options = $this->getTableOptionsForOverride(['charset' => 'utf8']); self::assertTrue(isset($options['charset'])); self::assertSame($options['charset'], 'utf8'); // explicit utf8mb4 $options = $this->getTableOptionsForOverride(['charset' => 'utf8mb4']); self::assertTrue(isset($options['charset'])); self::assertSame($options['charset'], 'utf8mb4'); } public function testTableOptions() : void { $eventManager = new EventManager(); $driverMock = $this->createMock(Driver::class); $platform = new MySqlPlatform(); // default, no overrides $table = new Table('foobar', [new Column('aa', Type::getType('integer'))]); self::assertSame( $platform->getCreateTableSQL($table), ['CREATE TABLE foobar (aa INT NOT NULL) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB'] ); // explicit utf8 $table = new Table('foobar', [new Column('aa', Type::getType('integer'))]); $table->addOption('charset', 'utf8'); self::assertSame( $platform->getCreateTableSQL($table), ['CREATE TABLE foobar (aa INT NOT NULL) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB'] ); // explicit utf8mb4 $table = new Table('foobar', [new Column('aa', Type::getType('integer'))]); $table->addOption('charset', 'utf8mb4'); self::assertSame( $platform->getCreateTableSQL($table), ['CREATE TABLE foobar (aa INT NOT NULL) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'] ); } /** * @param string[] $overrideOptions * * @return string[] */ private function getTableOptionsForOverride(array $overrideOptions = []) : array { $eventManager = new EventManager(); $driverMock = $this->createMock(Driver::class); $platform = new MySqlPlatform(); $connOptions = array_merge(['platform' => $platform], $overrideOptions); $conn = new Connection($connOptions, $driverMock, new Configuration(), $eventManager); $manager = new MySqlSchemaManager($conn, $platform); $schemaConfig = $manager->createSchemaConfig(); return $schemaConfig->getDefaultTableOptions(); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Schema/MySqlSchemaManagerTest.php000066400000000000000000000055261360544566000300570ustar00rootroot00000000000000createMock(Driver::class); $platform = $this->createMock(MySqlPlatform::class); $this->conn = $this->getMockBuilder(Connection::class) ->onlyMethods(['fetchAll']) ->setConstructorArgs([['platform' => $platform], $driverMock, new Configuration(), $eventManager]) ->getMock(); $this->manager = new MySqlSchemaManager($this->conn); } public function testCompositeForeignKeys() : void { $this->conn->expects($this->once())->method('fetchAll')->will($this->returnValue($this->getFKDefinition())); $fkeys = $this->manager->listTableForeignKeys('dummy'); self::assertCount(1, $fkeys, 'Table has to have one foreign key.'); self::assertInstanceOf(ForeignKeyConstraint::class, $fkeys[0]); self::assertEquals(['column_1', 'column_2', 'column_3'], array_map('strtolower', $fkeys[0]->getLocalColumns())); self::assertEquals(['column_1', 'column_2', 'column_3'], array_map('strtolower', $fkeys[0]->getForeignColumns())); } /** * @return string[][] */ public function getFKDefinition() : array { return [ [ 'CONSTRAINT_NAME' => 'FK_C1B1712387FE737264DE5A5511B8B3E', 'COLUMN_NAME' => 'column_1', 'REFERENCED_TABLE_NAME' => 'dummy', 'REFERENCED_COLUMN_NAME' => 'column_1', 'update_rule' => 'RESTRICT', 'delete_rule' => 'RESTRICT', ], [ 'CONSTRAINT_NAME' => 'FK_C1B1712387FE737264DE5A5511B8B3E', 'COLUMN_NAME' => 'column_2', 'REFERENCED_TABLE_NAME' => 'dummy', 'REFERENCED_COLUMN_NAME' => 'column_2', 'update_rule' => 'RESTRICT', 'delete_rule' => 'RESTRICT', ], [ 'CONSTRAINT_NAME' => 'FK_C1B1712387FE737264DE5A5511B8B3E', 'COLUMN_NAME' => 'column_3', 'REFERENCED_TABLE_NAME' => 'dummy', 'REFERENCED_COLUMN_NAME' => 'column_3', 'update_rule' => 'RESTRICT', 'delete_rule' => 'RESTRICT', ], ]; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Schema/Platforms/000077500000000000000000000000001360544566000247645ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Schema/Platforms/MySQLSchemaTest.php000066400000000000000000000045661360544566000304360ustar00rootroot00000000000000comparator = new Comparator(); $this->platform = new MySqlPlatform(); } public function testSwitchPrimaryKeyOrder() : void { $tableOld = new Table('test'); $tableOld->addColumn('foo_id', 'integer'); $tableOld->addColumn('bar_id', 'integer'); $tableNew = clone $tableOld; $tableOld->setPrimaryKey(['foo_id', 'bar_id']); $tableNew->setPrimaryKey(['bar_id', 'foo_id']); $diff = $this->comparator->diffTable($tableOld, $tableNew); $sql = $this->platform->getAlterTableSQL($diff); self::assertEquals( [ 'ALTER TABLE test DROP PRIMARY KEY', 'ALTER TABLE test ADD PRIMARY KEY (bar_id, foo_id)', ], $sql ); } /** * @group DBAL-132 */ public function testGenerateForeignKeySQL() : void { $tableOld = new Table('test'); $tableOld->addColumn('foo_id', 'integer'); $tableOld->addUnnamedForeignKeyConstraint('test_foreign', ['foo_id'], ['foo_id']); $sqls = []; foreach ($tableOld->getForeignKeys() as $fk) { $sqls[] = $this->platform->getCreateForeignKeySQL($fk, $tableOld); } self::assertEquals(['ALTER TABLE test ADD CONSTRAINT FK_D87F7E0C8E48560F FOREIGN KEY (foo_id) REFERENCES test_foreign (foo_id)'], $sqls); } /** * @group DDC-1737 */ public function testClobNoAlterTable() : void { $tableOld = new Table('test'); $tableOld->addColumn('id', 'integer'); $tableOld->addColumn('description', 'string', ['length' => 65536]); $tableNew = clone $tableOld; $tableNew->setPrimaryKey(['id']); $diff = $this->comparator->diffTable($tableOld, $tableNew); $sql = $this->platform->getAlterTableSQL($diff); self::assertEquals( ['ALTER TABLE test ADD PRIMARY KEY (id)'], $sql ); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Schema/SchemaDiffTest.php000066400000000000000000000117511360544566000263640ustar00rootroot00000000000000createSchemaDiff(); $platform = $this->createPlatform(true); $sql = $diff->toSql($platform); $expected = ['create_schema', 'drop_orphan_fk', 'alter_seq', 'drop_seq', 'create_seq', 'create_table', 'create_foreign_key', 'drop_table', 'alter_table']; self::assertEquals($expected, $sql); } public function testSchemaDiffToSaveSql() : void { $diff = $this->createSchemaDiff(); $platform = $this->createPlatform(false); $sql = $diff->toSaveSql($platform); $expected = ['create_schema', 'alter_seq', 'create_seq', 'create_table', 'create_foreign_key', 'alter_table']; self::assertEquals($expected, $sql); } /** * @return AbstractPlatform|MockObject */ private function createPlatform(bool $unsafe) { /** @var AbstractPlatform|MockObject $platform */ $platform = $this->createMock(AbstractPlatform::class); $platform->expects($this->exactly(1)) ->method('getCreateSchemaSQL') ->with('foo_ns') ->will($this->returnValue('create_schema')); if ($unsafe) { $platform->expects($this->exactly(1)) ->method('getDropSequenceSql') ->with($this->isInstanceOf(Sequence::class)) ->will($this->returnValue('drop_seq')); } $platform->expects($this->exactly(1)) ->method('getAlterSequenceSql') ->with($this->isInstanceOf(Sequence::class)) ->will($this->returnValue('alter_seq')); $platform->expects($this->exactly(1)) ->method('getCreateSequenceSql') ->with($this->isInstanceOf(Sequence::class)) ->will($this->returnValue('create_seq')); if ($unsafe) { $platform->expects($this->exactly(1)) ->method('getDropTableSql') ->with($this->isInstanceOf(Table::class)) ->will($this->returnValue('drop_table')); } $platform->expects($this->exactly(1)) ->method('getCreateTableSql') ->with($this->isInstanceOf(Table::class)) ->will($this->returnValue(['create_table'])); $platform->expects($this->exactly(1)) ->method('getCreateForeignKeySQL') ->with($this->isInstanceOf(ForeignKeyConstraint::class)) ->will($this->returnValue('create_foreign_key')); $platform->expects($this->exactly(1)) ->method('getAlterTableSql') ->with($this->isInstanceOf(TableDiff::class)) ->will($this->returnValue(['alter_table'])); if ($unsafe) { $platform->expects($this->exactly(1)) ->method('getDropForeignKeySql') ->with( $this->isInstanceOf(ForeignKeyConstraint::class), $this->isInstanceOf(Table::class) ) ->will($this->returnValue('drop_orphan_fk')); } $platform->expects($this->exactly(1)) ->method('supportsSchemas') ->will($this->returnValue(true)); $platform->expects($this->exactly(1)) ->method('supportsSequences') ->will($this->returnValue(true)); $platform->expects($this->exactly(2)) ->method('supportsForeignKeyConstraints') ->will($this->returnValue(true)); return $platform; } public function createSchemaDiff() : SchemaDiff { $diff = new SchemaDiff(); $diff->newNamespaces['foo_ns'] = 'foo_ns'; $diff->removedNamespaces['bar_ns'] = 'bar_ns'; $diff->changedSequences['foo_seq'] = new Sequence('foo_seq'); $diff->newSequences['bar_seq'] = new Sequence('bar_seq'); $diff->removedSequences['baz_seq'] = new Sequence('baz_seq'); $diff->newTables['foo_table'] = new Table('foo_table'); $diff->removedTables['bar_table'] = new Table('bar_table'); $diff->changedTables['baz_table'] = new TableDiff('baz_table'); $diff->newTables['foo_table']->addColumn('foreign_id', 'integer'); $diff->newTables['foo_table']->addForeignKeyConstraint('foreign_table', ['foreign_id'], ['id']); $fk = new ForeignKeyConstraint(['id'], 'foreign_table', ['id']); $fk->setLocalTable(new Table('local_table')); $diff->orphanedForeignKeys[] = $fk; return $diff; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Schema/SchemaTest.php000066400000000000000000000323461360544566000255760ustar00rootroot00000000000000hasTable($tableName)); $tables = $schema->getTables(); self::assertArrayHasKey($tableName, $tables); self::assertSame($table, $tables[$tableName]); self::assertSame($table, $schema->getTable($tableName)); self::assertTrue($schema->hasTable($tableName)); } public function testTableMatchingCaseInsensitive() : void { $table = new Table('Foo'); $schema = new Schema([$table]); self::assertTrue($schema->hasTable('foo')); self::assertTrue($schema->hasTable('FOO')); self::assertSame($table, $schema->getTable('FOO')); self::assertSame($table, $schema->getTable('foo')); self::assertSame($table, $schema->getTable('Foo')); } public function testGetUnknownTableThrowsException() : void { $this->expectException(SchemaException::class); $schema = new Schema(); $schema->getTable('unknown'); } public function testCreateTableTwiceThrowsException() : void { $this->expectException(SchemaException::class); $tableName = 'foo'; $table = new Table($tableName); $tables = [$table, $table]; $schema = new Schema($tables); } public function testRenameTable() : void { $tableName = 'foo'; $table = new Table($tableName); $schema = new Schema([$table]); self::assertTrue($schema->hasTable('foo')); $schema->renameTable('foo', 'bar'); self::assertFalse($schema->hasTable('foo')); self::assertTrue($schema->hasTable('bar')); self::assertSame($table, $schema->getTable('bar')); } public function testDropTable() : void { $tableName = 'foo'; $table = new Table($tableName); $schema = new Schema([$table]); self::assertTrue($schema->hasTable('foo')); $schema->dropTable('foo'); self::assertFalse($schema->hasTable('foo')); } public function testCreateTable() : void { $schema = new Schema(); self::assertFalse($schema->hasTable('foo')); $table = $schema->createTable('foo'); self::assertInstanceOf(Table::class, $table); self::assertEquals('foo', $table->getName()); self::assertTrue($schema->hasTable('foo')); } public function testAddSequences() : void { $sequence = new Sequence('a_seq', 1, 1); $schema = new Schema([], [$sequence]); self::assertTrue($schema->hasSequence('a_seq')); self::assertInstanceOf(Sequence::class, $schema->getSequence('a_seq')); $sequences = $schema->getSequences(); self::assertArrayHasKey('public.a_seq', $sequences); } public function testSequenceAccessCaseInsensitive() : void { $sequence = new Sequence('a_Seq'); $schema = new Schema([], [$sequence]); self::assertTrue($schema->hasSequence('a_seq')); self::assertTrue($schema->hasSequence('a_Seq')); self::assertTrue($schema->hasSequence('A_SEQ')); self::assertEquals($sequence, $schema->getSequence('a_seq')); self::assertEquals($sequence, $schema->getSequence('a_Seq')); self::assertEquals($sequence, $schema->getSequence('A_SEQ')); } public function testGetUnknownSequenceThrowsException() : void { $this->expectException(SchemaException::class); $schema = new Schema(); $schema->getSequence('unknown'); } public function testCreateSequence() : void { $schema = new Schema(); $sequence = $schema->createSequence('a_seq', 10, 20); self::assertEquals('a_seq', $sequence->getName()); self::assertEquals(10, $sequence->getAllocationSize()); self::assertEquals(20, $sequence->getInitialValue()); self::assertTrue($schema->hasSequence('a_seq')); self::assertInstanceOf(Sequence::class, $schema->getSequence('a_seq')); $sequences = $schema->getSequences(); self::assertArrayHasKey('public.a_seq', $sequences); } public function testDropSequence() : void { $sequence = new Sequence('a_seq', 1, 1); $schema = new Schema([], [$sequence]); $schema->dropSequence('a_seq'); self::assertFalse($schema->hasSequence('a_seq')); } public function testAddSequenceTwiceThrowsException() : void { $this->expectException(SchemaException::class); $sequence = new Sequence('a_seq', 1, 1); $schema = new Schema([], [$sequence, $sequence]); } public function testConfigMaxIdentifierLength() : void { $schemaConfig = new SchemaConfig(); $schemaConfig->setMaxIdentifierLength(5); $schema = new Schema([], [], $schemaConfig); $table = $schema->createTable('smalltable'); $table->addColumn('long_id', 'integer'); $table->addIndex(['long_id']); $index = current($table->getIndexes()); self::assertEquals(5, strlen($index->getName())); } public function testDeepClone() : void { $schema = new Schema(); $sequence = $schema->createSequence('baz'); $tableA = $schema->createTable('foo'); $tableA->addColumn('id', 'integer'); $tableB = $schema->createTable('bar'); $tableB->addColumn('id', 'integer'); $tableB->addColumn('foo_id', 'integer'); $tableB->addForeignKeyConstraint($tableA, ['foo_id'], ['id']); $schemaNew = clone $schema; self::assertNotSame($sequence, $schemaNew->getSequence('baz')); self::assertNotSame($tableA, $schemaNew->getTable('foo')); self::assertNotSame($tableA->getColumn('id'), $schemaNew->getTable('foo')->getColumn('id')); self::assertNotSame($tableB, $schemaNew->getTable('bar')); self::assertNotSame($tableB->getColumn('id'), $schemaNew->getTable('bar')->getColumn('id')); $fk = $schemaNew->getTable('bar')->getForeignKeys(); $fk = current($fk); $re = new ReflectionProperty($fk, '_localTable'); $re->setAccessible(true); self::assertSame($schemaNew->getTable('bar'), $re->getValue($fk)); } /** * @group DBAL-219 */ public function testHasTableForQuotedAsset() : void { $schema = new Schema(); $tableA = $schema->createTable('foo'); $tableA->addColumn('id', 'integer'); self::assertTrue($schema->hasTable('`foo`')); } /** * @group DBAL-669 */ public function testHasNamespace() : void { $schema = new Schema(); self::assertFalse($schema->hasNamespace('foo')); $schema->createTable('foo'); self::assertFalse($schema->hasNamespace('foo')); $schema->createTable('bar.baz'); self::assertFalse($schema->hasNamespace('baz')); self::assertTrue($schema->hasNamespace('bar')); self::assertFalse($schema->hasNamespace('tab')); $schema->createTable('tab.taz'); self::assertTrue($schema->hasNamespace('tab')); } /** * @group DBAL-669 */ public function testCreatesNamespace() : void { $schema = new Schema(); self::assertFalse($schema->hasNamespace('foo')); $schema->createNamespace('foo'); self::assertTrue($schema->hasNamespace('foo')); self::assertTrue($schema->hasNamespace('FOO')); self::assertTrue($schema->hasNamespace('`foo`')); self::assertTrue($schema->hasNamespace('`FOO`')); $schema->createNamespace('`bar`'); self::assertTrue($schema->hasNamespace('bar')); self::assertTrue($schema->hasNamespace('BAR')); self::assertTrue($schema->hasNamespace('`bar`')); self::assertTrue($schema->hasNamespace('`BAR`')); self::assertSame(['foo' => 'foo', 'bar' => '`bar`'], $schema->getNamespaces()); } /** * @group DBAL-669 */ public function testThrowsExceptionOnCreatingNamespaceTwice() : void { $schema = new Schema(); $schema->createNamespace('foo'); $this->expectException(SchemaException::class); $schema->createNamespace('foo'); } /** * @group DBAL-669 */ public function testCreatesNamespaceThroughAddingTableImplicitly() : void { $schema = new Schema(); self::assertFalse($schema->hasNamespace('foo')); $schema->createTable('baz'); self::assertFalse($schema->hasNamespace('foo')); self::assertFalse($schema->hasNamespace('baz')); $schema->createTable('foo.bar'); self::assertTrue($schema->hasNamespace('foo')); self::assertFalse($schema->hasNamespace('bar')); $schema->createTable('`baz`.bloo'); self::assertTrue($schema->hasNamespace('baz')); self::assertFalse($schema->hasNamespace('bloo')); $schema->createTable('`baz`.moo'); self::assertTrue($schema->hasNamespace('baz')); self::assertFalse($schema->hasNamespace('moo')); } /** * @group DBAL-669 */ public function testCreatesNamespaceThroughAddingSequenceImplicitly() : void { $schema = new Schema(); self::assertFalse($schema->hasNamespace('foo')); $schema->createSequence('baz'); self::assertFalse($schema->hasNamespace('foo')); self::assertFalse($schema->hasNamespace('baz')); $schema->createSequence('foo.bar'); self::assertTrue($schema->hasNamespace('foo')); self::assertFalse($schema->hasNamespace('bar')); $schema->createSequence('`baz`.bloo'); self::assertTrue($schema->hasNamespace('baz')); self::assertFalse($schema->hasNamespace('bloo')); $schema->createSequence('`baz`.moo'); self::assertTrue($schema->hasNamespace('baz')); self::assertFalse($schema->hasNamespace('moo')); } /** * @group DBAL-669 */ public function testVisitsVisitor() : void { $schema = new Schema(); $visitor = $this->createMock(Visitor::class); $schema->createNamespace('foo'); $schema->createNamespace('bar'); $schema->createTable('baz'); $schema->createTable('bla.bloo'); $schema->createSequence('moo'); $schema->createSequence('war'); $visitor->expects($this->once()) ->method('acceptSchema') ->with($schema); $visitor->expects($this->at(1)) ->method('acceptTable') ->with($schema->getTable('baz')); $visitor->expects($this->at(2)) ->method('acceptTable') ->with($schema->getTable('bla.bloo')); $visitor->expects($this->exactly(2)) ->method('acceptTable'); $visitor->expects($this->at(3)) ->method('acceptSequence') ->with($schema->getSequence('moo')); $visitor->expects($this->at(4)) ->method('acceptSequence') ->with($schema->getSequence('war')); $visitor->expects($this->exactly(2)) ->method('acceptSequence'); self::assertNull($schema->visit($visitor)); } /** * @group DBAL-669 */ public function testVisitsNamespaceVisitor() : void { $schema = new Schema(); $visitor = $this->createMock(AbstractVisitor::class); $schema->createNamespace('foo'); $schema->createNamespace('bar'); $schema->createTable('baz'); $schema->createTable('bla.bloo'); $schema->createSequence('moo'); $schema->createSequence('war'); $visitor->expects($this->once()) ->method('acceptSchema') ->with($schema); $visitor->expects($this->at(1)) ->method('acceptNamespace') ->with('foo'); $visitor->expects($this->at(2)) ->method('acceptNamespace') ->with('bar'); $visitor->expects($this->at(3)) ->method('acceptNamespace') ->with('bla'); $visitor->expects($this->exactly(3)) ->method('acceptNamespace'); $visitor->expects($this->at(4)) ->method('acceptTable') ->with($schema->getTable('baz')); $visitor->expects($this->at(5)) ->method('acceptTable') ->with($schema->getTable('bla.bloo')); $visitor->expects($this->exactly(2)) ->method('acceptTable'); $visitor->expects($this->at(6)) ->method('acceptSequence') ->with($schema->getSequence('moo')); $visitor->expects($this->at(7)) ->method('acceptSequence') ->with($schema->getSequence('war')); $visitor->expects($this->exactly(2)) ->method('acceptSequence'); self::assertNull($schema->visit($visitor)); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Schema/SequenceTest.php000066400000000000000000000031131360544566000261340ustar00rootroot00000000000000addColumn('id', 'integer', ['autoincrement' => true]); $table->setPrimaryKey(['id']); $sequence = new Sequence('foo_id_seq'); $sequence2 = new Sequence('bar_id_seq'); $sequence3 = new Sequence('other.foo_id_seq'); self::assertTrue($sequence->isAutoIncrementsFor($table)); self::assertFalse($sequence2->isAutoIncrementsFor($table)); self::assertFalse($sequence3->isAutoIncrementsFor($table)); } public function testIsAutoincrementForCaseInsensitive() : void { $table = new Table('foo'); $table->addColumn('ID', 'integer', ['autoincrement' => true]); $table->setPrimaryKey(['ID']); $sequence = new Sequence('foo_id_seq'); $sequence1 = new Sequence('foo_ID_seq'); $sequence2 = new Sequence('bar_id_seq'); $sequence3 = new Sequence('bar_ID_seq'); $sequence4 = new Sequence('other.foo_id_seq'); self::assertTrue($sequence->isAutoIncrementsFor($table)); self::assertTrue($sequence1->isAutoIncrementsFor($table)); self::assertFalse($sequence2->isAutoIncrementsFor($table)); self::assertFalse($sequence3->isAutoIncrementsFor($table)); self::assertFalse($sequence4->isAutoIncrementsFor($table)); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Schema/SqliteSchemaManagerTest.php000066400000000000000000000303161360544566000302460ustar00rootroot00000000000000createMock(Connection::class); $conn->method('getDatabasePlatform')->willReturn(new SqlitePlatform()); $manager = new SqliteSchemaManager($conn); $ref = new ReflectionMethod($manager, 'parseColumnCollationFromSQL'); $ref->setAccessible(true); self::assertSame($collation, $ref->invoke($manager, $column, $sql)); } /** * @return mixed[][] */ public static function getDataColumnCollation() : iterable { return [ ['RTRIM', 'a', 'CREATE TABLE "a" ("a" text DEFAULT "aa" COLLATE "RTRIM" NOT NULL)'], ['utf-8', 'a', 'CREATE TABLE "a" ("b" text UNIQUE NOT NULL COLLATE NOCASE, "a" text DEFAULT "aa" COLLATE "utf-8" NOT NULL)'], ['NOCASE', 'a', 'CREATE TABLE "a" ("a" text DEFAULT (lower(ltrim(" a") || rtrim("a "))) CHECK ("a") NOT NULL COLLATE NOCASE UNIQUE, "b" text COLLATE RTRIM)'], [null, 'a', 'CREATE TABLE "a" ("a" text CHECK ("a") NOT NULL, "b" text COLLATE RTRIM)'], ['RTRIM', 'a"b', 'CREATE TABLE "a" ("a""b" text COLLATE RTRIM)'], ['BINARY', 'b', 'CREATE TABLE "a" (bb TEXT COLLATE RTRIM, b VARCHAR(42) NOT NULL COLLATE BINARY)'], ['BINARY', 'b', 'CREATE TABLE "a" (bbb TEXT COLLATE NOCASE, bb TEXT COLLATE RTRIM, b VARCHAR(42) NOT NULL COLLATE BINARY)'], ['BINARY', 'b', 'CREATE TABLE "a" (b VARCHAR(42) NOT NULL COLLATE BINARY, bb TEXT COLLATE RTRIM)'], ['utf-8', 'bar#', 'CREATE TABLE dummy_table (id INTEGER NOT NULL, foo VARCHAR(255) COLLATE "utf-8" NOT NULL, "bar#" VARCHAR(255) COLLATE "utf-8" NOT NULL, baz VARCHAR(255) COLLATE "utf-8" NOT NULL, PRIMARY KEY(id))'], [null, 'bar#', 'CREATE TABLE dummy_table (id INTEGER NOT NULL, foo VARCHAR(255) NOT NULL, "bar#" VARCHAR(255) NOT NULL, baz VARCHAR(255) NOT NULL, PRIMARY KEY(id))'], ['utf-8', 'baz', 'CREATE TABLE dummy_table (id INTEGER NOT NULL, foo VARCHAR(255) COLLATE "utf-8" NOT NULL, "bar#" INTEGER NOT NULL, baz VARCHAR(255) COLLATE "utf-8" NOT NULL, PRIMARY KEY(id))'], [null, 'baz', 'CREATE TABLE dummy_table (id INTEGER NOT NULL, foo VARCHAR(255) NOT NULL, "bar#" INTEGER NOT NULL, baz VARCHAR(255) NOT NULL, PRIMARY KEY(id))'], ['utf-8', 'bar/', 'CREATE TABLE dummy_table (id INTEGER NOT NULL, foo VARCHAR(255) COLLATE "utf-8" NOT NULL, "bar/" VARCHAR(255) COLLATE "utf-8" NOT NULL, baz VARCHAR(255) COLLATE "utf-8" NOT NULL, PRIMARY KEY(id))'], [null, 'bar/', 'CREATE TABLE dummy_table (id INTEGER NOT NULL, foo VARCHAR(255) NOT NULL, "bar/" VARCHAR(255) NOT NULL, baz VARCHAR(255) NOT NULL, PRIMARY KEY(id))'], ['utf-8', 'baz', 'CREATE TABLE dummy_table (id INTEGER NOT NULL, foo VARCHAR(255) COLLATE "utf-8" NOT NULL, "bar/" INTEGER NOT NULL, baz VARCHAR(255) COLLATE "utf-8" NOT NULL, PRIMARY KEY(id))'], [null, 'baz', 'CREATE TABLE dummy_table (id INTEGER NOT NULL, foo VARCHAR(255) NOT NULL, "bar/" INTEGER NOT NULL, baz VARCHAR(255) NOT NULL, PRIMARY KEY(id))'], ]; } /** * @dataProvider getDataColumnComment * @group 2865 */ public function testParseColumnCommentFromSQL(?string $comment, string $column, string $sql) : void { $conn = $this->createMock(Connection::class); $conn->method('getDatabasePlatform')->willReturn(new SqlitePlatform()); $manager = new SqliteSchemaManager($conn); $ref = new ReflectionMethod($manager, 'parseColumnCommentFromSQL'); $ref->setAccessible(true); self::assertSame($comment, $ref->invoke($manager, $column, $sql)); } /** * @return mixed[][] */ public static function getDataColumnComment() : iterable { return [ 'Single column with no comment' => [ null, 'a', 'CREATE TABLE "a" ("a" TEXT DEFAULT "a" COLLATE RTRIM)', ], 'Single column with type comment' => [ '(DC2Type:x)', 'a', 'CREATE TABLE "a" ("a" CLOB DEFAULT NULL COLLATE BINARY --(DC2Type:x) )', ], 'Multiple similar columns with type comment 1' => [ null, 'b', 'CREATE TABLE "a" (a TEXT COLLATE RTRIM, "b" TEXT DEFAULT "a" COLLATE RTRIM, "bb" CLOB DEFAULT NULL COLLATE BINARY --(DC2Type:x) )', ], 'Multiple similar columns with type comment 2' => [ '(DC2Type:x)', 'b', 'CREATE TABLE "a" (a TEXT COLLATE RTRIM, "bb" TEXT DEFAULT "a" COLLATE RTRIM, "b" CLOB DEFAULT NULL COLLATE BINARY --(DC2Type:x) )', ], 'Multiple similar columns on different lines, with type comment 1' => [ null, 'bb', 'CREATE TABLE "a" (a TEXT COLLATE RTRIM, "b" CLOB DEFAULT NULL COLLATE BINARY --(DC2Type:x) , "bb" TEXT DEFAULT "a" COLLATE RTRIM', ], 'Multiple similar columns on different lines, with type comment 2' => [ '(DC2Type:x)', 'bb', 'CREATE TABLE "a" (a TEXT COLLATE RTRIM, "bb" CLOB DEFAULT NULL COLLATE BINARY --(DC2Type:x) , "b" TEXT DEFAULT "a" COLLATE RTRIM', ], 'Column with numeric but no comment 1' => [ null, 'a', 'CREATE TABLE "a" ("a" NUMERIC(10, 0) NOT NULL, "b" CLOB NOT NULL --(DC2Type:array) , "c" CHAR(36) NOT NULL --(DC2Type:guid) )', ], 'Column with numeric but no comment 2' => [ null, 'a', 'CREATE TABLE "b" ("a" NUMERIC(10, 0) NOT NULL, "b" CLOB NOT NULL --(DC2Type:array) , "c" CHAR(36) NOT NULL --(DC2Type:guid) )', ], 'Column with numeric but no comment 3' => [ '(DC2Type:guid)', 'c', 'CREATE TABLE "b" ("a" NUMERIC(10, 0) NOT NULL, "b" CLOB NOT NULL --(DC2Type:array) , "c" CHAR(36) NOT NULL --(DC2Type:guid) )', ], 'Column with numeric but no comment 4' => [ '(DC2Type:array)', 'b', 'CREATE TABLE "b" ("a" NUMERIC(10, 0) NOT NULL, "b" CLOB NOT NULL, --(DC2Type:array) "c" CHAR(36) NOT NULL --(DC2Type:guid) )', ], 'Column "bar", select "bar" with no comment' => [ null, 'bar', 'CREATE TABLE dummy_table ( id INTEGER NOT NULL, foo VARCHAR(255) COLLATE "utf-8" NOT NULL, "bar" VARCHAR(255) COLLATE "utf-8" NOT NULL, baz VARCHAR(255) COLLATE "utf-8" NOT NULL, PRIMARY KEY(id) )', ], 'Column "bar", select "bar" with type comment' => [ '(DC2Type:x)', 'bar', 'CREATE TABLE dummy_table ( id INTEGER NOT NULL, foo VARCHAR(255) COLLATE "utf-8" NOT NULL, "bar" VARCHAR(255) COLLATE "utf-8" NOT NULL, --(DC2Type:x) baz VARCHAR(255) COLLATE "utf-8" NOT NULL, --(DC2Type:y) PRIMARY KEY(id) )', ], 'Column "bar", select "baz" with no comment' => [ null, 'baz', 'CREATE TABLE dummy_table ( id INTEGER NOT NULL, foo VARCHAR(255) COLLATE "utf-8" NOT NULL, "bar" INTEGER NOT NULL, baz VARCHAR(255) COLLATE "utf-8" NOT NULL, PRIMARY KEY(id) )', ], 'Column "bar", select "baz" with type comment' => [ '(DC2Type:y)', 'baz', 'CREATE TABLE dummy_table ( id INTEGER NOT NULL, foo VARCHAR(255) COLLATE "utf-8" NOT NULL, "bar" INTEGER NOT NULL, --(DC2Type:x) baz VARCHAR(255) COLLATE "utf-8" NOT NULL, --(DC2Type:y) PRIMARY KEY(id) )', ], 'Column "bar#", select "bar#" with no comment' => [ null, 'bar#', 'CREATE TABLE dummy_table ( id INTEGER NOT NULL, foo VARCHAR(255) COLLATE "utf-8" NOT NULL, "bar#" VARCHAR(255) COLLATE "utf-8" NOT NULL, baz VARCHAR(255) COLLATE "utf-8" NOT NULL, PRIMARY KEY(id) )', ], 'Column "bar#", select "bar#" with type comment' => [ '(DC2Type:x)', 'bar#', 'CREATE TABLE dummy_table ( id INTEGER NOT NULL, foo VARCHAR(255) COLLATE "utf-8" NOT NULL, "bar#" VARCHAR(255) COLLATE "utf-8" NOT NULL, --(DC2Type:x) baz VARCHAR(255) COLLATE "utf-8" NOT NULL, --(DC2Type:y) PRIMARY KEY(id) )', ], 'Column "bar#", select "baz" with no comment' => [ null, 'baz', 'CREATE TABLE dummy_table ( id INTEGER NOT NULL, foo VARCHAR(255) COLLATE "utf-8" NOT NULL, "bar#" INTEGER NOT NULL, baz VARCHAR(255) COLLATE "utf-8" NOT NULL, PRIMARY KEY(id) )', ], 'Column "bar#", select "baz" with type comment' => [ '(DC2Type:y)', 'baz', 'CREATE TABLE dummy_table ( id INTEGER NOT NULL, foo VARCHAR(255) COLLATE "utf-8" NOT NULL, "bar#" INTEGER NOT NULL, --(DC2Type:x) baz VARCHAR(255) COLLATE "utf-8" NOT NULL, --(DC2Type:y) PRIMARY KEY(id) )', ], 'Column "bar/", select "bar/" with no comment' => [ null, 'bar/', 'CREATE TABLE dummy_table ( id INTEGER NOT NULL, foo VARCHAR(255) COLLATE "utf-8" NOT NULL, "bar/" VARCHAR(255) COLLATE "utf-8" NOT NULL, baz VARCHAR(255) COLLATE "utf-8" NOT NULL, PRIMARY KEY(id) )', ], 'Column "bar/", select "bar/" with type comment' => [ '(DC2Type:x)', 'bar/', 'CREATE TABLE dummy_table ( id INTEGER NOT NULL, foo VARCHAR(255) COLLATE "utf-8" NOT NULL, "bar/" VARCHAR(255) COLLATE "utf-8" NOT NULL, --(DC2Type:x) baz VARCHAR(255) COLLATE "utf-8" NOT NULL, --(DC2Type:y) PRIMARY KEY(id) )', ], 'Column "bar/", select "baz" with no comment' => [ null, 'baz', 'CREATE TABLE dummy_table ( id INTEGER NOT NULL, foo VARCHAR(255) COLLATE "utf-8" NOT NULL, "bar/" INTEGER NOT NULL, baz VARCHAR(255) COLLATE "utf-8" NOT NULL, PRIMARY KEY(id) )', ], 'Column "bar/", select "baz" with type comment' => [ '(DC2Type:y)', 'baz', 'CREATE TABLE dummy_table ( id INTEGER NOT NULL, foo VARCHAR(255) COLLATE "utf-8" NOT NULL, "bar/" INTEGER COLLATE "utf-8" NOT NULL, --(DC2Type:x) baz VARCHAR(255) COLLATE "utf-8" NOT NULL, --(DC2Type:y) PRIMARY KEY(id) )', ], ]; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Schema/Synchronizer/000077500000000000000000000000001360544566000255125ustar00rootroot00000000000000SingleDatabaseSynchronizerTest.php000066400000000000000000000043611360544566000342740ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Schema/Synchronizerconn = DriverManager::getConnection([ 'driver' => 'pdo_sqlite', 'memory' => true, ]); $this->synchronizer = new SingleDatabaseSynchronizer($this->conn); } public function testGetCreateSchema() : void { $schema = new Schema(); $table = $schema->createTable('test'); $table->addColumn('id', 'integer'); $table->setPrimaryKey(['id']); $sql = $this->synchronizer->getCreateSchema($schema); self::assertEquals(['CREATE TABLE test (id INTEGER NOT NULL, PRIMARY KEY(id))'], $sql); } public function testGetUpdateSchema() : void { $schema = new Schema(); $table = $schema->createTable('test'); $table->addColumn('id', 'integer'); $table->setPrimaryKey(['id']); $sql = $this->synchronizer->getUpdateSchema($schema); self::assertEquals(['CREATE TABLE test (id INTEGER NOT NULL, PRIMARY KEY(id))'], $sql); } public function testGetDropSchema() : void { $schema = new Schema(); $table = $schema->createTable('test'); $table->addColumn('id', 'integer'); $table->setPrimaryKey(['id']); $this->synchronizer->createSchema($schema); $sql = $this->synchronizer->getDropSchema($schema); self::assertEquals(['DROP TABLE test'], $sql); } public function testGetDropAllSchema() : void { $schema = new Schema(); $table = $schema->createTable('test'); $table->addColumn('id', 'integer'); $table->setPrimaryKey(['id']); $this->synchronizer->createSchema($schema); $sql = $this->synchronizer->getDropAllSchema(); self::assertEquals(['DROP TABLE test'], $sql); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Schema/TableDiffTest.php000066400000000000000000000031461360544566000262120ustar00rootroot00000000000000platform = $this->createMock(AbstractPlatform::class); } /** * @group DBAL-1013 */ public function testReturnsName() : void { $tableDiff = new TableDiff('foo'); self::assertEquals(new Identifier('foo'), $tableDiff->getName($this->platform)); } /** * @group DBAL-1016 */ public function testPrefersNameFromTableObject() : void { $tableMock = $this->getMockBuilder(Table::class) ->disableOriginalConstructor() ->getMock(); $tableDiff = new TableDiff('foo'); $tableDiff->fromTable = $tableMock; $tableMock->expects($this->once()) ->method('getQuotedName') ->with($this->platform) ->will($this->returnValue('foo')); self::assertEquals(new Identifier('foo'), $tableDiff->getName($this->platform)); } /** * @group DBAL-1013 */ public function testReturnsNewName() : void { $tableDiff = new TableDiff('foo'); self::assertFalse($tableDiff->getNewName()); $tableDiff->newName = 'bar'; self::assertEquals(new Identifier('bar'), $tableDiff->getNewName()); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Schema/TableTest.php000066400000000000000000000731711360544566000254260ustar00rootroot00000000000000expectException(DBALException::class); new Table(''); } public function testGetName() : void { $table = new Table('foo', [], [], []); self::assertEquals('foo', $table->getName()); } public function testColumns() : void { $type = Type::getType('integer'); $columns = []; $columns[] = new Column('foo', $type); $columns[] = new Column('bar', $type); $table = new Table('foo', $columns, [], []); self::assertTrue($table->hasColumn('foo')); self::assertTrue($table->hasColumn('bar')); self::assertFalse($table->hasColumn('baz')); self::assertInstanceOf(Column::class, $table->getColumn('foo')); self::assertInstanceOf(Column::class, $table->getColumn('bar')); self::assertCount(2, $table->getColumns()); } public function testColumnsCaseInsensitive() : void { $table = new Table('foo'); $column = $table->addColumn('Foo', 'integer'); self::assertTrue($table->hasColumn('Foo')); self::assertTrue($table->hasColumn('foo')); self::assertTrue($table->hasColumn('FOO')); self::assertSame($column, $table->getColumn('Foo')); self::assertSame($column, $table->getColumn('foo')); self::assertSame($column, $table->getColumn('FOO')); } public function testCreateColumn() : void { $type = Type::getType('integer'); $table = new Table('foo'); self::assertFalse($table->hasColumn('bar')); $table->addColumn('bar', 'integer'); self::assertTrue($table->hasColumn('bar')); self::assertSame($type, $table->getColumn('bar')->getType()); } public function testDropColumn() : void { $type = Type::getType('integer'); $columns = []; $columns[] = new Column('foo', $type); $columns[] = new Column('bar', $type); $table = new Table('foo', $columns, [], []); self::assertTrue($table->hasColumn('foo')); self::assertTrue($table->hasColumn('bar')); $table->dropColumn('foo')->dropColumn('bar'); self::assertFalse($table->hasColumn('foo')); self::assertFalse($table->hasColumn('bar')); } public function testGetUnknownColumnThrowsException() : void { $this->expectException(SchemaException::class); $table = new Table('foo', [], [], []); $table->getColumn('unknown'); } public function testAddColumnTwiceThrowsException() : void { $this->expectException(SchemaException::class); $type = Type::getType('integer'); $columns = []; $columns[] = new Column('foo', $type); $columns[] = new Column('foo', $type); $table = new Table('foo', $columns, [], []); } public function testCreateIndex() : void { $type = Type::getType('integer'); $columns = [new Column('foo', $type), new Column('bar', $type), new Column('baz', $type)]; $table = new Table('foo', $columns); $table->addIndex(['foo', 'bar'], 'foo_foo_bar_idx'); $table->addUniqueIndex(['bar', 'baz'], 'foo_bar_baz_uniq'); self::assertTrue($table->hasIndex('foo_foo_bar_idx')); self::assertTrue($table->hasIndex('foo_bar_baz_uniq')); } public function testIndexCaseInsensitive() : void { $type = Type::getType('integer'); $columns = [ new Column('foo', $type), new Column('bar', $type), new Column('baz', $type), ]; $table = new Table('foo', $columns); $table->addIndex(['foo', 'bar', 'baz'], 'Foo_Idx'); self::assertTrue($table->hasIndex('foo_idx')); self::assertTrue($table->hasIndex('Foo_Idx')); self::assertTrue($table->hasIndex('FOO_IDX')); } public function testAddIndexes() : void { $type = Type::getType('integer'); $columns = [ new Column('foo', $type), new Column('bar', $type), ]; $indexes = [ new Index('the_primary', ['foo'], true, true), new Index('bar_idx', ['bar'], false, false), ]; $table = new Table('foo', $columns, $indexes, []); self::assertTrue($table->hasIndex('the_primary')); self::assertTrue($table->hasIndex('bar_idx')); self::assertFalse($table->hasIndex('some_idx')); self::assertInstanceOf(Index::class, $table->getPrimaryKey()); self::assertInstanceOf(Index::class, $table->getIndex('the_primary')); self::assertInstanceOf(Index::class, $table->getIndex('bar_idx')); } public function testGetUnknownIndexThrowsException() : void { $this->expectException(SchemaException::class); $table = new Table('foo', [], [], []); $table->getIndex('unknownIndex'); } public function testAddTwoPrimaryThrowsException() : void { $this->expectException(SchemaException::class); $type = Type::getType('integer'); $columns = [new Column('foo', $type), new Column('bar', $type)]; $indexes = [ new Index('the_primary', ['foo'], true, true), new Index('other_primary', ['bar'], true, true), ]; $table = new Table('foo', $columns, $indexes, []); } public function testAddTwoIndexesWithSameNameThrowsException() : void { $this->expectException(SchemaException::class); $type = Type::getType('integer'); $columns = [new Column('foo', $type), new Column('bar', $type)]; $indexes = [ new Index('an_idx', ['foo'], false, false), new Index('an_idx', ['bar'], false, false), ]; $table = new Table('foo', $columns, $indexes, []); } public function testConstraints() : void { $constraint = new ForeignKeyConstraint([], 'foo', []); $tableA = new Table('foo', [], [], [$constraint]); $constraints = $tableA->getForeignKeys(); self::assertCount(1, $constraints); self::assertSame($constraint, array_shift($constraints)); } public function testOptions() : void { $table = new Table('foo', [], [], [], false, ['foo' => 'bar']); self::assertTrue($table->hasOption('foo')); self::assertEquals('bar', $table->getOption('foo')); } public function testBuilderSetPrimaryKey() : void { $table = new Table('foo'); $table->addColumn('bar', 'integer'); $table->setPrimaryKey(['bar']); self::assertTrue($table->hasIndex('primary')); self::assertInstanceOf(Index::class, $table->getPrimaryKey()); self::assertTrue($table->getIndex('primary')->isUnique()); self::assertTrue($table->getIndex('primary')->isPrimary()); } public function testBuilderAddUniqueIndex() : void { $table = new Table('foo'); $table->addColumn('bar', 'integer'); $table->addUniqueIndex(['bar'], 'my_idx'); self::assertTrue($table->hasIndex('my_idx')); self::assertTrue($table->getIndex('my_idx')->isUnique()); self::assertFalse($table->getIndex('my_idx')->isPrimary()); } public function testBuilderAddIndex() : void { $table = new Table('foo'); $table->addColumn('bar', 'integer'); $table->addIndex(['bar'], 'my_idx'); self::assertTrue($table->hasIndex('my_idx')); self::assertFalse($table->getIndex('my_idx')->isUnique()); self::assertFalse($table->getIndex('my_idx')->isPrimary()); } public function testBuilderAddIndexWithInvalidNameThrowsException() : void { $this->expectException(SchemaException::class); $table = new Table('foo'); $table->addColumn('bar', 'integer'); $table->addIndex(['bar'], 'invalid name %&/'); } public function testBuilderAddIndexWithUnknownColumnThrowsException() : void { $this->expectException(SchemaException::class); $table = new Table('foo'); $table->addIndex(['bar'], 'invalidName'); } public function testBuilderOptions() : void { $table = new Table('foo'); $table->addOption('foo', 'bar'); self::assertTrue($table->hasOption('foo')); self::assertEquals('bar', $table->getOption('foo')); } public function testAddForeignKeyConstraintUnknownLocalColumnThrowsException() : void { $this->expectException(SchemaException::class); $table = new Table('foo'); $table->addColumn('id', 'integer'); $foreignTable = new Table('bar'); $foreignTable->addColumn('id', 'integer'); $table->addForeignKeyConstraint($foreignTable, ['foo'], ['id']); } public function testAddForeignKeyConstraintUnknownForeignColumnThrowsException() : void { $this->expectException(SchemaException::class); $table = new Table('foo'); $table->addColumn('id', 'integer'); $foreignTable = new Table('bar'); $foreignTable->addColumn('id', 'integer'); $table->addForeignKeyConstraint($foreignTable, ['id'], ['foo']); } public function testAddForeignKeyConstraint() : void { $table = new Table('foo'); $table->addColumn('id', 'integer'); $foreignTable = new Table('bar'); $foreignTable->addColumn('id', 'integer'); $table->addForeignKeyConstraint($foreignTable, ['id'], ['id'], ['foo' => 'bar']); $constraints = $table->getForeignKeys(); self::assertCount(1, $constraints); $constraint = current($constraints); self::assertInstanceOf(ForeignKeyConstraint::class, $constraint); self::assertTrue($constraint->hasOption('foo')); self::assertEquals('bar', $constraint->getOption('foo')); } public function testAddIndexWithCaseSensitiveColumnProblem() : void { $table = new Table('foo'); $table->addColumn('id', 'integer'); $table->addIndex(['ID'], 'my_idx'); self::assertTrue($table->hasIndex('my_idx')); self::assertEquals(['ID'], $table->getIndex('my_idx')->getColumns()); self::assertTrue($table->getIndex('my_idx')->spansColumns(['id'])); } public function testAddPrimaryKeyColumnsAreExplicitlySetToNotNull() : void { $table = new Table('foo'); $column = $table->addColumn('id', 'integer', ['notnull' => false]); self::assertFalse($column->getNotnull()); $table->setPrimaryKey(['id']); self::assertTrue($column->getNotnull()); } /** * @group DDC-133 */ public function testAllowImplicitSchemaTableInAutogeneratedIndexNames() : void { $table = new Table('foo.bar'); $table->addColumn('baz', 'integer', []); $table->addIndex(['baz']); self::assertCount(1, $table->getIndexes()); } /** * @group DBAL-50 */ public function testAddForeignKeyIndexImplicitly() : void { $table = new Table('foo'); $table->addColumn('id', 'integer'); $foreignTable = new Table('bar'); $foreignTable->addColumn('id', 'integer'); $table->addForeignKeyConstraint($foreignTable, ['id'], ['id'], ['foo' => 'bar']); $indexes = $table->getIndexes(); self::assertCount(1, $indexes); $index = current($indexes); self::assertTrue($table->hasIndex($index->getName())); self::assertEquals(['id'], $index->getColumns()); } /** * @group DBAL-1063 */ public function testAddForeignKeyDoesNotCreateDuplicateIndex() : void { $table = new Table('foo'); $table->addColumn('bar', 'integer'); $table->addIndex(['bar'], 'bar_idx'); $foreignTable = new Table('bar'); $foreignTable->addColumn('foo', 'integer'); $table->addForeignKeyConstraint($foreignTable, ['bar'], ['foo']); self::assertCount(1, $table->getIndexes()); self::assertTrue($table->hasIndex('bar_idx')); self::assertSame(['bar'], $table->getIndex('bar_idx')->getColumns()); } /** * @group DBAL-1063 */ public function testAddForeignKeyAddsImplicitIndexIfIndexColumnsDoNotSpan() : void { $table = new Table('foo'); $table->addColumn('bar', 'integer'); $table->addColumn('baz', 'string'); $table->addColumn('bloo', 'string'); $table->addIndex(['baz', 'bar'], 'composite_idx'); $table->addIndex(['bar', 'baz', 'bloo'], 'full_idx'); $foreignTable = new Table('bar'); $foreignTable->addColumn('foo', 'integer'); $foreignTable->addColumn('baz', 'string'); $table->addForeignKeyConstraint($foreignTable, ['bar', 'baz'], ['foo', 'baz']); self::assertCount(3, $table->getIndexes()); self::assertTrue($table->hasIndex('composite_idx')); self::assertTrue($table->hasIndex('full_idx')); self::assertTrue($table->hasIndex('idx_8c73652176ff8caa78240498')); self::assertSame(['baz', 'bar'], $table->getIndex('composite_idx')->getColumns()); self::assertSame(['bar', 'baz', 'bloo'], $table->getIndex('full_idx')->getColumns()); self::assertSame(['bar', 'baz'], $table->getIndex('idx_8c73652176ff8caa78240498')->getColumns()); } /** * @group DBAL-50 * @group DBAL-1063 */ public function testOverrulingIndexDoesNotDropOverruledIndex() : void { $table = new Table('bar'); $table->addColumn('baz', 'integer', []); $table->addIndex(['baz']); $indexes = $table->getIndexes(); self::assertCount(1, $indexes); $index = current($indexes); $table->addUniqueIndex(['baz']); self::assertCount(2, $table->getIndexes()); self::assertTrue($table->hasIndex($index->getName())); } /** * @group DBAL-1063 */ public function testAllowsAddingDuplicateIndexesBasedOnColumns() : void { $table = new Table('foo'); $table->addColumn('bar', 'integer'); $table->addIndex(['bar'], 'bar_idx'); $table->addIndex(['bar'], 'duplicate_idx'); self::assertCount(2, $table->getIndexes()); self::assertTrue($table->hasIndex('bar_idx')); self::assertTrue($table->hasIndex('duplicate_idx')); self::assertSame(['bar'], $table->getIndex('bar_idx')->getColumns()); self::assertSame(['bar'], $table->getIndex('duplicate_idx')->getColumns()); } /** * @group DBAL-1063 */ public function testAllowsAddingFulfillingIndexesBasedOnColumns() : void { $table = new Table('foo'); $table->addColumn('bar', 'integer'); $table->addColumn('baz', 'string'); $table->addIndex(['bar'], 'bar_idx'); $table->addIndex(['bar', 'baz'], 'fulfilling_idx'); self::assertCount(2, $table->getIndexes()); self::assertTrue($table->hasIndex('bar_idx')); self::assertTrue($table->hasIndex('fulfilling_idx')); self::assertSame(['bar'], $table->getIndex('bar_idx')->getColumns()); self::assertSame(['bar', 'baz'], $table->getIndex('fulfilling_idx')->getColumns()); } /** * @group DBAL-50 * @group DBAL-1063 */ public function testPrimaryKeyOverrulingUniqueIndexDoesNotDropUniqueIndex() : void { $table = new Table('bar'); $table->addColumn('baz', 'integer', []); $table->addUniqueIndex(['baz'], 'idx_unique'); $table->setPrimaryKey(['baz']); $indexes = $table->getIndexes(); self::assertCount(2, $indexes, 'Table should only contain both the primary key table index and the unique one, even though it was overruled.'); self::assertTrue($table->hasPrimaryKey()); self::assertTrue($table->hasIndex('idx_unique')); } public function testAddingFulfillingRegularIndexOverridesImplicitForeignKeyConstraintIndex() : void { $foreignTable = new Table('foreign'); $foreignTable->addColumn('id', 'integer'); $localTable = new Table('local'); $localTable->addColumn('id', 'integer'); $localTable->addForeignKeyConstraint($foreignTable, ['id'], ['id']); self::assertCount(1, $localTable->getIndexes()); $localTable->addIndex(['id'], 'explicit_idx'); self::assertCount(1, $localTable->getIndexes()); self::assertTrue($localTable->hasIndex('explicit_idx')); } public function testAddingFulfillingUniqueIndexOverridesImplicitForeignKeyConstraintIndex() : void { $foreignTable = new Table('foreign'); $foreignTable->addColumn('id', 'integer'); $localTable = new Table('local'); $localTable->addColumn('id', 'integer'); $localTable->addForeignKeyConstraint($foreignTable, ['id'], ['id']); self::assertCount(1, $localTable->getIndexes()); $localTable->addUniqueIndex(['id'], 'explicit_idx'); self::assertCount(1, $localTable->getIndexes()); self::assertTrue($localTable->hasIndex('explicit_idx')); } public function testAddingFulfillingPrimaryKeyOverridesImplicitForeignKeyConstraintIndex() : void { $foreignTable = new Table('foreign'); $foreignTable->addColumn('id', 'integer'); $localTable = new Table('local'); $localTable->addColumn('id', 'integer'); $localTable->addForeignKeyConstraint($foreignTable, ['id'], ['id']); self::assertCount(1, $localTable->getIndexes()); $localTable->setPrimaryKey(['id'], 'explicit_idx'); self::assertCount(1, $localTable->getIndexes()); self::assertTrue($localTable->hasIndex('explicit_idx')); } public function testAddingFulfillingExplicitIndexOverridingImplicitForeignKeyConstraintIndexWithSameNameDoesNotThrowException() : void { $foreignTable = new Table('foreign'); $foreignTable->addColumn('id', 'integer'); $localTable = new Table('local'); $localTable->addColumn('id', 'integer'); $localTable->addForeignKeyConstraint($foreignTable, ['id'], ['id']); self::assertCount(1, $localTable->getIndexes()); self::assertTrue($localTable->hasIndex('IDX_8BD688E8BF396750')); $implicitIndex = $localTable->getIndex('IDX_8BD688E8BF396750'); $localTable->addIndex(['id'], 'IDX_8BD688E8BF396750'); self::assertCount(1, $localTable->getIndexes()); self::assertTrue($localTable->hasIndex('IDX_8BD688E8BF396750')); self::assertNotSame($implicitIndex, $localTable->getIndex('IDX_8BD688E8BF396750')); } /** * @group DBAL-64 */ public function testQuotedTableName() : void { $table = new Table('`bar`'); $mysqlPlatform = new MySqlPlatform(); $sqlitePlatform = new SqlitePlatform(); self::assertEquals('bar', $table->getName()); self::assertEquals('`bar`', $table->getQuotedName($mysqlPlatform)); self::assertEquals('"bar"', $table->getQuotedName($sqlitePlatform)); } /** * @group DBAL-79 */ public function testTableHasPrimaryKey() : void { $table = new Table('test'); self::assertFalse($table->hasPrimaryKey()); $table->addColumn('foo', 'integer'); $table->setPrimaryKey(['foo']); self::assertTrue($table->hasPrimaryKey()); } /** * @group DBAL-91 */ public function testAddIndexWithQuotedColumns() : void { $table = new Table('test'); $table->addColumn('"foo"', 'integer'); $table->addColumn('bar', 'integer'); $table->addIndex(['"foo"', '"bar"']); self::assertTrue($table->columnsAreIndexed(['"foo"', '"bar"'])); } /** * @group DBAL-91 */ public function testAddForeignKeyWithQuotedColumnsAndTable() : void { $table = new Table('test'); $table->addColumn('"foo"', 'integer'); $table->addColumn('bar', 'integer'); $table->addForeignKeyConstraint('"boing"', ['"foo"', '"bar"'], ['id']); self::assertCount(1, $table->getForeignKeys()); } /** * @group DBAL-177 */ public function testQuoteSchemaPrefixed() : void { $table = new Table('`test`.`test`'); self::assertEquals('test.test', $table->getName()); self::assertEquals('`test`.`test`', $table->getQuotedName(new MySqlPlatform())); } /** * @group DBAL-204 */ public function testFullQualifiedTableName() : void { $table = new Table('`test`.`test`'); self::assertEquals('test.test', $table->getFullQualifiedName('test')); self::assertEquals('test.test', $table->getFullQualifiedName('other')); $table = new Table('test'); self::assertEquals('test.test', $table->getFullQualifiedName('test')); self::assertEquals('other.test', $table->getFullQualifiedName('other')); } /** * @group DBAL-224 */ public function testDropIndex() : void { $table = new Table('test'); $table->addColumn('id', 'integer'); $table->addIndex(['id'], 'idx'); self::assertTrue($table->hasIndex('idx')); $table->dropIndex('idx'); self::assertFalse($table->hasIndex('idx')); } /** * @group DBAL-224 */ public function testDropPrimaryKey() : void { $table = new Table('test'); $table->addColumn('id', 'integer'); $table->setPrimaryKey(['id']); self::assertTrue($table->hasPrimaryKey()); $table->dropPrimaryKey(); self::assertFalse($table->hasPrimaryKey()); } /** * @group DBAL-234 */ public function testRenameIndex() : void { $table = new Table('test'); $table->addColumn('id', 'integer'); $table->addColumn('foo', 'integer'); $table->addColumn('bar', 'integer'); $table->addColumn('baz', 'integer'); $table->setPrimaryKey(['id'], 'pk'); $table->addIndex(['foo'], 'idx', ['flag']); $table->addUniqueIndex(['bar', 'baz'], 'uniq'); // Rename to custom name. self::assertSame($table, $table->renameIndex('pk', 'pk_new')); self::assertSame($table, $table->renameIndex('idx', 'idx_new')); self::assertSame($table, $table->renameIndex('uniq', 'uniq_new')); self::assertTrue($table->hasPrimaryKey()); self::assertTrue($table->hasIndex('pk_new')); self::assertTrue($table->hasIndex('idx_new')); self::assertTrue($table->hasIndex('uniq_new')); self::assertFalse($table->hasIndex('pk')); self::assertFalse($table->hasIndex('idx')); self::assertFalse($table->hasIndex('uniq')); self::assertEquals(new Index('pk_new', ['id'], true, true), $table->getPrimaryKey()); self::assertEquals(new Index('pk_new', ['id'], true, true), $table->getIndex('pk_new')); self::assertEquals( new Index('idx_new', ['foo'], false, false, ['flag']), $table->getIndex('idx_new') ); self::assertEquals(new Index('uniq_new', ['bar', 'baz'], true), $table->getIndex('uniq_new')); // Rename to auto-generated name. self::assertSame($table, $table->renameIndex('pk_new', null)); self::assertSame($table, $table->renameIndex('idx_new', null)); self::assertSame($table, $table->renameIndex('uniq_new', null)); self::assertTrue($table->hasPrimaryKey()); self::assertTrue($table->hasIndex('primary')); self::assertTrue($table->hasIndex('IDX_D87F7E0C8C736521')); self::assertTrue($table->hasIndex('UNIQ_D87F7E0C76FF8CAA78240498')); self::assertFalse($table->hasIndex('pk_new')); self::assertFalse($table->hasIndex('idx_new')); self::assertFalse($table->hasIndex('uniq_new')); self::assertEquals(new Index('primary', ['id'], true, true), $table->getPrimaryKey()); self::assertEquals(new Index('primary', ['id'], true, true), $table->getIndex('primary')); self::assertEquals( new Index('IDX_D87F7E0C8C736521', ['foo'], false, false, ['flag']), $table->getIndex('IDX_D87F7E0C8C736521') ); self::assertEquals( new Index('UNIQ_D87F7E0C76FF8CAA78240498', ['bar', 'baz'], true), $table->getIndex('UNIQ_D87F7E0C76FF8CAA78240498') ); // Rename to same name (changed case). self::assertSame($table, $table->renameIndex('primary', 'PRIMARY')); self::assertSame($table, $table->renameIndex('IDX_D87F7E0C8C736521', 'idx_D87F7E0C8C736521')); self::assertSame($table, $table->renameIndex('UNIQ_D87F7E0C76FF8CAA78240498', 'uniq_D87F7E0C76FF8CAA78240498')); self::assertTrue($table->hasPrimaryKey()); self::assertTrue($table->hasIndex('primary')); self::assertTrue($table->hasIndex('IDX_D87F7E0C8C736521')); self::assertTrue($table->hasIndex('UNIQ_D87F7E0C76FF8CAA78240498')); } /** * @group DBAL-2508 */ public function testKeepsIndexOptionsOnRenamingRegularIndex() : void { $table = new Table('foo'); $table->addColumn('id', 'integer'); $table->addIndex(['id'], 'idx_bar', [], ['where' => '1 = 1']); $table->renameIndex('idx_bar', 'idx_baz'); self::assertSame(['where' => '1 = 1'], $table->getIndex('idx_baz')->getOptions()); } /** * @group DBAL-2508 */ public function testKeepsIndexOptionsOnRenamingUniqueIndex() : void { $table = new Table('foo'); $table->addColumn('id', 'integer'); $table->addUniqueIndex(['id'], 'idx_bar', ['where' => '1 = 1']); $table->renameIndex('idx_bar', 'idx_baz'); self::assertSame(['where' => '1 = 1'], $table->getIndex('idx_baz')->getOptions()); } /** * @group DBAL-234 */ public function testThrowsExceptionOnRenamingNonExistingIndex() : void { $table = new Table('test'); $table->addColumn('id', 'integer'); $table->addIndex(['id'], 'idx'); $this->expectException(SchemaException::class); $table->renameIndex('foo', 'bar'); } /** * @group DBAL-234 */ public function testThrowsExceptionOnRenamingToAlreadyExistingIndex() : void { $table = new Table('test'); $table->addColumn('id', 'integer'); $table->addColumn('foo', 'integer'); $table->addIndex(['id'], 'idx_id'); $table->addIndex(['foo'], 'idx_foo'); $this->expectException(SchemaException::class); $table->renameIndex('idx_id', 'idx_foo'); } /** * @dataProvider getNormalizesAssetNames * @group DBAL-831 */ public function testNormalizesColumnNames(string $assetName) : void { $table = new Table('test'); $table->addColumn($assetName, 'integer'); $table->addIndex([$assetName], $assetName); $table->addForeignKeyConstraint('test', [$assetName], [$assetName], [], $assetName); self::assertTrue($table->hasColumn($assetName)); self::assertTrue($table->hasColumn('foo')); self::assertInstanceOf(Column::class, $table->getColumn($assetName)); self::assertInstanceOf(Column::class, $table->getColumn('foo')); self::assertTrue($table->hasIndex($assetName)); self::assertTrue($table->hasIndex('foo')); self::assertInstanceOf(Index::class, $table->getIndex($assetName)); self::assertInstanceOf(Index::class, $table->getIndex('foo')); self::assertTrue($table->hasForeignKey($assetName)); self::assertTrue($table->hasForeignKey('foo')); self::assertInstanceOf(ForeignKeyConstraint::class, $table->getForeignKey($assetName)); self::assertInstanceOf(ForeignKeyConstraint::class, $table->getForeignKey('foo')); $table->renameIndex($assetName, $assetName); self::assertTrue($table->hasIndex($assetName)); self::assertTrue($table->hasIndex('foo')); $table->renameIndex($assetName, 'foo'); self::assertTrue($table->hasIndex($assetName)); self::assertTrue($table->hasIndex('foo')); $table->renameIndex('foo', $assetName); self::assertTrue($table->hasIndex($assetName)); self::assertTrue($table->hasIndex('foo')); $table->renameIndex($assetName, 'bar'); self::assertFalse($table->hasIndex($assetName)); self::assertFalse($table->hasIndex('foo')); self::assertTrue($table->hasIndex('bar')); $table->renameIndex('bar', $assetName); $table->dropColumn($assetName); $table->dropIndex($assetName); $table->removeForeignKey($assetName); self::assertFalse($table->hasColumn($assetName)); self::assertFalse($table->hasColumn('foo')); self::assertFalse($table->hasIndex($assetName)); self::assertFalse($table->hasIndex('foo')); self::assertFalse($table->hasForeignKey($assetName)); self::assertFalse($table->hasForeignKey('foo')); } /** * @return mixed[][] */ public static function getNormalizesAssetNames() : iterable { return [ ['foo'], ['FOO'], ['`foo`'], ['`FOO`'], ['"foo"'], ['"FOO"'], ['"foo"'], ['"FOO"'], ]; } public function testTableComment() : void { $table = new Table('bar'); self::assertNull($table->getComment()); $table->setComment('foo'); self::assertEquals('foo', $table->getComment()); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Schema/Visitor/000077500000000000000000000000001360544566000244545ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Schema/Visitor/CreateSchemaSqlCollectorTest.php000066400000000000000000000112331360544566000327000ustar00rootroot00000000000000platformMock = $this->getMockBuilder(AbstractPlatform::class) ->onlyMethods( [ 'getCreateForeignKeySQL', 'getCreateSchemaSQL', 'getCreateSequenceSQL', 'getCreateTableSQL', 'supportsForeignKeyConstraints', 'supportsSchemas', ] ) ->getMockForAbstractClass(); $this->visitor = new CreateSchemaSqlCollector($this->platformMock); foreach (['getCreateSchemaSQL', 'getCreateForeignKeySQL', 'getCreateSequenceSQL'] as $method) { $this->platformMock->method($method) ->willReturn('foo'); } $this->platformMock->method('getCreateTableSQL') ->willReturn(['foo']); } public function testAcceptsNamespace() : void { $this->platformMock->expects($this->at(0)) ->method('supportsSchemas') ->will($this->returnValue(false)); $this->platformMock->expects($this->at(1)) ->method('supportsSchemas') ->will($this->returnValue(true)); $this->visitor->acceptNamespace('foo'); self::assertEmpty($this->visitor->getQueries()); $this->visitor->acceptNamespace('foo'); self::assertSame(['foo'], $this->visitor->getQueries()); } public function testAcceptsTable() : void { $table = $this->createTableMock(); $this->visitor->acceptTable($table); self::assertSame(['foo'], $this->visitor->getQueries()); } public function testAcceptsForeignKey() : void { $this->platformMock->expects($this->at(0)) ->method('supportsForeignKeyConstraints') ->will($this->returnValue(false)); $this->platformMock->expects($this->at(1)) ->method('supportsForeignKeyConstraints') ->will($this->returnValue(true)); $table = $this->createTableMock(); $foreignKey = $this->createForeignKeyConstraintMock(); $this->visitor->acceptForeignKey($table, $foreignKey); self::assertEmpty($this->visitor->getQueries()); $this->visitor->acceptForeignKey($table, $foreignKey); self::assertSame(['foo'], $this->visitor->getQueries()); } public function testAcceptsSequences() : void { $sequence = $this->createSequenceMock(); $this->visitor->acceptSequence($sequence); self::assertSame(['foo'], $this->visitor->getQueries()); } public function testResetsQueries() : void { foreach (['supportsSchemas', 'supportsForeignKeyConstraints'] as $method) { $this->platformMock->expects($this->any()) ->method($method) ->will($this->returnValue(true)); } $table = $this->createTableMock(); $foreignKey = $this->createForeignKeyConstraintMock(); $sequence = $this->createSequenceMock(); $this->visitor->acceptNamespace('foo'); $this->visitor->acceptTable($table); $this->visitor->acceptForeignKey($table, $foreignKey); $this->visitor->acceptSequence($sequence); self::assertNotEmpty($this->visitor->getQueries()); $this->visitor->resetQueries(); self::assertEmpty($this->visitor->getQueries()); } /** * @return ForeignKeyConstraint|MockObject */ private function createForeignKeyConstraintMock() { return $this->getMockBuilder(ForeignKeyConstraint::class) ->disableOriginalConstructor() ->getMock(); } /** * @return Sequence|MockObject */ private function createSequenceMock() { return $this->getMockBuilder(Sequence::class) ->disableOriginalConstructor() ->getMock(); } /** * @return Table|MockObject */ private function createTableMock() { return $this->getMockBuilder(Table::class) ->disableOriginalConstructor() ->getMock(); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Schema/Visitor/DropSchemaSqlCollectorTest.php000066400000000000000000000047221360544566000324060ustar00rootroot00000000000000createMock(Table::class); $tableTwo = $this->createMock(Table::class); $keyConstraintOne = $this->getStubKeyConstraint('first'); $keyConstraintTwo = $this->getStubKeyConstraint('second'); $platform = $this->getMockBuilder(AbstractPlatform::class) ->onlyMethods(['getDropForeignKeySQL']) ->getMockForAbstractClass(); $collector = new DropSchemaSqlCollector($platform); $platform->expects($this->exactly(2)) ->method('getDropForeignKeySQL'); $platform->expects($this->at(0)) ->method('getDropForeignKeySQL') ->with($keyConstraintOne, $tableOne); $platform->expects($this->at(1)) ->method('getDropForeignKeySQL') ->with($keyConstraintTwo, $tableTwo); $collector->acceptForeignKey($tableOne, $keyConstraintOne); $collector->acceptForeignKey($tableTwo, $keyConstraintTwo); $collector->getQueries(); } private function getStubKeyConstraint(string $name) : ForeignKeyConstraint { $constraint = $this->createMock(ForeignKeyConstraint::class); $constraint->expects($this->any()) ->method('getName') ->will($this->returnValue($name)); $constraint->expects($this->any()) ->method('getForeignColumns') ->will($this->returnValue([])); $constraint->expects($this->any()) ->method('getColumns') ->will($this->returnValue([])); return $constraint; } public function testGivenForeignKeyWithZeroLengthAcceptForeignKeyThrowsException() : void { $collector = new DropSchemaSqlCollector( $this->getMockForAbstractClass(AbstractPlatform::class) ); $this->expectException(SchemaException::class); $collector->acceptForeignKey( $this->createMock(Table::class), $this->getStubKeyConstraint('') ); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Schema/Visitor/RemoveNamespacedAssetsTest.php000066400000000000000000000045021360544566000324270ustar00rootroot00000000000000setName('test'); $schema = new Schema([], [], $config); $schema->createTable('test.test'); $schema->createTable('foo.bar'); $schema->createTable('baz'); $schema->visit(new RemoveNamespacedAssets()); $tables = $schema->getTables(); self::assertEquals(['test.test', 'test.baz'], array_keys($tables), "Only 2 tables should be present, both in 'test' namespace."); } /** * @group DBAL-204 */ public function testCleanupForeignKeys() : void { $config = new SchemaConfig(); $config->setName('test'); $schema = new Schema([], [], $config); $fooTable = $schema->createTable('foo.bar'); $fooTable->addColumn('id', 'integer'); $testTable = $schema->createTable('test.test'); $testTable->addColumn('id', 'integer'); $testTable->addForeignKeyConstraint('foo.bar', ['id'], ['id']); $schema->visit(new RemoveNamespacedAssets()); $sql = $schema->toSql(new MySqlPlatform()); self::assertCount(1, $sql, 'Just one CREATE TABLE statement, no foreign key and table to foo.bar'); } /** * @group DBAL-204 */ public function testCleanupForeignKeysDifferentOrder() : void { $config = new SchemaConfig(); $config->setName('test'); $schema = new Schema([], [], $config); $testTable = $schema->createTable('test.test'); $testTable->addColumn('id', 'integer'); $fooTable = $schema->createTable('foo.bar'); $fooTable->addColumn('id', 'integer'); $testTable->addForeignKeyConstraint('foo.bar', ['id'], ['id']); $schema->visit(new RemoveNamespacedAssets()); $sql = $schema->toSql(new MySqlPlatform()); self::assertCount(1, $sql, 'Just one CREATE TABLE statement, no foreign key and table to foo.bar'); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Schema/Visitor/SchemaSqlCollectorTest.php000066400000000000000000000047641360544566000315670ustar00rootroot00000000000000getMockBuilder(MySqlPlatform::class) ->onlyMethods(['getCreateTableSql', 'getCreateSequenceSql', 'getCreateForeignKeySql']) ->getMock(); $platformMock->expects($this->exactly(2)) ->method('getCreateTableSql') ->will($this->returnValue(['foo'])); $platformMock->expects($this->exactly(1)) ->method('getCreateSequenceSql') ->will($this->returnValue('bar')); $platformMock->expects($this->exactly(1)) ->method('getCreateForeignKeySql') ->will($this->returnValue('baz')); $schema = $this->createFixtureSchema(); $sql = $schema->toSql($platformMock); self::assertEquals(['foo', 'foo', 'bar', 'baz'], $sql); } public function testDropSchema() : void { $platformMock = $this->getMockBuilder(MySqlPlatform::class) ->onlyMethods(['getDropTableSql', 'getDropSequenceSql', 'getDropForeignKeySql']) ->getMock(); $platformMock->expects($this->exactly(2)) ->method('getDropTableSql') ->will($this->returnValue('tbl')); $platformMock->expects($this->exactly(1)) ->method('getDropSequenceSql') ->will($this->returnValue('seq')); $platformMock->expects($this->exactly(1)) ->method('getDropForeignKeySql') ->will($this->returnValue('fk')); $schema = $this->createFixtureSchema(); $sql = $schema->toDropSql($platformMock); self::assertEquals(['fk', 'seq', 'tbl', 'tbl'], $sql); } public function createFixtureSchema() : Schema { $schema = new Schema(); $tableA = $schema->createTable('foo'); $tableA->addColumn('id', 'integer'); $tableA->addColumn('bar', 'string', ['length' => 255]); $tableA->setPrimaryKey(['id']); $schema->createSequence('foo_seq'); $tableB = $schema->createTable('bar'); $tableB->addColumn('id', 'integer'); $tableB->setPrimaryKey(['id']); $tableA->addForeignKeyConstraint($tableB, ['bar'], ['id']); return $schema; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Sharding/000077500000000000000000000000001360544566000233545ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Sharding/PoolingShardConnectionTest.php000066400000000000000000000250311360544566000313370ustar00rootroot00000000000000 PoolingShardConnection::class, 'driver' => 'pdo_sqlite', 'global' => ['memory' => true], 'shards' => [ ['id' => 1, 'memory' => true], ['id' => 2, 'memory' => true], ], 'shardChoser' => MultiTenantShardChoser::class, ]); self::assertFalse($conn->isConnected(0)); $conn->connect(0); self::assertEquals(1, $conn->fetchColumn('SELECT 1')); self::assertTrue($conn->isConnected(0)); self::assertFalse($conn->isConnected(1)); $conn->connect(1); self::assertEquals(1, $conn->fetchColumn('SELECT 1')); self::assertTrue($conn->isConnected(1)); self::assertFalse($conn->isConnected(2)); $conn->connect(2); self::assertEquals(1, $conn->fetchColumn('SELECT 1')); self::assertTrue($conn->isConnected(2)); $conn->close(); self::assertFalse($conn->isConnected(0)); self::assertFalse($conn->isConnected(1)); self::assertFalse($conn->isConnected(2)); } public function testNoGlobalServerException() : void { $this->expectException('InvalidArgumentException'); $this->expectExceptionMessage("Connection Parameters require 'global' and 'shards' configurations."); DriverManager::getConnection([ 'wrapperClass' => PoolingShardConnection::class, 'driver' => 'pdo_sqlite', 'shards' => [ ['id' => 1, 'memory' => true], ['id' => 2, 'memory' => true], ], 'shardChoser' => MultiTenantShardChoser::class, ]); } public function testNoShardsServersException() : void { $this->expectException('InvalidArgumentException'); $this->expectExceptionMessage("Connection Parameters require 'global' and 'shards' configurations."); DriverManager::getConnection([ 'wrapperClass' => PoolingShardConnection::class, 'driver' => 'pdo_sqlite', 'global' => ['memory' => true], 'shardChoser' => MultiTenantShardChoser::class, ]); } public function testNoShardsChoserException() : void { $this->expectException('InvalidArgumentException'); $this->expectExceptionMessage("Missing Shard Choser configuration 'shardChoser'"); DriverManager::getConnection([ 'wrapperClass' => PoolingShardConnection::class, 'driver' => 'pdo_sqlite', 'global' => ['memory' => true], 'shards' => [ ['id' => 1, 'memory' => true], ['id' => 2, 'memory' => true], ], ]); } public function testShardChoserWrongInstance() : void { $this->expectException('InvalidArgumentException'); $this->expectExceptionMessage("The 'shardChoser' configuration is not a valid instance of Doctrine\DBAL\Sharding\ShardChoser\ShardChoser"); DriverManager::getConnection([ 'wrapperClass' => PoolingShardConnection::class, 'driver' => 'pdo_sqlite', 'global' => ['memory' => true], 'shards' => [ ['id' => 1, 'memory' => true], ['id' => 2, 'memory' => true], ], 'shardChoser' => new stdClass(), ]); } public function testShardNonNumericId() : void { $this->expectException('InvalidArgumentException'); $this->expectExceptionMessage('Shard Id has to be a non-negative number.'); DriverManager::getConnection([ 'wrapperClass' => PoolingShardConnection::class, 'driver' => 'pdo_sqlite', 'global' => ['memory' => true], 'shards' => [ ['id' => 'foo', 'memory' => true], ], 'shardChoser' => MultiTenantShardChoser::class, ]); } public function testShardMissingId() : void { $this->expectException('InvalidArgumentException'); $this->expectExceptionMessage("Missing 'id' for one configured shard. Please specify a unique shard-id."); DriverManager::getConnection([ 'wrapperClass' => PoolingShardConnection::class, 'driver' => 'pdo_sqlite', 'global' => ['memory' => true], 'shards' => [ ['memory' => true], ], 'shardChoser' => MultiTenantShardChoser::class, ]); } public function testDuplicateShardId() : void { $this->expectException('InvalidArgumentException'); $this->expectExceptionMessage('Shard 1 is duplicated in the configuration.'); DriverManager::getConnection([ 'wrapperClass' => PoolingShardConnection::class, 'driver' => 'pdo_sqlite', 'global' => ['memory' => true], 'shards' => [ ['id' => 1, 'memory' => true], ['id' => 1, 'memory' => true], ], 'shardChoser' => MultiTenantShardChoser::class, ]); } public function testSwitchShardWithOpenTransactionException() : void { $conn = DriverManager::getConnection([ 'wrapperClass' => PoolingShardConnection::class, 'driver' => 'pdo_sqlite', 'global' => ['memory' => true], 'shards' => [ ['id' => 1, 'memory' => true], ], 'shardChoser' => MultiTenantShardChoser::class, ]); $conn->beginTransaction(); $this->expectException(ShardingException::class); $this->expectExceptionMessage('Cannot switch shard when transaction is active.'); $conn->connect(1); } public function testGetActiveShardId() : void { $conn = DriverManager::getConnection([ 'wrapperClass' => PoolingShardConnection::class, 'driver' => 'pdo_sqlite', 'global' => ['memory' => true], 'shards' => [ ['id' => 1, 'memory' => true], ], 'shardChoser' => MultiTenantShardChoser::class, ]); self::assertNull($conn->getActiveShardId()); $conn->connect(0); self::assertEquals(0, $conn->getActiveShardId()); $conn->connect(1); self::assertEquals(1, $conn->getActiveShardId()); $conn->close(); self::assertNull($conn->getActiveShardId()); } public function testGetParamsOverride() : void { $conn = DriverManager::getConnection([ 'wrapperClass' => PoolingShardConnection::class, 'driver' => 'pdo_sqlite', 'global' => ['memory' => true, 'host' => 'localhost'], 'shards' => [ ['id' => 1, 'memory' => true, 'host' => 'foo'], ], 'shardChoser' => MultiTenantShardChoser::class, ]); self::assertEquals([ 'wrapperClass' => PoolingShardConnection::class, 'driver' => 'pdo_sqlite', 'global' => ['memory' => true, 'host' => 'localhost'], 'shards' => [ ['id' => 1, 'memory' => true, 'host' => 'foo'], ], 'shardChoser' => new MultiTenantShardChoser(), 'memory' => true, 'host' => 'localhost', ], $conn->getParams()); $conn->connect(1); self::assertEquals([ 'wrapperClass' => PoolingShardConnection::class, 'driver' => 'pdo_sqlite', 'global' => ['memory' => true, 'host' => 'localhost'], 'shards' => [ ['id' => 1, 'memory' => true, 'host' => 'foo'], ], 'shardChoser' => new MultiTenantShardChoser(), 'id' => 1, 'memory' => true, 'host' => 'foo', ], $conn->getParams()); } public function testGetHostOverride() : void { $conn = DriverManager::getConnection([ 'wrapperClass' => PoolingShardConnection::class, 'driver' => 'pdo_sqlite', 'host' => 'localhost', 'global' => ['memory' => true], 'shards' => [ ['id' => 1, 'memory' => true, 'host' => 'foo'], ], 'shardChoser' => MultiTenantShardChoser::class, ]); self::assertEquals('localhost', $conn->getHost()); $conn->connect(1); self::assertEquals('foo', $conn->getHost()); } public function testGetPortOverride() : void { $conn = DriverManager::getConnection([ 'wrapperClass' => PoolingShardConnection::class, 'driver' => 'pdo_sqlite', 'port' => 3306, 'global' => ['memory' => true], 'shards' => [ ['id' => 1, 'memory' => true, 'port' => 3307], ], 'shardChoser' => MultiTenantShardChoser::class, ]); self::assertEquals(3306, $conn->getPort()); $conn->connect(1); self::assertEquals(3307, $conn->getPort()); } public function testGetUsernameOverride() : void { $conn = DriverManager::getConnection([ 'wrapperClass' => PoolingShardConnection::class, 'driver' => 'pdo_sqlite', 'user' => 'foo', 'global' => ['memory' => true], 'shards' => [ ['id' => 1, 'memory' => true, 'user' => 'bar'], ], 'shardChoser' => MultiTenantShardChoser::class, ]); self::assertEquals('foo', $conn->getUsername()); $conn->connect(1); self::assertEquals('bar', $conn->getUsername()); } public function testGetPasswordOverride() : void { $conn = DriverManager::getConnection([ 'wrapperClass' => PoolingShardConnection::class, 'driver' => 'pdo_sqlite', 'password' => 'foo', 'global' => ['memory' => true], 'shards' => [ ['id' => 1, 'memory' => true, 'password' => 'bar'], ], 'shardChoser' => MultiTenantShardChoser::class, ]); self::assertEquals('foo', $conn->getPassword()); $conn->connect(1); self::assertEquals('bar', $conn->getPassword()); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Sharding/PoolingShardManagerTest.php000066400000000000000000000130351360544566000306130ustar00rootroot00000000000000getMockBuilder(PoolingShardConnection::class) ->onlyMethods(['connect', 'getParams', 'fetchAll']) ->disableOriginalConstructor() ->getMock(); } private function createPassthroughShardChoser() : ShardChoser { $mock = $this->createMock(ShardChoser::class); $mock->expects($this->any()) ->method('pickShard') ->will($this->returnCallback(static function ($value) { return $value; })); return $mock; } private function createStaticShardChooser() : ShardChoser { $mock = $this->createMock(ShardChoser::class); $mock->expects($this->any()) ->method('pickShard') ->willReturn(1); return $mock; } public function testSelectGlobal() : void { $conn = $this->createConnectionMock(); $conn->expects($this->once())->method('connect')->with($this->equalTo(0)); $conn->method('getParams') ->willReturn([ 'shardChoser' => $this->createMock(ShardChoser::class), ]); $shardManager = new PoolingShardManager($conn); $shardManager->selectGlobal(); self::assertNull($shardManager->getCurrentDistributionValue()); } public function testSelectShard() : void { $shardId = 10; $conn = $this->createConnectionMock(); $conn->expects($this->at(0))->method('getParams')->will($this->returnValue(['shardChoser' => $this->createPassthroughShardChoser()])); $conn->expects($this->at(1))->method('connect')->with($this->equalTo($shardId)); $shardManager = new PoolingShardManager($conn); $shardManager->selectShard($shardId); self::assertEquals($shardId, $shardManager->getCurrentDistributionValue()); } public function testGetShards() : void { $conn = $this->createConnectionMock(); $conn->expects($this->any())->method('getParams')->will( $this->returnValue( ['shards' => [ ['id' => 1], ['id' => 2] ], 'shardChoser' => $this->createPassthroughShardChoser()] ) ); $shardManager = new PoolingShardManager($conn); $shards = $shardManager->getShards(); self::assertEquals([['id' => 1], ['id' => 2]], $shards); } public function testQueryAll() : void { $sql = 'SELECT * FROM table'; $params = [1]; $types = [1]; $conn = $this->createConnectionMock(); $conn->expects($this->at(0))->method('getParams')->will($this->returnValue( ['shards' => [ ['id' => 1], ['id' => 2] ], 'shardChoser' => $this->createPassthroughShardChoser()] )); $conn->expects($this->at(1))->method('getParams')->will($this->returnValue( ['shards' => [ ['id' => 1], ['id' => 2] ], 'shardChoser' => $this->createPassthroughShardChoser()] )); $conn->expects($this->at(2))->method('connect')->with($this->equalTo(1)); $conn->expects($this->at(3)) ->method('fetchAll') ->with($this->equalTo($sql), $this->equalTo($params), $this->equalTo($types)) ->will($this->returnValue([ ['id' => 1] ])); $conn->expects($this->at(4))->method('connect')->with($this->equalTo(2)); $conn->expects($this->at(5)) ->method('fetchAll') ->with($this->equalTo($sql), $this->equalTo($params), $this->equalTo($types)) ->will($this->returnValue([ ['id' => 2] ])); $shardManager = new PoolingShardManager($conn); $result = $shardManager->queryAll($sql, $params, $types); self::assertEquals([['id' => 1], ['id' => 2]], $result); } public function testQueryAllWithStaticShardChoser() : void { $sql = 'SELECT * FROM table'; $params = [1]; $types = [1]; $conn = $this->createConnectionMock(); $conn->expects($this->at(0))->method('getParams')->will($this->returnValue( ['shards' => [ ['id' => 1], ['id' => 2] ], 'shardChoser' => $this->createStaticShardChooser()] )); $conn->expects($this->at(1))->method('getParams')->will($this->returnValue( ['shards' => [ ['id' => 1], ['id' => 2] ], 'shardChoser' => $this->createStaticShardChooser()] )); $conn->expects($this->at(2))->method('connect')->with($this->equalTo(1)); $conn->expects($this->at(3)) ->method('fetchAll') ->with($this->equalTo($sql), $this->equalTo($params), $this->equalTo($types)) ->will($this->returnValue([ ['id' => 1] ])); $conn->expects($this->at(4))->method('connect')->with($this->equalTo(2)); $conn->expects($this->at(5)) ->method('fetchAll') ->with($this->equalTo($sql), $this->equalTo($params), $this->equalTo($types)) ->will($this->returnValue([ ['id' => 2] ])); $shardManager = new PoolingShardManager($conn); $result = $shardManager->queryAll($sql, $params, $types); self::assertEquals([['id' => 1], ['id' => 2]], $result); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/000077500000000000000000000000001360544566000250225ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/AbstractTestCase.php000066400000000000000000000071521360544566000307370ustar00rootroot00000000000000markTestSkipped('No driver or sqlserver driver specified.'); } $params = [ 'driver' => $GLOBALS['db_type'], 'dbname' => $GLOBALS['db_name'], 'user' => $GLOBALS['db_username'], 'password' => $GLOBALS['db_password'], 'host' => $GLOBALS['db_host'], 'sharding' => [ 'federationName' => 'Orders_Federation', 'distributionKey' => 'CustID', 'distributionType' => 'integer', 'filteringEnabled' => false, ], 'driverOptions' => ['MultipleActiveResultSets' => false], ]; $this->conn = DriverManager::getConnection($params); $serverEdition = $this->conn->fetchColumn("SELECT CONVERT(NVARCHAR(128), SERVERPROPERTY('Edition'))"); if (strpos($serverEdition, 'SQL Azure') !== 0) { $this->markTestSkipped('SQL Azure only test.'); } // assume database is created and schema is: // Global products table // Customers, Orders, OrderItems federation tables. // See http://cloud.dzone.com/articles/using-sql-azure-federations $this->sm = new SQLAzureShardManager($this->conn); } protected function createShopSchema() : Schema { $schema = new Schema(); $products = $schema->createTable('Products'); $products->addColumn('ProductID', 'integer'); $products->addColumn('SupplierID', 'integer'); $products->addColumn('ProductName', 'string'); $products->addColumn('Price', 'decimal', ['scale' => 2, 'precision' => 12]); $products->setPrimaryKey(['ProductID']); $products->addOption('azure.federated', true); $customers = $schema->createTable('Customers'); $customers->addColumn('CustomerID', 'integer'); $customers->addColumn('CompanyName', 'string'); $customers->addColumn('FirstName', 'string'); $customers->addColumn('LastName', 'string'); $customers->setPrimaryKey(['CustomerID']); $customers->addOption('azure.federated', true); $customers->addOption('azure.federatedOnColumnName', 'CustomerID'); $orders = $schema->createTable('Orders'); $orders->addColumn('CustomerID', 'integer'); $orders->addColumn('OrderID', 'integer'); $orders->addColumn('OrderDate', 'datetime'); $orders->setPrimaryKey(['CustomerID', 'OrderID']); $orders->addOption('azure.federated', true); $orders->addOption('azure.federatedOnColumnName', 'CustomerID'); $orderItems = $schema->createTable('OrderItems'); $orderItems->addColumn('CustomerID', 'integer'); $orderItems->addColumn('OrderID', 'integer'); $orderItems->addColumn('ProductID', 'integer'); $orderItems->addColumn('Quantity', 'integer'); $orderItems->setPrimaryKey(['CustomerID', 'OrderID', 'ProductID']); $orderItems->addOption('azure.federated', true); $orderItems->addOption('azure.federatedOnColumnName', 'CustomerID'); return $schema; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/FunctionalTest.php000066400000000000000000000024011360544566000304720ustar00rootroot00000000000000createShopSchema(); $synchronizer = new SQLAzureFederationsSynchronizer($this->conn, $this->sm); $synchronizer->dropAllSchema(); $synchronizer->createSchema($schema); $this->sm->selectShard(0); $this->conn->insert('Products', [ 'ProductID' => 1, 'SupplierID' => 2, 'ProductName' => 'Test', 'Price' => 10.45, ]); $this->conn->insert('Customers', [ 'CustomerID' => 1, 'CompanyName' => 'Foo', 'FirstName' => 'Benjamin', 'LastName' => 'E.', ]); $query = 'SELECT * FROM Products'; $data = $this->conn->fetchAll($query); self::assertGreaterThan(0, count($data)); $query = 'SELECT * FROM Customers'; $data = $this->conn->fetchAll($query); self::assertGreaterThan(0, count($data)); $data = $this->sm->queryAll('SELECT * FROM Customers'); self::assertGreaterThan(0, count($data)); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/MultiTenantVisitorTest.php000066400000000000000000000030171360544566000322200ustar00rootroot00000000000000createTable('foo'); $foo->addColumn('id', 'string'); $foo->setPrimaryKey(['id']); $schema->visit($visitor); self::assertEquals(['id', 'tenant_id'], $foo->getPrimaryKey()->getColumns()); self::assertTrue($foo->hasColumn('tenant_id')); } public function testMultiTenantNonPrimaryKey() : void { $platform = new SQLAzurePlatform(); $visitor = new MultiTenantVisitor(); $schema = new Schema(); $foo = $schema->createTable('foo'); $foo->addColumn('id', 'string'); $foo->addColumn('created', 'datetime'); $foo->setPrimaryKey(['id']); $foo->addIndex(['created'], 'idx'); $foo->getPrimaryKey()->addFlag('nonclustered'); $foo->getIndex('idx')->addFlag('clustered'); $schema->visit($visitor); self::assertEquals(['id'], $foo->getPrimaryKey()->getColumns()); self::assertTrue($foo->hasColumn('tenant_id')); self::assertEquals(['created', 'tenant_id'], $foo->getIndex('idx')->getColumns()); } } SQLAzureFederationsSynchronizerTest.php000066400000000000000000000040341360544566000345650ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Sharding/SQLAzurecreateShopSchema(); $synchronizer = new SQLAzureFederationsSynchronizer($this->conn, $this->sm); $sql = $synchronizer->getCreateSchema($schema); self::assertEquals([ "--Create Federation\nCREATE FEDERATION Orders_Federation (CustID INT RANGE)", 'USE FEDERATION Orders_Federation (CustID = 0) WITH RESET, FILTERING = OFF;', 'CREATE TABLE Products (ProductID INT NOT NULL, SupplierID INT NOT NULL, ProductName NVARCHAR(255) NOT NULL, Price NUMERIC(12, 2) NOT NULL, PRIMARY KEY (ProductID))', 'CREATE TABLE Customers (CustomerID INT NOT NULL, CompanyName NVARCHAR(255) NOT NULL, FirstName NVARCHAR(255) NOT NULL, LastName NVARCHAR(255) NOT NULL, PRIMARY KEY (CustomerID))', 'CREATE TABLE Orders (CustomerID INT NOT NULL, OrderID INT NOT NULL, OrderDate DATETIME2(6) NOT NULL, PRIMARY KEY (CustomerID, OrderID))', 'CREATE TABLE OrderItems (CustomerID INT NOT NULL, OrderID INT NOT NULL, ProductID INT NOT NULL, Quantity INT NOT NULL, PRIMARY KEY (CustomerID, OrderID, ProductID))', ], $sql); } public function testUpdateSchema() : void { $schema = $this->createShopSchema(); $synchronizer = new SQLAzureFederationsSynchronizer($this->conn, $this->sm); $synchronizer->dropAllSchema(); $sql = $synchronizer->getUpdateSchema($schema); self::assertEquals([], $sql); } public function testDropSchema() : void { $schema = $this->createShopSchema(); $synchronizer = new SQLAzureFederationsSynchronizer($this->conn, $this->sm); $synchronizer->dropAllSchema(); $synchronizer->createSchema($schema); $sql = $synchronizer->getDropSchema($schema); self::assertCount(5, $sql); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Sharding/SQLAzure/SQLAzureShardManagerTest.php000066400000000000000000000073101360544566000323170ustar00rootroot00000000000000expectException(ShardingException::class); $this->expectExceptionMessage('SQLAzure requires a federation name to be set during sharding configuration.'); $conn = $this->createConnection(['sharding' => ['distributionKey' => 'abc', 'distributionType' => 'integer']]); new SQLAzureShardManager($conn); } public function testNoDistributionKey() : void { $this->expectException(ShardingException::class); $this->expectExceptionMessage('SQLAzure requires a distribution key to be set during sharding configuration.'); $conn = $this->createConnection(['sharding' => ['federationName' => 'abc', 'distributionType' => 'integer']]); new SQLAzureShardManager($conn); } public function testNoDistributionType() : void { $this->expectException(ShardingException::class); $conn = $this->createConnection(['sharding' => ['federationName' => 'abc', 'distributionKey' => 'foo']]); new SQLAzureShardManager($conn); } public function testGetDefaultDistributionValue() : void { $conn = $this->createConnection(['sharding' => ['federationName' => 'abc', 'distributionKey' => 'foo', 'distributionType' => 'integer']]); $sm = new SQLAzureShardManager($conn); self::assertNull($sm->getCurrentDistributionValue()); } public function testSelectGlobalTransactionActive() : void { $conn = $this->createConnection(['sharding' => ['federationName' => 'abc', 'distributionKey' => 'foo', 'distributionType' => 'integer']]); $conn->expects($this->at(1))->method('isTransactionActive')->will($this->returnValue(true)); $this->expectException(ShardingException::class); $this->expectExceptionMessage('Cannot switch shard during an active transaction.'); $sm = new SQLAzureShardManager($conn); $sm->selectGlobal(); } public function testSelectGlobal() : void { $conn = $this->createConnection(['sharding' => ['federationName' => 'abc', 'distributionKey' => 'foo', 'distributionType' => 'integer']]); $conn->expects($this->at(1))->method('isTransactionActive')->will($this->returnValue(false)); $conn->expects($this->at(2))->method('exec')->with($this->equalTo('USE FEDERATION ROOT WITH RESET')); $sm = new SQLAzureShardManager($conn); $sm->selectGlobal(); } public function testSelectShard() : void { $conn = $this->createConnection(['sharding' => ['federationName' => 'abc', 'distributionKey' => 'foo', 'distributionType' => 'integer']]); $conn->expects($this->at(1))->method('isTransactionActive')->will($this->returnValue(true)); $this->expectException(ShardingException::class); $this->expectExceptionMessage('Cannot switch shard during an active transaction.'); $sm = new SQLAzureShardManager($conn); $sm->selectShard(1234); self::assertEquals(1234, $sm->getCurrentDistributionValue()); } /** * @param mixed[] $params */ private function createConnection(array $params) : Connection { $conn = $this->getMockBuilder(Connection::class) ->onlyMethods(['getParams', 'exec', 'isTransactionActive']) ->disableOriginalConstructor() ->getMock(); $conn->expects($this->at(0))->method('getParams')->will($this->returnValue($params)); return $conn; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Sharding/ShardChoser/000077500000000000000000000000001360544566000255615ustar00rootroot00000000000000MultiTenantShardChoserTest.php000066400000000000000000000014621360544566000334500ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Sharding/ShardChosercreateConnectionMock(); self::assertEquals(1, $choser->pickShard(1, $conn)); self::assertEquals(2, $choser->pickShard(2, $conn)); } private function createConnectionMock() : PoolingShardConnection { return $this->getMockBuilder(PoolingShardConnection::class) ->onlyMethods(['connect', 'getParams', 'fetchAll']) ->disableOriginalConstructor() ->getMock(); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/StatementTest.php000066400000000000000000000115031360544566000251320ustar00rootroot00000000000000pdoStatement = $this->getMockBuilder(PDOStatement::class) ->onlyMethods(['execute', 'bindParam', 'bindValue']) ->getMock(); $driverConnection = $this->createMock(DriverConnection::class); $driverConnection->expects($this->any()) ->method('prepare') ->will($this->returnValue($this->pdoStatement)); $driver = $this->createMock(Driver::class); $this->conn = $this->getMockBuilder(Connection::class) ->setConstructorArgs([[], $driver]) ->getMock(); $this->conn->expects($this->atLeastOnce()) ->method('getWrappedConnection') ->will($this->returnValue($driverConnection)); $this->configuration = $this->createMock(Configuration::class); $this->conn->expects($this->any()) ->method('getConfiguration') ->will($this->returnValue($this->configuration)); $this->conn->expects($this->any()) ->method('getDriver') ->will($this->returnValue($driver)); } public function testExecuteCallsLoggerStartQueryWithParametersWhenValuesBound() : void { $name = 'foo'; $var = 'bar'; $type = ParameterType::STRING; $values = [$name => $var]; $types = [$name => $type]; $sql = ''; $logger = $this->createMock(SQLLogger::class); $logger->expects($this->once()) ->method('startQuery') ->with($this->equalTo($sql), $this->equalTo($values), $this->equalTo($types)); $this->configuration->expects($this->once()) ->method('getSQLLogger') ->will($this->returnValue($logger)); $statement = new Statement($sql, $this->conn); $statement->bindValue($name, $var, $type); $statement->execute(); } public function testExecuteCallsLoggerStartQueryWithParametersWhenParamsPassedToExecute() : void { $name = 'foo'; $var = 'bar'; $values = [$name => $var]; $types = []; $sql = ''; $logger = $this->createMock(SQLLogger::class); $logger->expects($this->once()) ->method('startQuery') ->with($this->equalTo($sql), $this->equalTo($values), $this->equalTo($types)); $this->configuration->expects($this->once()) ->method('getSQLLogger') ->will($this->returnValue($logger)); $statement = new Statement($sql, $this->conn); $statement->execute($values); } public function testExecuteCallsStartQueryWithTheParametersBoundViaBindParam() : void { $name = 'foo'; $var = 'bar'; $values = [$name => $var]; $types = [$name => ParameterType::STRING]; $sql = ''; $logger = $this->createMock(SQLLogger::class); $logger->expects(self::once()) ->method('startQuery') ->with(self::equalTo($sql), self::equalTo($values), self::equalTo($types)); $this->configuration->expects(self::once()) ->method('getSQLLogger') ->willReturn($logger); $statement = new Statement($sql, $this->conn); $statement->bindParam($name, $var); $statement->execute(); } public function testExecuteCallsLoggerStopQueryOnException() : void { $logger = $this->createMock(SQLLogger::class); $this->configuration->expects($this->once()) ->method('getSQLLogger') ->will($this->returnValue($logger)); // Needed to satisfy construction of DBALException $this->conn->expects($this->any()) ->method('resolveParams') ->will($this->returnValue([])); $logger->expects($this->once()) ->method('startQuery'); $logger->expects($this->once()) ->method('stopQuery'); $this->pdoStatement->expects($this->once()) ->method('execute') ->will($this->throwException(new Exception('Mock test exception'))); $statement = new Statement('', $this->conn); $this->expectException(DBALException::class); $statement->execute(); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Tools/000077500000000000000000000000001360544566000227155ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Tools/Console/000077500000000000000000000000001360544566000243175ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Tools/Console/RunSqlCommandTest.php000066400000000000000000000100321360544566000304070ustar00rootroot00000000000000add(new RunSqlCommand()); $this->command = $application->find('dbal:run-sql'); $this->commandTester = new CommandTester($this->command); $this->connectionMock = $this->createMock(Connection::class); $this->connectionMock->method('fetchAll') ->willReturn([[1]]); $this->connectionMock->method('executeUpdate') ->willReturn(42); $helperSet = ConsoleRunner::createHelperSet($this->connectionMock); $this->command->setHelperSet($helperSet); } public function testMissingSqlArgument() : void { try { $this->commandTester->execute([ 'command' => $this->command->getName(), 'sql' => null, ]); $this->fail('Expected a runtime exception when omitting sql argument'); } catch (RuntimeException $e) { self::assertStringContainsString("Argument 'SQL", $e->getMessage()); } } public function testIncorrectDepthOption() : void { try { $this->commandTester->execute([ 'command' => $this->command->getName(), 'sql' => 'SELECT 1', '--depth' => 'string', ]); $this->fail('Expected a logic exception when executing with a stringy depth'); } catch (LogicException $e) { self::assertStringContainsString("Option 'depth'", $e->getMessage()); } } public function testSelectStatementsPrintsResult() : void { $this->expectConnectionFetchAll(); $exitCode = $this->commandTester->execute([ 'command' => $this->command->getName(), 'sql' => 'SELECT 1', ]); $this->assertSame(0, $exitCode); self::assertRegExp('@int.*1.*@', $this->commandTester->getDisplay()); self::assertRegExp('@array.*1.*@', $this->commandTester->getDisplay()); } public function testUpdateStatementsPrintsAffectedLines() : void { $this->expectConnectionExecuteUpdate(); $this->commandTester->execute([ 'command' => $this->command->getName(), 'sql' => 'UPDATE foo SET bar = 42', ]); self::assertRegExp('@int.*42.*@', $this->commandTester->getDisplay()); self::assertNotRegExp('@array.*1.*@', $this->commandTester->getDisplay()); } private function expectConnectionExecuteUpdate() : void { $this->connectionMock ->expects($this->exactly(1)) ->method('executeUpdate'); $this->connectionMock ->expects($this->exactly(0)) ->method('fetchAll'); } private function expectConnectionFetchAll() : void { $this->connectionMock ->expects($this->exactly(0)) ->method('executeUpdate'); $this->connectionMock ->expects($this->exactly(1)) ->method('fetchAll'); } public function testStatementsWithFetchResultPrintsResult() : void { $this->expectConnectionFetchAll(); $this->commandTester->execute([ 'command' => $this->command->getName(), 'sql' => '"WITH bar as (SELECT 1) SELECT * FROM bar', '--force-fetch' => true, ]); self::assertRegExp('@int.*1.*@', $this->commandTester->getDisplay()); self::assertRegExp('@array.*1.*@', $this->commandTester->getDisplay()); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Tools/DumperTest.php000066400000000000000000000105421360544566000255240ustar00rootroot00000000000000foo = 'bar'; $obj->bar = 1234; $var = Dumper::export($obj, 2); self::assertEquals('stdClass', $var->__CLASS__); } public function testExportObjectWithReference() : void { $foo = 'bar'; $bar = ['foo' => & $foo]; $baz = (object) $bar; $var = Dumper::export($baz, 2); $baz->foo = 'tab'; self::assertEquals('bar', $var->foo); self::assertEquals('tab', $bar['foo']); } public function testExportArray() : void { $array = ['a' => 'b', 'b' => ['c', 'd' => ['e', 'f']]]; $var = Dumper::export($array, 2); $expected = $array; $expected['b']['d'] = 'Array(2)'; self::assertEquals($expected, $var); } public function testExportDateTime() : void { $obj = new DateTime('2010-10-10 10:10:10', new DateTimeZone('UTC')); $var = Dumper::export($obj, 2); self::assertEquals('DateTime', $var->__CLASS__); self::assertEquals('2010-10-10T10:10:10+00:00', $var->date); } public function testExportDateTimeImmutable() : void { $obj = new DateTimeImmutable('2010-10-10 10:10:10', new DateTimeZone('UTC')); $var = Dumper::export($obj, 2); self::assertEquals('DateTimeImmutable', $var->__CLASS__); self::assertEquals('2010-10-10T10:10:10+00:00', $var->date); } public function testExportDateTimeZone() : void { $obj = new DateTimeImmutable('2010-10-10 12:34:56', new DateTimeZone('Europe/Rome')); $var = Dumper::export($obj, 2); self::assertEquals('DateTimeImmutable', $var->__CLASS__); self::assertEquals('2010-10-10T12:34:56+02:00', $var->date); } public function testExportArrayTraversable() : void { $obj = new ArrayObject(['foobar']); $var = Dumper::export($obj, 2); self::assertContains('foobar', $var->__STORAGE__); $it = new ArrayIterator(['foobar']); $var = Dumper::export($it, 5); self::assertContains('foobar', $var->__STORAGE__); } /** * @param string[] $expected * * @dataProvider provideAttributesCases */ public function testExportParentAttributes(TestAsset\ParentClass $class, array $expected) : void { $print_r_class = print_r($class, true); $print_r_expected = print_r($expected, true); $print_r_class = substr($print_r_class, strpos($print_r_class, '(')); $print_r_expected = substr($print_r_expected, strpos($print_r_expected, '(')); self::assertSame($print_r_class, $print_r_expected); $var = Dumper::export($class, 3); $var = (array) $var; unset($var['__CLASS__']); self::assertSame($expected, $var); } /** * @return mixed[][] */ public static function provideAttributesCases() : iterable { return [ 'different-attributes' => [ new TestAsset\ChildClass(), [ 'childPublicAttribute' => 4, 'childProtectedAttribute:protected' => 5, 'childPrivateAttribute:Doctrine\Tests\DBAL\Tools\TestAsset\ChildClass:private' => 6, 'parentPublicAttribute' => 1, 'parentProtectedAttribute:protected' => 2, 'parentPrivateAttribute:Doctrine\Tests\DBAL\Tools\TestAsset\ParentClass:private' => 3, ], ], 'same-attributes' => [ new TestAsset\ChildWithSameAttributesClass(), [ 'parentPublicAttribute' => 4, 'parentProtectedAttribute:protected' => 5, 'parentPrivateAttribute:Doctrine\Tests\DBAL\Tools\TestAsset\ChildWithSameAttributesClass:private' => 6, 'parentPrivateAttribute:Doctrine\Tests\DBAL\Tools\TestAsset\ParentClass:private' => 3, ], ], ]; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Tools/TestAsset/000077500000000000000000000000001360544566000246345ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Tools/TestAsset/ChildClass.php000066400000000000000000000004361360544566000273610ustar00rootroot00000000000000platform = $this->createMock(AbstractPlatform::class); $this->type = Type::getType('array'); } public function testArrayConvertsToDatabaseValue() : void { self::assertIsString($this->type->convertToDatabaseValue([], $this->platform)); } public function testArrayConvertsToPHPValue() : void { self::assertIsArray($this->type->convertToPHPValue(serialize([]), $this->platform)); } public function testConversionFailure() : void { $this->expectException(ConversionException::class); $this->expectExceptionMessage("Could not convert database value to 'array' as an error was triggered by the unserialization: 'unserialize(): Error at offset 0 of 7 bytes'"); $this->type->convertToPHPValue('abcdefg', $this->platform); } public function testNullConversion() : void { self::assertNull($this->type->convertToPHPValue(null, $this->platform)); } /** * @group DBAL-73 */ public function testFalseConversion() : void { self::assertFalse($this->type->convertToPHPValue(serialize(false), $this->platform)); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Types/BaseDateTypeTestCase.php000066400000000000000000000064361360544566000274110ustar00rootroot00000000000000platform = $this->getMockForAbstractClass(AbstractPlatform::class); $this->currentTimezone = date_default_timezone_get(); self::assertInstanceOf(Type::class, $this->type); } /** * {@inheritDoc} */ protected function tearDown() : void { date_default_timezone_set($this->currentTimezone); } public function testDateConvertsToDatabaseValue() : void { self::assertIsString($this->type->convertToDatabaseValue(new DateTime(), $this->platform)); } /** * @param mixed $value * * @dataProvider invalidPHPValuesProvider */ public function testInvalidTypeConversionToDatabaseValue($value) : void { $this->expectException(ConversionException::class); $this->type->convertToDatabaseValue($value, $this->platform); } public function testNullConversion() : void { self::assertNull($this->type->convertToPHPValue(null, $this->platform)); } public function testConvertDateTimeToPHPValue() : void { $date = new DateTime('now'); self::assertSame($date, $this->type->convertToPHPValue($date, $this->platform)); } /** * @group #2794 * * Note that while \@see \DateTimeImmutable is supposed to be handled * by @see \Doctrine\DBAL\Types\DateTimeImmutableType, previous DBAL versions handled it just fine. * This test is just in place to prevent further regressions, even if the type is being misused */ public function testConvertDateTimeImmutableToPHPValue() : void { $date = new DateTimeImmutable('now'); self::assertSame($date, $this->type->convertToPHPValue($date, $this->platform)); } /** * @group #2794 * * Note that while \@see \DateTimeImmutable is supposed to be handled * by @see \Doctrine\DBAL\Types\DateTimeImmutableType, previous DBAL versions handled it just fine. * This test is just in place to prevent further regressions, even if the type is being misused */ public function testDateTimeImmutableConvertsToDatabaseValue() : void { self::assertIsString($this->type->convertToDatabaseValue(new DateTimeImmutable(), $this->platform)); } /** * @return mixed[][] */ public static function invalidPHPValuesProvider() : iterable { return [ [0], [''], ['foo'], ['10:11:12'], ['2015-01-31'], ['2015-01-31 10:11:12'], [new stdClass()], [27], [-1], [1.2], [[]], [['an array']], ]; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Types/BinaryTest.php000066400000000000000000000053531360544566000255240ustar00rootroot00000000000000platform = $this->createMock(AbstractPlatform::class); $this->type = Type::getType('binary'); } public function testReturnsBindingType() : void { self::assertSame(ParameterType::BINARY, $this->type->getBindingType()); } public function testReturnsName() : void { self::assertSame(Types::BINARY, $this->type->getName()); } public function testReturnsSQLDeclaration() : void { $this->platform->expects($this->once()) ->method('getBinaryTypeDeclarationSQL') ->willReturn('TEST_BINARY'); self::assertSame('TEST_BINARY', $this->type->getSQLDeclaration([], $this->platform)); } public function testBinaryNullConvertsToPHPValue() : void { self::assertNull($this->type->convertToPHPValue(null, $this->platform)); } public function testBinaryStringConvertsToPHPValue() : void { $databaseValue = 'binary string'; $phpValue = $this->type->convertToPHPValue($databaseValue, $this->platform); self::assertIsResource($phpValue); self::assertEquals($databaseValue, stream_get_contents($phpValue)); } public function testBinaryResourceConvertsToPHPValue() : void { $databaseValue = fopen('data://text/plain;base64,' . base64_encode('binary string'), 'r'); $phpValue = $this->type->convertToPHPValue($databaseValue, $this->platform); self::assertSame($databaseValue, $phpValue); } /** * @param mixed $value * * @dataProvider getInvalidDatabaseValues */ public function testThrowsConversionExceptionOnInvalidDatabaseValue($value) : void { $this->expectException(ConversionException::class); $this->type->convertToPHPValue($value, $this->platform); } /** * @return mixed[][] */ public static function getInvalidDatabaseValues() : iterable { return [ [false], [true], [0], [1], [-1], [0.0], [1.1], [-1.1], ]; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Types/BlobTest.php000066400000000000000000000034001360544566000251450ustar00rootroot00000000000000platform = $this->createMock(AbstractPlatform::class); $this->type = Type::getType('blob'); } public function testBlobNullConvertsToPHPValue() : void { self::assertNull($this->type->convertToPHPValue(null, $this->platform)); } public function testBinaryStringConvertsToPHPValue() : void { $databaseValue = $this->getBinaryString(); $phpValue = $this->type->convertToPHPValue($databaseValue, $this->platform); self::assertIsResource($phpValue); self::assertSame($databaseValue, stream_get_contents($phpValue)); } public function testBinaryResourceConvertsToPHPValue() : void { $databaseValue = fopen('data://text/plain;base64,' . base64_encode($this->getBinaryString()), 'r'); $phpValue = $this->type->convertToPHPValue($databaseValue, $this->platform); self::assertSame($databaseValue, $phpValue); } /** * Creates a binary string containing all possible byte values. */ private function getBinaryString() : string { $string = ''; for ($i = 0; $i < 256; $i++) { $string .= chr($i); } return $string; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Types/BooleanTest.php000066400000000000000000000020331360544566000256470ustar00rootroot00000000000000platform = $this->getMockForAbstractClass(AbstractPlatform::class); $this->type = Type::getType('boolean'); } public function testBooleanConvertsToDatabaseValue() : void { self::assertIsInt($this->type->convertToDatabaseValue(1, $this->platform)); } public function testBooleanConvertsToPHPValue() : void { self::assertIsBool($this->type->convertToPHPValue(0, $this->platform)); } public function testBooleanNullConvertsToPHPValue() : void { self::assertNull($this->type->convertToPHPValue(null, $this->platform)); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Types/ConversionExceptionTest.php000066400000000000000000000044531360544566000303040ustar00rootroot00000000000000getMessage() ); } /** * @param mixed $nonScalar * * @dataProvider nonScalarsProvider */ public function testConversionFailedInvalidTypeWithNonScalar($nonScalar) : void { $exception = ConversionException::conversionFailedInvalidType($nonScalar, 'foo', ['bar', 'baz']); self::assertInstanceOf(ConversionException::class, $exception); self::assertRegExp( '/^Could not convert PHP value of type \'(.*)\' to type \'foo\'. ' . 'Expected one of the following types: bar, baz$/', $exception->getMessage() ); } public function testConversionFailedFormatPreservesPreviousException() : void { $previous = new Exception(); $exception = ConversionException::conversionFailedFormat('foo', 'bar', 'baz', $previous); self::assertInstanceOf(ConversionException::class, $exception); self::assertSame($previous, $exception->getPrevious()); } /** * @return mixed[][] */ public static function nonScalarsProvider() : iterable { return [ [[]], [['foo']], [null], [new stdClass()], [tmpfile()], ]; } /** * @return mixed[][] */ public static function scalarsProvider() : iterable { return [ [''], ['foo'], [123], [-123], [12.34], [true], [false], ]; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Types/DateImmutableTypeTest.php000066400000000000000000000071311360544566000276530ustar00rootroot00000000000000type = Type::getType('date_immutable'); $this->platform = $this->createMock(AbstractPlatform::class); } public function testFactoryCreatesCorrectType() : void { self::assertSame(DateImmutableType::class, get_class($this->type)); } public function testReturnsName() : void { self::assertSame('date_immutable', $this->type->getName()); } public function testReturnsBindingType() : void { self::assertSame(ParameterType::STRING, $this->type->getBindingType()); } public function testConvertsDateTimeImmutableInstanceToDatabaseValue() : void { $date = $this->createMock(DateTimeImmutable::class); $this->platform->expects($this->once()) ->method('getDateFormatString') ->willReturn('Y-m-d'); $date->expects($this->once()) ->method('format') ->with('Y-m-d') ->willReturn('2016-01-01'); self::assertSame( '2016-01-01', $this->type->convertToDatabaseValue($date, $this->platform) ); } public function testConvertsNullToDatabaseValue() : void { self::assertNull($this->type->convertToDatabaseValue(null, $this->platform)); } public function testDoesNotSupportMutableDateTimeToDatabaseValueConversion() : void { $this->expectException(ConversionException::class); $this->type->convertToDatabaseValue(new DateTime(), $this->platform); } public function testConvertsDateTimeImmutableInstanceToPHPValue() : void { $date = new DateTimeImmutable(); self::assertSame($date, $this->type->convertToPHPValue($date, $this->platform)); } public function testConvertsNullToPHPValue() : void { self::assertNull($this->type->convertToPHPValue(null, $this->platform)); } public function testConvertsDateStringToPHPValue() : void { $this->platform->expects($this->once()) ->method('getDateFormatString') ->willReturn('Y-m-d'); $date = $this->type->convertToPHPValue('2016-01-01', $this->platform); self::assertInstanceOf(DateTimeImmutable::class, $date); self::assertSame('2016-01-01', $date->format('Y-m-d')); } public function testResetTimeFractionsWhenConvertingToPHPValue() : void { $this->platform->expects($this->any()) ->method('getDateFormatString') ->willReturn('Y-m-d'); $date = $this->type->convertToPHPValue('2016-01-01', $this->platform); self::assertSame('2016-01-01 00:00:00.000000', $date->format('Y-m-d H:i:s.u')); } public function testThrowsExceptionDuringConversionToPHPValueWithInvalidDateString() : void { $this->expectException(ConversionException::class); $this->type->convertToPHPValue('invalid date string', $this->platform); } public function testRequiresSQLCommentHint() : void { self::assertTrue($this->type->requiresSQLCommentHint($this->platform)); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Types/DateIntervalTest.php000066400000000000000000000076301360544566000266620ustar00rootroot00000000000000platform = $this->createMock(AbstractPlatform::class); $this->type = Type::getType('dateinterval'); self::assertInstanceOf(DateIntervalType::class, $this->type); } public function testDateIntervalConvertsToDatabaseValue() : void { $interval = new DateInterval('P2Y1DT1H2M3S'); $expected = '+P02Y00M01DT01H02M03S'; $actual = $this->type->convertToDatabaseValue($interval, $this->platform); self::assertEquals($expected, $actual); } public function testDateIntervalConvertsToPHPValue() : void { $interval = $this->type->convertToPHPValue('+P02Y00M01DT01H02M03S', $this->platform); self::assertInstanceOf(DateInterval::class, $interval); self::assertEquals('+P02Y00M01DT01H02M03S', $interval->format(DateIntervalType::FORMAT)); } public function testNegativeDateIntervalConvertsToDatabaseValue() : void { $interval = new DateInterval('P2Y1DT1H2M3S'); $interval->invert = 1; $actual = $this->type->convertToDatabaseValue($interval, $this->platform); self::assertEquals('-P02Y00M01DT01H02M03S', $actual); } public function testNegativeDateIntervalConvertsToPHPValue() : void { $interval = $this->type->convertToPHPValue('-P02Y00M01DT01H02M03S', $this->platform); self::assertInstanceOf(DateInterval::class, $interval); self::assertEquals('-P02Y00M01DT01H02M03S', $interval->format(DateIntervalType::FORMAT)); } public function testDateIntervalFormatWithoutSignConvertsToPHPValue() : void { $interval = $this->type->convertToPHPValue('P02Y00M01DT01H02M03S', $this->platform); self::assertInstanceOf(DateInterval::class, $interval); self::assertEquals('+P02Y00M01DT01H02M03S', $interval->format(DateIntervalType::FORMAT)); } public function testInvalidDateIntervalFormatConversion() : void { $this->expectException(ConversionException::class); $this->type->convertToPHPValue('abcdefg', $this->platform); } public function testDateIntervalNullConversion() : void { self::assertNull($this->type->convertToPHPValue(null, $this->platform)); } public function testDateIntervalEmptyStringConversion() : void { $this->expectException(ConversionException::class); $this->type->convertToPHPValue('', $this->platform); } /** * @group DBAL-1288 */ public function testRequiresSQLCommentHint() : void { self::assertTrue($this->type->requiresSQLCommentHint($this->platform)); } /** * @param mixed $value * * @dataProvider invalidPHPValuesProvider */ public function testInvalidTypeConversionToDatabaseValue($value) : void { $this->expectException(ConversionException::class); $this->type->convertToDatabaseValue($value, $this->platform); } /** * @return mixed[][] */ public static function invalidPHPValuesProvider() : iterable { return [ [0], [''], ['foo'], ['10:11:12'], ['2015-01-31'], ['2015-01-31 10:11:12'], [new stdClass()], [27], [-1], [1.2], [[]], [['an array']], [new DateTime()], ]; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Types/DateTest.php000066400000000000000000000031741360544566000251540ustar00rootroot00000000000000type = Type::getType('date'); parent::setUp(); } public function testDateConvertsToPHPValue() : void { // Birthday of jwage and also birthday of Doctrine. Send him a present ;) self::assertInstanceOf( DateTime::class, $this->type->convertToPHPValue('1985-09-01', $this->platform) ); } public function testDateResetsNonDatePartsToZeroUnixTimeValues() : void { $date = $this->type->convertToPHPValue('1985-09-01', $this->platform); self::assertEquals('00:00:00', $date->format('H:i:s')); } public function testDateRestsSummerTimeAffection() : void { date_default_timezone_set('Europe/Berlin'); $date = $this->type->convertToPHPValue('2009-08-01', $this->platform); self::assertEquals('00:00:00', $date->format('H:i:s')); self::assertEquals('2009-08-01', $date->format('Y-m-d')); $date = $this->type->convertToPHPValue('2009-11-01', $this->platform); self::assertEquals('00:00:00', $date->format('H:i:s')); self::assertEquals('2009-11-01', $date->format('Y-m-d')); } public function testInvalidDateFormatConversion() : void { $this->expectException(ConversionException::class); $this->type->convertToPHPValue('abcdefg', $this->platform); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Types/DateTimeImmutableTypeTest.php000066400000000000000000000076561360544566000305060ustar00rootroot00000000000000type = Type::getType('datetime_immutable'); $this->platform = $this->getMockBuilder(AbstractPlatform::class)->getMock(); } public function testFactoryCreatesCorrectType() : void { self::assertSame(DateTimeImmutableType::class, get_class($this->type)); } public function testReturnsName() : void { self::assertSame('datetime_immutable', $this->type->getName()); } public function testReturnsBindingType() : void { self::assertSame(ParameterType::STRING, $this->type->getBindingType()); } public function testConvertsDateTimeImmutableInstanceToDatabaseValue() : void { $date = $this->getMockBuilder(DateTimeImmutable::class)->getMock(); $this->platform->expects($this->once()) ->method('getDateTimeFormatString') ->willReturn('Y-m-d H:i:s'); $date->expects($this->once()) ->method('format') ->with('Y-m-d H:i:s') ->willReturn('2016-01-01 15:58:59'); self::assertSame( '2016-01-01 15:58:59', $this->type->convertToDatabaseValue($date, $this->platform) ); } public function testConvertsNullToDatabaseValue() : void { self::assertNull($this->type->convertToDatabaseValue(null, $this->platform)); } public function testDoesNotSupportMutableDateTimeToDatabaseValueConversion() : void { $this->expectException(ConversionException::class); $this->type->convertToDatabaseValue(new DateTime(), $this->platform); } public function testConvertsDateTimeImmutableInstanceToPHPValue() : void { $date = new DateTimeImmutable(); self::assertSame($date, $this->type->convertToPHPValue($date, $this->platform)); } public function testConvertsNullToPHPValue() : void { self::assertNull($this->type->convertToPHPValue(null, $this->platform)); } public function testConvertsDateTimeStringToPHPValue() : void { $this->platform->expects($this->once()) ->method('getDateTimeFormatString') ->willReturn('Y-m-d H:i:s'); $date = $this->type->convertToPHPValue('2016-01-01 15:58:59', $this->platform); self::assertInstanceOf(DateTimeImmutable::class, $date); self::assertSame('2016-01-01 15:58:59', $date->format('Y-m-d H:i:s')); } /** * @group DBAL-415 */ public function testConvertsDateTimeStringWithMicrosecondsToPHPValue() : void { $this->platform->expects($this->any()) ->method('getDateTimeFormatString') ->willReturn('Y-m-d H:i:s'); $date = $this->type->convertToPHPValue('2016-01-01 15:58:59.123456', $this->platform); self::assertSame('2016-01-01 15:58:59', $date->format('Y-m-d H:i:s')); } public function testThrowsExceptionDuringConversionToPHPValueWithInvalidDateTimeString() : void { $this->platform->expects($this->atLeastOnce()) ->method('getDateTimeFormatString') ->willReturn('Y-m-d H:i:s'); $this->expectException(ConversionException::class); $this->type->convertToPHPValue('invalid datetime string', $this->platform); } public function testRequiresSQLCommentHint() : void { self::assertTrue($this->type->requiresSQLCommentHint($this->platform)); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Types/DateTimeTest.php000066400000000000000000000030411360544566000257640ustar00rootroot00000000000000type = Type::getType('datetime'); parent::setUp(); } public function testDateTimeConvertsToDatabaseValue() : void { $date = new DateTime('1985-09-01 10:10:10'); $expected = $date->format($this->platform->getDateTimeTzFormatString()); $actual = $this->type->convertToDatabaseValue($date, $this->platform); self::assertEquals($expected, $actual); } public function testDateTimeConvertsToPHPValue() : void { // Birthday of jwage and also birthday of Doctrine. Send him a present ;) $date = $this->type->convertToPHPValue('1985-09-01 00:00:00', $this->platform); self::assertInstanceOf('DateTime', $date); self::assertEquals('1985-09-01 00:00:00', $date->format('Y-m-d H:i:s')); } public function testInvalidDateTimeFormatConversion() : void { $this->expectException(ConversionException::class); $this->type->convertToPHPValue('abcdefg', $this->platform); } public function testConvertsNonMatchingFormatToPhpValueWithParser() : void { $date = '1985/09/01 10:10:10.12345'; $actual = $this->type->convertToPHPValue($date, $this->platform); self::assertEquals('1985-09-01 10:10:10', $actual->format('Y-m-d H:i:s')); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Types/DateTimeTzImmutableTypeTest.php000066400000000000000000000070441360544566000310130ustar00rootroot00000000000000type = Type::getType('datetimetz_immutable'); $this->platform = $this->createMock(AbstractPlatform::class); } public function testFactoryCreatesCorrectType() : void { self::assertSame(DateTimeTzImmutableType::class, get_class($this->type)); } public function testReturnsName() : void { self::assertSame('datetimetz_immutable', $this->type->getName()); } public function testReturnsBindingType() : void { self::assertSame(ParameterType::STRING, $this->type->getBindingType()); } public function testConvertsDateTimeImmutableInstanceToDatabaseValue() : void { $date = $this->createMock(DateTimeImmutable::class); $this->platform->expects($this->once()) ->method('getDateTimeTzFormatString') ->willReturn('Y-m-d H:i:s T'); $date->expects($this->once()) ->method('format') ->with('Y-m-d H:i:s T') ->willReturn('2016-01-01 15:58:59 UTC'); self::assertSame( '2016-01-01 15:58:59 UTC', $this->type->convertToDatabaseValue($date, $this->platform) ); } public function testConvertsNullToDatabaseValue() : void { self::assertNull($this->type->convertToDatabaseValue(null, $this->platform)); } public function testDoesNotSupportMutableDateTimeToDatabaseValueConversion() : void { $this->expectException(ConversionException::class); $this->type->convertToDatabaseValue(new DateTime(), $this->platform); } public function testConvertsDateTimeImmutableInstanceToPHPValue() : void { $date = new DateTimeImmutable(); self::assertSame($date, $this->type->convertToPHPValue($date, $this->platform)); } public function testConvertsNullToPHPValue() : void { self::assertNull($this->type->convertToPHPValue(null, $this->platform)); } public function testConvertsDateTimeWithTimezoneStringToPHPValue() : void { $this->platform->expects($this->once()) ->method('getDateTimeTzFormatString') ->willReturn('Y-m-d H:i:s T'); $date = $this->type->convertToPHPValue('2016-01-01 15:58:59 UTC', $this->platform); self::assertInstanceOf(DateTimeImmutable::class, $date); self::assertSame('2016-01-01 15:58:59 UTC', $date->format('Y-m-d H:i:s T')); } public function testThrowsExceptionDuringConversionToPHPValueWithInvalidDateTimeWithTimezoneString() : void { $this->platform->expects($this->atLeastOnce()) ->method('getDateTimeTzFormatString') ->willReturn('Y-m-d H:i:s T'); $this->expectException(ConversionException::class); $this->type->convertToPHPValue('invalid datetime with timezone string', $this->platform); } public function testRequiresSQLCommentHint() : void { self::assertTrue($this->type->requiresSQLCommentHint($this->platform)); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Types/DateTimeTzTest.php000066400000000000000000000023711360544566000263070ustar00rootroot00000000000000type = Type::getType('datetimetz'); parent::setUp(); } public function testDateTimeConvertsToDatabaseValue() : void { $date = new DateTime('1985-09-01 10:10:10'); $expected = $date->format($this->platform->getDateTimeTzFormatString()); $actual = $this->type->convertToDatabaseValue($date, $this->platform); self::assertEquals($expected, $actual); } public function testDateTimeConvertsToPHPValue() : void { // Birthday of jwage and also birthday of Doctrine. Send him a present ;) $date = $this->type->convertToPHPValue('1985-09-01 00:00:00', $this->platform); self::assertInstanceOf('DateTime', $date); self::assertEquals('1985-09-01 00:00:00', $date->format('Y-m-d H:i:s')); } public function testInvalidDateFormatConversion() : void { $this->expectException(ConversionException::class); $this->type->convertToPHPValue('abcdefg', $this->platform); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Types/DecimalTest.php000066400000000000000000000015631360544566000256350ustar00rootroot00000000000000platform = $this->createMock(AbstractPlatform::class); $this->type = Type::getType('decimal'); } public function testDecimalConvertsToPHPValue() : void { self::assertIsString($this->type->convertToPHPValue('5.5', $this->platform)); } public function testDecimalNullConvertsToPHPValue() : void { self::assertNull($this->type->convertToPHPValue(null, $this->platform)); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Types/FloatTest.php000066400000000000000000000022541360544566000253420ustar00rootroot00000000000000platform = $this->createMock(AbstractPlatform::class); $this->type = Type::getType('float'); } public function testFloatConvertsToPHPValue() : void { self::assertIsFloat($this->type->convertToPHPValue('5.5', $this->platform)); } public function testFloatNullConvertsToPHPValue() : void { self::assertNull($this->type->convertToPHPValue(null, $this->platform)); } public function testFloatConvertToDatabaseValue() : void { self::assertIsFloat($this->type->convertToDatabaseValue(5.5, $this->platform)); } public function testFloatNullConvertToDatabaseValue() : void { self::assertNull($this->type->convertToDatabaseValue(null, $this->platform)); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Types/GuidTypeTest.php000066400000000000000000000024231360544566000260250ustar00rootroot00000000000000platform = $this->createMock(AbstractPlatform::class); $this->type = Type::getType('guid'); } public function testConvertToPHPValue() : void { self::assertIsString($this->type->convertToPHPValue('foo', $this->platform)); self::assertIsString($this->type->convertToPHPValue('', $this->platform)); } public function testNullConversion() : void { self::assertNull($this->type->convertToPHPValue(null, $this->platform)); } public function testNativeGuidSupport() : void { self::assertTrue($this->type->requiresSQLCommentHint($this->platform)); $this->platform->expects($this->any()) ->method('hasNativeGuidType') ->will($this->returnValue(true)); self::assertFalse($this->type->requiresSQLCommentHint($this->platform)); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Types/IntegerTest.php000066400000000000000000000016771360544566000257020ustar00rootroot00000000000000platform = $this->createMock(AbstractPlatform::class); $this->type = Type::getType('integer'); } public function testIntegerConvertsToPHPValue() : void { self::assertIsInt($this->type->convertToPHPValue('1', $this->platform)); self::assertIsInt($this->type->convertToPHPValue('0', $this->platform)); } public function testIntegerNullConvertsToPHPValue() : void { self::assertNull($this->type->convertToPHPValue(null, $this->platform)); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Types/JsonArrayTest.php000066400000000000000000000046711360544566000262120ustar00rootroot00000000000000platform = $this->createMock(AbstractPlatform::class); $this->type = Type::getType('json_array'); } public function testReturnsBindingType() : void { self::assertSame(ParameterType::STRING, $this->type->getBindingType()); } public function testReturnsName() : void { self::assertSame(Types::JSON_ARRAY, $this->type->getName()); } public function testReturnsSQLDeclaration() : void { $this->platform->expects($this->once()) ->method('getJsonTypeDeclarationSQL') ->willReturn('TEST_JSON'); self::assertSame('TEST_JSON', $this->type->getSQLDeclaration([], $this->platform)); } public function testJsonNullConvertsToPHPValue() : void { self::assertSame([], $this->type->convertToPHPValue(null, $this->platform)); } public function testJsonEmptyStringConvertsToPHPValue() : void { self::assertSame([], $this->type->convertToPHPValue('', $this->platform)); } public function testJsonStringConvertsToPHPValue() : void { $value = ['foo' => 'bar', 'bar' => 'foo']; $databaseValue = json_encode($value); $phpValue = $this->type->convertToPHPValue($databaseValue, $this->platform); self::assertEquals($value, $phpValue); } public function testJsonResourceConvertsToPHPValue() : void { $value = ['foo' => 'bar', 'bar' => 'foo']; $databaseValue = fopen('data://text/plain;base64,' . base64_encode(json_encode($value)), 'r'); $phpValue = $this->type->convertToPHPValue($databaseValue, $this->platform); self::assertSame($value, $phpValue); } public function testRequiresSQLCommentHint() : void { self::assertTrue($this->type->requiresSQLCommentHint($this->platform)); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Types/JsonTest.php000066400000000000000000000055011360544566000252040ustar00rootroot00000000000000platform = $this->createMock(AbstractPlatform::class); $this->type = Type::getType('json'); } public function testReturnsBindingType() : void { self::assertSame(ParameterType::STRING, $this->type->getBindingType()); } public function testReturnsName() : void { self::assertSame(Types::JSON, $this->type->getName()); } public function testReturnsSQLDeclaration() : void { $this->platform->expects($this->once()) ->method('getJsonTypeDeclarationSQL') ->willReturn('TEST_JSON'); self::assertSame('TEST_JSON', $this->type->getSQLDeclaration([], $this->platform)); } public function testJsonNullConvertsToPHPValue() : void { self::assertNull($this->type->convertToPHPValue(null, $this->platform)); } public function testJsonEmptyStringConvertsToPHPValue() : void { self::assertNull($this->type->convertToPHPValue('', $this->platform)); } public function testJsonStringConvertsToPHPValue() : void { $value = ['foo' => 'bar', 'bar' => 'foo']; $databaseValue = json_encode($value); $phpValue = $this->type->convertToPHPValue($databaseValue, $this->platform); self::assertEquals($value, $phpValue); } /** @dataProvider providerFailure */ public function testConversionFailure(string $data) : void { $this->expectException(ConversionException::class); $this->type->convertToPHPValue($data, $this->platform); } /** * @return mixed[][] */ public static function providerFailure() : iterable { return [['a'], ['{']]; } public function testJsonResourceConvertsToPHPValue() : void { $value = ['foo' => 'bar', 'bar' => 'foo']; $databaseValue = fopen('data://text/plain;base64,' . base64_encode(json_encode($value)), 'r'); $phpValue = $this->type->convertToPHPValue($databaseValue, $this->platform); self::assertSame($value, $phpValue); } public function testRequiresSQLCommentHint() : void { self::assertTrue($this->type->requiresSQLCommentHint($this->platform)); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Types/ObjectTest.php000066400000000000000000000032571360544566000255070ustar00rootroot00000000000000platform = $this->createMock(AbstractPlatform::class); $this->type = Type::getType('object'); } public function testObjectConvertsToDatabaseValue() : void { self::assertIsString($this->type->convertToDatabaseValue(new stdClass(), $this->platform)); } public function testObjectConvertsToPHPValue() : void { self::assertIsObject($this->type->convertToPHPValue(serialize(new stdClass()), $this->platform)); } public function testConversionFailure() : void { $this->expectException(ConversionException::class); $this->expectExceptionMessage("Could not convert database value to 'object' as an error was triggered by the unserialization: 'unserialize(): Error at offset 0 of 7 bytes'"); $this->type->convertToPHPValue('abcdefg', $this->platform); } public function testNullConversion() : void { self::assertNull($this->type->convertToPHPValue(null, $this->platform)); } /** * @group DBAL-73 */ public function testFalseConversion() : void { self::assertFalse($this->type->convertToPHPValue(serialize(false), $this->platform)); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Types/SmallIntTest.php000066400000000000000000000017051360544566000260200ustar00rootroot00000000000000platform = $this->createMock(AbstractPlatform::class); $this->type = Type::getType('smallint'); } public function testSmallIntConvertsToPHPValue() : void { self::assertIsInt($this->type->convertToPHPValue('1', $this->platform)); self::assertIsInt($this->type->convertToPHPValue('0', $this->platform)); } public function testSmallIntNullConvertsToPHPValue() : void { self::assertNull($this->type->convertToPHPValue(null, $this->platform)); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Types/StringTest.php000066400000000000000000000036331360544566000255450ustar00rootroot00000000000000platform = $this->createMock(AbstractPlatform::class); $this->type = Type::getType('string'); } public function testReturnsSqlDeclarationFromPlatformVarchar() : void { $this->platform->expects($this->once()) ->method('getVarcharTypeDeclarationSQL') ->willReturn('TEST_VARCHAR'); self::assertEquals('TEST_VARCHAR', $this->type->getSqlDeclaration([], $this->platform)); } public function testReturnsDefaultLengthFromPlatformVarchar() : void { $this->platform->expects($this->once()) ->method('getVarcharDefaultLength') ->willReturn(255); self::assertEquals(255, $this->type->getDefaultLength($this->platform)); } public function testConvertToPHPValue() : void { self::assertIsString($this->type->convertToPHPValue('foo', $this->platform)); self::assertIsString($this->type->convertToPHPValue('', $this->platform)); } public function testNullConversion() : void { self::assertNull($this->type->convertToPHPValue(null, $this->platform)); } public function testSQLConversion() : void { self::assertFalse($this->type->canRequireSQLConversion(), 'String type can never require SQL conversion to work.'); self::assertEquals('t.foo', $this->type->convertToDatabaseValueSQL('t.foo', $this->platform)); self::assertEquals('t.foo', $this->type->convertToPHPValueSQL('t.foo', $this->platform)); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Types/TimeImmutableTypeTest.php000066400000000000000000000071441360544566000277000ustar00rootroot00000000000000type = Type::getType('time_immutable'); $this->platform = $this->getMockBuilder(AbstractPlatform::class)->getMock(); } public function testFactoryCreatesCorrectType() : void { self::assertSame(TimeImmutableType::class, get_class($this->type)); } public function testReturnsName() : void { self::assertSame('time_immutable', $this->type->getName()); } public function testReturnsBindingType() : void { self::assertSame(ParameterType::STRING, $this->type->getBindingType()); } public function testConvertsDateTimeImmutableInstanceToDatabaseValue() : void { $date = $this->getMockBuilder(DateTimeImmutable::class)->getMock(); $this->platform->expects($this->once()) ->method('getTimeFormatString') ->willReturn('H:i:s'); $date->expects($this->once()) ->method('format') ->with('H:i:s') ->willReturn('15:58:59'); self::assertSame( '15:58:59', $this->type->convertToDatabaseValue($date, $this->platform) ); } public function testConvertsNullToDatabaseValue() : void { self::assertNull($this->type->convertToDatabaseValue(null, $this->platform)); } public function testDoesNotSupportMutableDateTimeToDatabaseValueConversion() : void { $this->expectException(ConversionException::class); $this->type->convertToDatabaseValue(new DateTime(), $this->platform); } public function testConvertsDateTimeImmutableInstanceToPHPValue() : void { $date = new DateTimeImmutable(); self::assertSame($date, $this->type->convertToPHPValue($date, $this->platform)); } public function testConvertsNullToPHPValue() : void { self::assertNull($this->type->convertToPHPValue(null, $this->platform)); } public function testConvertsTimeStringToPHPValue() : void { $this->platform->expects($this->once()) ->method('getTimeFormatString') ->willReturn('H:i:s'); $date = $this->type->convertToPHPValue('15:58:59', $this->platform); self::assertInstanceOf(DateTimeImmutable::class, $date); self::assertSame('15:58:59', $date->format('H:i:s')); } public function testResetDateFractionsWhenConvertingToPHPValue() : void { $this->platform->expects($this->any()) ->method('getTimeFormatString') ->willReturn('H:i:s'); $date = $this->type->convertToPHPValue('15:58:59', $this->platform); self::assertSame('1970-01-01 15:58:59', $date->format('Y-m-d H:i:s')); } public function testThrowsExceptionDuringConversionToPHPValueWithInvalidTimeString() : void { $this->expectException(ConversionException::class); $this->type->convertToPHPValue('invalid time string', $this->platform); } public function testRequiresSQLCommentHint() : void { self::assertTrue($this->type->requiresSQLCommentHint($this->platform)); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Types/TimeTest.php000066400000000000000000000017251360544566000251750ustar00rootroot00000000000000type = Type::getType('time'); parent::setUp(); } public function testTimeConvertsToPHPValue() : void { self::assertInstanceOf('DateTime', $this->type->convertToPHPValue('5:30:55', $this->platform)); } public function testDateFieldResetInPHPValue() : void { $time = $this->type->convertToPHPValue('01:23:34', $this->platform); self::assertEquals('01:23:34', $time->format('H:i:s')); self::assertEquals('1970-01-01', $time->format('Y-m-d')); } public function testInvalidTimeFormatConversion() : void { $this->expectException(ConversionException::class); $this->type->convertToPHPValue('abcdefg', $this->platform); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Types/TypeRegistryTest.php000066400000000000000000000110151360544566000267420ustar00rootroot00000000000000testType = new BlobType(); $this->otherTestType = new BinaryType(); $this->registry = new TypeRegistry(); $this->registry->register(self::TEST_TYPE_NAME, $this->testType); $this->registry->register(self::OTHER_TEST_TYPE_NAME, $this->otherTestType); } public function testGet() : void { self::assertSame($this->testType, $this->registry->get(self::TEST_TYPE_NAME)); self::assertSame($this->otherTestType, $this->registry->get(self::OTHER_TEST_TYPE_NAME)); $this->expectException(DBALException::class); $this->registry->get('unknown'); } public function testGetReturnsSameInstances() : void { self::assertSame( $this->registry->get(self::TEST_TYPE_NAME), $this->registry->get(self::TEST_TYPE_NAME) ); } public function testLookupName() : void { self::assertSame( self::TEST_TYPE_NAME, $this->registry->lookupName($this->testType) ); self::assertSame( self::OTHER_TEST_TYPE_NAME, $this->registry->lookupName($this->otherTestType) ); $this->expectException(DBALException::class); $this->registry->lookupName(new TextType()); } public function testHas() : void { self::assertTrue($this->registry->has(self::TEST_TYPE_NAME)); self::assertTrue($this->registry->has(self::OTHER_TEST_TYPE_NAME)); self::assertFalse($this->registry->has('unknown')); } public function testRegister() : void { $newType = new TextType(); $this->registry->register('some', $newType); self::assertTrue($this->registry->has('some')); self::assertSame($newType, $this->registry->get('some')); } public function testRegisterWithAlradyRegisteredName() : void { $this->registry->register('some', new TextType()); $this->expectException(DBALException::class); $this->registry->register('some', new TextType()); } public function testRegisterWithAlreadyRegisteredInstance() : void { $newType = new TextType(); $this->registry->register('some', $newType); $this->expectException(DBALException::class); $this->registry->register('other', $newType); } public function testOverride() : void { $baseType = new TextType(); $overrideType = new StringType(); $this->registry->register('some', $baseType); $this->registry->override('some', $overrideType); self::assertSame($overrideType, $this->registry->get('some')); } public function testOverrideAllowsExistingInstance() : void { $type = new TextType(); $this->registry->register('some', $type); $this->registry->override('some', $type); self::assertSame($type, $this->registry->get('some')); } public function testOverrideWithAlreadyRegisteredInstance() : void { $newType = new TextType(); $this->registry->register('first', $newType); $this->registry->register('second', new StringType()); $this->expectException(DBALException::class); $this->registry->override('second', $newType); } public function testOverrideWithUnknownType() : void { $this->expectException(DBALException::class); $this->registry->override('unknown', new TextType()); } public function testGetMap() : void { $registeredTypes = $this->registry->getMap(); self::assertCount(2, $registeredTypes); self::assertArrayHasKey(self::TEST_TYPE_NAME, $registeredTypes); self::assertArrayHasKey(self::OTHER_TEST_TYPE_NAME, $registeredTypes); self::assertSame($this->testType, $registeredTypes[self::TEST_TYPE_NAME]); self::assertSame($this->otherTestType, $registeredTypes[self::OTHER_TEST_TYPE_NAME]); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Types/TypeTest.php000066400000000000000000000013221360544566000252110ustar00rootroot00000000000000getReflectionConstants() as $constant) { if (! $constant->isPublic()) { continue; } yield [$constant->getValue()]; } } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Types/VarDateTimeImmutableTypeTest.php000066400000000000000000000061261360544566000311460ustar00rootroot00000000000000type = Type::getType('vardatetime_immutable'); $this->platform = $this->getMockForAbstractClass(AbstractPlatform::class); } public function testReturnsName() : void { self::assertSame('datetime_immutable', $this->type->getName()); } public function testReturnsBindingType() : void { self::assertSame(ParameterType::STRING, $this->type->getBindingType()); } public function testConvertsDateTimeImmutableInstanceToDatabaseValue() : void { $date = $this->getMockBuilder(DateTimeImmutable::class)->getMock(); $date->expects($this->once()) ->method('format') ->with('Y-m-d H:i:s') ->willReturn('2016-01-01 15:58:59'); self::assertSame( '2016-01-01 15:58:59', $this->type->convertToDatabaseValue($date, $this->platform) ); } public function testConvertsNullToDatabaseValue() : void { self::assertNull($this->type->convertToDatabaseValue(null, $this->platform)); } public function testDoesNotSupportMutableDateTimeToDatabaseValueConversion() : void { $this->expectException(ConversionException::class); $this->type->convertToDatabaseValue(new DateTime(), $this->platform); } public function testConvertsDateTimeImmutableInstanceToPHPValue() : void { $date = new DateTimeImmutable(); self::assertSame($date, $this->type->convertToPHPValue($date, $this->platform)); } public function testConvertsNullToPHPValue() : void { self::assertNull($this->type->convertToPHPValue(null, $this->platform)); } public function testConvertsDateishStringToPHPValue() : void { $date = $this->type->convertToPHPValue('2016-01-01 15:58:59.123456 UTC', $this->platform); self::assertInstanceOf(DateTimeImmutable::class, $date); self::assertSame('2016-01-01 15:58:59.123456 UTC', $date->format('Y-m-d H:i:s.u T')); } public function testThrowsExceptionDuringConversionToPHPValueWithInvalidDateishString() : void { $this->expectException(ConversionException::class); $this->type->convertToPHPValue('invalid date-ish string', $this->platform); } public function testRequiresSQLCommentHint() : void { self::assertTrue($this->type->requiresSQLCommentHint($this->platform)); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/Types/VarDateTimeTest.php000066400000000000000000000046111360544566000264410ustar00rootroot00000000000000platform = $this->createMock(AbstractPlatform::class); if (! Type::hasType('vardatetime')) { Type::addType('vardatetime', VarDateTimeType::class); } $this->type = Type::getType('vardatetime'); } public function testDateTimeConvertsToDatabaseValue() : void { $date = new DateTime('1985-09-01 10:10:10'); $expected = $date->format($this->platform->getDateTimeTzFormatString()); $actual = $this->type->convertToDatabaseValue($date, $this->platform); self::assertEquals($expected, $actual); } public function testDateTimeConvertsToPHPValue() : void { // Birthday of jwage and also birthday of Doctrine. Send him a present ;) $date = $this->type->convertToPHPValue('1985-09-01 00:00:00', $this->platform); self::assertInstanceOf('DateTime', $date); self::assertEquals('1985-09-01 00:00:00', $date->format('Y-m-d H:i:s')); self::assertEquals('000000', $date->format('u')); } public function testInvalidDateTimeFormatConversion() : void { $this->expectException(ConversionException::class); $this->type->convertToPHPValue('abcdefg', $this->platform); } public function testConversionWithMicroseconds() : void { $date = $this->type->convertToPHPValue('1985-09-01 00:00:00.123456', $this->platform); self::assertInstanceOf('DateTime', $date); self::assertEquals('1985-09-01 00:00:00', $date->format('Y-m-d H:i:s')); self::assertEquals('123456', $date->format('u')); } public function testNullConversion() : void { self::assertNull($this->type->convertToPHPValue(null, $this->platform)); } public function testConvertDateTimeToPHPValue() : void { $date = new DateTime('now'); self::assertSame($date, $this->type->convertToPHPValue($date, $this->platform)); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DBAL/UtilTest.php000066400000000000000000000056261360544566000241140ustar00rootroot00000000000000 ':param1'], ], [ 'SELECT name FROM users WHERE id = ? AND status = ?', 'SELECT name FROM users WHERE id = :param1 AND status = :param2', [1 => ':param1', 2 => ':param2'], ], [ "UPDATE users SET name = '???', status = ?", "UPDATE users SET name = '???', status = :param1", [1 => ':param1'], ], [ "UPDATE users SET status = ?, name = '???'", "UPDATE users SET status = :param1, name = '???'", [1 => ':param1'], ], [ "UPDATE users SET foo = ?, name = '???', status = ?", "UPDATE users SET foo = :param1, name = '???', status = :param2", [1 => ':param1', 2 => ':param2'], ], [ 'UPDATE users SET name = "???", status = ?', 'UPDATE users SET name = "???", status = :param1', [1 => ':param1'], ], [ 'UPDATE users SET status = ?, name = "???"', 'UPDATE users SET status = :param1, name = "???"', [1 => ':param1'], ], [ 'UPDATE users SET foo = ?, name = "???", status = ?', 'UPDATE users SET foo = :param1, name = "???", status = :param2', [1 => ':param1', 2 => ':param2'], ], [ 'SELECT * FROM users WHERE id = ? AND name = "" AND status = ?', 'SELECT * FROM users WHERE id = :param1 AND name = "" AND status = :param2', [1 => ':param1', 2 => ':param2'], ], [ "SELECT * FROM users WHERE id = ? AND name = '' AND status = ?", "SELECT * FROM users WHERE id = :param1 AND name = '' AND status = :param2", [1 => ':param1', 2 => ':param2'], ], ]; } /** * @param mixed[] $expectedOutputParamsMap * * @dataProvider dataConvertPositionalToNamedParameters */ public function testConvertPositionalToNamedParameters(string $inputSQL, string $expectedOutputSQL, array $expectedOutputParamsMap) : void { [$statement, $params] = OCI8Statement::convertPositionalToNamedPlaceholders($inputSQL); self::assertEquals($expectedOutputSQL, $statement); self::assertEquals($expectedOutputParamsMap, $params); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DbalFunctionalTestCase.php000066400000000000000000000062111360544566000261450ustar00rootroot00000000000000close(); self::$sharedConnection = null; } protected function setUp() : void { if (! isset(self::$sharedConnection)) { self::$sharedConnection = TestUtil::getConnection(); } $this->connection = self::$sharedConnection; $this->sqlLoggerStack = new DebugStack(); $this->connection->getConfiguration()->setSQLLogger($this->sqlLoggerStack); } protected function tearDown() : void { while ($this->connection->isTransactionActive()) { $this->connection->rollBack(); } } protected function onNotSuccessfulTest(Throwable $t) : void { if ($t instanceof AssertionFailedError) { throw $t; } if (isset($this->sqlLoggerStack->queries) && count($this->sqlLoggerStack->queries)) { $queries = ''; $i = count($this->sqlLoggerStack->queries); foreach (array_reverse($this->sqlLoggerStack->queries) as $query) { $params = array_map(static function ($p) { if (is_object($p)) { return get_class($p); } if (is_scalar($p)) { return "'" . $p . "'"; } return var_export($p, true); }, $query['params'] ?: []); $queries .= $i . ". SQL: '" . $query['sql'] . "' Params: " . implode(', ', $params) . PHP_EOL; $i--; } $trace = $t->getTrace(); $traceMsg = ''; foreach ($trace as $part) { if (! isset($part['file'])) { continue; } if (strpos($part['file'], 'PHPUnit/') !== false) { // Beginning with PHPUnit files we don't print the trace anymore. break; } $traceMsg .= $part['file'] . ':' . $part['line'] . PHP_EOL; } $message = '[' . get_class($t) . '] ' . $t->getMessage() . PHP_EOL . PHP_EOL . 'With queries:' . PHP_EOL . $queries . PHP_EOL . 'Trace:' . PHP_EOL . $traceMsg; throw new Exception($message, (int) $t->getCode(), $t); } throw $t; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DbalPerformanceTestCase.php000066400000000000000000000024261360544566000263100ustar00rootroot00000000000000startTime, 'Test timing was started'); self::assertNotNull($this->runTime, 'Test timing was stopped'); } /** * begin timing */ protected function startTiming() : void { $this->startTime = microtime(true); } /** * end timing */ protected function stopTiming() : void { $this->runTime = microtime(true) - $this->startTime; } /** * @return float elapsed test execution time */ public function getTime() : float { return $this->runTime; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DbalPerformanceTestListener.php000066400000000000000000000032531360544566000272210ustar00rootroot00000000000000timings[$class])) { $this->timings[$class] = []; } // Store timing data for each test in the order they were run. $this->timings[$class][$test->getName(true)] = $test->getTime(); } /** * Report performance test timings. * * Note: __destruct is used here because PHPUnit doesn't have a * 'All tests over' hook. */ public function __destruct() { if (empty($this->timings)) { return; } // Report timings. print "\nPerformance test results:\n\n"; foreach ($this->timings as $class => $tests) { printf("%s:\n", $class); foreach ($tests as $test => $time) { printf("\t%s: %.3f seconds\n", $test, $time); } } } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/DbalTestCase.php000066400000000000000000000002531360544566000241220ustar00rootroot00000000000000real database connection using the following parameters * of the $GLOBALS array: * * 'db_type' : The name of the Doctrine DBAL database driver to use. * 'db_username' : The username to use for connecting. * 'db_password' : The password to use for connecting. * 'db_host' : The hostname of the database to connect to. * 'db_server' : The server name of the database to connect to * (optional, some vendors allow multiple server instances with different names on the same host). * 'db_name' : The name of the database to connect to. * 'db_port' : The port of the database to connect to. * * Usually these variables of the $GLOBALS array are filled by PHPUnit based * on an XML configuration file. If no such parameters exist, an SQLite * in-memory database is used. * * IMPORTANT: Each invocation of this method returns a NEW database connection. * * @return Connection The database connection instance. */ public static function getConnection() : Connection { if (self::hasRequiredConnectionParams() && ! self::$initialized) { self::initializeDatabase(); self::$initialized = true; } $conn = DriverManager::getConnection(self::getConnectionParams()); self::addDbEventSubscribers($conn); return $conn; } /** * @return mixed[] */ public static function getConnectionParams() : array { if (self::hasRequiredConnectionParams()) { return self::getParamsForMainConnection(); } return self::getFallbackConnectionParams(); } private static function hasRequiredConnectionParams() : bool { return isset( $GLOBALS['db_type'], $GLOBALS['db_username'], $GLOBALS['db_password'], $GLOBALS['db_host'], $GLOBALS['db_name'], $GLOBALS['db_port'] ) && isset( $GLOBALS['tmpdb_type'], $GLOBALS['tmpdb_username'], $GLOBALS['tmpdb_password'], $GLOBALS['tmpdb_host'], $GLOBALS['tmpdb_port'] ); } private static function initializeDatabase() : void { $realDbParams = self::getParamsForMainConnection(); $tmpDbParams = self::getParamsForTemporaryConnection(); $realConn = DriverManager::getConnection($realDbParams); // Connect to tmpdb in order to drop and create the real test db. $tmpConn = DriverManager::getConnection($tmpDbParams); $platform = $tmpConn->getDatabasePlatform(); if ($platform->supportsCreateDropDatabase()) { $dbname = $realConn->getDatabase(); $realConn->close(); $tmpConn->getSchemaManager()->dropAndCreateDatabase($dbname); $tmpConn->close(); } else { $sm = $realConn->getSchemaManager(); $schema = $sm->createSchema(); $stmts = $schema->toDropSql($realConn->getDatabasePlatform()); foreach ($stmts as $stmt) { $realConn->exec($stmt); } } } /** * @return mixed[] */ private static function getFallbackConnectionParams() : array { if (! extension_loaded('pdo_sqlite')) { Assert::markTestSkipped('PDO SQLite extension is not loaded'); } $params = [ 'driver' => 'pdo_sqlite', 'memory' => true, ]; if (isset($GLOBALS['db_path'])) { $params['path'] = $GLOBALS['db_path']; unlink($GLOBALS['db_path']); } return $params; } private static function addDbEventSubscribers(Connection $conn) : void { if (! isset($GLOBALS['db_event_subscribers'])) { return; } $evm = $conn->getEventManager(); foreach (explode(',', $GLOBALS['db_event_subscribers']) as $subscriberClass) { $subscriberInstance = new $subscriberClass(); $evm->addEventSubscriber($subscriberInstance); } } /** * @return mixed[] */ private static function getParamsForTemporaryConnection() : array { $connectionParams = [ 'driver' => $GLOBALS['tmpdb_type'], 'user' => $GLOBALS['tmpdb_username'], 'password' => $GLOBALS['tmpdb_password'], 'host' => $GLOBALS['tmpdb_host'], 'dbname' => null, 'port' => $GLOBALS['tmpdb_port'], ]; if (isset($GLOBALS['tmpdb_name'])) { $connectionParams['dbname'] = $GLOBALS['tmpdb_name']; } if (isset($GLOBALS['tmpdb_server'])) { $connectionParams['server'] = $GLOBALS['tmpdb_server']; } if (isset($GLOBALS['tmpdb_unix_socket'])) { $connectionParams['unix_socket'] = $GLOBALS['tmpdb_unix_socket']; } return $connectionParams; } /** * @return mixed[] */ private static function getParamsForMainConnection() : array { $connectionParams = [ 'driver' => $GLOBALS['db_type'], 'user' => $GLOBALS['db_username'], 'password' => $GLOBALS['db_password'], 'host' => $GLOBALS['db_host'], 'dbname' => $GLOBALS['db_name'], 'port' => $GLOBALS['db_port'], ]; if (isset($GLOBALS['db_server'])) { $connectionParams['server'] = $GLOBALS['db_server']; } if (isset($GLOBALS['db_unix_socket'])) { $connectionParams['unix_socket'] = $GLOBALS['db_unix_socket']; } return $connectionParams; } public static function getTempConnection() : Connection { return DriverManager::getConnection(self::getParamsForTemporaryConnection()); } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/Types/000077500000000000000000000000001360544566000222175ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/Types/CommentedType.php000066400000000000000000000011511360544566000255030ustar00rootroot00000000000000getName()); } /** * {@inheritDoc} */ public function requiresSQLCommentHint(AbstractPlatform $platform) { return true; } } php-doctrine-dbal-2.10.1/tests/Doctrine/Tests/Types/MySqlPointType.php000066400000000000000000000011501360544566000256460ustar00rootroot00000000000000getName()); } /** * {@inheritDoc} */ public function getMappedDatabaseTypes(AbstractPlatform $platform) { return ['point']; } } php-doctrine-dbal-2.10.1/tests/appveyor/000077500000000000000000000000001360544566000201075ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/appveyor/mssql.sql2008r2sp2.sqlsrv.appveyor.xml000066400000000000000000000027541360544566000271760ustar00rootroot00000000000000 ../Doctrine/Tests/DBAL ../../lib/Doctrine performance locking_functional php-doctrine-dbal-2.10.1/tests/appveyor/mssql.sql2012sp1.sqlsrv.appveyor.xml000066400000000000000000000027501360544566000267200ustar00rootroot00000000000000 ../Doctrine/Tests/DBAL ../../lib/Doctrine performance locking_functional php-doctrine-dbal-2.10.1/tests/appveyor/mssql.sql2017.pdo_sqlsrv.appveyor.xml000066400000000000000000000027501360544566000271430ustar00rootroot00000000000000 ../Doctrine/Tests/DBAL ../../lib/Doctrine performance locking_functional php-doctrine-dbal-2.10.1/tests/appveyor/mssql.sql2017.sqlsrv.appveyor.xml000066400000000000000000000027421360544566000263020ustar00rootroot00000000000000 ../Doctrine/Tests/DBAL ../../lib/Doctrine performance locking_functional php-doctrine-dbal-2.10.1/tests/continuousphp/000077500000000000000000000000001360544566000211605ustar00rootroot00000000000000php-doctrine-dbal-2.10.1/tests/continuousphp/bootstrap.php000066400000000000000000000015461360544566000237140ustar00rootroot00000000000000 'oci8', 'host' => 'oracle-xe-11', 'user' => 'ORACLE', 'password' => 'ORACLE', 'dbname' => 'XE', ])->query('ALTER USER ORACLE IDENTIFIED BY ORACLE'); $pos = array_search('--coverage-clover', $_SERVER['argv'], true); if ($pos === false) { return; } $file = $_SERVER['argv'][$pos + 1]; register_shutdown_function(static function () use ($file) : void { $cmd = 'wget https://github.com/scrutinizer-ci/ocular/releases/download/1.5.2/ocular.phar' . ' && php ocular.phar code-coverage:upload --format=php-clover ' . escapeshellarg($file); passthru($cmd); }); })(); php-doctrine-dbal-2.10.1/tests/continuousphp/install-pdo-oci.sh000077500000000000000000000003011360544566000245070ustar00rootroot00000000000000#!/bin/bash set -euo pipefail docker-php-ext-configure pdo_oci --with-pdo-oci=instantclient,/usr/local/instantclient sudo -E env PHP_INI_DIR=/usr/local/etc/php docker-php-ext-install pdo_oci php-doctrine-dbal-2.10.1/tests/continuousphp/oci8.phpunit.continuousphp.xml000066400000000000000000000027311360544566000271520ustar00rootroot00000000000000 ../Doctrine/Tests/DBAL ../../lib/Doctrine performance locking_functional php-doctrine-dbal-2.10.1/tests/continuousphp/pdo-oci.phpunit.xml000066400000000000000000000024631360544566000247270ustar00rootroot00000000000000 ../Doctrine/Tests/DBAL ../../lib/Doctrine php-doctrine-dbal-2.10.1/tests/phpstan-polyfill.php000066400000000000000000000005121360544566000222560ustar00rootroot00000000000000 ../Doctrine/Tests/DBAL ../../lib/Doctrine performance locking_functional php-doctrine-dbal-2.10.1/tests/travis/install-db2-ibm_db2.sh000066400000000000000000000012521360544566000235150ustar00rootroot00000000000000#!/usr/bin/env bash set -ex echo "Installing extension" ( # updating APT packages as per support recommendation sudo apt -y -q update sudo apt install ksh cd /tmp wget http://cdn1.netmake.com.br/download/Conexao/DB2/Linux/x64_v10.5fp8_linuxx64_dsdriver.tar.gz tar xf x64_v10.5fp8_linuxx64_dsdriver.tar.gz ksh dsdriver/installDSDriver pecl download ibm_db2 tar xf ibm_db2-* rm ibm_db2-*.tgz cd ibm_db2-* phpize ./configure --with-IBM_DB2=/tmp/dsdriver make -j `nproc` make install echo -e 'extension=ibm_db2.so\nibm_db2.instance_name=db2inst1' > ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/ibm_db2.ini ) php-doctrine-dbal-2.10.1/tests/travis/install-db2.sh000066400000000000000000000010751360544566000222240ustar00rootroot00000000000000#!/usr/bin/env bash set -ex echo Setting up IBM DB2 echo "su - db2inst1 -c 'db2 CONNECT TO doctrine && db2 CREATE USER TEMPORARY TABLESPACE doctrine_tbsp PAGESIZE 4 K'" > /tmp/doctrine-init.sh chmod +x /tmp/doctrine-init.sh sudo docker run \ -d \ -p 50000:50000 \ -e DB2INST1_PASSWORD=Doctrine2018 \ -e LICENSE=accept \ -e DBNAME=doctrine \ -v /tmp/doctrine-init.sh:/var/custom/doctrine-init.sh:ro \ --name db2 \ --privileged=true \ ibmcom/db2:11.5.0.0 sudo docker logs -f db2 | sed '/(*) Setup has completed./ q' echo DB2 started php-doctrine-dbal-2.10.1/tests/travis/install-mssql-pdo_sqlsrv.sh000066400000000000000000000001401360544566000250760ustar00rootroot00000000000000#!/usr/bin/env bash set -ex echo "Installing extension" pecl install pdo_sqlsrv-5.7.0preview php-doctrine-dbal-2.10.1/tests/travis/install-mssql-sqlsrv.sh000066400000000000000000000001341360544566000242370ustar00rootroot00000000000000#!/usr/bin/env bash set -ex echo "Installing extension" pecl install sqlsrv-5.7.0preview php-doctrine-dbal-2.10.1/tests/travis/install-mssql.sh000066400000000000000000000007541360544566000227170ustar00rootroot00000000000000#!/usr/bin/env bash set -ex echo Setting up Microsoft SQL Server sudo docker pull microsoft/mssql-server-linux:2017-latest sudo docker run \ -e 'ACCEPT_EULA=Y' \ -e 'SA_PASSWORD=Doctrine2018' \ -p 127.0.0.1:1433:1433 \ --name mssql \ -d \ microsoft/mssql-server-linux:2017-latest sudo docker exec -i mssql bash <<< 'until echo quit | /opt/mssql-tools/bin/sqlcmd -S 127.0.0.1 -l 1 -U sa -P Doctrine2018 > /dev/null 2>&1 ; do sleep 1; done' echo SQL Server started php-doctrine-dbal-2.10.1/tests/travis/install-mysql-5.7.sh000066400000000000000000000005171360544566000232310ustar00rootroot00000000000000#!/usr/bin/env bash set -ex echo "Starting MySQL 5.7..." sudo docker run \ -d \ -e MYSQL_ALLOW_EMPTY_PASSWORD=yes \ -e MYSQL_DATABASE=doctrine_tests \ -p 33306:3306 \ --name mysql57 \ mysql:5.7 sudo docker exec -i mysql57 bash <<< 'until echo \\q | mysql doctrine_tests > /dev/null 2>&1 ; do sleep 1; done' php-doctrine-dbal-2.10.1/tests/travis/install-mysql-8.0.sh000066400000000000000000000006461360544566000232300ustar00rootroot00000000000000#!/usr/bin/env bash set -ex echo "Starting MySQL 8.0..." sudo docker pull mysql:8.0 sudo docker run \ -d \ -e MYSQL_ALLOW_EMPTY_PASSWORD=yes \ -e MYSQL_DATABASE=doctrine_tests \ -p 33306:3306 \ --name mysql80 \ mysql:8.0 \ --default-authentication-plugin=mysql_native_password sudo docker exec -i mysql80 bash <<< 'until echo \\q | mysql doctrine_tests > /dev/null 2>&1 ; do sleep 1; done' php-doctrine-dbal-2.10.1/tests/travis/install-postgres-10.sh000066400000000000000000000005021360544566000236330ustar00rootroot00000000000000#!/usr/bin/env bash set -ex echo "Installing Postgres 10" sudo service postgresql stop sudo apt-get remove -q 'postgresql-*' sudo apt-get update -q sudo apt-get install -q postgresql-10 postgresql-client-10 sudo cp /etc/postgresql/{9.6,10}/main/pg_hba.conf echo "Restarting Postgres 10" sudo service postgresql restart php-doctrine-dbal-2.10.1/tests/travis/install-postgres-11.sh000066400000000000000000000004471360544566000236440ustar00rootroot00000000000000#!/usr/bin/env bash set -ex echo "Preparing Postgres 11" sudo service postgresql stop || true sudo docker run -d --name postgres11 -p 5432:5432 postgres:11.1 sudo docker exec -i postgres11 bash <<< 'until pg_isready -U postgres > /dev/null 2>&1 ; do sleep 1; done' echo "Postgres 11 ready" php-doctrine-dbal-2.10.1/tests/travis/install-sqlsrv-dependencies.sh000066400000000000000000000005501360544566000255300ustar00rootroot00000000000000#!/usr/bin/env bash set -ex echo Installing driver dependencies curl https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add - curl https://packages.microsoft.com/config/ubuntu/14.04/prod.list | sudo tee /etc/apt/sources.list.d/mssql.list sudo apt-get update ACCEPT_EULA=Y sudo apt-get install -qy msodbcsql17 unixodbc unixodbc-dev libssl1.0.0 php-doctrine-dbal-2.10.1/tests/travis/mariadb.mysqli.travis.xml000066400000000000000000000027071360544566000245250ustar00rootroot00000000000000 ../Doctrine/Tests/DBAL ../../lib/Doctrine performance locking_functional php-doctrine-dbal-2.10.1/tests/travis/mariadb.travis.xml000066400000000000000000000026351360544566000232100ustar00rootroot00000000000000 ../Doctrine/Tests/DBAL ../../lib/Doctrine performance locking_functional php-doctrine-dbal-2.10.1/tests/travis/mysql.docker.travis.xml000066400000000000000000000026331360544566000242220ustar00rootroot00000000000000 ../Doctrine/Tests/DBAL ../../lib/Doctrine performance locking_functional php-doctrine-dbal-2.10.1/tests/travis/mysql.travis.xml000066400000000000000000000026351360544566000227560ustar00rootroot00000000000000 ../Doctrine/Tests/DBAL ../../lib/Doctrine performance locking_functional php-doctrine-dbal-2.10.1/tests/travis/mysqli.docker.travis.xml000066400000000000000000000026251360544566000243740ustar00rootroot00000000000000 ../Doctrine/Tests/DBAL ../../lib/Doctrine performance locking_functional php-doctrine-dbal-2.10.1/tests/travis/mysqli.travis.xml000066400000000000000000000026271360544566000231300ustar00rootroot00000000000000 ../Doctrine/Tests/DBAL ../../lib/Doctrine performance locking_functional php-doctrine-dbal-2.10.1/tests/travis/pdo_sqlsrv.travis.xml000066400000000000000000000026511360544566000240030ustar00rootroot00000000000000 ../Doctrine/Tests/DBAL ../../lib/Doctrine performance locking_functional php-doctrine-dbal-2.10.1/tests/travis/pgsql.travis.xml000066400000000000000000000026411360544566000227340ustar00rootroot00000000000000 ../Doctrine/Tests/DBAL ../../lib/Doctrine performance locking_functional php-doctrine-dbal-2.10.1/tests/travis/sqlite.travis.xml000066400000000000000000000016021360544566000231030ustar00rootroot00000000000000 ../Doctrine/Tests/DBAL ../../lib/Doctrine performance locking_functional php-doctrine-dbal-2.10.1/tests/travis/sqlsrv.travis.xml000066400000000000000000000026411360544566000231400ustar00rootroot00000000000000 ../Doctrine/Tests/DBAL ../../lib/Doctrine performance locking_functional