├── .github
└── workflows
│ ├── docs.yml
│ └── tests.yml
├── .gitignore
├── .phpcs.xml
├── .readthedocs.yml
├── .scrutinizer.yml
├── AUTHORS.rst
├── CHANGES.txt
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.rst
├── DEVELOP.rst
├── LICENSE
├── NOTICE
├── README.rst
├── Vagrantfile
├── codecov.yml
├── composer.json
├── devtools
└── create_tag.sh
├── docs
├── Makefile
├── _extra
│ └── robots.txt
├── appendices
│ ├── compatibility.rst
│ ├── data-types.rst
│ ├── index.rst
│ └── table-options.rst
├── build.json
├── conf.py
├── connect.rst
├── docutils.conf
├── getting-started.rst
├── index.rst
└── requirements.txt
├── phpunit.xml.dist
├── provisioning.sh
├── src
└── Crate
│ └── DBAL
│ ├── Driver
│ └── PDOCrate
│ │ ├── CrateStatement.php
│ │ ├── Driver.php
│ │ └── PDOConnection.php
│ ├── Platforms
│ ├── CratePlatform.php
│ ├── CratePlatform1.php
│ ├── CratePlatform4.php
│ └── Keywords
│ │ └── CrateKeywords.php
│ ├── Schema
│ └── CrateSchemaManager.php
│ └── Types
│ ├── ArrayType.php
│ ├── MapType.php
│ └── TimestampType.php
└── test
└── Crate
└── Test
└── DBAL
├── DBALFunctionalTestCase.php
├── Functional
├── BindingTest.php
├── ConnectionTest.php
├── DataAccessTest.php
├── ModifyLimitQueryTest.php
├── NamedParametersTest.php
├── Schema
│ └── SchemaManagerTest.php
├── TableOptionsTest.php
├── TypeConversionTest.php
├── Types
│ └── MapTypeTest.php
└── WriteTest.php
├── PDOCrate
└── DriverTest.php
└── Platforms
└── CratePlatformTest.php
/.github/workflows/docs.yml:
--------------------------------------------------------------------------------
1 | name: Docs
2 |
3 | on:
4 | push:
5 | branches: [ main ]
6 | pull_request:
7 | branches: [ main ]
8 |
9 | schedule:
10 | - cron: '0 7 * * *'
11 |
12 | # Allow job to be triggered manually.
13 | workflow_dispatch:
14 |
15 | # Cancel in-progress jobs when pushing to the same branch.
16 | concurrency:
17 | cancel-in-progress: true
18 | group: ${{ github.workflow }}-${{ github.ref }}
19 |
20 | jobs:
21 | documentation:
22 | name: Build docs on ${{ matrix.os }}
23 | runs-on: ${{ matrix.os }}
24 |
25 | strategy:
26 | matrix:
27 | os: [ubuntu-latest]
28 |
29 | steps:
30 |
31 | - name: Acquire sources
32 | uses: actions/checkout@v3
33 |
34 | - name: Set up Python
35 | uses: actions/setup-python@v4
36 | with:
37 | python-version: "3.11"
38 |
39 | - name: Build docs
40 | run: |
41 | cd docs && make check
42 |
--------------------------------------------------------------------------------
/.github/workflows/tests.yml:
--------------------------------------------------------------------------------
1 | name: Tests
2 |
3 | on:
4 | push:
5 | branches: [ main ]
6 | pull_request:
7 | branches: [ main ]
8 |
9 | # Allow job to be triggered manually.
10 | workflow_dispatch:
11 |
12 | # Cancel in-progress jobs when pushing to the same branch.
13 | concurrency:
14 | cancel-in-progress: true
15 | group: ${{ github.workflow }}-${{ github.ref }}
16 |
17 | jobs:
18 | tests:
19 |
20 | runs-on: ${{ matrix.os }}
21 | strategy:
22 | fail-fast: false
23 | matrix:
24 | os: [ 'ubuntu-latest' ] #, macos-latest, windows-latest ]
25 | php-version: [ '8.0', '8.1', '8.2', '8.3', '8.4' ]
26 |
27 | # https://docs.github.com/en/free-pro-team@latest/actions/guides/about-service-containers
28 | services:
29 | cratedb:
30 | image: crate/crate:nightly
31 | ports:
32 | - 4200:4200
33 |
34 | # https://github.com/marketplace/actions/setup-php-action
35 | name: PHP ${{ matrix.php-version }} on OS ${{ matrix.os }}
36 | steps:
37 |
38 | - name: Acquire sources
39 | uses: actions/checkout@v3
40 | with:
41 | fetch-depth: 2
42 |
43 | - name: Setup PHP
44 | uses: shivammathur/setup-php@v2
45 | with:
46 | php-version: ${{ matrix.php-version }}
47 | # Select PHPUnit version suitable for PHP 7.2.
48 | tools: composer, phpunit:^8.5
49 |
50 | - uses: ramsey/composer-install@v2
51 |
52 | # Remark: --prefer-source is needed for "Doctrine\Tests\DBAL\Platforms\AbstractPlatformTestCase"
53 | - name: Install doctrine/dbal from source
54 | run: |
55 | rm -rf vendor/doctrine/dbal
56 | composer update doctrine/dbal --prefer-source
57 |
58 | - name: Run code style checks
59 | run: composer run check-style
60 |
61 | - name: Run tests
62 | run: composer run test
63 |
64 | # https://github.com/codecov/codecov-action
65 | - name: Upload coverage results to Codecov
66 | uses: codecov/codecov-action@v4
67 | if: always() && (matrix.php-version == '7.4' || startsWith(matrix.php-version, '8.'))
68 | with:
69 | files: ./build/logs/clover.xml
70 | fail_ci_if_error: false
71 |
72 | - name: Upload coverage results to Scrutinizer CI
73 | if: always() && (matrix.php-version == '7.4' || startsWith(matrix.php-version, '8.'))
74 | run: |
75 | composer global require scrutinizer/ocular
76 | ocular code-coverage:upload --format=php-clover build/logs/clover.xml
77 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | .installed.cfg
3 | .project
4 | .vagrant
5 | .phpunit.result.cache
6 | *-console.log
7 | .crate-docs
8 | /composer.lock
9 | bin/
10 | build/
11 | composer.phar
12 | out/
13 | report/
14 | vendor/
15 |
--------------------------------------------------------------------------------
/.phpcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ./src
7 | ./vendor/*
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.readthedocs.yml:
--------------------------------------------------------------------------------
1 | ---
2 | version: 2
3 |
4 | build:
5 | os: "ubuntu-22.04"
6 | tools:
7 | python: "3.11"
8 |
9 | python:
10 | install:
11 | - requirements: docs/requirements.txt
12 |
13 | sphinx:
14 | builder: html
15 | configuration: docs/conf.py
16 | fail_on_warning: true
17 |
--------------------------------------------------------------------------------
/.scrutinizer.yml:
--------------------------------------------------------------------------------
1 | #
2 | # Scrutinizer code analysis for PHP.
3 | #
4 | # https://scrutinizer-ci.com/docs/guides/php/
5 | # https://scrutinizer-ci.com/docs/guides/php/continuous-integration-deployment
6 | # https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/
7 | # https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/checks
8 |
9 |
10 | filter:
11 |
12 | # Everything in a root level "test" directory will be excluded
13 | excluded_paths:
14 | - "test/"
15 |
16 | # Everything in a root level "vendor" directory will be excluded from analysis
17 | # but treated as a dependency
18 | dependency_paths:
19 | - "vendor/"
20 |
21 |
22 | before_commands:
23 | - "composer install --dev --prefer-source"
24 |
25 |
26 | # Use new PHP Analysis Engine.
27 | # https://scrutinizer-ci.com/docs/tools/php/php-analyzer/guides/migrate_to_new_php_analysis
28 | build:
29 | nodes:
30 | analysis:
31 | environment:
32 | php:
33 | version: 8.1
34 | tests:
35 | override:
36 | - php-scrutinizer-run --enable-security-analysis
37 | - phpcs-run --standard=.phpcs.xml
38 |
39 |
40 | # https://scrutinizer-ci.com/docs/tools/external-code-coverage/
41 | tools:
42 | external_code_coverage:
43 |
44 | enabled: true
45 |
46 | # Scrutinizer will wait for two code coverage submissions
47 | # in order to cover both PHP7 and PHP8.
48 | runs: 2
49 |
--------------------------------------------------------------------------------
/AUTHORS.rst:
--------------------------------------------------------------------------------
1 | Main Authors
2 | ============
3 |
4 | Christian Haudum (@chaudum)
5 | Sebastian Utz (@seut)
6 | Tom Kapanka (@spanktar)
7 |
8 | Code Contributors
9 | =================
10 |
11 | Kamil Adryjanek (@kadryjanek)
12 | Alexander Schranz (@alexander-schranz)
13 |
14 | Note: (@user) means a github user name.
15 |
--------------------------------------------------------------------------------
/CHANGES.txt:
--------------------------------------------------------------------------------
1 | ======================
2 | CHANGES for crate-dbal
3 | ======================
4 |
5 | Unreleased
6 | ==========
7 |
8 | - Verified support on PHP 8.4
9 |
10 | 2024/02/02 4.0.2
11 | ================
12 |
13 | - Update internal version number
14 |
15 | 2024/02/02 4.0.1
16 | ================
17 |
18 | - README: Update list of supported PHP versions
19 |
20 | 2024/02/02 4.0.0
21 | ================
22 |
23 | - Dropped support for PHP 7.x, it has reached end of life
24 | - Added support for PHP 8.3
25 |
26 | 2022/11/29 3.0.1
27 | ================
28 |
29 | - Added support for PHP 8.1 and PHP 8.2
30 |
31 | 2021/04/28 3.0.0
32 | ================
33 |
34 | - Dropped support for PHP 7.2, it has reached end of life
35 |
36 | - Upgraded to CrateDB PDO Adapter 2.1.2
37 |
38 | - Fixed compatibility with Doctrine DBAL 2.13
39 |
40 | - Added support for PHP 8.0
41 |
42 | 2020/06/18 2.3.0
43 | ================
44 |
45 | Changes
46 | -------
47 |
48 | - Added support for CrateDB specific table options when retrieving table information
49 | from the schema manager.
50 |
51 | Fixes
52 | -----
53 |
54 | None
55 |
56 | 2020/01/08 2.2.0
57 | ================
58 |
59 | Changes
60 | -------
61 |
62 | - Updated Doctrine DBAL version to 2.10
63 |
64 | Fixes
65 | -----
66 |
67 | None
68 |
69 | 2019/11/21 2.1.0
70 | ================
71 |
72 | Changes
73 | -------
74 |
75 | - Added support for CrateDB specific table options incl. usage documentation.
76 |
77 | Fixes
78 | -----
79 |
80 | - Fixed handling of ``PRIMARY KEY`` contraints.
81 | Tables *without* any PK raised an exception while reading, on Tables
82 | *with* any PK, the constraints weren't read/processed correctly.
83 |
84 |
85 | 2019/08/20 2.0.0
86 | ================
87 |
88 | - Added support for CrateDB >= 4.0
89 |
90 | - Added ARRAY type mapping for all typed arrays supported by CrateDB. Before
91 | only a subset was supported.
92 |
93 | - Updated Doctrine DBAL version to 2.9
94 |
95 | - BREAKING: Drop support for PHP < 7.2
96 |
97 | 2018/09/05 1.1.0
98 | ================
99 |
100 | - Added support for latest (< 2.7.0) Doctrine version
101 |
102 | 2018/06/15 1.0.0
103 | ================
104 |
105 | - Updated crate-pdo to ``1.0.0`` which includes following changes:
106 |
107 | - Added support for SSL via ``PDO::CRATE_ATTR_SSL_MODE``
108 |
109 | - BREAKING: Upgraded the library to use PHP 7.2 features
110 |
111 | 2017/02/06 0.3.1
112 | ================
113 |
114 | - Fixed an issue that ignored provided ``UNIQUE`` constraints. The client now
115 | throws an exception and informs the user to use the ``PRIMARY KEY``
116 | constraint instead.
117 |
118 | 2016/11/07 0.3.0
119 | ================
120 |
121 | - Updated crate-pdo to ``0.6.0`` which includes following changes:
122 |
123 | - Expose ``getServerVersion()`` and ``getServerInfo()`` on the PDO implementation
124 | which return the version number of the Crate server connected to.
125 |
126 | - Fix: having the same named parameter multiple times in a prepared SQL
127 | statement caused incorrect parameter substitution with bound values.
128 |
129 | - Fixed an issue that occur if parameters are passed in a different order
130 | than specified in the sql statement.
131 |
132 | - Updated dependency: guzzlehttp/guzzle to ~6.0
133 | WARNING: This is a backward incompatible change!
134 |
135 | - Support for multiple hosts in DSN connection string
136 |
137 | - Added support for using a default schema in PDO connection
138 | via ``/schema`` suffix in connection string.
139 |
140 | 2016/01/12 0.2.1
141 | ================
142 |
143 | - updated crate-pdo to ``0.3.1`` which includes following changes:
144 |
145 | - Added support for PHP 7
146 |
147 | 2015/05/08 0.2.0
148 | ================
149 |
150 | - updated crate-pdo to ``0.2.1`` which includes following changes:
151 |
152 | - Support guzzle http basic auth
153 | through doctrine dbal connection user credentials
154 |
155 | 2015/02/11 0.1.1
156 | ================
157 |
158 | - add support for latest (up to 2.5.1) Doctrine version
159 |
160 | 2015/01/08 0.1.0
161 | ================
162 |
163 | - updated dependency ``crate-pdo 0.1.0`` which includes following
164 | changes:
165 |
166 | - Fix performance issues by switching http client library to
167 | ``guzzle``.
168 |
169 | 2014/12/19 0.0.5
170 | ================
171 |
172 | - updated dependency ``crate-pdo 0.0.7`` which includes following changes:
173 |
174 | - Fix: Literals containing a `:` character were misinterpreted as
175 | named parameters.
176 |
177 | - Nailed dependency versions of amphp/artax and amphp/amp
178 | to prevent composer from fetching newer, incompatible releases
179 |
180 | 2014/11/27 0.0.4
181 | ================
182 |
183 | - updated dependency ``crate-pdo 0.0.5``, this version will support
184 | crate ``array`` and ``object`` data types
185 |
186 | 2014/10/30 0.0.3
187 | ================
188 |
189 | - updated dependency ``crate-pdo 0.0.4``
190 |
191 | 2014/10/27 0.0.2
192 | ================
193 |
194 | - updated dependencies:
195 | - php 5.5
196 | - crate-pdo 0.0.3
197 |
198 | 2014/10/27 0.0.1
199 | ================
200 |
201 | - initial release
202 | see ``README.rst`` for supported types, limitations and not supported DBAL features
203 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, sex characteristics, gender identity and expression,
9 | level of experience, education, socio-economic status, nationality, personal
10 | appearance, race, religion, or sexual identity and orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at support@crate.io. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72 |
73 | [homepage]: https://www.contributor-covenant.org
74 |
75 | For answers to common questions about this code of conduct, see
76 | https://www.contributor-covenant.org/faq
77 |
--------------------------------------------------------------------------------
/CONTRIBUTING.rst:
--------------------------------------------------------------------------------
1 | ============
2 | Contributing
3 | ============
4 |
5 | Thank you for your interest in contributing.
6 |
7 | Please see the CrateDB `contribution guide`_ for more information. Everything in
8 | the CrateDB contribution guide also applies to this repository.
9 |
10 | .. _contribution guide: https://github.com/crate/crate/blob/master/CONTRIBUTING.rst
11 |
--------------------------------------------------------------------------------
/DEVELOP.rst:
--------------------------------------------------------------------------------
1 | ###############
2 | Developer Guide
3 | ###############
4 |
5 |
6 | *************
7 | Using Vagrant
8 | *************
9 |
10 |
11 | Prerequisites
12 | =============
13 |
14 | You will need Vagrant_ and one of its providers.
15 |
16 | We currently use VirtualBox_ but any provider should work just as well.
17 |
18 | Installation
19 | ============
20 |
21 | Clone the project::
22 |
23 | git clone git@github.com:crate/crate-dbal.git
24 | cd crate-dbal
25 |
26 | Start up the Vagrant machine::
27 |
28 | vagrant up
29 |
30 | When run for the first time, it will also run the needed provisioning.
31 |
32 | If you are using IntelliJ or PhpStorm IDE you can follow the `IDE guide`_ to
33 | set up your remote interpreter and test environment.
34 |
35 | Running the Tests
36 | =================
37 |
38 | You can run the tests like::
39 |
40 | vagrant ssh
41 | cd /vagrant
42 |
43 | # Run test suite
44 | composer run test
45 |
46 | # Run code style checks
47 | composer run check-style
48 |
49 | # Some code style quirks can be automatically fixed
50 | composer run fix-style
51 |
52 |
53 |
54 | ************
55 | Using Docker
56 | ************
57 |
58 |
59 | Installation
60 | ============
61 |
62 | Install prerequisites::
63 |
64 | # Install different PHP releases.
65 | brew install php@7.3 php@7.4 php@8.0 brew-php-switcher composer
66 |
67 | # Select PHP version.
68 | brew-php-switcher 7.3
69 | brew-php-switcher 7.4
70 | brew-php-switcher 8.0
71 |
72 | # Install xdebug extension for tracking code coverage.
73 | pecl install xdebug
74 |
75 | Get the sources::
76 |
77 | git clone git@github.com:crate/crate-dbal.git
78 | cd crate-dbal
79 |
80 | Setup project dependencies::
81 |
82 | composer install
83 |
84 |
85 | Running the Tests
86 | =================
87 |
88 | ::
89 |
90 | # Run CrateDB
91 | docker run -it --rm --publish 4200:4200 --publish 5432:5432 crate/crate:nightly
92 |
93 | # Run test suite
94 | composer run test
95 |
96 | # Run code style checks
97 | composer run style
98 |
99 | # Run code style checks
100 | ./vendor/bin/phpcs ./src
101 |
102 |
103 | ****************************
104 | Working on the documentation
105 | ****************************
106 |
107 | - The documentation is written using `Sphinx`_ and `ReStructuredText`_.
108 | - Python>=3.7 is required.
109 |
110 | Change into the ``docs`` directory:
111 |
112 | .. code-block:: console
113 |
114 | $ cd docs
115 |
116 | For help, run:
117 |
118 | .. code-block:: console
119 |
120 | $ make
121 |
122 | Crate Docs Build
123 |
124 | Run `make `, where is one of:
125 |
126 | dev Run a Sphinx development server that builds and lints the
127 | documentation as you edit the source files
128 |
129 | html Build the static HTML output
130 |
131 | check Build, test, and lint the documentation
132 |
133 | qa Generate QA telemetry
134 |
135 | reset Reset the build
136 |
137 | You must install `fswatch`_ to use the ``dev`` target.
138 |
139 |
140 | Continuous integration and deployment
141 | =====================================
142 |
143 | CI is configured to run ``make check`` from the ``docs`` directory.
144 |
145 | `Read the Docs`_ (RTD) automatically deploys the documentation whenever a
146 | configured branch is updated.
147 |
148 | To make changes to the RTD configuration (e.g., to activate or deactivate a
149 | release version), please contact the `@crate/tech-writing`_ team.
150 |
151 |
152 | Archiving Docs Versions
153 | =======================
154 |
155 | Check the `versions hosted on ReadTheDocs`_.
156 |
157 | We should only be hosting the docs for `latest`, the last three minor release
158 | branches of the last major release, and the last minor release branch
159 | corresponding to the last two major releases.
160 |
161 | For example:
162 |
163 | - ``latest``
164 | - ``0.3``
165 | - ``0.2``
166 | - ``0.1``
167 |
168 | Because this project has not yet had a major release, as of yet, there are no
169 | major releases before `0` to include in this list.
170 |
171 | To make changes to the RTD configuration (e.g., to activate or deactivate a
172 | release version), please contact the `@crate/docs`_ team.
173 |
174 |
175 | *********
176 | Releasing
177 | *********
178 |
179 | - Bump version number in ``src/Crate/DBAL/Driver/PDOCrate/Driver.php``
180 | - Edit ``CHANGES.txt`` correspondingly
181 | - Commit changes: ``Release x.x.x``
182 | - Tag repository: ``git tag x.x.x``
183 | - Push to GitHub: ``git push && git push --tags``
184 | - Verify publishing worked: https://packagist.org/packages/crate/crate-dbal
185 |
186 |
187 | .. _@crate/docs: https://github.com/orgs/crate/teams/docs
188 | .. _@crate/tech-writing: https://github.com/orgs/crate/teams/tech-writing
189 | .. _Composer: https://getcomposer.org
190 | .. _IDE guide: https://gist.github.com/mikethebeer/d8feda1bcc6b6ef6ea59
191 | .. _ReStructuredText: http://docutils.sourceforge.net/rst.html
192 | .. _Sphinx: http://sphinx-doc.org/
193 | .. _Vagrant: https://www.vagrantup.com/downloads.html
194 | .. _versions hosted on ReadTheDocs: https://readthedocs.org/projects/crate-dbal/versions/
195 | .. _VirtualBox: https://www.virtualbox.org/
196 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 |
3 | Apache License
4 | Version 2.0, January 2004
5 | http://www.apache.org/licenses/
6 |
7 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
8 |
9 | 1. Definitions.
10 |
11 | "License" shall mean the terms and conditions for use, reproduction,
12 | and distribution as defined by Sections 1 through 9 of this document.
13 |
14 | "Licensor" shall mean the copyright owner or entity authorized by
15 | the copyright owner that is granting the License.
16 |
17 | "Legal Entity" shall mean the union of the acting entity and all
18 | other entities that control, are controlled by, or are under common
19 | control with that entity. For the purposes of this definition,
20 | "control" means (i) the power, direct or indirect, to cause the
21 | direction or management of such entity, whether by contract or
22 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
23 | outstanding shares, or (iii) beneficial ownership of such entity.
24 |
25 | "You" (or "Your") shall mean an individual or Legal Entity
26 | exercising permissions granted by this License.
27 |
28 | "Source" form shall mean the preferred form for making modifications,
29 | including but not limited to software source code, documentation
30 | source, and configuration files.
31 |
32 | "Object" form shall mean any form resulting from mechanical
33 | transformation or translation of a Source form, including but
34 | not limited to compiled object code, generated documentation,
35 | and conversions to other media types.
36 |
37 | "Work" shall mean the work of authorship, whether in Source or
38 | Object form, made available under the License, as indicated by a
39 | copyright notice that is included in or attached to the work
40 | (an example is provided in the Appendix below).
41 |
42 | "Derivative Works" shall mean any work, whether in Source or Object
43 | form, that is based on (or derived from) the Work and for which the
44 | editorial revisions, annotations, elaborations, or other modifications
45 | represent, as a whole, an original work of authorship. For the purposes
46 | of this License, Derivative Works shall not include works that remain
47 | separable from, or merely link (or bind by name) to the interfaces of,
48 | the Work and Derivative Works thereof.
49 |
50 | "Contribution" shall mean any work of authorship, including
51 | the original version of the Work and any modifications or additions
52 | to that Work or Derivative Works thereof, that is intentionally
53 | submitted to Licensor for inclusion in the Work by the copyright owner
54 | or by an individual or Legal Entity authorized to submit on behalf of
55 | the copyright owner. For the purposes of this definition, "submitted"
56 | means any form of electronic, verbal, or written communication sent
57 | to the Licensor or its representatives, including but not limited to
58 | communication on electronic mailing lists, source code control systems,
59 | and issue tracking systems that are managed by, or on behalf of, the
60 | Licensor for the purpose of discussing and improving the Work, but
61 | excluding communication that is conspicuously marked or otherwise
62 | designated in writing by the copyright owner as "Not a Contribution."
63 |
64 | "Contributor" shall mean Licensor and any individual or Legal Entity
65 | on behalf of whom a Contribution has been received by Licensor and
66 | subsequently incorporated within the Work.
67 |
68 | 2. Grant of Copyright License. Subject to the terms and conditions of
69 | this License, each Contributor hereby grants to You a perpetual,
70 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
71 | copyright license to reproduce, prepare Derivative Works of,
72 | publicly display, publicly perform, sublicense, and distribute the
73 | Work and such Derivative Works in Source or Object form.
74 |
75 | 3. Grant of Patent License. Subject to the terms and conditions of
76 | this License, each Contributor hereby grants to You a perpetual,
77 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
78 | (except as stated in this section) patent license to make, have made,
79 | use, offer to sell, sell, import, and otherwise transfer the Work,
80 | where such license applies only to those patent claims licensable
81 | by such Contributor that are necessarily infringed by their
82 | Contribution(s) alone or by combination of their Contribution(s)
83 | with the Work to which such Contribution(s) was submitted. If You
84 | institute patent litigation against any entity (including a
85 | cross-claim or counterclaim in a lawsuit) alleging that the Work
86 | or a Contribution incorporated within the Work constitutes direct
87 | or contributory patent infringement, then any patent licenses
88 | granted to You under this License for that Work shall terminate
89 | as of the date such litigation is filed.
90 |
91 | 4. Redistribution. You may reproduce and distribute copies of the
92 | Work or Derivative Works thereof in any medium, with or without
93 | modifications, and in Source or Object form, provided that You
94 | meet the following conditions:
95 |
96 | (a) You must give any other recipients of the Work or
97 | Derivative Works a copy of this License; and
98 |
99 | (b) You must cause any modified files to carry prominent notices
100 | stating that You changed the files; and
101 |
102 | (c) You must retain, in the Source form of any Derivative Works
103 | that You distribute, all copyright, patent, trademark, and
104 | attribution notices from the Source form of the Work,
105 | excluding those notices that do not pertain to any part of
106 | the Derivative Works; and
107 |
108 | (d) If the Work includes a "NOTICE" text file as part of its
109 | distribution, then any Derivative Works that You distribute must
110 | include a readable copy of the attribution notices contained
111 | within such NOTICE file, excluding those notices that do not
112 | pertain to any part of the Derivative Works, in at least one
113 | of the following places: within a NOTICE text file distributed
114 | as part of the Derivative Works; within the Source form or
115 | documentation, if provided along with the Derivative Works; or,
116 | within a display generated by the Derivative Works, if and
117 | wherever such third-party notices normally appear. The contents
118 | of the NOTICE file are for informational purposes only and
119 | do not modify the License. You may add Your own attribution
120 | notices within Derivative Works that You distribute, alongside
121 | or as an addendum to the NOTICE text from the Work, provided
122 | that such additional attribution notices cannot be construed
123 | as modifying the License.
124 |
125 | You may add Your own copyright statement to Your modifications and
126 | may provide additional or different license terms and conditions
127 | for use, reproduction, or distribution of Your modifications, or
128 | for any such Derivative Works as a whole, provided Your use,
129 | reproduction, and distribution of the Work otherwise complies with
130 | the conditions stated in this License.
131 |
132 | 5. Submission of Contributions. Unless You explicitly state otherwise,
133 | any Contribution intentionally submitted for inclusion in the Work
134 | by You to the Licensor shall be under the terms and conditions of
135 | this License, without any additional terms or conditions.
136 | Notwithstanding the above, nothing herein shall supersede or modify
137 | the terms of any separate license agreement you may have executed
138 | with Licensor regarding such Contributions.
139 |
140 | 6. Trademarks. This License does not grant permission to use the trade
141 | names, trademarks, service marks, or product names of the Licensor,
142 | except as required for reasonable and customary use in describing the
143 | origin of the Work and reproducing the content of the NOTICE file.
144 |
145 | 7. Disclaimer of Warranty. Unless required by applicable law or
146 | agreed to in writing, Licensor provides the Work (and each
147 | Contributor provides its Contributions) on an "AS IS" BASIS,
148 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
149 | implied, including, without limitation, any warranties or conditions
150 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
151 | PARTICULAR PURPOSE. You are solely responsible for determining the
152 | appropriateness of using or redistributing the Work and assume any
153 | risks associated with Your exercise of permissions under this License.
154 |
155 | 8. Limitation of Liability. In no event and under no legal theory,
156 | whether in tort (including negligence), contract, or otherwise,
157 | unless required by applicable law (such as deliberate and grossly
158 | negligent acts) or agreed to in writing, shall any Contributor be
159 | liable to You for damages, including any direct, indirect, special,
160 | incidental, or consequential damages of any character arising as a
161 | result of this License or out of the use or inability to use the
162 | Work (including but not limited to damages for loss of goodwill,
163 | work stoppage, computer failure or malfunction, or any and all
164 | other commercial damages or losses), even if such Contributor
165 | has been advised of the possibility of such damages.
166 |
167 | 9. Accepting Warranty or Additional Liability. While redistributing
168 | the Work or Derivative Works thereof, You may choose to offer,
169 | and charge a fee for, acceptance of support, warranty, indemnity,
170 | or other liability obligations and/or rights consistent with this
171 | License. However, in accepting such obligations, You may act only
172 | on Your own behalf and on Your sole responsibility, not on behalf
173 | of any other Contributor, and only if You agree to indemnify,
174 | defend, and hold each Contributor harmless for any liability
175 | incurred by, or claims asserted against, such Contributor by reason
176 | of your accepting any such warranty or additional liability.
177 |
178 | END OF TERMS AND CONDITIONS
179 |
180 | APPENDIX: How to apply the Apache License to your work.
181 |
182 | To apply the Apache License to your work, attach the following
183 | boilerplate notice, with the fields enclosed by brackets "[]"
184 | replaced with your own identifying information. (Don't include
185 | the brackets!) The text should be enclosed in the appropriate
186 | comment syntax for the file format. We also recommend that a
187 | file or class name and description of purpose be included on the
188 | same "printed page" as the copyright notice for easier
189 | identification within third-party archives.
190 |
191 | Copyright [yyyy] [name of copyright owner]
192 |
193 | Licensed under the Apache License, Version 2.0 (the "License");
194 | you may not use this file except in compliance with the License.
195 | You may obtain a copy of the License at
196 |
197 | http://www.apache.org/licenses/LICENSE-2.0
198 |
199 | Unless required by applicable law or agreed to in writing, software
200 | distributed under the License is distributed on an "AS IS" BASIS,
201 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
202 | See the License for the specific language governing permissions and
203 | limitations under the License.
204 |
205 |
206 | ===============================================================================
207 |
208 | For the `docs` directory:
209 |
210 | The source files for the documentation are licensed under the Apache License
211 | Version 2.0. These source files are used by the project maintainers to build
212 | online documentation for end-users:
213 |
214 |
215 |
216 | If you want to make contributions to the documentation, it may be necessary for
217 | you to build the documentation yourself by following the instructions in the
218 | `DEVELOP.rst` file. If you do this, a number of third-party software components
219 | are necessary.
220 |
221 | We do not ship the source code for these optional third-party software
222 | components or their dependencies, so we cannot make any guarantees about the
223 | licensing status of these components.
224 |
225 | However, for convenience, the documentation build system explicitly references
226 | the following software components (grouped by license):
227 |
228 | PSF License:
229 |
230 | - Python 3
231 |
232 | MIT License:
233 |
234 | - pip
235 | - setuptools
236 | - sphinx-autobuild
237 |
238 | BSD License:
239 |
240 | - alabaster
241 | - sphinx
242 |
243 | Apache License 2.0:
244 |
245 | - crate-docs-theme
246 |
247 | Please note that each of these components may specify its own dependencies and
248 | those dependencies may be licensed differently.
249 |
--------------------------------------------------------------------------------
/NOTICE:
--------------------------------------------------------------------------------
1 | CrateDB DBAL Driver
2 | Copyright 2013-2018 Crate.IO GmbH ("Crate")
3 |
4 |
5 | Licensed to Crate.IO GmbH (referred to in this notice as "Crate") under one or
6 | more contributor license agreements.
7 |
8 | Unless otherwise stated, every component of the CrateDB DBAL Driver is licensed
9 | under the Apache License, Version 2.0.
10 |
11 | Third-party components bundled with the CrateDB DBAL Driver are listed in the
12 | LICENSE file along with their respective licenses. Any additional mandatory
13 | notices pertaining to those dependencies will be reproduced in this file.
14 |
15 | Crate provides pre-built releases for convenience, also known as convenience
16 | releases. Building the CrateDB DBAL Driver from source pulls in a number of
17 | additional third-party dependencies. Hence, convenience releases will contain a
18 | mix of CCrateDB DBAL Driver source code and third-party build-time dependencies
19 | not listed in the LICENSE file or in this file.
20 |
21 | Crate is committed to only using permissively licensed third-party code.
22 | However, for the time being, if you make use of convenience releases, it is
23 | your responsibility to check the licensing status of the bundled third-party
24 | build-time dependencies.
25 |
--------------------------------------------------------------------------------
/README.rst:
--------------------------------------------------------------------------------
1 | ===================
2 | CrateDB DBAL Driver
3 | ===================
4 |
5 | .. image:: https://github.com/crate/crate-dbal/workflows/Tests/badge.svg
6 | :target: https://github.com/crate/crate-dbal/actions?workflow=Tests
7 | :alt: Build status (code)
8 |
9 | .. image:: https://github.com/crate/crate-dbal/workflows/Docs/badge.svg
10 | :target: https://github.com/crate/crate-dbal/actions?workflow=Docs
11 | :alt: Build status (documentation)
12 |
13 | .. image:: https://codecov.io/gh/crate/crate-dbal/branch/main/graph/badge.svg
14 | :target: https://app.codecov.io/gh/crate/crate-dbal
15 | :alt: Coverage
16 |
17 | .. image:: https://scrutinizer-ci.com/g/crate/crate-dbal/badges/quality-score.png?b=main
18 | :target: https://scrutinizer-ci.com/g/crate/crate-dbal
19 | :alt: Quality
20 |
21 | .. image:: https://poser.pugx.org/crate/crate-dbal/v/stable
22 | :target: https://packagist.org/packages/crate/crate-dbal
23 | :alt: Latest stable version
24 |
25 | .. image:: https://img.shields.io/badge/PHP-8.0%2C%208.1%2C%208.2%2C%208.3%2C%208.4-green.svg
26 | :target: https://packagist.org/packages/crate/crate-dbal
27 | :alt: Supported PHP versions
28 |
29 | .. image:: https://poser.pugx.org/crate/crate-dbal/d/monthly
30 | :target: https://packagist.org/packages/crate/crate-dbal
31 | :alt: Monthly downloads
32 |
33 | .. image:: https://poser.pugx.org/crate/crate-dbal/license
34 | :target: https://packagist.org/packages/crate/crate-dbal
35 | :alt: License
36 |
37 | |
38 |
39 | The CrateDB DBAL driver is an implementation of the `DBAL`_ abstraction layer
40 | for CrateDB_.
41 |
42 | `DBAL`_ is a PHP database abstraction layer that comes with database schema
43 | introspection, schema management, and `PDO`_ abstraction.
44 |
45 | Prerequisites
46 | =============
47 |
48 | You need to be using PHP and Composer_.
49 |
50 | Installation
51 | ============
52 |
53 | The CrateDB PDO adapter is available as a Composer package. Install it like::
54 |
55 | composer require crate/crate-dbal
56 |
57 | See the `installation documentation`_ for more info.
58 |
59 | Contributing
60 | ============
61 |
62 | This project is primarily maintained by `Crate.io`_, but we welcome community
63 | contributions!
64 |
65 | See the `developer docs`_ and the `contribution docs`_ for more information.
66 |
67 | Help
68 | ====
69 |
70 | Looking for more help?
71 |
72 | - Read the `project docs`_
73 | - Check out our `support channels`_
74 |
75 | .. _`DBAL`: http://www.doctrine-project.org/projects/dbal.html
76 | .. _`PDO`: http://php.net/manual/en/book.pdo.php
77 | .. _Composer: https://getcomposer.org/
78 | .. _contribution docs: CONTRIBUTING.rst
79 | .. _Crate.io: http://crate.io/
80 | .. _CrateDB: https://github.com/crate/crate
81 | .. _developer docs: DEVELOP.rst
82 | .. _installation documentation: https://crate.io/docs/reference/dbal/installation.html
83 | .. _project docs: https://crate.io/docs/reference/dbal/
84 | .. _support channels: https://crate.io/support/
85 |
--------------------------------------------------------------------------------
/Vagrantfile:
--------------------------------------------------------------------------------
1 | VAGRANTFILE_API_VERSION = "2"
2 |
3 | Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
4 |
5 | config.vm.box = "ubuntu/bionic64"
6 |
7 | config.vm.network "forwarded_port", guest: 4200, host: 44200
8 |
9 | config.vm.provision "shell", path: "provisioning.sh"
10 |
11 | config.vm.provider "virtualbox" do |vb|
12 | vb.customize ["modifyvm", :id, "--memory", "1024"]
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/codecov.yml:
--------------------------------------------------------------------------------
1 | # https://docs.codecov.io/docs/common-recipe-list
2 | # https://docs.codecov.io/docs/commit-status#patch-status
3 |
4 | coverage:
5 | status:
6 | project:
7 | default:
8 | target: 85% # the required coverage value
9 | threshold: 3% # the leniency in hitting the target
10 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "crate/crate-dbal",
3 | "description": "Doctrine Database Abstraction Layer (DBAL) adapter for CrateDB",
4 | "authors": [
5 | {
6 | "name": "Crate.io",
7 | "email": "office@crate.io",
8 | "homepage": "https://crate.io",
9 | "role": "maintainer"
10 | }
11 | ],
12 | "license": "Apache-2.0",
13 | "homepage": "https://github.com/crate/crate-dbal",
14 | "keywords": ["database", "dbal", "doctrine", "cratedb"],
15 | "minimum-stability": "dev",
16 | "prefer-stable": true,
17 | "require": {
18 | "php": "^8.0|^8.1|^8.2|^8.3|^8.4",
19 | "doctrine/dbal": "^2",
20 | "crate/crate-pdo": "^2"
21 | },
22 | "autoload": {
23 | "psr-0": {
24 | "Crate\\DBAL": "src"
25 | }
26 | },
27 | "require-dev": {
28 | "phpunit/phpunit": "^9.0",
29 | "squizlabs/php_codesniffer": "^3.5"
30 | },
31 | "autoload-dev": {
32 | "psr-0": {
33 | "Crate\\Test": "test",
34 | "Doctrine\\Tests": "vendor/doctrine/dbal/tests"
35 | }
36 | },
37 | "config": {
38 | "preferred-install": {
39 | "doctrine/dbal": "source"
40 | }
41 | },
42 | "scripts": {
43 | "test": "XDEBUG_MODE=coverage phpunit --coverage-clover build/logs/clover.xml",
44 | "check-style": "phpcs",
45 | "fix-style": "phpcbf"
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/devtools/create_tag.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Licensed to Crate.IO GmbH ("Crate") under one or more contributor
4 | # license agreements. See the NOTICE file distributed with this work for
5 | # additional information regarding copyright ownership. Crate licenses
6 | # this file to you under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License. You may
8 | # obtain a copy of the License at
9 | #
10 | # http://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15 | # License for the specific language governing permissions and limitations
16 | # under the License.
17 | #
18 | # However, if you have executed another commercial license agreement
19 | # with Crate these terms will supersede the license and you may use the
20 | # software solely pursuant to the terms of the relevant commercial agreement.
21 |
22 | function print_green() {
23 | echo -e "\033[2;32m$1\033[0m"
24 | }
25 | function print_red() {
26 | echo -e "\033[1;31m$1\033[0m"
27 | }
28 |
29 | # check if everything is committed
30 | CLEAN=`git status -s`
31 | if [ ! -z "$CLEAN" ]
32 | then
33 | print_red "Working directory not clean. Please commit all changes before tagging!"
34 | echo "Aborting."
35 | exit 1
36 | fi
37 |
38 | echo "Fetching origin..."
39 | git fetch origin > /dev/null
40 |
41 | # get current branc
42 | BRANCH=`git branch | grep "^*" | cut -d " " -f 2`
43 | echo "Current branch is $BRANCH."
44 |
45 | # check if BRANCH == origin/BRANCH
46 | LOCAL_COMMIT=$(git log --pretty=oneline -n 1 ${BRANCH} | cat)
47 | ORIGIN_COMMIT=$(git log --pretty=oneline -n 1 origin/${BRANCH} | cat)
48 |
49 | if [ "$LOCAL_COMMIT" != "$ORIGIN_COMMIT" ]
50 | then
51 | print_red "Local $BRANCH is not up to date."
52 | echo "Local commit: $LOCAL_COMMIT"
53 | echo "Origin commit: $ORIGIN_COMMIT"
54 | echo "Aborting."
55 | exit 1
56 | fi
57 |
58 | # get version from Driver class
59 | VERSION=$(grep "\ for more
27 | # information.
28 |
29 | # This file is taken from the demo Sphinx project available at
30 | # . This demo docs project
31 | # provides a reference implementation that should be copied for all Sphinx
32 | # projects at Crate.io.
33 |
34 | # The Crate Docs build system works by centralizing its core components in the
35 | # `crate-docs` repository. At build time, this Makefile creates a copy of the
36 | # this project under the `.crate-docs` directory. This Makefile is an interface
37 | # for those core components.
38 |
39 |
40 | # Upgraded instructions
41 | # -----------------------------------------------------------------------------
42 |
43 | # You must pin your Sphinx project to a specific version of the Crate Docs
44 | # project. You can do this by editing the `build.json` file. Change the JSON
45 | # `message` value to the desired release number. A list of releases is
46 | # available at .
47 |
48 | # Although care has been taken to restrict changes to the core components, you
49 | # may occasionally need to update your project to match the reference
50 | # implementation. Check the release notes for any special instructions.
51 |
52 |
53 | # Project-specific customization
54 | # =============================================================================
55 |
56 | # If you want to customize the build system for your Sphinx project, add lines
57 | # to this section.
58 |
59 |
60 | # Build system integration
61 | # =============================================================================
62 |
63 | # This is a boilerplate section is required for integration with the Crate Docs
64 | # build system. All Sphinx projects using a the same Crate Docs version
65 | # should have exactly the same boilerplate.
66 |
67 | # IF YOU ARE EDITING THIS FILE IN A REAL SPHINX PROJECT, YOU SHOULD NOT MAKE
68 | # ANY CHANGES TO THIS SECTION.
69 |
70 | # If you want to make changes to the boilerplate, please make a pull request on
71 | # the demo Sphinx project in the Crate Docs repository available at
72 | # .
73 |
74 | .EXPORT_ALL_VARIABLES:
75 |
76 | DOCS_DIR := docs
77 | TOP_DIR := ..
78 | BUILD_JSON := build.json
79 | BUILD_REPO := https://github.com/crate/crate-docs.git
80 | LATEST_BUILD := https://github.com/crate/crate-docs/releases/latest
81 | CLONE_DIR := .crate-docs
82 | SRC_DIR := $(CLONE_DIR)/common-build
83 | SELF_SRC := $(TOP_DIR)/common-build
84 | SELF_MAKEFILE := $(SELF_SRC)/rules.mk
85 | SRC_MAKE := $(MAKE) -f $(SRC_DIR)/rules.mk
86 |
87 | # Parse the JSON file
88 | BUILD_VERSION := $(shell cat $(BUILD_JSON) | \
89 | python -c 'import json, sys; print(json.load(sys.stdin)["message"])')
90 |
91 | ifeq ($(BUILD_VERSION),)
92 | $(error No build version specified in `$(BUILD_JSON)`.)
93 | endif
94 |
95 | # This is a non-essential check so we timeout after only two seconds so as not
96 | # to frustrate the user when there are network issues
97 | LATEST_VERSION := $(shell curl -sI --connect-timeout 2 '$(LATEST_BUILD)' | \
98 | grep -i 'Location:' | grep -Eoh '[^/]+$$')
99 |
100 | # Skip if no version could be determined (i.e., because of a network error)
101 | ifneq ($(LATEST_VERSION),)
102 | # Only issue a warning if there is a version mismatch
103 | ifneq ($(BUILD_VERSION),$(LATEST_VERSION))
104 | define version_warning
105 | You are using Crate Docs version $(BUILD_VERSION), however version \
106 | $(LATEST_VERSION) is available. You should consider upgrading. Follow the \
107 | instructions in `Makefile` and then run `make reset`.
108 | endef
109 | endif
110 | endif
111 |
112 | # Default rule
113 | .PHONY: help
114 | help: $(CLONE_DIR)
115 | @ $(MAKE) version-warn
116 | @ $(SRC_MAKE) $@
117 |
118 | .PHONY: version-warn
119 | version-warn:
120 | @ # Because version numbers may vary in length, we must wrap the warning
121 | @ # message at run time to be sure of correct output
122 | @ if test -n '$(version_warning)'; then \
123 | printf '\033[33m'; \
124 | echo '$(version_warning)' | fold -w 79 -s; \
125 | printf '\033[00m\n'; \
126 | fi
127 |
128 | ifneq ($(wildcard $(SELF_MAKEFILE)),)
129 | # The project detects itself and fakes an install of its own core build rules
130 | # so that it can test itself
131 | $(CLONE_DIR):
132 | @ printf '\033[1mInstalling the build system...\033[00m\n'
133 | @ mkdir -p $@
134 | @ cp -R $(SELF_SRC) $(SRC_DIR)
135 | @ printf 'Created: $(CLONE_DIR)\n'
136 | else
137 | # All other projects install a versioned copy of the core build rules
138 | $(CLONE_DIR):
139 | @ printf '\033[1mInstalling the build system...\033[00m\n'
140 | @ git clone --depth=1 -c advice.detachedHead=false \
141 | --branch=$(BUILD_VERSION) $(BUILD_REPO) $(CLONE_DIR)
142 | @ printf 'Created: $(CLONE_DIR)\n'
143 | endif
144 |
145 | # Don't pass through this target
146 | .PHONY: Makefile
147 | Makefile:
148 |
149 | # By default, pass targets through to the core build rules
150 | .PHONY:
151 | %: $(CLONE_DIR)
152 | @ $(MAKE) version-warn
153 | @ $(SRC_MAKE) $@
154 |
155 | .PHONY: reset
156 | reset:
157 | @ printf '\033[1mResetting the build system...\033[00m\n'
158 | @ rm -rf $(CLONE_DIR)
159 | @ printf 'Removed: $(CLONE_DIR)\n'
160 |
--------------------------------------------------------------------------------
/docs/_extra/robots.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 | Disallow: /
3 |
4 | Sitemap: https://cratedb.com/docs/dbal/en/latest/site.xml
5 |
--------------------------------------------------------------------------------
/docs/appendices/compatibility.rst:
--------------------------------------------------------------------------------
1 | .. _compatibility:
2 |
3 | =============
4 | Compatibility
5 | =============
6 |
7 | .. rubric:: Table of contents
8 |
9 | .. contents::
10 | :local:
11 |
12 | .. _versions:
13 |
14 | Version notes
15 | =============
16 |
17 | .. _cratedb-versions:
18 |
19 | CrateDB
20 | -------
21 |
22 | Consult the following table for CrateDB version compatibility notes:
23 |
24 | +----------------+-----------------+-------------------------------------------+
25 | | Driver Version | CrateDB Version | Notes |
26 | +================+=================+===========================================+
27 | | Any | >= 2.1.x | Client needs to connect with a valid |
28 | | | | database user to access CrateDB. |
29 | | | | |
30 | | | | The default CrateDB user is ``crate`` and |
31 | | | | has no password is set. |
32 | | | | |
33 | +----------------+-----------------+-------------------------------------------+
34 | | >= 1.0 | >= 2.3.x | |
35 | +----------------+-----------------+-------------------------------------------+
36 | | >= 2.0 | >= 4.0.x | |
37 | +----------------+-----------------+-------------------------------------------+
38 |
39 | .. _implementations:
40 |
41 | Implementation notes
42 | ====================
43 |
44 | .. _dbal-implementation:
45 |
46 | DBAL
47 | ----
48 |
49 | +----------------+----------------------------------------------+------------+
50 | | Driver Version | Feature | Notes |
51 | +================+==============================================+============+
52 | | >= 0.2.0 | HTTP basic auth. | Supported. |
53 | +----------------+----------------------------------------------+------------+
54 | | >= 0.2.1 | PHP 7. | Supported. |
55 | +----------------+----------------------------------------------+------------+
56 | | >= 0.3 | Exposed PDO methods: | Supported. |
57 | | | | |
58 | | | - ``getServerVersion()`` | |
59 | | | - ``getServerInfo()`` | |
60 | + +----------------------------------------------+------------+
61 | | | Connection to multiple CrateDB nodes. | Supported. |
62 | + +----------------------------------------------+------------+
63 | | | Default schema selection. | Supported. |
64 | + +----------------------------------------------+------------+
65 | | | CrateDB SQL features: | Supported. |
66 | | | | |
67 | | | - Joins (with or without a `query builder`_) | |
68 | | | - Fulltext indexes (without a query builder) | |
69 | +----------------+----------------------------------------------+------------+
70 | | >= 1.1 | [BREAKING]: PDO library requires PHP 7.2 | Supported. |
71 | + +----------------------------------------------+------------+
72 | | | Added SSL support | Supported. |
73 | + +----------------------------------------------+------------+
74 | | | Based on Doctrine 2.6.3 | Supported. |
75 | +----------------+----------------------------------------------+------------+
76 | | >= 2.0 | Based on Doctrine 2.9 | Supported. |
77 | +----------------+----------------------------------------------+------------+
78 | | >= 2.2 | Based on Doctrine 2.10 | Supported. |
79 | +----------------+----------------------------------------------+------------+
80 |
81 | .. _query builder: https://www.doctrine-project.org/projects/doctrine-dbal/en/3.0/reference/query-builder.html#join-clauses
82 |
--------------------------------------------------------------------------------
/docs/appendices/data-types.rst:
--------------------------------------------------------------------------------
1 | .. _data-types:
2 |
3 | ==========
4 | Data types
5 | ==========
6 |
7 | .. _type-map:
8 |
9 | Type map
10 | ========
11 |
12 | This driver maps CrateDB types to the following PHP types:
13 |
14 | .. csv-table::
15 | :header: "CrateDB Type", "PHP Type"
16 |
17 | "`boolean`__", "`boolean`__"
18 | "`byte`__", "`integer`__"
19 | "`short`__", "`integer`__"
20 | "`integer`__", "`integer`__",
21 | "`long`__", "`string`__"
22 | "`float`__", "`float`__"
23 | "`double`__", "`float`__"
24 | "`string`__", "`string`__"
25 | "`ip`__", "`string`__"
26 | "`timestamp`__", "`DateTime`__"
27 | "`geo_point`__", "`array`__"
28 | "`geo_shape`__", "`array`__"
29 | "`object`__", "`array`__"
30 | "`array`__", "`array`__"
31 |
32 | __ https://cratedb.com/docs/crate/reference/en/latest/general/ddl/data-types.html#boolean
33 | __ https://www.php.net/manual/en/language.types.boolean.php
34 | __ https://cratedb.com/docs/crate/reference/en/latest/general/ddl/data-types.html#numeric-data
35 | __ https://www.php.net/manual/en/language.types.integer.php
36 | __ https://cratedb.com/docs/crate/reference/en/latest/general/ddl/data-types.html#numeric-data
37 | __ https://www.php.net/manual/en/language.types.integer.php
38 | __ https://cratedb.com/docs/crate/reference/en/latest/general/ddl/data-types.html#numeric-data
39 | __ https://www.php.net/manual/en/language.types.integer.php
40 | __ https://cratedb.com/docs/crate/reference/en/latest/general/ddl/data-types.html#numeric-data
41 | __ https://www.php.net/manual/en/language.types.string.php
42 | __ https://cratedb.com/docs/crate/reference/en/latest/general/ddl/data-types.html#numeric-data
43 | __ https://www.php.net/manual/en/language.types.float.php
44 | __ https://cratedb.com/docs/crate/reference/en/latest/general/ddl/data-types.html#numeric-data
45 | __ https://www.php.net/manual/en/language.types.float.php
46 | __ https://cratedb.com/docs/crate/reference/en/latest/general/ddl/data-types.html#character-data
47 | __ https://www.php.net/manual/en/language.types.string.php
48 | __ https://cratedb.com/docs/crate/reference/en/latest/general/ddl/data-types.html#ip
49 | __ https://www.php.net/manual/en/language.types.string.php
50 | __ https://cratedb.com/docs/crate/reference/en/latest/general/ddl/data-types.html#dates-and-times
51 | __ https://www.php.net/manual/en/class.datetime.php
52 | __ https://cratedb.com/docs/crate/reference/en/latest/general/ddl/data-types.html#geo-point
53 | __ https://www.php.net/manual/en/language.types.array.php
54 | __ https://cratedb.com/docs/crate/reference/en/latest/general/ddl/data-types.html#geo-shape
55 | __ https://www.php.net/manual/en/language.types.array.php
56 | __ https://cratedb.com/docs/crate/reference/en/latest/general/ddl/data-types.html#object
57 | __ https://www.php.net/manual/en/language.types.array.php
58 | __ https://cratedb.com/docs/crate/reference/en/latest/general/ddl/data-types.html#array
59 | __ https://www.php.net/manual/en/language.types.array.php
60 |
61 | .. _column-type-definitions:
62 |
63 | Column type definitions
64 | =======================
65 |
66 | When defining CrateDB `timestamp`_, `object`_ or `array`_ type columns, you
67 | must construct the DBAL column definition programatically, using the types and
68 | attributes provided by the CrateDB DBAL driver.
69 |
70 | Primitive column types (e.g. string, integer, and so on) can be defined in
71 | the regular DBAL way.
72 |
73 | The custom type objects provided by the CrateDB DBAL driver are:
74 |
75 | - `TimestampType`_
76 | - `MapType`_
77 | - `ArrayType`_
78 |
79 | Here's an example of how the ``MapType`` can be used:
80 |
81 | .. code-block:: php
82 |
83 | use Doctrine\DBAL\Schema\Column;
84 | use Doctrine\DBAL\Schema\Table;
85 | use Doctrine\DBAL\Types\Type;
86 | use Crate\DBAL\Types\MapType;
87 |
88 | $table = new Table('test_table');
89 | $objDefinition = array(
90 | 'type' => MapType::STRICT,
91 | 'fields' => array(
92 | new Column('id', Type::getType('integer'), array()),
93 | new Column('name', Type::getType('string'), array()),
94 | ),
95 | );
96 | $table->addColumn(
97 | 'object_column', MapType::NAME,
98 | array('platformOptions'=>$objDefinition));
99 | $schemaManager->createTable($table);
100 |
101 | Here, the ``MapType`` class being used to model a CrateDB object. Standard DBAL
102 | types, like ``string``, are being used to construct the schema of the object,
103 | via calls to the the use of the ``Column`` class and calls to the
104 | ``Type::getType`` static method, and so on.
105 |
106 | .. SEEALSO::
107 |
108 | The Doctrine `ORM documentation`_ has more about type mapping.
109 |
110 | .. _array: https://crate.io/docs/crate/reference/en/latest/general/ddl/data-types.html#array
111 | .. _ArrayType: https://github.com/crate/crate-dbal/blob/main/src/Crate/DBAL/Types/ArrayType.php
112 | .. _MapType: https://github.com/crate/crate-dbal/blob/main/src/Crate/DBAL/Types/MapType.php
113 | .. _object: https://crate.io/docs/crate/reference/en/latest/general/ddl/data-types.html#object
114 | .. _ORM documentation: https://www.doctrine-project.org/projects/doctrine-orm/en/3.0/reference/basic-mapping.html
115 | .. _timestamp: https://crate.io/docs/crate/reference/en/latest/general/ddl/data-types.html#dates-and-times
116 | .. _TimestampType: https://github.com/crate/crate-dbal/blob/main/src/Crate/DBAL/Types/TimestampType.php
117 |
--------------------------------------------------------------------------------
/docs/appendices/index.rst:
--------------------------------------------------------------------------------
1 | .. _appendices:
2 |
3 | ==========
4 | Appendices
5 | ==========
6 |
7 | Supplementary information for the CrateDB DBAL driver.
8 |
9 | .. rubric:: Table of contents
10 |
11 | .. toctree::
12 | :maxdepth: 2
13 |
14 | table-options
15 | data-types
16 | compatibility
17 |
--------------------------------------------------------------------------------
/docs/appendices/table-options.rst:
--------------------------------------------------------------------------------
1 | .. _table-options:
2 |
3 | ================================
4 | CrateDB specific table options
5 | ================================
6 |
7 | CrateDB supports a custom ``CREATE TABLE`` syntax for adjusting the table
8 | configuration incl. ``SHARDING`` and ``PARTITIONING`` of the table.
9 | See `CrateDB CREATE TABLE Documentation`_ for all supported configuration
10 | options.
11 |
12 | All CrateDB specific table options must be passed in using the ``$options``
13 | argument of the DBAL ``Table()`` constructor.
14 |
15 | Example:
16 |
17 | .. code-block:: php
18 |
19 | $options = [];
20 | $options['sharding_shards'] = 5;
21 | $myTable = new Table('my_table', [], [], [], 0, $options);
22 |
23 |
24 | Sharding Options
25 | ================
26 |
27 | Following table options can used to adjust the sharding of a table.
28 | See also `CrateDB Sharding Documentation`_.
29 |
30 | .. list-table::
31 | :header-rows: 1
32 |
33 | * - Name
34 | - Description
35 | * - ``$options['sharding_num_shards']``
36 | - Specifies the number of shards a table is stored in. Must be greater than 0.
37 | * - ``$options['sharding_routing_column']``
38 | - Allows to explicitly specify a column or field on which rows are sharded by.
39 |
40 |
41 | Partitioning Options
42 | ====================
43 |
44 | Following table options can used to define the partitioning columns of a table.
45 | See also `CrateDB Partitioned Tables Documentation`_.
46 |
47 |
48 | .. list-table::
49 | :header-rows: 1
50 |
51 | * - Name
52 | - Description
53 | * - ``$options['partition_columns']``
54 | - Specifies the columns on which partitions should be created on.
55 |
56 | General Options
57 | ===============
58 |
59 | All general CrateDB specific table options used inside the ``WITH (...)`` clause
60 | can be configured under the ``table_options`` option key.
61 |
62 | Example on how to adjust the replicas:
63 |
64 | .. code-block:: php
65 |
66 | $options = [];
67 | $options['table_options'] = [];
68 | $options['table_options']['number_of_replicas'] = '2';
69 | $myTable = new Table('my_table', [], [], [], 0, $options);
70 |
71 |
72 | .. _CrateDB CREATE TABLE Documentation: https://cratedb.com/docs/crate/reference/en/latest/sql/statements/create-table.html
73 | .. _CrateDB Sharding Documentation: https://cratedb.com/docs/crate/reference/en/latest/general/ddl/sharding.html
74 | .. _CrateDB Partitioned Tables Documentation: https://cratedb.com/docs/crate/reference/en/latest/general/ddl/partitioned-tables.html
75 |
--------------------------------------------------------------------------------
/docs/build.json:
--------------------------------------------------------------------------------
1 | {
2 | "schemaVersion": 1,
3 | "label": "docs build",
4 | "message": "2.1.2"
5 | }
6 |
--------------------------------------------------------------------------------
/docs/conf.py:
--------------------------------------------------------------------------------
1 | from crate.theme.rtd.conf.dbal import *
2 |
3 | from sphinx.highlighting import lexers
4 | from pygments.lexers.web import PhpLexer
5 | lexers["php"] = PhpLexer(startinline=True, linenos=1)
6 | lexers["php-annotations"] = PhpLexer(startinline=True, linenos=1)
7 | # primary_domain = "php"
8 |
9 | # Disable version chooser.
10 | html_context.update({
11 | "display_version": False,
12 | "current_version": None,
13 | "versions": [],
14 | })
15 |
--------------------------------------------------------------------------------
/docs/connect.rst:
--------------------------------------------------------------------------------
1 | .. _connect:
2 |
3 | ==================
4 | Connect to CrateDB
5 | ==================
6 |
7 | .. rubric:: Table of contents
8 |
9 | .. contents::
10 | :local:
11 |
12 | Authentication
13 | ==============
14 |
15 | .. NOTE::
16 |
17 | These examples authenticate as ``crate``, the default database user in
18 | CrateDB versions 2.1.x and later.
19 |
20 | If you are using CrateDB 2.1.x or later, you must supply a username. If you
21 | are using earlier versions of CrateDB, this parameter is not supported.
22 |
23 | See the :ref:`compatibility notes ` for more information.
24 |
25 | If you have not configured a custom `database user`_, you probably want to
26 | authenticate as the CrateDB superuser, which is ``crate``. The superuser
27 | does not have a password, so you can omit the ``password`` argument.
28 |
29 | DBAL
30 | ====
31 |
32 | If you plan to query CrateDB via DBAL, you can get a connection from the
33 | ``DriverManager`` class using `standard DBAL parameters`_, like so:
34 |
35 | .. code-block:: php
36 |
37 | $params = array(
38 | 'driverClass' => 'Crate\DBAL\Driver\PDOCrate\Driver',
39 | 'user' => 'crate',
40 | 'host' => 'localhost',
41 | 'port' => 4200
42 | );
43 | $connection = \Doctrine\DBAL\DriverManager::getConnection($params);
44 | $schemaManager = $connection->getSchemaManager();
45 |
46 | With these connection parameters, the ``DriverManager`` will attempt to
47 | authenticate as ``crate`` with a CrateDB node listening on ``localhost:4200``.
48 |
49 | .. SEEALSO::
50 |
51 | For more help using DBAL_, consult the `DBAL documentation`_.
52 |
53 | Doctrine ORM
54 | ============
55 |
56 | If you want to use the `Object-Relational Mapping`_ (ORM) features of Doctrine,
57 | you must set up an ``EntityManager`` instance.
58 |
59 | Here's a slightly modified version of the `Doctrine provided example`_:
60 |
61 | .. code-block:: php
62 |
63 | use Doctrine\ORM\Tools\Setup;
64 | use Doctrine\ORM\EntityManager;
65 |
66 | $paths = array("/path/to/entity-files");
67 | $isDevMode = false;
68 |
69 | // the connection configuration
70 | $params = array(
71 | 'driverClass' => 'Crate\DBAL\Driver\PDOCrate\Driver',
72 | 'user' => 'crate'
73 | 'host' => 'localhost',
74 | 'port' => 4200
75 | );
76 |
77 | $config = Setup::createAnnotationMetadataConfiguration($paths, $isDevMode);
78 | $entityManager = EntityManager::create($params, $config);
79 |
80 | Here's what we changed in the above example:
81 |
82 | - Specified the CrateDB driver class
83 | - Specified the ``crate`` user
84 | - Configured the connection for ``localhost:4200``
85 |
86 | .. SEEALSO::
87 |
88 | The CrateDB DBAL driver provides three custom type objects. Consult the
89 | :ref:`data types ` appendix for more information about type
90 | maps and column type definitions.
91 |
92 | Next steps
93 | ==========
94 |
95 | Use the standard the `DBAL documentation`_ or `Doctrine ORM documentation`_ for the rest of
96 | your setup process.
97 |
98 | .. _database user: https://cratedb.com/docs/crate/reference/en/latest/admin/user-management.html
99 | .. _DBAL: https://www.doctrine-project.org/projects/dbal.html
100 | .. _DBAL documentation: https://www.doctrine-project.org/projects/doctrine-dbal/en/3.0/index.html
101 | .. _Doctrine provided example: https://www.doctrine-project.org/projects/doctrine-orm/en/3.0/reference/configuration.html#obtaining-an-entitymanager
102 | .. _Object-Relational Mapping: https://www.doctrine-project.org/projects/orm.html
103 | .. _Doctrine ORM documentation: https://www.doctrine-project.org/projects/doctrine-orm/en/3.0/index.html
104 | .. _standard DBAL parameters: https://www.doctrine-project.org/projects/doctrine-dbal/en/3.0/reference/configuration.html
105 |
--------------------------------------------------------------------------------
/docs/docutils.conf:
--------------------------------------------------------------------------------
1 | [html4css1 writer]
2 | field_name_limit: 40
3 |
--------------------------------------------------------------------------------
/docs/getting-started.rst:
--------------------------------------------------------------------------------
1 | ===============
2 | Getting started
3 | ===============
4 |
5 | Learn how to install and get started with the :ref:`CrateDB DBAL driver
6 | `.
7 |
8 | .. rubric:: Table of contents
9 |
10 | .. contents::
11 | :local:
12 |
13 | Prerequisites
14 | =============
15 |
16 | Your project must be using `Composer`_.
17 |
18 | Set up as a dependency
19 | ======================
20 |
21 | The driver is available as a package at `crate/crate-dbal`_.
22 |
23 | Add the driver package to your project's `composer.json`_::
24 |
25 | composer require crate/crate-dbal
26 |
27 | If you're using `Doctrine ORM`_, you should add the ``doctrine/orm`` dependency
28 | too::
29 |
30 | composer require doctrine/orm
31 |
32 |
33 | Install
34 | =======
35 |
36 | Once the package has been configured as a dependency, you can install it, like::
37 |
38 | composer install
39 |
40 | Afterwards, if you are not already doing so, you must require the Composer
41 | `autoload.php`_ file. You can do this by adding a line like this to your PHP
42 | application:
43 |
44 | .. code-block:: php
45 |
46 | require __DIR__ . '/vendor/autoload.php';
47 |
48 | .. SEEALSO::
49 |
50 | For more help with Composer, consult the `Composer documentation`_.
51 |
52 | Next steps
53 | ==========
54 |
55 | Learn how to :ref:`connect to CrateDB `.
56 |
57 | .. _autoload.php: https://getcomposer.org/doc/01-basic-usage.md#autoloading
58 | .. _Composer documentation: https://getcomposer.org
59 | .. _Composer: https://getcomposer.org/
60 | .. _composer.json: https://getcomposer.org/doc/01-basic-usage.md#composer-json-project-setup
61 | .. _crate/crate-dbal: https://packagist.org/packages/crate/crate-dbal
62 | .. _Doctrine ORM: https://www.doctrine-project.org/projects/orm.html
63 |
--------------------------------------------------------------------------------
/docs/index.rst:
--------------------------------------------------------------------------------
1 | .. _index:
2 |
3 | ===================
4 | CrateDB DBAL Driver
5 | ===================
6 |
7 | A `DBAL`_ driver for `CrateDB`_.
8 |
9 | DBAL is a PHP database abstraction layer that comes with database schema
10 | introspection, schema management, and `PDO`_ support.
11 |
12 | This driver also works with `Doctrine ORM`_, an `Object-Relational Mapper`_.
13 |
14 | .. NOTE::
15 |
16 | This is a basic CrateDB driver reference.
17 |
18 | For general help setting up and using Doctrine software, please consult the
19 | `DBAL documentation`_ or the `Doctrine ORM documentation`_.
20 |
21 | .. SEEALSO::
22 |
23 | The CrateDB PHP DBAL driver is an open source project and is `hosted on
24 | GitHub`_.
25 |
26 | .. rubric:: Table of contents
27 |
28 | .. toctree::
29 | :maxdepth: 2
30 |
31 | getting-started
32 | connect
33 | appendices/index
34 |
35 |
36 | .. _CrateDB: https://cratedb.com/product
37 | .. _DBAL documentation: https://www.doctrine-project.org/projects/doctrine-dbal/en/3.0/index.html
38 | .. _DBAL: https://www.doctrine-project.org/projects/dbal.html
39 | .. _Doctrine ORM: https://www.doctrine-project.org/projects/orm.html
40 | .. _Doctrine ORM documentation: https://www.doctrine-project.org/projects/doctrine-orm/en/3.0/index.html
41 | .. _hosted on GitHub: https://github.com/crate/crate-dbal
42 | .. _Object-Relational Mapper: https://www.doctrine-project.org/projects/orm.html
43 | .. _open source: https://en.wikipedia.org/wiki/Open-source_software
44 | .. _PDO: https://www.php.net/manual/en/intro.pdo.php
45 |
--------------------------------------------------------------------------------
/docs/requirements.txt:
--------------------------------------------------------------------------------
1 | crate-docs-theme
2 |
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 | ./test/Crate/Test
15 |
16 |
17 |
18 | ./src
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/provisioning.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | export DEBIAN_FRONTEND=noninteractive
3 | apt-get update
4 | apt-get upgrade
5 | add-apt-repository -y ppa:ondrej/php
6 | wget https://cdn.crate.io/downloads/deb/DEB-GPG-KEY-crate
7 | apt-key add DEB-GPG-KEY-crate
8 | . /etc/os-release
9 | echo "deb https://cdn.crate.io/downloads/deb/stable/ $UBUNTU_CODENAME main" > /etc/apt/sources.list.d/crate-stable-$UBUNTU_CODENAME.list
10 | apt-get update
11 | # test classes of DBAL which we depend on are only available inside the source, so DON'T install zip|unzip to force
12 | # composer to install depencenies from source
13 | apt-get install -y crate php7.3-cli php7.3-xml php7.3-curl php7.3-mbstring php7.3-xdebug
14 | curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
15 | cd /vagrant && su vagrant -c 'composer install'
--------------------------------------------------------------------------------
/src/Crate/DBAL/Driver/PDOCrate/CrateStatement.php:
--------------------------------------------------------------------------------
1 | constructPdoDsn($params), $username, $password, $driverOptions);
46 | }
47 |
48 | /**
49 | * Constructs the Crate PDO DSN.
50 | *
51 | * @return string The DSN.
52 | */
53 | private function constructPdoDsn(array $params)
54 | {
55 | $dsn = self::NAME . ':';
56 | if (isset($params['host']) && $params['host'] != '') {
57 | $dsn .= $params['host'];
58 | } else {
59 | $dsn .= 'localhost';
60 | }
61 | $dsn .= ':' . (isset($params['port']) ? $params['port'] : '4200');
62 |
63 | return $dsn;
64 | }
65 |
66 | /**
67 | * {@inheritDoc}
68 | */
69 | public function getDatabasePlatform()
70 | {
71 | return new CratePlatform();
72 | }
73 |
74 | /**
75 | * {@inheritDoc}
76 | */
77 | public function getSchemaManager(Connection $conn)
78 | {
79 | return new CrateSchemaManager($conn);
80 | }
81 |
82 | /**
83 | * {@inheritDoc}
84 | */
85 | public function getName()
86 | {
87 | return self::NAME;
88 | }
89 |
90 | /**
91 | * {@inheritDoc}
92 | */
93 | public function getDatabase(Connection $conn)
94 | {
95 | return null;
96 | }
97 |
98 | /**
99 | * {@inheritDoc}
100 | */
101 | public function createDatabasePlatformForVersion($version)
102 | {
103 | if (version_compare($version, self::VERSION_057, "<")) {
104 | return new CratePlatform();
105 | } elseif (version_compare($version, self::VERSION_4, "<")) {
106 | return new CratePlatform1();
107 | } else {
108 | return new CratePlatform4();
109 | }
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php:
--------------------------------------------------------------------------------
1 | setAttribute(PDO::ATTR_STATEMENT_CLASS, CrateStatement::class);
40 | $this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
41 | }
42 |
43 | /**
44 | * Checks whether a query is required to retrieve the database server version.
45 | *
46 | * @return boolean True if a query is required to retrieve the database server version, false otherwise.
47 | */
48 | public function requiresQueryForServerVersion()
49 | {
50 | return false;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/Crate/DBAL/Platforms/CratePlatform1.php:
--------------------------------------------------------------------------------
1 | doctrineTypeMapping = array(
33 | 'integer' => 'integer',
34 | 'int' => 'integer',
35 | 'bool' => 'boolean',
36 | 'boolean' => 'boolean',
37 | 'timestamp' => 'timestamp',
38 |
39 | 'object' => 'map',
40 | 'array' => 'array',
41 |
42 | // postgresql compatible type names, default for CrateDB >= 4.0
43 | 'text' => 'string',
44 | 'char' => 'string',
45 | 'smallint' => 'smallint',
46 | 'bigint' => 'bigint',
47 | 'real' => 'float',
48 | 'double precision' => 'float',
49 | 'timestamp without time zone' => 'timestamp',
50 | 'timestamp with time zone' => 'timestamp',
51 | );
52 | }
53 |
54 | /**
55 | * {@inheritDoc}
56 | */
57 | public function getBigIntTypeDeclarationSQL(array $field)
58 | {
59 | return 'BIGINT';
60 | }
61 |
62 | /**
63 | * {@inheritDoc}
64 | */
65 | public function getSmallIntTypeDeclarationSQL(array $field)
66 | {
67 | return 'SMALLINT';
68 | }
69 |
70 | /**
71 | * {@inheritDoc}
72 | */
73 | public function getFloatDeclarationSQL(array $field)
74 | {
75 | return 'DOUBLE PRECISION';
76 | }
77 |
78 | /**
79 | * {@inheritDoc}
80 | */
81 | protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed)
82 | {
83 | return 'TEXT';
84 | }
85 |
86 | /**
87 | * {@inheritDoc}
88 | */
89 | public function getClobTypeDeclarationSQL(array $field)
90 | {
91 | return 'TEXT';
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/src/Crate/DBAL/Platforms/Keywords/CrateKeywords.php:
--------------------------------------------------------------------------------
1 | $row['constraint_name'],
42 | 'column_name' => $row['column_name'],
43 | 'non_unique' => ! $isPrimary,
44 | 'primary' => $isPrimary,
45 | 'where' => '',
46 | ];
47 | }
48 |
49 | return parent::_getPortableTableIndexesList($buffer, $tableName);
50 | }
51 | /**
52 | * {@inheritDoc}
53 | */
54 | protected function _getPortableTableColumnDefinition($tableColumn)
55 | {
56 | $tableColumn = array_change_key_case($tableColumn, CASE_LOWER);
57 |
58 | if (!isset($tableColumn['column_name'])) {
59 | $tableColumn['column_name'] = '';
60 | }
61 | if (!isset($tableColumn['is_nullable'])) {
62 | $tableColumn['is_nullable'] = true;
63 | }
64 |
65 | $dbType = strtolower($tableColumn['data_type']);
66 | $type = $this->_platform->getDoctrineTypeMapping($dbType);
67 |
68 | $options = array(
69 | 'length' => null,
70 | 'notnull' => ! $tableColumn['is_nullable'],
71 | 'default' => null,
72 | 'precision' => null,
73 | 'scale' => null,
74 | 'fixed' => null,
75 | 'unsigned' => false,
76 | 'autoincrement' => false,
77 | 'comment' => '',
78 | );
79 |
80 | return new Column($tableColumn['column_name'], Type::getType($type), $options);
81 | }
82 |
83 | /**
84 | * {@inheritDoc}
85 | */
86 | protected function _getPortableTablesList($tables)
87 | {
88 | $tableNames = array();
89 | foreach ($tables as $tableRow) {
90 | $tableRow = array_change_key_case($tableRow, \CASE_LOWER);
91 | $tableNames[] = $tableRow['table_name']; // ignore schema for now
92 | }
93 |
94 | return $tableNames;
95 | }
96 |
97 | /**
98 | * Flattens a multidimensional array into a 1 dimensional array, where
99 | * keys are concatinated with '.'
100 | *
101 | * @return array
102 | */
103 | private function flatten(array $array, string $prefix = '') : array
104 | {
105 | $result = array();
106 | foreach ($array as $key => $value) {
107 | if (is_array($value)) {
108 | $result = $result + self::flatten($value, $prefix . $key . '.');
109 | } else {
110 | $result[$prefix . $key] = $value;
111 | }
112 | }
113 | return $result;
114 | }
115 |
116 | /**
117 | * {@inheritDoc}
118 | */
119 | public function listTableDetails($tableName) : Table
120 | {
121 | $columns = $this->listTableColumns($tableName);
122 | $indexes = $this->listTableIndexes($tableName);
123 | $options = [];
124 |
125 | $s = $this->_conn->fetchAssoc($this->_platform->getTableOptionsSQL($tableName));
126 |
127 | $options['sharding_routing_column'] = $s['clustered_by'];
128 | $options['sharding_num_shards'] = $s['number_of_shards'];
129 | $options['partition_columns'] = $s['partitioned_by'];
130 | $options['table_options'] = self::flatten($s['settings']);
131 | $options['table_options']['number_of_replicas'] = $s['number_of_replicas'];
132 | $options['table_options']['column_policy'] = $s['column_policy'];
133 | return new Table($tableName, $columns, $indexes, [], [], $options);
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/src/Crate/DBAL/Types/ArrayType.php:
--------------------------------------------------------------------------------
1 | 0 && !(array_keys($value) === range(0, count($value) - 1)))) {
62 | return null;
63 | }
64 | return $value;
65 | }
66 |
67 | public function convertToPHPValue($value, AbstractPlatform $platform)
68 | {
69 | return $value;
70 | }
71 |
72 | /**
73 | * Gets the SQL declaration snippet for a field of this type.
74 | *
75 | * @param array $fieldDeclaration The field declaration.
76 | * @param AbstractPlatform $platform The currently used database platform.
77 | * @return string
78 | * @throws \Doctrine\DBAL\DBALException
79 | */
80 | public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
81 | {
82 | $options = !array_key_exists('platformOptions', $fieldDeclaration) ?
83 | array() : $fieldDeclaration['platformOptions'];
84 | return $this->getArrayTypeDeclarationSQL($platform, $fieldDeclaration, $options);
85 | }
86 |
87 | /**
88 | * Gets the SQL snippet used to declare an ARRAY column type.
89 | *
90 | * @param AbstractPlatform $platform
91 | * @param array $field
92 | *
93 | * @param array $options
94 | * @return string
95 | * @throws \Doctrine\DBAL\DBALException
96 | */
97 | public function getArrayTypeDeclarationSQL(AbstractPlatform $platform, array $field, array $options)
98 | {
99 | $type = array_key_exists('type', $options) ? $options['type'] : Type::STRING;
100 | return 'ARRAY ( ' . Type::getType($type)->getSQLDeclaration($field, $platform) . ' )';
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/src/Crate/DBAL/Types/MapType.php:
--------------------------------------------------------------------------------
1 | 0 && !(array_keys($value) !== range(0, count($value) - 1)))) {
68 | return null;
69 | }
70 |
71 | return $value;
72 | }
73 |
74 | public function convertToPHPValue($value, AbstractPlatform $platform)
75 | {
76 | return $value == null ?: (array) $value;
77 | }
78 |
79 | /**
80 | * Gets the SQL declaration snippet for a field of this type.
81 | *
82 | * @param array $fieldDeclaration The field declaration.
83 | * @param AbstractPlatform $platform The currently used database platform.
84 | * @return string
85 | * @throws \Doctrine\DBAL\DBALException
86 | */
87 | public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
88 | {
89 | $options = !array_key_exists('platformOptions', $fieldDeclaration) ?
90 | array() : $fieldDeclaration['platformOptions'];
91 |
92 | return $this->getMapTypeDeclarationSQL($platform, $fieldDeclaration, $options);
93 | }
94 |
95 | /**
96 | * Gets the SQL snippet used to declare an OBJECT column type.
97 | *
98 | * @param array $field
99 | *
100 | * @return string
101 | * @throws \Doctrine\DBAL\DBALException
102 | */
103 | public function getMapTypeDeclarationSQL(AbstractPlatform $platform, array $field, array $options)
104 | {
105 | $type = array_key_exists('type', $options) ? $options['type'] : MapType::DYNAMIC;
106 |
107 | $fields = array_key_exists('fields', $options) ? $options['fields'] : array();
108 | $columns = array();
109 | foreach ($fields as $field) {
110 | $columns[$field->getQuotedName($platform)] = CratePlatform::prepareColumnData($platform, $field);
111 | }
112 | $objectFields = $platform->getColumnDeclarationListSQL($columns);
113 |
114 | $declaration = count($columns) > 0 ? ' AS ( ' . $objectFields . ' )' : '';
115 | return 'OBJECT ( ' . $type . ' )' . $declaration ;
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/src/Crate/DBAL/Types/TimestampType.php:
--------------------------------------------------------------------------------
1 | getTimestamp()*self::S_TO_MS : null;
51 | }
52 |
53 | public function convertToPHPValue($value, AbstractPlatform $platform)
54 | {
55 | if ($value === null || $value instanceof DateTime) {
56 | return $value;
57 | }
58 |
59 | if (!is_int($value)) {
60 | return null;
61 | }
62 |
63 | $val = new DateTime();
64 | $val->setTimestamp($value/self::S_TO_MS);
65 |
66 | return $val;
67 | }
68 |
69 | /**
70 | * Gets the SQL declaration snippet for a field of this type.
71 | *
72 | * @return string
73 | * @param array $fieldDeclaration The field declaration.
74 | * @param AbstractPlatform $platform The currently used database platform.
75 | */
76 | public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
77 | {
78 | return $platform->getDateTimeTypeDeclarationSQL($fieldDeclaration);
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/test/Crate/Test/DBAL/DBALFunctionalTestCase.php:
--------------------------------------------------------------------------------
1 | close();
53 | self::$_sharedConn = null;
54 | }
55 | }
56 |
57 | public function setUp() : void
58 | {
59 | if ( ! isset(self::$_sharedConn)) {
60 | $params = array(
61 | 'driverClass' => 'Crate\DBAL\Driver\PDOCrate\Driver',
62 | 'host' => 'localhost',
63 | 'port' => 4200
64 | );
65 | self::$_sharedConn = DriverManager::getConnection($params);
66 | }
67 | $this->_conn = self::$_sharedConn;
68 |
69 | $this->_sqlLoggerStack = new DebugStack();
70 | $this->_conn->getConfiguration()->setSQLLogger($this->_sqlLoggerStack);
71 | }
72 |
73 | protected function onNotSuccessfulTest(Throwable $e) : void
74 | {
75 | if ($e instanceof AssertionFailedError) {
76 | throw $e;
77 | }
78 |
79 | if(isset($this->_sqlLoggerStack->queries) && count($this->_sqlLoggerStack->queries)) {
80 | $queries = "";
81 | $i = count($this->_sqlLoggerStack->queries);
82 | foreach (array_reverse($this->_sqlLoggerStack->queries) AS $query) {
83 | $params = array_map(function($p) { if (is_object($p)) return get_class($p); else return "'".print_r($p, true)."'"; }, $query['params'] ?: array());
84 | $queries .= ($i+1).". SQL: '".$query['sql']."' Params: ".implode(", ", $params).PHP_EOL;
85 | $i--;
86 | }
87 |
88 | $trace = $e->getTrace();
89 | $traceMsg = "";
90 | foreach($trace AS $part) {
91 | if(isset($part['file'])) {
92 | if(strpos($part['file'], "PHPUnit/") !== false) {
93 | // Beginning with PHPUnit files we don't print the trace anymore.
94 | break;
95 | }
96 |
97 | $traceMsg .= $part['file'].":".$part['line'].PHP_EOL;
98 | }
99 | }
100 |
101 | $message = "[".get_class($e)."] ".$e->getMessage().PHP_EOL.PHP_EOL."With queries:".PHP_EOL.$queries.PHP_EOL."Trace:".PHP_EOL.$traceMsg;
102 |
103 | throw new \Exception($message, (int)$e->getCode(), $e);
104 | }
105 | throw $e;
106 | }
107 |
108 | public function execute($stmt)
109 | {
110 | return $this->_conn->query($stmt);
111 | }
112 |
113 | public function refresh($table_name)
114 | {
115 | $this->_conn->query('REFRESH TABLE ' . $table_name);
116 | }
117 |
118 | public function prepareStatement($sql)
119 | {
120 | return $this->_conn->prepare($sql);
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/test/Crate/Test/DBAL/Functional/BindingTest.php:
--------------------------------------------------------------------------------
1 | prepareStatement('SELECT * FROM sys.cluster WHERE name = ?');
35 | $stmt->bindParam(1, $name);
36 | $stmt->execute();
37 |
38 | $noName = 'i0ejfNlzSFCloGYtSzddTw';
39 |
40 | $stmt = $this->prepareStatement('SELECT * FROM sys.cluster WHERE name = ? OR master_node = ?');
41 | $stmt->bindParam(1, $name);
42 | $stmt->bindParam(2, $noName);
43 | $this->assertTrue($stmt->execute());
44 | }
45 |
46 | public function testBindPositionalValue()
47 | {
48 | $stmt = $this->prepareStatement('SELECT * FROM sys.cluster WHERE name = ?');
49 | $stmt->bindValue(1, 'crate');
50 | $stmt->execute();
51 |
52 | $stmt = $this->prepareStatement('SELECT * FROM sys.cluster WHERE name = ? OR master_node = ?');
53 | $stmt->bindValue(1, 'crate');
54 | $stmt->bindValue(2, 'i0ejfNlzSFCloGYtSzddTw');
55 | $this->assertTrue($stmt->execute());
56 | }
57 |
58 | public function testBindNamedParam()
59 | {
60 | $name = 'crate';
61 |
62 | $stmt = $this->prepareStatement('SELECT * FROM sys.cluster WHERE name = :name');
63 | $stmt->bindParam('name', $name);
64 | $stmt->execute();
65 |
66 | $noName = 'i0ejfNlzSFCloGYtSzddTw';
67 |
68 | $stmt = $this->prepareStatement('SELECT * FROM sys.cluster WHERE name = :name OR master_node = :master_node');
69 | $stmt->bindParam('name', $name);
70 | $stmt->bindParam('master_node', $noName);
71 | $this->assertTrue($stmt->execute());
72 | }
73 |
74 | public function testBindNamedValue()
75 | {
76 | $stmt = $this->prepareStatement('SELECT * FROM sys.cluster WHERE name = :name');
77 | $stmt->bindValue('name', 'crate');
78 | $stmt->execute();
79 |
80 | $stmt = $this->prepareStatement('SELECT * FROM sys.cluster WHERE name = :name OR master_node = :master_node');
81 | $stmt->bindValue('name', 'crate');
82 | $stmt->bindValue('master_node', 'i0ejfNlzSFCloGYtSzddTw');
83 | $this->assertTrue($stmt->execute());
84 | }
85 |
86 | public function testBindTimestamp()
87 | {
88 | if ($this->_conn->getSchemaManager()->tablesExist("foo")) {
89 | $this->execute("DROP TABLE foo");
90 | }
91 |
92 | $this->execute("CREATE TABLE foo (id int, ts timestamp) with (number_of_replicas=0)");
93 | $this->execute("INSERT INTO foo (id, ts) VALUES (1, 1413901591000)");
94 | $this->execute("INSERT INTO foo (id, ts) VALUES (2, 1413901592000)");
95 | $this->execute("INSERT INTO foo (id, ts) VALUES (3, 1413901593000)");
96 | $this->execute("REFRESH TABLE foo");
97 |
98 | $date = new \DateTime("2014-10-21 14:26:32"); // => 1413901592000
99 |
100 | $stmt = $this->prepareStatement('SELECT * FROM foo WHERE ts > ?');
101 | $stmt->bindValue(1, $date, 'datetimetz');
102 | $stmt->execute();
103 | $row = $stmt->fetchAll();
104 | $this->assertEquals($row[0]['id'], 3);
105 | $this->assertEquals($row[0]['ts'], 1413901593000);
106 |
107 | $stmt = $this->prepareStatement('SELECT * FROM foo WHERE ts < ?');
108 | $stmt->bindValue(1, $date, 'datetime');
109 | $stmt->execute();
110 | $row = $stmt->fetchAll();
111 | $this->assertEquals($row[0]['id'], 1);
112 | $this->assertEquals($row[0]['ts'], 1413901591000);
113 |
114 | $this->execute("DROP TABLE foo");
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/test/Crate/Test/DBAL/Functional/ConnectionTest.php:
--------------------------------------------------------------------------------
1 | resetSharedConn();
32 | parent::setUp();
33 | }
34 |
35 | public function tearDown() : void
36 | {
37 | parent::tearDown();
38 | $this->resetSharedConn();
39 | }
40 |
41 | public function testBasicAuthConnection()
42 | {
43 | $auth = ['crate', 'secret'];
44 | $params = array(
45 | 'driverClass' => 'Crate\DBAL\Driver\PDOCrate\Driver',
46 | 'host' => 'localhost',
47 | 'port' => 4200,
48 | 'user' => $auth[0],
49 | 'password' => $auth[1],
50 | );
51 | $conn = \Doctrine\DBAL\DriverManager::getConnection($params);
52 | $this->assertEquals($auth[0], $conn->getUsername());
53 | $this->assertEquals($auth[1], $conn->getPassword());
54 | $auth_attr = $conn->getWrappedConnection()->getAttribute(PDO::CRATE_ATTR_HTTP_BASIC_AUTH);
55 | $this->assertEquals($auth_attr, $auth);
56 | }
57 |
58 | public function testGetConnection()
59 | {
60 | $this->assertInstanceOf('Doctrine\DBAL\Connection', $this->_conn);
61 | $this->assertInstanceOf('Crate\DBAL\Driver\PDOCrate\PDOConnection', $this->_conn->getWrappedConnection());
62 | }
63 |
64 | public function testGetDriver()
65 | {
66 | $this->assertInstanceOf('Crate\DBAL\Driver\PDOCrate\Driver', $this->_conn->getDriver());
67 | }
68 |
69 | public function testStatement()
70 | {
71 | $sql = 'SELECT * FROM sys.cluster';
72 | $stmt = $this->_conn->prepare($sql);
73 | $this->assertInstanceOf('Doctrine\DBAL\Statement', $stmt);
74 | $this->assertInstanceOf('Crate\PDO\PDOStatement', $stmt->getWrappedStatement());
75 |
76 | }
77 |
78 | public function testConnect()
79 | {
80 | $this->assertTrue($this->_conn->connect());
81 |
82 | $stmt = $this->_conn->query('select * from sys.cluster');
83 | $this->assertEquals(1, $stmt->rowCount());
84 |
85 | $row = $stmt->fetch();
86 | $this->assertEquals('crate', $row['name']);
87 | }
88 |
89 | }
90 |
91 |
--------------------------------------------------------------------------------
/test/Crate/Test/DBAL/Functional/DataAccessTest.php:
--------------------------------------------------------------------------------
1 | _conn->getSchemaManager();
47 | $table = new \Doctrine\DBAL\Schema\Table("fetch_table");
48 | $table->addColumn('test_int', 'integer');
49 | $table->addColumn('test_string', 'string');
50 | $table->addColumn('test_datetime', 'timestamp', array('notnull' => false));
51 | $table->addColumn('test_array', 'array', array('columnDefinition'=>'ARRAY(STRING)'));
52 | $platformOptions = array(
53 | 'type' => MapType::STRICT,
54 | 'fields' => array(
55 | new Column('id', Type::getType('integer'), array()),
56 | new Column('name', Type::getType('string'), array()),
57 | new Column('value', Type::getType('float'), array()),
58 | ),
59 | );
60 | $table->addColumn('test_object', MapType::NAME,
61 | array('platformOptions'=>$platformOptions));
62 | $table->setPrimaryKey(array('test_int'));
63 |
64 | $sm->createTable($table);
65 |
66 | $this->_conn->insert('fetch_table', array(
67 | 'test_int' => 1,
68 | 'test_string' => 'foo',
69 | 'test_datetime' => new \DateTime('2010-01-01 10:10:10'),
70 | 'test_array' => array('foo','bar'),
71 | 'test_object' => array('id'=>1, 'name'=>'foo', 'value'=>1.234,),
72 | ), array('integer','string','timestamp','array','map'));
73 | $this->refresh('fetch_table');
74 | }
75 | }
76 |
77 | public function tearDown() : void
78 | {
79 | if (self::$generated === true) {
80 | $this->_conn->getSchemaManager()->dropTable('fetch_table');
81 | self::$generated = false;
82 | }
83 | }
84 |
85 | public function testPrepareWithBindValue()
86 | {
87 | $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?";
88 | $stmt = $this->_conn->prepare($sql);
89 | $this->assertInstanceOf('Doctrine\DBAL\Statement', $stmt);
90 |
91 | $stmt->bindValue(1, 1, PDO::PARAM_INT);
92 | $stmt->bindValue(2, 'foo', PDO::PARAM_STR);
93 | $stmt->execute();
94 |
95 | $row = $stmt->fetch(\PDO::FETCH_ASSOC);
96 | $row = array_change_key_case($row, \CASE_LOWER);
97 | $this->assertEquals(array('test_int' => 1, 'test_string' => 'foo'), $row);
98 | }
99 |
100 | public function testPrepareWithBindParam()
101 | {
102 | $paramInt = 1;
103 | $paramStr = 'foo';
104 |
105 | $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?";
106 | $stmt = $this->_conn->prepare($sql);
107 | $this->assertInstanceOf('Doctrine\DBAL\Statement', $stmt);
108 |
109 | $stmt->bindParam(1, $paramInt, PDO::PARAM_INT);
110 | $stmt->bindParam(2, $paramStr, PDO::PARAM_STR);
111 | $stmt->execute();
112 |
113 | $row = $stmt->fetch(\PDO::FETCH_ASSOC);
114 | $row = array_change_key_case($row, \CASE_LOWER);
115 | $this->assertEquals(array('test_int' => 1, 'test_string' => 'foo'), $row);
116 | }
117 |
118 | public function testPrepareWithFetchAll()
119 | {
120 | $paramInt = 1;
121 | $paramStr = 'foo';
122 |
123 | $sql = "SELECT test_int, test_string, test_datetime, test_array, test_object FROM fetch_table WHERE test_int = ? AND test_string = ?";
124 | $stmt = $this->_conn->prepare($sql);
125 | $this->assertInstanceOf('Doctrine\DBAL\Statement', $stmt);
126 |
127 | $stmt->bindParam(1, $paramInt, PDO::PARAM_INT);
128 | $stmt->bindParam(2, $paramStr, PDO::PARAM_STR);
129 | $stmt->execute();
130 |
131 | $rows = $stmt->fetchAll(\PDO::FETCH_ASSOC);
132 | $rows[0] = array_change_key_case($rows[0], \CASE_LOWER);
133 | $this->assertEquals(array(
134 | 'test_int' => 1,
135 | 'test_string' => 'foo',
136 | 'test_datetime' => 1262340610000,
137 | 'test_array' => array('foo', 'bar'),
138 | 'test_object' => array('id'=>1, 'name'=>'foo', 'value'=>1.234)
139 | ), $rows[0]);
140 |
141 | $this->assertEquals($this->_conn->convertToPHPValue($rows[0]['test_datetime'], 'timestamp'),
142 | new \DateTime('2010-01-01 10:10:10'));
143 | $this->assertEquals($this->_conn->convertToPHPValue($rows[0]['test_object'], 'map'),
144 | array('id'=>1, 'name'=>'foo', 'value'=>1.234));
145 | $this->assertEquals($this->_conn->convertToPHPValue($rows[0]['test_array'], 'array'),
146 | array('foo','bar'));
147 | }
148 |
149 | /**
150 | * @group DBAL-228
151 | */
152 | public function testPrepareWithFetchAllBoth()
153 | {
154 | $paramInt = 1;
155 | $paramStr = 'foo';
156 |
157 | $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?";
158 | $stmt = $this->_conn->prepare($sql);
159 | $this->assertInstanceOf('Doctrine\DBAL\Statement', $stmt);
160 |
161 | $stmt->bindParam(1, $paramInt, PDO::PARAM_INT);
162 | $stmt->bindParam(2, $paramStr, PDO::PARAM_STR);
163 | $stmt->execute();
164 |
165 | $rows = $stmt->fetchAll(\PDO::FETCH_BOTH);
166 | $rows[0] = array_change_key_case($rows[0], \CASE_LOWER);
167 | $this->assertEquals(array('test_int' => 1, 'test_string' => 'foo', 0 => 1, 1 => 'foo'), $rows[0]);
168 | }
169 |
170 | public function testPrepareWithFetchColumn()
171 | {
172 | $paramInt = 1;
173 | $paramStr = 'foo';
174 |
175 | $sql = "SELECT test_int FROM fetch_table WHERE test_int = ? AND test_string = ?";
176 | $stmt = $this->_conn->prepare($sql);
177 | $this->assertInstanceOf('Doctrine\DBAL\Statement', $stmt);
178 |
179 | $stmt->bindParam(1, $paramInt, PDO::PARAM_INT);
180 | $stmt->bindParam(2, $paramStr, PDO::PARAM_STR);
181 | $stmt->execute();
182 |
183 | $column = $stmt->fetchColumn();
184 | $this->assertEquals(1, $column);
185 | }
186 |
187 | public function testPrepareWithIterator()
188 | {
189 | $paramInt = 1;
190 | $paramStr = 'foo';
191 |
192 | $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?";
193 | $stmt = $this->_conn->prepare($sql);
194 | $this->assertInstanceOf('Doctrine\DBAL\Statement', $stmt);
195 |
196 | $stmt->bindParam(1, $paramInt, PDO::PARAM_INT);
197 | $stmt->bindParam(2, $paramStr, PDO::PARAM_STR);
198 | $stmt->execute();
199 |
200 | $rows = array();
201 | $stmt->setFetchMode(\PDO::FETCH_ASSOC);
202 | foreach ($stmt as $row) {
203 | $rows[] = array_change_key_case($row, \CASE_LOWER);
204 | }
205 |
206 | $this->assertEquals(array('test_int' => 1, 'test_string' => 'foo'), $rows[0]);
207 | }
208 |
209 | public function testPrepareWithQuoted()
210 | {
211 | $table = 'fetch_table';
212 | $paramInt = 1;
213 | $paramStr = 'foo';
214 |
215 | $sql = "SELECT test_int, test_string FROM " . $this->_conn->quoteIdentifier($table) . " ".
216 | "WHERE test_int = " . $this->_conn->quote($paramInt, ParameterType::INTEGER) . " AND test_string = '" . $paramStr . "')";
217 | $stmt = $this->_conn->prepare($sql);
218 | $this->assertInstanceOf('Doctrine\DBAL\Statement', $stmt);
219 | }
220 |
221 | public function testPrepareWithExecuteParams()
222 | {
223 | $paramInt = 1;
224 | $paramStr = 'foo';
225 |
226 | $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?";
227 | $stmt = $this->_conn->prepare($sql);
228 | $this->assertInstanceOf('Doctrine\DBAL\Statement', $stmt);
229 | $stmt->execute(array($paramInt, $paramStr));
230 |
231 | $row = $stmt->fetch(\PDO::FETCH_ASSOC);
232 | $this->assertTrue($row !== false);
233 | $row = array_change_key_case($row, \CASE_LOWER);
234 | $this->assertEquals(array('test_int' => 1, 'test_string' => 'foo'), $row);
235 | }
236 |
237 | public function testFetchAll()
238 | {
239 | $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?";
240 | $data = $this->_conn->fetchAll($sql, array(1, 'foo'));
241 |
242 | $this->assertEquals(1, count($data));
243 |
244 | $row = $data[0];
245 | $this->assertEquals(2, count($row));
246 |
247 | $row = array_change_key_case($row, \CASE_LOWER);
248 | $this->assertEquals(1, $row['test_int']);
249 | $this->assertEquals('foo', $row['test_string']);
250 | }
251 |
252 | public function testFetchBoth()
253 | {
254 | $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?";
255 | $row = $this->_conn->executeQuery($sql, array(1, 'foo'))->fetch(\PDO::FETCH_BOTH);
256 |
257 | $this->assertTrue($row !== false);
258 |
259 | $row = array_change_key_case($row, \CASE_LOWER);
260 |
261 | $this->assertEquals(1, $row['test_int']);
262 | $this->assertEquals('foo', $row['test_string']);
263 | $this->assertEquals(1, $row[0]);
264 | $this->assertEquals('foo', $row[1]);
265 | }
266 |
267 | public function testFetchRow()
268 | {
269 | $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?";
270 | $row = $this->_conn->fetchAssoc($sql, array(1, 'foo'));
271 |
272 | $this->assertTrue($row !== false);
273 |
274 | $row = array_change_key_case($row, \CASE_LOWER);
275 |
276 | $this->assertEquals(1, $row['test_int']);
277 | $this->assertEquals('foo', $row['test_string']);
278 | }
279 |
280 | public function testFetchArray()
281 | {
282 | $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?";
283 | $row = $this->_conn->fetchArray($sql, array(1, 'foo'));
284 |
285 | $this->assertEquals(1, $row[0]);
286 | $this->assertEquals('foo', $row[1]);
287 | }
288 |
289 | public function testFetchColumn()
290 | {
291 | $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?";
292 | $testInt = $this->_conn->fetchColumn($sql, array(1, 'foo'), 0);
293 |
294 | $this->assertEquals(1, $testInt);
295 |
296 | $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?";
297 | $testString = $this->_conn->fetchColumn($sql, array(1, 'foo'), 1);
298 |
299 | $this->assertEquals('foo', $testString);
300 | }
301 |
302 | /**
303 | * @group DDC-697
304 | */
305 | public function testExecuteQueryBindDateTimeType()
306 | {
307 | $sql = 'SELECT count(*) AS c FROM fetch_table WHERE test_datetime = ?';
308 | $stmt = $this->_conn->executeQuery($sql,
309 | array(1 => new \DateTime('2010-01-01 10:10:10')),
310 | array(1 => Type::DATETIME)
311 | );
312 |
313 | $this->assertEquals(1, $stmt->fetchColumn());
314 | }
315 |
316 | /**
317 | * @group DDC-697
318 | */
319 | public function testExecuteUpdateBindDateTimeType()
320 | {
321 | $datetime = new \DateTime('2010-02-02 20:20:20');
322 |
323 | $sql = 'INSERT INTO fetch_table (test_int, test_string, test_datetime) VALUES (?, ?, ?)';
324 | $affectedRows = $this->_conn->executeUpdate($sql,
325 | array(1 => 50, 2 => 'foo', 3 => $datetime),
326 | array(1 => PDO::PARAM_INT, 2 => PDO::PARAM_STR, 3 => Type::DATETIME)
327 | );
328 | $this->assertEquals(1, $affectedRows);
329 | $this->refresh('fetch_table');
330 |
331 | $this->assertEquals(1, $this->_conn->executeQuery(
332 | 'SELECT count(*) AS c FROM fetch_table WHERE test_datetime = ?',
333 | array(1 => $datetime),
334 | array(1 => Type::DATETIME)
335 | )->fetchColumn());
336 | }
337 |
338 | /**
339 | * @group DDC-697
340 | */
341 | public function testPrepareQueryBindValueDateTimeType()
342 | {
343 | $sql = 'SELECT count(*) AS c FROM fetch_table WHERE test_datetime = ?';
344 | $stmt = $this->_conn->prepare($sql);
345 | $stmt->bindValue(1, new \DateTime('2010-01-01 10:10:10'), Type::DATETIME);
346 | $stmt->execute();
347 |
348 | $this->assertEquals(1, $stmt->fetchColumn());
349 | }
350 |
351 | /**
352 | * @group DBAL-78
353 | */
354 | public function testNativeArrayListSupport()
355 | {
356 | for ($i = 100; $i < 110; $i++) {
357 | $this->_conn->insert('fetch_table', array('test_int' => $i, 'test_string' => 'foo' . $i, 'test_datetime' => '2010-01-01T10:10:10'));
358 | }
359 | $this->refresh('fetch_table');
360 |
361 | $stmt = $this->_conn->executeQuery('SELECT test_int FROM fetch_table WHERE test_int IN (?) ORDER BY test_int',
362 | array(array(100, 101, 102, 103, 104)), array(Connection::PARAM_INT_ARRAY));
363 |
364 | $data = $stmt->fetchAll(PDO::FETCH_NUM);
365 | $this->assertEquals(5, count($data));
366 | $this->assertEquals(array(array(100), array(101), array(102), array(103), array(104)), $data);
367 |
368 | $stmt = $this->_conn->executeQuery('SELECT test_int FROM fetch_table WHERE test_string IN (?) ORDER BY test_int',
369 | array(array('foo100', 'foo101', 'foo102', 'foo103', 'foo104')), array(Connection::PARAM_STR_ARRAY));
370 |
371 | $data = $stmt->fetchAll(PDO::FETCH_NUM);
372 | $this->assertEquals(5, count($data));
373 | $this->assertEquals(array(array(100), array(101), array(102), array(103), array(104)), $data);
374 | }
375 |
376 | /**
377 | * @group DDC-1014
378 | */
379 | public function testDateArithmetics()
380 | {
381 | $this->markTestSkipped('Data add day expression not supported by crate platform');
382 |
383 | $p = $this->_conn->getDatabasePlatform();
384 | $sql = 'SELECT ';
385 | $sql .= $p->getDateDiffExpression('test_datetime', $p->getCurrentTimestampSQL()) .' AS diff, ';
386 | $sql .= $p->getDateAddDaysExpression('test_datetime', 10) .' AS add_days, ';
387 | $sql .= $p->getDateSubDaysExpression('test_datetime', 10) .' AS sub_days, ';
388 | $sql .= $p->getDateAddMonthExpression('test_datetime', 2) .' AS add_month, ';
389 | $sql .= $p->getDateSubMonthExpression('test_datetime', 2) .' AS sub_month ';
390 | $sql .= 'FROM fetch_table';
391 |
392 | $row = $this->_conn->fetchAssoc($sql);
393 | $row = array_change_key_case($row, CASE_LOWER);
394 |
395 | $diff = floor( (strtotime('2010-01-01')-time()) / 3600 / 24);
396 | $this->assertEquals($diff, (int)$row['diff'], "Date difference should be approx. ".$diff." days.", 1);
397 | $this->assertEquals('2010-01-11', date('Y-m-d', strtotime($row['add_days'])), "Adding date should end up on 2010-01-11");
398 | $this->assertEquals('2009-12-22', date('Y-m-d', strtotime($row['sub_days'])), "Subtracting date should end up on 2009-12-22");
399 | $this->assertEquals('2010-03-01', date('Y-m-d', strtotime($row['add_month'])), "Adding month should end up on 2010-03-01");
400 | $this->assertEquals('2009-11-01', date('Y-m-d', strtotime($row['sub_month'])), "Adding month should end up on 2009-11-01");
401 | }
402 |
403 | public function testQuoteSQLInjection()
404 | {
405 | $this->expectException(DBALException::class);
406 |
407 | $sql = "SELECT * FROM fetch_table WHERE test_string = bar' OR '1'='1";
408 | $this->_conn->fetchAll($sql);
409 | }
410 |
411 | /**
412 | * @group DDC-1213
413 | */
414 | public function testBitComparisonExpressionSupport()
415 | {
416 | $this->markTestSkipped("Bit comparison expression not supported by crate");
417 |
418 | $this->_conn->executeQuery('DELETE FROM fetch_table')->execute();
419 | $platform = $this->_conn->getDatabasePlatform();
420 | $bitmap = array();
421 |
422 | for ($i = 2; $i < 9; $i = $i + 2) {
423 | $bitmap[$i] = array(
424 | 'bit_or' => ($i | 2),
425 | 'bit_and' => ($i & 2)
426 | );
427 | $this->_conn->insert('fetch_table', array(
428 | 'test_int' => $i,
429 | 'test_string' => json_encode($bitmap[$i]),
430 | 'test_datetime' => '2010-01-01T10:10:10'
431 | ));
432 | }
433 |
434 | $sql[] = 'SELECT ';
435 | $sql[] = 'test_int, ';
436 | $sql[] = 'test_string, ';
437 | $sql[] = $platform->getBitOrComparisonExpression('test_int', 2) . ' AS bit_or, ';
438 | $sql[] = $platform->getBitAndComparisonExpression('test_int', 2) . ' AS bit_and ';
439 | $sql[] = 'FROM fetch_table';
440 |
441 | $stmt = $this->_conn->executeQuery(implode(PHP_EOL, $sql));
442 | $data = $stmt->fetchAll(PDO::FETCH_ASSOC);
443 |
444 |
445 | $this->assertEquals(4, count($data));
446 | $this->assertEquals(count($bitmap), count($data));
447 | foreach ($data as $row) {
448 | $row = array_change_key_case($row, CASE_LOWER);
449 |
450 | $this->assertArrayHasKey('test_int', $row);
451 |
452 | $id = $row['test_int'];
453 |
454 | $this->assertArrayHasKey($id, $bitmap);
455 | $this->assertArrayHasKey($id, $bitmap);
456 |
457 | $this->assertArrayHasKey('bit_or', $row);
458 | $this->assertArrayHasKey('bit_and', $row);
459 |
460 | $this->assertEquals($row['bit_or'], $bitmap[$id]['bit_or']);
461 | $this->assertEquals($row['bit_and'], $bitmap[$id]['bit_and']);
462 | }
463 | }
464 |
465 | public function testSetDefaultFetchMode()
466 | {
467 | $stmt = $this->_conn->query("SELECT * FROM fetch_table");
468 | $stmt->setFetchMode(\PDO::FETCH_NUM);
469 |
470 | $row = array_keys($stmt->fetch());
471 | $this->assertEquals(0, count( array_filter($row, function($v) { return ! is_numeric($v); })), "should be no non-numerical elements in the result.");
472 | }
473 |
474 | /**
475 | * @group DBAL-196
476 | */
477 | public function testFetchAllSupportFetchClass()
478 | {
479 | $this->markTestSkipped("PDO::FETCH_CLASS not supported by crate PDO");
480 |
481 | $this->setupFixture();
482 |
483 | $sql = "SELECT test_int, test_string, test_datetime FROM fetch_table";
484 | $stmt = $this->_conn->prepare($sql);
485 | $stmt->execute();
486 |
487 | $results = $stmt->fetchAll(
488 | \PDO::FETCH_CLASS,
489 | __NAMESPACE__.'\\MyFetchClass'
490 | );
491 |
492 | $this->assertEquals(1, count($results));
493 | $this->assertInstanceOf(__NAMESPACE__.'\\MyFetchClass', $results[0]);
494 |
495 | $this->assertEquals(1, $results[0]->test_int);
496 | $this->assertEquals('foo', $results[0]->test_string);
497 | $this->assertStringStartsWith('2010-01-01T10:10:10', $results[0]->test_datetime);
498 | }
499 |
500 | /**
501 | * @group DBAL-241
502 | */
503 | public function testFetchAllStyleColumn()
504 | {
505 | $sql = "DELETE FROM fetch_table";
506 | $this->_conn->executeUpdate($sql);
507 |
508 | $this->_conn->insert('fetch_table', array('test_int' => 1, 'test_string' => 'foo'));
509 | $this->_conn->insert('fetch_table', array('test_int' => 10, 'test_string' => 'foo'));
510 | $this->refresh("fetch_table");
511 |
512 | $sql = "SELECT test_int FROM fetch_table ORDER BY test_int ASC";
513 | $rows = $this->_conn->query($sql)->fetchAll(\PDO::FETCH_COLUMN);
514 |
515 | $this->assertEquals(array(1, 10), $rows);
516 | }
517 |
518 | /**
519 | * @group DBAL-214
520 | */
521 | public function testSetFetchModeClassFetchAll()
522 | {
523 | $this->markTestSkipped("PDO::FETCH_CLASS not supported crate PDO");
524 | $this->setupFixture();
525 |
526 | $sql = "SELECT * FROM fetch_table";
527 | $stmt = $this->_conn->query($sql);
528 | $stmt->setFetchMode(\PDO::FETCH_CLASS, __NAMESPACE__ . '\\MyFetchClass', array());
529 |
530 | $results = $stmt->fetchAll();
531 |
532 | $this->assertEquals(1, count($results));
533 | $this->assertInstanceOf(__NAMESPACE__.'\\MyFetchClass', $results[0]);
534 |
535 | $this->assertEquals(1, $results[0]->test_int);
536 | $this->assertEquals('foo', $results[0]->test_string);
537 | $this->assertStringStartsWith('2010-01-01T10:10:10', $results[0]->test_datetime);
538 | }
539 |
540 | /**
541 | * @group DBAL-214
542 | */
543 | public function testSetFetchModeClassFetch()
544 | {
545 | $this->markTestSkipped("PDO::FETCH_CLASS not supported by crate PDO");
546 |
547 | $this->setupFixture();
548 |
549 | $sql = "SELECT * FROM fetch_table";
550 | $stmt = $this->_conn->query($sql);
551 | $stmt->setFetchMode(\PDO::FETCH_CLASS, __NAMESPACE__ . '\\MyFetchClass', array());
552 |
553 | $results = array();
554 | while ($row = $stmt->fetch()) {
555 | $results[] = $row;
556 | }
557 |
558 | $this->assertEquals(1, count($results));
559 | $this->assertInstanceOf(__NAMESPACE__.'\\MyFetchClass', $results[0]);
560 |
561 | $this->assertEquals(1, $results[0]->test_int);
562 | $this->assertEquals('foo', $results[0]->test_string);
563 | $this->assertStringStartsWith('2010-01-01T10:10:10', $results[0]->test_datetime);
564 | }
565 |
566 | /**
567 | * @group DBAL-257
568 | */
569 | public function testEmptyFetchColumnReturnsFalse()
570 | {
571 | $this->_conn->executeQuery('DELETE FROM fetch_table')->execute();
572 | $this->refresh("fetch_table");
573 | $this->assertFalse($this->_conn->fetchColumn('SELECT test_int FROM fetch_table'));
574 | $this->assertFalse($this->_conn->query('SELECT test_int FROM fetch_table')->fetchColumn());
575 | }
576 |
577 | /**
578 | * @group DBAL-339
579 | */
580 | public function testSetFetchModeOnDbalStatement()
581 | {
582 | $sql = "SELECT test_int, test_string FROM fetch_table WHERE test_int = ? AND test_string = ?";
583 | $stmt = $this->_conn->executeQuery($sql, array(1, "foo"));
584 | $stmt->setFetchMode(\PDO::FETCH_NUM);
585 |
586 | while ($row = $stmt->fetch()) {
587 | $this->assertTrue(isset($row[0]));
588 | $this->assertTrue(isset($row[1]));
589 | }
590 | }
591 |
592 | private function setupFixture()
593 | {
594 | $this->_conn->executeQuery('DELETE FROM fetch_table')->execute();
595 | $this->_conn->insert('fetch_table', array(
596 | 'test_int' => 1,
597 | 'test_string' => 'foo',
598 | 'test_datetime' => '2010-01-01T10:10:10'
599 | ));
600 | }
601 |
602 | }
603 |
--------------------------------------------------------------------------------
/test/Crate/Test/DBAL/Functional/ModifyLimitQueryTest.php:
--------------------------------------------------------------------------------
1 | addColumn('test_int', 'integer');
41 | $table->setPrimaryKey(array('test_int'));
42 |
43 | $table2 = new \Doctrine\DBAL\Schema\Table("modify_limit_table2");
44 | $table2->addColumn('id', 'integer', array('autoincrement' => true));
45 | $table2->addColumn('test_int', 'integer');
46 | $table2->setPrimaryKey(array('id'));
47 |
48 | $sm = $this->_conn->getSchemaManager();
49 | $sm->createTable($table);
50 | $sm->createTable($table2);
51 | self::$tableCreated = true;
52 | }
53 | }
54 |
55 | public function tearDown() : void
56 | {
57 | parent::tearDown();
58 | if (self::$tableCreated) {
59 | $sm = $this->_conn->getSchemaManager();
60 | try {
61 | $sm->dropTable('modify_limit_table');
62 | $sm->dropTable('modify_limit_table2');
63 | self::$tableCreated = false;
64 | } catch (DBALException $e) {}
65 | }
66 | }
67 |
68 | public function testModifyLimitQuerySimpleQuery()
69 | {
70 | $this->_conn->insert('modify_limit_table', array('test_int' => 1));
71 | $this->_conn->insert('modify_limit_table', array('test_int' => 2));
72 | $this->_conn->insert('modify_limit_table', array('test_int' => 3));
73 | $this->_conn->insert('modify_limit_table', array('test_int' => 4));
74 |
75 | $this->refresh('modify_limit_table');
76 |
77 | $sql = "SELECT * FROM modify_limit_table ORDER BY test_int ASC";
78 |
79 | $this->assertLimitResult(array(1, 2, 3, 4), $sql, 10, 0);
80 | $this->assertLimitResult(array(1, 2), $sql, 2, 0);
81 | $this->assertLimitResult(array(3, 4), $sql, 2, 2);
82 | }
83 |
84 | public function testModifyLimitQueryOrderBy()
85 | {
86 | $this->_conn->insert('modify_limit_table', array('test_int' => 1));
87 | $this->_conn->insert('modify_limit_table', array('test_int' => 2));
88 | $this->_conn->insert('modify_limit_table', array('test_int' => 3));
89 | $this->_conn->insert('modify_limit_table', array('test_int' => 4));
90 |
91 | $this->refresh('modify_limit_table');
92 |
93 | $sql = "SELECT * FROM modify_limit_table ORDER BY test_int DESC";
94 |
95 | $this->assertLimitResult(array(4, 3, 2, 1), $sql, 10, 0);
96 | $this->assertLimitResult(array(4, 3), $sql, 2, 0);
97 | $this->assertLimitResult(array(2, 1), $sql, 2, 2);
98 | }
99 |
100 | public function testModifyLimitQueryGroupBy()
101 | {
102 | $this->_conn->insert('modify_limit_table2', array('test_int' => 1, 'id' => 1));
103 | $this->_conn->insert('modify_limit_table2', array('test_int' => 1, 'id' => 2));
104 | $this->_conn->insert('modify_limit_table2', array('test_int' => 1, 'id' => 3));
105 | $this->_conn->insert('modify_limit_table2', array('test_int' => 2, 'id' => 4));
106 | $this->_conn->insert('modify_limit_table2', array('test_int' => 2, 'id' => 5));
107 |
108 | $this->refresh('modify_limit_table2');
109 |
110 | $sql = "SELECT test_int FROM modify_limit_table2 GROUP BY test_int order by test_int";
111 | $this->assertLimitResult(array(1, 2), $sql, 10, 0);
112 | $this->assertLimitResult(array(1), $sql, 1, 0);
113 | $this->assertLimitResult(array(2), $sql, 1, 1);
114 | }
115 |
116 | public function assertLimitResult($expectedResults, $sql, $limit, $offset)
117 | {
118 | $p = $this->_conn->getDatabasePlatform();
119 | $data = array();
120 | foreach ($this->_conn->fetchAll($p->modifyLimitQuery($sql, $limit, $offset)) AS $row) {
121 | $row = array_change_key_case($row, CASE_LOWER);
122 | $data[] = $row['test_int'];
123 | }
124 | $this->assertEquals($expectedResults, $data);
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/test/Crate/Test/DBAL/Functional/NamedParametersTest.php:
--------------------------------------------------------------------------------
1 | 1,'bar'=> array(1, 2, 3)),
21 | array('foo'=>PDO::PARAM_INT,'bar'=> Connection::PARAM_INT_ARRAY,),
22 | array(
23 | array('id'=>1,'foo'=>1,'bar'=>1),
24 | array('id'=>2,'foo'=>1,'bar'=>2),
25 | array('id'=>3,'foo'=>1,'bar'=>3),
26 | )
27 | ),
28 |
29 | array(
30 | 'SELECT * FROM ddc1372_foobar f WHERE f.foo = :foo AND f.bar IN (:bar) ORDER BY f.id',
31 | array('foo'=>1,'bar'=> array(1, 2, 3)),
32 | array('bar'=> Connection::PARAM_INT_ARRAY,'foo'=>PDO::PARAM_INT),
33 | array(
34 | array('id'=>1,'foo'=>1,'bar'=>1),
35 | array('id'=>2,'foo'=>1,'bar'=>2),
36 | array('id'=>3,'foo'=>1,'bar'=>3),
37 | )
38 | ),
39 |
40 | array(
41 | 'SELECT * FROM ddc1372_foobar f WHERE f.bar IN (:bar) AND f.foo = :foo ORDER BY f.id',
42 | array('foo'=>1,'bar'=> array(1, 2, 3)),
43 | array('bar'=> Connection::PARAM_INT_ARRAY,'foo'=>PDO::PARAM_INT),
44 | array(
45 | array('id'=>1,'foo'=>1,'bar'=>1),
46 | array('id'=>2,'foo'=>1,'bar'=>2),
47 | array('id'=>3,'foo'=>1,'bar'=>3),
48 | )
49 | ),
50 |
51 | array(
52 | 'SELECT * FROM ddc1372_foobar f WHERE f.bar IN (:bar) AND f.foo = :foo ORDER BY f.id',
53 | array('foo'=>1,'bar'=> array('1', '2', '3')),
54 | array('bar'=> Connection::PARAM_STR_ARRAY,'foo'=>PDO::PARAM_INT),
55 | array(
56 | array('id'=>1,'foo'=>1,'bar'=>1),
57 | array('id'=>2,'foo'=>1,'bar'=>2),
58 | array('id'=>3,'foo'=>1,'bar'=>3),
59 | )
60 | ),
61 |
62 | array(
63 | 'SELECT * FROM ddc1372_foobar f WHERE f.bar IN (:bar) AND f.foo IN (:foo) ORDER BY f.id',
64 | array('foo'=>array('1'),'bar'=> array(1, 2, 3,4)),
65 | array('bar'=> Connection::PARAM_STR_ARRAY,'foo'=>Connection::PARAM_INT_ARRAY),
66 | array(
67 | array('id'=>1,'foo'=>1,'bar'=>1),
68 | array('id'=>2,'foo'=>1,'bar'=>2),
69 | array('id'=>3,'foo'=>1,'bar'=>3),
70 | array('id'=>4,'foo'=>1,'bar'=>4),
71 | )
72 | ),
73 |
74 | array(
75 | 'SELECT * FROM ddc1372_foobar f WHERE f.bar IN (:bar) AND f.foo IN (:foo) ORDER BY f.id',
76 | array('foo'=>1,'bar'=> 2),
77 | array('bar'=>PDO::PARAM_INT,'foo'=>PDO::PARAM_INT),
78 | array(
79 | array('id'=>2,'foo'=>1,'bar'=>2),
80 | )
81 | ),
82 |
83 | array(
84 | 'SELECT * FROM ddc1372_foobar f WHERE f.bar = :arg AND f.foo <> :arg ORDER BY f.id',
85 | array('arg'=>'1'),
86 | array('arg'=>PDO::PARAM_STR),
87 | array(
88 | array('id'=>5,'foo'=>2,'bar'=>1),
89 | )
90 | ),
91 |
92 | array(
93 | 'SELECT * FROM ddc1372_foobar f WHERE f.bar NOT IN (:arg) AND f.foo IN (:arg) ORDER BY f.id',
94 | array('arg'=>array(1, 2)),
95 | array('arg'=>Connection::PARAM_INT_ARRAY),
96 | array(
97 | array('id'=>3,'foo'=>1,'bar'=>3),
98 | array('id'=>4,'foo'=>1,'bar'=>4),
99 | )
100 | ),
101 |
102 | );
103 | }
104 |
105 | public function setUp() : void
106 | {
107 | parent::setUp();
108 |
109 | if (!$this->_conn->getSchemaManager()->tablesExist("ddc1372_foobar")) {
110 | try {
111 | $table = new \Doctrine\DBAL\Schema\Table("ddc1372_foobar");
112 | $table->addColumn('id', 'integer');
113 | $table->addColumn('foo','string');
114 | $table->addColumn('bar','string');
115 | $table->setPrimaryKey(array('id'));
116 |
117 |
118 | $sm = $this->_conn->getSchemaManager();
119 | $sm->createTable($table);
120 |
121 | $this->_conn->insert('ddc1372_foobar', array(
122 | 'id' => 1, 'foo' => 1, 'bar' => 1
123 | ));
124 | $this->_conn->insert('ddc1372_foobar', array(
125 | 'id' => 2, 'foo' => 1, 'bar' => 2
126 | ));
127 | $this->_conn->insert('ddc1372_foobar', array(
128 | 'id' => 3, 'foo' => 1, 'bar' => 3
129 | ));
130 | $this->_conn->insert('ddc1372_foobar', array(
131 | 'id' => 4, 'foo' => 1, 'bar' => 4
132 | ));
133 | $this->_conn->insert('ddc1372_foobar', array(
134 | 'id' => 5, 'foo' => 2, 'bar' => 1
135 | ));
136 | $this->_conn->insert('ddc1372_foobar', array(
137 | 'id' => 6, 'foo' => 2, 'bar' => 2
138 | ));
139 |
140 | $this->refresh('ddc1372_foobar');
141 | } catch(\Exception $e) {
142 | $this->fail($e->getMessage());
143 | }
144 | }
145 | }
146 |
147 | public function tearDown() : void
148 | {
149 | parent::tearDown();
150 | if ($this->_conn->getSchemaManager()->tablesExist("ddc1372_foobar")) {
151 | try {
152 | $sm = $this->_conn->getSchemaManager();
153 | $sm->dropTable('ddc1372_foobar');
154 | } catch(\Exception $e) {
155 | $this->fail($e->getMessage());
156 | }
157 | }
158 | }
159 |
160 | /**
161 | * @dataProvider ticketProvider
162 | * @param string $query
163 | * @param array $params
164 | * @param array $types
165 | * @param array $expected
166 | */
167 | public function testTicket($query,$params,$types,$expected)
168 | {
169 | $stmt = $this->_conn->executeQuery($query, $params, $types);
170 | $result = $stmt->fetchAll(\PDO::FETCH_ASSOC);
171 |
172 | foreach ($result as $k => $v) {
173 | $result[$k] = array_change_key_case($v, CASE_LOWER);
174 | }
175 |
176 | $this->assertEquals($result, $expected);
177 | }
178 |
179 | }
180 |
--------------------------------------------------------------------------------
/test/Crate/Test/DBAL/Functional/Schema/SchemaManagerTest.php:
--------------------------------------------------------------------------------
1 | _sm = $this->_conn->getSchemaManager();
43 | }
44 |
45 | public function tearDown() : void
46 | {
47 | foreach ($this->_sm->listTableNames() as $tableName) {
48 | $this->_sm->dropTable($tableName);
49 | }
50 | }
51 |
52 | public function testListTables()
53 | {
54 | $this->createTestTable('list_tables_test');
55 | $tables = $this->_sm->listTables();
56 |
57 | $this->assertIsArray($tables);
58 | $this->assertTrue(count($tables) > 0, "List Tables has to find at least one table named 'list_tables_test'.");
59 |
60 | $foundTable = false;
61 | foreach ($tables AS $table) {
62 | $this->assertInstanceOf('Doctrine\DBAL\Schema\Table', $table);
63 | if (strtolower($table->getName()) == 'list_tables_test') {
64 | $foundTable = true;
65 |
66 | $this->assertTrue($table->hasColumn('id'));
67 | $this->assertTrue($table->hasColumn('test'));
68 | $this->assertTrue($table->hasColumn('foreign_key_test'));
69 | }
70 | }
71 |
72 | $this->assertTrue( $foundTable , "The 'list_tables_test' table has to be found.");
73 | }
74 |
75 | public function createListTableColumns()
76 | {
77 | $table = new Table('list_table_columns');
78 | $table->addColumn('text', Type::STRING);
79 | $table->addColumn('ts', TimestampType::NAME);
80 | $table->addColumn('num_float_double', Type::FLOAT);
81 | $table->addColumn('num_short', Type::SMALLINT);
82 | $table->addColumn('num_int', Type::INTEGER);
83 | $table->addColumn('num_long', Type::BIGINT);
84 | $table->addColumn('id', 'integer', array('notnull' => true));
85 | $table->setPrimaryKey(array('id'));
86 |
87 | // OBJECT schema definition via platform options
88 | $mapOpts = array(
89 | 'type' => MapType::STRICT,
90 | 'fields' => array(
91 | new Column('id', Type::getType('integer'), array()),
92 | new Column('name', Type::getType('string'), array()),
93 | ),
94 | );
95 | $table->addColumn('obj', 'map',
96 | array('platformOptions'=>$mapOpts));
97 |
98 | // OBJECT schema definition via columnDefinition
99 | $table->addColumn('obj2', 'map',
100 | array('columnDefinition'=>'OBJECT (STRICT) AS ( id INTEGER, name STRING )'));
101 |
102 | // ARRAY schema definition via platform options
103 | $arrOpts = array(
104 | 'type' => Type::FLOAT,
105 | );
106 | $table->addColumn('arr_float', 'array',
107 | array('platformOptions'=>$arrOpts));
108 |
109 | // ARRAY schema definition via columnDefinition
110 | $table->addColumn('arr_str', 'array',
111 | array('columnDefinition'=>'ARRAY (STRING)'));
112 | $table->addColumn('arr_obj', 'array',
113 | array('columnDefinition'=>'ARRAY (OBJECT (IGNORED) AS ( id INTEGER, name STRING ))'));
114 |
115 | return $table;
116 | }
117 |
118 | public function testListTableColumns()
119 | {
120 | $table = $this->createListTableColumns();
121 |
122 | $this->_sm->dropAndCreateTable($table);
123 |
124 | $columns = $this->_sm->listTableColumns('list_table_columns');
125 | $columnsKeys = array_keys($columns);
126 |
127 | self::assertArrayHasKey('id', $columns);
128 | self::assertEquals(0, array_search('id', $columnsKeys));
129 | self::assertEquals('id', strtolower($columns['id']->getname()));
130 | self::assertInstanceOf(IntegerType::class, $columns['id']->gettype());
131 | self::assertFalse($columns['id']->getunsigned());
132 | self::assertTrue($columns['id']->getnotnull());
133 | self::assertNull($columns['id']->getdefault());
134 | self::assertIsArray($columns['id']->getPlatformOptions());
135 |
136 | $this->assertArrayHasKey('text', $columns);
137 | $this->assertEquals('text', strtolower($columns['text']->getname()));
138 | $this->assertInstanceOf('Doctrine\DBAL\Types\StringType', $columns['text']->gettype());
139 |
140 | $this->assertEquals('ts', strtolower($columns['ts']->getname()));
141 | $this->assertInstanceOf('Crate\DBAL\Types\TimestampType', $columns['ts']->gettype());
142 |
143 | $this->assertEquals('num_float_double', strtolower($columns['num_float_double']->getname()));
144 | $this->assertInstanceOf('Doctrine\DBAL\Types\FloatType', $columns['num_float_double']->gettype());
145 |
146 | $this->assertArrayHasKey('num_short', $columns);
147 | $this->assertEquals('num_short', strtolower($columns['num_short']->getname()));
148 | $this->assertInstanceOf('Doctrine\DBAL\Types\SmallIntType', $columns['num_short']->gettype());
149 |
150 | $this->assertArrayHasKey('num_int', $columns);
151 | $this->assertEquals('num_int', strtolower($columns['num_int']->getname()));
152 | $this->assertInstanceOf('Doctrine\DBAL\Types\IntegerType', $columns['num_int']->gettype());
153 |
154 | $this->assertArrayHasKey('num_long', $columns);
155 | $this->assertEquals('num_long', strtolower($columns['num_long']->getname()));
156 | $this->assertInstanceOf('Doctrine\DBAL\Types\BigIntType', $columns['num_long']->gettype());
157 |
158 | $this->assertEquals('obj', strtolower($columns['obj']->getname()));
159 | $this->assertInstanceOf('Crate\DBAL\Types\MapType', $columns['obj']->gettype());
160 |
161 | $this->assertEquals("obj['id']", strtolower($columns["obj['id']"]->getname()));
162 | $this->assertInstanceOf('Doctrine\DBAL\Types\IntegerType', $columns["obj['id']"]->gettype());
163 |
164 | $this->assertEquals("obj['name']", strtolower($columns["obj['name']"]->getname()));
165 | $this->assertInstanceOf('Doctrine\DBAL\Types\StringType', $columns["obj['name']"]->gettype());
166 |
167 | $this->assertEquals('obj2', strtolower($columns['obj2']->getname()));
168 | $this->assertInstanceOf('Crate\DBAL\Types\MapType', $columns['obj2']->gettype());
169 |
170 | $this->assertEquals("obj2['id']", strtolower($columns["obj2['id']"]->getname()));
171 | $this->assertInstanceOf('Doctrine\DBAL\Types\IntegerType', $columns["obj2['id']"]->gettype());
172 |
173 | $this->assertEquals("obj2['name']", strtolower($columns["obj2['name']"]->getname()));
174 | $this->assertInstanceOf('Doctrine\DBAL\Types\StringType', $columns["obj2['name']"]->gettype());
175 |
176 | $this->assertEquals('arr_float', strtolower($columns['arr_float']->getname()));
177 | $this->assertInstanceOf('Crate\DBAL\Types\ArrayType', $columns['arr_float']->gettype());
178 |
179 | $this->assertEquals('arr_str', strtolower($columns['arr_str']->getname()));
180 | $this->assertInstanceOf('Crate\DBAL\Types\ArrayType', $columns['arr_str']->gettype());
181 |
182 | $this->assertEquals('arr_obj', strtolower($columns['arr_obj']->getname()));
183 | $this->assertInstanceOf('Crate\DBAL\Types\ArrayType', $columns['arr_obj']->gettype());
184 | }
185 |
186 |
187 | public function testCreateSchema()
188 | {
189 | $this->createTestTable('test_table');
190 |
191 | $schema = $this->_sm->createSchema();
192 | $this->assertTrue($schema->hasTable('test_table'));
193 | }
194 |
195 | /**
196 | * @param string $name
197 | * @param array $data
198 | */
199 | protected function createTestTable($name = 'test_table', $data = array())
200 | {
201 | $options = array();
202 | if (isset($data['options'])) {
203 | $options = $data['options'];
204 | }
205 |
206 | $table = $this->getTestTable($name, $options);
207 | $this->_sm->dropAndCreateTable($table);
208 | }
209 |
210 | protected function getTestTable($name, $options=array())
211 | {
212 | $table = new Table($name, array(), array(), array(), false, $options);
213 | $table->setSchemaConfig($this->_sm->createSchemaConfig());
214 | $table->addColumn('id', 'integer', array('notnull' => true));
215 | $table->setPrimaryKey(array('id'));
216 | $table->addColumn('test', 'string', array('length' => 255));
217 | $table->addColumn('foreign_key_test', 'integer');
218 | return $table;
219 | }
220 |
221 | protected function getTestCompositeTable($name)
222 | {
223 | $table = new Table($name, array(), array(), array(), false, array());
224 | $table->setSchemaConfig($this->_sm->createSchemaConfig());
225 | $table->addColumn('id', 'integer', array('notnull' => true));
226 | $table->addColumn('other_id', 'integer', array('notnull' => true));
227 | $table->setPrimaryKey(array('id', 'other_id'));
228 | $table->addColumn('test', 'string', array('length' => 255));
229 | $table->addColumn('test_other', 'string', array('length' => 255));
230 | return $table;
231 | }
232 |
233 | protected function assertHasTable($tables, $tableName)
234 | {
235 | $foundTable = false;
236 | foreach ($tables AS $table) {
237 | $this->assertInstanceOf('Doctrine\DBAL\Schema\Table', $table, 'No Table instance was found in tables array.');
238 | if (strtolower($table->getName()) == 'list_tables_test_new_name') {
239 | $foundTable = true;
240 | }
241 | }
242 | $this->assertTrue($foundTable, "Could not find new table");
243 | }
244 |
245 | public function testListTableIndexes()
246 | {
247 | $table = $this->getTestCompositeTable('list_table_indexes_test');
248 |
249 | $this->_sm->dropAndCreateTable($table);
250 |
251 | $tableIndexes = $this->_sm->listTableIndexes('list_table_indexes_test');
252 |
253 | self::assertEquals(1, count($tableIndexes));
254 |
255 | self::assertArrayHasKey('primary', $tableIndexes, 'listTableIndexes() has to return a "primary" array key.');
256 | self::assertEquals(['id', 'other_id'], array_map('strtolower', $tableIndexes['primary']->getColumns()));
257 | self::assertTrue($tableIndexes['primary']->isUnique());
258 | self::assertTrue($tableIndexes['primary']->isPrimary());
259 | }
260 | }
261 |
--------------------------------------------------------------------------------
/test/Crate/Test/DBAL/Functional/TableOptionsTest.php:
--------------------------------------------------------------------------------
1 | _conn->getSchemaManager()->tablesExist("ddc1372_foobar")) {
38 | try {
39 | $sm = $this->_conn->getSchemaManager();
40 | $sm->dropTable('table_option_test');
41 | } catch(\Exception $e) {
42 | $this->fail($e->getMessage());
43 | }
44 | }
45 | }
46 |
47 | public function testAdditionalTableOptions()
48 | {
49 | $platform = $this->_conn->getDatabasePlatform();
50 |
51 | $options = [];
52 | $options['sharding_routing_column'] = 'id';
53 | $options['sharding_num_shards'] = 6;
54 | $options['partition_columns'] = ['parted', 'date'];
55 | $options['table_options'] = [];
56 | $options['table_options']['number_of_replicas'] = '0-2';
57 | $options['table_options']['write.wait_for_active_shards'] = 'ALL';
58 |
59 | $table = new Table('t1', [], [], [], 0, $options);
60 | $table->addColumn('id', 'integer');
61 | $table->addColumn('parted', 'integer');
62 | $table->addColumn('date', 'timestamp');
63 |
64 | $sql = $platform->getCreateTableSQL($table);
65 | $this->assertEquals(array(
66 | 'CREATE TABLE t1 (id INTEGER, parted INTEGER, date TIMESTAMP)'
67 | . ' CLUSTERED BY (id) INTO 6 SHARDS'
68 | . ' PARTITIONED BY (parted, date)'
69 | . ' WITH ("number_of_replicas" = \'0-2\', "write.wait_for_active_shards" = \'ALL\')')
70 | , $sql);
71 | }
72 |
73 | public function testGetAdditionalTableOptions()
74 | {
75 | $options = [];
76 | $options['sharding_routing_column'] = 'id';
77 | $options['sharding_num_shards'] = 6;
78 | $options['partition_columns'] = ['parted', 'date'];
79 | $options['table_options'] = [];
80 | $options['table_options']['number_of_replicas'] = '0-2';
81 | $options['table_options']['write.wait_for_active_shards'] = 'ALL';
82 |
83 | $table = new Table('table_option_test', [], [], [], 0, $options);
84 | $table->addColumn('id', 'integer');
85 | $table->addColumn('parted', 'integer');
86 | $table->addColumn('date', 'timestamp');
87 |
88 | $sm = $this->_conn->getSchemaManager();
89 | $sm->createTable($table);
90 |
91 | $schema = $sm->createSchema();
92 |
93 | $retrievedTable = $schema->getTable($table->getName());
94 | $options = $retrievedTable->getOptions();
95 |
96 | $this->assertEquals($options['sharding_routing_column'], 'id');
97 | $this->assertEquals($options['sharding_num_shards'], 6);
98 | $this->assertEquals($options['partition_columns'], ['parted', 'date']);
99 | $this->assertEquals($options['table_options']['number_of_replicas'], '0-2');
100 | $this->assertEquals($options['table_options']['write.wait_for_active_shards'], 'ALL');
101 | }
102 |
103 | public function testPartitionColumnsNotArray()
104 | {
105 | $platform = $this->_conn->getDatabasePlatform();
106 |
107 | $options = [];
108 | $options['partition_columns'] = 'parted';
109 | $table = new Table('t1', [], [], [], 0, $options);
110 | $table->addColumn('parted', 'integer');
111 |
112 | $this->expectException(InvalidArgumentException::class);
113 | $this->expectExceptionMessage("Expecting array type at 'partition_columns'");
114 | $platform->getCreateTableSQL($table);
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/test/Crate/Test/DBAL/Functional/TypeConversionTest.php:
--------------------------------------------------------------------------------
1 | platform = new CratePlatform();
40 | }
41 |
42 | public function testTimestampType()
43 | {
44 | $input = new \DateTime("2014-10-21 15:23:38");
45 |
46 | // datetimetz
47 | $type = Type::getType(Type::DATETIMETZ);
48 | $expected = $input->format('Y-m-d\TH:i:sO');
49 | $output = $type->convertToDatabaseValue($input, $this->platform);
50 | $this->assertEquals($output, $expected);
51 | $inputRestored = $type->convertToPHPValue($output, $this->platform);
52 | $this->assertEquals($inputRestored, $input);
53 | $inputRestored = $type->convertToPHPValue($input, $this->platform);
54 | $this->assertEquals($inputRestored, $input);
55 |
56 | // datetime
57 | $type = Type::getType(Type::DATETIME);
58 | $expected = $input->format('Y-m-d\TH:i:s');
59 | $output = $type->convertToDatabaseValue($input, $this->platform);
60 | $this->assertEquals($output, $expected);
61 | $inputRestored = $type->convertToPHPValue($output, $this->platform);
62 | $this->assertEquals($inputRestored, $input);
63 | $inputRestored = $type->convertToPHPValue($input, $this->platform);
64 | $this->assertEquals($inputRestored, $input);
65 |
66 | // date
67 | $type = Type::getType(Type::DATE);
68 | $expected = $input->format('Y-m-d\TH:i:s');
69 | $output = $type->convertToDatabaseValue($input, $this->platform);
70 | $this->assertEquals($output, $expected);
71 | $inputRestored = $type->convertToPHPValue($output, $this->platform);
72 | $this->assertEquals($inputRestored, $input);
73 | $inputRestored = $type->convertToPHPValue($input, $this->platform);
74 | $this->assertEquals($inputRestored, $input);
75 |
76 | // time
77 | $type = Type::getType(Type::TIME);
78 | $expected = $input->format('Y-m-d\TH:i:s');
79 | $output = $type->convertToDatabaseValue($input, $this->platform);
80 | $this->assertEquals($output, $expected);
81 | $inputRestored = $type->convertToPHPValue($output, $this->platform);
82 | $this->assertEquals($inputRestored, $input);
83 | $inputRestored = $type->convertToPHPValue($input, $this->platform);
84 | $this->assertEquals($inputRestored, $input);
85 |
86 | // timestamp
87 | $type = Type::getType(TimestampType::NAME);
88 | $expected = $input->format('U')*TimestampType::S_TO_MS;
89 | $output = $type->convertToDatabaseValue($input, $this->platform);
90 | $this->assertEquals($output, $expected);
91 | $inputRestored = $type->convertToPHPValue($output, $this->platform);
92 | $this->assertEquals($inputRestored, $input);
93 | $inputRestored = $type->convertToPHPValue($input, $this->platform);
94 | $this->assertEquals($inputRestored, $input);
95 | }
96 |
97 | public function testTimestampTypeNull()
98 | {
99 | $types = array(Type::getType(Type::DATETIMETZ),
100 | Type::getType(Type::DATETIME),
101 | Type::getType(Type::DATE),
102 | Type::getType(Type::TIME),
103 | Type::getType(TimestampType::NAME)
104 | );
105 | foreach ($types as $type) {
106 | // to DB value
107 | $value = $type->convertToDatabaseValue(null, $this->platform);
108 | $this->assertEquals($value, null);
109 |
110 | // to PHP value
111 | $value = $type->convertToPHPValue(null, $this->platform);
112 | $this->assertEquals($value, null);
113 | }
114 | }
115 |
116 | public function testMapType()
117 | {
118 | $type = Type::getType(MapType::NAME);
119 |
120 | // to DB value
121 | $output = $type->convertToDatabaseValue(array('foo'=>'bar'), $this->platform);
122 | $this->assertEquals($output, array('foo'=>'bar'));
123 |
124 | $output = $type->convertToDatabaseValue(array(), $this->platform);
125 | $this->assertEquals($output, array());
126 | }
127 |
128 | public function testMapTypeNullValue()
129 | {
130 | $type = Type::getType(MapType::NAME);
131 |
132 | // to DB value
133 | $output = $type->convertToDatabaseValue(null, $this->platform);
134 | $this->assertEquals($output, null);
135 | }
136 |
137 | public function testMapTypeInvalid()
138 | {
139 | $type = Type::getType(MapType::NAME);
140 |
141 | // to DB value
142 | $notAMap = array('foo', 'bar');
143 | $output = $type->convertToDatabaseValue($notAMap, $this->platform);
144 | $this->assertEquals($output, null);
145 |
146 | }
147 |
148 | public function testArrayType()
149 | {
150 | $type = Type::getType(ArrayType::NAME);
151 |
152 | // to DB value
153 | $output = $type->convertToDatabaseValue(array('foo', 'bar'), $this->platform);
154 | $this->assertEquals($output, array('foo', 'bar'));
155 |
156 | $output = $type->convertToDatabaseValue(array(), $this->platform);
157 | $this->assertEquals($output, array());
158 | }
159 |
160 | public function testArrayTypeNullValue()
161 | {
162 | $type = Type::getType(ArrayType::NAME);
163 |
164 | // to DB value
165 | $output = $type->convertToDatabaseValue(null, $this->platform);
166 | $this->assertEquals($output, null);
167 | }
168 |
169 | public function testArrayTypeInvalid()
170 | {
171 | $type = Type::getType(ArrayType::NAME);
172 |
173 | // to DB value
174 | $notAnArray = array('foo'=>'bar');
175 | $output = $type->convertToDatabaseValue($notAnArray, $this->platform);
176 | $this->assertEquals($output, null);
177 | }
178 |
179 | }
180 |
--------------------------------------------------------------------------------
/test/Crate/Test/DBAL/Functional/Types/MapTypeTest.php:
--------------------------------------------------------------------------------
1 | _conn->getDatabasePlatform();
37 |
38 | $table = new Table('items');
39 | $objDefinition = array(
40 | 'type' => MapType::STRICT,
41 | 'fields' => array(
42 | new Column('id', Type::getType(Type::INTEGER), array()),
43 | new Column('name', Type::getType(Type::STRING), array()),
44 | ),
45 | );
46 | $table->addColumn(
47 | 'object_column', MapType::NAME,
48 | array('platformOptions' => $objDefinition)
49 | );
50 |
51 | $createFlags = CratePlatform::CREATE_INDEXES|CratePlatform::CREATE_FOREIGNKEYS;
52 | $sql = $platform->getCreateTableSQL($table, $createFlags);
53 | $this->assertEquals(array('CREATE TABLE items (object_column OBJECT ( strict ) AS ( id INTEGER, name TEXT ))'), $sql);
54 | }
55 |
56 | }
--------------------------------------------------------------------------------
/test/Crate/Test/DBAL/Functional/WriteTest.php:
--------------------------------------------------------------------------------
1 | addColumn('test_int', Type::INTEGER);
44 | $table->addColumn('test_string', Type::STRING);
45 | $table->addColumn('test_float', Type::FLOAT);
46 | $table->addColumn('test_array', Type::TARRAY, array('columnDefinition'=>'ARRAY(STRING)'));
47 | $table->addColumn("test_map", MapType::NAME);
48 | $table->addColumn("test_bool", Type::BOOLEAN);
49 |
50 | $platformOptions = array(
51 | 'type' => MapType::STRICT,
52 | 'fields' => array(
53 | new Column('id', Type::getType(Type::INTEGER), array()),
54 | new Column('name', Type::getType(Type::STRING), array()),
55 | new Column('value', Type::getType(Type::FLOAT), array()),
56 | ),
57 | );
58 | $table->addColumn('test_obj', MapType::NAME, array('platformOptions'=>$platformOptions));
59 |
60 | $sm = $this->_conn->getSchemaManager();
61 | $sm->createTable($table);
62 | }
63 | }
64 |
65 | public function tearDown() : void
66 | {
67 | if (self::$generated === true) {
68 | $this->execute('drop table write_table');
69 | self::$generated = false;
70 | }
71 | }
72 |
73 |
74 | /**
75 | * @group DBAL-80
76 | */
77 | public function testExecuteUpdateFirstTypeIsNull()
78 | {
79 | $sql = "INSERT INTO write_table (test_string, test_int) VALUES (?, ?)";
80 | $this->_conn->executeUpdate($sql, array("text", 1111), array(null, PDO::PARAM_INT));
81 | $this->refresh('write_table');
82 |
83 | $sql = "SELECT test_obj, test_string, test_int FROM write_table WHERE test_string = ? AND test_int = ?";
84 | $this->assertEquals($this->_conn->fetchColumn($sql, array("text", 1111)), null);
85 | $this->assertEquals($this->_conn->fetchColumn($sql, array("text", 1111), 1), "text");
86 | $this->assertEquals($this->_conn->fetchColumn($sql, array("text", 1111), 2), 1111);
87 | }
88 |
89 | public function testExecuteUpdate()
90 | {
91 | $sql = "INSERT INTO write_table (test_int) VALUES ( " . $this->_conn->quote(1, PDO::PARAM_INT) . ")";
92 | $affected = $this->_conn->executeUpdate($sql);
93 |
94 | $this->assertEquals(1, $affected, "executeUpdate() should return the number of affected rows!");
95 | }
96 |
97 | public function testExecuteUpdateWithTypes()
98 | {
99 | $sql = "INSERT INTO write_table (test_int, test_string) VALUES (?, ?)";
100 | $affected = $this->_conn->executeUpdate($sql, array(1, 'foo'), array(\PDO::PARAM_INT, \PDO::PARAM_STR));
101 |
102 | $this->assertEquals(1, $affected, "executeUpdate() should return the number of affected rows!");
103 | }
104 |
105 | public function testPrepareRowCountReturnsAffectedRows()
106 | {
107 | $sql = "INSERT INTO write_table (test_int, test_string) VALUES (?, ?)";
108 | $stmt = $this->_conn->prepare($sql);
109 |
110 | $stmt->bindValue(1, 1);
111 | $stmt->bindValue(2, "foo");
112 | $stmt->execute();
113 |
114 | $this->assertEquals(1, $stmt->rowCount());
115 | }
116 |
117 | public function testPrepareWithPdoTypes()
118 | {
119 | $sql = "INSERT INTO write_table (test_int, test_string) VALUES (?, ?)";
120 | $stmt = $this->_conn->prepare($sql);
121 |
122 | $stmt->bindValue(1, 1, \PDO::PARAM_INT);
123 | $stmt->bindValue(2, "foo", \PDO::PARAM_STR);
124 | $stmt->execute();
125 |
126 | $this->assertEquals(1, $stmt->rowCount());
127 | }
128 |
129 | public function testPrepareWithDbalTypes()
130 | {
131 | $sql = "INSERT INTO write_table (test_int, test_string, test_float, test_obj) VALUES (?, ?, ?, ?)";
132 | $stmt = $this->_conn->prepare($sql);
133 |
134 | $stmt->bindValue(1, 1, Type::getType('integer'));
135 | $stmt->bindValue(2, "foo", Type::getType('string'));
136 | $stmt->bindValue(3, 3.141592, Type::getType('float'));
137 | $stmt->bindValue(4, array('id'=>1, 'name'=>'christian', 'value'=>1.234), Type::getType('map'));
138 | $stmt->execute();
139 |
140 | $this->assertEquals(1, $stmt->rowCount());
141 | }
142 |
143 | public function testPrepareWithDbalTypeNames()
144 | {
145 | $sql = "INSERT INTO write_table (test_int, test_string, test_float, test_map, test_bool) VALUES (?, ?, ?, ?, ?)";
146 | $stmt = $this->_conn->prepare($sql);
147 |
148 | $stmt->bindValue(1, 1, 'integer');
149 | $stmt->bindValue(2, "foo", 'string');
150 | $stmt->bindValue(3, 3.141592, 'float');
151 | $stmt->bindValue(4, array('id'=>1, 'name'=>'christian', 'value'=>1.234), 'map');
152 | $stmt->bindValue(5, true, 'boolean');
153 | $stmt->execute();
154 |
155 | $this->assertEquals(1, $stmt->rowCount());
156 | }
157 |
158 | public function insertRows()
159 | {
160 | $this->assertEquals(1, $this->_conn->insert('write_table', array(
161 | 'test_int' => 1,
162 | 'test_string' => 'foo',
163 | 'test_float' => 1.234,
164 | 'test_array' => array('foo','bar'),
165 | 'test_obj' => array('id'=>1, 'name'=>'foo', 'value'=>1.234),
166 | ), array('integer','string','float','array','map')));
167 | $this->assertEquals(1, $this->_conn->insert('write_table', array(
168 | 'test_int' => 2,
169 | 'test_string' => 'bar',
170 | 'test_float' => 2.345,
171 | 'test_array' => array('bar','foo'),
172 | 'test_obj' => array('id'=>2, 'name'=>'bar', 'value'=>2.345),
173 | ), array('integer','string','float','array','map')));
174 |
175 | $this->refresh('write_table');
176 | }
177 |
178 | public function testInsert()
179 | {
180 | $this->insertRows();
181 | }
182 |
183 | public function testDelete()
184 | {
185 | $this->insertRows();
186 |
187 | $this->assertEquals(1, $this->_conn->delete('write_table', array('test_int' => 2)));
188 | $this->refresh('write_table');
189 | $this->assertEquals(1, count($this->_conn->fetchAll('SELECT * FROM write_table')));
190 |
191 | $this->assertEquals(1, $this->_conn->delete('write_table', array('test_int' => 1)));
192 | $this->refresh('write_table');
193 | $this->assertEquals(0, count($this->_conn->fetchAll('SELECT * FROM write_table')));
194 | }
195 |
196 | public function testUpdate()
197 | {
198 | $this->insertRows();
199 |
200 | $this->assertEquals(1, $this->_conn->update('write_table', array('test_string' => 'bar'), array('test_string' => 'foo')));
201 | $this->refresh('write_table');
202 | $this->assertEquals(2, $this->_conn->update('write_table', array('test_string' => 'baz'), array('test_string' => 'bar')));
203 | $this->refresh('write_table');
204 | $this->assertEquals(0, $this->_conn->update('write_table', array('test_string' => 'baz'), array('test_string' => 'bar')));
205 | }
206 |
207 | }
208 |
--------------------------------------------------------------------------------
/test/Crate/Test/DBAL/PDOCrate/DriverTest.php:
--------------------------------------------------------------------------------
1 | assertInstanceOf(CratePlatform::class, $driver->createDatabasePlatformForVersion("0.56.6"));
39 |
40 | }
41 |
42 | public function testCreatePlatformForVersionLess_4()
43 | {
44 | $driver = new Driver();
45 | $this->assertInstanceOf(CratePlatform1::class, $driver->createDatabasePlatformForVersion("3.2"));
46 |
47 | }
48 |
49 | public function testCreatePlatformForVersionGreaterEquals_4()
50 | {
51 | $driver = new Driver();
52 | $this->assertInstanceOf(CratePlatform4::class, $driver->createDatabasePlatformForVersion("4.0.0"));
53 | }
54 | }
--------------------------------------------------------------------------------
/test/Crate/Test/DBAL/Platforms/CratePlatformTest.php:
--------------------------------------------------------------------------------
1 | createDatabasePlatformForVersion(self::CRATE_TEST_VERSION);
48 | }
49 |
50 | public function getGenerateTableSql() : string
51 | {
52 | return 'CREATE TABLE test (id INTEGER, test TEXT, PRIMARY KEY(id))';
53 | }
54 |
55 | public function getGenerateTableWithMultiColumnUniqueIndexSql() : array
56 | {
57 | }
58 |
59 | public function getGenerateTableWithMultiColumnIndexSql()
60 | {
61 | return array(
62 | 'CREATE TABLE test (foo TEXT, bar TEXT, ' .
63 | 'INDEX IDX_D87F7E0C8C73652176FF8CAA USING FULLTEXT (foo, bar))'
64 | );
65 | }
66 |
67 | public function getGenerateIndexSql() : string
68 | {
69 | $this->markTestSkipped('Platform does not support CREATE INDEX.');
70 | }
71 |
72 | public function getGenerateUniqueIndexSql() : string
73 | {
74 | $this->markTestSkipped('Platform does not support CREATE UNIQUE INDEX.');
75 | }
76 |
77 | public function testGeneratesForeignKeyCreationSql() : void
78 | {
79 | $this->markTestSkipped('Platform does not support FOREIGN KEY constraints.');
80 | }
81 |
82 | public function getGenerateForeignKeySql() : string
83 | {
84 | $this->markTestSkipped('Platform does not support ADD FOREIGN KEY.');
85 | }
86 |
87 | /**
88 | * @param mixed[] $column
89 | *
90 | * @group DBAL-1082
91 | * @dataProvider getGeneratesDecimalTypeDeclarationSQL
92 | */
93 | public function testGeneratesDecimalTypeDeclarationSQL(array $column, $expectedSql) : void
94 | {
95 | $this->markTestSkipped('Platform does not support any decleration of datatype DECIMAL.');
96 | }
97 |
98 | public function getGenerateAlterTableSql() : array
99 | {
100 | return array(
101 | 'ALTER TABLE mytable ADD quota INTEGER',
102 | );
103 | }
104 |
105 | public function testAlterTableChangeQuotedColumn() : void
106 | {
107 | $this->markTestSkipped('Platform does not support ALTER TABLE.');
108 | }
109 |
110 | protected function getQuotedColumnInPrimaryKeySQL() : array
111 | {
112 | return array(
113 | 'CREATE TABLE "quoted" ("create" TEXT, PRIMARY KEY("create"))',
114 | );
115 | }
116 |
117 | protected function getQuotedColumnInIndexSQL() : array
118 | {
119 | return array(
120 | 'CREATE TABLE "quoted" ("create" TEXT, ' .
121 | 'INDEX IDX_22660D028FD6E0FB USING FULLTEXT ("create")' .
122 | ')'
123 | );
124 | }
125 |
126 | protected function getQuotedNameInIndexSQL() : array
127 | {
128 | return array(
129 | 'CREATE TABLE test (column1 TEXT, INDEX key USING FULLTEXT (column1))'
130 | );
131 | }
132 |
133 | /**
134 | * @group DBAL-374
135 | */
136 | public function testQuotedColumnInForeignKeyPropagation() : void
137 | {
138 | $this->markTestSkipped('Platform does not support ADD FOREIGN KEY.');
139 | }
140 |
141 | protected function getQuotedColumnInForeignKeySQL() : array {}
142 |
143 | protected function getQuotesReservedKeywordInUniqueConstraintDeclarationSQL() : string
144 | {
145 | return 'CONSTRAINT "select" UNIQUE (foo)';
146 | }
147 |
148 | protected function getQuotesReservedKeywordInIndexDeclarationSQL() : string
149 | {
150 | return 'INDEX "select" USING FULLTEXT (foo)';
151 | }
152 |
153 | /**
154 | * @group DBAL-835
155 | */
156 | public function testQuotesAlterTableRenameColumn() : void
157 | {
158 | $this->markTestSkipped('Platform does not support ALTER TABLE.');
159 | }
160 |
161 | protected function getQuotedAlterTableRenameColumnSQL() : array {}
162 |
163 | /**
164 | * @group DBAL-835
165 | */
166 | public function testQuotesAlterTableChangeColumnLength() : void
167 | {
168 | $this->markTestSkipped('Platform does not support ALTER TABLE.');
169 | }
170 |
171 | protected function getQuotedAlterTableChangeColumnLengthSQL() : array {}
172 |
173 | /**
174 | * @group DBAL-807
175 | */
176 | public function testQuotesAlterTableRenameIndexInSchema() : void
177 | {
178 | $this->markTestSkipped('Platform does not support ALTER TABLE.');
179 | }
180 |
181 | protected function getCommentOnColumnSQL() : array
182 | {
183 | return array(
184 | "COMMENT ON COLUMN foo.bar IS 'comment'",
185 | "COMMENT ON COLUMN \"Foo\".\"BAR\" IS 'comment'",
186 | "COMMENT ON COLUMN \"select\".\"from\" IS 'comment'",
187 | );
188 | }
189 |
190 | /**
191 | * @group DBAL-1010
192 | */
193 | public function testGeneratesAlterTableRenameColumnSQL() : void
194 | {
195 | $this->markTestSkipped('Platform does not support ALTER TABLE.');
196 | }
197 |
198 | public function getAlterTableRenameColumnSQL() : array {}
199 |
200 | /**
201 | * @group DBAL-1016
202 | */
203 | public function testQuotesTableIdentifiersInAlterTableSQL() : void
204 | {
205 | $this->markTestSkipped('Platform does not support ALTER TABLE.');
206 | }
207 |
208 | protected function getQuotesTableIdentifiersInAlterTableSQL() : array {}
209 |
210 | /**
211 | * @group DBAL-1062
212 | */
213 | public function testGeneratesAlterTableRenameIndexUsedByForeignKeySQL() : void
214 | {
215 | $this->markTestSkipped('Platform does not support ALTER TABLE.');
216 | }
217 |
218 | protected function getGeneratesAlterTableRenameIndexUsedByForeignKeySQL() : array {}
219 |
220 | /**
221 | * @group DBAL-1090
222 | */
223 | public function testAlterStringToFixedString() : void
224 | {
225 | $this->markTestSkipped('Platform does not support ALTER TABLE.');
226 | }
227 |
228 | protected function getAlterStringToFixedStringSQL() : array {}
229 |
230 | public function testGenerateSubstrExpression()
231 | {
232 | $this->assertEquals($this->platform->getSubstringExpression('col', 0), "SUBSTR(col, 0)");
233 | $this->assertEquals($this->platform->getSubstringExpression('col', 1, 2), "SUBSTR(col, 1, 2)");
234 | }
235 |
236 | public function testGenerateNowExpression()
237 | {
238 | $this->expectException(DBALException::class);
239 | $this->expectExceptionMessage('Operation \'Crate\DBAL\Platforms\CratePlatform::getNowExpression\' is not supported by platform.');
240 | $this->platform->getNowExpression();
241 | }
242 |
243 | public function testGenerateRegexExpression()
244 | {
245 | $this->assertEquals($this->platform->getRegexpExpression(), "LIKE");
246 | }
247 |
248 | public function testGenerateDateDiffExpression()
249 | {
250 | $this->expectException(DBALException::class);
251 | $this->expectExceptionMessage('Operation \'Crate\DBAL\Platforms\CratePlatform::getDateDiffExpression\' is not supported by platform.');
252 |
253 | $this->platform->getDateDiffExpression('2014-10-10 10:10:10', '2014-10-20 20:20:20');
254 | }
255 |
256 | public function testCreateDatabases()
257 | {
258 | $this->expectException(DBALException::class);
259 | $this->expectExceptionMessage('Operation \'Crate\DBAL\Platforms\CratePlatform::getCreateDatabaseSQL\' is not supported by platform.');
260 |
261 | $this->platform->getCreateDatabaseSQL('foo');
262 | }
263 |
264 | public function testListDatabases()
265 | {
266 | $this->expectException(DBALException::class);
267 | $this->expectExceptionMessage('Operation \'Crate\DBAL\Platforms\CratePlatform::getListDatabasesSQL\' is not supported by platform.');
268 |
269 | $this->platform->getListDatabasesSQL();
270 | }
271 |
272 | public function testDropDatabases()
273 | {
274 | $this->expectException(DBALException::class);
275 | $this->expectExceptionMessage('Operation \'Crate\DBAL\Platforms\CratePlatform::getDropDatabaseSQL\' is not supported by platform.');
276 |
277 | $this->platform->getDropDatabaseSQL('foo');
278 | }
279 |
280 | public function testGenerateBlobTypeGeneration()
281 | {
282 | $this->expectException(DBALException::class);
283 | $this->expectExceptionMessage('Operation \'Crate\DBAL\Platforms\CratePlatform::getBlobTypeDeclarationSQL\' is not supported by platform.');
284 |
285 | $this->platform->getBlobTypeDeclarationSQL(array());
286 | }
287 |
288 | public function testTruncateTableSQL()
289 | {
290 | $this->expectException(DBALException::class);
291 |
292 | $this->platform->getTruncateTableSQL('foo');
293 | }
294 |
295 | public function testReadLockSQL()
296 | {
297 | $this->expectException(DBALException::class);
298 |
299 | $this->platform->getReadLockSQL();
300 | }
301 |
302 | public function testConvertBooleans()
303 | {
304 | $this->assertEquals($this->platform->convertBooleans(false), 'false');
305 | $this->assertEquals($this->platform->convertBooleans(true), 'true');
306 |
307 | $this->assertEquals($this->platform->convertBooleans(0), 'false');
308 | $this->assertEquals($this->platform->convertBooleans(1), 'true');
309 |
310 | $this->assertEquals($this->platform->convertBooleans(array(true, 1, false, 0)),
311 | array('true', 'true', 'false', 'false'));
312 | }
313 |
314 | public function testSQLResultCasting()
315 | {
316 | $this->assertEquals($this->platform->getSQLResultCasing("LoWeRcAsE"), 'lowercase');
317 | }
318 |
319 | public function testGenerateTableSqlWithoutColumns()
320 | {
321 | $this->expectException(DBALException::class);
322 | $this->expectExceptionMessage('No columns specified for table foo');
323 |
324 |
325 | $table = new Table("foo");
326 | $this->assertEquals($this->platform->getCreateTableSQL($table)[0],
327 | 'CREATE TABLE foo');
328 | }
329 |
330 | public function testGenerateTableSql()
331 | {
332 | $table = new Table("foo");
333 | $table->addColumn('col_bool', 'boolean');
334 | $table->addColumn('col_int', 'integer');
335 | $table->addColumn('col_float', 'float');
336 | $table->addColumn('col_timestamp', 'timestamp');
337 | $table->addColumn('col_datetimetz', 'datetimetz');
338 | $table->addColumn('col_datetime', 'datetime');
339 | $table->addColumn('col_date', 'date');
340 | $table->addColumn('col_time', 'time');
341 | $table->addColumn('col_array', 'array');
342 | $table->addColumn('col_object', 'map');
343 | $this->assertEquals($this->platform->getCreateTableSQL($table)[0],
344 | 'CREATE TABLE foo (col_bool BOOLEAN, col_int INTEGER, col_float DOUBLE PRECISION, col_timestamp TIMESTAMP, col_datetimetz TIMESTAMP, col_datetime TIMESTAMP, col_date TIMESTAMP, col_time TIMESTAMP, col_array ARRAY ( TEXT ), col_object OBJECT ( dynamic ))');
345 | }
346 |
347 | public function testUnsupportedUniqueIndexConstraint()
348 | {
349 | $this->expectException(DBALException::class);
350 | $this->expectExceptionMessage("Unique constraints are not supported. Use `primary key` instead");
351 |
352 | $table = new Table("foo");
353 | $table->addColumn("unique_string", "string");
354 | $table->addUniqueIndex(array("unique_string"));
355 | $this->platform->getCreateTableSQL($table);
356 | }
357 |
358 | public function testUniqueConstraintInCustomSchemaOptions()
359 | {
360 | $this->expectException(DBALException::class);
361 | $this->expectExceptionMessage("Unique constraints are not supported. Use `primary key` instead");
362 |
363 | $table = new Table("foo");
364 | $table->addColumn("unique_string", "string")->setCustomSchemaOption("unique", true);
365 | $this->platform->getCreateTableSQL($table);
366 | }
367 |
368 | public function testGeneratesTableAlterationSql() : void
369 | {
370 | $expectedSql = $this->getGenerateAlterTableSql();
371 |
372 | $tableDiff = new TableDiff('mytable');
373 | $tableDiff->addedColumns['quota'] = new \Doctrine\DBAL\Schema\Column('quota', \Doctrine\DBAL\Types\Type::getType('integer'), array('notnull' => false));
374 |
375 | $sql = $this->platform->getAlterTableSQL($tableDiff);
376 |
377 | $this->assertEquals($expectedSql, $sql);
378 | }
379 |
380 | public function testGetAlterTableSqlDispatchEvent() : void
381 | {
382 | $events = array(
383 | 'onSchemaAlterTableAddColumn'
384 | );
385 |
386 | $listenerMock = $this->getMockBuilder('GetAlterTableSqlDispatchEvenListener')
387 | ->setMethods($events)
388 | ->getMock();
389 | $listenerMock
390 | ->expects($this->once())
391 | ->method('onSchemaAlterTableAddColumn');
392 |
393 | $eventManager = new EventManager();
394 | $events = array(
395 | Events::onSchemaAlterTableAddColumn,
396 | );
397 | $eventManager->addEventListener($events, $listenerMock);
398 |
399 | $this->platform->setEventManager($eventManager);
400 |
401 | $tableDiff = new TableDiff('mytable');
402 | $tableDiff->addedColumns['added'] = new \Doctrine\DBAL\Schema\Column('added', \Doctrine\DBAL\Types\Type::getType('integer'), array());
403 |
404 | $this->platform->getAlterTableSQL($tableDiff);
405 | }
406 |
407 | public function testGenerateTableWithMultiColumnUniqueIndex() : void
408 | {
409 | $table = new Table('test');
410 | $table->addColumn('foo', 'string', array('notnull' => false, 'length' => 255));
411 | $table->addColumn('bar', 'string', array('notnull' => false, 'length' => 255));
412 | $table->addUniqueIndex(array("foo", "bar"));
413 |
414 | $this->expectException(DBALException::class);
415 | $this->expectExceptionMessage('Operation \'Unique constraints are not supported. Use `primary key` instead\' is not supported by platform.');
416 |
417 | $this->platform->getCreateTableSQL($table);
418 | }
419 |
420 | public function testGenerateTableWithMultiColumnIndex()
421 | {
422 | $table = new Table('test');
423 | $table->addColumn('foo', 'string', array('notnull' => false, 'length' => 255));
424 | $table->addColumn('bar', 'string', array('notnull' => false, 'length' => 255));
425 | $table->addIndex(array("foo", "bar"));
426 |
427 | $sql = $this->platform->getCreateTableSQL($table);
428 | $this->assertEquals($this->getGenerateTableWithMultiColumnIndexSql(), $sql);
429 | }
430 |
431 | /**
432 | * @param Column $column
433 | */
434 | private function getSQLDeclaration($column)
435 | {
436 | $p = $this->platform;
437 | return $p->getColumnDeclarationSQL($column->getName(), CratePlatform::prepareColumnData($p, $column));
438 | }
439 |
440 | public function testGenerateObjectSQLDeclaration()
441 | {
442 |
443 | $column = new Column('obj', Type::getType(MapType::NAME));
444 | $this->assertEquals($this->getSQLDeclaration($column), 'obj OBJECT ( dynamic )');
445 |
446 | $column = new Column('obj', Type::getType(MapType::NAME),
447 | array('platformOptions'=>array('type'=>MapType::STRICT)));
448 | $this->assertEquals($this->getSQLDeclaration($column), 'obj OBJECT ( strict )');
449 |
450 | $column = new Column('obj', Type::getType(MapType::NAME),
451 | array('platformOptions'=>array('type'=>MapType::IGNORED, 'fields'=>array())));
452 | $this->assertEquals($this->getSQLDeclaration($column), 'obj OBJECT ( ignored )');
453 |
454 | $column = new Column('obj', Type::getType(MapType::NAME),
455 | array('platformOptions'=>array(
456 | 'type'=>MapType::STRICT,
457 | 'fields'=>array(
458 | new Column('num', Type::getType(Type::INTEGER)),
459 | new Column('text', Type::getType(Type::STRING)),
460 | new Column('arr', Type::getType(ArrayType::NAME)),
461 | new Column('obj', Type::getType(MapType::NAME)),
462 | ),
463 | )));
464 | $this->assertEquals($this->getSQLDeclaration($column), 'obj OBJECT ( strict ) AS ( num INTEGER, text TEXT, arr ARRAY ( TEXT ), obj OBJECT ( dynamic ) )');
465 |
466 | }
467 |
468 | public function testGenerateArraySQLDeclaration()
469 | {
470 | $column = new Column('arr', Type::getType(ArrayType::NAME));
471 | $this->assertEquals($this->getSQLDeclaration($column), 'arr ARRAY ( TEXT )');
472 |
473 | $column = new Column('arr', Type::getType(ArrayType::NAME),
474 | array('platformOptions'=> array('type'=>Type::INTEGER)));
475 | $this->assertEquals($this->getSQLDeclaration($column), 'arr ARRAY ( INTEGER )');
476 |
477 | }
478 |
479 | public function testPlatformSupport() {
480 | $this->assertFalse($this->platform->supportsSequences());
481 | $this->assertFalse($this->platform->supportsSchemas());
482 | $this->assertTrue($this->platform->supportsIdentityColumns());
483 | $this->assertFalse($this->platform->supportsIndexes());
484 | $this->assertFalse($this->platform->supportsCommentOnStatement());
485 | $this->assertFalse($this->platform->supportsForeignKeyConstraints());
486 | $this->assertFalse($this->platform->supportsForeignKeyOnUpdate());
487 | $this->assertFalse($this->platform->supportsViews());
488 | $this->assertFalse($this->platform->prefersSequences());
489 | }
490 |
491 | /**
492 | * @return string
493 | */
494 | protected function getQuotesReservedKeywordInTruncateTableSQL() : string
495 | {
496 | $this->markTestSkipped('Platform does not support TRUNCATE TABLE.');
497 | }
498 |
499 | /**
500 | * @return array}>
501 | */
502 | public function asciiStringSqlDeclarationDataProvider() : array
503 | {
504 | return [
505 | ['TEXT', ['length' => 12]],
506 | ['TEXT', ['length' => 12, 'fixed' => true]],
507 | ];
508 | }
509 | }
510 |
--------------------------------------------------------------------------------