├── .github ├── dependabot.yml └── workflows │ ├── docs.yml │ └── tests.yml ├── .gitignore ├── .gitmodules ├── .mailmap ├── .mergify.yml ├── .readthedocs.yml ├── CHANGES.txt ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.rst ├── DEVELOP.rst ├── LICENSE ├── NOTICE ├── README.rst ├── build.gradle ├── codeStyle.xml ├── copyright.xml ├── devtools └── create_tag.sh ├── docs ├── .gitignore ├── Makefile ├── _extra │ └── robots.txt ├── build.json ├── conf.py ├── connect.rst ├── data-types.rst ├── docutils.conf ├── getting-started.rst ├── index.rst ├── internals.rst └── requirements.txt ├── driver ├── main │ ├── java │ │ └── io │ │ │ └── crate │ │ │ └── client │ │ │ └── jdbc │ │ │ ├── CrateDriver.java │ │ │ └── CrateDriverVersion.java │ └── resources │ │ └── META-INF │ │ ├── LICENSE │ │ └── services │ │ └── java.sql.Driver └── test │ └── java │ └── io │ └── crate │ └── client │ └── jdbc │ ├── CrateDriverTest.java │ ├── PgCrateVersionTest.java │ └── integrationtests │ ├── BaseIntegrationTest.java │ ├── ByPassSpecSettingITest.java │ ├── ConnectionITest.java │ ├── DriverITest.java │ ├── FetchSizeITest.java │ ├── MetaDataITest.java │ ├── RowCountITest.java │ ├── TypesITest.java │ └── UnsupportedFeaturesITest.java ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── pg ├── build.gradle └── jre8.properties └── settings.gradle /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | 9 | - package-ecosystem: "gradle" 10 | directory: "/" 11 | schedule: 12 | interval: "monthly" 13 | 14 | - package-ecosystem: "github-actions" 15 | directory: "/" 16 | schedule: 17 | interval: "monthly" 18 | -------------------------------------------------------------------------------- /.github/workflows/docs.yml: -------------------------------------------------------------------------------- 1 | name: Documentation 2 | 3 | on: 4 | pull_request: ~ 5 | push: 6 | branches: 7 | - master 8 | 9 | # Allow job to be triggered manually. 10 | workflow_dispatch: 11 | 12 | # Run each night. 13 | schedule: 14 | - cron: '0 7 * * *' 15 | 16 | # Cancel in-progress jobs when pushing to the same branch. 17 | concurrency: 18 | cancel-in-progress: true 19 | group: ${{ github.workflow }}-${{ github.ref }} 20 | 21 | jobs: 22 | documentation: 23 | 24 | name: Build docs on ${{ matrix.os }} 25 | runs-on: ${{ matrix.os }} 26 | 27 | strategy: 28 | matrix: 29 | os: [ubuntu-latest, macos-latest] 30 | 31 | steps: 32 | - name: Acquire sources 33 | uses: actions/checkout@v4 34 | 35 | - name: Set up Python 36 | uses: actions/setup-python@v5 37 | with: 38 | python-version: '3.11' 39 | 40 | - name: Validate documentation 41 | run: | 42 | cd docs && make check 43 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: 4 | pull_request: ~ 5 | push: 6 | branches: 7 | - master 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 | test: 19 | 20 | name: "Test Java: ${{ matrix.java-version }} 21 | CrateDB: ${{ matrix.cratedb-version }} 22 | on ${{ matrix.os }}" 23 | runs-on: ${{ matrix.os }} 24 | strategy: 25 | fail-fast: false 26 | matrix: 27 | os: ['ubuntu-latest'] 28 | java-version: ['11'] 29 | cratedb-version: [ 30 | '4.8.4', 31 | '5.10.3', 32 | ] 33 | 34 | env: 35 | JAVA_VERSION: ${{ matrix.java-version }} 36 | CRATE_VERSION: ${{ matrix.cratedb-version }} 37 | 38 | steps: 39 | 40 | - name: Acquire sources 41 | uses: actions/checkout@v4 42 | with: 43 | submodules: 'recursive' 44 | 45 | - name: Setup Java 46 | uses: actions/setup-java@v4 47 | with: 48 | distribution: 'temurin' 49 | java-version: '${{ matrix.java-version }}' 50 | cache: 'gradle' 51 | 52 | - name: Run gradle test 53 | uses: eskatos/gradle-command-action@v3 54 | with: 55 | arguments: test 56 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .classpath/ 2 | .DS_Store 3 | .gradle/ 4 | .idea/ 5 | .project/ 6 | .settings/ 7 | *.iml 8 | *.ipr 9 | *.iws 10 | *~ 11 | *build/ 12 | downloads/ 13 | out/ 14 | parts/ 15 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "pg/upstream"] 2 | path = pg/upstream 3 | url = https://github.com/crate/pgjdbc 4 | -------------------------------------------------------------------------------- /.mailmap: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Bernd Dorn 8 | Bernhard Kuzel 9 | Lukas Ender 10 | Mathias Fussenegger 11 | Mathias Fussenegger 12 | Philipp Bogensberger -------------------------------------------------------------------------------- /.mergify.yml: -------------------------------------------------------------------------------- 1 | queue_rules: 2 | - name: default 3 | queue_conditions: 4 | - label=ready-to-merge 5 | - '#approved-reviews-by>=1' 6 | - status-success~=^Test Java 7 | - status-success=docs/readthedocs.org:crate-jdbc 8 | - status-success=verification/cla-signed 9 | merge_conditions: 10 | - check-success~=^Test Java 11 | - check-success=docs/readthedocs.org:crate-jdbc 12 | - check-success=verification/cla-signed 13 | merge_method: rebase 14 | 15 | pull_request_rules: 16 | - name: automatic merge 17 | conditions: [] 18 | actions: 19 | queue: 20 | -------------------------------------------------------------------------------- /.readthedocs.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | build: 4 | os: "ubuntu-22.04" 5 | tools: 6 | python: "3.11" 7 | 8 | sphinx: 9 | builder: html 10 | configuration: docs/conf.py 11 | fail_on_warning: true 12 | 13 | python: 14 | install: 15 | - requirements: docs/requirements.txt 16 | -------------------------------------------------------------------------------- /CHANGES.txt: -------------------------------------------------------------------------------- 1 | ================================== 2 | Changes for Crate Data JDBC Client 3 | ================================== 4 | 5 | Unreleased 6 | ========== 7 | 8 | - Bumped the required JRE version to 11 9 | 10 | 2023/04/18 2.7.0 11 | ================ 12 | 13 | - Changed ``getPrimaryKeys()`` SQL stmt to use the table schema as the schema 14 | instead of the table catalog. This fixes compatibility with CrateDB >= 5.1.0 15 | as all catalog fields at the ``information_schema.tables`` schema expose now 16 | the correct catalog value (``crate``) instead of the table schema. 17 | 18 | - Migrated from Bintray to Maven Central. All new releases to go to Maven Central 19 | from now on. 20 | 21 | 2019/07/02 2.6.0 22 | ================ 23 | 24 | - Added compatibility for column type changes of 25 | ``information_schema.columns.is_generated`` on CrateDB >= 4.0.0 26 | 27 | 2018/12/06 2.5.1 28 | ================ 29 | 30 | - Fixed support for negative row counts which was removed by 2.5.0. 31 | 32 | 2018/11/30 2.5.0 33 | ================ 34 | 35 | - BREAKING: 36 | 37 | - By default, SSL verification is now handled according to ``libpq`` (see 38 | https://www.postgresql.org/docs/10/libpq-ssl.html) instead of using JAVA's 39 | default keystore handler. To still use a key/truststore, the ``sslfactory`` 40 | must be changed via properties to 41 | ``io.crate.shade.org.postgresql.ssl.DefaultJavaSSLFactory``. 42 | 43 | - The servers's row count of non-DDL statements will be returned instead of 0. 44 | 45 | - Added compatibility with JDK 11. 46 | 47 | - Changed minimum compatibility to JDK 8. 48 | 49 | 2018/07/19 2.4.0 50 | ================ 51 | 52 | - Changed the default value of the connection property ``loadBalanceHosts`` to 53 | ``true``, which will randomize the order in which the client tries to connect 54 | to the given CrateDB hosts. 55 | 56 | 2018/07/04 2.3.1 57 | ================ 58 | 59 | - Register driver class correctly so it does not require explicit 60 | initialization. This fixes problems with some third-party connection pooling 61 | tools. 62 | 63 | - Updated ``getTables()`` method in DatabaseMetaData to only return tables but 64 | not views with CrateBD versions greater than ``2.3.x``. 65 | 66 | 2018/03/22 2.3.0 67 | ================ 68 | 69 | - Updated ``getPrimaryKeys()`` method in DatabaseMetaData to work correctly 70 | with CrateDB 2.3.0 and newer. 71 | 72 | 2017/08/18 2.2.0 73 | ================ 74 | 75 | - Getting table/column metadata now retrieves the information from CrateDB's 76 | ``information_schema.tables`` and ``information_schema.columns`` tables 77 | for all SQL99 compliant fields. 78 | 79 | - Changed the assumeMinServerVersion default to "9.5", because CrateDB 80 | emulates Postgres version 9.5. 81 | This change eliminates initial SET SESSION statements which are ignored 82 | on the server-side anyway. 83 | 84 | - BREAKING: 85 | 86 | - Strict mode: The driver will no longer report that transactions are 87 | supported. The default transaction isolation is ``TRANSACTION_NONE`` 88 | 89 | - Strict mode: Disabled read-only connections. 90 | 91 | 2017/04/27 2.1.7 92 | ================ 93 | 94 | - Fix: Unsupported DatabaseMetaData methods returned a row with all values set 95 | to ``null`` instead of an empty result with no rows at all. 96 | 97 | 2017/03/03 2.1.6 98 | ================ 99 | 100 | - Fix: Also shade ``org.apache`` packages in standalone jar to prevent 101 | collisions. 102 | 103 | 2017/02/01 2.1.5 104 | ================ 105 | 106 | - Allow setting autocommit to false in non-strict mode. 107 | Autocommit must be false otherwise ``setFetchSize()`` on the statement does 108 | not have any effect and all rows are fetched at once. 109 | 110 | 2017/01/20 2.1.4 111 | ================ 112 | 113 | - Re-implemented Connection#getMoreResults() method which is used by 3rd party 114 | application to check whether more than one ResultSet is returned. 115 | Since CrateDB does not support multiple results, this method will always 116 | return false. 117 | 118 | 2017/01/09 2.1.3 119 | ================ 120 | 121 | - Replace only first occurrence of ``crate`` in connection string (as part of 122 | the protocol) when passed to PostgreSQL driver ``connect()`` implementation. 123 | This could have caused a connection error in case ``crate`` was part of the 124 | hostname. 125 | 126 | 2016/12/16 2.1.2 127 | ================ 128 | 129 | - Fix: Do not allow connection strings that start with ``postgresql://`` or 130 | ``jdbc:postgresql://`` 131 | This is important if you use both the PostgreSQL and CrateDB JDBC driver in 132 | the same application. 133 | 134 | 2016/11/24 2.1.1 135 | ================ 136 | 137 | - Fix: usage of unsupported features like ``executeUpdate`` with return 138 | columns was not caught properly 139 | 140 | 2016/11/22 2.1.0 141 | ================ 142 | 143 | - shaded pgsql sources to avoid dependency conflicts in projects which are 144 | depending on crate jdbc and postgresql jdbc driver 145 | 146 | - Fixed the issue which caused `getSchemas` and `getPrimaryKeys` to fail in 147 | Crate versions higher than 0.57. 148 | 149 | 2016/11/07 2.0.1 150 | ================ 151 | 152 | - Fixed packaging issue which caused the inccorect resolution of the 153 | transitive dependencies. 154 | 155 | 2016/11/04 2.0.0 156 | ================ 157 | 158 | - BREAKING: 159 | 160 | - Removed Crate client from the Crate JDBC driver. The driver uses the 161 | postgres wire protocol. 162 | 163 | - Support for the ``showsubcolumns`` parameter has been dropped. 164 | 165 | - The format of the connection string has been changed. The default schema 166 | name cannot be set via the connection string. 167 | 168 | 2016/11/04 1.14.0 169 | ================= 170 | 171 | - Updated Crate client to 0.56.3 172 | 173 | - Updated Crate JDBC metadata method supportsAlterTableWithAddColumn 174 | to reflect the current state of Crate. 175 | 176 | - Updated Crate JDBC metadata keywords methods to reflect the current 177 | state of Crate. 178 | 179 | - Updated Crate JDBC database metadata outer joins methods to reflect the 180 | current state of Crate. 181 | 182 | - Updated Crate JDBC database metadata methods getNumericFunctions, getStringFunctions 183 | and getTimeDateFunctions to reflect the current state of Crate. 184 | 185 | - Updated Crate client to 0.55.6. 186 | 187 | - Applications no longer need to load the Crate JDBC driver explicitly 188 | using `Class.forName()`. 189 | 190 | 2016/09/07 1.13.1 191 | ================= 192 | 193 | - Updated Crate client to 0.55.4. 194 | 195 | - Fix: Pacakaging of the Crate standalone JDBC driver for the versions 196 | which use crate-client <= 0.55.2. 197 | 198 | 2016/07/11 1.13.0 199 | ================= 200 | 201 | - Updated Crate client to 0.55.2. 202 | 203 | - Added JDBC property that allows to fetch nested columns if table metadata is queried. 204 | 205 | - It is now possible to set connection properties via the connection string. 206 | 207 | 2016/06/27 1.12.3 208 | ================= 209 | 210 | - Make jars Java 7 compatible when building with newer JDK version 211 | 212 | 2016/06/08 1.12.2 213 | ================= 214 | 215 | - Fix: Crate client was not closed when last JDBC connection was closed, and 216 | therefore caused leaking threads. 217 | 218 | 2016/05/17 1.12.1 219 | ================= 220 | 221 | - Set/get fetch direction and size methods no longer throw an exception. 222 | The methods calls are silently ignored. 223 | 224 | 2016/05/17 1.12.0 225 | ================= 226 | 227 | - update crate client to 0.54.9 228 | 229 | - make fetch size and set direction functionality compliant with the 230 | JDBC specification. 231 | 232 | - implemented the ``strict`` connection setting which enforces 233 | the driver to be compliant with the JDBC specification. 234 | 235 | 2016/02/08 1.11.0 236 | ================= 237 | 238 | - updated crate testing to 0.3.0 239 | 240 | - Updated Crate client to ``0.54.4`` 241 | 242 | - use only one shared CrateClient for all connections with the same URL 243 | 244 | 2016/01/20 1.10.0 245 | ================ 246 | 247 | - Updated Crate client to ``0.54.3`` 248 | 249 | 2015/12/10 1.9.3 250 | ================ 251 | 252 | - Implemented getTransactionIsolation to adhere JDBC spec 253 | 254 | 2015/10/23 1.9.2 255 | ================ 256 | 257 | - Updated Crate client to ``0.51.7`` which fixes following issues: 258 | 259 | - Fixed the issue which causes overloading of the first configured node 260 | in the cluster when multiple clients connections are established. 261 | 262 | 2015/10/12 1.9.1 263 | ================ 264 | 265 | - Updated Crate client to ``0.51.6`` 266 | 267 | - Fix: close JDBC connection correctly before raising exception for invalid 268 | URL format in order to prevent memory leak 269 | 270 | - Fix: URL parameters after the schema name are ignored 271 | 272 | - Fix: close Crate client to shut down remaining thread pools and connections 273 | when closing JDBC connection 274 | 275 | 2015/09/01 1.9.0 276 | ================ 277 | 278 | - Fixed an issue which caused the crate driver to take over jdbc 279 | urls from none crate urls 280 | 281 | - Updated Crate client to ``0.50.5`` 282 | 283 | 2015/07/09 1.8.1 284 | ================ 285 | 286 | - Updated Crate client to ``0.49.5`` 287 | 288 | - Fix: executeBatch() method on a prepared statement did not take 289 | custom schema from connection into account and therefore caused 290 | TableUnknownException 291 | 292 | 2015/07/03 1.8.0 293 | ================ 294 | 295 | - Added support for setting the QueryTimeout 296 | 297 | 2015/06/15 1.7.0 298 | ================ 299 | 300 | - Updated Crate client to ``0.49.2`` 301 | 302 | - Fix: do not throw exception when ``createStatement`` and ``prepareStatement`` 303 | are invoked with supported result set type, concurrency and holdability 304 | 305 | - Fix: do not return ``null`` but an empty ``ResultSet`` if there are no 306 | matches for a ``PreparedStatement`` 307 | 308 | 2015/04/09 1.6.0 309 | ================ 310 | 311 | - Added support for setting the default schema in the JDBC URL. 312 | This works for Crate 0.48.1 and later. 313 | 314 | 2015/04/03 1.5.1 315 | ================ 316 | 317 | - updated crate client to 0.47.8 318 | 319 | 2015/03/01 1.5.0 320 | ================ 321 | 322 | - updated crate client to 0.47.4 323 | 324 | - Fix: do not throw exception when setting CrateConnection to read-only mode 325 | 326 | - Fix: support arrays that might be returned as ``java.util.List`` 327 | 328 | - Fixed URL handling: In some cases the long format ``jdbc:crate`` wasn't 329 | accepted. 330 | 331 | - use ``information_schema.schemata`` for crate servers newer than or 332 | equal to version 0.46 333 | 334 | 2014/11/28 1.4.0 335 | ================ 336 | 337 | - throw SQLException instead of NullPointerException if any of the 338 | ``.get`` methods is called on a ResultSet before ``.next()`` has been 339 | called. 340 | 341 | - added support for multiple servers in JDBC URL format. 342 | 343 | - updated crate-client to 0.45.5 344 | 345 | 2014/10/31 1.3.0 346 | ================ 347 | 348 | - update crate-client to 0.45.2 349 | 350 | 2014/09/29 1.2.0 351 | ================ 352 | 353 | - updated crate-client to 0.44.2 354 | 355 | 2014/09/10 1.1.1 356 | ================ 357 | 358 | - ensure that empty resultsets on selects 359 | and zero rowcount on other statements are treated correctly 360 | 361 | 2014/09/05 1.1.0 362 | ================ 363 | 364 | - implemented batch execution to CrateStatement and CratePreparedStatement 365 | 366 | - updated crate-client to 0.42.2 367 | 368 | 2014/08/12 1.0.5 369 | ================ 370 | 371 | - updated crate-client to 0.41.2 372 | 373 | - improved docs formatting of field lists 374 | 375 | 2014/07/30 1.0.4 376 | ================ 377 | 378 | - added support for jdbc:crate: url prefix 379 | 380 | - updated crate-client version to 0.40.3 381 | 382 | 2014/06/03 1.0.3 383 | ================ 384 | 385 | - fixed missing class files in jdbc-standalone jar file 386 | 387 | 2014/05/23 1.0.2 388 | ================ 389 | 390 | - fix: do not return nested columns at database metadata 391 | 392 | 2014/05/20 1.0.1 393 | ================ 394 | 395 | - updated build configuration for documentation 396 | 397 | 2014/05/20 1.0.0 398 | ================ 399 | 400 | - initial version of jdbc driver 401 | -------------------------------------------------------------------------------- /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 applies to this repository. 9 | 10 | .. _contribution guide: https://github.com/crate/crate/blob/master/CONTRIBUTING.rst -------------------------------------------------------------------------------- /DEVELOP.rst: -------------------------------------------------------------------------------- 1 | =============== 2 | Developer guide 3 | =============== 4 | 5 | These instructions show you how to build the CrateDB JDBC driver from the 6 | source code, and how to invoke the test suite. For a conventional install 7 | (using pre-built JAR files), follow the `installation documentation`_. 8 | 9 | 10 | Acquire source 11 | ============== 12 | 13 | Clone the repository:: 14 | 15 | $ git clone --recursive https://github.com/crate/crate-jdbc 16 | 17 | Change directory into the repository:: 18 | 19 | $ cd crate-jdbc 20 | 21 | Building 22 | ======== 23 | 24 | This project uses Gradle_ as build tool. 25 | 26 | Gradle can be invoked like so:: 27 | 28 | $ ./gradlew 29 | 30 | The first time this command is executed, Gradle is downloaded and bootstrapped 31 | for you automatically. 32 | 33 | Build a regular JAR file:: 34 | 35 | $ ./gradlew jar 36 | 37 | Or, build a JAR file that includes dependencies:: 38 | 39 | $ ./gradlew standaloneJar 40 | 41 | Afterwards you can find the JAR file in the ``build/lib`` directory. 42 | 43 | Note that building the JAR files requires your environment locale set to 44 | ``UTF-8``. 45 | 46 | Build, sign and publish the JAR files locally 47 | --------------------------------------------- 48 | 49 | To test the build and publishing process, you can build, sign and publish the 50 | JAR files locally:: 51 | 52 | $ ./gradlew publishJdbcPublicationToMavenLocal 53 | 54 | or for the standalong version which includes dependencies:: 55 | 56 | $ ./gradlew publishJdbcStandalonePublicationToMavenLocal 57 | 58 | For the signing to work, you need to have the required (ascii) key and password 59 | configured under the following ENVIRONMENT variables: 60 | 61 | - `ORG_GRADLE_PROJECT_signingKey` <- the private key in ascii format 62 | - `ORG_GRADLE_PROJECT_signingPassword` <- the password for the private key 63 | 64 | 65 | Testing 66 | ======= 67 | 68 | Run the unit tests like so:: 69 | 70 | $ ./gradlew test 71 | 72 | Integration tests use a randomized CrateDB version. If you want to run the 73 | tests against a specific version you can either use the ``CRATE_VERSION`` or 74 | ``CRATE_URL`` environment variable, e.g.:: 75 | 76 | $ CRATE_VERSION=2.3.4 ./gradlew test 77 | 78 | or:: 79 | 80 | $ CRATE_URL=https://cdn.crate.io/downloads/releases/nightly/crate-0.58.0-201611210301-7d469f8.tar.gz ./gradlew test 81 | 82 | If you are using MacOS, you have to specify the URL to download the server, e.g.:: 83 | 84 | $ CRATE_URL=https://cdn2.crate.io/downloads/releases/cratedb/x64_mac/crate-5.9.0.tar.gz ./gradlew test 85 | 86 | For debugging purposes, integration tests can be run against any CrateDB build. 87 | Build tar.gz file by running ./gradlew distTar from crate repository and set 88 | path to the generated file to the ``CRATE_PATH`` environment variable, e.g.:: 89 | 90 | $ CRATE_PATH=../crate/app/build/distributions/crate-4.7.0-SNAPSHOT-3edf1b4f2f2.tar.gz ./gradlew test 91 | 92 | Preparing a Release 93 | =================== 94 | 95 | To create a new release, you must: 96 | 97 | - Add a new version to the ``io.crate.client.jdbc.CrateDriverVersion`` class 98 | 99 | - Point the ``CURRENT`` version in that class to the newly added version 100 | 101 | - Add a note for the new version at the ``CHANGES.txt`` file 102 | 103 | - Commit your changes with a message like "prepare release x.x.x" 104 | 105 | - Push to origin 106 | 107 | - Create a tag by running ``./devtools/create_tag.sh`` 108 | 109 | - Archive docs for old releases (see section below) 110 | 111 | At this point, Jenkins will take care of building and uploading the release to 112 | the Maven repository. 113 | 114 | However, if you'd like to do this manually, you can run:: 115 | 116 | $ ./gradlew clean ublishToSonatype closeAndReleaseSonatypeStagingRepository 117 | 118 | This requires you to have the required (ascii) key and password configured, 119 | see `Build, sign and publish the JAR files locally`_. 120 | 121 | Archiving Docs Versions 122 | ----------------------- 123 | 124 | Check the `versions hosted on ReadTheDocs`_. 125 | 126 | We should only be hosting the docs for `latest`, the last three minor release 127 | branches of the last major release, and the last minor release branch 128 | corresponding to the last two major releases. 129 | 130 | For example: 131 | 132 | - ``latest`` 133 | - ``2.2`` 134 | - ``2.1`` 135 | - ``2.0`` 136 | - ``1.14`` 137 | 138 | Because this project has not any releases with major version of ``0``, we stop 139 | at ``1.14``. 140 | 141 | To make changes to the RTD configuration (e.g., to activate or deactivate a 142 | release version), please contact the `@crate/docs`_ team. 143 | 144 | Writing Documentation 145 | ===================== 146 | 147 | The docs live under the docs directory. 148 | 149 | The docs are written written with ReStructuredText_ and processed with Sphinx_. 150 | 151 | Build the docs by running:: 152 | 153 | cd docs 154 | make html 155 | open .crate-docs/.build/index.html 156 | 157 | The docs are automatically built from Git by `Read the Docs`_ and there is 158 | nothing special you need to do to get the live docs to update. 159 | 160 | .. _@crate/docs: https://github.com/orgs/crate/teams/docs 161 | .. _Gradle: https://gradle.org/ 162 | .. _installation documentation: https://crate.io/docs/jdbc/en/latest/getting-started.html 163 | .. _ReStructuredText: http://docutils.sourceforge.net/rst.html 164 | .. _Sphinx: http://sphinx-doc.org/ 165 | .. _Read the Docs: http://readthedocs.org/ 166 | .. _versions hosted on ReadTheDocs: https://readthedocs.org/projects/crate-jdbc/versions/ 167 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | 204 | 205 | =============================================================================== 206 | 207 | For the `docs` directory: 208 | 209 | The source files for the documentation are licensed under the Apache License 210 | Version 2.0. These source files are used by the project maintainers to build 211 | online documentation for end-users: 212 | 213 | 214 | 215 | If you want to make contributions to the documentation, it may be necessary for 216 | you to build the documentation yourself by following the instructions in the 217 | `DEVELOP.rst` file. If you do this, a number of third-party software components 218 | are necessary. 219 | 220 | We do not ship the source code for these optional third-party software 221 | components or their dependencies, so we cannot make any guarantees about the 222 | licensing status of these components. 223 | 224 | However, for convenience, the documentation build system explicitly references 225 | the following software components (grouped by license): 226 | 227 | PSF License: 228 | 229 | - Python 3 230 | 231 | MIT License: 232 | 233 | - pip 234 | - setuptools 235 | - sphinx-autobuild 236 | 237 | BSD License: 238 | 239 | - alabaster 240 | - sphinx 241 | 242 | Apache License 2.0: 243 | 244 | - crate-docs-theme 245 | 246 | Please note that each of these components may specify its own dependencies and 247 | those dependencies may be licensed differently. 248 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | CrateDB Data JDBC Driver 2 | Copyright 2013-2023 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 Data JDBC Driver is 9 | licensed under the Apache License, Version 2.0. 10 | 11 | Third-party components bundled with the CrateDB Data JDBC Driver listed in 12 | the 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 Data JDBC Driver from source pulls in a number of 17 | additional third-party dependencies. Hence, convenience releases will contain a 18 | mix of CrateDB Data JDBC Driver source code and third-party build-time 19 | dependencies 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 JDBC driver 3 | =================== 4 | 5 | |tests| |docs| |rtd| |maven-central| 6 | 7 | | 8 | 9 | A `JDBC`_ driver for `CrateDB`_, based on the `PostgreSQL JDBC Driver`_. 10 | 11 | This is a `type 4 JDBC driver`_ written in pure Java. It communicates with the 12 | database using the `PostgreSQL Wire Protocol`_. 13 | 14 | `JDBC`_ is a standard Java API that provides common interfaces for accessing 15 | databases in Java. 16 | 17 | Installation 18 | ============ 19 | 20 | The driver comes in two variants, available on Maven Central at `crate-jdbc`_ 21 | and `crate-jdbc-standalone`_. 22 | 23 | For a conventional install (using pre-built JAR files), follow the 24 | `installation documentation`_. For setting up a development sandbox, to build 25 | the JAR from source, please follow up reading the `developer guide`_. 26 | 27 | Documentation and help 28 | ====================== 29 | 30 | - `CrateDB JDBC driver documentation`_ 31 | - `CrateDB reference documentation`_ 32 | - `JDBC tutorial`_ 33 | - `JDBC API documentation`_ 34 | - `Developer guide`_ 35 | - `Contributing`_ 36 | - Other `support channels`_ 37 | 38 | Contributing 39 | ============ 40 | 41 | The CrateDB JDBC driver library is an open source project, and is `managed on 42 | GitHub`_. We appreciate contributions of any kind. 43 | 44 | 45 | .. _Contributing: CONTRIBUTING.rst 46 | .. _crate-jdbc: https://repo1.maven.org/maven2/io/crate/crate-jdbc/ 47 | .. _crate-jdbc-standalone: https://repo1.maven.org/maven2/io/crate/crate-jdbc-standalone/ 48 | .. _Crate.io: http://crate.io/ 49 | .. _CrateDB: https://github.com/crate/crate 50 | .. _CrateDB JDBC driver documentation: https://crate.io/docs/projects/crate-jdbc/ 51 | .. _CrateDB reference documentation: https://crate.io/docs/reference/ 52 | .. _developer guide: DEVELOP.rst 53 | .. _installation documentation: https://crate.io/docs/jdbc/en/latest/getting-started.html 54 | .. _JDBC: https://en.wikipedia.org/wiki/Java_Database_Connectivity 55 | .. _JDBC API documentation: https://docs.oracle.com/javase/8/docs/technotes/guides/jdbc/ 56 | .. _JDBC tutorial: https://docs.oracle.com/javase/tutorial/jdbc/basics/ 57 | .. _managed on GitHub: https://github.com/crate/crate-jdbc 58 | .. _PostgreSQL JDBC Driver: https://github.com/pgjdbc/pgjdbc 59 | .. _PostgreSQL Wire Protocol: https://crate.io/docs/crate/reference/en/latest/interfaces/postgres.html 60 | .. _support channels: https://crate.io/support/ 61 | .. _type 4 JDBC driver: https://en.wikipedia.org/wiki/JDBC_driver#Type_4_driver_.E2.80.93_Database-Protocol_driver_.28Pure_Java_driver.29 62 | 63 | 64 | 65 | .. |tests| image:: https://github.com/crate/crate-jdbc/actions/workflows/tests.yml/badge.svg?branch=master 66 | :alt: Build status 67 | :target: https://github.com/crate/crate-jdbc/actions/workflows/tests.yml?query=branch=master 68 | 69 | .. |docs| image:: https://github.com/crate/crate-jdbc/actions/workflows/docs.yml/badge.svg 70 | :alt: Documentation: Link checker 71 | :target: https://github.com/crate/crate-jdbc/actions/workflows/docs.yml 72 | 73 | .. |rtd| image:: https://readthedocs.org/projects/crate-jdbc/badge/ 74 | :alt: Read the Docs status 75 | :target: https://readthedocs.org/projects/crate-jdbc/ 76 | 77 | .. |maven-central| image:: https://maven-badges.herokuapp.com/maven-central/io.crate/crate-jdbc/badge.svg 78 | :alt: Latest release on Maven Central 79 | :target: https://repo1.maven.org/maven2/io/crate/crate-jdbc/ 80 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.github.johnrengelman.shadow' version '8.1.1' 3 | id "io.github.gradle-nexus.publish-plugin" version "2.0.0" 4 | id "maven-publish" 5 | id "signing" 6 | } 7 | 8 | import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar 9 | 10 | allprojects { 11 | apply plugin: 'idea' 12 | apply plugin: "java-library" 13 | compileJava {options.encoding = "UTF-8"} 14 | repositories { 15 | mavenCentral() 16 | gradlePluginPortal() 17 | } 18 | sourceCompatibility = "11" 19 | targetCompatibility = "11" 20 | } 21 | 22 | group = "io.crate" 23 | 24 | dependencies { 25 | implementation project(':pg') 26 | testImplementation 'io.crate:crate-testing:0.12.1' 27 | testImplementation 'org.hamcrest:hamcrest-all:1.3' 28 | testImplementation 'junit:junit:4.13.2' 29 | testImplementation ('com.carrotsearch.randomizedtesting:randomizedtesting-runner:2.8.3') { 30 | exclude group: 'junit', module: 'junit' 31 | } 32 | testImplementation ("org.mockito:mockito-core:5.11.0") { 33 | exclude group: 'org.hamcrest', module: 'hamcrest-core' 34 | } 35 | } 36 | 37 | nexusPublishing { 38 | repositories { 39 | sonatype() 40 | } 41 | } 42 | 43 | sourceSets { 44 | main { 45 | java { 46 | srcDir 'driver/main/java' 47 | } 48 | resources { 49 | srcDir 'driver/main/resources' 50 | } 51 | } 52 | test { 53 | java { 54 | srcDir 'driver/test/java' 55 | } 56 | } 57 | } 58 | 59 | task getVersion(dependsOn: [compileJava]) { 60 | doFirst { 61 | def stdout = new ByteArrayOutputStream() 62 | javaexec { 63 | classpath = sourceSets.main.runtimeClasspath 64 | main = 'io.crate.client.jdbc.CrateDriverVersion' 65 | standardOutput = stdout 66 | } 67 | ext.gitTag = "git describe".execute().in.text.trim() 68 | ext.version = stdout.toString().trim().split(" ")[1].replace(',','').trim() 69 | 70 | if (!gradle.taskGraph.hasTask(publishToSonatype)) { 71 | ext.version = version + "-" + "git rev-parse --short HEAD".execute().in.text.trim() 72 | } 73 | project.version = version 74 | 75 | logger.quiet("gitTag: " + gitTag) 76 | logger.quiet("version: " + version) 77 | } 78 | } 79 | 80 | shadowJar.dependsOn([getVersion]) 81 | shadowJar { 82 | archiveClassifier.set('') 83 | duplicatesStrategy 'fail' 84 | configurations = [project.configurations.compileClasspath] 85 | dependencies { 86 | include(project(':pg')) 87 | } 88 | doFirst { 89 | from sourceSets.main.output 90 | manifest { 91 | attributes("Implementation-Title": "CrateDB JDBC Driver", "Implementation-Version": project.version) 92 | } 93 | } 94 | 95 | relocate 'org.postgresql', 'io.crate.shade.org.postgresql' 96 | } 97 | 98 | jar.dependsOn(dependsOn: [shadowJar]) 99 | jar { 100 | actions = [] // Do nothing, build shadowJar instead 101 | } 102 | 103 | task standaloneJar(type: ShadowJar, dependsOn: [getVersion]) { 104 | archiveBaseName.set('crate-jdbc-standalone') 105 | archiveClassifier.set('') 106 | duplicatesStrategy 'fail' 107 | configurations = [project.configurations.compileClasspath] 108 | doFirst { 109 | from sourceSets.main.output 110 | manifest { 111 | attributes("Implementation-Title": "CrateDB JDBC Driver (Standalone)", "Implementation-Version": project.version) 112 | } 113 | } 114 | // Crate JDBC dependencies 115 | relocate 'com.fasterxml.jackson', 'io.crate.shade.com.fasterxml.jackson' 116 | relocate 'org.postgresql', 'io.crate.shade.org.postgresql' 117 | // PGJDBC dependencies 118 | relocate 'waffle', 'io.crate.shade.waffle' 119 | relocate 'com.sun.jna', 'io.crate.shade.com.sun.jna' 120 | relocate 'org.slf4j', 'io.crate.shade.org.slf4j' 121 | relocate 'org.apache', 'io.crate.shade.org.apache' 122 | relocate 'org.osgi', 'io.crate.shade.org.osgi' 123 | relocate 'com.google', 'io.crate.shade.com.google' 124 | relocate 'com.ongres', 'io.crate.shade.com.ongres' 125 | } 126 | 127 | task javadocJar(type: Jar, dependsOn: [getVersion, javadoc]) { 128 | archiveClassifier.set("javadoc") 129 | from javadoc.destinationDir 130 | doFirst { 131 | manifest { 132 | attributes("Implementation-Title": "CrateDB JDBC Driver", "Implementation-Version": project.version) 133 | } 134 | } 135 | } 136 | 137 | task javadocJarStandalone (type: Jar, dependsOn: [getVersion, javadoc]) { 138 | archiveBaseName.set('crate-jdbc-standalone') 139 | archiveClassifier.set('javadoc') 140 | from javadoc.destinationDir 141 | doFirst { 142 | manifest { 143 | attributes("Implementation-Title": "CrateDB JDBC Driver (Standalone)", "Implementation-Version": project.version) 144 | } 145 | } 146 | } 147 | 148 | task sourcesJar (type : Jar, dependsOn: [getVersion]) { 149 | archiveClassifier.set('sources') 150 | from sourceSets.main.allSource 151 | doFirst { 152 | manifest { 153 | attributes("Implementation-Title": "CrateDB JDBC Driver", "Implementation-Version": project.version) 154 | } 155 | } 156 | } 157 | 158 | task sourcesJarStandalone (type : Jar, dependsOn: [getVersion]) { 159 | archiveBaseName.set('crate-jdbc-standalone') 160 | archiveClassifier.set('sources') 161 | from sourceSets.main.allSource 162 | doFirst { 163 | manifest { 164 | attributes("Implementation-Title": "CrateDB JDBC Driver (Standalone)", "Implementation-Version": project.version) 165 | } 166 | } 167 | } 168 | 169 | 170 | artifacts { 171 | archives shadowJar 172 | archives standaloneJar 173 | archives javadocJar 174 | archives javadocJarStandalone 175 | archives sourcesJar 176 | archives sourcesJarStandalone 177 | } 178 | 179 | 180 | project.ext.sonatypeUsername = project.hasProperty('sonatypeUsername') ? sonatypeUsername : "" 181 | project.ext.sonatypePassword = project.hasProperty('sonatypePassword') ? sonatypePassword : "" 182 | project.ext.url = 'https://crate.io' 183 | project.ext.scm = { 184 | url = 'https://github.com/crate/crate-jdbc' 185 | connection = 'scm:git:git://github.com/crate/crate-jdbc.git' 186 | developerConnection = 'scm:git:ssh:git@github.com:crate/crate-jdbc.git' 187 | } 188 | project.ext.licenses = { 189 | license { 190 | name = 'The Apache Software License, Version 2.0' 191 | url = 'http://www.apache.org/license/LICENSE-2.0.txt' 192 | distribution = 'repo' 193 | } 194 | } 195 | project.ext.developers = { 196 | developer { 197 | id = 'crate' 198 | name = 'Crate Developers' 199 | email = 'office@crate.io' 200 | } 201 | } 202 | 203 | publishing { 204 | publications { 205 | jdbc(MavenPublication) { 206 | artifactId = 'crate-jdbc' 207 | artifact shadowJar 208 | artifact sourcesJar 209 | artifact javadocJar 210 | version = project.version 211 | pom { 212 | name = "crate-jdbc" 213 | description = "CrateDB JDBC Driver" 214 | url = project.ext.url 215 | licenses project.ext.licenses 216 | developers project.ext.developers 217 | scm project.ext.scm 218 | } 219 | } 220 | jdbcStandalone(MavenPublication) { 221 | artifactId = 'crate-jdbc-standalone' 222 | artifact standaloneJar 223 | artifact javadocJarStandalone 224 | artifact sourcesJarStandalone 225 | version = project.version 226 | pom { 227 | name = "crate-jdbc-standalone" 228 | description = "CrateDB JDBC Driver (Standalone)" 229 | url = project.ext.url 230 | licenses project.ext.licenses 231 | developers project.ext.developers 232 | scm project.ext.scm 233 | } 234 | } 235 | } 236 | } 237 | 238 | signing { 239 | def signingKey = findProperty("signingKey") 240 | def signingPassword = findProperty("signingPassword") 241 | useInMemoryPgpKeys(signingKey, signingPassword) 242 | sign(publishing.publications) 243 | } 244 | 245 | test { 246 | // show standard out and standard error of the test JVM(s) on the console 247 | testLogging.showStandardStreams = true 248 | outputs.upToDateWhen { false } 249 | } 250 | 251 | idea { 252 | project { 253 | vcs = 'Git'; 254 | languageLevel = 'JDK_1_8'; 255 | ipr { 256 | withXml { provider -> 257 | def node = provider.asNode(); 258 | node.append(new XmlParser().parse(file("codeStyle.xml"))); 259 | def copyrightManager = node.component.find { it.'@name' == 'CopyrightManager' } 260 | copyrightManager.@default = "CrateASL2"; 261 | def aslCopyright = copyrightManager.copyright.find { it.option.find { it.@name == "myName" }?.@value == "CrateASL2" } 262 | if (aslCopyright == null) { 263 | copyrightManager.append(new XmlParser().parse(file("copyright.xml"))) 264 | } 265 | } 266 | } 267 | } 268 | } 269 | 270 | wrapper { 271 | gradleVersion = '8.3' 272 | } 273 | -------------------------------------------------------------------------------- /codeStyle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 19 | 21 | -------------------------------------------------------------------------------- /copyright.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | -------------------------------------------------------------------------------- /devtools/create_tag.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | # Licensed to Crate.IO GmbH ("Crate") under one or more contributor 5 | # license agreements. See the NOTICE file distributed with this work for 6 | # additional information regarding copyright ownership. Crate licenses 7 | # this file to you under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. You may 9 | # obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 16 | # License for the specific language governing permissions and limitations 17 | # under the License. 18 | # 19 | # However, if you have executed another commercial license agreement 20 | # with Crate these terms will supersede the license and you may use the 21 | # software solely pursuant to the terms of the relevant commercial agreement. 22 | 23 | # Info: Be aware from where you are invoking this script due to relative paths. 24 | # For example, 'gradlew' has to be in the same directory as where you are 25 | # invoking this script from. 26 | # E.g.: ../crate>./devtools/create_tag.sh 27 | 28 | # check if everything is committed 29 | CLEAN=`git status -s` 30 | if [ ! -z "$CLEAN" ] 31 | then 32 | echo "Working directory not clean. Please commit all changes before tagging" 33 | echo "Aborting." 34 | exit -1 35 | fi 36 | 37 | echo "Fetching origin..." 38 | git fetch origin > /dev/null 39 | 40 | # get current branc 41 | BRANCH=`git branch | grep "^*" | cut -d " " -f 2` 42 | echo "Current branch is $BRANCH." 43 | 44 | # check if BRANCH == origin/BRANCH 45 | LOCAL_COMMIT=`git show --format="%H" $BRANCH` 46 | ORIGIN_COMMIT=`git show --format="%H" origin/$BRANCH` 47 | 48 | if [ "$LOCAL_COMMIT" != "$ORIGIN_COMMIT" ] 49 | then 50 | echo "Local $BRANCH is not up to date. " 51 | echo "Aborting." 52 | exit -1 53 | fi 54 | 55 | # get the version 56 | echo "Getting version ..." 57 | VERSION=`./gradlew getVersion | grep version | cut -d ":" -f 2 | tr -d ' '` 58 | echo "$VERSION" 59 | 60 | # check if tag to create has already been created 61 | EXISTS=`git tag | grep $VERSION` 62 | 63 | if [ "$VERSION" == "$EXISTS" ] 64 | then 65 | echo "Revision $VERSION already tagged." 66 | echo "Aborting." 67 | exit -1 68 | fi 69 | 70 | # check if VERSION is in head of CHANGES.txt 71 | VERSION_NUMBER=`echo $VERSION | cut -d '-' -f 1` 72 | REV_NOTE=`grep "[0-9/]\{10\} $VERSION_NUMBER" CHANGES.txt` 73 | if [ -z "$REV_NOTE" ] 74 | then 75 | echo "No notes for revision $VERSION found in CHANGES.txt" 76 | echo "Aborting." 77 | exit -1 78 | fi 79 | 80 | echo "Creating tag $VERSION_NUMBER ..." 81 | git tag -a "$VERSION_NUMBER" -m "Tag release for revision $VERSION" 82 | git push --tags 83 | echo "Done." 84 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | .crate-docs 2 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Licensed to Crate (https://crate.io) under one or more contributor license 2 | # agreements. See the NOTICE file distributed with this work for additional 3 | # information regarding copyright ownership. Crate licenses this file to you 4 | # under the Apache License, Version 2.0 (the "License"); you may not use this 5 | # file except in compliance with the License. You may obtain a copy of the 6 | # License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | # License for the specific language governing permissions and limitations under 14 | # the License. 15 | # 16 | # However, if you have executed another commercial license agreement with Crate 17 | # these terms will supersede the license and you may use the software solely 18 | # pursuant to the terms of the relevant commercial agreement. 19 | 20 | 21 | # ============================================================================= 22 | # Crate Docs 23 | # ============================================================================= 24 | 25 | # The Crate Docs project provides a common set of tools for producing the 26 | # Crate.io documentation. See 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 | python3 -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/jdbc/en/latest/site.xml 5 | -------------------------------------------------------------------------------- /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.jdbc import * 2 | 3 | exclude_patterns = ['.crate-docs/**', 'requirements.txt'] 4 | 5 | linkcheck_anchors_ignore = [ 6 | r"diff-.*", 7 | ] 8 | 9 | # Enable version chooser. 10 | html_context.update({ 11 | "display_version": True, 12 | }) 13 | -------------------------------------------------------------------------------- /docs/connect.rst: -------------------------------------------------------------------------------- 1 | .. _connect: 2 | 3 | ================== 4 | Connect to CrateDB 5 | ================== 6 | 7 | .. _introduction: 8 | 9 | Introduction 10 | ============ 11 | 12 | The CrateDB JDBC driver provides the ``io.crate.client.jdbc.CrateDriver`` 13 | class. JDBC 4.0 will initialise this class automatically if it is found on your 14 | `class path`_. 15 | 16 | .. NOTE:: 17 | 18 | For CrateDB versions 2.1.x and later, you must configure a database user 19 | when connecting. Consult the `Connection Properties`_ section for more 20 | information. 21 | 22 | .. SEEALSO:: 23 | 24 | Please also consult the JDBC documentation for general information about 25 | how to `establish a connection using the DriverManager`_. 26 | 27 | .. _basics: 28 | 29 | The basics 30 | ========== 31 | 32 | Connect to CrateDB using the ``DriverManager`` class, like so:: 33 | 34 | Connection conn = DriverManager.getConnection("crate://localhost:5432/"); 35 | 36 | .. _database-urls: 37 | 38 | Database connection URLs 39 | ======================== 40 | 41 | A JDBC database is represented by special type of *Uniform Resource Locator* 42 | (URL) called a `database connection URL`_. 43 | 44 | The simplest database connection URL for CrateDB looks like this:: 45 | 46 | crate:/// 47 | 48 | Here, ```` is the node *host string*. 49 | 50 | A host string looks like this:: 51 | 52 | : 53 | 54 | Here, ```` is the hostname or IP address of the CrateDB node and 55 | ```` is a valid :ref:`psql.port ` number. 56 | 57 | Example host strings: 58 | 59 | - ``localhost:5432`` 60 | - ``crate-1.vm.example.com:5432`` 61 | - ``198.51.100.1:5432`` 62 | 63 | You can specify a second CrateDB node, like so:: 64 | 65 | crate://,/ 66 | 67 | Here, ```` and ```` are the host strings for the 68 | first and second CrateDB nodes, respectively. 69 | 70 | In fact, you can specify as many nodes as you like. Each corresponding host 71 | string must be separated from the previous one using a ``,`` character. 72 | 73 | The driver will attempt to connect to each node in the order they appear. The 74 | first successul connection will be used, and all other nodes will be ignored 75 | for the duration of that connection. 76 | 77 | .. NOTE:: 78 | 79 | The last host string must be followed by a ``/`` character. 80 | 81 | .. _schema-selection: 82 | 83 | Schema selection 84 | ================ 85 | 86 | To specify a different schema, use the ``setSchema`` method, like so: 87 | 88 | .. code-block:: java 89 | 90 | Connection conn = DriverManager.getConnection("crate://localhost:5432/"); 91 | conn.setSchema("my_schema"); 92 | 93 | .. TIP:: 94 | 95 | The default CrateDB schema is ``doc``, and if you do not specify a schema, 96 | this is what will be used. 97 | 98 | However, you can query any schema you like by specifying it in the query. 99 | 100 | .. _connection_properties: 101 | 102 | Connection properties 103 | ===================== 104 | 105 | Database connections have number of configurable properties. 106 | 107 | Here's a simple example: 108 | 109 | .. code-block:: java 110 | 111 | Properties properties = new Properties(); 112 | properties.put("user", "crate"); 113 | Connection conn = DriverManager.getConnection( 114 | "crate://localhost:5432/", properties 115 | ); 116 | 117 | Here, we set the ``user`` property to ``crate`` so that the driver will attempt 118 | to connect to the CrateDB node as the ``crate`` user. 119 | 120 | .. NOTE:: 121 | 122 | For simplicity, we only document use of the ``Properties`` class for setting 123 | properties. However, you can also set properties using `URL parameters`_ if 124 | you wish. 125 | 126 | The CrateDB JDBC driver supports following properties: 127 | 128 | :``strict``: 129 | 130 | If set to ``false``, the CrateDB JDBC driver silently ignores unsupported 131 | JDBC features. 132 | 133 | This will, for example, allow the driver to be used by most third-party 134 | applications that attempt to use transactional features. 135 | 136 | .. WARNING:: 137 | 138 | Silently ignoring transactions may result in data corruption or data 139 | loss. 140 | 141 | If set to ``true``, the CrateDB JDBC driver behaves strictly according to 142 | CrateDB's capabilities and the JDBC specification. 143 | 144 | In strict mode, attempts to use unsupported features will result in an 145 | exception being raised. 146 | 147 | Unsupported features include: 148 | 149 | - `Transactions`_, e.g.: 150 | 151 | - Any `isolation level`_ that isn't ``TRANSACTION_NONE`` 152 | 153 | - `Disabling auto-commit mode`_ 154 | 155 | - `Setting and rolling back to savepoints`_ 156 | 157 | - `Read-only connections`_ 158 | 159 | Defaults to ``false``. 160 | 161 | :``user``: 162 | 163 | Specifies the CrateDB user. 164 | 165 | Defaults to the same string as the OS system user. 166 | 167 | .. NOTE:: 168 | 169 | Authentication was introduced in CrateDB versions 2.1.x. 170 | 171 | If you are using CrateDB 2.1.x or later, you must supply a username. If 172 | you are using earlier versions of CrateDB, this argument is not supported. 173 | 174 | See the :ref:`compatibility notes ` for more 175 | information. 176 | 177 | If you have not configured a custom 178 | :ref:`database user `, 179 | you probably want to authenticate as the CrateDB superuser, which is 180 | ``crate``. The superuser does not have a password, so you can omit the 181 | ``password`` property. 182 | 183 | If you are authenticating as a custom user, that user will need to have 184 | :ref:`DQL privileges ` on the 185 | ``sys.nodes`` table, because this table is used for version negotiation. 186 | 187 | :``password``: 188 | 189 | Sets the password for authentication. 190 | 191 | :``ssl``: 192 | 193 | If set to ``true``, the driver will attempt to establish a secure connection 194 | to CrateDB using SSL. If a secure connection is not possible, no connection 195 | will be made. 196 | 197 | Defaults to ``false``. 198 | 199 | :``loadBalanceHosts``: 200 | 201 | If set to ``true``, the driver will randomly shuffle the order of the host 202 | strings. Over multiple connection attempts, this distributes connection 203 | attempts across the whole cluster, functioning as `client-side random load 204 | balancing`_. 205 | If ``false``, the driver will try the hosts in the order they are defined. 206 | 207 | Defaults to ``true``. 208 | 209 | Next steps 210 | ========== 211 | 212 | Use the standard `JDBC API`_ documentation for the rest of your setup process. 213 | Also have a look at corresponding code :ref:`examples`. 214 | 215 | 216 | .. _class path: https://docs.oracle.com/javase/tutorial/essential/environment/paths.html 217 | .. _client-side random load balancing: https://en.wikipedia.org/wiki/Load_balancing_(computing)#Client-side_random_load_balancing 218 | .. _database connection URL: https://docs.oracle.com/javase/tutorial/jdbc/basics/connecting.html#db_connection_url 219 | .. _Disabling auto-commit mode: https://docs.oracle.com/javase/tutorial/jdbc/basics/transactions.html#disable_auto_commit 220 | .. _documentation: https://github.com/crate/crate-sample-apps/blob/master/java/documentation.md 221 | .. _establish a connection using the DriverManager: https://docs.oracle.com/javase/tutorial/jdbc/basics/connecting.html 222 | .. _failover: https://en.wikipedia.org/wiki/Failover 223 | .. _isolation level: https://docs.oracle.com/javase/tutorial/jdbc/basics/transactions.html#transactions_data_integrity 224 | .. _JDBC API: https://docs.oracle.com/javase/8/docs/technotes/guides/jdbc/ 225 | .. _Read-only connections: https://docs.oracle.com/javase/7/docs/api/java/sql/Connection.html#setReadOnly(boolean) 226 | .. _Setting and rolling back to savepoints: https://docs.oracle.com/javase/tutorial/jdbc/basics/transactions.html#set_roll_back_savepoints 227 | .. _Transactions: https://docs.oracle.com/javase/tutorial/jdbc/basics/transactions.html 228 | .. _URL parameters: https://docs.oracle.com/javase/tutorial/jdbc/basics/connecting.html#db_connection_url 229 | .. _User Management: https://crate.io/docs/crate/reference/en/latest/sql/administration/user_management.html 230 | -------------------------------------------------------------------------------- /docs/data-types.rst: -------------------------------------------------------------------------------- 1 | .. _data-types: 2 | 3 | ========== 4 | Data types 5 | ========== 6 | 7 | Type mapping 8 | ============ 9 | 10 | JDBC maps SQL types to `Plain Old Java Objects`_ (POJOs). 11 | 12 | While this mapping is straightforward for most CrateDB types, for some it is 13 | not. 14 | 15 | The following table shows how the CrateDB types are mapped to `JDBC types`_ and 16 | what method can be used to fetch them from a `ResultSet`_ instance: 17 | 18 | +---------------+-----------------+------------------+ 19 | | CrateDB Type | JDBC Type | ResultSet Method | 20 | +===============+=================+==================+ 21 | | `boolean`__ | `BOOLEAN`__ | ``getBoolean`` | 22 | +---------------+-----------------+------------------+ 23 | | `byte`__ | `TINYINT`__ | ``getByte`` | 24 | +---------------+-----------------+------------------+ 25 | | `short`__ | `SMALLINT`__ | ``getShort`` | 26 | +---------------+-----------------+------------------+ 27 | | `integer`__ | `INTEGER`__ | ``getInteger`` | 28 | +---------------+-----------------+------------------+ 29 | | `long`__ | `BIGINT`__ | ``getLong`` | 30 | +---------------+-----------------+------------------+ 31 | | `float`__ | `REAL`__ | ``getFloat`` | 32 | +---------------+-----------------+------------------+ 33 | | `double`__ | `DOUBLE`__ | ``getDouble`` | 34 | +---------------+-----------------+------------------+ 35 | | `string`__ | `VARCHAR`__ | ``getString`` | 36 | +---------------+-----------------+------------------+ 37 | | `ip`__ | `VARCHAR`__ | ``getString`` | 38 | +---------------+-----------------+------------------+ 39 | | `timestamp`__ | `TIMESTAMP`__ | ``getDate``, | 40 | | | | ``getTime``, or | 41 | | | | ``getTimestamp`` | 42 | +---------------+-----------------+------------------+ 43 | | `geo_point`__ | `ARRAY`__ | ``getArray`` | 44 | +---------------+-----------------+------------------+ 45 | | `geo_shape`__ | `JAVA_OBJECT`__ | ``getObject`` | 46 | +---------------+-----------------+------------------+ 47 | | `object`__ | `JAVA_OBJECT`__ | ``getObject`` | 48 | +---------------+-----------------+------------------+ 49 | | `array`__ | `ARRAY`__ | ``getArray`` | 50 | +---------------+-----------------+------------------+ 51 | 52 | __ https://crate.io/docs/crate/reference/en/latest/general/ddl/data-types.html#boolean 53 | __ https://docs.oracle.com/javase/8/docs/api/java/sql/JDBCType.html#BOOLEAN 54 | __ https://crate.io/docs/crate/reference/en/latest/general/ddl/data-types.html#numeric-data 55 | __ https://docs.oracle.com/javase/8/docs/api/java/sql/JDBCType.html#TINYINT 56 | __ https://crate.io/docs/crate/reference/en/latest/general/ddl/data-types.html#numeric-data 57 | __ https://docs.oracle.com/javase/8/docs/api/java/sql/JDBCType.html#SMALLINT 58 | __ https://crate.io/docs/crate/reference/en/latest/general/ddl/data-types.html#numeric-data 59 | __ https://docs.oracle.com/javase/8/docs/api/java/sql/JDBCType.html#INTEGER 60 | __ https://crate.io/docs/crate/reference/en/latest/general/ddl/data-types.html#numeric-data 61 | __ https://docs.oracle.com/javase/8/docs/api/java/sql/JDBCType.html#BIGINT 62 | __ https://crate.io/docs/crate/reference/en/latest/general/ddl/data-types.html#numeric-data 63 | __ https://docs.oracle.com/javase/8/docs/api/java/sql/JDBCType.html#REAL 64 | __ https://crate.io/docs/crate/reference/en/latest/general/ddl/data-types.html#numeric-data 65 | __ https://docs.oracle.com/javase/8/docs/api/java/sql/JDBCType.html#DOUBLE 66 | __ https://crate.io/docs/crate/reference/en/latest/general/ddl/data-types.html#character-data 67 | __ https://docs.oracle.com/javase/8/docs/api/java/sql/JDBCType.html#VARCHAR 68 | __ https://crate.io/docs/crate/reference/en/latest/general/ddl/data-types.html#ip 69 | __ https://docs.oracle.com/javase/8/docs/api/java/sql/JDBCType.html#VARCHAR 70 | __ https://crate.io/docs/crate/reference/en/latest/general/ddl/data-types.html#dates-and-times 71 | __ https://docs.oracle.com/javase/8/docs/api/java/sql/JDBCType.html#TIMESTAMP 72 | __ https://crate.io/docs/crate/reference/en/latest/general/ddl/data-types.html#geo-point 73 | __ https://docs.oracle.com/javase/8/docs/api/java/sql/JDBCType.html#ARRAY 74 | __ https://crate.io/docs/crate/reference/en/latest/general/ddl/data-types.html#geo-shape 75 | __ https://docs.oracle.com/javase/8/docs/api/java/sql/JDBCType.html#JAVA_OBJECT 76 | __ https://crate.io/docs/crate/reference/en/latest/general/ddl/data-types.html#object 77 | __ https://docs.oracle.com/javase/8/docs/api/java/sql/JDBCType.html#JAVA_OBJECT 78 | __ https://crate.io/docs/crate/reference/en/latest/general/ddl/data-types.html#array 79 | __ https://docs.oracle.com/javase/8/docs/api/java/sql/JDBCType.html#ARRAY 80 | 81 | Array types 82 | ----------- 83 | 84 | Array types map to `java.sql.Array`_ instances. 85 | 86 | Use the ``.getArray()`` to get the underlying array (it is usually safe to 87 | cast it to ``Object[]``) if you prefer. Otherwise, to have JDBC handle type 88 | mapping, you can use ``.getResultSet()`` and use the related 89 | ``ResultSetMetaData`` to get the array values converted to Java POJOs. 90 | 91 | The ``ResultSet`` will have one column with the inner array type and the name 92 | of the array field (``Array.getBaseType()``) and as many rows as there are 93 | elements in the array. 94 | 95 | Here's one example: 96 | 97 | .. code-block:: java 98 | 99 | Statement statement = connection.createStatement(); 100 | ResultSet resultSet = statement.executeQuery( 101 | "SELECT array_field FROM my_table" 102 | ); 103 | resultSet.first(); 104 | Array arrayField = resultSet.getArray("array_field"); 105 | Object[] arrayFieldValue = (Object[]) arrayFieldValue.getArray(); 106 | 107 | When inserting arrays using a prepared statement, you must convert your array 108 | to a `java.sql.Array`_ by the use of ``createArrayOf()``. This function takes 109 | as its first argument, a CrateDB type as described above and as its second the 110 | array you want to convert. 111 | 112 | You can then use ``setArray()`` to set this converted array. 113 | 114 | For example: 115 | 116 | .. code-block:: java 117 | 118 | PreparedStatement preparedStatement = connection.prepareStatement( 119 | "INSERT into my_table (string_array) VALUES (?)" 120 | ); 121 | preparedStatement.setArray(1, connection.createArrayOf( 122 | "string", new String[]{"a", "b"} 123 | )); 124 | preparedStatement.execute(); 125 | 126 | Object types 127 | ------------ 128 | 129 | Object columns map to a `java.util.Map`_ object. 130 | 131 | You can fetch them using ``ResultSet.getObject()`` and cast the result to 132 | ``Map``. This ``Map`` will contain all nested columns defined in 133 | the object. 134 | 135 | Here's an example: 136 | 137 | .. code-block:: java 138 | 139 | Statement statement = connection.createStatement(); 140 | ResultSet resultSet = statement.executeQuery( 141 | "SELECT object_field FROM my_table" 142 | ); 143 | resultSet.first(); 144 | 145 | Map objectValue = (Map) resultSet.getObject("object_field"); 146 | Object objectField = objectValue.get("nested_field"); 147 | 148 | .. CAUTION:: 149 | 150 | Objects can be ``null``. 151 | 152 | .. _java.sql.Array: https://docs.oracle.com/javase/8/docs/api/java/sql/Array.html 153 | .. _java.util.Map: https://docs.oracle.com/javase/8/docs/api/java/util/Map.html 154 | .. _JDBC types: https://docs.oracle.com/javase/8/docs/api/java/sql/Types.html 155 | .. _Plain Old Java Objects: https://en.wikipedia.org/wiki/Plain_old_Java_object 156 | .. _ResultSet: https://docs.oracle.com/javase/8/docs/api/java/sql/ResultSet.html 157 | -------------------------------------------------------------------------------- /docs/docutils.conf: -------------------------------------------------------------------------------- 1 | [html4css1 writer] 2 | field_name_limit: 40 3 | 4 | -------------------------------------------------------------------------------- /docs/getting-started.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | Installation 3 | ============ 4 | 5 | Learn how to install and get started with the :ref:`CrateDB JDBC driver 6 | `. 7 | 8 | Prerequisites 9 | ============= 10 | 11 | The CrateDB JDBC driver requires Java 8, preferably update 20 or later. We 12 | recommend using `Oracle’s Java`_ on macOS and `OpenJDK`_ on Linux Systems. 13 | 14 | Install 15 | ======= 16 | 17 | The driver comes in two variants, available on Maven Central at the 18 | `repository root folder`_. 19 | 20 | - `crate-jdbc`_ 21 | 22 | The driver JAR, suitable to be used as a dependency in your Maven or 23 | Gradle project. 24 | 25 | - `crate-jdbc-standalone`_ 26 | 27 | A single, standalone JAR file, that bundles all the 28 | driver dependencies, suitable to be used as a plugin for tools such as 29 | `DataGrip`_, `DBeaver`_, `SQuirreL`_, etc.. This variant should not be 30 | used as a dependency in a Maven or Gradle project. 31 | 32 | .. SEEALSO:: 33 | 34 | To build the CrateDB JDBC driver from the source code, follow the 35 | `developer guide`_. 36 | 37 | Set up as a dependency 38 | ====================== 39 | 40 | This section shows you how to set up the CrateDB JDBC driver as a 41 | dependency using Maven or Gradle, two popular build tools for Java projects. 42 | 43 | Maven 44 | ----- 45 | 46 | Add ``crate-jdbc`` as a dependency, like so: 47 | 48 | .. code-block:: xml 49 | 50 | 51 | 52 | io.crate 53 | crate-jdbc 54 | 2.7.0 55 | 56 | 57 | 58 | Gradle 59 | ------ 60 | 61 | If you're using `Gradle`_, you will need to add the Maven Central repository to your 62 | ``build.gradle`` file: 63 | 64 | .. code-block:: groovy 65 | 66 | repositories { 67 | mavenCentral() 68 | } 69 | 70 | Then, add ``crate-jdbc`` as a dependency: 71 | 72 | .. code-block:: groovy 73 | 74 | dependencies { 75 | implementation 'io.crate:crate-jdbc:2.7.0' 76 | } 77 | 78 | Next steps 79 | ========== 80 | 81 | Once the JDBC driver is set up, you probably want to :ref:`connect to CrateDB 82 | `. 83 | 84 | 85 | .. _crate-jdbc: https://repo1.maven.org/maven2/io/crate/crate-jdbc/ 86 | .. _crate-jdbc-standalone: https://repo1.maven.org/maven2/io/crate/crate-jdbc-standalone/ 87 | .. _developer guide: https://github.com/crate/crate-jdbc/blob/master/DEVELOP.rst 88 | .. _DataGrip: https://www.jetbrains.com/datagrip/ 89 | .. _DBeaver: https://dbeaver.io/about/ 90 | .. _Gradle: https://gradle.org/ 91 | .. _instructions on GitHub: https://github.com/crate/crate-jdbc 92 | .. _OpenJDK: https://openjdk.org/ 93 | .. _Oracle’s Java: https://www.oracle.com/java/technologies/downloads/ 94 | .. _repository root folder: https://repo1.maven.org/maven2/io/crate/ 95 | .. _SQuirreL: https://crate.io/blog/use-cratedb-squirrel-basic-java-desktop-client 96 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. _index: 2 | 3 | ################### 4 | CrateDB JDBC Driver 5 | ################### 6 | 7 | ************ 8 | Introduction 9 | ************ 10 | 11 | A `JDBC`_ driver for `CrateDB`_, based on the `PostgreSQL JDBC Driver`_ which is adhering to the `JDBC 4.1 specification`_. It is written in pure Java, and communicates with the database using the `PostgreSQL Wire Protocol`_. 12 | 13 | .. _synopsis: 14 | 15 | ******** 16 | Synopsis 17 | ******** 18 | 19 | Connect to CrateDB instance running on ``localhost``: 20 | 21 | .. code-block:: java 22 | 23 | import java.sql.Connection; 24 | import java.sql.DriverManager; 25 | 26 | Connection conn = DriverManager.getConnection("jdbc:crate://localhost:5432/"); 27 | 28 | Connect to CrateDB Cloud: 29 | 30 | .. code-block:: java 31 | 32 | import java.sql.Connection; 33 | import java.sql.DriverManager; 34 | import java.util.Properties; 35 | 36 | Properties connectionProps = new Properties(); 37 | connectionProps.put("user", "admin"); 38 | connectionProps.put("password", ""); 39 | connectionProps.put("tcpKeepAlive", true); 40 | 41 | Connection conn = DriverManager.getConnection("jdbc:crate://example.aks1.westeurope.azure.cratedb.net:5432/?user=crate", connectionProps); 42 | 43 | .. _examples: 44 | 45 | Examples 46 | ======== 47 | 48 | - The `Basic example for connecting to CrateDB and CrateDB Cloud using JDBC`_ 49 | demonstrates CrateDB's PostgreSQL wire protocol compatibility by exercising a 50 | basic example using both the vanilla pgJDBC Driver and the CrateDB JDBC Driver. 51 | - The `sample application`_ and the corresponding `sample application 52 | documentation`_ demonstrate the use of the driver on behalf of an example 53 | "guestbook" application, using `Spring Data JDBC`_. 54 | - The article `Build a data ingestion pipeline using Kafka, Flink, and CrateDB`_, 55 | and the accompanying repositories `Apache Kafka, Apache Flink, and CrateDB`_ 56 | and `Flink example jobs for CrateDB`_. 57 | 58 | ************* 59 | Documentation 60 | ************* 61 | 62 | For general help about `JDBC`_, please consult the `JDBC tutorial`_ and the `JDBC API documentation`_. 63 | 64 | .. toctree:: 65 | :titlesonly: 66 | 67 | getting-started 68 | connect 69 | data-types 70 | internals 71 | 72 | 73 | .. SEEALSO:: 74 | 75 | The CrateDB JDBC driver is an open source project and is `hosted on 76 | GitHub`_. Every kind of contribution, feedback, or patch, is much 77 | welcome! 78 | 79 | 80 | .. _Apache Kafka, Apache Flink, and CrateDB: https://github.com/crate/cratedb-examples/tree/main/framework/flink 81 | .. _Basic example for connecting to CrateDB and CrateDB Cloud using JDBC: https://github.com/crate/cratedb-examples/tree/main/by-language/java-jdbc 82 | .. _Build a data ingestion pipeline using Kafka, Flink, and CrateDB: https://dev.to/crate/build-a-data-ingestion-pipeline-using-kafka-flink-and-cratedb-1h5o 83 | .. _CrateDB: https://crate.io/products/cratedb/ 84 | .. _CrateDB source: https://github.com/crate/crate 85 | .. _Flink example jobs for CrateDB: https://github.com/crate/cratedb-flink-jobs 86 | .. _hosted on GitHub: https://github.com/crate/crate-jdbc/ 87 | .. _JDBC: https://en.wikipedia.org/wiki/Java_Database_Connectivity 88 | .. _JDBC 4.1 specification: https://download.oracle.com/otn-pub/jcp/jdbc-4_1-mrel-spec/jdbc4.1-fr-spec.pdf 89 | .. _JDBC API documentation: https://docs.oracle.com/javase/8/docs/technotes/guides/jdbc/ 90 | .. _JDBC tutorial: https://docs.oracle.com/javase/tutorial/jdbc/basics/ 91 | .. _PostgreSQL JDBC Driver: https://github.com/pgjdbc/pgjdbc 92 | .. _PostgreSQL Wire Protocol: https://www.postgresql.org/docs/current/protocol.html 93 | .. _sample application: https://github.com/crate/crate-sample-apps/tree/main/java-spring 94 | .. _sample application documentation: https://github.com/crate/crate-sample-apps/blob/main/java-spring/documentation.md 95 | .. _Spring Data JDBC: https://spring.io/projects/spring-data-jdbc/ 96 | -------------------------------------------------------------------------------- /docs/internals.rst: -------------------------------------------------------------------------------- 1 | .. _details: 2 | .. _internals: 3 | 4 | ######### 5 | Internals 6 | ######### 7 | 8 | pgJDBC employs a few behaviours that strictly expect a PostgreSQL 9 | server on the other end, so that some operations will fail on databases 10 | offering wire-compatibility with PostgreSQL, but do not provide certain 11 | features like the `hstore`_ or `jsonb`_ extensions. 12 | 13 | The background is that, when using the ``jdbc:postgresql://`` JDBC driver 14 | prefix, downstream applications and frameworks will implicitly select 15 | the corresponding dialect implementation for PostgreSQL. 16 | 17 | 18 | ************* 19 | Compatibility 20 | ************* 21 | 22 | While CrateDB is compatible with PostgreSQL on the wire protocol, it needs 23 | JDBC support for its SQL dialect, provided by the ``jdbc:crate://`` protocol 24 | identifier. 25 | 26 | - IDEs like `DataGrip`_ and `DBeaver`_ need this driver, because they would 27 | otherwise emit SQL statements too specific to PostgreSQL. 28 | 29 | - The `Apache Flink JDBC Connector`_ needs this driver to not select the 30 | PostgreSQL dialect, see also `Apache Kafka, Apache Flink, and CrateDB`_. 31 | 32 | - Tools like `Dataiku`_ need this driver to implement transaction commands 33 | like ``ROLLBACK`` as a no-op. 34 | 35 | .. note:: 36 | 37 | For basic and general purpose use, the official `PostgreSQL JDBC Driver`_ 38 | can also be used. Sometimes, it is easier because pgJDBC is included 39 | into many applications out of the box. 40 | 41 | 42 | .. _differences: 43 | .. _implementations: 44 | .. _jdbc-implementation: 45 | 46 | ********************* 47 | Differences to pgJDBC 48 | ********************* 49 | 50 | The driver is based upon a fork of the `PostgreSQL JDBC Driver`_, see `pgjdbc 51 | driver fork`_, and adjusts a few details to compensate for behavioral 52 | differences of CrateDB. 53 | Please take notice of the corresponding implementation notes: 54 | 55 | :Supported: 56 | 57 | - A few metadata functions have been adjusted to better support CrateDB's type system. 58 | - The CrateDB JDBC driver deserializes objects to a Map, pgJDBC treats them as JSON. 59 | - DDL and DML statements are supported through adjustments to the 60 | `PgPreparedStatement`_ and `PgStatement`_ interfaces. 61 | 62 | :Unsupported: 63 | 64 | - `CallableStatement`_ is not supported, as CrateDB itself does not support 65 | stored procedures. 66 | - `DataSource`_ is not supported. 67 | - `ParameterMetaData`_, e.g. as returned by `PreparedStatement`_, is not 68 | supported. 69 | - `ResultSet`_ objects are read only (``TYPE_FORWARD_ONLY``, ``CONCUR_READ_ONLY``), 70 | so changes to a ``ResultSet`` are not supported. 71 | 72 | To learn further details about the compatibility with JDBC and PostgreSQL 73 | features, see the specific code changes to the `PgConnection`_, 74 | `PgDatabaseMetaData`_, and `PgResultSet`_ classes. 75 | 76 | 77 | 78 | .. _Apache Flink JDBC Connector: https://github.com/apache/flink-connector-jdbc 79 | .. _Apache Kafka, Apache Flink, and CrateDB: https://github.com/crate/cratedb-examples/tree/main/framework/flink 80 | .. _CallableStatement: https://docs.oracle.com/javase/8/docs/api/java/sql/CallableStatement.html 81 | .. _Dataiku: https://www.dataiku.com/ 82 | .. _DataGrip: https://www.jetbrains.com/datagrip/ 83 | .. _DataSource: https://docs.oracle.com/javase/8/docs/api/javax/sql/DataSource.html 84 | .. _DBeaver: https://dbeaver.io/about/ 85 | .. _hstore: https://www.postgresql.org/docs/current/hstore.html 86 | .. _jsonb: https://www.postgresql.org/docs/current/datatype-json.html 87 | .. _ParameterMetaData: https://docs.oracle.com/javase/8/docs/api/java/sql/ParameterMetaData.html 88 | .. _pgjdbc driver fork: https://github.com/crate/pgjdbc 89 | .. _PostgreSQL JDBC Driver: https://jdbc.postgresql.org/ 90 | .. _PreparedStatement: https://docs.oracle.com/javase/8/docs/api/java/sql/PreparedStatement.html 91 | .. _ResultSet: https://docs.oracle.com/javase/8/docs/api/java/sql/ResultSet.html 92 | 93 | 94 | .. _PgConnection: https://github.com/pgjdbc/pgjdbc/compare/REL42.2.5...crate:pgjdbc:REL42.2.5_crate?expand=1#diff-8ee30bec696495ec5763a3e1c1b216776efc124729f72e18dbaa35064af0aef0 95 | .. _PgDatabaseMetaData: https://github.com/pgjdbc/pgjdbc/compare/REL42.2.5...crate:pgjdbc:REL42.2.5_crate?expand=1#diff-0571f8ac3385a7f7bb34e5c77f8afd24810311506989379c2e85c6c16eea6ce4 96 | .. _PgResultSet: https://github.com/pgjdbc/pgjdbc/compare/REL42.2.5...crate:pgjdbc:REL42.2.5_crate?expand=1#diff-7e93771092eab9084402e3c7c81319a1f037febdc7614264329bd29f11d39ef2 97 | .. _PgPreparedStatement: https://github.com/pgjdbc/pgjdbc/compare/REL42.2.5...crate:pgjdbc:REL42.2.5_crate?expand=1#diff-d4946409bd7c59e525f34b4c974a3df76638dc84adc060cc5d13d5409c6aeb21 98 | .. _PgStatement: https://github.com/pgjdbc/pgjdbc/compare/REL42.2.5...crate:pgjdbc:REL42.2.5_crate?expand=1#diff-2abcc60e1b1ef8eeadd6372bf7afd0c0ebae0ebd691b0965fc914fea794eb6d0 99 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | crate-docs-theme>=0.35.0 2 | -------------------------------------------------------------------------------- /driver/main/java/io/crate/client/jdbc/CrateDriver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to Crate under one or more contributor license agreements. 3 | * See the NOTICE file distributed with this work for additional 4 | * information regarding copyright ownership. Crate licenses this file 5 | * to you under the Apache License, Version 2.0 (the "License"); you may 6 | * not use this file except in compliance with the License. You may 7 | * obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | * implied. See the License for the specific language governing 15 | * permissions and limitations under the License. 16 | * 17 | * However, if you have executed another commercial license agreement 18 | * with Crate these terms will supersede the license and you may use the 19 | * software solely pursuant to the terms of the relevant commercial 20 | * agreement. 21 | */ 22 | 23 | package io.crate.client.jdbc; 24 | 25 | import java.sql.Connection; 26 | import java.sql.Driver; 27 | import java.sql.DriverManager; 28 | import java.sql.SQLException; 29 | import java.util.Properties; 30 | 31 | public class CrateDriver extends org.postgresql.Driver { 32 | 33 | private static final String PROTOCOL = "jdbc"; 34 | 35 | private static final String CRATE_PROTOCOL = "crate"; 36 | private static final String CRATE_PREFIX = CRATE_PROTOCOL + ":" + "//"; 37 | private static final String CRATE_PREFIX_LONG = PROTOCOL + ":" + CRATE_PREFIX; 38 | 39 | private static final String PSQL_PROTOCOL = "postgresql"; 40 | private static final String PSQL_PREFIX = PSQL_PROTOCOL + ":" + "//"; 41 | private static final String PSQL_PREFIX_LONG = PROTOCOL + ":" + PSQL_PREFIX; 42 | 43 | private static Driver registeredDriver; 44 | 45 | /** 46 | * Taken from {@link org.postgresql.Driver} 47 | */ 48 | static { 49 | try { 50 | register(); 51 | } catch (SQLException e) { 52 | throw new ExceptionInInitializerError(e); 53 | } 54 | } 55 | 56 | @Override 57 | public Connection connect(String url, Properties info) throws SQLException { 58 | if (!acceptsURL(url)) { 59 | return null; 60 | } 61 | String psqlUrl = processURL(url); 62 | if (psqlUrl == null) { 63 | return null; 64 | } 65 | return super.connect(psqlUrl, info); 66 | } 67 | 68 | /* 69 | * Convert crate:// or jdbc:crate:// URL to jdbc:postgresql:// URL 70 | * Returns null if URL is invalid. 71 | */ 72 | static String processURL(String url) { 73 | if (url.startsWith(CRATE_PREFIX)) { 74 | url = String.format("%s:%s", PROTOCOL, url); 75 | } else if (!url.startsWith(CRATE_PREFIX_LONG)) { 76 | return null; 77 | } 78 | return url.replace(CRATE_PREFIX_LONG, PSQL_PREFIX_LONG); 79 | } 80 | 81 | @Override 82 | public boolean acceptsURL(String url) { 83 | return url.startsWith(CRATE_PREFIX) || url.startsWith(CRATE_PREFIX_LONG); 84 | } 85 | 86 | @Override 87 | public int getMajorVersion() { 88 | return CrateDriverVersion.CURRENT.major; 89 | } 90 | 91 | @Override 92 | public int getMinorVersion() { 93 | return CrateDriverVersion.CURRENT.minor; 94 | } 95 | 96 | @Override 97 | public boolean jdbcCompliant() { 98 | return false; 99 | } 100 | 101 | /** 102 | * Copied from {@link org.postgresql.Driver#register()}. 103 | */ 104 | public static void register() throws SQLException { 105 | if (isRegistered()) { 106 | throw new IllegalStateException( 107 | "Driver is already registered. It can only be registered once."); 108 | } 109 | Driver crateDriver = new CrateDriver(); 110 | DriverManager.registerDriver(crateDriver); 111 | registeredDriver = crateDriver; 112 | } 113 | 114 | /** 115 | * Copied from {@link org.postgresql.Driver#deregister()}. 116 | */ 117 | public static void deregister() throws SQLException { 118 | if (!isRegistered()) { 119 | throw new IllegalStateException( 120 | "Driver is not registered (or it has not been registered using Driver.register() method)"); 121 | } 122 | DriverManager.deregisterDriver(registeredDriver); 123 | registeredDriver = null; 124 | } 125 | 126 | /** 127 | * Copied from {@link org.postgresql.Driver#isRegistered()}. 128 | */ 129 | public static boolean isRegistered() { 130 | return registeredDriver != null; 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /driver/main/java/io/crate/client/jdbc/CrateDriverVersion.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to Crate under one or more contributor license agreements. 3 | * See the NOTICE file distributed with this work for additional 4 | * information regarding copyright ownership. Crate licenses this file 5 | * to you under the Apache License, Version 2.0 (the "License"); you may 6 | * not use this file except in compliance with the License. You may 7 | * obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | * implied. See the License for the specific language governing 15 | * permissions and limitations under the License. 16 | * 17 | * However, if you have executed another commercial license agreement 18 | * with Crate these terms will supersede the license and you may use the 19 | * software solely pursuant to the terms of the relevant commercial 20 | * agreement. 21 | */ 22 | 23 | package io.crate.client.jdbc; 24 | 25 | public class CrateDriverVersion { 26 | 27 | private static final boolean SNAPSHOT = false; 28 | static final CrateDriverVersion CURRENT = new CrateDriverVersion(20700, SNAPSHOT); 29 | 30 | private final int id; 31 | final byte major; 32 | final byte minor; 33 | private final byte revision; 34 | private final Boolean snapshot; 35 | 36 | private CrateDriverVersion(int id, Boolean snapshot) { 37 | this.id = id; 38 | this.major = (byte) ((id / 10000) % 100); 39 | this.minor = (byte) ((id / 100) % 100); 40 | this.revision = (byte) ((id) % 100); 41 | this.snapshot = snapshot; 42 | } 43 | 44 | private boolean snapshot() { 45 | return snapshot != null && snapshot; 46 | } 47 | 48 | /** 49 | * Just the version number (without -SNAPSHOT if snapshot). 50 | */ 51 | private String number() { 52 | return String.valueOf(major) + '.' + minor + '.' + revision; 53 | } 54 | 55 | public static void main(String[] args) { 56 | System.out.println( 57 | "Version: " + CrateDriverVersion.CURRENT + 58 | ", JVM: " + System.getProperty("java.version")); 59 | } 60 | 61 | @Override 62 | public String toString() { 63 | StringBuilder sb = new StringBuilder(); 64 | sb.append(number()); 65 | if (snapshot()) { 66 | sb.append("-SNAPSHOT"); 67 | } 68 | return sb.toString(); 69 | } 70 | 71 | @Override 72 | public boolean equals(Object o) { 73 | if (this == o) return true; 74 | if (o == null || getClass() != o.getClass()) return false; 75 | 76 | CrateDriverVersion version = (CrateDriverVersion) o; 77 | 78 | return id == version.id; 79 | } 80 | 81 | @Override 82 | public int hashCode() { 83 | return id; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /driver/main/resources/META-INF/LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | 204 | 205 | =============================================================================== 206 | 207 | For the `docs` directory: 208 | 209 | The source files for the documentation are licensed under the Apache License 210 | Version 2.0. These source files are used by the project maintainers to build 211 | online documentation for end-users: 212 | 213 | 214 | 215 | If you want to make contributions to the documentation, it may be necessary for 216 | you to build the documentation yourself by following the instructions in the 217 | `DEVELOP.rst` file. If you do this, a number of third-party software components 218 | are necessary. 219 | 220 | We do not ship the source code for these optional third-party software 221 | components or their dependencies, so we cannot make any guarantees about the 222 | licensing status of these components. 223 | 224 | However, for convenience, the documentation build system explicitly references 225 | the following software components (grouped by license): 226 | 227 | PSF License: 228 | 229 | - Python 3 230 | 231 | MIT License: 232 | 233 | - pip 234 | - setuptools 235 | - sphinx-autobuild 236 | 237 | BSD License: 238 | 239 | - alabaster 240 | - sphinx 241 | 242 | Apache License 2.0: 243 | 244 | - crate-docs-theme 245 | 246 | Please note that each of these components may specify its own dependencies and 247 | those dependencies may be licensed differently. 248 | -------------------------------------------------------------------------------- /driver/main/resources/META-INF/services/java.sql.Driver: -------------------------------------------------------------------------------- 1 | io.crate.client.jdbc.CrateDriver 2 | -------------------------------------------------------------------------------- /driver/test/java/io/crate/client/jdbc/CrateDriverTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to CRATE Technology GmbH ("Crate") under one or more contributor 3 | * license agreements. See the NOTICE file distributed with this work for 4 | * additional information regarding copyright ownership. Crate licenses 5 | * this file to you under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. You may 7 | * obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14 | * License for the specific language governing permissions and limitations 15 | * under the License. 16 | * 17 | * However, if you have executed another commercial license agreement 18 | * with Crate these terms will supersede the license and you may use the 19 | * software solely pursuant to the terms of the relevant commercial agreement. 20 | */ 21 | 22 | package io.crate.client.jdbc; 23 | 24 | import org.junit.Test; 25 | 26 | import static org.hamcrest.Matchers.nullValue; 27 | import static org.hamcrest.core.Is.is; 28 | import static org.junit.Assert.assertThat; 29 | 30 | public class CrateDriverTest { 31 | 32 | @Test 33 | public void testProcessUrl() { 34 | assertThat(CrateDriver.processURL("crate://localhost:5432/"), is("jdbc:postgresql://localhost:5432/")); 35 | assertThat(CrateDriver.processURL("jdbc:crate://localhost:5432/"), is("jdbc:postgresql://localhost:5432/")); 36 | assertThat(CrateDriver.processURL("postgres://localhost:5432/"), nullValue()); 37 | assertThat(CrateDriver.processURL("jdbc://postgres://localhost:5432/"), nullValue()); 38 | assertThat(CrateDriver.processURL("foo://localhost:5432/"), nullValue()); 39 | assertThat(CrateDriver.processURL("crate://crate1.local:5432/"), is("jdbc:postgresql://crate1.local:5432/")); 40 | assertThat(CrateDriver.processURL("jdbc:crate://crate1.local:5432/"), is("jdbc:postgresql://crate1.local:5432/")); 41 | } 42 | 43 | @Test 44 | public void testAccepts() { 45 | CrateDriver driver = new CrateDriver(); 46 | 47 | assertThat(driver.acceptsURL("crate://"), is(true)); 48 | assertThat(driver.acceptsURL("crate://localhost/foo"), is(true)); 49 | assertThat(driver.acceptsURL("crate:///foo"), is(true)); 50 | assertThat(driver.acceptsURL("jdbc:crate://"), is(true)); 51 | 52 | assertThat(driver.acceptsURL("cr8://"), is(false)); 53 | assertThat(driver.acceptsURL("mysql://"), is(false)); 54 | assertThat(driver.acceptsURL("jdbc:mysql://"), is(false)); 55 | assertThat(driver.acceptsURL("postgres://"), is(false)); 56 | assertThat(driver.acceptsURL("jdbc:postgres://"), is(false)); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /driver/test/java/io/crate/client/jdbc/PgCrateVersionTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to Crate under one or more contributor license agreements. 3 | * See the NOTICE file distributed with this work for additional 4 | * information regarding copyright ownership. Crate licenses this file 5 | * to you under the Apache License, Version 2.0 (the "License"); you may 6 | * not use this file except in compliance with the License. You may 7 | * obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | * implied. See the License for the specific language governing 15 | * permissions and limitations under the License. 16 | * 17 | * However, if you have executed another commercial license agreement 18 | * with Crate these terms will supersede the license and you may use the 19 | * software solely pursuant to the terms of the relevant commercial 20 | * agreement. 21 | */ 22 | 23 | package io.crate.client.jdbc; 24 | 25 | import org.junit.Test; 26 | import org.postgresql.jdbc.CrateVersion; 27 | 28 | import static org.hamcrest.MatcherAssert.assertThat; 29 | import static org.hamcrest.core.Is.is; 30 | 31 | public class PgCrateVersionTest { 32 | 33 | @Test 34 | public void testAfterCrateVersion() { 35 | assertThat(new CrateVersion("1.0").after("1.0"), is(false)); 36 | assertThat(new CrateVersion("1.0").after("0.57.1"), is(true)); 37 | assertThat(new CrateVersion("1.0.0").after("0.57"), is(true)); 38 | assertThat(new CrateVersion("1.0.0").after("0.57.1"), is(true)); 39 | assertThat(new CrateVersion("1.0.0").after("1.1.1"), is(false)); 40 | } 41 | 42 | @Test 43 | public void testBeforeCrateVersion() { 44 | assertThat(new CrateVersion("1.0").before("1.1"), is(true)); 45 | assertThat(new CrateVersion("1.0").before("0.57.1"), is(false)); 46 | assertThat(new CrateVersion("1.0.0").before("0.57.1"), is(false)); 47 | assertThat(new CrateVersion("0.57.0").before("0.57"), is(false)); 48 | assertThat(new CrateVersion("1.0.0").before("1.1.1"), is(true)); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /driver/test/java/io/crate/client/jdbc/integrationtests/BaseIntegrationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to Crate under one or more contributor license agreements. 3 | * See the NOTICE file distributed with this work for additional 4 | * information regarding copyright ownership. Crate licenses this file 5 | * to you under the Apache License, Version 2.0 (the "License"); you may 6 | * not use this file except in compliance with the License. You may 7 | * obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | * implied. See the License for the specific language governing 15 | * permissions and limitations under the License. 16 | * 17 | * However, if you have executed another commercial license agreement 18 | * with Crate these terms will supersede the license and you may use the 19 | * software solely pursuant to the terms of the relevant commercial 20 | * agreement. 21 | */ 22 | 23 | package io.crate.client.jdbc.integrationtests; 24 | 25 | import com.carrotsearch.randomizedtesting.RandomizedTest; 26 | import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope; 27 | import io.crate.testing.CrateTestCluster; 28 | import io.crate.testing.CrateTestServer; 29 | import org.junit.*; 30 | import org.junit.rules.ExpectedException; 31 | 32 | import java.sql.*; 33 | import java.util.HashMap; 34 | import java.util.Map; 35 | import java.util.Random; 36 | 37 | @ThreadLeakScope(ThreadLeakScope.Scope.SUITE) 38 | public abstract class BaseIntegrationTest extends RandomizedTest { 39 | 40 | private static final String[] CRATE_VERSIONS = new String[] { 41 | "4.8.4", 42 | "5.10.3", 43 | }; 44 | 45 | @Rule 46 | public ExpectedException expectedException = ExpectedException.none(); 47 | 48 | static CrateTestCluster TEST_CLUSTER; 49 | 50 | private static String getRandomServerVersion() { 51 | String version = System.getenv().get("CRATE_VERSION"); 52 | if (version != null) { 53 | return version; 54 | } 55 | Random random = getRandom(); 56 | return CRATE_VERSIONS[random.nextInt(CRATE_VERSIONS.length)]; 57 | } 58 | 59 | @BeforeClass 60 | public static void setUpCluster() throws Throwable { 61 | String downloadUrl = System.getenv().get("CRATE_URL"); 62 | CrateTestCluster.Builder builder; 63 | if (downloadUrl != null) { 64 | builder = CrateTestCluster.fromURL(downloadUrl); 65 | } else { 66 | String filePath = System.getenv().get("CRATE_PATH"); 67 | if (filePath != null) { 68 | builder = CrateTestCluster.fromFile(filePath); 69 | } else { 70 | String versionNumber = System.getenv().get("CRATE_VERSION"); 71 | if (versionNumber != null) { 72 | builder = CrateTestCluster.fromVersion(versionNumber); 73 | } else { 74 | builder = CrateTestCluster.fromVersion(getRandomServerVersion()); 75 | } 76 | } 77 | } 78 | TEST_CLUSTER = builder.keepWorkingDir(false).build(); 79 | TEST_CLUSTER.before(); 80 | } 81 | 82 | @AfterClass 83 | public static void tearDownCluster() { 84 | TEST_CLUSTER.after(); 85 | } 86 | 87 | @Before 88 | public void setUp() throws Exception { 89 | setUpTestTable(); 90 | } 91 | 92 | @After 93 | public void tearDown() { 94 | tearDownTables(); 95 | } 96 | 97 | static String getConnectionString() { 98 | CrateTestServer server = TEST_CLUSTER.randomServer(); 99 | return String.format("crate://%s:%s/doc?user=crate", server.crateHost(), server.psqlPort()); 100 | } 101 | 102 | private static void tearDownTables() { 103 | try (Connection conn = DriverManager.getConnection(getConnectionString())) { 104 | ResultSet rs = conn.createStatement().executeQuery( 105 | "SELECT table_schema, table_name " + 106 | "FROM information_schema.tables " + 107 | "WHERE table_schema not in ('pg_catalog', 'sys', 'information_schema', 'blob')" 108 | ); 109 | while (rs.next()) { 110 | conn.createStatement().execute(String.format( 111 | "DROP TABLE IF EXISTS \"%s\".\"%s\"", rs.getString("table_schema"), rs.getString("table_name") 112 | )); 113 | } 114 | } catch (Exception ignore) { 115 | } 116 | } 117 | 118 | private static void setUpTestTable() throws SQLException, InterruptedException { 119 | try (Connection conn = DriverManager.getConnection(getConnectionString())) { 120 | conn.createStatement().execute( 121 | "create table if not exists test (" + 122 | " id integer primary key," + 123 | " string_field string," + 124 | " boolean_field boolean," + 125 | " byte_field byte," + 126 | " short_field short," + 127 | " integer_field integer," + 128 | " long_field long," + 129 | " float_field float," + 130 | " double_field double," + 131 | " timestamp_field timestamp," + 132 | " object_field object as (\"inner\" string)," + 133 | " ip_field ip," + 134 | " geo_point_field geo_point," + 135 | " geo_shape_field geo_shape" + 136 | ") clustered by (id) into 1 shards with (number_of_replicas=0)"); 137 | } 138 | ensureYellow(); 139 | } 140 | 141 | static void insertIntoTestTable() throws SQLException { 142 | Map objectField = new HashMap() {{ 143 | put("inner", "Zoon"); 144 | }}; 145 | try (Connection conn = DriverManager.getConnection(getConnectionString())) { 146 | PreparedStatement preparedStatement = 147 | conn.prepareStatement("insert into test (id, string_field, boolean_field, byte_field, " + 148 | "short_field, integer_field, long_field, float_field, double_field, object_field, " + 149 | "timestamp_field, ip_field, geo_point_field, geo_shape_field) values " + 150 | "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); 151 | preparedStatement.setInt(1, 1); 152 | preparedStatement.setString(2, "Youri"); 153 | preparedStatement.setBoolean(3, true); 154 | preparedStatement.setByte(4, (byte) 120); 155 | preparedStatement.setShort(5, (short) 1000); 156 | preparedStatement.setInt(6, 1200000); 157 | preparedStatement.setLong(7, 120000000000L); 158 | preparedStatement.setFloat(8, 1.4f); 159 | preparedStatement.setDouble(9, 3.456789); 160 | preparedStatement.setObject(10, objectField); 161 | preparedStatement.setTimestamp(11, new Timestamp(1000L)); 162 | preparedStatement.setString(12, "127.0.0.1"); 163 | preparedStatement.setArray(13, conn.createArrayOf("double", new Double[]{9.7419021d, 47.4048045d})); 164 | preparedStatement.setString(14, "POLYGON ((30 10, 40 40, 20 40, 10 20, 30 10))"); 165 | preparedStatement.execute(); 166 | conn.createStatement().execute("refresh table test"); 167 | } 168 | } 169 | 170 | static void ensureYellow() throws SQLException, InterruptedException { 171 | while (countUnassigned() > 0) { 172 | Thread.sleep(100); 173 | } 174 | } 175 | 176 | private static Long countUnassigned() throws SQLException { 177 | try (Connection conn = DriverManager.getConnection(getConnectionString())) { 178 | ResultSet rs = conn.createStatement() 179 | .executeQuery("SELECT count(*) FROM sys.shards WHERE state != 'STARTED'"); 180 | rs.next(); 181 | return rs.getLong(1); 182 | } 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /driver/test/java/io/crate/client/jdbc/integrationtests/ByPassSpecSettingITest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to Crate under one or more contributor license agreements. 3 | * See the NOTICE file distributed with this work for additional 4 | * information regarding copyright ownership. Crate licenses this file 5 | * to you under the Apache License, Version 2.0 (the "License"); you may 6 | * not use this file except in compliance with the License. You may 7 | * obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | * implied. See the License for the specific language governing 15 | * permissions and limitations under the License. 16 | * 17 | * However, if you have executed another commercial license agreement 18 | * with Crate these terms will supersede the license and you may use the 19 | * software solely pursuant to the terms of the relevant commercial 20 | * agreement. 21 | */ 22 | 23 | package io.crate.client.jdbc.integrationtests; 24 | 25 | import org.junit.BeforeClass; 26 | import org.junit.Test; 27 | import org.postgresql.util.PSQLException; 28 | 29 | import java.sql.*; 30 | import java.util.Properties; 31 | 32 | import static org.hamcrest.Matchers.is; 33 | import static org.junit.Assert.assertThat; 34 | 35 | public class ByPassSpecSettingITest extends BaseIntegrationTest { 36 | 37 | private static Properties strictProperties = new Properties(); 38 | private static String connectionString; 39 | 40 | @BeforeClass 41 | public static void beforeClass() { 42 | strictProperties.put("strict", "true"); 43 | connectionString = getConnectionString(); 44 | } 45 | 46 | @Test 47 | public void testSetAutoCommitStrictFalse() throws SQLException { 48 | Connection connection = DriverManager.getConnection(connectionString); 49 | 50 | connection.setAutoCommit(false); 51 | assertThat(connection.getAutoCommit(), is(false)); 52 | 53 | connection.setAutoCommit(true); 54 | assertThat(connection.getAutoCommit(), is(true)); 55 | connection.close(); 56 | } 57 | 58 | @Test 59 | public void testCommitStrictFalse() throws SQLException { 60 | Connection connection = DriverManager.getConnection(connectionString); 61 | connection.commit(); 62 | assertThat(connection.getAutoCommit(), is(true)); 63 | connection.close(); 64 | } 65 | 66 | @Test 67 | public void testSavepointStrictFalse() throws SQLException { 68 | Connection connection = DriverManager.getConnection(connectionString); 69 | Savepoint savepoint = connection.setSavepoint("savepoint"); 70 | connection.releaseSavepoint(savepoint); 71 | connection.close(); 72 | } 73 | 74 | @Test 75 | public void testRollbackStrictFalse() throws SQLException { 76 | Connection connection = DriverManager.getConnection(connectionString); 77 | connection.rollback(); 78 | connection.rollback(null); 79 | connection.close(); 80 | } 81 | 82 | @Test 83 | public void testSetAutoToTrueCommitStrictTrue() throws SQLException { 84 | Connection connection = DriverManager.getConnection(connectionString, strictProperties); 85 | connection.setAutoCommit(true); 86 | assertThat(connection.getAutoCommit(), is(true)); 87 | connection.close(); 88 | } 89 | 90 | @Test 91 | public void testSetAutoCommitToFalseStrictTrue() throws SQLException { 92 | try(Connection connection = DriverManager.getConnection(connectionString, strictProperties)) { 93 | expectedException.expect(SQLFeatureNotSupportedException.class); 94 | expectedException.expectMessage("The auto-commit mode cannot be disabled in strict mode. The Crate JDBC driver does not support manual commit."); 95 | connection.setAutoCommit(false); 96 | } 97 | } 98 | 99 | @Test 100 | public void testCommitWhenAutoCommitIsTrueStrictTrue() throws SQLException { 101 | try(Connection connection = DriverManager.getConnection(connectionString, strictProperties)) { 102 | connection.setAutoCommit(true); 103 | expectedException.expect(SQLFeatureNotSupportedException.class); 104 | expectedException.expectMessage("The commit operation is not allowed. The Crate JDBC driver does not support manual commit."); 105 | connection.commit(); // cannot commit in a strict mode if auto-commit is set to true 106 | } 107 | } 108 | 109 | @Test 110 | public void testSetSavepointStrictTrue() throws SQLException { 111 | try(Connection connection = DriverManager.getConnection(connectionString, strictProperties)) { 112 | expectedException.expect(SQLFeatureNotSupportedException.class); 113 | expectedException.expectMessage("Savepoint is not supported."); 114 | connection.setSavepoint("savepoint"); 115 | } 116 | } 117 | 118 | @Test 119 | public void testRollbackSavepointStrictTrue() throws SQLException { 120 | try(Connection connection = DriverManager.getConnection(connectionString, strictProperties)) { 121 | expectedException.expect(SQLFeatureNotSupportedException.class); 122 | expectedException.expectMessage("Rollback is not supported."); 123 | connection.rollback(null); 124 | } 125 | } 126 | 127 | @Test 128 | public void testReleaseSavepointStrictTrue() throws SQLException { 129 | try(Connection connection = DriverManager.getConnection(connectionString, strictProperties)) { 130 | expectedException.expect(SQLFeatureNotSupportedException.class); 131 | expectedException.expectMessage("Savepoint is not supported."); 132 | connection.releaseSavepoint(null); 133 | } 134 | } 135 | 136 | @Test 137 | public void testRollbackStrictTrue() throws SQLException { 138 | try(Connection connection = DriverManager.getConnection(connectionString, strictProperties)) { 139 | expectedException.expect(SQLFeatureNotSupportedException.class); 140 | expectedException.expectMessage("Rollback is not supported."); 141 | connection.rollback(); 142 | } 143 | } 144 | 145 | @Test 146 | public void testSupportsTransactionsStrictFalse() throws SQLException { 147 | Connection connection = DriverManager.getConnection(connectionString); 148 | DatabaseMetaData metadata = connection.getMetaData(); 149 | assertThat(metadata.supportsTransactions(), is (true)); 150 | connection.close(); 151 | } 152 | 153 | @Test 154 | public void testSupportsTransactionsStrictTrue() throws SQLException { 155 | Connection connection = DriverManager.getConnection(connectionString, strictProperties); 156 | DatabaseMetaData metadata = connection.getMetaData(); 157 | assertThat(metadata.supportsTransactions(), is (false)); 158 | connection.close(); 159 | } 160 | 161 | @Test 162 | public void testGetDefaultTransactionIsolationReadCommittedStrictFalse() throws SQLException { 163 | Connection connection = DriverManager.getConnection(connectionString); 164 | DatabaseMetaData metadata = connection.getMetaData(); 165 | assertThat(metadata.getDefaultTransactionIsolation(), is (Connection.TRANSACTION_READ_COMMITTED)); 166 | connection.close(); 167 | } 168 | 169 | @Test 170 | public void testGetDefaultTransactionIsolationStrictTrue() throws SQLException { 171 | Connection connection = DriverManager.getConnection(connectionString, strictProperties); 172 | DatabaseMetaData metadata = connection.getMetaData(); 173 | assertThat(metadata.getDefaultTransactionIsolation(), is (Connection.TRANSACTION_NONE)); 174 | connection.close(); 175 | } 176 | 177 | @Test 178 | public void testSupportsTransactionIsolationLevelStrictFalse() throws SQLException { 179 | Connection connection = DriverManager.getConnection(connectionString); 180 | DatabaseMetaData metadata = connection.getMetaData(); 181 | assertThat(metadata.supportsTransactionIsolationLevel(Connection.TRANSACTION_NONE), is (false)); 182 | assertThat(metadata.supportsTransactionIsolationLevel(Connection.TRANSACTION_READ_UNCOMMITTED), is (true)); 183 | assertThat(metadata.supportsTransactionIsolationLevel(Connection.TRANSACTION_READ_COMMITTED), is (true)); 184 | assertThat(metadata.supportsTransactionIsolationLevel(Connection.TRANSACTION_REPEATABLE_READ), is (true)); 185 | assertThat(metadata.supportsTransactionIsolationLevel(Connection.TRANSACTION_SERIALIZABLE), is (true)); 186 | connection.close(); 187 | } 188 | 189 | @Test 190 | public void testSupportsTransactionIsolationLevelStrictTrue() throws SQLException { 191 | Connection connection = DriverManager.getConnection(connectionString, strictProperties); 192 | DatabaseMetaData metadata = connection.getMetaData(); 193 | assertThat(metadata.supportsTransactionIsolationLevel(Connection.TRANSACTION_NONE), is (true)); 194 | assertThat(metadata.supportsTransactionIsolationLevel(Connection.TRANSACTION_READ_UNCOMMITTED), is (false)); 195 | assertThat(metadata.supportsTransactionIsolationLevel(Connection.TRANSACTION_READ_COMMITTED), is (false)); 196 | assertThat(metadata.supportsTransactionIsolationLevel(Connection.TRANSACTION_REPEATABLE_READ), is (false)); 197 | assertThat(metadata.supportsTransactionIsolationLevel(Connection.TRANSACTION_SERIALIZABLE), is (false)); 198 | connection.close(); 199 | } 200 | 201 | @Test 202 | public void testSupportsDataDefinitionAndDataManipulationTransactionsStrictFalse() throws SQLException { 203 | Connection connection = DriverManager.getConnection(connectionString); 204 | DatabaseMetaData metadata = connection.getMetaData(); 205 | assertThat(metadata.supportsDataDefinitionAndDataManipulationTransactions(), is (true)); 206 | connection.close(); 207 | } 208 | 209 | @Test 210 | public void testSupportsDataDefinitionAndDataManipulationTransactionsStrictTrue() throws SQLException { 211 | Connection connection = DriverManager.getConnection(connectionString, strictProperties); 212 | DatabaseMetaData metadata = connection.getMetaData(); 213 | assertThat(metadata.supportsDataDefinitionAndDataManipulationTransactions(), is (false)); 214 | connection.close(); 215 | } 216 | 217 | @Test 218 | public void testSetReadOnlyStrictTrue() throws SQLException { 219 | try (Connection connection = DriverManager.getConnection(connectionString, 220 | strictProperties)) { 221 | expectedException.expect(SQLFeatureNotSupportedException.class); 222 | expectedException.expectMessage( 223 | "Setting transaction isolation READ ONLY not supported."); 224 | connection.setReadOnly(true); 225 | } 226 | } 227 | 228 | @Test 229 | public void testGetConnectionStrictTrueReadOnlyTrue() throws Exception { 230 | Properties readOnlyStrictProperties = new Properties(); 231 | readOnlyStrictProperties.setProperty("strict", "true"); 232 | readOnlyStrictProperties.setProperty("readOnly", "true"); 233 | 234 | expectedException.expect(PSQLException.class); 235 | expectedException.expectMessage("Read-only connections are not supported."); 236 | DriverManager.getConnection(connectionString, readOnlyStrictProperties); 237 | } 238 | 239 | } 240 | 241 | -------------------------------------------------------------------------------- /driver/test/java/io/crate/client/jdbc/integrationtests/ConnectionITest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to Crate under one or more contributor license agreements. 3 | * See the NOTICE file distributed with this work for additional 4 | * information regarding copyright ownership. Crate licenses this file 5 | * to you under the Apache License, Version 2.0 (the "License"); you may 6 | * not use this file except in compliance with the License. You may 7 | * obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | * implied. See the License for the specific language governing 15 | * permissions and limitations under the License. 16 | * 17 | * However, if you have executed another commercial license agreement 18 | * with Crate these terms will supersede the license and you may use the 19 | * software solely pursuant to the terms of the relevant commercial 20 | * agreement. 21 | */ 22 | 23 | package io.crate.client.jdbc.integrationtests; 24 | 25 | import io.crate.testing.CrateTestServer; 26 | import org.hamcrest.Matchers; 27 | import org.junit.Ignore; 28 | import org.junit.Test; 29 | import org.postgresql.jdbc.CrateVersion; 30 | import org.postgresql.jdbc.PgDatabaseMetaData; 31 | import org.postgresql.util.PSQLException; 32 | 33 | import java.sql.BatchUpdateException; 34 | import java.sql.Connection; 35 | import java.sql.DriverManager; 36 | import java.sql.PreparedStatement; 37 | import java.sql.ResultSet; 38 | import java.sql.SQLException; 39 | import java.sql.Statement; 40 | import java.sql.Timestamp; 41 | 42 | import static com.google.common.collect.Maps.newHashMap; 43 | import static org.hamcrest.Matchers.anyOf; 44 | import static org.hamcrest.Matchers.containsString; 45 | import static org.hamcrest.Matchers.instanceOf; 46 | import static org.hamcrest.Matchers.notNullValue; 47 | import static org.hamcrest.core.Is.is; 48 | import static org.junit.Assert.assertArrayEquals; 49 | import static org.junit.Assert.assertFalse; 50 | import static org.junit.Assert.assertThat; 51 | import static org.junit.Assert.assertTrue; 52 | import static org.junit.Assert.fail; 53 | 54 | public class ConnectionITest extends BaseIntegrationTest { 55 | 56 | @Test 57 | public void testConnectionWithCustomSchema() throws SQLException, InterruptedException { 58 | try (Connection conn = DriverManager.getConnection(getConnectionString())) { 59 | conn.setSchema("foo"); 60 | assertThat(conn.getSchema(), is("foo")); 61 | 62 | Statement stmt = conn.createStatement(); 63 | stmt.execute("CREATE TABLE t (name STRING) WITH (number_of_replicas=0)"); 64 | ensureYellow(); 65 | 66 | ResultSet rs = stmt.executeQuery( 67 | "SELECT table_schema " + 68 | "FROM information_schema.TABLES " + 69 | "WHERE table_name = 't'" 70 | ); 71 | 72 | assertThat(rs.next(), is(true)); 73 | assertThat(rs.getObject(1), is("foo")); 74 | assertThat(rs.next(), is(false)); 75 | } 76 | } 77 | 78 | @Test 79 | public void testConnectionWithCustomSchemaPrepareStatement() throws Exception { 80 | try (Connection conn = DriverManager.getConnection(getConnectionString())) { 81 | conn.setSchema("bar"); 82 | 83 | PreparedStatement stmt = conn.prepareStatement( 84 | "CREATE TABLE t (id INTEGER) WITH (number_of_replicas=0)"); 85 | assertThat(stmt.execute(), is(false)); 86 | ensureYellow(); 87 | 88 | ResultSet rs = conn.createStatement().executeQuery( 89 | "SELECT table_schema " + 90 | "FROM information_schema.TABLES " + 91 | "WHERE table_name = 't'" 92 | ); 93 | 94 | assertThat(rs.next(), is(true)); 95 | assertThat(rs.getObject(1), is("bar")); 96 | assertThat(rs.next(), is(false)); 97 | } 98 | } 99 | 100 | @Test 101 | public void testSelectWithoutResultUsingPreparedStatement() throws Exception { 102 | try (Connection conn = DriverManager.getConnection(getConnectionString())) { 103 | PreparedStatement preparedStatement = conn.prepareStatement("select * from test where id = ?"); 104 | preparedStatement.setInt(1, 2); 105 | ResultSet resultSet = preparedStatement.executeQuery(); 106 | 107 | assertThat(resultSet, notNullValue()); 108 | assertThat(resultSet.isBeforeFirst(), is(false)); 109 | } 110 | } 111 | 112 | @Test 113 | public void testSelectUsingPreparedStatement() throws Exception { 114 | insertIntoTestTable(); 115 | try (Connection conn = DriverManager.getConnection(getConnectionString())) { 116 | PreparedStatement preparedStatement = conn.prepareStatement("select * from test where id = ?"); 117 | preparedStatement.setInt(1, 1); 118 | ResultSet resultSet = preparedStatement.executeQuery(); 119 | 120 | assertThat(resultSet.next(), is(true)); 121 | assertThat(resultSet.getInt("id"), is(1)); 122 | assertThat(resultSet.getString("string_field"), is("Youri")); 123 | assertThat(resultSet.getBoolean("boolean_field"), is(true)); 124 | assertThat(resultSet.getByte("byte_field"), is(new Byte("120"))); 125 | assertThat(resultSet.getShort("short_field"), is(new Short("1000"))); 126 | assertThat(resultSet.getInt("integer_field"), is(1200000)); 127 | assertThat(resultSet.getLong("long_field"), is(120000000000L)); 128 | assertThat(resultSet.getFloat("float_field"), is(1.4f)); 129 | assertThat(resultSet.getDouble("double_field"), is(3.456789d)); 130 | assertThat(resultSet.getTimestamp("timestamp_field"), is(new Timestamp(1000L))); 131 | assertThat(resultSet.getString("ip_field"), is("127.0.0.1")); 132 | assertThat(resultSet.next(), is(false)); 133 | } 134 | } 135 | 136 | @Test 137 | public void testException() throws Exception { 138 | try (Connection conn = DriverManager.getConnection(getConnectionString())) { 139 | expectedException.expect(anyOf(instanceOf(SQLException.class), instanceOf(PSQLException.class))); 140 | expectedException.expectMessage(anyOf( 141 | containsString("line 1:1: no viable alternative at input 'ERROR'"), 142 | containsString("line 1:1: mismatched input 'ERROR' expecting {'SELECT', '")) 143 | ); 144 | conn.createStatement().execute("ERROR"); 145 | } 146 | } 147 | 148 | @Test 149 | public void testExecuteBatchStatement() throws Exception { 150 | try (Connection conn = DriverManager.getConnection(getConnectionString())) { 151 | Statement stmt = conn.createStatement(); 152 | stmt.addBatch("insert into test (id) values (3)"); 153 | stmt.addBatch("insert into test (id) values (4)"); 154 | 155 | int[] results = stmt.executeBatch(); 156 | assertArrayEquals(results, new int[]{1, 1}); 157 | conn.createStatement().execute("refresh table test"); 158 | ResultSet resultSet = conn.createStatement().executeQuery("select count(*) from test"); 159 | assertThat(resultSet.next(), is(true)); 160 | assertThat(resultSet.getLong(1), is(2L)); 161 | } 162 | } 163 | 164 | @Test 165 | @Ignore("validate batch behaviour") 166 | public void testExecuteBatchStatementFail() throws Exception { 167 | try (Connection conn = DriverManager.getConnection(getConnectionString())) { 168 | Statement stmt = conn.createStatement(); 169 | stmt.addBatch("insert into test (id) values (3)"); 170 | stmt.addBatch("insert into test (id) values (5)"); 171 | stmt.addBatch("select * from sys.cluster"); 172 | 173 | try { 174 | stmt.executeBatch(); 175 | fail("BatchUpdateException not thrown"); 176 | } catch (BatchUpdateException e) { 177 | assertArrayEquals(e.getUpdateCounts(), new int[]{1, 1, Statement.EXECUTE_FAILED}); 178 | } 179 | conn.createStatement().execute("refresh table test"); 180 | ResultSet resultSet = conn.createStatement().executeQuery("select count(*) from test"); 181 | assertThat(resultSet.next(), is(true)); 182 | assertThat(resultSet.getLong(1), is(3L)); 183 | } 184 | } 185 | 186 | @Test 187 | public void testExecuteBatchPreparedStatement() throws Exception { 188 | try (Connection conn = DriverManager.getConnection(getConnectionString())) { 189 | PreparedStatement stmt = conn.prepareStatement("insert into test (id) values (?)"); 190 | stmt.setInt(1, 2); 191 | stmt.addBatch(); 192 | 193 | stmt.setInt(1, 4); 194 | stmt.addBatch(); 195 | 196 | int[] results = stmt.executeBatch(); 197 | assertArrayEquals(new int[]{1, 1}, results); 198 | conn.createStatement().execute("refresh table test"); 199 | ResultSet resultSet = conn.createStatement().executeQuery("select count(*) from test"); 200 | assertThat(resultSet.next(), is(true)); 201 | assertThat(resultSet.getLong(1), is(2L)); 202 | } 203 | } 204 | 205 | @Test 206 | public void testExecuteBatchPreparedStatementFailBulkTypes() throws Exception { 207 | try (Connection conn = DriverManager.getConnection(getConnectionString())) { 208 | PreparedStatement stmt = conn.prepareStatement("insert into test (id) values (?)"); 209 | stmt.setObject(1, newHashMap()); 210 | stmt.addBatch(); 211 | PgDatabaseMetaData metaData = (PgDatabaseMetaData) conn.getMetaData(); 212 | 213 | try { 214 | stmt.executeBatch(); 215 | fail("BatchUpdateException not thrown"); 216 | } catch (BatchUpdateException e) { 217 | String msg = e.getMessage(); 218 | 219 | CrateVersion version = metaData.getCrateVersion(); // Don't query version several times. 220 | if (version.compareTo("4.7.0") >= 0) { 221 | assertThat(msg, containsString("Cannot cast value `{}` to type `integer`")); 222 | } else if (version.compareTo("4.2.0") >= 0) { 223 | assertThat(msg, Matchers.allOf( 224 | containsString("The type 'object' of the insert source "), 225 | containsString("is not convertible to the type 'integer' of target column 'id'")) 226 | ); 227 | } else if (metaData.getCrateVersion().before("2.3.4")) { 228 | assertThat(msg, containsString("Validation failed for id: {} cannot be cast to type integer")); 229 | } else { 230 | assertThat(msg, containsString("Validation failed for id: Cannot cast {} to type integer")); 231 | } 232 | assertArrayEquals(new int[]{Statement.EXECUTE_FAILED}, e.getUpdateCounts()); 233 | } 234 | conn.createStatement().execute("refresh table test"); 235 | ResultSet resultSet = conn.createStatement().executeQuery("select count(*) from test"); 236 | assertThat(resultSet.next(), is(true)); 237 | assertThat(resultSet.getLong(1), is(0L)); 238 | } 239 | } 240 | 241 | @Test 242 | @Ignore 243 | public void testExecuteBatchPreparedStatementFailOne() throws Exception { 244 | try (Connection conn = DriverManager.getConnection(getConnectionString())) { 245 | PreparedStatement stmt = conn.prepareStatement("insert into test (id, string_field) values (?, ?)"); 246 | stmt.setInt(1, 2); 247 | stmt.setString(2, "foo"); 248 | stmt.addBatch(); 249 | 250 | stmt.setInt(1, 1); 251 | stmt.setObject(2, "baz"); 252 | stmt.addBatch(); 253 | 254 | int[] results = stmt.executeBatch(); 255 | assertArrayEquals(new int[]{1, Statement.EXECUTE_FAILED}, results); 256 | conn.createStatement().execute("refresh table test"); 257 | ResultSet resultSet = conn.createStatement().executeQuery("select count(*) from test"); 258 | assertThat(resultSet.next(), is(true)); 259 | assertThat(resultSet.getLong(1), is(2L)); 260 | } 261 | } 262 | 263 | @Test 264 | public void testExecuteBatchPreparedStatementFailSyntax() throws Exception { 265 | try (Connection conn = DriverManager.getConnection(getConnectionString())) { 266 | PreparedStatement stmt = conn.prepareStatement("insert test (id) values (?)"); 267 | stmt.setInt(1, 2); 268 | stmt.addBatch(); 269 | 270 | try { 271 | stmt.executeBatch(); 272 | fail("BatchUpdateException not thrown"); 273 | } catch (BatchUpdateException e) { 274 | assertArrayEquals(new int[]{Statement.EXECUTE_FAILED}, e.getUpdateCounts()); 275 | } 276 | conn.createStatement().execute("refresh table test"); 277 | ResultSet resultSet = conn.createStatement().executeQuery("select count(*) from test"); 278 | assertThat(resultSet.next(), is(true)); 279 | assertThat(resultSet.getLong(1), is(0L)); 280 | } 281 | } 282 | 283 | @Test 284 | public void testSelectWhenNothingMatches() throws Exception { 285 | try (Connection conn = DriverManager.getConnection(getConnectionString())) { 286 | assertTrue(conn.createStatement().execute("select * from test where id = 1000000")); 287 | } 288 | } 289 | 290 | @Test 291 | public void testExecuteUpdateWhenNothingMatches() throws Exception { 292 | try (Connection conn = DriverManager.getConnection(getConnectionString())) { 293 | assertThat(conn.createStatement().executeUpdate("update test set string_field = 'new_value' " + 294 | "where string_field = 'nothing_matches_this'"), is(0)); 295 | } 296 | } 297 | 298 | @Test 299 | public void testMultipleHostsConnectionString() throws Exception { 300 | CrateTestServer server = TEST_CLUSTER.randomServer(); 301 | String connectionStr = String.format( 302 | "crate://%s:%s,%s:%s/doc?user=crate", server.crateHost(), server.psqlPort(), server.crateHost(), server.psqlPort() 303 | ); 304 | try (Connection conn = DriverManager.getConnection(connectionStr)) { 305 | assertThat(conn.createStatement().execute("select 1 from sys.cluster"), is(true)); 306 | } 307 | } 308 | 309 | @Test 310 | public void testGetMoreResults() throws Exception { 311 | /** 312 | * getMoreResults() always returns false, because CrateDB does not support multiple result sets. 313 | * In Postgres multiple result sets may occur when executing multiple statements (separated by ;) or when 314 | * calling stored procedures. 315 | */ 316 | try (Connection conn = DriverManager.getConnection(getConnectionString())) { 317 | Statement stmt = conn.createStatement(); 318 | assertTrue(stmt.execute("select name from sys.nodes")); 319 | assertFalse(stmt.getMoreResults()); 320 | } 321 | } 322 | } -------------------------------------------------------------------------------- /driver/test/java/io/crate/client/jdbc/integrationtests/DriverITest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to Crate under one or more contributor license agreements. 3 | * See the NOTICE file distributed with this work for additional 4 | * information regarding copyright ownership. Crate licenses this file 5 | * to you under the Apache License, Version 2.0 (the "License"); you may 6 | * not use this file except in compliance with the License. You may 7 | * obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | * implied. See the License for the specific language governing 15 | * permissions and limitations under the License. 16 | * 17 | * However, if you have executed another commercial license agreement 18 | * with Crate these terms will supersede the license and you may use the 19 | * software solely pursuant to the terms of the relevant commercial 20 | * agreement. 21 | */ 22 | 23 | package io.crate.client.jdbc.integrationtests; 24 | 25 | import io.crate.client.jdbc.CrateDriver; 26 | import io.crate.testing.CrateTestServer; 27 | import org.junit.BeforeClass; 28 | import org.junit.Ignore; 29 | import org.junit.Test; 30 | import org.postgresql.PGConnection; 31 | 32 | import java.sql.Connection; 33 | import java.sql.DriverManager; 34 | import java.sql.SQLException; 35 | import java.util.Properties; 36 | 37 | import static org.hamcrest.CoreMatchers.instanceOf; 38 | import static org.hamcrest.Matchers.nullValue; 39 | import static org.hamcrest.core.Is.is; 40 | import static org.hamcrest.core.StringContains.containsString; 41 | import static org.junit.Assert.assertFalse; 42 | import static org.junit.Assert.assertThat; 43 | import static org.junit.Assert.assertTrue; 44 | 45 | public class DriverITest extends BaseIntegrationTest { 46 | 47 | private static CrateDriver DRIVER; 48 | private static final Properties PROP; 49 | 50 | static { 51 | PROP = new Properties(); 52 | PROP.setProperty("user", "crate"); 53 | } 54 | 55 | private static String HOST_AND_PORT; 56 | 57 | @BeforeClass 58 | public static void beforeClass() { 59 | DRIVER = new CrateDriver(); 60 | CrateTestServer server = TEST_CLUSTER.randomServer(); 61 | HOST_AND_PORT = String.format("%s:%s", server.crateHost(), server.psqlPort()); 62 | } 63 | 64 | @Test 65 | public void testDriverRegistration() throws Exception { 66 | Connection c1 = DriverManager.getConnection("crate://" + HOST_AND_PORT + "/doc?user=crate"); 67 | assertThat(c1, instanceOf(PGConnection.class)); 68 | c1.close(); 69 | 70 | Connection c2 = DriverManager.getConnection("jdbc:crate://" + HOST_AND_PORT + "/doc?user=crate"); 71 | assertThat(c1, instanceOf(PGConnection.class)); 72 | c2.close(); 73 | 74 | expectedException.expect(SQLException.class); 75 | expectedException.expectMessage( 76 | containsString(String.format("No suitable driver found for %s", "jdbc:mysql://" + HOST_AND_PORT + "/"))); 77 | DriverManager.getConnection("jdbc:mysql://" + HOST_AND_PORT + "/"); 78 | } 79 | 80 | @Test 81 | public void testDriverRegistrationDoesNotOverridePostgres() throws Exception { 82 | expectedException.expect(SQLException.class); 83 | expectedException.expectMessage( 84 | containsString(String.format("No suitable driver found for %s", "jdbc:postgresql://" + HOST_AND_PORT + "/"))); 85 | DriverManager.getConnection("jdbc:postgresql://" + HOST_AND_PORT + "/"); 86 | } 87 | 88 | private void assertInstanceOfCrateConnection(String connString, Properties prop) throws SQLException { 89 | try (Connection conn = DRIVER.connect(connString, prop)) { 90 | assertThat(conn, instanceOf(PGConnection.class)); 91 | assertFalse(conn.isClosed()); 92 | assertTrue(conn.isValid(0)); 93 | } 94 | } 95 | 96 | private void assertConnectionIsNull(String connString, Properties prop) throws SQLException { 97 | try (Connection conn = DRIVER.connect(connString, prop)) { 98 | assertThat(conn, is(nullValue())); 99 | } 100 | } 101 | 102 | @Test 103 | public void testConnectDriver() throws Exception { 104 | assertInstanceOfCrateConnection("jdbc:crate://" + HOST_AND_PORT + "/", PROP); 105 | assertInstanceOfCrateConnection("crate://" + HOST_AND_PORT + "/", PROP); 106 | 107 | assertInstanceOfCrateConnection("jdbc:crate://" + HOST_AND_PORT + "/db", PROP); 108 | assertInstanceOfCrateConnection("crate://" + HOST_AND_PORT + "/db", PROP); 109 | 110 | assertInstanceOfCrateConnection("jdbc:crate://" + HOST_AND_PORT + "/db?asdf=abcd", PROP); 111 | assertInstanceOfCrateConnection("crate://" + HOST_AND_PORT + "/db?asdf=abcd", PROP); 112 | 113 | assertConnectionIsNull("crt://" + HOST_AND_PORT + "/", PROP); 114 | assertConnectionIsNull("jdbc:mysql://" + HOST_AND_PORT + "/", PROP); 115 | assertConnectionIsNull("crate://" + HOST_AND_PORT, PROP); 116 | } 117 | 118 | @Test 119 | @Ignore("set/get schema is not implemented") 120 | public void testClientPropertyUrlParser() throws Exception { 121 | Connection conn = DriverManager.getConnection("crate://" + HOST_AND_PORT + "/?prop1=value1&prop2=value2"); 122 | Properties properties = conn.getClientInfo(); 123 | assertThat(properties.size(), is(2)); 124 | assertThat(properties.getProperty("prop1"), is("value1")); 125 | assertThat(properties.getProperty("prop2"), is("value2")); 126 | conn.close(); 127 | } 128 | 129 | @Test 130 | @Ignore 131 | public void testNullProperty() throws Exception { 132 | Connection conn = DriverManager.getConnection("crate://" + HOST_AND_PORT); 133 | conn.setClientInfo(null); 134 | conn.close(); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /driver/test/java/io/crate/client/jdbc/integrationtests/FetchSizeITest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to CRATE Technology GmbH ("Crate") under one or more contributor 3 | * license agreements. See the NOTICE file distributed with this work for 4 | * additional information regarding copyright ownership. Crate licenses 5 | * this file to you under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. You may 7 | * obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14 | * License for the specific language governing permissions and limitations 15 | * under the License. 16 | * 17 | * However, if you have executed another commercial license agreement 18 | * with Crate these terms will supersede the license and you may use the 19 | * software solely pursuant to the terms of the relevant commercial agreement. 20 | */ 21 | 22 | package io.crate.client.jdbc.integrationtests; 23 | 24 | import org.junit.Test; 25 | import org.postgresql.core.*; 26 | 27 | import java.lang.reflect.Field; 28 | import java.sql.*; 29 | import java.util.List; 30 | 31 | import static org.junit.Assert.assertEquals; 32 | 33 | 34 | /** 35 | * We are allowed to disable autoCommit (= manual commit) if strict mode is not enabled. 36 | * Manual commit is required for {@link org.postgresql.jdbc.PgStatement#setFetchSize(int)} to work correctly! 37 | * If autoCommit is true {@link org.postgresql.jdbc.PgStatement#executeInternal(CachedQuery, ParameterList, int)} 38 | * will never set the QueryExecutor.QUERY_FORWARD_CURSOR flag and therefore fetch all results at once instead of 39 | * batching them. 40 | */ 41 | public class FetchSizeITest extends BaseIntegrationTest { 42 | 43 | /** 44 | * fetch size and execution flag is correctly appied if autoCommit == false 45 | */ 46 | @Test 47 | public void testFetchSizeNotIgnoredIfManualCommit() throws Exception { 48 | try (Connection connection = DriverManager.getConnection(getConnectionString())) { 49 | connection.setAutoCommit(false); 50 | try (Statement statement = connection.createStatement()) { 51 | statement.setFetchSize(10); 52 | statement.execute("select * from sys.summits"); 53 | ResultSet rs = statement.getResultSet(); 54 | assertEquals(10, rs.getFetchSize()); 55 | Field rowsField = rs.getClass().getDeclaredField("rows"); 56 | rowsField.setAccessible(true); 57 | List rows = (List) rowsField.get(rs); 58 | assertEquals(10, rows.size()); 59 | } 60 | } 61 | } 62 | 63 | /* 64 | * fetch size is ignored if autoCommit == true 65 | */ 66 | @Test 67 | public void testFetchSizeIgnoredIfAutocommit() throws Exception { 68 | try (Connection connection = DriverManager.getConnection(getConnectionString())) { 69 | connection.setAutoCommit(true); 70 | try (Statement statement = connection.createStatement()) { 71 | statement.setFetchSize(10); 72 | statement.execute("select * from sys.summits"); 73 | ResultSet rs = statement.getResultSet(); 74 | assertEquals(10, rs.getFetchSize()); 75 | Field rowsField = rs.getClass().getDeclaredField("rows"); 76 | rowsField.setAccessible(true); 77 | List rows = (List) rowsField.get(rs); 78 | assertEquals(1605, rows.size()); 79 | } 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /driver/test/java/io/crate/client/jdbc/integrationtests/MetaDataITest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to Crate under one or more contributor license agreements. 3 | * See the NOTICE file distributed with this work for additional 4 | * information regarding copyright ownership. Crate licenses this file 5 | * to you under the Apache License, Version 2.0 (the "License"); you may 6 | * not use this file except in compliance with the License. You may 7 | * obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | * implied. See the License for the specific language governing 15 | * permissions and limitations under the License. 16 | * 17 | * However, if you have executed another commercial license agreement 18 | * with Crate these terms will supersede the license and you may use the 19 | * software solely pursuant to the terms of the relevant commercial 20 | * agreement. 21 | */ 22 | 23 | package io.crate.client.jdbc.integrationtests; 24 | 25 | import org.junit.Before; 26 | import org.junit.Test; 27 | import org.postgresql.jdbc.CrateVersion; 28 | import org.postgresql.jdbc.PgDatabaseMetaData; 29 | 30 | import java.sql.Connection; 31 | import java.sql.DatabaseMetaData; 32 | import java.sql.DriverManager; 33 | import java.sql.ResultSet; 34 | import java.sql.ResultSetMetaData; 35 | import java.sql.SQLException; 36 | import java.sql.Types; 37 | import java.util.ArrayList; 38 | import java.util.List; 39 | 40 | import static org.hamcrest.CoreMatchers.hasItems; 41 | import static org.hamcrest.CoreMatchers.nullValue; 42 | import static org.hamcrest.Matchers.anyOf; 43 | import static org.hamcrest.Matchers.instanceOf; 44 | import static org.hamcrest.core.Is.is; 45 | import static org.junit.Assert.assertFalse; 46 | import static org.junit.Assert.assertThat; 47 | 48 | public class MetaDataITest extends BaseIntegrationTest { 49 | 50 | private Connection conn; 51 | 52 | @Before 53 | public void setUpTest() throws Throwable { 54 | conn = DriverManager.getConnection(getConnectionString()); 55 | conn.createStatement().execute("create table test.cluster (arr array(int), name string)"); 56 | conn.createStatement().execute("create table doc.names (id int primary key, name string)"); 57 | conn.createStatement().execute("create table my_schema.names (id int primary key, name string)"); 58 | } 59 | 60 | @Test 61 | public void testGetTables() throws SQLException { 62 | DatabaseMetaData metaData = conn.getMetaData(); 63 | ResultSet rs = metaData.getTables("", "sys", "cluster", null); 64 | 65 | assertThat(rs.next(), is(true)); 66 | assertThat(rs.getString("TABLE_SCHEM"), is("sys")); 67 | assertThat(rs.getString("TABLE_NAME"), is("cluster")); 68 | assertThat(rs.getString("TABLE_TYPE"), anyOf(is("SYSTEM TABLE"), is("BASE TABLE"))); 69 | assertThat(rs.next(), is(false)); 70 | } 71 | 72 | @Test 73 | public void testGetTablesWithNullSchema() throws SQLException { 74 | PgDatabaseMetaData metaData = (PgDatabaseMetaData) conn.getMetaData(); 75 | ResultSet rs = metaData.getTables("", null, "clus%", null); 76 | 77 | assertThat(rs.next(), is(true)); 78 | assertThat(rs.getString("TABLE_SCHEM"), is("sys")); 79 | assertThat(rs.getString("TABLE_NAME"), is("cluster")); 80 | assertThat(rs.getString("TABLE_TYPE"), anyOf(is("SYSTEM TABLE"), is("BASE TABLE"))); 81 | 82 | // sys.cluster_health is added to CrateDB 6.0 83 | if (metaData.getCrateVersion().compareTo("6.0.0") >= 0) { 84 | assertThat(rs.next(), is(true)); 85 | assertThat(rs.getString("TABLE_SCHEM"), is("sys")); 86 | assertThat(rs.getString("TABLE_NAME"), is("cluster_health")); 87 | assertThat(rs.getString("TABLE_TYPE"), anyOf(is("SYSTEM TABLE"), is("BASE TABLE"))); 88 | } 89 | 90 | assertThat(rs.next(), is(true)); 91 | assertThat(rs.getString("TABLE_SCHEM"), is("test")); 92 | assertThat(rs.getString("TABLE_NAME"), is("cluster")); 93 | assertThat(rs.getString("TABLE_TYPE"), anyOf(is("TABLE"), is("BASE TABLE"))); 94 | assertThat(rs.next(), is(false)); 95 | } 96 | 97 | @Test 98 | public void testGetTablesWithEmptySchema() throws SQLException { 99 | DatabaseMetaData metaData = conn.getMetaData(); 100 | ResultSet rs = metaData.getTables("", "", "clust%", null); 101 | assertThat(rs.next(), is(false)); 102 | } 103 | 104 | @Test 105 | public void testGetColumns() throws SQLException { 106 | DatabaseMetaData metaData = conn.getMetaData(); 107 | ResultSet rs = metaData.getColumns("", "test", "clus%", "ar%"); 108 | 109 | assertThat(rs.next(), is(true)); 110 | assertThat(rs.getString("TABLE_SCHEM"), is("test")); 111 | assertThat(rs.getString("TABLE_NAME"), is("cluster")); 112 | assertThat(rs.getString("COLUMN_NAME"), is("arr")); 113 | assertThat(rs.getString("TYPE_NAME"), is("integer_array")); 114 | assertThat(rs.getInt("DATA_TYPE"), is(Types.ARRAY)); 115 | assertThat(rs.getInt("ORDINAL_POSITION"), is(1)); 116 | assertThat(rs.next(), is(false)); 117 | } 118 | 119 | @Test 120 | public void testGetColumnsWithEmptySchema() throws SQLException { 121 | DatabaseMetaData metaData = conn.getMetaData(); 122 | ResultSet rs = metaData.getTables("", "", "clust%", null); 123 | assertThat(rs.next(), is(false)); 124 | } 125 | 126 | @Test 127 | public void testGetColumnsWithNullSchema() throws SQLException { 128 | DatabaseMetaData metaData = conn.getMetaData(); 129 | ResultSet rs = metaData.getColumns("", null, "clus%", "name"); 130 | 131 | assertThat(rs.next(), is(true)); 132 | assertThat(rs.getString("TABLE_SCHEM"), is("sys")); 133 | assertThat(rs.getString("TABLE_NAME"), is("cluster")); 134 | assertThat(rs.getString("COLUMN_NAME"), is("name")); 135 | 136 | assertThat(rs.next(), is(true)); 137 | assertThat(rs.getString("TABLE_SCHEM"), is("test")); 138 | assertThat(rs.getString("TABLE_NAME"), is("cluster")); 139 | assertThat(rs.getString("COLUMN_NAME"), is("name")); 140 | assertThat(rs.next(), is(false)); 141 | } 142 | 143 | @Test 144 | public void testGetSchemasWithSchemaPattern() throws SQLException { 145 | DatabaseMetaData metaData = conn.getMetaData(); 146 | ResultSet rs = metaData.getSchemas("", "tes%"); 147 | 148 | assertThat(rs.next(), is(true)); 149 | assertThat(rs.getString("TABLE_SCHEM"), is("test")); 150 | assertThat(rs.getString("TABLE_CAT"), is(nullValue())); 151 | assertThat(rs.next(), is(false)); 152 | } 153 | 154 | @Test 155 | public void testGetSchemasWithNullSchemaPattern() throws SQLException { 156 | DatabaseMetaData metaData = conn.getMetaData(); 157 | ResultSet rs = metaData.getSchemas("", null); 158 | 159 | List schemas = new ArrayList<>(); 160 | while (rs.next()) { 161 | schemas.add(rs.getString("TABLE_SCHEM")); 162 | } 163 | assertThat(schemas, hasItems("sys", "test", "information_schema")); 164 | } 165 | 166 | @Test 167 | 168 | public void testExcludeNestedColumns() throws Exception { 169 | ResultSet resultSet = conn.getMetaData().getColumns(null, "sys", "nodes", null); 170 | while (resultSet.next()) { 171 | assertFalse(resultSet.getString(4).contains(".")); 172 | assertFalse(resultSet.getString(4).contains("[")); 173 | } 174 | } 175 | 176 | @Test 177 | public void testTypesResponseNoResult() throws Exception { 178 | ResultSet result = conn.createStatement().executeQuery("select * from test.cluster where 1=0"); 179 | ResultSetMetaData metaData = result.getMetaData(); 180 | assertThat(metaData.getColumnCount(), is(2)); 181 | for (int i = 1; i <= result.getMetaData().getColumnCount(); i++) { 182 | // test that we can get the types, whatever they are 183 | assertThat(metaData.getColumnType(i), instanceOf(Integer.class)); 184 | } 185 | } 186 | 187 | @Test 188 | public void testGetSchemas() throws Exception { 189 | DatabaseMetaData metaData = conn.getMetaData(); 190 | ResultSet rs = metaData.getSchemas(); 191 | List schemas = new ArrayList<>(); 192 | while (rs.next()) { 193 | schemas.add(rs.getString(1)); 194 | } 195 | assertThat(schemas, hasItems("doc", "sys", "information_schema", "pg_catalog")); 196 | } 197 | 198 | @Test 199 | public void testGetPrimaryKeysPk() throws SQLException { 200 | DatabaseMetaData metaData = conn.getMetaData(); 201 | ResultSet rs = metaData.getPrimaryKeys("", "doc", "names"); 202 | assertThat(rs.next(), is(true)); 203 | assertThat(rs.getString("TABLE_SCHEM"), is("doc")); 204 | assertThat(rs.getString("TABLE_NAME"), is("names")); 205 | assertThat(rs.getString("COLUMN_NAME"), is("id")); 206 | } 207 | 208 | @Test 209 | public void testGetPrimaryKeysNoPk() throws SQLException { 210 | DatabaseMetaData metaData = conn.getMetaData(); 211 | ResultSet rs = metaData.getPrimaryKeys("", "test", "cluster"); 212 | assertThat(rs.next(), is(false)); 213 | } 214 | 215 | @Test 216 | public void testGetPrimaryWithoutSchemaDoesNotFilter() throws SQLException { 217 | DatabaseMetaData metaData = conn.getMetaData(); 218 | ResultSet rs = metaData.getPrimaryKeys("", null, "names"); 219 | assertThat(rs.next(), is(true)); 220 | assertThat(rs.getString("TABLE_SCHEM"), is("doc")); 221 | assertThat(rs.getString("TABLE_NAME"), is("names")); 222 | assertThat(rs.getString("COLUMN_NAME"), is("id")); 223 | assertThat(rs.next(), is(true)); 224 | assertThat(rs.getString("TABLE_SCHEM"), is("my_schema")); 225 | assertThat(rs.getString("TABLE_NAME"), is("names")); 226 | assertThat(rs.getString("COLUMN_NAME"), is("id")); 227 | } 228 | 229 | @Test 230 | public void testGetPrimaryMultiplePks() throws SQLException { 231 | conn.createStatement().execute("create table if not exists t_multi_pks (id int primary key, id2 int primary key, name string)"); 232 | DatabaseMetaData metaData = conn.getMetaData(); 233 | ResultSet rs = metaData.getPrimaryKeys("", "doc", "t_multi_pks"); 234 | assertThat(rs.next(), is(true)); 235 | assertThat(rs.getString("COLUMN_NAME"), is("id")); 236 | assertThat(rs.next(), is(true)); 237 | assertThat(rs.getString("COLUMN_NAME"), is("id2")); 238 | conn.createStatement().execute("drop table t_multi_pks"); 239 | } 240 | 241 | @Test 242 | public void testUnsupportedMethodWithEmptyImpl() throws SQLException { 243 | DatabaseMetaData metaData = conn.getMetaData(); 244 | ResultSet rs = metaData.getPseudoColumns("", "doc", "information_schema", "pg_catalog"); 245 | assertThat(rs.getMetaData().getColumnCount(), is(12)); 246 | assertThat(rs.getMetaData().getColumnName(1), is("TABLE_CAT")); 247 | // The empty result doesn't contain any rows 248 | assertThat(rs.next(), is(false)); 249 | } 250 | } 251 | -------------------------------------------------------------------------------- /driver/test/java/io/crate/client/jdbc/integrationtests/RowCountITest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to CRATE Technology GmbH ("Crate") under one or more contributor 3 | * license agreements. See the NOTICE file distributed with this work for 4 | * additional information regarding copyright ownership. Crate licenses 5 | * this file to you under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. You may 7 | * obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14 | * License for the specific language governing permissions and limitations 15 | * under the License. 16 | * 17 | * However, if you have executed another commercial license agreement 18 | * with Crate these terms will supersede the license and you may use the 19 | * software solely pursuant to the terms of the relevant commercial agreement. 20 | */ 21 | 22 | package io.crate.client.jdbc.integrationtests; 23 | 24 | import org.junit.Test; 25 | 26 | import java.sql.Connection; 27 | import java.sql.DriverManager; 28 | import java.sql.Statement; 29 | 30 | import static org.hamcrest.Matchers.is; 31 | import static org.junit.Assert.assertThat; 32 | 33 | public class RowCountITest extends BaseIntegrationTest { 34 | 35 | @Test 36 | public void testNonDDLRowCount() throws Exception { 37 | try(Connection conn = DriverManager.getConnection(getConnectionString())) { 38 | Statement statement = conn.createStatement(); 39 | assertThat(statement.executeUpdate("create table t (id int)"), is(1)); 40 | } 41 | } 42 | 43 | @Test 44 | public void testUnknownRowCount() throws Exception { 45 | try(Connection conn = DriverManager.getConnection(getConnectionString())) { 46 | Statement statement = conn.createStatement(); 47 | statement.execute("create table t (p string, x int) partitioned by (p)"); 48 | statement.execute("insert into t (p, x) values ('a', 1)"); 49 | statement.execute("refresh table t"); 50 | 51 | assertThat(statement.executeUpdate("delete from t where p = 'a'"), is(-2)); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /driver/test/java/io/crate/client/jdbc/integrationtests/TypesITest.java: -------------------------------------------------------------------------------- 1 | package io.crate.client.jdbc.integrationtests; 2 | 3 | import org.hamcrest.Matchers; 4 | import org.hamcrest.core.Is; 5 | import org.junit.Before; 6 | import org.junit.BeforeClass; 7 | import org.junit.Test; 8 | import org.postgresql.geometric.PGpoint; 9 | import org.postgresql.jdbc.PgDatabaseMetaData; 10 | import org.postgresql.jdbc.PgResultSet; 11 | import org.postgresql.util.PGobject; 12 | 13 | import java.sql.*; 14 | import java.util.Arrays; 15 | import java.util.Collections; 16 | import java.util.HashMap; 17 | import java.util.Map; 18 | 19 | import static org.hamcrest.Matchers.instanceOf; 20 | import static org.hamcrest.core.Is.is; 21 | import static org.junit.Assert.assertEquals; 22 | import static org.junit.Assert.assertThat; 23 | 24 | public class TypesITest extends BaseIntegrationTest { 25 | 26 | private static Connection CONNECTION; 27 | 28 | @BeforeClass 29 | public static void beforeClass() throws SQLException { 30 | CONNECTION = DriverManager.getConnection(getConnectionString()); 31 | } 32 | 33 | @Before 34 | public void setUpTables() throws Exception { 35 | insertIntoTestTable(); 36 | 37 | // set up the table with array datatypes only 38 | setUpArrayTable(); 39 | insertIntoArrayTable(); 40 | } 41 | 42 | private static void setUpArrayTable() throws SQLException, InterruptedException { 43 | String stmt = "create table if not exists arrayTest (" + 44 | " id integer primary key," + 45 | " str_array array(string)," + 46 | " bool_array array(boolean)," + 47 | " byte_array array(byte)," + 48 | " short_array array(short)," + 49 | " integer_array array(integer)," + 50 | " long_array array(long)," + 51 | " float_array array(float)," + 52 | " double_array array(double)," + 53 | " timestamp_array array(timestamp),"; 54 | 55 | // CrateDB < 4.0.0 does not map ip arrays correctly to a pg type 56 | PgDatabaseMetaData metaData = (PgDatabaseMetaData) CONNECTION.getMetaData(); 57 | if (metaData.getCrateVersion().before("4.0.0")) { 58 | stmt = stmt + " ip_array array(string),"; 59 | } else { 60 | stmt = stmt + " ip_array array(ip),"; 61 | } 62 | 63 | stmt = stmt + " obj_array array(object)" + 64 | ") clustered by (id) into 1 shards with (number_of_replicas=0)"; 65 | 66 | CONNECTION.createStatement().execute(stmt); 67 | ensureYellow(); 68 | } 69 | 70 | private static void insertIntoArrayTable() throws SQLException { 71 | PreparedStatement preparedStatement = 72 | CONNECTION.prepareStatement("insert into arrayTest (id, str_array, bool_array, byte_array, " + 73 | "short_array, integer_array, long_array, float_array, double_array, timestamp_array, " + 74 | "ip_array, obj_array) values " + 75 | "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); 76 | preparedStatement.setInt(1, 1); 77 | preparedStatement.setArray(2, CONNECTION.createArrayOf("string", new String[]{"a", "b", "c", "d"})); 78 | preparedStatement.setArray(2, CONNECTION.createArrayOf("string", new String[]{"a", "b", "c", "d"})); 79 | preparedStatement.setArray(3, CONNECTION.createArrayOf("boolean", new Boolean[]{true, false})); 80 | preparedStatement.setArray(4, CONNECTION.createArrayOf("byte", new Byte[]{new Byte("120"), new Byte("100")})); 81 | preparedStatement.setArray(5, CONNECTION.createArrayOf("short", new Short[]{1300, 1200})); 82 | preparedStatement.setArray(6, CONNECTION.createArrayOf("integer", new Integer[]{2147483647, 234583})); 83 | preparedStatement.setArray(7, CONNECTION.createArrayOf("long", new Long[]{9223372036854775806L, 4L})); 84 | preparedStatement.setArray(8, CONNECTION.createArrayOf("float", new Float[]{3.402f, 3.403f, 1.4f})); 85 | preparedStatement.setArray(9, CONNECTION.createArrayOf("double", new Double[]{1.79769313486231570e+308, 1.69769313486231570e+308})); 86 | preparedStatement.setArray(10, CONNECTION.createArrayOf("timestamp", new Timestamp[]{new Timestamp(1000L), new Timestamp(2000L)})); 87 | preparedStatement.setArray(11, CONNECTION.createArrayOf("ip", new String[]{"127.142.132.9", "127.0.0.1"})); 88 | preparedStatement.setArray(12, CONNECTION.createArrayOf("object", new Object[]{ 89 | new HashMap() {{ 90 | put("element1", "testing"); 91 | }}, new HashMap() {{ 92 | put("element2", "testing2"); 93 | }} 94 | })); 95 | preparedStatement.execute(); 96 | CONNECTION.createStatement().execute("refresh table arrayTest"); 97 | } 98 | 99 | @Test 100 | public void testSelectStringType() throws Exception { 101 | ResultSet resultSet = CONNECTION.createStatement().executeQuery("select string_field from test"); 102 | assertThat(resultSet, instanceOf(PgResultSet.class)); 103 | assertThat(resultSet.next(), is(true)); 104 | assertThat(resultSet.getString("string_field"), is("Youri")); 105 | } 106 | 107 | @Test 108 | public void testSelectBooleanType() throws Exception { 109 | ResultSet resultSet = CONNECTION.createStatement().executeQuery("select boolean_field from test"); 110 | assertThat(resultSet, instanceOf(PgResultSet.class)); 111 | assertThat(resultSet.next(), is(true)); 112 | assertThat(resultSet.getBoolean("boolean_field"), is(true)); 113 | } 114 | 115 | @Test 116 | public void testSelectByteType() throws Exception { 117 | ResultSet resultSet = CONNECTION.createStatement().executeQuery("select byte_field from test"); 118 | assertThat(resultSet, instanceOf(PgResultSet.class)); 119 | assertThat(resultSet.next(), is(true)); 120 | assertThat(resultSet.getByte("byte_field"), is(new Byte("120"))); 121 | } 122 | 123 | @Test 124 | public void testSelectShortType() throws Exception { 125 | ResultSet resultSet = CONNECTION.createStatement().executeQuery("select short_field from test"); 126 | assertThat(resultSet, instanceOf(PgResultSet.class)); 127 | assertThat(resultSet.next(), is(true)); 128 | assertThat(resultSet.getShort("short_field"), is(new Short("1000"))); 129 | } 130 | 131 | @Test 132 | public void testSelectIntegerType() throws Exception { 133 | ResultSet resultSet = CONNECTION.createStatement().executeQuery("select integer_field from test"); 134 | assertThat(resultSet, instanceOf(PgResultSet.class)); 135 | assertThat(resultSet.next(), is(true)); 136 | assertThat(resultSet.getInt("integer_field"), is(1200000)); 137 | } 138 | 139 | @Test 140 | public void testSelectLongType() throws Exception { 141 | ResultSet resultSet = CONNECTION.createStatement().executeQuery("select long_field from test"); 142 | assertThat(resultSet, instanceOf(PgResultSet.class)); 143 | assertThat(resultSet.next(), is(true)); 144 | assertThat(resultSet.getLong("long_field"), is(120000000000L)); 145 | } 146 | 147 | @Test 148 | public void testSelectFloatType() throws Exception { 149 | ResultSet resultSet = CONNECTION.createStatement().executeQuery("select float_field from test"); 150 | assertThat(resultSet, instanceOf(PgResultSet.class)); 151 | assertThat(resultSet.next(), is(true)); 152 | assertThat(resultSet.getFloat("float_field"), is(1.4f)); 153 | } 154 | 155 | @Test 156 | public void testSelectDoubleType() throws Exception { 157 | ResultSet resultSet = CONNECTION.createStatement().executeQuery("select double_field from test"); 158 | assertThat(resultSet, instanceOf(PgResultSet.class)); 159 | assertThat(resultSet.next(), is(true)); 160 | assertThat(resultSet.getDouble("double_field"), is(3.456789d)); 161 | } 162 | 163 | @Test 164 | public void testSelectTimestampType() throws Exception { 165 | ResultSet resultSet = CONNECTION.createStatement().executeQuery("select timestamp_field from test"); 166 | assertThat(resultSet, instanceOf(PgResultSet.class)); 167 | assertThat(resultSet.next(), is(true)); 168 | assertThat(resultSet.getTimestamp("timestamp_field"), is(new Timestamp(1000L))); 169 | } 170 | 171 | @Test 172 | public void testSelectIPType() throws Exception { 173 | ResultSet resultSet = CONNECTION.createStatement().executeQuery("select ip_field from test"); 174 | assertThat(resultSet, instanceOf(PgResultSet.class)); 175 | assertThat(resultSet.next(), is(true)); 176 | assertThat(resultSet.getString("ip_field"), is("127.0.0.1")); 177 | } 178 | 179 | @Test 180 | public void testSelectGeoPoint() throws Exception { 181 | ResultSet rs = CONNECTION.createStatement().executeQuery("SELECT geo_point_field FROM test"); 182 | PgDatabaseMetaData metaData = (PgDatabaseMetaData) CONNECTION.getMetaData(); 183 | 184 | assertThat(rs, instanceOf(PgResultSet.class)); 185 | assertThat(rs.next(), is(true)); 186 | // for versions >= 4.1.0 the representation of geo points is changed to a `PGpoint` 187 | // instead of `Double[]`. 188 | if (metaData.getCrateVersion().before("4.1.0")) { 189 | assertThat((Double[]) rs.getArray("geo_point_field").getArray(), 190 | Matchers.arrayContaining(9.7419021d, 47.4048045d)); 191 | } else { 192 | Object geoPoint = rs.getObject("geo_point_field"); 193 | assertThat(geoPoint, Matchers.instanceOf(PGpoint.class)); 194 | PGpoint point = (PGpoint) geoPoint; 195 | assertThat(point.x, Matchers.closeTo(9.7419, 0.001)); 196 | assertThat(point.y, Matchers.closeTo(47.4048, 0.001)); 197 | } 198 | } 199 | 200 | @Test 201 | public void testSelectGeoShape() throws Exception { 202 | ResultSet resultSet = CONNECTION.createStatement().executeQuery("select geo_shape_field from test"); 203 | assertThat(resultSet, instanceOf(PgResultSet.class)); 204 | assertThat(resultSet.next(), is(true)); 205 | assertThat((Map) resultSet.getObject("geo_shape_field"), Is.is(new HashMap(){{ 206 | put("coordinates", Collections.singletonList( 207 | Arrays.asList( 208 | Arrays.asList(30.0, 10.0), 209 | Arrays.asList(40.0, 40.0), 210 | Arrays.asList(20.0, 40.0), 211 | Arrays.asList(10.0, 20.0), 212 | Arrays.asList(30.0, 10.0) 213 | ) 214 | )); 215 | put("type", "Polygon"); 216 | } 217 | })); 218 | assertThat(resultSet.getObject("geo_shape_field", PGobject.class).getValue(), 219 | Matchers.allOf( 220 | Matchers.containsString("\"type\":\"Polygon\""), 221 | Matchers.containsString("\"coordinates\":[[[30.0,10.0],[40.0,40.0],[20.0,40.0],[10.0,20.0],[30.0,10.0]]]") 222 | ) 223 | ); 224 | } 225 | 226 | @Test 227 | public void testSelectStringArrayType() throws Exception { 228 | ResultSet resultSet = CONNECTION.createStatement().executeQuery("select str_array from arrayTest"); 229 | assertThat(resultSet, instanceOf(PgResultSet.class)); 230 | assertThat(resultSet.next(), is(true)); 231 | 232 | Array strArray = resultSet.getArray("str_array"); 233 | assertThat(strArray.getArray().getClass().isArray(), is(true)); 234 | assertThat(strArray.getBaseType(), is(Types.VARCHAR)); 235 | assertThat((Object[]) strArray.getArray(), Matchers.arrayContaining("a", "b", "c", "d")); 236 | } 237 | 238 | @Test 239 | public void testSelectBooleanArrayType() throws Exception { 240 | ResultSet resultSet = CONNECTION.createStatement().executeQuery("select bool_array from arrayTest"); 241 | assertThat(resultSet, instanceOf(PgResultSet.class)); 242 | assertThat(resultSet.next(), is(true)); 243 | 244 | Array boolArray = resultSet.getArray("bool_array"); 245 | assertThat(boolArray.getArray().getClass().isArray(), is(true)); 246 | assertThat(boolArray.getBaseType(), is(Types.BOOLEAN)); 247 | assertThat((Object[]) boolArray.getArray(), Matchers.arrayContaining(true, false)); 248 | } 249 | 250 | @Test 251 | public void testSelectByteArrayType() throws Exception { 252 | ResultSet resultSet = CONNECTION.createStatement().executeQuery("select byte_array from arrayTest"); 253 | assertThat(resultSet, instanceOf(PgResultSet.class)); 254 | assertThat(resultSet.next(), is(true)); 255 | 256 | Array byteArray = resultSet.getArray("byte_array"); 257 | assertThat(byteArray.getArray().getClass().isArray(), is(true)); 258 | assertThat(byteArray.getBaseType(), is(Types.TINYINT)); 259 | assertThat((Object[]) byteArray.getArray(), Matchers.arrayContaining(new Byte("120"), new Byte("100"))); 260 | } 261 | 262 | @Test 263 | public void testSelectShortArrayType() throws Exception { 264 | ResultSet resultSet = CONNECTION.createStatement().executeQuery("select short_array from arrayTest"); 265 | assertThat(resultSet, instanceOf(PgResultSet.class)); 266 | assertThat(resultSet.next(), is(true)); 267 | 268 | Array shortArray = resultSet.getArray("short_array"); 269 | assertThat(shortArray.getArray().getClass().isArray(), is(true)); 270 | assertThat(shortArray.getBaseType(), is(Types.SMALLINT)); 271 | assertThat((Object[]) shortArray.getArray(), Matchers.arrayContaining((short) 1300, (short) 1200)); 272 | } 273 | 274 | @Test 275 | public void testSelectIntegerArrayType() throws Exception { 276 | ResultSet resultSet = CONNECTION.createStatement().executeQuery("select integer_array from arrayTest"); 277 | assertThat(resultSet, instanceOf(PgResultSet.class)); 278 | assertThat(resultSet.next(), is(true)); 279 | 280 | Array integerArray = resultSet.getArray("integer_array"); 281 | assertThat(integerArray.getArray().getClass().isArray(), is(true)); 282 | assertThat(integerArray.getBaseType(), is(Types.INTEGER)); 283 | assertThat((Object[]) integerArray.getArray(), Matchers.arrayContaining(2147483647, 234583)); 284 | } 285 | 286 | @Test 287 | public void testSelectLongArrayType() throws Exception { 288 | ResultSet resultSet = CONNECTION.createStatement().executeQuery("select long_array from arrayTest"); 289 | assertThat(resultSet, instanceOf(PgResultSet.class)); 290 | assertThat(resultSet.next(), is(true)); 291 | 292 | Array longArray = resultSet.getArray("long_array"); 293 | assertThat(longArray.getArray().getClass().isArray(), is(true)); 294 | assertThat(longArray.getBaseType(), is(Types.BIGINT)); 295 | assertThat((Object[]) longArray.getArray(), Matchers.arrayContaining(9223372036854775806L, 4L)); 296 | } 297 | 298 | @Test 299 | public void testSelectFloatArrayType() throws Exception { 300 | ResultSet resultSet = CONNECTION.createStatement().executeQuery("select float_array from arrayTest"); 301 | assertThat(resultSet, instanceOf(PgResultSet.class)); 302 | assertThat(resultSet.next(), is(true)); 303 | 304 | Array floatArray = resultSet.getArray("float_array"); 305 | assertThat(floatArray.getArray().getClass().isArray(), is(true)); 306 | assertThat(floatArray.getBaseType(), is(Types.REAL)); 307 | assertThat((Object[]) floatArray.getArray(), Matchers.arrayContaining(3.402f, 3.403f, 1.4f)); 308 | } 309 | 310 | @Test 311 | public void testSelectDoubleArrayType() throws Exception { 312 | ResultSet resultSet = CONNECTION.createStatement().executeQuery("select double_array from arrayTest"); 313 | assertThat(resultSet, instanceOf(PgResultSet.class)); 314 | assertThat(resultSet.next(), is(true)); 315 | 316 | Array doubleArray = resultSet.getArray("double_array"); 317 | assertThat(doubleArray.getArray().getClass().isArray(), is(true)); 318 | assertThat(doubleArray.getBaseType(), is(Types.DOUBLE)); 319 | assertThat((Object[]) doubleArray.getArray(), Matchers.arrayContaining(1.79769313486231570e+308, 1.69769313486231570e+308)); 320 | } 321 | 322 | @Test 323 | public void testSelectTimestampArrayType() throws Exception { 324 | ResultSet resultSet = CONNECTION.createStatement().executeQuery("select timestamp_array from arrayTest"); 325 | assertThat(resultSet, instanceOf(PgResultSet.class)); 326 | assertThat(resultSet.next(), is(true)); 327 | 328 | Array timestampArray = resultSet.getArray("timestamp_array"); 329 | assertThat(timestampArray.getArray().getClass().isArray(), is(true)); 330 | assertThat(timestampArray.getBaseType(), is(Types.TIMESTAMP)); 331 | assertThat((Object[]) timestampArray.getArray(), Matchers.arrayContaining(new Timestamp(1000L), new Timestamp(2000L))); 332 | } 333 | 334 | @Test 335 | public void testSelectIPArrayType() throws Exception { 336 | ResultSet resultSet = CONNECTION.createStatement().executeQuery("select ip_array from arrayTest"); 337 | assertThat(resultSet, instanceOf(PgResultSet.class)); 338 | assertThat(resultSet.next(), is(true)); 339 | 340 | Array ipArray = resultSet.getArray("ip_array"); 341 | assertThat(ipArray.getArray().getClass().isArray(), is(true)); 342 | assertThat(ipArray.getBaseType(), is(Types.VARCHAR)); 343 | assertThat((Object[]) ipArray.getArray(), Matchers.arrayContaining("127.142.132.9", "127.0.0.1")); 344 | } 345 | 346 | @Test 347 | public void testSelectObjectArrayType() throws Exception { 348 | ResultSet resultSet = CONNECTION.createStatement() 349 | .executeQuery("SELECT obj_array FROM arrayTest"); 350 | assertThat(resultSet, instanceOf(PgResultSet.class)); 351 | assertThat(resultSet.next(), is(true)); 352 | 353 | Array objArray = resultSet.getArray("obj_array"); 354 | assertThat(objArray.getArray().getClass().isArray(), is(true)); 355 | assertThat(objArray.getBaseType(), is(Types.JAVA_OBJECT)); 356 | 357 | PgDatabaseMetaData metaData = (PgDatabaseMetaData) CONNECTION.getMetaData(); 358 | // CrateDB >= 4.1.0 maps the `array(object)` data type to 359 | // the `PGArray(JSON)` instead of `JSON` Postgres type. 360 | if (metaData.getCrateVersion().before("4.1.0")) { 361 | Object[] expectedArray = new Object[]{ 362 | new HashMap() {{ 363 | put("element1", "testing"); 364 | }}, 365 | new HashMap() {{ 366 | put("element2", "testing2"); 367 | }}}; 368 | 369 | assertThat(objArray.getArray(), is(expectedArray)); 370 | } else { 371 | PGobject firstObj = new PGobject(); 372 | firstObj.setType("json"); 373 | firstObj.setValue("{\"element1\":\"testing\"}"); 374 | PGobject secondObj = new PGobject(); 375 | secondObj.setType("json"); 376 | secondObj.setValue("{\"element2\":\"testing2\"}"); 377 | 378 | assertThat(objArray.getArray(), is(new Object[]{firstObj, secondObj})); 379 | } 380 | } 381 | 382 | @Test 383 | public void testSetGetObject() throws SQLException { 384 | Map expected = new HashMap<>(); 385 | expected.put("n", 1); 386 | 387 | CONNECTION.createStatement().executeUpdate("create table test_obj (obj object as (n int))"); 388 | PreparedStatement statement = CONNECTION.prepareStatement("insert into test_obj (obj) values (?)"); 389 | statement.setObject(1, expected); 390 | statement.execute(); 391 | 392 | CONNECTION.createStatement().execute("refresh table test_obj"); 393 | ResultSet resultSet = CONNECTION.createStatement().executeQuery("select obj from test_obj"); 394 | assertThat(resultSet.next(), is(true)); 395 | CONNECTION.createStatement().execute("drop table test_obj"); 396 | 397 | @SuppressWarnings("unchecked") 398 | Map map = (Map) resultSet.getObject(1); 399 | assertEquals(expected, map); 400 | } 401 | } 402 | -------------------------------------------------------------------------------- /driver/test/java/io/crate/client/jdbc/integrationtests/UnsupportedFeaturesITest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to CRATE Technology GmbH ("Crate") under one or more contributor 3 | * license agreements. See the NOTICE file distributed with this work for 4 | * additional information regarding copyright ownership. Crate licenses 5 | * this file to you under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. You may 7 | * obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14 | * License for the specific language governing permissions and limitations 15 | * under the License. 16 | * 17 | * However, if you have executed another commercial license agreement 18 | * with Crate these terms will supersede the license and you may use the 19 | * software solely pursuant to the terms of the relevant commercial agreement. 20 | */ 21 | 22 | package io.crate.client.jdbc.integrationtests; 23 | 24 | import org.junit.BeforeClass; 25 | import org.junit.Test; 26 | 27 | import java.sql.Connection; 28 | import java.sql.DriverManager; 29 | import java.sql.SQLException; 30 | import java.sql.SQLFeatureNotSupportedException; 31 | 32 | public class UnsupportedFeaturesITest extends BaseIntegrationTest { 33 | 34 | private static Connection connection; 35 | 36 | @BeforeClass 37 | public static void beforeClass() throws SQLException, InterruptedException { 38 | connection = DriverManager.getConnection(getConnectionString()); 39 | } 40 | 41 | @Test 42 | public void testPrepareCall() throws SQLException { 43 | expectUnsupportedFeature("Connection: prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) not supported"); 44 | connection.prepareCall("select *", 0, 0); 45 | } 46 | 47 | @Test 48 | public void testPrepareStatementWithColumnNames() throws SQLException { 49 | expectUnsupportedFeature("Connection: prepareStatement(String sql, String[] columnNames) not supported"); 50 | connection.prepareStatement("select *", new String[]{"id"}); 51 | } 52 | 53 | @Test 54 | public void testExecuteUpdateNotSupported() throws SQLException { 55 | expectUnsupportedFeature("Statement: executeUpdate(String sql, String[] columnNames) not supported"); 56 | connection.createStatement().executeUpdate("insert into test (id, name) values (3, 'hello')", new String[]{"id", "name"}); 57 | } 58 | 59 | private void expectUnsupportedFeature(String errorMessage) { 60 | expectedException.expect(SQLFeatureNotSupportedException.class); 61 | expectedException.expectMessage(errorMessage); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crate/crate-jdbc/70db55411954f06ec715a7da2fa83d5ffbdcdfa9/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /pg/build.gradle: -------------------------------------------------------------------------------- 1 | // https://github.com/raydac/java-comment-preprocessor/wiki/AndroidGradlePreprocessing 2 | 3 | // the folder contains the result 4 | def jcpRoot = "${buildDir}/jcp" 5 | // the original root folder path 6 | def srcRoot = 'upstream/pgjdbc/src' 7 | 8 | configurations { 9 | jcp 10 | processedMainCompile.extendsFrom(implementation) 11 | } 12 | 13 | dependencies { 14 | api 'com.github.dblock.waffle:waffle-jna:1.8.1' 15 | implementation 'net.java.dev.jna:jna:4.2.1' 16 | implementation 'net.java.dev.jna:jna-platform:4.2.1' 17 | implementation 'org.slf4j:jcl-over-slf4j:2.0.17' 18 | implementation 'com.fasterxml.jackson.core:jackson-databind:2.18.3' 19 | implementation 'org.osgi:org.osgi.enterprise:5.0.0' 20 | implementation 'org.osgi:org.osgi.core:4.3.1' 21 | implementation 'com.ongres.scram:client:2.1' 22 | jcp('com.igormaznitsa:jcp:6.0.1') { 23 | exclude group: 'org.apache.maven.*' 24 | exclude group: 'org.codehaus.*' 25 | } 26 | } 27 | 28 | if (!hasProperty("buildProfile")) ext.buildProfile = "jre8" 29 | 30 | task preprocessJava { 31 | doLast { 32 | def jcpjar = file(project.configurations.jcp.find { it.name.startsWith("jcp-") }) 33 | ant.taskdef(resource: 'com/igormaznitsa/jcp/ant/antlib.xml', classpath: jcpjar) 34 | 35 | ['/main/java', '/main/resources'].each { dir -> 36 | def fromDir = srcRoot + dir; 37 | def toDir = jcpRoot + dir; 38 | println "Preproces: ${fromDir} -> ${toDir}" 39 | ant.preprocess(excluded: "none", processing: 'java,xml', source: fromDir, destination: toDir) { 40 | cfgFile(file: "${buildProfile}.properties") 41 | } 42 | } 43 | } 44 | } 45 | 46 | task preprocessTestJava { 47 | doLast { 48 | def jcpjar = file(project.configurations.jcp.find { it.name.startsWith("jcp-") }) 49 | ant.taskdef(resource: 'com/igormaznitsa/jcp/ant/antlib.xml', classpath: jcpjar) 50 | 51 | ['/test/java', '/test/resources'].each { dir -> 52 | def fromDir = srcRoot + dir; 53 | def toDir = jcpRoot + dir; 54 | println "Preproces: ${fromDir} -> ${toDir}" 55 | ant.preprocess(excluded: "none", processing: 'java,xml', source: fromDir, destination: toDir) { 56 | cfgFile(file: "${buildProfile}.properties") 57 | } 58 | } 59 | } 60 | } 61 | 62 | sourceSets { 63 | main { 64 | java { 65 | srcDir "${srcRoot}/main/java" 66 | exclude '**/osgi/*' 67 | } 68 | resources { 69 | srcDir "${srcRoot}/main/resources" 70 | exclude '**/services/java.sql.Driver' 71 | } 72 | } 73 | processedMain { 74 | java { 75 | srcDir "${buildDir}/jcp/main/java" 76 | exclude '**/osgi/*' 77 | } 78 | resources { 79 | srcDir "${buildDir}/jcp/main/resources" 80 | exclude '**/services/java.sql.Driver' 81 | } 82 | } 83 | } 84 | 85 | compileJava.dependsOn preprocessJava 86 | 87 | test { 88 | enabled = false; 89 | } 90 | -------------------------------------------------------------------------------- /pg/jre8.properties: -------------------------------------------------------------------------------- 1 | mvn.project.property.parsedversion.majorversion=42 2 | mvn.project.property.parsedversion.minorversion=2 3 | mvn.project.property.parsedversion.incrementalversion=5 4 | mvn.project.property.parsedversion.osgiversion="42.2.5" 5 | mvn.project.property.postgresql.jdbc.spec="JDBC4.2" 6 | mvn.project.property.jdbc.specification.version="4.2" 7 | mvn.project.property.jdbc.specification.version.nodot="42" 8 | mvn.project.property.template.default.pg.port=5432 9 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include 'pg' 2 | --------------------------------------------------------------------------------