commit
861eb45025
@ -0,0 +1,22 @@
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
target/
|
||||
/var
|
||||
/*/var/
|
||||
pom.xml.versionsBackup
|
||||
test-output/
|
||||
/atlassian-ide-plugin.xml
|
||||
.idea
|
||||
.DS_Store
|
||||
.classpath
|
||||
.settings
|
||||
.project
|
||||
temp-testng-customsuite.xml
|
||||
test-output
|
||||
.externalToolBuilders
|
||||
*~
|
||||
benchmark_outputs
|
||||
*.pyc
|
||||
*.class
|
||||
.checkstyle
|
@ -0,0 +1,19 @@
|
||||
language: java
|
||||
|
||||
jdk:
|
||||
- oraclejdk8
|
||||
|
||||
env:
|
||||
global:
|
||||
- MAVEN_OPTS="-Xmx256M"
|
||||
|
||||
sudo: false
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.m2/io
|
||||
- $HOME/.m2/org
|
||||
|
||||
install: mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V -q -T 2
|
||||
|
||||
script: mvn test -Dair.check.skip-dependency=true
|
@ -0,0 +1,11 @@
|
||||
# Contributing to Presto
|
||||
|
||||
## Contributor License Agreement ("CLA")
|
||||
|
||||
In order to accept your pull request, we need you to submit a CLA. You only need to do this once, so if you've done this for another Facebook open source project, you're good to go. If you are submitting a pull request for the first time, just let us know that you have completed the CLA and we can cross-check with your GitHub username.
|
||||
|
||||
Complete your CLA here: <https://code.facebook.com/cla>
|
||||
|
||||
## License
|
||||
|
||||
By contributing to Presto, you agree that your contributions will be licensed under the [Apache License Version 2.0 (APLv2)](LICENSE).
|
@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
@ -0,0 +1,73 @@
|
||||
# Presto
|
||||
|
||||
Presto is a distributed SQL query engine for big data.
|
||||
|
||||
See the [User Manual](https://prestodb.io/docs/current/) for deployment instructions and end user documentation.
|
||||
|
||||
## Requirements
|
||||
|
||||
* Mac OS X or Linux
|
||||
* Java 8, 64-bit
|
||||
* Maven 3.2.3+ (for building)
|
||||
* Python 2.4+ (for running with the launcher script)
|
||||
|
||||
## Building Presto
|
||||
|
||||
Presto is a standard Maven project. Simply run the following command from the project root directory:
|
||||
|
||||
mvn clean install
|
||||
|
||||
On the first build, Maven will download all the dependencies from the internet and cache them in the local repository (`~/.m2/repository`), which can take a considerable amount of time. Subsequent builds will be faster.
|
||||
|
||||
Presto has a comprehensive set of unit tests that can take several minutes to run. You can disable the tests when building:
|
||||
|
||||
mvn clean install -DskipTests
|
||||
|
||||
## Running Presto in your IDE
|
||||
|
||||
### Overview
|
||||
|
||||
After building Presto for the first time, you can load the project into your IDE and run the server. We recommend using [IntelliJ IDEA](http://www.jetbrains.com/idea/). Because Presto is a standard Maven project, you can import it into your IDE using the root `pom.xml` file. In IntelliJ, choose Open Project from the Quick Start box or choose Open from the File menu and select the root `pom.xml` file.
|
||||
|
||||
After opening the project in IntelliJ, double check that the Java SDK is properly configured properly for the project:
|
||||
|
||||
* Open the File menu and select Project Structure
|
||||
* In the SDKs section, ensure that a 1.8 JDK is selected (create one if none exist)
|
||||
* In the Project section, ensure the Project language level is set to 8.0 as Presto makes use of several Java 8 language features
|
||||
|
||||
Presto comes with sample configuration that should work out-of-the-box for development. Use the following options to create a run configuration:
|
||||
|
||||
* Main Class: `com.facebook.presto.server.PrestoServer`
|
||||
* VM Options: `-ea -Xmx2G -Dconfig=etc/config.properties -Dlog.levels-file=etc/log.properties`
|
||||
* Working directory: `$MODULE_DIR$`
|
||||
* Use classpath of module: `presto-main`
|
||||
|
||||
The working directory should be the `presto-main` subdirectory. In IntelliJ, using `$MODULE_DIR$` accomplishes this automatically.
|
||||
|
||||
Additionally, the Hive plugin must be configured with location of your Hive metastore Thrift service. Add the following to the list of VM options, replacing `localhost:9083` with the correct host and port (or use the below value if you do not have a Hive metastore):
|
||||
|
||||
-Dhive.metastore.uri=thrift://localhost:9083
|
||||
|
||||
### Using SOCKS for Hive or HDFS
|
||||
|
||||
If your Hive metastore or HDFS cluster is not directly accessible to your local machine, you can use SSH port forwarding to access it. Setup a dynamic SOCKS proxy with SSH listening on local port 1080:
|
||||
|
||||
ssh -v -N -D 1080 server
|
||||
|
||||
Then add the following to the list of VM options:
|
||||
|
||||
-Dhive.metastore.thrift.client.socks-proxy=localhost:1080
|
||||
|
||||
### Running the CLI
|
||||
|
||||
Start the CLI to connect to the server and run SQL queries:
|
||||
|
||||
presto-cli/target/presto-cli-*-executable.jar
|
||||
|
||||
Run a query to see the nodes in the cluster:
|
||||
|
||||
SELECT * FROM system.runtime.nodes;
|
||||
|
||||
In the sample configuration, the Hive connector is mounted in the `hive` catalog, so you can run the following queries to show the tables in the Hive database `default`:
|
||||
|
||||
SHOW TABLES FROM hive.default;
|
@ -0,0 +1,916 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>airbase</artifactId>
|
||||
<version>39</version>
|
||||
</parent>
|
||||
|
||||
<groupId>com.facebook.presto</groupId>
|
||||
<artifactId>presto-root</artifactId>
|
||||
<version>0.107</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>presto-root</name>
|
||||
<description>Presto</description>
|
||||
<url>https://github.com/facebook/presto</url>
|
||||
|
||||
<inceptionYear>2012</inceptionYear>
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
<name>Apache License 2.0</name>
|
||||
<url>http://www.apache.org/licenses/LICENSE-2.0</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
|
||||
<scm>
|
||||
<connection>scm:git:git://github.com/facebook/presto.git</connection>
|
||||
<url>https://github.com/facebook/presto</url>
|
||||
<tag>0.107</tag>
|
||||
</scm>
|
||||
|
||||
<properties>
|
||||
<air.main.basedir>${project.basedir}</air.main.basedir>
|
||||
|
||||
<air.check.skip-extended>true</air.check.skip-extended>
|
||||
<air.check.skip-license>false</air.check.skip-license>
|
||||
|
||||
<air.check.fail-checkstyle>true</air.check.fail-checkstyle>
|
||||
<air.check.skip-checkstyle>false</air.check.skip-checkstyle>
|
||||
|
||||
<dep.antlr.version>4.3</dep.antlr.version>
|
||||
<dep.airlift.version>0.110</dep.airlift.version>
|
||||
<dep.packaging.version>${dep.airlift.version}</dep.packaging.version>
|
||||
<dep.slice.version>0.14</dep.slice.version>
|
||||
|
||||
<cli.skip-execute>true</cli.skip-execute>
|
||||
<cli.main-class>None</cli.main-class>
|
||||
|
||||
<!-- use a fractional hour timezone offset for tests -->
|
||||
<air.test.timezone>Asia/Katmandu</air.test.timezone>
|
||||
<air.test.parallel>methods</air.test.parallel>
|
||||
<air.test.thread-count>4</air.test.thread-count>
|
||||
<air.test.jvmsize>1792m</air.test.jvmsize>
|
||||
|
||||
<air.javadoc.lint>-missing</air.javadoc.lint>
|
||||
</properties>
|
||||
|
||||
<modules>
|
||||
<module>presto-spi</module>
|
||||
<module>presto-kafka</module>
|
||||
<module>presto-cassandra</module>
|
||||
<module>presto-orc</module>
|
||||
<module>presto-hive</module>
|
||||
<module>presto-hive-hadoop1</module>
|
||||
<module>presto-hive-hadoop2</module>
|
||||
<module>presto-hive-cdh4</module>
|
||||
<module>presto-hive-cdh5</module>
|
||||
<module>presto-example-http</module>
|
||||
<module>presto-tpch</module>
|
||||
<module>presto-raptor</module>
|
||||
<module>presto-base-jdbc</module>
|
||||
<module>presto-mysql</module>
|
||||
<module>presto-sqlserver</module>
|
||||
<module>presto-postgresql</module>
|
||||
<module>presto-client</module>
|
||||
<module>presto-parser</module>
|
||||
<module>presto-main</module>
|
||||
<module>presto-ml</module>
|
||||
<module>presto-benchmark</module>
|
||||
<module>presto-tests</module>
|
||||
<module>presto-jdbc</module>
|
||||
<module>presto-cli</module>
|
||||
<module>presto-benchmark-driver</module>
|
||||
<module>presto-server</module>
|
||||
<module>presto-docs</module>
|
||||
<module>presto-verifier</module>
|
||||
<module>presto-oracle</module>
|
||||
</modules>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.facebook.presto</groupId>
|
||||
<artifactId>presto-spi</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.facebook.presto</groupId>
|
||||
<artifactId>presto-orc</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.facebook.presto</groupId>
|
||||
<artifactId>presto-hive</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.facebook.presto</groupId>
|
||||
<artifactId>presto-hive-cdh4</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>zip</type>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.facebook.presto</groupId>
|
||||
<artifactId>presto-example-http</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>zip</type>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.facebook.presto</groupId>
|
||||
<artifactId>presto-hive</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>test-jar</type>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.facebook.presto</groupId>
|
||||
<artifactId>presto-tpch</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.facebook.presto</groupId>
|
||||
<artifactId>presto-base-jdbc</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.facebook.presto</groupId>
|
||||
<artifactId>presto-mysql</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.facebook.presto</groupId>
|
||||
<artifactId>presto-sqlserver</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.facebook.presto</groupId>
|
||||
<artifactId>presto-raptor</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.facebook.presto</groupId>
|
||||
<artifactId>presto-cli</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.facebook.presto</groupId>
|
||||
<artifactId>presto-client</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.facebook.presto</groupId>
|
||||
<artifactId>presto-parser</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.facebook.presto</groupId>
|
||||
<artifactId>presto-parser</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>test-jar</type>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.facebook.presto</groupId>
|
||||
<artifactId>presto-main</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.facebook.presto</groupId>
|
||||
<artifactId>presto-main</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>test-jar</type>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.facebook.presto</groupId>
|
||||
<artifactId>presto-jdbc</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.facebook.presto</groupId>
|
||||
<artifactId>presto-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.facebook.presto</groupId>
|
||||
<artifactId>presto-tests</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.facebook.presto</groupId>
|
||||
<artifactId>presto-benchmark</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.facebook.presto.hadoop</groupId>
|
||||
<artifactId>hadoop-apache1</artifactId>
|
||||
<version>0.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.facebook.presto.hadoop</groupId>
|
||||
<artifactId>hadoop-apache2</artifactId>
|
||||
<version>0.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.facebook.presto.hadoop</groupId>
|
||||
<artifactId>hadoop-cdh4</artifactId>
|
||||
<version>0.8</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.facebook.presto.hive</groupId>
|
||||
<artifactId>hive-apache</artifactId>
|
||||
<version>0.14</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.facebook.hive</groupId>
|
||||
<artifactId>hive-dwrf</artifactId>
|
||||
<version>0.8</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.iq80.snappy</groupId>
|
||||
<artifactId>snappy</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.facebook.presto.hadoop</groupId>
|
||||
<artifactId>hadoop-cdh4</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>it.unimi.dsi</groupId>
|
||||
<artifactId>fastutil</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.facebook.hive</groupId>
|
||||
<artifactId>hive-dwrf-shims</artifactId>
|
||||
<version>0.8</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<groupId>commons-logging</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.protobuf</groupId>
|
||||
<artifactId>protobuf-java</artifactId>
|
||||
<version>2.4.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>log</artifactId>
|
||||
<version>${dep.airlift.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>log-manager</artifactId>
|
||||
<version>${dep.airlift.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>json</artifactId>
|
||||
<version>${dep.airlift.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>units</artifactId>
|
||||
<version>${dep.airlift.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>concurrent</artifactId>
|
||||
<version>${dep.airlift.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>configuration</artifactId>
|
||||
<version>${dep.airlift.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>discovery</artifactId>
|
||||
<version>${dep.airlift.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>testing</artifactId>
|
||||
<version>${dep.airlift.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>node</artifactId>
|
||||
<version>${dep.airlift.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>bootstrap</artifactId>
|
||||
<version>${dep.airlift.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>event</artifactId>
|
||||
<version>${dep.airlift.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>http-server</artifactId>
|
||||
<version>${dep.airlift.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>jaxrs</artifactId>
|
||||
<version>${dep.airlift.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>jmx</artifactId>
|
||||
<version>${dep.airlift.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>trace-token</artifactId>
|
||||
<version>${dep.airlift.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>dbpool</artifactId>
|
||||
<version>${dep.airlift.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>jmx-http</artifactId>
|
||||
<version>${dep.airlift.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>http-client</artifactId>
|
||||
<version>${dep.airlift.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>stats</artifactId>
|
||||
<version>${dep.airlift.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>joni</artifactId>
|
||||
<version>2.1.5.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.airlift.tpch</groupId>
|
||||
<artifactId>tpch</artifactId>
|
||||
<version>0.4</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ow2.asm</groupId>
|
||||
<artifactId>asm-all</artifactId>
|
||||
<version>4.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>1.3.170</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.sonatype.aether</groupId>
|
||||
<artifactId>aether-api</artifactId>
|
||||
<version>1.13.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.airlift.resolver</groupId>
|
||||
<artifactId>resolver</artifactId>
|
||||
<version>1.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>airline</artifactId>
|
||||
<version>0.6</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.iq80.snappy</groupId>
|
||||
<artifactId>snappy</artifactId>
|
||||
<version>0.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.openjdk.jol</groupId>
|
||||
<artifactId>jol-core</artifactId>
|
||||
<version>0.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jetbrains</groupId>
|
||||
<artifactId>annotations</artifactId>
|
||||
<version>13.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>it.unimi.dsi</groupId>
|
||||
<artifactId>fastutil</artifactId>
|
||||
<version>6.5.9</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.facebook.thirdparty</groupId>
|
||||
<artifactId>libsvm</artifactId>
|
||||
<version>3.18.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>5.1.35</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<version>9.3-1102-jdbc41</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.antlr</groupId>
|
||||
<artifactId>antlr4-runtime</artifactId>
|
||||
<version>${dep.antlr.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.antlr</groupId>
|
||||
<artifactId>antlr4-annotations</artifactId>
|
||||
<version>${dep.antlr.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>jline</groupId>
|
||||
<artifactId>jline</artifactId>
|
||||
<version>2.12</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jdbi</groupId>
|
||||
<artifactId>jdbi</artifactId>
|
||||
<version>2.55</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.thrift</groupId>
|
||||
<artifactId>libthrift</artifactId>
|
||||
<version>0.9.1</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpcore</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>net.sf.opencsv</groupId>
|
||||
<artifactId>opencsv</artifactId>
|
||||
<version>2.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-math3</artifactId>
|
||||
<version>3.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
<version>1.9</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty</artifactId>
|
||||
<version>3.7.0.Final</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.airlift.discovery</groupId>
|
||||
<artifactId>discovery-server</artifactId>
|
||||
<version>1.24</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.amazonaws</groupId>
|
||||
<artifactId>aws-java-sdk</artifactId>
|
||||
<version>1.8.9.1</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>testing-mysql-server</artifactId>
|
||||
<version>0.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>testing-postgresql-server</artifactId>
|
||||
<version>0.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.kafka</groupId>
|
||||
<artifactId>kafka_2.10</artifactId>
|
||||
<version>0.8.1.1</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-jdk14</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.xerial.snappy</groupId>
|
||||
<artifactId>snappy-java</artifactId>
|
||||
<version>1.1.1.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.zookeeper</groupId>
|
||||
<artifactId>zookeeper</artifactId>
|
||||
<version>3.3.6</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>junit</artifactId>
|
||||
<groupId>junit</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>log4j</artifactId>
|
||||
<groupId>log4j</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.101tec</groupId>
|
||||
<artifactId>zkclient</artifactId>
|
||||
<version>0.4</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>log4j</artifactId>
|
||||
<groupId>log4j</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jgrapht</groupId>
|
||||
<artifactId>jgrapht-core</artifactId>
|
||||
<version>0.9.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.antlr</groupId>
|
||||
<artifactId>antlr4-maven-plugin</artifactId>
|
||||
<version>${dep.antlr.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>antlr4</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<visitor>true</visitor>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>2.3</version>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.skife.maven</groupId>
|
||||
<artifactId>really-executable-jar-maven-plugin</artifactId>
|
||||
<version>1.0.5</version>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<version>1.2.1</version>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.tomdz.maven</groupId>
|
||||
<artifactId>sphinx-maven-plugin</artifactId>
|
||||
<version>1.0.3</version>
|
||||
</plugin>
|
||||
|
||||
<!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
|
||||
<plugin>
|
||||
<!--suppress MavenModelInspection -->
|
||||
<groupId>org.eclipse.m2e</groupId>
|
||||
<!--suppress MavenModelInspection -->
|
||||
<artifactId>lifecycle-mapping</artifactId>
|
||||
<!--suppress MavenModelInspection -->
|
||||
<version>1.0.0</version>
|
||||
<configuration>
|
||||
<lifecycleMappingMetadata>
|
||||
<pluginExecutions>
|
||||
<pluginExecution>
|
||||
<pluginExecutionFilter>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<versionRange>[2.5.1,)</versionRange>
|
||||
<goals>
|
||||
<goal>copy</goal>
|
||||
<goal>analyze-dep-mgt</goal>
|
||||
<goal>analyze-duplicate</goal>
|
||||
<goal>analyze-only</goal>
|
||||
</goals>
|
||||
</pluginExecutionFilter>
|
||||
<action>
|
||||
<ignore/>
|
||||
</action>
|
||||
</pluginExecution>
|
||||
<pluginExecution>
|
||||
<pluginExecutionFilter>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<versionRange>[0.6.2.201302030002,)</versionRange>
|
||||
<goals>
|
||||
<goal>prepare-agent</goal>
|
||||
</goals>
|
||||
</pluginExecutionFilter>
|
||||
<action>
|
||||
<ignore/>
|
||||
</action>
|
||||
</pluginExecution>
|
||||
<pluginExecution>
|
||||
<pluginExecutionFilter>
|
||||
<groupId>com.mycila</groupId>
|
||||
<artifactId>license-maven-plugin</artifactId>
|
||||
<versionRange>[2.3,)</versionRange>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
</pluginExecutionFilter>
|
||||
<action>
|
||||
<ignore/>
|
||||
</action>
|
||||
</pluginExecution>
|
||||
<pluginExecution>
|
||||
<pluginExecutionFilter>
|
||||
<groupId>com.ning.maven.plugins</groupId>
|
||||
<artifactId>maven-duplicate-finder-plugin</artifactId>
|
||||
<versionRange>[1.0.4,)</versionRange>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
</pluginExecutionFilter>
|
||||
<action>
|
||||
<ignore/>
|
||||
</action>
|
||||
</pluginExecution>
|
||||
<pluginExecution>
|
||||
<pluginExecutionFilter>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
<versionRange>[0,)</versionRange>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
</pluginExecutionFilter>
|
||||
<action>
|
||||
<ignore/>
|
||||
</action>
|
||||
</pluginExecution>
|
||||
<pluginExecution>
|
||||
<pluginExecutionFilter>
|
||||
<groupId>io.takari.maven.plugins</groupId>
|
||||
<artifactId>presto-maven-plugin</artifactId>
|
||||
<versionRange>[0,)</versionRange>
|
||||
<goals>
|
||||
<goal>generate-service-descriptor</goal>
|
||||
</goals>
|
||||
</pluginExecutionFilter>
|
||||
<action>
|
||||
<ignore/>
|
||||
</action>
|
||||
</pluginExecution>
|
||||
<pluginExecution>
|
||||
<pluginExecutionFilter>
|
||||
<groupId>io.takari.maven.plugins</groupId>
|
||||
<artifactId>takari-lifecycle-plugin</artifactId>
|
||||
<versionRange>[0,)</versionRange>
|
||||
<goals>
|
||||
<goal>compile</goal>
|
||||
<goal>process-resources</goal>
|
||||
<goal>process-test-resources</goal>
|
||||
<goal>testCompile</goal>
|
||||
</goals>
|
||||
</pluginExecutionFilter>
|
||||
<action>
|
||||
<ignore/>
|
||||
</action>
|
||||
</pluginExecution>
|
||||
<pluginExecution>
|
||||
<pluginExecutionFilter>
|
||||
<groupId>org.gaul</groupId>
|
||||
<artifactId>modernizer-maven-plugin</artifactId>
|
||||
<versionRange>[0,)</versionRange>
|
||||
<goals>
|
||||
<goal>modernizer</goal>
|
||||
</goals>
|
||||
</pluginExecutionFilter>
|
||||
<action>
|
||||
<ignore/>
|
||||
</action>
|
||||
</pluginExecution>
|
||||
</pluginExecutions>
|
||||
</lifecycleMappingMetadata>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.gaul</groupId>
|
||||
<artifactId>modernizer-maven-plugin</artifactId>
|
||||
<version>1.2.2</version>
|
||||
<configuration>
|
||||
<javaVersion>1.8</javaVersion>
|
||||
<failOnViolations>false</failOnViolations>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>modernizer</id>
|
||||
<goals>
|
||||
<goal>modernizer</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
<version>2.15</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>validate</phase>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<skip>${air.check.skip-checkstyle}</skip>
|
||||
<failOnViolation>${air.check.fail-checkstyle}</failOnViolation>
|
||||
<consoleOutput>true</consoleOutput>
|
||||
<includeTestSourceDirectory>true</includeTestSourceDirectory>
|
||||
<configLocation>${air.main.basedir}/src/checkstyle/checks.xml</configLocation>
|
||||
<excludes>**/com/facebook/presto/operator/PagesIndexOrdering.java</excludes>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
<dependencies>
|
||||
<!-- The version of checkstyle the plugin depends on doesn't support Java 8,
|
||||
so override it manually until a new version of the plugin is released.
|
||||
This is copied verbatim from the dependency declaration in the checkstyle
|
||||
plugin -->
|
||||
<dependency>
|
||||
<groupId>com.puppycrawl.tools</groupId>
|
||||
<artifactId>checkstyle</artifactId>
|
||||
<version>6.6</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>io.takari.maven.plugins</groupId>
|
||||
<artifactId>presto-maven-plugin</artifactId>
|
||||
<version>0.1.5</version>
|
||||
<extensions>true</extensions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>io.takari.maven.plugins</groupId>
|
||||
<artifactId>provisio-maven-plugin</artifactId>
|
||||
<version>0.1.11</version>
|
||||
<extensions>true</extensions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration combine.children="append">
|
||||
<fork>false</fork>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<profiles>
|
||||
<!-- run cli for development: mvn -am -pl presto-cli -P cli compile exec:java -->
|
||||
<profile>
|
||||
<id>cli</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<skip>${cli.skip-execute}</skip>
|
||||
<executable>${java.home}/bin/java</executable>
|
||||
<mainClass>${cli.main-class}</mainClass>
|
||||
<arguments>
|
||||
<argument>--debug</argument>
|
||||
</arguments>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
@ -0,0 +1,201 @@
|
||||
<?xml version="1.0"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.facebook.presto</groupId>
|
||||
<artifactId>presto-root</artifactId>
|
||||
<version>0.107</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>presto-base-jdbc</artifactId>
|
||||
<name>presto-base-jdbc</name>
|
||||
<description>Presto - Base JDBC Connector</description>
|
||||
|
||||
<properties>
|
||||
<air.main.basedir>${project.parent.basedir}</air.main.basedir>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>bootstrap</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>log</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>configuration</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>concurrent</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.inject</groupId>
|
||||
<artifactId>guice</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.validation</groupId>
|
||||
<artifactId>validation-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
<artifactId>annotations</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>joda-time</groupId>
|
||||
<artifactId>joda-time</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Presto SPI -->
|
||||
<dependency>
|
||||
<groupId>com.facebook.presto</groupId>
|
||||
<artifactId>presto-spi</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>slice</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.inject</groupId>
|
||||
<artifactId>javax.inject</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-dbutils</groupId>
|
||||
<artifactId>commons-dbutils</artifactId>
|
||||
<version>1.6</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.facebook.presto</groupId>
|
||||
<artifactId>presto-main</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>units</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- for testing -->
|
||||
<dependency>
|
||||
<groupId>org.testng</groupId>
|
||||
<artifactId>testng</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>testing</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>json</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.facebook.presto</groupId>
|
||||
<artifactId>presto-tpch</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.airlift.tpch</groupId>
|
||||
<artifactId>tpch</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.facebook.presto</groupId>
|
||||
<artifactId>presto-tests</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<!-- integration tests take a very long time so only run them in the CI server -->
|
||||
<excludes>
|
||||
<exclude>**/TestJdbcDistributedQueries.java</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>ci</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes combine.self="override" />
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
@ -0,0 +1,540 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc;
|
||||
|
||||
import com.facebook.presto.plugin.jdbc.cache.JdbcCacheConfig;
|
||||
import com.facebook.presto.plugin.jdbc.cache.JdbcCacheSplit;
|
||||
import com.facebook.presto.plugin.jdbc.cache.JdbcJavaBean;
|
||||
import com.facebook.presto.plugin.jdbc.cache.JdbcResultCache;
|
||||
import com.facebook.presto.plugin.jdbc.subtable.JdbcSubTableConfig;
|
||||
import com.facebook.presto.plugin.jdbc.subtable.JdbcSubTableManager;
|
||||
import com.facebook.presto.spi.ColumnHandle;
|
||||
import com.facebook.presto.spi.ColumnMetadata;
|
||||
import com.facebook.presto.spi.ConnectorPartition;
|
||||
import com.facebook.presto.spi.ConnectorPartitionResult;
|
||||
import com.facebook.presto.spi.ConnectorSplitSource;
|
||||
import com.facebook.presto.spi.ConnectorTableMetadata;
|
||||
import com.facebook.presto.spi.FixedSplitSource;
|
||||
import com.facebook.presto.spi.HostAddress;
|
||||
import com.facebook.presto.spi.PrestoException;
|
||||
import com.facebook.presto.spi.SchemaTableName;
|
||||
import com.facebook.presto.spi.TableNotFoundException;
|
||||
import com.facebook.presto.spi.TupleDomain;
|
||||
import com.facebook.presto.spi.type.Type;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import io.airlift.log.Logger;
|
||||
import io.airlift.slice.Slice;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.Driver;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.sql.Types;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.facebook.presto.spi.StandardErrorCode.NOT_FOUND;
|
||||
import static com.facebook.presto.spi.StandardErrorCode.NOT_SUPPORTED;
|
||||
import static com.facebook.presto.spi.type.BigintType.BIGINT;
|
||||
import static com.facebook.presto.spi.type.BooleanType.BOOLEAN;
|
||||
import static com.facebook.presto.spi.type.DateType.DATE;
|
||||
import static com.facebook.presto.spi.type.DoubleType.DOUBLE;
|
||||
import static com.facebook.presto.spi.type.TimeType.TIME;
|
||||
import static com.facebook.presto.spi.type.TimeWithTimeZoneType.TIME_WITH_TIME_ZONE;
|
||||
import static com.facebook.presto.spi.type.TimestampType.TIMESTAMP;
|
||||
import static com.facebook.presto.spi.type.TimestampWithTimeZoneType.TIMESTAMP_WITH_TIME_ZONE;
|
||||
import static com.facebook.presto.spi.type.VarbinaryType.VARBINARY;
|
||||
import static com.facebook.presto.spi.type.VarcharType.VARCHAR;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Strings.isNullOrEmpty;
|
||||
import static com.google.common.collect.Iterables.getOnlyElement;
|
||||
import static com.google.common.collect.Maps.fromProperties;
|
||||
import static java.util.Collections.nCopies;
|
||||
import static java.util.Locale.ENGLISH;
|
||||
|
||||
public class BaseJdbcClient
|
||||
implements JdbcClient
|
||||
{
|
||||
private static final Logger log = Logger.get(BaseJdbcClient.class);
|
||||
public static final int TYPE_MYSQL = 1;
|
||||
public static final int TYPE_ORACLE = 2;
|
||||
public static final int TYPE_SQLSERVER = 3;
|
||||
|
||||
private static final Map<Type, String> SQL_TYPES = ImmutableMap.<Type, String>builder()
|
||||
.put(BOOLEAN, "boolean")
|
||||
.put(BIGINT, "bigint")
|
||||
.put(DOUBLE, "double precision")
|
||||
.put(VARCHAR, "varchar")
|
||||
.put(VARBINARY, "varbinary")
|
||||
.put(DATE, "date")
|
||||
.put(TIME, "time")
|
||||
.put(TIME_WITH_TIME_ZONE, "time with timezone")
|
||||
.put(TIMESTAMP, "timestamp")
|
||||
.put(TIMESTAMP_WITH_TIME_ZONE, "timestamp with timezone")
|
||||
.build();
|
||||
|
||||
protected final String connectorId;
|
||||
protected final Driver driver;
|
||||
protected final String connectionUrl;
|
||||
protected final Properties connectionProperties;
|
||||
protected final String identifierQuote;
|
||||
protected int dbType;
|
||||
|
||||
protected final boolean jdbcSubTableEnable;
|
||||
private JdbcSubTableManager subTableManager;
|
||||
|
||||
protected final boolean cacheEnable;
|
||||
private JdbcResultCache jdbcResultCache;
|
||||
|
||||
public BaseJdbcClient(JdbcConnectorId connectorId,
|
||||
BaseJdbcConfig config,
|
||||
String identifierQuote,
|
||||
Driver driver,
|
||||
JdbcSubTableConfig subTableConfig,
|
||||
JdbcCacheConfig cacheConfig)
|
||||
{
|
||||
this.connectorId = checkNotNull(connectorId, "connectorId is null").toString();
|
||||
this.identifierQuote = checkNotNull(identifierQuote, "identifierQuote is null");
|
||||
this.driver = checkNotNull(driver, "driver is null");
|
||||
|
||||
checkNotNull(config, "config is null");
|
||||
connectionUrl = config.getConnectionUrl();
|
||||
|
||||
connectionProperties = new Properties();
|
||||
if (config.getConnectionUser() != null) {
|
||||
connectionProperties.setProperty("user", config.getConnectionUser());
|
||||
}
|
||||
if (config.getConnectionPassword() != null) {
|
||||
connectionProperties.setProperty("password", config.getConnectionPassword());
|
||||
}
|
||||
|
||||
// sub table
|
||||
jdbcSubTableEnable = subTableConfig.getJdbcSubTableEnable();
|
||||
if (jdbcSubTableEnable) {
|
||||
this.subTableManager = new JdbcSubTableManager(this.connectorId, identifierQuote,
|
||||
driver, connectionUrl, connectionProperties, subTableConfig);
|
||||
}
|
||||
// jdbc cache
|
||||
cacheEnable = cacheConfig.getJdbcCacheEnable();
|
||||
if (cacheEnable) {
|
||||
this.jdbcResultCache = new JdbcResultCache(identifierQuote, driver, connectionProperties, cacheConfig);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getSchemaNames()
|
||||
{
|
||||
try (Connection connection = driver.connect(connectionUrl, connectionProperties);
|
||||
ResultSet resultSet = connection.getMetaData().getSchemas()) {
|
||||
ImmutableSet.Builder<String> schemaNames = ImmutableSet.builder();
|
||||
while (resultSet.next()) {
|
||||
String schemaName = resultSet.getString("TABLE_SCHEM").toLowerCase(ENGLISH);
|
||||
// skip internal schemas
|
||||
if (!schemaName.equals("information_schema")) {
|
||||
schemaNames.add(schemaName);
|
||||
}
|
||||
}
|
||||
return schemaNames.build();
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SchemaTableName> getTableNames(@Nullable String schema)
|
||||
{
|
||||
try (Connection connection = driver.connect(connectionUrl, connectionProperties)) {
|
||||
DatabaseMetaData metadata = connection.getMetaData();
|
||||
if (metadata.storesUpperCaseIdentifiers() && (schema != null)) {
|
||||
schema = schema.toUpperCase(ENGLISH);
|
||||
}
|
||||
try (ResultSet resultSet = getTables(connection, schema, null)) {
|
||||
ImmutableList.Builder<SchemaTableName> list = ImmutableList.builder();
|
||||
while (resultSet.next()) {
|
||||
list.add(getSchemaTableName(resultSet));
|
||||
}
|
||||
return list.build();
|
||||
}
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public JdbcTableHandle getTableHandle(SchemaTableName schemaTableName)
|
||||
{
|
||||
try (Connection connection = driver.connect(connectionUrl, connectionProperties)) {
|
||||
DatabaseMetaData metadata = connection.getMetaData();
|
||||
String jdbcSchemaName = schemaTableName.getSchemaName();
|
||||
String jdbcTableName = schemaTableName.getTableName();
|
||||
if (metadata.storesUpperCaseIdentifiers()) {
|
||||
jdbcSchemaName = jdbcSchemaName.toUpperCase(ENGLISH);
|
||||
jdbcTableName = jdbcTableName.toUpperCase(ENGLISH);
|
||||
}
|
||||
try (ResultSet resultSet = getTables(connection, jdbcSchemaName, jdbcTableName)) {
|
||||
List<JdbcTableHandle> tableHandles = new ArrayList<>();
|
||||
while (resultSet.next()) {
|
||||
tableHandles.add(new JdbcTableHandle(
|
||||
connectorId,
|
||||
schemaTableName,
|
||||
resultSet.getString("TABLE_CAT"),
|
||||
resultSet.getString("TABLE_SCHEM"),
|
||||
resultSet.getString("TABLE_NAME")));
|
||||
}
|
||||
if (tableHandles.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
if (tableHandles.size() > 1) {
|
||||
throw new PrestoException(NOT_SUPPORTED, "Multiple tables matched: " + schemaTableName);
|
||||
}
|
||||
return getOnlyElement(tableHandles);
|
||||
}
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<JdbcColumnHandle> getColumns(JdbcTableHandle tableHandle)
|
||||
{
|
||||
try (Connection connection = driver.connect(connectionUrl, connectionProperties)) {
|
||||
DatabaseMetaData metadata = connection.getMetaData();
|
||||
try (ResultSet resultSet = metadata.getColumns(tableHandle.getCatalogName(), tableHandle.getSchemaName(), tableHandle.getTableName(), null)) {
|
||||
List<JdbcColumnHandle> columns = new ArrayList<>();
|
||||
boolean found = false;
|
||||
while (resultSet.next()) {
|
||||
found = true;
|
||||
Type columnType = toPrestoType(resultSet.getInt("DATA_TYPE"));
|
||||
// skip unsupported column types
|
||||
if (columnType != null) {
|
||||
String columnName = resultSet.getString("COLUMN_NAME");
|
||||
columns.add(new JdbcColumnHandle(connectorId, columnName, columnType));
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
throw new TableNotFoundException(tableHandle.getSchemaTableName());
|
||||
}
|
||||
if (columns.isEmpty()) {
|
||||
throw new PrestoException(NOT_SUPPORTED, "Table has no supported column types: " + tableHandle.getSchemaTableName());
|
||||
}
|
||||
return ImmutableList.copyOf(columns);
|
||||
}
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConnectorPartitionResult getPartitions(JdbcTableHandle jdbcTableHandle, TupleDomain<ColumnHandle> tupleDomain)
|
||||
{
|
||||
// currently we don't support partitions
|
||||
return new ConnectorPartitionResult(
|
||||
ImmutableList.<ConnectorPartition>of(new JdbcPartition(jdbcTableHandle, tupleDomain)),
|
||||
tupleDomain);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConnectorSplitSource getPartitionSplits(JdbcPartition jdbcPartition)
|
||||
{
|
||||
if (jdbcSubTableEnable) {
|
||||
return subTableManager.getTableSplits(jdbcPartition);
|
||||
}
|
||||
JdbcTableHandle jdbcTableHandle = jdbcPartition.getJdbcTableHandle();
|
||||
List<HostAddress> of = ImmutableList.of();
|
||||
JdbcSplit jdbcSplit = new JdbcSplit(
|
||||
connectorId,
|
||||
jdbcTableHandle.getCatalogName(),
|
||||
jdbcTableHandle.getSchemaName(),
|
||||
jdbcTableHandle.getTableName(),
|
||||
connectionUrl,
|
||||
fromProperties(connectionProperties),
|
||||
jdbcPartition.getTupleDomain(),
|
||||
"", of, true, "", "", "", "", System.nanoTime(), 1, false, "");
|
||||
return new FixedSplitSource(connectorId, ImmutableList.of(jdbcSplit));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getConnection(JdbcSplit split)
|
||||
throws SQLException
|
||||
{
|
||||
Connection connection = driver.connect(split.getConnectionUrl(), toProperties(split.getConnectionProperties()));
|
||||
try {
|
||||
connection.setReadOnly(true);
|
||||
}
|
||||
catch (SQLException e) {
|
||||
connection.close();
|
||||
throw e;
|
||||
}
|
||||
return connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String buildSql(JdbcSplit split, List<JdbcColumnHandle> columnHandles)
|
||||
{
|
||||
return new QueryBuilder(identifierQuote).buildSql(
|
||||
dbType,
|
||||
split.getCatalogName(),
|
||||
split.getSchemaName(),
|
||||
split.getTableName(),
|
||||
columnHandles,
|
||||
split.getTupleDomain());
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcOutputTableHandle beginCreateTable(ConnectorTableMetadata tableMetadata)
|
||||
{
|
||||
SchemaTableName schemaTableName = tableMetadata.getTable();
|
||||
String schema = schemaTableName.getSchemaName();
|
||||
String table = schemaTableName.getTableName();
|
||||
|
||||
if (!getSchemaNames().contains(schema)) {
|
||||
throw new PrestoException(NOT_FOUND, "Schema not found: " + schema);
|
||||
}
|
||||
|
||||
try (Connection connection = driver.connect(connectionUrl, connectionProperties)) {
|
||||
boolean uppercase = connection.getMetaData().storesUpperCaseIdentifiers();
|
||||
if (uppercase) {
|
||||
schema = schema.toUpperCase(ENGLISH);
|
||||
table = table.toUpperCase(ENGLISH);
|
||||
}
|
||||
String catalog = connection.getCatalog();
|
||||
|
||||
String temporaryName = "tmp_presto_" + UUID.randomUUID().toString().replace("-", "");
|
||||
StringBuilder sql = new StringBuilder()
|
||||
.append("CREATE TABLE ")
|
||||
.append(quoted(catalog, schema, temporaryName))
|
||||
.append(" (");
|
||||
ImmutableList.Builder<String> columnNames = ImmutableList.builder();
|
||||
ImmutableList.Builder<Type> columnTypes = ImmutableList.builder();
|
||||
ImmutableList.Builder<String> columnList = ImmutableList.builder();
|
||||
for (ColumnMetadata column : tableMetadata.getColumns()) {
|
||||
String columnName = column.getName();
|
||||
if (uppercase) {
|
||||
columnName = columnName.toUpperCase(ENGLISH);
|
||||
}
|
||||
columnNames.add(columnName);
|
||||
columnTypes.add(column.getType());
|
||||
columnList.add(new StringBuilder()
|
||||
.append(quoted(columnName))
|
||||
.append(" ")
|
||||
.append(toSqlType(column.getType()))
|
||||
.toString());
|
||||
}
|
||||
Joiner.on(", ").appendTo(sql, columnList.build());
|
||||
sql.append(")");
|
||||
|
||||
execute(connection, sql.toString());
|
||||
|
||||
return new JdbcOutputTableHandle(
|
||||
connectorId,
|
||||
catalog,
|
||||
schema,
|
||||
table,
|
||||
columnNames.build(),
|
||||
columnTypes.build(),
|
||||
tableMetadata.getOwner(),
|
||||
temporaryName,
|
||||
connectionUrl,
|
||||
fromProperties(connectionProperties));
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void commitCreateTable(JdbcOutputTableHandle handle, Collection<Slice> fragments)
|
||||
{
|
||||
StringBuilder sql = new StringBuilder()
|
||||
.append("ALTER TABLE ")
|
||||
.append(quoted(handle.getCatalogName(), handle.getSchemaName(), handle.getTemporaryTableName()))
|
||||
.append(" RENAME TO ")
|
||||
.append(quoted(handle.getCatalogName(), handle.getSchemaName(), handle.getTableName()));
|
||||
|
||||
try (Connection connection = getConnection(handle)) {
|
||||
execute(connection, sql.toString());
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dropTable(JdbcTableHandle handle)
|
||||
{
|
||||
StringBuilder sql = new StringBuilder()
|
||||
.append("DROP TABLE ")
|
||||
.append(quoted(handle.getCatalogName(), handle.getSchemaName(), handle.getTableName()));
|
||||
|
||||
try (Connection connection = driver.connect(connectionUrl, connectionProperties)) {
|
||||
execute(connection, sql.toString());
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String buildInsertSql(JdbcOutputTableHandle handle)
|
||||
{
|
||||
String vars = Joiner.on(',').join(nCopies(handle.getColumnNames().size(), "?"));
|
||||
return new StringBuilder()
|
||||
.append("INSERT INTO ")
|
||||
.append(quoted(handle.getCatalogName(), handle.getSchemaName(), handle.getTemporaryTableName()))
|
||||
.append(" VALUES (").append(vars).append(")")
|
||||
.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getConnection(JdbcOutputTableHandle handle)
|
||||
throws SQLException
|
||||
{
|
||||
return driver.connect(handle.getConnectionUrl(), toProperties(handle.getConnectionProperties()));
|
||||
}
|
||||
|
||||
protected ResultSet getTables(Connection connection, String schemaName, String tableName)
|
||||
throws SQLException
|
||||
{
|
||||
return connection.getMetaData().getTables(connection.getCatalog(), schemaName, tableName, new String[] {"TABLE", "VIEW"});
|
||||
}
|
||||
|
||||
protected SchemaTableName getSchemaTableName(ResultSet resultSet)
|
||||
throws SQLException
|
||||
{
|
||||
return new SchemaTableName(
|
||||
resultSet.getString("TABLE_SCHEM").toLowerCase(ENGLISH),
|
||||
resultSet.getString("TABLE_NAME").toLowerCase(ENGLISH));
|
||||
}
|
||||
|
||||
protected void execute(Connection connection, String query)
|
||||
throws SQLException
|
||||
{
|
||||
try (Statement statement = connection.createStatement()) {
|
||||
log.debug("Execute: %s", query);
|
||||
statement.execute(query);
|
||||
}
|
||||
}
|
||||
|
||||
protected Type toPrestoType(int jdbcType)
|
||||
{
|
||||
switch (jdbcType) {
|
||||
case Types.BIT:
|
||||
case Types.BOOLEAN:
|
||||
return BOOLEAN;
|
||||
case Types.TINYINT:
|
||||
case Types.SMALLINT:
|
||||
case Types.INTEGER:
|
||||
case Types.BIGINT:
|
||||
return BIGINT;
|
||||
case Types.FLOAT:
|
||||
case Types.REAL:
|
||||
case Types.DOUBLE:
|
||||
case Types.NUMERIC:
|
||||
case Types.DECIMAL:
|
||||
return DOUBLE;
|
||||
case Types.CHAR:
|
||||
case Types.NCHAR:
|
||||
case Types.VARCHAR:
|
||||
case Types.NVARCHAR:
|
||||
case Types.LONGVARCHAR:
|
||||
case Types.LONGNVARCHAR:
|
||||
return VARCHAR;
|
||||
case Types.BINARY:
|
||||
case Types.VARBINARY:
|
||||
case Types.LONGVARBINARY:
|
||||
return VARBINARY;
|
||||
case Types.DATE:
|
||||
return DATE;
|
||||
case Types.TIME:
|
||||
return TIME;
|
||||
case Types.TIMESTAMP:
|
||||
return TIMESTAMP;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected String toSqlType(Type type)
|
||||
{
|
||||
String sqlType = SQL_TYPES.get(type);
|
||||
if (sqlType != null) {
|
||||
return sqlType;
|
||||
}
|
||||
throw new PrestoException(NOT_SUPPORTED, "Unsuported column type: " + type.getTypeSignature());
|
||||
}
|
||||
|
||||
protected String quoted(String name)
|
||||
{
|
||||
name = name.replace(identifierQuote, identifierQuote + identifierQuote);
|
||||
return identifierQuote + name + identifierQuote;
|
||||
}
|
||||
|
||||
protected String quoted(String catalog, String schema, String table)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (!isNullOrEmpty(catalog)) {
|
||||
sb.append(quoted(catalog)).append(".");
|
||||
}
|
||||
if (!isNullOrEmpty(schema)) {
|
||||
sb.append(quoted(schema)).append(".");
|
||||
}
|
||||
sb.append(quoted(table));
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static Properties toProperties(Map<String, String> map)
|
||||
{
|
||||
Properties properties = new Properties();
|
||||
for (Map.Entry<String, String> entry : map.entrySet()) {
|
||||
properties.setProperty(entry.getKey(), entry.getValue());
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
public synchronized List<JdbcJavaBean> getTableDataSet(JdbcCacheSplit key)
|
||||
{
|
||||
return jdbcResultCache.getResult(key);
|
||||
}
|
||||
|
||||
public boolean isCacheTable(String tableName)
|
||||
{
|
||||
return cacheEnable && jdbcResultCache != null && jdbcResultCache.isCacheTable(tableName);
|
||||
}
|
||||
|
||||
public void commitPdboLogs(JdbcSplit split, long rowCount)
|
||||
{
|
||||
this.subTableManager.commitPdboLogs(split, rowCount);
|
||||
}
|
||||
|
||||
public int getDb_type()
|
||||
{
|
||||
return dbType;
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc;
|
||||
|
||||
import io.airlift.configuration.Config;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
public class BaseJdbcConfig
|
||||
{
|
||||
private String connectionUrl;
|
||||
private String connectionUser;
|
||||
private String connectionPassword;
|
||||
|
||||
@NotNull
|
||||
public String getConnectionUrl()
|
||||
{
|
||||
return connectionUrl;
|
||||
}
|
||||
|
||||
@Config("connection-url")
|
||||
public BaseJdbcConfig setConnectionUrl(String connectionUrl)
|
||||
{
|
||||
this.connectionUrl = connectionUrl;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getConnectionUser()
|
||||
{
|
||||
return connectionUser;
|
||||
}
|
||||
|
||||
@Config("connection-user")
|
||||
public BaseJdbcConfig setConnectionUser(String connectionUser)
|
||||
{
|
||||
this.connectionUser = connectionUser;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getConnectionPassword()
|
||||
{
|
||||
return connectionPassword;
|
||||
}
|
||||
|
||||
@Config("connection-password")
|
||||
public BaseJdbcConfig setConnectionPassword(String connectionPassword)
|
||||
{
|
||||
this.connectionPassword = connectionPassword;
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc;
|
||||
|
||||
import com.facebook.presto.spi.ColumnHandle;
|
||||
import com.facebook.presto.spi.ConnectorPartitionResult;
|
||||
import com.facebook.presto.spi.ConnectorSplitSource;
|
||||
import com.facebook.presto.spi.ConnectorTableMetadata;
|
||||
import com.facebook.presto.spi.SchemaTableName;
|
||||
import com.facebook.presto.spi.TupleDomain;
|
||||
import io.airlift.slice.Slice;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public interface JdbcClient
|
||||
{
|
||||
Set<String> getSchemaNames();
|
||||
|
||||
List<SchemaTableName> getTableNames(@Nullable String schema);
|
||||
|
||||
@Nullable
|
||||
JdbcTableHandle getTableHandle(SchemaTableName schemaTableName);
|
||||
|
||||
List<JdbcColumnHandle> getColumns(JdbcTableHandle tableHandle);
|
||||
|
||||
ConnectorPartitionResult getPartitions(JdbcTableHandle jdbcTableHandle, TupleDomain<ColumnHandle> tupleDomain);
|
||||
|
||||
ConnectorSplitSource getPartitionSplits(JdbcPartition jdbcPartition);
|
||||
|
||||
Connection getConnection(JdbcSplit split)
|
||||
throws SQLException;
|
||||
|
||||
String buildSql(JdbcSplit split, List<JdbcColumnHandle> columnHandles);
|
||||
|
||||
JdbcOutputTableHandle beginCreateTable(ConnectorTableMetadata tableMetadata);
|
||||
|
||||
void commitCreateTable(JdbcOutputTableHandle handle, Collection<Slice> fragments);
|
||||
|
||||
void dropTable(JdbcTableHandle jdbcTableHandle);
|
||||
|
||||
String buildInsertSql(JdbcOutputTableHandle handle);
|
||||
|
||||
Connection getConnection(JdbcOutputTableHandle handle)
|
||||
throws SQLException;
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc;
|
||||
|
||||
import com.facebook.presto.spi.ColumnMetadata;
|
||||
import com.facebook.presto.spi.ColumnHandle;
|
||||
import com.facebook.presto.spi.type.Type;
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import static com.google.common.base.MoreObjects.toStringHelper;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public final class JdbcColumnHandle
|
||||
implements ColumnHandle
|
||||
{
|
||||
private final String connectorId;
|
||||
private final String columnName;
|
||||
private final Type columnType;
|
||||
|
||||
@JsonCreator
|
||||
public JdbcColumnHandle(
|
||||
@JsonProperty("connectorId") String connectorId,
|
||||
@JsonProperty("columnName") String columnName,
|
||||
@JsonProperty("columnType") Type columnType)
|
||||
{
|
||||
this.connectorId = checkNotNull(connectorId, "connectorId is null");
|
||||
this.columnName = checkNotNull(columnName, "columnName is null");
|
||||
this.columnType = checkNotNull(columnType, "columnType is null");
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
public String getConnectorId()
|
||||
{
|
||||
return connectorId;
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
public String getColumnName()
|
||||
{
|
||||
return columnName;
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
public Type getColumnType()
|
||||
{
|
||||
return columnType;
|
||||
}
|
||||
|
||||
public ColumnMetadata getColumnMetadata()
|
||||
{
|
||||
return new ColumnMetadata(columnName, columnType, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if ((obj == null) || (getClass() != obj.getClass())) {
|
||||
return false;
|
||||
}
|
||||
JdbcColumnHandle o = (JdbcColumnHandle) obj;
|
||||
return Objects.equals(this.connectorId, o.connectorId) &&
|
||||
Objects.equals(this.columnName, o.columnName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hash(connectorId, columnName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return toStringHelper(this)
|
||||
.add("connectorId", connectorId)
|
||||
.add("columnName", columnName)
|
||||
.add("columnType", columnType)
|
||||
.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc;
|
||||
|
||||
import com.facebook.presto.spi.Connector;
|
||||
import com.facebook.presto.spi.ConnectorHandleResolver;
|
||||
import com.facebook.presto.spi.ConnectorMetadata;
|
||||
import com.facebook.presto.spi.ConnectorRecordSetProvider;
|
||||
import com.facebook.presto.spi.ConnectorRecordSinkProvider;
|
||||
import com.facebook.presto.spi.ConnectorSplitManager;
|
||||
import io.airlift.bootstrap.LifeCycleManager;
|
||||
import io.airlift.log.Logger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class JdbcConnector
|
||||
implements Connector
|
||||
{
|
||||
private static final Logger log = Logger.get(JdbcConnector.class);
|
||||
|
||||
private final LifeCycleManager lifeCycleManager;
|
||||
private final JdbcMetadata jdbcMetadata;
|
||||
private final JdbcSplitManager jdbcSplitManager;
|
||||
private final JdbcRecordSetProvider jdbcRecordSetProvider;
|
||||
private final JdbcHandleResolver jdbcHandleResolver;
|
||||
private final JdbcRecordSinkProvider jdbcRecordSinkProvider;
|
||||
|
||||
@Inject
|
||||
public JdbcConnector(
|
||||
LifeCycleManager lifeCycleManager,
|
||||
JdbcMetadata jdbcMetadata,
|
||||
JdbcSplitManager jdbcSplitManager,
|
||||
JdbcRecordSetProvider jdbcRecordSetProvider,
|
||||
JdbcHandleResolver jdbcHandleResolver,
|
||||
JdbcRecordSinkProvider jdbcRecordSinkProvider)
|
||||
{
|
||||
this.lifeCycleManager = checkNotNull(lifeCycleManager, "lifeCycleManager is null");
|
||||
this.jdbcMetadata = checkNotNull(jdbcMetadata, "jdbcMetadata is null");
|
||||
this.jdbcSplitManager = checkNotNull(jdbcSplitManager, "jdbcSplitManager is null");
|
||||
this.jdbcRecordSetProvider = checkNotNull(jdbcRecordSetProvider, "jdbcRecordSetProvider is null");
|
||||
this.jdbcHandleResolver = checkNotNull(jdbcHandleResolver, "jdbcHandleResolver is null");
|
||||
this.jdbcRecordSinkProvider = checkNotNull(jdbcRecordSinkProvider, "jdbcRecordSinkProvider is null");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConnectorMetadata getMetadata()
|
||||
{
|
||||
return jdbcMetadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConnectorSplitManager getSplitManager()
|
||||
{
|
||||
return jdbcSplitManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConnectorRecordSetProvider getRecordSetProvider()
|
||||
{
|
||||
return jdbcRecordSetProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConnectorHandleResolver getHandleResolver()
|
||||
{
|
||||
return jdbcHandleResolver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConnectorRecordSinkProvider getRecordSinkProvider()
|
||||
{
|
||||
return jdbcRecordSinkProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void shutdown()
|
||||
{
|
||||
try {
|
||||
lifeCycleManager.stop();
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error(e, "Error shutting down connector");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc;
|
||||
|
||||
import com.facebook.presto.spi.Connector;
|
||||
import com.facebook.presto.spi.ConnectorFactory;
|
||||
import com.facebook.presto.spi.classloader.ThreadContextClassLoader;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Module;
|
||||
import io.airlift.bootstrap.Bootstrap;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Strings.isNullOrEmpty;
|
||||
|
||||
public class JdbcConnectorFactory
|
||||
implements ConnectorFactory
|
||||
{
|
||||
private final String name;
|
||||
private final Module module;
|
||||
private final Map<String, String> optionalConfig;
|
||||
private final ClassLoader classLoader;
|
||||
|
||||
public JdbcConnectorFactory(String name, Module module, Map<String, String> optionalConfig, ClassLoader classLoader)
|
||||
{
|
||||
checkArgument(!isNullOrEmpty(name), "name is null or empty");
|
||||
this.name = name;
|
||||
this.module = checkNotNull(module, "module is null");
|
||||
this.optionalConfig = ImmutableMap.copyOf(checkNotNull(optionalConfig, "optionalConfig is null"));
|
||||
this.classLoader = checkNotNull(classLoader, "classLoader is null");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connector create(String connectorId, Map<String, String> requiredConfig)
|
||||
{
|
||||
checkNotNull(requiredConfig, "requiredConfig is null");
|
||||
checkNotNull(optionalConfig, "optionalConfig is null");
|
||||
|
||||
try (ThreadContextClassLoader ignored = new ThreadContextClassLoader(classLoader)) {
|
||||
Bootstrap app = new Bootstrap(new JdbcModule(connectorId), module);
|
||||
|
||||
Injector injector = app
|
||||
.strictConfig()
|
||||
.doNotInitializeLogging()
|
||||
.setRequiredConfigurationProperties(requiredConfig)
|
||||
.setOptionalConfigurationProperties(optionalConfig)
|
||||
.initialize();
|
||||
|
||||
return injector.getInstance(JdbcConnector.class);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public final class JdbcConnectorId
|
||||
{
|
||||
private final String id;
|
||||
|
||||
public JdbcConnectorId(String id)
|
||||
{
|
||||
this.id = checkNotNull(id, "id is null");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hash(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if ((obj == null) || (getClass() != obj.getClass())) {
|
||||
return false;
|
||||
}
|
||||
JdbcConnectorId other = (JdbcConnectorId) obj;
|
||||
return Objects.equals(this.id, other.id);
|
||||
}
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc;
|
||||
|
||||
import com.facebook.presto.spi.ColumnHandle;
|
||||
import com.facebook.presto.spi.ConnectorHandleResolver;
|
||||
import com.facebook.presto.spi.ConnectorOutputTableHandle;
|
||||
import com.facebook.presto.spi.ConnectorSplit;
|
||||
import com.facebook.presto.spi.ConnectorTableHandle;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class JdbcHandleResolver
|
||||
implements ConnectorHandleResolver
|
||||
{
|
||||
private final String connectorId;
|
||||
|
||||
@Inject
|
||||
public JdbcHandleResolver(JdbcConnectorId clientId)
|
||||
{
|
||||
this.connectorId = checkNotNull(clientId, "clientId is null").toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canHandle(ConnectorTableHandle tableHandle)
|
||||
{
|
||||
return tableHandle instanceof JdbcTableHandle && ((JdbcTableHandle) tableHandle).getConnectorId().equals(connectorId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canHandle(ColumnHandle columnHandle)
|
||||
{
|
||||
return columnHandle instanceof JdbcColumnHandle && ((JdbcColumnHandle) columnHandle).getConnectorId().equals(connectorId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canHandle(ConnectorSplit split)
|
||||
{
|
||||
return split instanceof JdbcSplit && ((JdbcSplit) split).getConnectorId().equals(connectorId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canHandle(ConnectorOutputTableHandle tableHandle)
|
||||
{
|
||||
return (tableHandle instanceof JdbcOutputTableHandle) && ((JdbcOutputTableHandle) tableHandle).getConnectorId().equals(connectorId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends ConnectorTableHandle> getTableHandleClass()
|
||||
{
|
||||
return JdbcTableHandle.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends ColumnHandle> getColumnHandleClass()
|
||||
{
|
||||
return JdbcColumnHandle.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends ConnectorSplit> getSplitClass()
|
||||
{
|
||||
return JdbcSplit.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends ConnectorOutputTableHandle> getOutputTableHandleClass()
|
||||
{
|
||||
return JdbcOutputTableHandle.class;
|
||||
}
|
||||
}
|
@ -0,0 +1,209 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc;
|
||||
|
||||
import com.facebook.presto.spi.ColumnMetadata;
|
||||
import com.facebook.presto.spi.ColumnHandle;
|
||||
import com.facebook.presto.spi.ConnectorInsertTableHandle;
|
||||
import com.facebook.presto.spi.ConnectorMetadata;
|
||||
import com.facebook.presto.spi.ConnectorOutputTableHandle;
|
||||
import com.facebook.presto.spi.ConnectorSession;
|
||||
import com.facebook.presto.spi.ConnectorTableHandle;
|
||||
import com.facebook.presto.spi.ConnectorTableMetadata;
|
||||
import com.facebook.presto.spi.InsertOption;
|
||||
import com.facebook.presto.spi.PrestoException;
|
||||
import com.facebook.presto.spi.SchemaTableName;
|
||||
import com.facebook.presto.spi.SchemaTablePrefix;
|
||||
import com.facebook.presto.spi.TableNotFoundException;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import io.airlift.slice.Slice;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.facebook.presto.plugin.jdbc.Types.checkType;
|
||||
import static com.facebook.presto.spi.StandardErrorCode.NOT_SUPPORTED;
|
||||
import static com.facebook.presto.spi.StandardErrorCode.PERMISSION_DENIED;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class JdbcMetadata
|
||||
implements ConnectorMetadata
|
||||
{
|
||||
private final JdbcClient jdbcClient;
|
||||
private final boolean allowDropTable;
|
||||
|
||||
@Inject
|
||||
public JdbcMetadata(JdbcConnectorId connectorId, JdbcClient jdbcClient, JdbcMetadataConfig config)
|
||||
{
|
||||
this.jdbcClient = checkNotNull(jdbcClient, "client is null");
|
||||
|
||||
checkNotNull(config, "config is null");
|
||||
allowDropTable = config.isAllowDropTable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> listSchemaNames(ConnectorSession session)
|
||||
{
|
||||
return ImmutableList.copyOf(jdbcClient.getSchemaNames());
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcTableHandle getTableHandle(ConnectorSession session, SchemaTableName tableName)
|
||||
{
|
||||
return jdbcClient.getTableHandle(tableName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConnectorTableMetadata getTableMetadata(ConnectorTableHandle table)
|
||||
{
|
||||
JdbcTableHandle handle = checkType(table, JdbcTableHandle.class, "tableHandle");
|
||||
|
||||
ImmutableList.Builder<ColumnMetadata> columnMetadata = ImmutableList.builder();
|
||||
for (JdbcColumnHandle column : jdbcClient.getColumns(handle)) {
|
||||
columnMetadata.add(column.getColumnMetadata());
|
||||
}
|
||||
return new ConnectorTableMetadata(handle.getSchemaTableName(), columnMetadata.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SchemaTableName> listTables(ConnectorSession session, String schemaNameOrNull)
|
||||
{
|
||||
return jdbcClient.getTableNames(schemaNameOrNull);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ColumnHandle getSampleWeightColumnHandle(ConnectorTableHandle tableHandle)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ColumnHandle> getColumnHandles(ConnectorTableHandle tableHandle)
|
||||
{
|
||||
JdbcTableHandle jdbcTableHandle = checkType(tableHandle, JdbcTableHandle.class, "tableHandle");
|
||||
|
||||
ImmutableMap.Builder<String, ColumnHandle> columnHandles = ImmutableMap.builder();
|
||||
for (JdbcColumnHandle column : jdbcClient.getColumns(jdbcTableHandle)) {
|
||||
columnHandles.put(column.getColumnMetadata().getName(), column);
|
||||
}
|
||||
return columnHandles.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<SchemaTableName, List<ColumnMetadata>> listTableColumns(ConnectorSession session, SchemaTablePrefix prefix)
|
||||
{
|
||||
ImmutableMap.Builder<SchemaTableName, List<ColumnMetadata>> columns = ImmutableMap.builder();
|
||||
for (SchemaTableName tableName : listTables(session, prefix.getSchemaName())) {
|
||||
try {
|
||||
JdbcTableHandle tableHandle = jdbcClient.getTableHandle(tableName);
|
||||
if (tableHandle == null) {
|
||||
continue;
|
||||
}
|
||||
columns.put(tableName, getTableMetadata(tableHandle).getColumns());
|
||||
}
|
||||
catch (TableNotFoundException e) {
|
||||
// table disappeared during listing operation
|
||||
}
|
||||
}
|
||||
return columns.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ColumnMetadata getColumnMetadata(ConnectorTableHandle tableHandle, ColumnHandle columnHandle)
|
||||
{
|
||||
checkType(tableHandle, JdbcTableHandle.class, "tableHandle");
|
||||
return checkType(columnHandle, JdbcColumnHandle.class, "columnHandle").getColumnMetadata();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canCreateSampledTables(ConnectorSession session)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createTable(ConnectorSession session, ConnectorTableMetadata tableMetadata)
|
||||
{
|
||||
throw new PrestoException(NOT_SUPPORTED, "This connector does not support creating tables");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dropTable(ConnectorTableHandle tableHandle)
|
||||
{
|
||||
if (!allowDropTable) {
|
||||
throw new PrestoException(PERMISSION_DENIED, "DROP TABLE is disabled in this catalog");
|
||||
}
|
||||
JdbcTableHandle handle = checkType(tableHandle, JdbcTableHandle.class, "tableHandle");
|
||||
jdbcClient.dropTable(handle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConnectorOutputTableHandle beginCreateTable(ConnectorSession session, ConnectorTableMetadata tableMetadata)
|
||||
{
|
||||
return jdbcClient.beginCreateTable(tableMetadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void commitCreateTable(ConnectorOutputTableHandle tableHandle, Collection<Slice> fragments)
|
||||
{
|
||||
JdbcOutputTableHandle handle = checkType(tableHandle, JdbcOutputTableHandle.class, "tableHandle");
|
||||
jdbcClient.commitCreateTable(handle, fragments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renameTable(ConnectorTableHandle tableHandle, SchemaTableName newTableName)
|
||||
{
|
||||
throw new PrestoException(NOT_SUPPORTED, "This connector does not support renaming tables");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConnectorInsertTableHandle beginInsert(ConnectorSession session, ConnectorTableHandle tableHandle, InsertOption insertOption)
|
||||
{
|
||||
throw new PrestoException(NOT_SUPPORTED, "This connector does not support inserts");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void commitInsert(ConnectorInsertTableHandle insertHandle, Collection<Slice> fragments)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createView(ConnectorSession session, SchemaTableName viewName, String viewData, boolean replace)
|
||||
{
|
||||
throw new PrestoException(NOT_SUPPORTED, "This connector does not support creating views");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dropView(ConnectorSession session, SchemaTableName viewName)
|
||||
{
|
||||
throw new PrestoException(NOT_SUPPORTED, "This connector does not support dropping views");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SchemaTableName> listViews(ConnectorSession session, String schemaNameOrNull)
|
||||
{
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<SchemaTableName, String> getViews(ConnectorSession session, SchemaTablePrefix prefix)
|
||||
{
|
||||
return ImmutableMap.of();
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc;
|
||||
|
||||
import io.airlift.configuration.Config;
|
||||
import io.airlift.configuration.ConfigDescription;
|
||||
|
||||
public class JdbcMetadataConfig
|
||||
{
|
||||
private boolean allowDropTable;
|
||||
|
||||
public boolean isAllowDropTable()
|
||||
{
|
||||
return allowDropTable;
|
||||
}
|
||||
|
||||
@Config("allow-drop-table")
|
||||
@ConfigDescription("Allow connector to drop tables")
|
||||
public JdbcMetadataConfig setAllowDropTable(boolean allowDropTable)
|
||||
{
|
||||
this.allowDropTable = allowDropTable;
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc;
|
||||
|
||||
import com.google.inject.Binder;
|
||||
import com.google.inject.Module;
|
||||
import com.google.inject.Scopes;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static io.airlift.configuration.ConfigBinder.configBinder;
|
||||
|
||||
public class JdbcModule
|
||||
implements Module
|
||||
{
|
||||
private final String connectorId;
|
||||
|
||||
public JdbcModule(String connectorId)
|
||||
{
|
||||
this.connectorId = checkNotNull(connectorId, "connector id is null");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(Binder binder)
|
||||
{
|
||||
binder.bind(JdbcConnectorId.class).toInstance(new JdbcConnectorId(connectorId));
|
||||
binder.bind(JdbcMetadata.class).in(Scopes.SINGLETON);
|
||||
binder.bind(JdbcSplitManager.class).in(Scopes.SINGLETON);
|
||||
binder.bind(JdbcRecordSetProvider.class).in(Scopes.SINGLETON);
|
||||
binder.bind(JdbcHandleResolver.class).in(Scopes.SINGLETON);
|
||||
binder.bind(JdbcRecordSinkProvider.class).in(Scopes.SINGLETON);
|
||||
binder.bind(JdbcConnector.class).in(Scopes.SINGLETON);
|
||||
configBinder(binder).bindConfig(JdbcMetadataConfig.class);
|
||||
}
|
||||
}
|
@ -0,0 +1,181 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc;
|
||||
|
||||
import com.facebook.presto.spi.ConnectorOutputTableHandle;
|
||||
import com.facebook.presto.spi.type.Type;
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static java.lang.String.format;
|
||||
|
||||
public class JdbcOutputTableHandle
|
||||
implements ConnectorOutputTableHandle
|
||||
{
|
||||
private final String connectorId;
|
||||
private final String catalogName;
|
||||
private final String schemaName;
|
||||
private final String tableName;
|
||||
private final List<String> columnNames;
|
||||
private final List<Type> columnTypes;
|
||||
private final String tableOwner;
|
||||
private final String temporaryTableName;
|
||||
private final String connectionUrl;
|
||||
private final Map<String, String> connectionProperties;
|
||||
|
||||
@JsonCreator
|
||||
public JdbcOutputTableHandle(
|
||||
@JsonProperty("connectorId") String connectorId,
|
||||
@JsonProperty("catalogName") @Nullable String catalogName,
|
||||
@JsonProperty("schemaName") @Nullable String schemaName,
|
||||
@JsonProperty("tableName") String tableName,
|
||||
@JsonProperty("columnNames") List<String> columnNames,
|
||||
@JsonProperty("columnTypes") List<Type> columnTypes,
|
||||
@JsonProperty("tableOwner") String tableOwner,
|
||||
@JsonProperty("temporaryTableName") String temporaryTableName,
|
||||
@JsonProperty("connectionUrl") String connectionUrl,
|
||||
@JsonProperty("connectionProperties") Map<String, String> connectionProperties)
|
||||
{
|
||||
this.connectorId = checkNotNull(connectorId, "connectorId is null");
|
||||
this.catalogName = catalogName;
|
||||
this.schemaName = schemaName;
|
||||
this.tableName = checkNotNull(tableName, "tableName is null");
|
||||
this.tableOwner = checkNotNull(tableOwner, "tableOwner is null");
|
||||
this.temporaryTableName = checkNotNull(temporaryTableName, "temporaryTableName is null");
|
||||
this.connectionUrl = checkNotNull(connectionUrl, "connectionUrl is null");
|
||||
this.connectionProperties = ImmutableMap.copyOf(checkNotNull(connectionProperties, "connectionProperties is null"));
|
||||
|
||||
checkNotNull(columnNames, "columnNames is null");
|
||||
checkNotNull(columnTypes, "columnTypes is null");
|
||||
checkArgument(columnNames.size() == columnTypes.size(), "columnNames and columnTypes sizes don't match");
|
||||
this.columnNames = ImmutableList.copyOf(columnNames);
|
||||
this.columnTypes = ImmutableList.copyOf(columnTypes);
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
public String getConnectorId()
|
||||
{
|
||||
return connectorId;
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
@Nullable
|
||||
public String getCatalogName()
|
||||
{
|
||||
return catalogName;
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
@Nullable
|
||||
public String getSchemaName()
|
||||
{
|
||||
return schemaName;
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
public String getTableName()
|
||||
{
|
||||
return tableName;
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
public List<String> getColumnNames()
|
||||
{
|
||||
return columnNames;
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
public List<Type> getColumnTypes()
|
||||
{
|
||||
return columnTypes;
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
public String getTableOwner()
|
||||
{
|
||||
return tableOwner;
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
public String getTemporaryTableName()
|
||||
{
|
||||
return temporaryTableName;
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
public String getConnectionUrl()
|
||||
{
|
||||
return connectionUrl;
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
public Map<String, String> getConnectionProperties()
|
||||
{
|
||||
return connectionProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return format("jdbc:%s.%s.%s", catalogName, schemaName, tableName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hash(
|
||||
connectorId,
|
||||
catalogName,
|
||||
schemaName,
|
||||
tableName,
|
||||
columnNames,
|
||||
columnTypes,
|
||||
tableOwner,
|
||||
temporaryTableName,
|
||||
connectionUrl,
|
||||
connectionProperties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null || getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
JdbcOutputTableHandle other = (JdbcOutputTableHandle) obj;
|
||||
return Objects.equals(this.connectorId, other.connectorId) &&
|
||||
Objects.equals(this.catalogName, other.catalogName) &&
|
||||
Objects.equals(this.schemaName, other.schemaName) &&
|
||||
Objects.equals(this.tableName, other.tableName) &&
|
||||
Objects.equals(this.columnNames, other.columnNames) &&
|
||||
Objects.equals(this.columnTypes, other.columnTypes) &&
|
||||
Objects.equals(this.tableOwner, other.tableOwner) &&
|
||||
Objects.equals(this.temporaryTableName, other.temporaryTableName) &&
|
||||
Objects.equals(this.connectionUrl, other.connectionUrl) &&
|
||||
Objects.equals(this.connectionProperties, other.connectionProperties);
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc;
|
||||
|
||||
import com.facebook.presto.spi.ColumnHandle;
|
||||
import com.facebook.presto.spi.ConnectorPartition;
|
||||
import com.facebook.presto.spi.TupleDomain;
|
||||
|
||||
import static com.google.common.base.MoreObjects.toStringHelper;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class JdbcPartition
|
||||
implements ConnectorPartition
|
||||
{
|
||||
private final JdbcTableHandle jdbcTableHandle;
|
||||
private final TupleDomain<ColumnHandle> domain;
|
||||
|
||||
public JdbcPartition(JdbcTableHandle jdbcTableHandle, TupleDomain<ColumnHandle> domain)
|
||||
{
|
||||
this.jdbcTableHandle = checkNotNull(jdbcTableHandle, "jdbcTableHandle is null");
|
||||
this.domain = checkNotNull(domain, "domain is null");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPartitionId()
|
||||
{
|
||||
return jdbcTableHandle.toString();
|
||||
}
|
||||
|
||||
public JdbcTableHandle getJdbcTableHandle()
|
||||
{
|
||||
return jdbcTableHandle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TupleDomain<ColumnHandle> getTupleDomain()
|
||||
{
|
||||
return domain;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return toStringHelper(this)
|
||||
.add("jdbcTableHandle", jdbcTableHandle)
|
||||
.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc;
|
||||
|
||||
import com.facebook.presto.spi.ConnectorFactory;
|
||||
import com.facebook.presto.spi.Plugin;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.inject.Module;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.google.common.base.MoreObjects.firstNonNull;
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Strings.isNullOrEmpty;
|
||||
|
||||
public class JdbcPlugin
|
||||
implements Plugin
|
||||
{
|
||||
private final String name;
|
||||
private final Module module;
|
||||
private Map<String, String> optionalConfig = ImmutableMap.of();
|
||||
|
||||
public JdbcPlugin(String name, Module module)
|
||||
{
|
||||
checkArgument(!isNullOrEmpty(name), "name is null or empty");
|
||||
this.name = name;
|
||||
this.module = checkNotNull(module, "module is null");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOptionalConfig(Map<String, String> optionalConfig)
|
||||
{
|
||||
this.optionalConfig = ImmutableMap.copyOf(checkNotNull(optionalConfig, "optionalConfig is null"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> getServices(Class<T> type)
|
||||
{
|
||||
if (type == ConnectorFactory.class) {
|
||||
return ImmutableList.of(type.cast(new JdbcConnectorFactory(name, module, optionalConfig, getClassLoader())));
|
||||
}
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
private static ClassLoader getClassLoader()
|
||||
{
|
||||
return firstNonNull(Thread.currentThread().getContextClassLoader(), JdbcPlugin.class.getClassLoader());
|
||||
}
|
||||
}
|
@ -0,0 +1,362 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc;
|
||||
|
||||
import com.facebook.presto.plugin.jdbc.cache.JdbcCacheSplit;
|
||||
import com.facebook.presto.plugin.jdbc.cache.JdbcJavaBean;
|
||||
import com.facebook.presto.spi.PrestoException;
|
||||
import com.facebook.presto.spi.RecordCursor;
|
||||
import com.facebook.presto.spi.type.BigintType;
|
||||
import com.facebook.presto.spi.type.DateType;
|
||||
import com.facebook.presto.spi.type.TimeType;
|
||||
import com.facebook.presto.spi.type.TimestampType;
|
||||
import com.facebook.presto.spi.type.Type;
|
||||
import com.facebook.presto.spi.type.VarbinaryType;
|
||||
import com.facebook.presto.spi.type.VarcharType;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import io.airlift.log.Logger;
|
||||
import io.airlift.slice.Slice;
|
||||
import org.joda.time.chrono.ISOChronology;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.Date;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.sql.Time;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import static com.facebook.presto.spi.StandardErrorCode.INTERNAL_ERROR;
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static com.google.common.base.Strings.isNullOrEmpty;
|
||||
import static io.airlift.slice.Slices.utf8Slice;
|
||||
import static io.airlift.slice.Slices.wrappedBuffer;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
|
||||
public class JdbcRecordCursor
|
||||
implements RecordCursor
|
||||
{
|
||||
private static final Logger log = Logger.get(JdbcRecordCursor.class);
|
||||
|
||||
private static final ISOChronology UTC_CHRONOLOGY = ISOChronology.getInstance(UTC);
|
||||
|
||||
private final List<JdbcColumnHandle> columnHandles;
|
||||
|
||||
private Connection connection;
|
||||
private Statement statement;
|
||||
private ResultSet resultSet;
|
||||
private boolean closed;
|
||||
|
||||
private List<JdbcJavaBean> tableDataSet;
|
||||
private boolean isCacheTable = false;
|
||||
private AtomicLong rowRecord = new AtomicLong(0);
|
||||
private BaseJdbcClient client;
|
||||
private JdbcSplit split;
|
||||
|
||||
public JdbcRecordCursor(JdbcClient jdbcClient, JdbcSplit split, List<JdbcColumnHandle> columnHandles)
|
||||
{
|
||||
this.client = (BaseJdbcClient) jdbcClient;
|
||||
this.split = split;
|
||||
isCacheTable = client.isCacheTable(split.getBaseTableName());
|
||||
this.columnHandles = ImmutableList.copyOf(checkNotNull(columnHandles, "columnHandles is null"));
|
||||
if (isCacheTable) {
|
||||
JdbcCacheSplit key = new JdbcCacheSplit(split.getConnectorId(), split.getCatalogName(),
|
||||
split.getSchemaName(), split.getTableName(), split.getConnectionUrl(), split.getBaseTableName());
|
||||
tableDataSet = client.getTableDataSet(key);
|
||||
}
|
||||
else {
|
||||
String sql = jdbcClient.buildSql(split, columnHandles);
|
||||
try {
|
||||
connection = jdbcClient.getConnection(split);
|
||||
statement = connection.createStatement();
|
||||
statement.setFetchSize(1000);
|
||||
|
||||
String whereCondition = split.getSplitPart();
|
||||
if (!isNullOrEmpty(whereCondition)) {
|
||||
if (whereCondition.indexOf("LIMIT") != -1) {
|
||||
sql += split.getSplitPart();
|
||||
}
|
||||
else {
|
||||
if (sql.indexOf("WHERE") != -1) {
|
||||
sql += " AND " + split.getSplitPart();
|
||||
}
|
||||
else {
|
||||
sql += " WHERE " + split.getSplitPart();
|
||||
}
|
||||
}
|
||||
}
|
||||
long startTime = System.currentTimeMillis();
|
||||
log.info("JdbcRecordCursor Executing: %s ", sql);
|
||||
resultSet = statement.executeQuery(sql);
|
||||
log.debug("The connection url: %s ,JdbcRecordCursor Executing: %s ,spend time : %s", split.getConnectionUrl(), sql, (System.currentTimeMillis() - startTime));
|
||||
}
|
||||
catch (SQLException e) {
|
||||
log.error("Execute sql [%s] error, connection url : %s", sql, split.getConnectionUrl());
|
||||
throw handleSqlException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getReadTimeNanos()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTotalBytes()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCompletedBytes()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType(int field)
|
||||
{
|
||||
return columnHandles.get(field).getColumnType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean advanceNextPosition()
|
||||
{
|
||||
if (closed) {
|
||||
return false;
|
||||
}
|
||||
boolean result;
|
||||
if (isCacheTable) {
|
||||
long andIncrement = rowRecord.incrementAndGet();
|
||||
result = andIncrement <= tableDataSet.size();
|
||||
}
|
||||
else {
|
||||
try {
|
||||
result = resultSet.next();
|
||||
if (result) {
|
||||
rowRecord.getAndIncrement();
|
||||
}
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw handleSqlException(e);
|
||||
}
|
||||
}
|
||||
if (!result) {
|
||||
close();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBoolean(int field)
|
||||
{
|
||||
checkState(!closed, "cursor is closed");
|
||||
if (isCacheTable) {
|
||||
return (boolean) getFieldValue(field);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
return resultSet.getBoolean(field + 1);
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw handleSqlException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong(int field)
|
||||
{
|
||||
checkState(!closed, "cursor is closed");
|
||||
try {
|
||||
Type type = getType(field);
|
||||
if (type.equals(BigintType.BIGINT)) {
|
||||
if (isCacheTable) {
|
||||
return (long) getFieldValue(field);
|
||||
}
|
||||
else {
|
||||
return resultSet.getLong(field + 1);
|
||||
}
|
||||
}
|
||||
if (type.equals(DateType.DATE)) {
|
||||
Date date = null;
|
||||
if (isCacheTable) {
|
||||
date = (Date) getFieldValue(field);
|
||||
}
|
||||
else {
|
||||
date = resultSet.getDate(field + 1);
|
||||
}
|
||||
// JDBC returns a date using a timestamp at midnight in the JVM timezone
|
||||
long localMillis = date.getTime();
|
||||
// Convert it to a midnight in UTC
|
||||
long utcMillis = ISOChronology.getInstance().getZone().getMillisKeepLocal(UTC, localMillis);
|
||||
// convert to days
|
||||
return TimeUnit.MILLISECONDS.toDays(utcMillis);
|
||||
}
|
||||
if (type.equals(TimeType.TIME)) {
|
||||
Time time = null;
|
||||
if (isCacheTable) {
|
||||
time = (Time) getFieldValue(field);
|
||||
}
|
||||
else {
|
||||
time = resultSet.getTime(field + 1);
|
||||
}
|
||||
return UTC_CHRONOLOGY.millisOfDay().get(time.getTime());
|
||||
}
|
||||
if (type.equals(TimestampType.TIMESTAMP)) {
|
||||
Timestamp timestamp = null;
|
||||
if (isCacheTable) {
|
||||
timestamp = (Timestamp) getFieldValue(field);
|
||||
}
|
||||
else {
|
||||
timestamp = resultSet.getTimestamp(field + 1);
|
||||
}
|
||||
return timestamp.getTime();
|
||||
}
|
||||
throw new PrestoException(INTERNAL_ERROR, "Unhandled type for long: " + type.getTypeSignature());
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw handleSqlException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDouble(int field)
|
||||
{
|
||||
checkState(!closed, "cursor is closed");
|
||||
if (isCacheTable) {
|
||||
return (double) getFieldValue(field);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
return resultSet.getDouble(field + 1);
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw handleSqlException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice getSlice(int field)
|
||||
{
|
||||
checkState(!closed, "cursor is closed");
|
||||
try {
|
||||
Type type = getType(field);
|
||||
if (type.equals(VarcharType.VARCHAR)) {
|
||||
String str = null;
|
||||
if (isCacheTable) {
|
||||
str = (String) getFieldValue(field);
|
||||
}
|
||||
else {
|
||||
str = resultSet.getString(field + 1);
|
||||
}
|
||||
return utf8Slice(str);
|
||||
}
|
||||
if (type.equals(VarbinaryType.VARBINARY)) {
|
||||
byte[] bytes = null;
|
||||
if (isCacheTable) {
|
||||
bytes = (byte[]) getFieldValue(field);
|
||||
}
|
||||
else {
|
||||
bytes = resultSet.getBytes(field + 1);
|
||||
}
|
||||
return wrappedBuffer(bytes);
|
||||
}
|
||||
throw new PrestoException(INTERNAL_ERROR, "Unhandled type for slice: " + type.getTypeSignature());
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw handleSqlException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNull(int field)
|
||||
{
|
||||
checkState(!closed, "cursor is closed");
|
||||
checkArgument(field < columnHandles.size(), "Invalid field index");
|
||||
|
||||
try {
|
||||
if (isCacheTable) {
|
||||
Object feildValue = getFieldValue(field);
|
||||
return feildValue == null;
|
||||
}
|
||||
// JDBC is kind of dumb: we need to read the field and then ask
|
||||
// if it was null, which means we are wasting effort here.
|
||||
// We could save the result of the field access if it matters.
|
||||
resultSet.getObject(field + 1);
|
||||
|
||||
return resultSet.wasNull();
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw handleSqlException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"UnusedDeclaration", "EmptyTryBlock"})
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
if (closed) {
|
||||
return;
|
||||
}
|
||||
if (!isNullOrEmpty(split.getSplitField()) && split.isCalcStepEnable()) {
|
||||
client.commitPdboLogs(split, rowRecord.get());
|
||||
}
|
||||
closed = true;
|
||||
try {
|
||||
if (statement != null) {
|
||||
statement.cancel();
|
||||
}
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
// use try with resources to close everything properly
|
||||
try (ResultSet resultSet = this.resultSet;
|
||||
Statement statement = this.statement;
|
||||
Connection connection = this.connection) {
|
||||
// do nothing
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
}
|
||||
|
||||
private Object getFieldValue(int field)
|
||||
{
|
||||
String lowerCase = columnHandles.get(field).getColumnName().toLowerCase();
|
||||
JdbcJavaBean jdbcJavaBean = tableDataSet.get(rowRecord.intValue() - 1);
|
||||
return jdbcJavaBean.getFieldObjectValue(jdbcJavaBean.getColumns().indexOf(lowerCase));
|
||||
}
|
||||
|
||||
private RuntimeException handleSqlException(SQLException e)
|
||||
{
|
||||
try {
|
||||
close();
|
||||
}
|
||||
catch (Exception closeException) {
|
||||
e.addSuppressed(closeException);
|
||||
}
|
||||
return Throwables.propagate(e);
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc;
|
||||
|
||||
import com.facebook.presto.spi.RecordCursor;
|
||||
import com.facebook.presto.spi.RecordSet;
|
||||
import com.facebook.presto.spi.type.Type;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class JdbcRecordSet
|
||||
implements RecordSet
|
||||
{
|
||||
private final JdbcClient jdbcClient;
|
||||
private final List<JdbcColumnHandle> columnHandles;
|
||||
private final List<Type> columnTypes;
|
||||
private final JdbcSplit split;
|
||||
|
||||
public JdbcRecordSet(JdbcClient jdbcClient, JdbcSplit split, List<JdbcColumnHandle> columnHandles)
|
||||
{
|
||||
this.jdbcClient = checkNotNull(jdbcClient, "jdbcClient is null");
|
||||
this.split = checkNotNull(split, "split is null");
|
||||
|
||||
checkNotNull(split, "split is null");
|
||||
this.columnHandles = checkNotNull(columnHandles, "column handles is null");
|
||||
ImmutableList.Builder<Type> types = ImmutableList.builder();
|
||||
for (JdbcColumnHandle column : columnHandles) {
|
||||
types.add(column.getColumnType());
|
||||
}
|
||||
this.columnTypes = types.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Type> getColumnTypes()
|
||||
{
|
||||
return columnTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecordCursor cursor()
|
||||
{
|
||||
return new JdbcRecordCursor(jdbcClient, split, columnHandles);
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc;
|
||||
|
||||
import com.facebook.presto.spi.ColumnHandle;
|
||||
import com.facebook.presto.spi.ConnectorRecordSetProvider;
|
||||
import com.facebook.presto.spi.ConnectorSplit;
|
||||
import com.facebook.presto.spi.RecordSet;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.facebook.presto.plugin.jdbc.Types.checkType;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class JdbcRecordSetProvider
|
||||
implements ConnectorRecordSetProvider
|
||||
{
|
||||
private final JdbcClient jdbcClient;
|
||||
|
||||
@Inject
|
||||
public JdbcRecordSetProvider(JdbcClient jdbcClient)
|
||||
{
|
||||
this.jdbcClient = checkNotNull(jdbcClient, "jdbcClient is null");
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecordSet getRecordSet(ConnectorSplit split, List<? extends ColumnHandle> columns)
|
||||
{
|
||||
JdbcSplit jdbcSplit = checkType(split, JdbcSplit.class, "split");
|
||||
|
||||
ImmutableList.Builder<JdbcColumnHandle> handles = ImmutableList.builder();
|
||||
for (ColumnHandle handle : columns) {
|
||||
handles.add(checkType(handle, JdbcColumnHandle.class, "columnHandle"));
|
||||
}
|
||||
|
||||
return new JdbcRecordSet(jdbcClient, jdbcSplit, handles.build());
|
||||
}
|
||||
}
|
@ -0,0 +1,205 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc;
|
||||
|
||||
import com.facebook.presto.spi.RecordSink;
|
||||
import com.facebook.presto.spi.type.Type;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import io.airlift.slice.Slice;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.joda.time.chrono.ISOChronology;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.Date;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static com.facebook.presto.spi.type.DateType.DATE;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
public class JdbcRecordSink
|
||||
implements RecordSink
|
||||
{
|
||||
private final Connection connection;
|
||||
private final PreparedStatement statement;
|
||||
|
||||
private final int fieldCount;
|
||||
private final List<Type> columnTypes;
|
||||
private int field = -1;
|
||||
private int batchSize;
|
||||
|
||||
public JdbcRecordSink(JdbcOutputTableHandle handle, JdbcClient jdbcClient)
|
||||
{
|
||||
try {
|
||||
connection = jdbcClient.getConnection(handle);
|
||||
connection.setAutoCommit(false);
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
|
||||
try {
|
||||
statement = connection.prepareStatement(jdbcClient.buildInsertSql(handle));
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
|
||||
fieldCount = handle.getColumnNames().size();
|
||||
columnTypes = handle.getColumnTypes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginRecord(long sampleWeight)
|
||||
{
|
||||
checkState(field == -1, "already in record");
|
||||
field = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishRecord()
|
||||
{
|
||||
checkState(field != -1, "not in record");
|
||||
checkState(field == fieldCount, "not all fields set");
|
||||
field = -1;
|
||||
|
||||
try {
|
||||
statement.addBatch();
|
||||
batchSize++;
|
||||
|
||||
if (batchSize >= 1000) {
|
||||
statement.executeBatch();
|
||||
connection.commit();
|
||||
connection.setAutoCommit(false);
|
||||
batchSize = 0;
|
||||
}
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendNull()
|
||||
{
|
||||
try {
|
||||
statement.setObject(next(), null);
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendBoolean(boolean value)
|
||||
{
|
||||
try {
|
||||
statement.setBoolean(next(), value);
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendLong(long value)
|
||||
{
|
||||
try {
|
||||
if (DATE.equals(columnTypes.get(field))) {
|
||||
// convert to midnight in default time zone
|
||||
long utcMillis = TimeUnit.DAYS.toMillis(value);
|
||||
long localMillis = ISOChronology.getInstanceUTC().getZone().getMillisKeepLocal(DateTimeZone.getDefault(), utcMillis);
|
||||
statement.setDate(next(), new Date(localMillis));
|
||||
}
|
||||
else {
|
||||
statement.setLong(next(), value);
|
||||
}
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendDouble(double value)
|
||||
{
|
||||
try {
|
||||
statement.setDouble(next(), value);
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendString(byte[] value)
|
||||
{
|
||||
try {
|
||||
statement.setString(next(), new String(value, UTF_8));
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Slice> commit()
|
||||
{
|
||||
// commit and close
|
||||
try (Connection connection = this.connection) {
|
||||
if (batchSize > 0) {
|
||||
statement.executeBatch();
|
||||
connection.commit();
|
||||
}
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
// the committer does not need any additional info
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
@Override
|
||||
public void rollback()
|
||||
{
|
||||
// rollback and close
|
||||
try (Connection connection = this.connection;
|
||||
PreparedStatement statement = this.statement) {
|
||||
connection.rollback();
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Type> getColumnTypes()
|
||||
{
|
||||
return columnTypes;
|
||||
}
|
||||
|
||||
private int next()
|
||||
{
|
||||
checkState(field != -1, "not in record");
|
||||
checkState(field < fieldCount, "all fields already set");
|
||||
field++;
|
||||
return field;
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc;
|
||||
|
||||
import com.facebook.presto.spi.ConnectorInsertTableHandle;
|
||||
import com.facebook.presto.spi.ConnectorOutputTableHandle;
|
||||
import com.facebook.presto.spi.ConnectorRecordSinkProvider;
|
||||
import com.facebook.presto.spi.RecordSink;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static com.facebook.presto.plugin.jdbc.Types.checkType;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class JdbcRecordSinkProvider
|
||||
implements ConnectorRecordSinkProvider
|
||||
{
|
||||
private final JdbcClient jdbcClient;
|
||||
|
||||
@Inject
|
||||
public JdbcRecordSinkProvider(JdbcClient jdbcClient)
|
||||
{
|
||||
this.jdbcClient = checkNotNull(jdbcClient, "jdbcClient is null");
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecordSink getRecordSink(ConnectorOutputTableHandle tableHandle)
|
||||
{
|
||||
return new JdbcRecordSink(checkType(tableHandle, JdbcOutputTableHandle.class, "tableHandle"), jdbcClient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecordSink getRecordSink(ConnectorInsertTableHandle tableHandle)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc;
|
||||
|
||||
import com.facebook.presto.spi.ColumnHandle;
|
||||
import com.facebook.presto.spi.ConnectorSplit;
|
||||
import com.facebook.presto.spi.HostAddress;
|
||||
import com.facebook.presto.spi.TupleDomain;
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class JdbcSplit
|
||||
implements ConnectorSplit
|
||||
{
|
||||
private final String connectorId;
|
||||
private final String catalogName;
|
||||
private final String schemaName;
|
||||
private final String tableName;
|
||||
private final String connectionUrl;
|
||||
private final Map<String, String> connectionProperties;
|
||||
private final TupleDomain<ColumnHandle> tupleDomain;
|
||||
private final String splitPart;
|
||||
private final List<HostAddress> addresses;
|
||||
private final boolean remotelyAccessible;
|
||||
private final String baseTableName;
|
||||
private final String splitField;
|
||||
private final String beginIndex;
|
||||
private final String endIndex;
|
||||
private final long timeStamp;
|
||||
private final int scanNodes;
|
||||
private final boolean isCalcStepEnable;
|
||||
private final String dbHost;
|
||||
|
||||
@JsonCreator
|
||||
public JdbcSplit(
|
||||
@JsonProperty("connectorId") String connectorId,
|
||||
@JsonProperty("catalogName") @Nullable String catalogName,
|
||||
@JsonProperty("schemaName") @Nullable String schemaName,
|
||||
@JsonProperty("tableName") String tableName,
|
||||
@JsonProperty("connectionUrl") String connectionUrl,
|
||||
@JsonProperty("connectionProperties") Map<String, String> connectionProperties,
|
||||
@JsonProperty("tupleDomain") TupleDomain<ColumnHandle> tupleDomain,
|
||||
@JsonProperty("splitPart") String splitPart,
|
||||
@JsonProperty("addresses") List<HostAddress> addresses,
|
||||
@JsonProperty("remotelyAccessible") boolean remotelyAccessible,
|
||||
@JsonProperty("baseTableName") String baseTableName,
|
||||
@JsonProperty("splitField") String splitField,
|
||||
@JsonProperty("beginIndex") String beginIndex,
|
||||
@JsonProperty("endIndex") String endIndex,
|
||||
@JsonProperty("timeStamp") long timeStamp,
|
||||
@JsonProperty("scanNodes") int scanNodes,
|
||||
@JsonProperty("isCalcStepEnable") boolean isCalcStepEnable,
|
||||
@JsonProperty("dbHost") String dbHost)
|
||||
{
|
||||
this.connectorId = checkNotNull(connectorId, "connector id is null");
|
||||
this.catalogName = catalogName;
|
||||
this.schemaName = schemaName;
|
||||
this.tableName = checkNotNull(tableName, "table name is null");
|
||||
this.connectionUrl = checkNotNull(connectionUrl, "connectionUrl is null");
|
||||
this.connectionProperties = ImmutableMap.copyOf(checkNotNull(connectionProperties, "connectionProperties is null"));
|
||||
this.tupleDomain = checkNotNull(tupleDomain, "tupleDomain is null");
|
||||
this.splitPart = splitPart;
|
||||
this.remotelyAccessible = remotelyAccessible;
|
||||
this.addresses = checkNotNull(addresses, "host addresses is null");
|
||||
this.baseTableName = baseTableName;
|
||||
this.splitField = splitField;
|
||||
this.beginIndex = beginIndex;
|
||||
this.endIndex = endIndex;
|
||||
this.timeStamp = timeStamp;
|
||||
this.scanNodes = scanNodes;
|
||||
this.isCalcStepEnable = isCalcStepEnable;
|
||||
this.dbHost = dbHost;
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
public String getConnectorId()
|
||||
{
|
||||
return connectorId;
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
@Nullable
|
||||
public String getCatalogName()
|
||||
{
|
||||
return catalogName;
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
@Nullable
|
||||
public String getSchemaName()
|
||||
{
|
||||
return schemaName;
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
public String getTableName()
|
||||
{
|
||||
return tableName;
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
public String getConnectionUrl()
|
||||
{
|
||||
return connectionUrl;
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
public Map<String, String> getConnectionProperties()
|
||||
{
|
||||
return connectionProperties;
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
public TupleDomain<ColumnHandle> getTupleDomain()
|
||||
{
|
||||
return tupleDomain;
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
@Override
|
||||
public boolean isRemotelyAccessible()
|
||||
{
|
||||
return remotelyAccessible;
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
@Override
|
||||
public List<HostAddress> getAddresses()
|
||||
{
|
||||
return addresses;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getInfo()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
public String getSplitPart()
|
||||
{
|
||||
return splitPart;
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
public String getBaseTableName()
|
||||
{
|
||||
return baseTableName;
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
public String getSplitField()
|
||||
{
|
||||
return splitField;
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
public String getBeginIndex()
|
||||
{
|
||||
return beginIndex;
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
public String getEndIndex()
|
||||
{
|
||||
return endIndex;
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
public long getTimeStamp()
|
||||
{
|
||||
return timeStamp;
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
public int getScanNodes()
|
||||
{
|
||||
return scanNodes;
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
public boolean isCalcStepEnable()
|
||||
{
|
||||
return isCalcStepEnable;
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
public String getDbHost()
|
||||
{
|
||||
return dbHost;
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc;
|
||||
|
||||
import com.facebook.presto.spi.ColumnHandle;
|
||||
import com.facebook.presto.spi.ConnectorPartition;
|
||||
import com.facebook.presto.spi.ConnectorPartitionResult;
|
||||
import com.facebook.presto.spi.ConnectorSplit;
|
||||
import com.facebook.presto.spi.ConnectorSplitManager;
|
||||
import com.facebook.presto.spi.ConnectorSplitSource;
|
||||
import com.facebook.presto.spi.ConnectorTableHandle;
|
||||
import com.facebook.presto.spi.FixedSplitSource;
|
||||
import com.facebook.presto.spi.TupleDomain;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.facebook.presto.plugin.jdbc.Types.checkType;
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class JdbcSplitManager
|
||||
implements ConnectorSplitManager
|
||||
{
|
||||
private final String connectorId;
|
||||
private final JdbcClient jdbcClient;
|
||||
|
||||
@Inject
|
||||
public JdbcSplitManager(JdbcConnectorId connectorId, JdbcClient jdbcClient)
|
||||
{
|
||||
this.connectorId = checkNotNull(connectorId, "connectorId is null").toString();
|
||||
this.jdbcClient = checkNotNull(jdbcClient, "client is null");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConnectorPartitionResult getPartitions(ConnectorTableHandle tableHandle, TupleDomain<ColumnHandle> tupleDomain)
|
||||
{
|
||||
JdbcTableHandle handle = checkType(tableHandle, JdbcTableHandle.class, "tableHandle");
|
||||
return jdbcClient.getPartitions(handle, tupleDomain);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConnectorSplitSource getPartitionSplits(ConnectorTableHandle tableHandle, List<ConnectorPartition> partitions)
|
||||
{
|
||||
if (partitions.isEmpty()) {
|
||||
return new FixedSplitSource(connectorId, ImmutableList.<ConnectorSplit>of());
|
||||
}
|
||||
|
||||
checkArgument(partitions.size() == 1, "Expected one partition but got %s", partitions.size());
|
||||
JdbcPartition partition = checkType(partitions.get(0), JdbcPartition.class, "partition");
|
||||
|
||||
return jdbcClient.getPartitionSplits(partition);
|
||||
}
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc;
|
||||
|
||||
import com.facebook.presto.spi.ConnectorTableHandle;
|
||||
import com.facebook.presto.spi.SchemaTableName;
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.google.common.base.Joiner;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public final class JdbcTableHandle
|
||||
implements ConnectorTableHandle
|
||||
{
|
||||
private final String connectorId;
|
||||
private final SchemaTableName schemaTableName;
|
||||
private final String catalogName;
|
||||
private final String schemaName;
|
||||
private final String tableName;
|
||||
|
||||
@JsonCreator
|
||||
public JdbcTableHandle(
|
||||
@JsonProperty("connectorId") String connectorId,
|
||||
@JsonProperty("schemaTableName") SchemaTableName schemaTableName,
|
||||
@JsonProperty("catalogName") @Nullable String catalogName,
|
||||
@JsonProperty("schemaName") @Nullable String schemaName,
|
||||
@JsonProperty("tableName") String tableName)
|
||||
{
|
||||
this.connectorId = checkNotNull(connectorId, "connectorId is null");
|
||||
this.schemaTableName = checkNotNull(schemaTableName, "schemaTableName is null");
|
||||
this.catalogName = catalogName;
|
||||
this.schemaName = schemaName;
|
||||
this.tableName = checkNotNull(tableName, "tableName is null");
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
public String getConnectorId()
|
||||
{
|
||||
return connectorId;
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
public SchemaTableName getSchemaTableName()
|
||||
{
|
||||
return schemaTableName;
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
@Nullable
|
||||
public String getCatalogName()
|
||||
{
|
||||
return catalogName;
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
@Nullable
|
||||
public String getSchemaName()
|
||||
{
|
||||
return schemaName;
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
public String getTableName()
|
||||
{
|
||||
return tableName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if ((obj == null) || (getClass() != obj.getClass())) {
|
||||
return false;
|
||||
}
|
||||
JdbcTableHandle o = (JdbcTableHandle) obj;
|
||||
return Objects.equals(this.connectorId, o.connectorId) &&
|
||||
Objects.equals(this.schemaTableName, o.schemaTableName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hash(connectorId, schemaTableName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return Joiner.on(":").useForNull("null").join(connectorId, schemaTableName, catalogName, schemaName, tableName);
|
||||
}
|
||||
}
|
@ -0,0 +1,199 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc;
|
||||
|
||||
import com.facebook.presto.spi.ColumnHandle;
|
||||
import com.facebook.presto.spi.Domain;
|
||||
import com.facebook.presto.spi.Range;
|
||||
import com.facebook.presto.spi.TupleDomain;
|
||||
import com.facebook.presto.spi.type.BigintType;
|
||||
import com.facebook.presto.spi.type.BooleanType;
|
||||
import com.facebook.presto.spi.type.DateType;
|
||||
import com.facebook.presto.spi.type.DoubleType;
|
||||
import com.facebook.presto.spi.type.TimestampType;
|
||||
import com.facebook.presto.spi.type.Type;
|
||||
import com.facebook.presto.spi.type.VarcharType;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import io.airlift.slice.Slice;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static com.google.common.base.Strings.isNullOrEmpty;
|
||||
import static com.google.common.collect.Iterables.getOnlyElement;
|
||||
import static com.google.common.collect.Iterables.transform;
|
||||
|
||||
public class QueryBuilder
|
||||
{
|
||||
private final String quote;
|
||||
|
||||
public QueryBuilder(String quote)
|
||||
{
|
||||
this.quote = checkNotNull(quote, "quote is null");
|
||||
}
|
||||
|
||||
public String buildSql(int dbtype, String catalog, String schema, String table, List<JdbcColumnHandle> columns, TupleDomain<ColumnHandle> tupleDomain)
|
||||
{
|
||||
StringBuilder sql = new StringBuilder();
|
||||
|
||||
sql.append("SELECT ");
|
||||
Joiner.on(", ").appendTo(sql, transform(columns, column -> quote(column.getColumnName())));
|
||||
if (columns.isEmpty()) {
|
||||
sql.append("null");
|
||||
}
|
||||
|
||||
sql.append(" FROM ");
|
||||
if (!isNullOrEmpty(catalog)) {
|
||||
sql.append(quote(catalog)).append('.');
|
||||
}
|
||||
if (!isNullOrEmpty(schema)) {
|
||||
sql.append(quote(schema)).append('.');
|
||||
}
|
||||
sql.append(quote(table));
|
||||
if (dbtype == BaseJdbcClient.TYPE_SQLSERVER) {
|
||||
sql.append(" WITH(NOLOCK) ");
|
||||
}
|
||||
|
||||
List<String> clauses = toConjuncts(columns, tupleDomain);
|
||||
if (!clauses.isEmpty()) {
|
||||
sql.append(" WHERE ")
|
||||
.append(Joiner.on(" AND ").join(clauses));
|
||||
}
|
||||
|
||||
return sql.toString();
|
||||
}
|
||||
|
||||
private List<String> toConjuncts(List<JdbcColumnHandle> columns, TupleDomain<ColumnHandle> tupleDomain)
|
||||
{
|
||||
ImmutableList.Builder<String> builder = ImmutableList.builder();
|
||||
for (JdbcColumnHandle column : columns) {
|
||||
Type type = column.getColumnType();
|
||||
if (type.equals(BigintType.BIGINT) || type.equals(DoubleType.DOUBLE) || type.equals(BooleanType.BOOLEAN)
|
||||
|| type.equals(VarcharType.VARCHAR) || type.equals(DateType.DATE) || type.equals(TimestampType.TIMESTAMP)) {
|
||||
Domain domain = tupleDomain.getDomains().get(column);
|
||||
if (domain != null) {
|
||||
builder.add(toPredicate(column.getColumnName(), domain, type));
|
||||
}
|
||||
}
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private String toPredicate(String columnName, Domain domain, Type columnType)
|
||||
{
|
||||
if (domain.getRanges().isNone() && domain.isNullAllowed()) {
|
||||
return quote(columnName) + " IS NULL";
|
||||
}
|
||||
|
||||
if (domain.getRanges().isAll() && !domain.isNullAllowed()) {
|
||||
return quote(columnName) + " IS NOT NULL";
|
||||
}
|
||||
|
||||
// Add disjuncts for ranges
|
||||
List<String> disjuncts = new ArrayList<>();
|
||||
List<Object> singleValues = new ArrayList<>();
|
||||
for (Range range : domain.getRanges()) {
|
||||
checkState(!range.isAll()); // Already checked
|
||||
if (range.isSingleValue()) {
|
||||
singleValues.add(range.getLow().getValue());
|
||||
}
|
||||
else {
|
||||
List<String> rangeConjuncts = new ArrayList<>();
|
||||
if (!range.getLow().isLowerUnbounded()) {
|
||||
switch (range.getLow().getBound()) {
|
||||
case ABOVE:
|
||||
rangeConjuncts.add(toPredicate(columnName, ">", range.getLow().getValue(), columnType));
|
||||
break;
|
||||
case EXACTLY:
|
||||
rangeConjuncts.add(toPredicate(columnName, ">=", range.getLow().getValue(), columnType));
|
||||
break;
|
||||
case BELOW:
|
||||
throw new IllegalArgumentException("Low Marker should never use BELOW bound: " + range);
|
||||
default:
|
||||
throw new AssertionError("Unhandled bound: " + range.getLow().getBound());
|
||||
}
|
||||
}
|
||||
if (!range.getHigh().isUpperUnbounded()) {
|
||||
switch (range.getHigh().getBound()) {
|
||||
case ABOVE:
|
||||
throw new IllegalArgumentException("High Marker should never use ABOVE bound: " + range);
|
||||
case EXACTLY:
|
||||
rangeConjuncts.add(toPredicate(columnName, "<=", range.getHigh().getValue(), columnType));
|
||||
break;
|
||||
case BELOW:
|
||||
rangeConjuncts.add(toPredicate(columnName, "<", range.getHigh().getValue(), columnType));
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError("Unhandled bound: " + range.getHigh().getBound());
|
||||
}
|
||||
}
|
||||
// If rangeConjuncts is null, then the range was ALL, which should already have been checked for
|
||||
checkState(!rangeConjuncts.isEmpty());
|
||||
disjuncts.add("(" + Joiner.on(" AND ").join(rangeConjuncts) + ")");
|
||||
}
|
||||
}
|
||||
|
||||
// Add back all of the possible single values either as an equality or an IN predicate
|
||||
if (singleValues.size() == 1) {
|
||||
disjuncts.add(toPredicate(columnName, "=", getOnlyElement(singleValues), columnType));
|
||||
}
|
||||
else if (singleValues.size() > 1) {
|
||||
ImmutableList.Builder<String> inListBuilder = ImmutableList.builder();
|
||||
singleValues.stream().forEach(value -> inListBuilder.add(encode(value, columnType)));
|
||||
disjuncts.add(quote(columnName) + " IN (" + Joiner.on(",").join(inListBuilder.build()) + ")");
|
||||
}
|
||||
|
||||
// Add nullability disjuncts
|
||||
checkState(!disjuncts.isEmpty());
|
||||
if (domain.isNullAllowed()) {
|
||||
disjuncts.add(quote(columnName) + " IS NULL");
|
||||
}
|
||||
|
||||
return "(" + Joiner.on(" OR ").join(disjuncts) + ")";
|
||||
}
|
||||
|
||||
private String toPredicate(String columnName, String operator, Object value, Type columnType)
|
||||
{
|
||||
return quote(columnName) + " " + operator + " " + encode(value, columnType);
|
||||
}
|
||||
|
||||
private String quote(String name)
|
||||
{
|
||||
name = name.replace(quote, quote + quote);
|
||||
return quote + name + quote;
|
||||
}
|
||||
|
||||
private static String encode(Object value, Type columnType)
|
||||
{
|
||||
if (value instanceof Number || value instanceof Boolean) {
|
||||
if (columnType.equals(DateType.DATE)) {
|
||||
return "'" + new SimpleDateFormat("yyyy-MM-dd").format(new Date(86400000 * Long.parseLong(value.toString(), 10))) + "'";
|
||||
}
|
||||
else if (columnType.equals(TimestampType.TIMESTAMP)) {
|
||||
return "'" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date(Long.parseLong(value.toString(), 10))) + "'";
|
||||
}
|
||||
return value.toString();
|
||||
}
|
||||
else if (value instanceof Slice) {
|
||||
return "'" + ((Slice) value).toStringUtf8() + "'";
|
||||
}
|
||||
throw new UnsupportedOperationException("Can't handle type: " + value.getClass().getName());
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public final class Types
|
||||
{
|
||||
private Types() {}
|
||||
|
||||
public static <A, B extends A> B checkType(A value, Class<B> target, String name)
|
||||
{
|
||||
checkNotNull(value, "%s is null", name);
|
||||
checkArgument(target.isInstance(value),
|
||||
"%s must be of type %s, not %s",
|
||||
name,
|
||||
target.getName(),
|
||||
value.getClass().getName());
|
||||
return target.cast(value);
|
||||
}
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc.cache;
|
||||
|
||||
import io.airlift.configuration.Config;
|
||||
import io.airlift.units.Duration;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class JdbcCacheConfig
|
||||
{
|
||||
public static final String DEFAULT_VALUE = "NA";
|
||||
private String cacheTableConfig = DEFAULT_VALUE;
|
||||
private String cacheTableClause;
|
||||
private Duration cacheRefreshInterval = new Duration(5, TimeUnit.MINUTES);
|
||||
private Duration cacheExpireInterval = new Duration(5, TimeUnit.MINUTES);
|
||||
private boolean jdbcCacheEnable = false;
|
||||
|
||||
public String getCacheTableConfig()
|
||||
{
|
||||
return cacheTableConfig;
|
||||
}
|
||||
|
||||
@Config("jdbc-cache-table-config")
|
||||
public JdbcCacheConfig setCacheTableConfig(String cacheTableConfig)
|
||||
{
|
||||
this.cacheTableConfig = cacheTableConfig;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getCacheTableClause()
|
||||
{
|
||||
return cacheTableClause;
|
||||
}
|
||||
|
||||
@Config("jdbc-cache-table-clause")
|
||||
public JdbcCacheConfig setCacheTableClause(String cacheTableClause)
|
||||
{
|
||||
this.cacheTableClause = cacheTableClause;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Duration getCacheRefreshInterval()
|
||||
{
|
||||
return cacheRefreshInterval;
|
||||
}
|
||||
|
||||
@Config("jdbc-cache-refresh-interval")
|
||||
public JdbcCacheConfig setCacheRefreshInterval(Duration cacheRefreshInterval)
|
||||
{
|
||||
this.cacheRefreshInterval = cacheRefreshInterval;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Duration getCacheExpireInterval()
|
||||
{
|
||||
return cacheExpireInterval;
|
||||
}
|
||||
|
||||
@Config("jdbc-cache-expire-interval")
|
||||
public JdbcCacheConfig setCacheExpireInterval(Duration cacheExpireInterval)
|
||||
{
|
||||
this.cacheExpireInterval = cacheExpireInterval;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean getJdbcCacheEnable()
|
||||
{
|
||||
return jdbcCacheEnable;
|
||||
}
|
||||
|
||||
@Config("jdbc-cache-enable")
|
||||
public JdbcCacheConfig setJdbcCacheEnable(boolean jdbcCacheEnable)
|
||||
{
|
||||
this.jdbcCacheEnable = jdbcCacheEnable;
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc.cache;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class JdbcCacheSplit
|
||||
{
|
||||
private final String connectorId;
|
||||
private final String catalogName;
|
||||
private final String schemaName;
|
||||
private final String tableName;
|
||||
private final String baseTableName;
|
||||
private final String connectionUrl;
|
||||
|
||||
public JdbcCacheSplit(String connectorId, String catalogName,
|
||||
String schemaName, String tableName, String connectionUrl, String baseTableName)
|
||||
{
|
||||
this.connectorId = checkNotNull(connectorId, "connector id is null");
|
||||
this.catalogName = catalogName;
|
||||
this.schemaName = schemaName;
|
||||
this.tableName = checkNotNull(tableName, "table name is null");
|
||||
this.connectionUrl = checkNotNull(connectionUrl, "connectionUrl is null");
|
||||
this.baseTableName = checkNotNull(baseTableName, "table name is null");
|
||||
}
|
||||
|
||||
public String getConnectorId()
|
||||
{
|
||||
return connectorId;
|
||||
}
|
||||
|
||||
public String getCatalogName()
|
||||
{
|
||||
return catalogName == null ? "null" : catalogName;
|
||||
}
|
||||
|
||||
public String getSchemaName()
|
||||
{
|
||||
return schemaName == null ? "null" : schemaName;
|
||||
}
|
||||
|
||||
public String getTableName()
|
||||
{
|
||||
return tableName;
|
||||
}
|
||||
|
||||
public String getBaseTableName()
|
||||
{
|
||||
return baseTableName;
|
||||
}
|
||||
|
||||
public String getConnectionUrl()
|
||||
{
|
||||
return connectionUrl;
|
||||
}
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hash(getConnectorId(), getConnectionUrl(), getCatalogName(), getSchemaName(), getTableName());
|
||||
}
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (obj instanceof JdbcCacheSplit) {
|
||||
JdbcCacheSplit other = (JdbcCacheSplit) obj;
|
||||
return this.getConnectorId().equals(other.getConnectorId())
|
||||
&& this.getConnectionUrl().equals(other.getConnectionUrl())
|
||||
&& this.getCatalogName().equals(other.getCatalogName())
|
||||
&& this.getSchemaName().equals(other.getSchemaName())
|
||||
&& this.getTableName().equals(other.getTableName());
|
||||
}
|
||||
else {
|
||||
return this.hashCode() == obj.hashCode();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return getConnectorId() + ","
|
||||
+ getConnectionUrl() + ","
|
||||
+ getCatalogName() + ","
|
||||
+ getSchemaName() + ","
|
||||
+ getTableName();
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc.cache;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class JdbcJavaBean
|
||||
{
|
||||
private List<String> columns;
|
||||
private Object[] values;
|
||||
public JdbcJavaBean(List<String> columns)
|
||||
{
|
||||
this.columns = columns;
|
||||
this.values = new Object[columns.size()];
|
||||
}
|
||||
|
||||
public Object getFieldObjectValue(int index)
|
||||
{
|
||||
return values[index];
|
||||
}
|
||||
|
||||
public void setFieldObjectValue(int index, Object value)
|
||||
{
|
||||
values[index] = value;
|
||||
}
|
||||
|
||||
public List<String> getColumns()
|
||||
{
|
||||
return columns;
|
||||
}
|
||||
}
|
@ -0,0 +1,227 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc.cache;
|
||||
|
||||
import io.airlift.log.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.Driver;
|
||||
import java.sql.Statement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.facebook.presto.plugin.jdbc.util.JdbcUtil;
|
||||
import com.facebook.presto.spi.type.BigintType;
|
||||
import com.facebook.presto.spi.type.BooleanType;
|
||||
import com.facebook.presto.spi.type.DateType;
|
||||
import com.facebook.presto.spi.type.DoubleType;
|
||||
import com.facebook.presto.spi.type.TimeType;
|
||||
import com.facebook.presto.spi.type.TimestampType;
|
||||
import com.facebook.presto.spi.type.Type;
|
||||
import com.facebook.presto.spi.type.VarbinaryType;
|
||||
import com.facebook.presto.spi.type.VarcharType;
|
||||
import com.fasterxml.jackson.core.JsonParseException;
|
||||
import com.fasterxml.jackson.databind.JsonMappingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Strings.isNullOrEmpty;
|
||||
import static java.util.Locale.ENGLISH;
|
||||
|
||||
public class JdbcResultCache
|
||||
{
|
||||
private final LoadingCache<JdbcCacheSplit, List<JdbcJavaBean>> jdbcResultCache;
|
||||
private final String identifierQuote;
|
||||
private final Driver driver;
|
||||
private final Properties connectionProperties;
|
||||
private static final Logger log = Logger.get(JdbcResultCache.class);
|
||||
private List<String> tableList = new ArrayList<String>();
|
||||
private HashMap<String, List<String>> fieldList = new HashMap<String, List<String>>();
|
||||
private LinkedHashMap<String, String> cacheTableClauseMap;
|
||||
|
||||
public JdbcResultCache(String identifierQuote,
|
||||
Driver driver,
|
||||
Properties connectionProperties,
|
||||
JdbcCacheConfig cacheConfig)
|
||||
{
|
||||
this.identifierQuote = identifierQuote;
|
||||
this.driver = driver;
|
||||
this.connectionProperties = connectionProperties;
|
||||
long expiresAfterWrite = checkNotNull(cacheConfig.getCacheExpireInterval(), "cacheExpireInterval is null").toMillis();
|
||||
long refreshAfterWrite = checkNotNull(cacheConfig.getCacheRefreshInterval(), "cacheRefreshInterval is null").toMillis();
|
||||
analyseCacheTableAndField(cacheConfig.getCacheTableConfig(), cacheConfig.getCacheTableClause());
|
||||
jdbcResultCache = CacheBuilder
|
||||
.newBuilder()
|
||||
.expireAfterWrite(expiresAfterWrite, TimeUnit.MILLISECONDS)
|
||||
.refreshAfterWrite(refreshAfterWrite, TimeUnit.MILLISECONDS)
|
||||
.build(new CacheLoader<JdbcCacheSplit, List<JdbcJavaBean>>(){
|
||||
@Override
|
||||
public List<JdbcJavaBean> load(JdbcCacheSplit key) throws Exception
|
||||
{
|
||||
return loadTableDataSet(key);
|
||||
}
|
||||
});
|
||||
}
|
||||
private List<JdbcJavaBean> loadTableDataSet(JdbcCacheSplit key)
|
||||
{
|
||||
log.debug("loadTableDataSet key : " + key);
|
||||
List<JdbcJavaBean> list = new ArrayList<JdbcJavaBean>();
|
||||
try {
|
||||
Connection connection = getConnection(key.getConnectionUrl());
|
||||
HashMap<String, Type> types = getColumnTypes(key);
|
||||
String tableName = key.getBaseTableName();
|
||||
List<String> columns = fieldList.get(tableName);
|
||||
String columnPart = Joiner.on(",").join(columns);
|
||||
String sql = "SELECT " + columnPart + " FROM " +
|
||||
JdbcUtil.getTableName(identifierQuote, key.getCatalogName(), key.getSchemaName(), key.getTableName());
|
||||
if (cacheTableClauseMap != null && !isNullOrEmpty(cacheTableClauseMap.get(tableName))) {
|
||||
sql += " WHERE " + cacheTableClauseMap.get(tableName);
|
||||
}
|
||||
Statement statement = connection.createStatement();
|
||||
statement.setFetchSize(10_000);
|
||||
long startTime = System.currentTimeMillis();
|
||||
ResultSet resultSet = statement.executeQuery(sql);
|
||||
log.debug("The connection url: %s ,ExecuteQuery: %s ,spend time : %s , thread id : %s", key.getConnectionUrl(), sql, (System.currentTimeMillis() - startTime), Thread.currentThread().getId());
|
||||
while (resultSet.next()) {
|
||||
JdbcJavaBean tableDataSet = new JdbcJavaBean(columns);
|
||||
for (int i = 1; i <= columns.size(); i++) {
|
||||
Type type = types.get(columns.get(i - 1));
|
||||
if (type.equals(BooleanType.BOOLEAN)) {
|
||||
tableDataSet.setFieldObjectValue((i - 1), resultSet.getBoolean(i));
|
||||
}
|
||||
else if (type.equals(BigintType.BIGINT)) {
|
||||
tableDataSet.setFieldObjectValue((i - 1), resultSet.getLong(i));
|
||||
}
|
||||
else if (type.equals(DateType.DATE)) {
|
||||
tableDataSet.setFieldObjectValue((i - 1), resultSet.getDate(i));
|
||||
}
|
||||
else if (type.equals(TimeType.TIME)) {
|
||||
tableDataSet.setFieldObjectValue((i - 1), resultSet.getTime(i));
|
||||
}
|
||||
else if (type.equals(TimestampType.TIMESTAMP)) {
|
||||
tableDataSet.setFieldObjectValue((i - 1), resultSet.getTimestamp(i));
|
||||
}
|
||||
else if (type.equals(DoubleType.DOUBLE)) {
|
||||
tableDataSet.setFieldObjectValue((i - 1), resultSet.getDouble(i));
|
||||
}
|
||||
else if (type.equals(VarcharType.VARCHAR)) {
|
||||
tableDataSet.setFieldObjectValue((i - 1), resultSet.getString(i));
|
||||
}
|
||||
else if (type.equals(VarbinaryType.VARBINARY)) {
|
||||
tableDataSet.setFieldObjectValue((i - 1), resultSet.getBytes(i));
|
||||
}
|
||||
}
|
||||
list.add(tableDataSet);
|
||||
}
|
||||
log.debug("The connection url: %s ,parse result: %s ,spend time : %s , thread id : %s", key.getConnectionUrl(), sql, (System.currentTimeMillis() - startTime), Thread.currentThread().getId());
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
public List<JdbcJavaBean> getResult(JdbcCacheSplit key)
|
||||
{
|
||||
try {
|
||||
return jdbcResultCache.get(key);
|
||||
}
|
||||
catch (ExecutionException e) {
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
}
|
||||
|
||||
public HashMap<String, Type> getColumnTypes(JdbcCacheSplit key)
|
||||
{
|
||||
HashMap<String, Type> types = new HashMap<String, Type>();
|
||||
try (Connection connection = getConnection(key.getConnectionUrl())) {
|
||||
DatabaseMetaData metadata = connection.getMetaData();
|
||||
try (ResultSet resultSet = metadata.getColumns(key.getSchemaName(), key.getCatalogName(), key.getTableName(), null)) {
|
||||
while (resultSet.next()) {
|
||||
Type columnType = JdbcUtil.toPrestoType(resultSet.getInt("DATA_TYPE"));
|
||||
if (columnType != null) {
|
||||
String columnName = resultSet.getString("COLUMN_NAME").toLowerCase(ENGLISH);
|
||||
types.put(columnName, columnType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
return types;
|
||||
}
|
||||
|
||||
public Connection getConnection(String connectionURL)
|
||||
throws SQLException
|
||||
{
|
||||
Connection connection = driver.connect(connectionURL, connectionProperties);
|
||||
try {
|
||||
connection.setReadOnly(true);
|
||||
}
|
||||
catch (SQLException e) {
|
||||
connection.close();
|
||||
throw e;
|
||||
}
|
||||
return connection;
|
||||
}
|
||||
|
||||
private void analyseCacheTableAndField(String cacheTableConfig, String cacheTableClause)
|
||||
{
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
try {
|
||||
// table name and column field
|
||||
List<LinkedHashMap<String, Object>> readValue = objectMapper.readValue(cacheTableConfig.toLowerCase(ENGLISH), ArrayList.class);
|
||||
for (LinkedHashMap<String, Object> map : readValue) {
|
||||
for (String t : map.keySet()) {
|
||||
tableList.add(t);
|
||||
ArrayList<String> object = (ArrayList<String>) map.get(t);
|
||||
fieldList.put(t, object);
|
||||
}
|
||||
}
|
||||
if (!isNullOrEmpty(cacheTableClause)) {
|
||||
// table where condition
|
||||
cacheTableClauseMap = (LinkedHashMap<String, String>) objectMapper.readValue(cacheTableClause, Map.class);
|
||||
}
|
||||
}
|
||||
catch (JsonParseException e) {
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
catch (JsonMappingException e) {
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isCacheTable(String tableName)
|
||||
{
|
||||
return tableList.contains(tableName);
|
||||
}
|
||||
}
|
@ -0,0 +1,255 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc.subtable;
|
||||
|
||||
import static java.util.Locale.ENGLISH;
|
||||
import io.airlift.log.Logger;
|
||||
import io.airlift.units.Duration;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import org.apache.commons.dbutils.DbUtils;
|
||||
import org.apache.commons.dbutils.QueryRunner;
|
||||
import org.apache.commons.dbutils.ResultSetHandler;
|
||||
|
||||
import com.facebook.presto.plugin.jdbc.JdbcSplit;
|
||||
import com.facebook.presto.plugin.jdbc.subtable.PdboTableInfo.DBType;
|
||||
import com.facebook.presto.plugin.jdbc.util.JdbcUtil;
|
||||
import com.facebook.presto.plugin.jdbc.util.PdboMetadata;
|
||||
import com.facebook.presto.server.PrestoServer;
|
||||
import com.mysql.jdbc.Driver;
|
||||
|
||||
public class JdbcLoadTread implements Runnable
|
||||
{
|
||||
private static final Logger log = Logger.get(JdbcLoadTread.class);
|
||||
|
||||
protected final String connectionUrl;
|
||||
protected final Properties connectionProperties;
|
||||
protected final String connectorId;
|
||||
protected final Duration jdbcReloadSubtableInterval;
|
||||
private long lastLoadSubTableTimeStamp = 0L;
|
||||
protected final Driver driver;
|
||||
private final boolean jdbcSubTableAllocator;
|
||||
|
||||
private final ConcurrentMap<PdboTableInfo, ArrayList<PdboSplit>> pdboTables = new ConcurrentHashMap<>();
|
||||
|
||||
public JdbcLoadTread(String connectionUrl,
|
||||
Properties connectionProperties,
|
||||
String connectorId,
|
||||
Duration jdbcReloadSubtableInterval) throws SQLException
|
||||
{
|
||||
this.connectionUrl = connectionUrl;
|
||||
this.connectionProperties = connectionProperties;
|
||||
this.connectorId = connectorId;
|
||||
this.jdbcReloadSubtableInterval = jdbcReloadSubtableInterval;
|
||||
this.driver = new Driver();
|
||||
this.jdbcSubTableAllocator = PrestoServer.isCoordinator();
|
||||
}
|
||||
|
||||
public void run()
|
||||
{
|
||||
while (jdbcSubTableAllocator) {
|
||||
try {
|
||||
if (lastLoadSubTableTimeStamp == 0) {
|
||||
loadPdboTableInfo();
|
||||
}
|
||||
else {
|
||||
Thread.sleep(jdbcReloadSubtableInterval.toMillis());
|
||||
long curTime = System.currentTimeMillis();
|
||||
loadPdboTableInfo();
|
||||
log.debug(connectorId + " load sub-table info spend time : " + (System.currentTimeMillis() - curTime) + " ms ");
|
||||
}
|
||||
lastLoadSubTableTimeStamp = System.currentTimeMillis();
|
||||
}
|
||||
catch (Exception e) {
|
||||
lastLoadSubTableTimeStamp = System.currentTimeMillis();
|
||||
log.error(e, connectorId + " Error reloading sub-table infomation : %s" , e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void loadPdboTableInfo()
|
||||
{
|
||||
String sql = PdboMetadata.getPdboTableInfoSQL();
|
||||
Connection conn = getConnection();
|
||||
QueryRunner runner = new QueryRunner();
|
||||
try {
|
||||
runner.query(conn, sql, new PdboTableResultHandle(), connectorId);
|
||||
}
|
||||
catch (SQLException e) {
|
||||
log.error(e, "loadPdboTableInfo Execute %s error : %s" , sql, e.getMessage());
|
||||
}
|
||||
finally {
|
||||
DbUtils.closeQuietly(conn);
|
||||
}
|
||||
}
|
||||
|
||||
public List<PdboSplit> getPDBOLogs(String connectorId, String schemaName, String tableName)
|
||||
{
|
||||
String sql = PdboMetadata.getPdboLogsSQL();
|
||||
Connection conn = getConnection();
|
||||
QueryRunner runner = new QueryRunner();
|
||||
List<PdboSplit> pdboSplits = null;
|
||||
try {
|
||||
pdboSplits = runner.query(conn, sql, new PdboLogsResultHandle(), connectorId, schemaName, tableName);
|
||||
}
|
||||
catch (SQLException e) {
|
||||
log.error(e, "getPDBOLogs Execute %s error : %s" , sql, e.getMessage());
|
||||
}
|
||||
finally {
|
||||
DbUtils.closeQuietly(conn);
|
||||
}
|
||||
return pdboSplits;
|
||||
}
|
||||
|
||||
private class PdboLogsResultHandle implements ResultSetHandler<List<PdboSplit>>
|
||||
{
|
||||
@Override
|
||||
public List<PdboSplit> handle(ResultSet rs) throws SQLException
|
||||
{
|
||||
List<PdboSplit> tables = new ArrayList<>();
|
||||
int scannodenumber = 0;
|
||||
//A.CONNECTORID,A.SCHEMANAME,A.TABLENAME,A.ROWS,A.BEGININDEX,A.ENDINDEX,B.DBTYPE,
|
||||
//C.DBHOST,C.DBPORT,C.CONNECTION_PROPERTIES,C.PRESTO_WORK_HOST,C.REMOTELYACCESSIBLE,C.SPLITFIELD,
|
||||
//C.SCANNODENUMBER,D.USERNAME,D.PASSWORD,A.CONTROL_SCAN_CONCURRENCY_ENABLED,A.SCAN_CONCURRENCY_COUNT
|
||||
while (rs.next()) {
|
||||
scannodenumber = rs.getInt(14);
|
||||
tables.add(new PdboSplit().setConnectorId(rs.getString(1)).
|
||||
setSchemaName(rs.getString(2)).
|
||||
setTableName(rs.getString(3)).
|
||||
setRows(rs.getLong(4)).
|
||||
setBeginIndex(rs.getLong(5)).
|
||||
setEndIndex(rs.getLong(6)).
|
||||
setDbHost(rs.getString(8)).
|
||||
setConnectionUrl(getConnectionURL(rs.getString(7), rs.getString(8), rs.getString(9), rs.getString(10))).
|
||||
setPrestoWorkHost(rs.getString(11)).
|
||||
setRemotelyAccessible(rs.getString(12)).
|
||||
setSplitField(rs.getString(13)).
|
||||
setScanNodes(rs.getInt(14)).
|
||||
setUsername(JdbcUtil.Base64Decode(rs.getString(15))).
|
||||
setPassword(JdbcUtil.Base64Decode(rs.getString(16))).
|
||||
setCalcStepEnable("Y").
|
||||
setControlScanConcurrencyEnabled(rs.getString(17)).
|
||||
setScanConcurrencyCount(rs.getInt(18)));
|
||||
}
|
||||
if (scannodenumber != tables.size()) {
|
||||
tables.clear();
|
||||
loadPdboTableInfo();
|
||||
}
|
||||
return tables;
|
||||
}
|
||||
}
|
||||
|
||||
private class PdboTableResultHandle implements ResultSetHandler<String>
|
||||
{
|
||||
@Override
|
||||
public String handle(ResultSet rs) throws SQLException
|
||||
{
|
||||
pdboTables.clear();
|
||||
//CONNECTORID,PRESTO_SCHEMA,PRESTO_TABLE,DBTYPE,PDBOENABLE,CONTROL_SCAN_CONCURRENCY_ENABLED,SCAN_CONCURRENCY_COUNT
|
||||
//DBHOST,DBPORT,CONNECTION_PROPERTIES,SOURCE_SCHEMA,SOURCE_TABLE,SPLITFIELD,REMOTELYACCESSIBLE,PRESTO_WORK_HOST,SCANNODENUMBER,
|
||||
//FIELDMAXVALUE,FIELDMINVALUE,USERNAME,PASSWORD,"
|
||||
while (rs.next()) {
|
||||
PdboTableInfo table = new PdboTableInfo(rs.getString(1).toLowerCase(ENGLISH),
|
||||
rs.getString(2).toLowerCase(ENGLISH), rs.getString(3).toLowerCase(ENGLISH));
|
||||
table.setDbType(rs.getString(4));
|
||||
table.setCalcStepEnable(rs.getString(5));
|
||||
table.setControlScanConcurrencyEnabled(rs.getString(6));
|
||||
table.setScanConcurrencyCount(rs.getInt(7));
|
||||
String connectionUrl = getConnectionURL(table.getDbType(), rs.getString(8), rs.getString(9), rs.getString(10));
|
||||
PdboSplit pdboSplit = new PdboSplit().setSchemaName(rs.getString(11).toLowerCase(ENGLISH)).
|
||||
setTableName(rs.getString(12).toLowerCase(ENGLISH)).
|
||||
setDbHost(rs.getString(8)).
|
||||
setConnectionUrl(connectionUrl).
|
||||
setSplitField(rs.getString(13)).
|
||||
setRemotelyAccessible(rs.getString(14)).
|
||||
setPrestoWorkHost(rs.getString(15)).
|
||||
setScanNodes(rs.getInt(16)).
|
||||
setFieldMaxValue(rs.getLong(17)).
|
||||
setFieldMinValue(rs.getLong(18)).
|
||||
setUsername(JdbcUtil.Base64Decode(rs.getString(19))).
|
||||
setPassword(JdbcUtil.Base64Decode(rs.getString(20))).
|
||||
setCalcStepEnable(rs.getString(5)).
|
||||
setControlScanConcurrencyEnabled(rs.getString(6)).
|
||||
setScanConcurrencyCount(rs.getInt(7));
|
||||
ArrayList<PdboSplit> routeList = pdboTables.get(table);
|
||||
if (routeList == null) {
|
||||
routeList = new ArrayList<>();
|
||||
}
|
||||
routeList.add(pdboSplit);
|
||||
pdboTables.put(table, routeList);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String getConnectionURL(String dbType, String dbHost, String dbPort, String connectionProperties)
|
||||
throws SQLException
|
||||
{
|
||||
String connectionUrl = "";
|
||||
if (dbType.equals(DBType.MYSQL.toString())) {
|
||||
connectionUrl = "jdbc:mysql://";
|
||||
}
|
||||
else if (dbType.equals(DBType.SQLSERVER.toString())) {
|
||||
connectionUrl = "jdbc:jtds:sqlserver://";
|
||||
}
|
||||
else if (dbType.equals(DBType.ORACLE.toString())) {
|
||||
connectionUrl = "jdbc:oracle:thin:@";
|
||||
}
|
||||
connectionUrl += dbHost + ":" + dbPort + connectionProperties;
|
||||
return connectionUrl;
|
||||
}
|
||||
|
||||
public ConcurrentMap<PdboTableInfo, ArrayList<PdboSplit>> getPdboTableInfo()
|
||||
{
|
||||
return pdboTables;
|
||||
}
|
||||
|
||||
public void commitPdboLogs(JdbcSplit split, long rowCount)
|
||||
{
|
||||
Connection conn = getConnection();
|
||||
QueryRunner runner = new QueryRunner();
|
||||
String insertSql = PdboMetadata.getInsertPdboLogSQL(split, rowCount, connectorId);
|
||||
String updateSql = PdboMetadata.getUpdatePdboHistoryLogSQL(split, connectorId);
|
||||
try {
|
||||
runner.update(conn, updateSql);
|
||||
runner.update(conn, insertSql);
|
||||
}
|
||||
catch (SQLException e) {
|
||||
log.error(e, "insert sql : %s,update sql : %s commitPdboLogs error : %s", insertSql, updateSql, e.getMessage());
|
||||
}
|
||||
finally {
|
||||
DbUtils.closeQuietly(conn);
|
||||
}
|
||||
}
|
||||
|
||||
public Connection getConnection()
|
||||
{
|
||||
Connection conn = null;
|
||||
try {
|
||||
conn = driver.connect(connectionUrl, connectionProperties);
|
||||
}
|
||||
catch (SQLException e) {
|
||||
log.error("Connect pdbo db error : " + e.getMessage());
|
||||
}
|
||||
return conn;
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc.subtable;
|
||||
|
||||
import io.airlift.configuration.Config;
|
||||
import io.airlift.units.Duration;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class JdbcSubTableConfig
|
||||
{
|
||||
public static final String DEFAULT_VALUE = "NA";
|
||||
|
||||
private String jdbcSubTableConnectionURL;
|
||||
private String jdbcSubTableConnectionUser;
|
||||
private String jdbcSubTableConnectionPassword;
|
||||
private Duration jdbcReloadSubtableInterval = new Duration(5, TimeUnit.MINUTES);
|
||||
private boolean jdbcSubTableEnable = false;
|
||||
|
||||
public String getJdbcSubTableConnectionURL()
|
||||
{
|
||||
return jdbcSubTableConnectionURL;
|
||||
}
|
||||
|
||||
@Config("jdbc-sub-table-connection-url")
|
||||
public JdbcSubTableConfig setJdbcSubTableConnectionURL(String connectionUrl)
|
||||
{
|
||||
this.jdbcSubTableConnectionURL = connectionUrl;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getJdbcSubTableConnectionUser()
|
||||
{
|
||||
return jdbcSubTableConnectionUser;
|
||||
}
|
||||
|
||||
@Config("jdbc-sub-table-connection-user")
|
||||
public JdbcSubTableConfig setJdbcSubTableConnectionUser(String connectionUser)
|
||||
{
|
||||
this.jdbcSubTableConnectionUser = connectionUser;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getJdbcSubTableConnectionPassword()
|
||||
{
|
||||
return jdbcSubTableConnectionPassword;
|
||||
}
|
||||
|
||||
@Config("jdbc-sub-table-connection-password")
|
||||
public JdbcSubTableConfig setJdbcSubTableConnectionPassword(String connectionPassword)
|
||||
{
|
||||
this.jdbcSubTableConnectionPassword = connectionPassword;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Duration getJdbcReloadSubtableInterval()
|
||||
{
|
||||
return jdbcReloadSubtableInterval;
|
||||
}
|
||||
|
||||
@Config("jdbc-reload-subtable-interval")
|
||||
public JdbcSubTableConfig setJdbcReloadSubtableInterval(Duration jdbcReloadSubtableInterval)
|
||||
{
|
||||
this.jdbcReloadSubtableInterval = jdbcReloadSubtableInterval;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean getJdbcSubTableEnable()
|
||||
{
|
||||
return jdbcSubTableEnable;
|
||||
}
|
||||
|
||||
@Config("jdbc-sub-table-enable")
|
||||
public JdbcSubTableConfig setJdbcSubTableEnable(boolean jdbcSubTableEnable)
|
||||
{
|
||||
this.jdbcSubTableEnable = jdbcSubTableEnable;
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,297 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc.subtable;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Strings.isNullOrEmpty;
|
||||
import static com.google.common.collect.Maps.fromProperties;
|
||||
import static java.util.Locale.ENGLISH;
|
||||
import io.airlift.log.Logger;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.Driver;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import com.facebook.presto.plugin.jdbc.JdbcPartition;
|
||||
import com.facebook.presto.plugin.jdbc.JdbcSplit;
|
||||
import com.facebook.presto.plugin.jdbc.JdbcTableHandle;
|
||||
import com.facebook.presto.plugin.jdbc.util.JdbcUtil;
|
||||
import com.facebook.presto.spi.ConnectorSplitSource;
|
||||
import com.facebook.presto.spi.HostAddress;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
public class JdbcSubTableManager
|
||||
{
|
||||
private static final Logger log = Logger.get(JdbcSubTableManager.class);
|
||||
|
||||
protected final String connectorId;
|
||||
protected final String identifierQuote;
|
||||
protected final Driver driver;
|
||||
protected final String defaultConnectionUrl;
|
||||
protected final Properties defaultConnectionProperties;
|
||||
protected final String jdbcSubTableConnectionUrl;
|
||||
protected final Properties jdbcSubTableConnectionProperties;
|
||||
|
||||
private JdbcLoadTread loadTread;
|
||||
|
||||
public JdbcSubTableManager(String connectorId,
|
||||
String identifierQuote,
|
||||
Driver driver,
|
||||
String defaultConnectionUrl,
|
||||
Properties defaultConnectionProperties,
|
||||
JdbcSubTableConfig config)
|
||||
{
|
||||
this.connectorId = checkNotNull(connectorId, "connectorId is null").toString();
|
||||
this.identifierQuote = checkNotNull(identifierQuote, "identifierQuote is null");
|
||||
this.driver = checkNotNull(driver, "driver is null");
|
||||
this.defaultConnectionUrl = defaultConnectionUrl;
|
||||
this.defaultConnectionProperties = defaultConnectionProperties;
|
||||
|
||||
checkNotNull(config, "config is null");
|
||||
jdbcSubTableConnectionUrl = config.getJdbcSubTableConnectionURL();
|
||||
jdbcSubTableConnectionProperties = new Properties();
|
||||
jdbcSubTableConnectionProperties.setProperty("user", config.getJdbcSubTableConnectionUser());
|
||||
jdbcSubTableConnectionProperties.setProperty("password", config.getJdbcSubTableConnectionPassword());
|
||||
|
||||
if (config.getJdbcSubTableEnable()) {
|
||||
try {
|
||||
loadTread = new JdbcLoadTread(config.getJdbcSubTableConnectionURL(), jdbcSubTableConnectionProperties,
|
||||
connectorId, config.getJdbcReloadSubtableInterval());
|
||||
}
|
||||
catch (SQLException e) {
|
||||
log.error("Init JdbcLoadTread error", e);
|
||||
}
|
||||
Thread loadTableThread = new Thread(loadTread);
|
||||
loadTableThread.setName("LoadTableThread");
|
||||
loadTableThread.setDaemon(true);
|
||||
loadTableThread.start();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get table splits
|
||||
* @param jdbcPartition
|
||||
* @return
|
||||
*/
|
||||
public ConnectorSplitSource getTableSplits(JdbcPartition jdbcPartition)
|
||||
{
|
||||
JdbcTableHandle jdbcTableHandle = jdbcPartition.getJdbcTableHandle();
|
||||
List<JdbcSplit> jdbcSplitsList = new ArrayList<JdbcSplit>();
|
||||
String schemaName = getSchemaName(jdbcTableHandle);
|
||||
PdboTableInfo key = new PdboTableInfo(connectorId, schemaName, jdbcTableHandle.getTableName().toLowerCase(ENGLISH));
|
||||
ArrayList<PdboSplit> pdboSplits = loadTread.getPdboTableInfo().get(key);
|
||||
if (JdbcUtil.checkListNullOrEmpty(pdboSplits)) {
|
||||
if (pdboSplits == null) {
|
||||
pdboSplits = new ArrayList<PdboSplit>();
|
||||
}
|
||||
PdboSplit config = new PdboSplit();
|
||||
config.setConnectionUrl(defaultConnectionUrl);
|
||||
config.setConnectorId(jdbcTableHandle.getCatalogName());
|
||||
config.setSchemaName(jdbcTableHandle.getSchemaName());
|
||||
config.setTableName(jdbcTableHandle.getTableName());
|
||||
config.setRemotelyAccessible("Y");
|
||||
config.setPrestoTableName(jdbcTableHandle.getTableName());
|
||||
pdboSplits.add(config);
|
||||
}
|
||||
long timeStamp = System.nanoTime();
|
||||
if (pdboSplits.get(0).isCalcStepEnable()) {
|
||||
jdbcSplitsList = getTableSplitsFromPdboLog(connectorId, schemaName, jdbcTableHandle.getTableName().toLowerCase(ENGLISH), jdbcPartition, timeStamp);
|
||||
}
|
||||
if (JdbcUtil.checkListNullOrEmpty(jdbcSplitsList)) {
|
||||
for (PdboSplit config : pdboSplits) {
|
||||
constructJdbcSplits(jdbcPartition, jdbcSplitsList, config, timeStamp);
|
||||
}
|
||||
}
|
||||
return new PdboSplitSource(connectorId, jdbcSplitsList, pdboSplits.get(0).getControlScanConcurrencyEnabled(), pdboSplits.get(0).getScanConcurrencyCount());
|
||||
}
|
||||
|
||||
private String getSchemaName(JdbcTableHandle jdbcTableHandle)
|
||||
{
|
||||
String schemaName = "";
|
||||
if (defaultConnectionUrl.indexOf("mysql") != -1) {
|
||||
schemaName = jdbcTableHandle.getCatalogName().toLowerCase(ENGLISH);
|
||||
}
|
||||
else {
|
||||
schemaName = jdbcTableHandle.getSchemaName().toLowerCase(ENGLISH);
|
||||
}
|
||||
return schemaName;
|
||||
}
|
||||
|
||||
private void constructJdbcSplits(JdbcPartition jdbcPartition,
|
||||
List<JdbcSplit> splits, PdboSplit config, long timeStamp)
|
||||
{
|
||||
List<HostAddress> addresses = getSplitHost(config.getPrestoWorkHost());
|
||||
Properties connectionProperties = resetConnectionProperties(config.getUsername(), config.getPassword());
|
||||
int scanNodes = config.getScanNodes() <= 0 ? 1 : config.getScanNodes();
|
||||
if (scanNodes == 1 || (scanNodes > 1 && isNullOrEmpty(config.getSplitField()))) {
|
||||
addJdbcSplit(jdbcPartition, splits, addresses, new String[]{"", "", ""}, connectionProperties, timeStamp, scanNodes, config);
|
||||
}
|
||||
else {
|
||||
splitTable(jdbcPartition, splits, config, addresses, connectionProperties, scanNodes, timeStamp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Splitting table by field or limit
|
||||
*/
|
||||
private void splitTable(JdbcPartition jdbcPartition,
|
||||
List<JdbcSplit> splits, PdboSplit config,
|
||||
List<HostAddress> addresses, Properties connectionProperties,
|
||||
int scanNodes, long timeStamp)
|
||||
{
|
||||
long tableTotalRecords = 0L;
|
||||
Long[] autoIncrementFieldMinAndMaxValue = new Long[2];
|
||||
autoIncrementFieldMinAndMaxValue = getSplitFieldMinAndMaxValue(config, connectionProperties);
|
||||
tableTotalRecords = autoIncrementFieldMinAndMaxValue[0] - autoIncrementFieldMinAndMaxValue[1];
|
||||
long targetChunkSize = (long) Math.ceil(tableTotalRecords * 1.0 / scanNodes);
|
||||
long chunkOffset = 0L;
|
||||
long autoIncrementOffset = 0L;
|
||||
while (chunkOffset < tableTotalRecords) {
|
||||
long chunkLength = Math.min(targetChunkSize, tableTotalRecords - chunkOffset);
|
||||
if (chunkOffset == 0) {
|
||||
autoIncrementOffset = autoIncrementFieldMinAndMaxValue[1] - 1;
|
||||
}
|
||||
String[] splitInfo = getSplitInfo(chunkOffset, autoIncrementOffset,
|
||||
autoIncrementFieldMinAndMaxValue, chunkLength, tableTotalRecords, config.getSplitField());
|
||||
addJdbcSplit(jdbcPartition, splits, addresses, splitInfo, connectionProperties, timeStamp, scanNodes, config);
|
||||
chunkOffset += chunkLength;
|
||||
autoIncrementOffset += chunkLength;
|
||||
}
|
||||
fillLastRecord(jdbcPartition, connectionProperties, splits, scanNodes, timeStamp, config.getFieldMaxValue(), config);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the table split by field,the filter conditions will follow like this :
|
||||
* field > offset and field <= offset + chunkLength.
|
||||
* @return splitInfo[0] : splitPart; splitInfo[1] : beginIndex; splitInfo[2] : endIndex;
|
||||
*/
|
||||
private String[] getSplitInfo(long chunkOffset, long autoIncrementOffset,
|
||||
Long[] autoIncrementFieldMinAndMaxValue, long chunkLength, long tableTotalRecords, String splitField)
|
||||
{
|
||||
String[] splitInfo = new String[3];
|
||||
String splitPart = "";
|
||||
splitInfo[1] = String.valueOf(autoIncrementOffset);
|
||||
splitPart = splitField + " > " + autoIncrementOffset + " and " + splitField + " <= ";
|
||||
if ((chunkOffset + chunkLength) == tableTotalRecords) {
|
||||
splitPart += autoIncrementFieldMinAndMaxValue[0];
|
||||
splitInfo[2] = String.valueOf(autoIncrementFieldMinAndMaxValue[0]);
|
||||
}
|
||||
else {
|
||||
splitPart += (autoIncrementOffset + chunkLength);
|
||||
splitInfo[2] = String.valueOf(autoIncrementOffset + chunkLength);
|
||||
}
|
||||
splitInfo[0] = splitPart;
|
||||
return splitInfo;
|
||||
}
|
||||
|
||||
private void addJdbcSplit(JdbcPartition jdbcPartition,
|
||||
List<JdbcSplit> builder, List<HostAddress> addresses, String[] splitInfo,
|
||||
Properties connectionProperties, long timeStamp, int scanNodes, PdboSplit config)
|
||||
{
|
||||
builder.add(new JdbcSplit(connectorId, config.getConnectorId(), config.getSchemaName(), config.getTableName(),
|
||||
config.getConnectionUrl(), fromProperties(connectionProperties), jdbcPartition.getTupleDomain(),
|
||||
splitInfo[0], addresses, config.getRemotelyAccessible(), config.getPrestoTableName(),
|
||||
config.getSplitField(), splitInfo[1], splitInfo[2], timeStamp, scanNodes, config.isCalcStepEnable(), config.getDbHost()));
|
||||
}
|
||||
|
||||
protected Long[] getSplitFieldMinAndMaxValue(PdboSplit conf, Properties connectionProperties)
|
||||
{
|
||||
Long[] value = new Long[2];
|
||||
if (conf.getFieldMaxValue() > 0) {
|
||||
value[0] = conf.getFieldMaxValue();
|
||||
value[1] = conf.getFieldMinValue();
|
||||
return value;
|
||||
}
|
||||
String sql = "SELECT MAX(" + conf.getSplitField() + "),MIN(" + conf.getSplitField() + ") FROM "
|
||||
+ JdbcUtil.getTableName(identifierQuote, conf.getConnectorId(), conf.getSchemaName(), conf.getTableName());
|
||||
Connection connection = null;
|
||||
Statement stat = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
connection = driver.connect(conf.getConnectionUrl(), connectionProperties);
|
||||
stat = connection.createStatement();
|
||||
rs = stat.executeQuery(sql.toString());
|
||||
while (rs.next()) {
|
||||
value[0] = rs.getLong(1);
|
||||
value[1] = rs.getLong(2);
|
||||
}
|
||||
}
|
||||
catch (SQLException e) {
|
||||
log.error("SQL : " + sql + ",getSplitFieldMinAndMaxValue error : " + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
finally {
|
||||
JdbcUtil.closeJdbcConnection(connection, stat, rs);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public List<JdbcSplit> getTableSplitsFromPdboLog(String catalogName, String schemaName, String tableName,
|
||||
JdbcPartition jdbcPartition, long timeStamp)
|
||||
{
|
||||
List<JdbcSplit> splits = new ArrayList<>();
|
||||
List<PdboSplit> pdboLogs = loadTread.getPDBOLogs(catalogName, schemaName, tableName);
|
||||
if (JdbcUtil.checkListNullOrEmpty(pdboLogs)) {
|
||||
return splits;
|
||||
}
|
||||
int scanNodes = pdboLogs.size();
|
||||
for (PdboSplit table : pdboLogs) {
|
||||
table.setConnectorId(null);
|
||||
List<HostAddress> addresses = getSplitHost(table.getPrestoWorkHost());
|
||||
Properties connectionProperties = resetConnectionProperties(table.getUsername(), table.getPassword());
|
||||
String splitPart = table.getSplitField() + " > " + table.getBeginIndex() + " and "
|
||||
+ table.getSplitField() + " <= " + table.getEndIndex();
|
||||
addJdbcSplit(jdbcPartition, splits, addresses,
|
||||
new String[]{splitPart, String.valueOf(table.getBeginIndex()), String.valueOf(table.getEndIndex())},
|
||||
connectionProperties, timeStamp, scanNodes, table);
|
||||
}
|
||||
PdboSplit lastRecord = pdboLogs.get(scanNodes - 1);
|
||||
fillLastRecord(jdbcPartition, resetConnectionProperties(lastRecord.getUsername(), lastRecord.getPassword()),
|
||||
splits, scanNodes, timeStamp, lastRecord.getEndIndex(), lastRecord);
|
||||
return splits;
|
||||
}
|
||||
|
||||
private void fillLastRecord(JdbcPartition jdbcPartition, Properties connectionProperties,
|
||||
List<JdbcSplit> splits, int scanNodes, long timeStamp, long endIndex, PdboSplit config)
|
||||
{
|
||||
String splitPart = config.getSplitField() + " > " + endIndex;
|
||||
addJdbcSplit(jdbcPartition, splits, getSplitHost(config.getPrestoWorkHost()),
|
||||
new String[]{splitPart, "", ""}, connectionProperties, timeStamp, scanNodes, config);
|
||||
}
|
||||
|
||||
private Properties resetConnectionProperties(String username, String password)
|
||||
{
|
||||
Properties connectionProperties = (Properties) defaultConnectionProperties.clone();
|
||||
if (!isNullOrEmpty(username) && !isNullOrEmpty(password)) {
|
||||
connectionProperties.setProperty("user", username);
|
||||
connectionProperties.setProperty("password", password);
|
||||
}
|
||||
return connectionProperties;
|
||||
}
|
||||
|
||||
private List<HostAddress> getSplitHost(String host)
|
||||
{
|
||||
return isNullOrEmpty(host) ? ImmutableList.of() : ImmutableList.of(HostAddress.fromString(host));
|
||||
}
|
||||
|
||||
public void commitPdboLogs(JdbcSplit split, long rowCount)
|
||||
{
|
||||
loadTread.commitPdboLogs(split, rowCount);
|
||||
}
|
||||
}
|
@ -0,0 +1,284 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc.subtable;
|
||||
|
||||
import com.facebook.presto.plugin.jdbc.util.JdbcUtil;
|
||||
|
||||
public class PdboSplit
|
||||
{
|
||||
private String connectorId;
|
||||
private String schemaName;
|
||||
private String tableName;
|
||||
private Long rows;
|
||||
private Long beginIndex;
|
||||
private Long endIndex;
|
||||
private String recordFlag;
|
||||
private String dbHost;
|
||||
private String connectionUrl;
|
||||
private String prestoWorkHost;
|
||||
private String remotelyAccessible;
|
||||
private String splitField;
|
||||
private String username;
|
||||
private String password;
|
||||
private Long timeStamp;
|
||||
private int scanNodes;
|
||||
private long fieldMaxValue;
|
||||
private long fieldMinValue;
|
||||
private String prestoTableName;
|
||||
private String calcStepEnable;
|
||||
private String controlScanConcurrencyEnabled;
|
||||
private int scanConcurrencyCount;
|
||||
|
||||
public String getConnectorId()
|
||||
{
|
||||
return connectorId;
|
||||
}
|
||||
|
||||
public PdboSplit setConnectorId(String connectorId)
|
||||
{
|
||||
this.connectorId = connectorId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getSchemaName()
|
||||
{
|
||||
return schemaName;
|
||||
}
|
||||
|
||||
public PdboSplit setSchemaName(String schemaName)
|
||||
{
|
||||
this.schemaName = schemaName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getTableName()
|
||||
{
|
||||
return tableName;
|
||||
}
|
||||
|
||||
public PdboSplit setTableName(String tableName)
|
||||
{
|
||||
this.tableName = tableName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Long getRows()
|
||||
{
|
||||
return rows;
|
||||
}
|
||||
|
||||
public PdboSplit setRows(Long rows)
|
||||
{
|
||||
this.rows = rows;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Long getBeginIndex()
|
||||
{
|
||||
return beginIndex;
|
||||
}
|
||||
|
||||
public PdboSplit setBeginIndex(Long beginIndex)
|
||||
{
|
||||
this.beginIndex = beginIndex;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Long getEndIndex()
|
||||
{
|
||||
return endIndex;
|
||||
}
|
||||
|
||||
public PdboSplit setEndIndex(Long endIndex)
|
||||
{
|
||||
this.endIndex = endIndex;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getRecordFlag()
|
||||
{
|
||||
return recordFlag;
|
||||
}
|
||||
|
||||
public PdboSplit setRecordFlag(String recordFlag)
|
||||
{
|
||||
this.recordFlag = recordFlag;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getDbHost()
|
||||
{
|
||||
return (dbHost == null || dbHost.length() == 0) ? "default" : dbHost;
|
||||
}
|
||||
|
||||
public PdboSplit setDbHost(String dbHost)
|
||||
{
|
||||
this.dbHost = dbHost;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getConnectionUrl()
|
||||
{
|
||||
return connectionUrl;
|
||||
}
|
||||
|
||||
public PdboSplit setConnectionUrl(String connectionUrl)
|
||||
{
|
||||
this.connectionUrl = connectionUrl;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getPrestoWorkHost()
|
||||
{
|
||||
return prestoWorkHost;
|
||||
}
|
||||
|
||||
public PdboSplit setPrestoWorkHost(String prestoWorkHost)
|
||||
{
|
||||
this.prestoWorkHost = prestoWorkHost;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean getRemotelyAccessible()
|
||||
{
|
||||
return JdbcUtil.converStringToBoolean(remotelyAccessible, false);
|
||||
}
|
||||
|
||||
public PdboSplit setRemotelyAccessible(String remotelyAccessible)
|
||||
{
|
||||
this.remotelyAccessible = remotelyAccessible;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getUsername()
|
||||
{
|
||||
return username;
|
||||
}
|
||||
|
||||
public PdboSplit setUsername(String username)
|
||||
{
|
||||
this.username = username;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getPassword()
|
||||
{
|
||||
return password;
|
||||
}
|
||||
|
||||
public PdboSplit setPassword(String password)
|
||||
{
|
||||
this.password = password;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getSplitField()
|
||||
{
|
||||
return splitField;
|
||||
}
|
||||
|
||||
public PdboSplit setSplitField(String splitField)
|
||||
{
|
||||
this.splitField = splitField;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Long getTimeStamp()
|
||||
{
|
||||
return timeStamp;
|
||||
}
|
||||
|
||||
public PdboSplit setTimeStamp(Long timeStamp)
|
||||
{
|
||||
this.timeStamp = timeStamp;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getScanNodes()
|
||||
{
|
||||
return scanNodes;
|
||||
}
|
||||
|
||||
public PdboSplit setScanNodes(int scanNodes)
|
||||
{
|
||||
this.scanNodes = scanNodes;
|
||||
return this;
|
||||
}
|
||||
|
||||
public long getFieldMaxValue()
|
||||
{
|
||||
return fieldMaxValue;
|
||||
}
|
||||
|
||||
public PdboSplit setFieldMaxValue(long fieldMaxValue)
|
||||
{
|
||||
this.fieldMaxValue = fieldMaxValue;
|
||||
return this;
|
||||
}
|
||||
|
||||
public long getFieldMinValue()
|
||||
{
|
||||
return fieldMinValue;
|
||||
}
|
||||
|
||||
public PdboSplit setFieldMinValue(long fieldMinValue)
|
||||
{
|
||||
this.fieldMinValue = fieldMinValue;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getPrestoTableName()
|
||||
{
|
||||
return prestoTableName;
|
||||
}
|
||||
|
||||
public void setPrestoTableName(String prestoTableName)
|
||||
{
|
||||
this.prestoTableName = prestoTableName;
|
||||
}
|
||||
|
||||
public boolean isCalcStepEnable()
|
||||
{
|
||||
return JdbcUtil.converStringToBoolean(calcStepEnable, false);
|
||||
}
|
||||
|
||||
public PdboSplit setCalcStepEnable(String calcStepEnable)
|
||||
{
|
||||
this.calcStepEnable = calcStepEnable;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean getControlScanConcurrencyEnabled()
|
||||
{
|
||||
return JdbcUtil.converStringToBoolean(controlScanConcurrencyEnabled, false);
|
||||
}
|
||||
|
||||
public PdboSplit setControlScanConcurrencyEnabled(
|
||||
String controlScanConcurrencyEnabled)
|
||||
{
|
||||
this.controlScanConcurrencyEnabled = controlScanConcurrencyEnabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getScanConcurrencyCount()
|
||||
{
|
||||
return scanConcurrencyCount;
|
||||
}
|
||||
|
||||
public PdboSplit setScanConcurrencyCount(int scanConcurrencyCount)
|
||||
{
|
||||
this.scanConcurrencyCount = scanConcurrencyCount;
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc.subtable;
|
||||
|
||||
import com.facebook.presto.plugin.jdbc.JdbcSplit;
|
||||
import com.facebook.presto.spi.ConnectorSplit;
|
||||
import com.facebook.presto.spi.ConnectorSplitSource;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import static java.util.concurrent.CompletableFuture.completedFuture;
|
||||
|
||||
public class PdboSplitSource
|
||||
implements ConnectorSplitSource
|
||||
{
|
||||
private final String dataSourceName;
|
||||
private final List<ConnectorSplit> splits;
|
||||
private int offset;
|
||||
private final boolean controlScanConcurrencyEnabled;
|
||||
private final int scanConcurrencyCount;
|
||||
|
||||
public PdboSplitSource(String dataSourceName, Iterable<? extends ConnectorSplit> splits, boolean controlScanConcurrencyEnabled, int scanConcurrencyCount)
|
||||
{
|
||||
this.dataSourceName = dataSourceName;
|
||||
if (splits == null) {
|
||||
throw new NullPointerException("splits is null");
|
||||
}
|
||||
List<ConnectorSplit> splitsList = new ArrayList<>();
|
||||
sortSplitByDbHost(splits, controlScanConcurrencyEnabled, splitsList);
|
||||
this.splits = Collections.unmodifiableList(splitsList);
|
||||
this.controlScanConcurrencyEnabled = controlScanConcurrencyEnabled;
|
||||
this.scanConcurrencyCount = scanConcurrencyCount;
|
||||
}
|
||||
|
||||
private void sortSplitByDbHost(Iterable<? extends ConnectorSplit> splits,
|
||||
boolean controlScanConcurrencyEnabled,
|
||||
List<ConnectorSplit> splitsList)
|
||||
{
|
||||
Map<String, List<ConnectorSplit>> map = new HashMap<String, List<ConnectorSplit>>();
|
||||
if (controlScanConcurrencyEnabled) {
|
||||
int splitSize = 0;
|
||||
for (ConnectorSplit split : splits) {
|
||||
if (split instanceof JdbcSplit) {
|
||||
JdbcSplit jdbcSplit = (JdbcSplit) split;
|
||||
List<ConnectorSplit> list = map.get(jdbcSplit.getDbHost());
|
||||
if (list == null) {
|
||||
list = new ArrayList<>();
|
||||
}
|
||||
list.add(split);
|
||||
map.put(jdbcSplit.getDbHost(), list);
|
||||
splitSize++;
|
||||
}
|
||||
}
|
||||
int loopCount = 0;
|
||||
while (loopCount < splitSize) {
|
||||
for (String dbHost : map.keySet()) {
|
||||
List<ConnectorSplit> list = map.get(dbHost);
|
||||
if (list == null || list.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
splitsList.add(list.get(0));
|
||||
loopCount++;
|
||||
list.remove(0);
|
||||
map.put(dbHost, list);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (ConnectorSplit split : splits) {
|
||||
splitsList.add(split);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDataSourceName()
|
||||
{
|
||||
return dataSourceName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<List<ConnectorSplit>> getNextBatch(int maxSize)
|
||||
{
|
||||
int remainingSplits = splits.size() - offset;
|
||||
int size = Math.min(remainingSplits, maxSize);
|
||||
List<ConnectorSplit> results = splits.subList(offset, offset + size);
|
||||
offset += size;
|
||||
return completedFuture(results);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFinished()
|
||||
{
|
||||
return offset >= splits.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isControlScanConcurrencyEnabled()
|
||||
{
|
||||
return controlScanConcurrencyEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getScanConcurrencyCount()
|
||||
{
|
||||
return scanConcurrencyCount;
|
||||
}
|
||||
}
|
@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc.subtable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import com.facebook.presto.plugin.jdbc.util.JdbcUtil;
|
||||
|
||||
public class PdboTableInfo
|
||||
{
|
||||
enum DBType
|
||||
{
|
||||
MYSQL,
|
||||
SQLSERVER,
|
||||
ORACLE
|
||||
}
|
||||
private String tableId;
|
||||
private String dbType;
|
||||
private String connectorId;
|
||||
private String prestoSchema;
|
||||
private String prestoTable;
|
||||
private String calcStepEnable;
|
||||
private String controlScanConcurrencyEnabled;
|
||||
private int scanConcurrencyCount;
|
||||
|
||||
public PdboTableInfo(String connectorId, String prestoSchema, String prestoTable)
|
||||
{
|
||||
this.connectorId = connectorId;
|
||||
this.prestoSchema = prestoSchema;
|
||||
this.prestoTable = prestoTable;
|
||||
}
|
||||
public String getTableId()
|
||||
{
|
||||
return tableId;
|
||||
}
|
||||
|
||||
public void setTableId(String tableId)
|
||||
{
|
||||
this.tableId = tableId;
|
||||
}
|
||||
|
||||
public String getDbType()
|
||||
{
|
||||
return dbType;
|
||||
}
|
||||
|
||||
public void setDbType(String dbType)
|
||||
{
|
||||
this.dbType = dbType;
|
||||
}
|
||||
|
||||
public String getConnectorId()
|
||||
{
|
||||
return connectorId;
|
||||
}
|
||||
|
||||
public void setConnectorId(String connectorId)
|
||||
{
|
||||
this.connectorId = connectorId;
|
||||
}
|
||||
|
||||
public String getPrestoSchema()
|
||||
{
|
||||
return prestoSchema;
|
||||
}
|
||||
|
||||
public void setPrestoSchema(String prestoSchema)
|
||||
{
|
||||
this.prestoSchema = prestoSchema;
|
||||
}
|
||||
|
||||
public String getPrestoTable()
|
||||
{
|
||||
return prestoTable;
|
||||
}
|
||||
|
||||
public void setPrestoTable(String prestoTable)
|
||||
{
|
||||
this.prestoTable = prestoTable;
|
||||
}
|
||||
|
||||
public boolean isCalcStepEnable()
|
||||
{
|
||||
return JdbcUtil.converStringToBoolean(calcStepEnable, false);
|
||||
}
|
||||
|
||||
public void setCalcStepEnable(String calcStepEnable)
|
||||
{
|
||||
this.calcStepEnable = calcStepEnable;
|
||||
}
|
||||
|
||||
public boolean getControlScanConcurrencyEnabled()
|
||||
{
|
||||
return JdbcUtil.converStringToBoolean(controlScanConcurrencyEnabled, false);
|
||||
}
|
||||
|
||||
public void setControlScanConcurrencyEnabled(
|
||||
String controlScanConcurrencyEnabled)
|
||||
{
|
||||
this.controlScanConcurrencyEnabled = controlScanConcurrencyEnabled;
|
||||
}
|
||||
|
||||
public int getScanConcurrencyCount()
|
||||
{
|
||||
return scanConcurrencyCount;
|
||||
}
|
||||
|
||||
public void setScanConcurrencyCount(int scanConcurrencyCount)
|
||||
{
|
||||
this.scanConcurrencyCount = scanConcurrencyCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hash(getConnectorId(), getPrestoSchema(), getPrestoTable());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return getConnectorId() + "-" + getPrestoSchema() + "-" + getPrestoTable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
return this.hashCode() == obj.hashCode();
|
||||
}
|
||||
}
|
@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc.util;
|
||||
|
||||
import com.facebook.presto.spi.type.Type;
|
||||
import io.airlift.log.Logger;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.sql.Types;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import static com.facebook.presto.spi.type.BigintType.BIGINT;
|
||||
import static com.facebook.presto.spi.type.BooleanType.BOOLEAN;
|
||||
import static com.facebook.presto.spi.type.DateType.DATE;
|
||||
import static com.facebook.presto.spi.type.DoubleType.DOUBLE;
|
||||
import static com.facebook.presto.spi.type.TimeType.TIME;
|
||||
import static com.facebook.presto.spi.type.TimestampType.TIMESTAMP;
|
||||
import static com.facebook.presto.spi.type.VarbinaryType.VARBINARY;
|
||||
import static com.facebook.presto.spi.type.VarcharType.VARCHAR;
|
||||
import static com.google.common.base.Strings.isNullOrEmpty;
|
||||
|
||||
public final class JdbcUtil
|
||||
{
|
||||
private static final Logger log = Logger.get(JdbcUtil.class);
|
||||
|
||||
private JdbcUtil()
|
||||
{
|
||||
}
|
||||
/**
|
||||
* Get table name : catalog.schema.table
|
||||
* @param catalog
|
||||
* @param schema
|
||||
* @param table
|
||||
* @return
|
||||
*/
|
||||
public static String getTableName(String identifierQuote, String catalog, String schema, String table)
|
||||
{
|
||||
StringBuilder sql = new StringBuilder();
|
||||
if (!isNullOrEmpty(schema)) {
|
||||
sql.append(quoted(identifierQuote, schema)).append('.');
|
||||
}
|
||||
else {
|
||||
if (!isNullOrEmpty(catalog)) {
|
||||
sql.append(quoted(identifierQuote, catalog)).append('.');
|
||||
}
|
||||
}
|
||||
sql.append(quoted(identifierQuote, table));
|
||||
return sql.toString();
|
||||
}
|
||||
|
||||
private static String quoted(String identifierQuote, String name)
|
||||
{
|
||||
name = name.replace(identifierQuote, identifierQuote + identifierQuote);
|
||||
return identifierQuote + name + identifierQuote;
|
||||
}
|
||||
|
||||
/**
|
||||
* close JDBC connection
|
||||
* @param connection
|
||||
* @param stat
|
||||
* @param rs
|
||||
*/
|
||||
public static void closeJdbcConnection(Connection connection, Statement stat, ResultSet rs)
|
||||
{
|
||||
try {
|
||||
if (rs != null) {
|
||||
rs.close();
|
||||
}
|
||||
if (stat != null) {
|
||||
stat.close();
|
||||
}
|
||||
if (connection != null) {
|
||||
connection.close();
|
||||
}
|
||||
}
|
||||
catch (SQLException e) {
|
||||
log.error("close connection error : " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public static Type toPrestoType(int jdbcType)
|
||||
{
|
||||
switch (jdbcType) {
|
||||
case Types.BIT:
|
||||
case Types.BOOLEAN:
|
||||
return BOOLEAN;
|
||||
case Types.TINYINT:
|
||||
case Types.SMALLINT:
|
||||
case Types.INTEGER:
|
||||
case Types.BIGINT:
|
||||
return BIGINT;
|
||||
case Types.FLOAT:
|
||||
case Types.REAL:
|
||||
case Types.DOUBLE:
|
||||
case Types.NUMERIC:
|
||||
case Types.DECIMAL:
|
||||
return DOUBLE;
|
||||
case Types.CHAR:
|
||||
case Types.NCHAR:
|
||||
case Types.VARCHAR:
|
||||
case Types.NVARCHAR:
|
||||
case Types.LONGVARCHAR:
|
||||
case Types.LONGNVARCHAR:
|
||||
return VARCHAR;
|
||||
case Types.BINARY:
|
||||
case Types.VARBINARY:
|
||||
case Types.LONGVARBINARY:
|
||||
return VARBINARY;
|
||||
case Types.DATE:
|
||||
return DATE;
|
||||
case Types.TIME:
|
||||
return TIME;
|
||||
case Types.TIMESTAMP:
|
||||
return TIMESTAMP;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Properties toProperties(Map<String, String> map)
|
||||
{
|
||||
Properties properties = new Properties();
|
||||
for (Map.Entry<String, String> entry : map.entrySet()) {
|
||||
properties.setProperty(entry.getKey(), entry.getValue());
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
public static <E> boolean checkListNullOrEmpty(List<E> list)
|
||||
{
|
||||
return list == null || list.isEmpty();
|
||||
}
|
||||
|
||||
public static boolean converStringToBoolean(String fieldValue, boolean defaultValue)
|
||||
{
|
||||
if (fieldValue == null || "".equals(fieldValue)) {
|
||||
return defaultValue;
|
||||
}
|
||||
else if ("Y".equals(fieldValue)
|
||||
|| "y".equals(fieldValue)) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static String Base64Encode(String str)
|
||||
{
|
||||
str = str == null ? "" : str;
|
||||
return new String(Base64.getEncoder().encode(str.getBytes()), StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
public static String Base64Decode(String str)
|
||||
{
|
||||
str = str == null ? "" : str;
|
||||
return new String(Base64.getDecoder().decode(str.getBytes()), StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc.util;
|
||||
|
||||
import com.facebook.presto.plugin.jdbc.JdbcSplit;
|
||||
|
||||
public final class PdboMetadata
|
||||
{
|
||||
public static final String PDBO_DATABASE = "route_schema";
|
||||
public static final String PDBO_TABLE = PDBO_DATABASE + ".pdbo_table";
|
||||
public static final String PDBO_ROUTE = PDBO_DATABASE + ".pdbo_route";
|
||||
public static final String PDBO_LOG = PDBO_DATABASE + ".pdbo_log";
|
||||
public static final String DB_INFO = PDBO_DATABASE + ".db_info";
|
||||
|
||||
private PdboMetadata()
|
||||
{
|
||||
}
|
||||
|
||||
public static String getPdboLogsSQL()
|
||||
{
|
||||
return "SELECT A.CONNECTORID,A.SCHEMANAME,A.TABLENAME,A.ROWS,A.BEGININDEX,A.ENDINDEX,B.DBTYPE,"
|
||||
+ " C.DBHOST,C.DBPORT,C.CONNECTION_PROPERTIES,C.PRESTO_WORK_HOST,C.REMOTELYACCESSIBLE,C.SPLITFIELD, "
|
||||
+ " C.SCANNODENUMBER,D.USERNAME,D.PASSWORD,A.CONTROL_SCAN_CONCURRENCY_ENABLED,A.SCAN_CONCURRENCY_COUNT "
|
||||
+ " FROM " + PDBO_LOG + " A INNER JOIN " + PDBO_TABLE + " B "
|
||||
+ " ON A.CONNECTORID = B.CONNECTORID AND A.SCHEMANAME = B.PRESTO_SCHEMA AND A.TABLENAME = B.PRESTO_TABLE "
|
||||
+ " INNER JOIN " + PDBO_ROUTE + " C ON B.TABLEID = C.TABLEID "
|
||||
+ " LEFT JOIN " + DB_INFO + " D ON C.UID = D.UID "
|
||||
+ " WHERE A.CONNECTORID = ? "
|
||||
+ " AND A.SCHEMANAME = ? "
|
||||
+ " AND A.TABLENAME = ? "
|
||||
+ " AND A.RECORDFLAG = 'finish' "
|
||||
+ " AND B.CALC_STEP_ENABLE = 'Y' "
|
||||
+ " ORDER BY A.BEGININDEX";
|
||||
}
|
||||
|
||||
public static String getPdboTableInfoSQL()
|
||||
{
|
||||
return "SELECT CONNECTORID,PRESTO_SCHEMA,PRESTO_TABLE,DBTYPE,CALC_STEP_ENABLE,CONTROL_SCAN_CONCURRENCY_ENABLED,SCAN_CONCURRENCY_COUNT,"
|
||||
+ " B.DBHOST,B.DBPORT,CONNECTION_PROPERTIES,SOURCE_SCHEMA,SOURCE_TABLE,SPLITFIELD,REMOTELYACCESSIBLE,PRESTO_WORK_HOST,SCANNODENUMBER,"
|
||||
+ " FIELDMAXVALUE,FIELDMINVALUE,USERNAME,PASSWORD"
|
||||
+ " FROM " + PDBO_TABLE + " A INNER JOIN " + PDBO_ROUTE + " B ON A.TABLEID = B.TABLEID"
|
||||
+ " LEFT JOIN " + DB_INFO + " C ON B.UID = C.UID"
|
||||
+ " WHERE CONNECTORID = ? ";
|
||||
}
|
||||
|
||||
public static String getInsertPdboLogSQL(JdbcSplit split, long rowCount, String connectorId)
|
||||
{
|
||||
return "INSERT INTO " + PDBO_LOG
|
||||
+ " (CONNECTORID,SCHEMANAME,TABLENAME,ROWS,BEGININDEX,ENDINDEX,RECORDFLAG,SCANNODES,TIMESTAMP) VALUES "
|
||||
+ "('" + connectorId + "',"
|
||||
+ "'" + split.getSchemaName() + "',"
|
||||
+ "'" + split.getTableName() + "',"
|
||||
+ rowCount + ","
|
||||
+ split.getBeginIndex() + ","
|
||||
+ split.getEndIndex() + ","
|
||||
+ "'new',"
|
||||
+ split.getScanNodes() + ","
|
||||
+ split.getTimeStamp() + ")";
|
||||
}
|
||||
|
||||
public static String getUpdatePdboHistoryLogSQL(JdbcSplit split, String connectorId)
|
||||
{
|
||||
return "UPDATE " + PDBO_LOG + " SET RECORDFLAG='runhistory' "
|
||||
+ "WHERE RECORDFLAG='new' AND CONNECTORID='" + connectorId
|
||||
+ "' AND SCHEMANAME='" + split.getSchemaName() + "' AND TABLENAME='"
|
||||
+ split.getTableName() + "'" + " AND timestamp < " + split.getTimeStamp();
|
||||
}
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc;
|
||||
|
||||
import com.facebook.presto.Session;
|
||||
import com.facebook.presto.tests.DistributedQueryRunner;
|
||||
import com.facebook.presto.tpch.TpchPlugin;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import io.airlift.tpch.TpchTable;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.facebook.presto.spi.type.TimeZoneKey.UTC_KEY;
|
||||
import static com.facebook.presto.tests.QueryAssertions.copyTpchTables;
|
||||
import static com.facebook.presto.tpch.TpchMetadata.TINY_SCHEMA_NAME;
|
||||
import static io.airlift.testing.Closeables.closeAllSuppress;
|
||||
import static java.util.Locale.ENGLISH;
|
||||
|
||||
public final class JdbcQueryRunner
|
||||
{
|
||||
private JdbcQueryRunner()
|
||||
{
|
||||
}
|
||||
|
||||
private static final String TPCH_SCHEMA = "tpch";
|
||||
|
||||
public static DistributedQueryRunner createJdbcQueryRunner(TpchTable<?>... tables)
|
||||
throws Exception
|
||||
{
|
||||
return createJdbcQueryRunner(ImmutableList.copyOf(tables));
|
||||
}
|
||||
|
||||
public static DistributedQueryRunner createJdbcQueryRunner(Iterable<TpchTable<?>> tables)
|
||||
throws Exception
|
||||
{
|
||||
DistributedQueryRunner queryRunner = null;
|
||||
try {
|
||||
queryRunner = new DistributedQueryRunner(createSession(), 3);
|
||||
|
||||
queryRunner.installPlugin(new TpchPlugin());
|
||||
queryRunner.createCatalog("tpch", "tpch");
|
||||
|
||||
Map<String, String> properties = TestingH2JdbcModule.createProperties();
|
||||
createSchema(properties, "tpch");
|
||||
|
||||
queryRunner.installPlugin(new JdbcPlugin("base-jdbc", new TestingH2JdbcModule()));
|
||||
queryRunner.createCatalog("jdbc", "base-jdbc", properties);
|
||||
|
||||
copyTpchTables(queryRunner, "tpch", TINY_SCHEMA_NAME, createSession(), tables);
|
||||
|
||||
return queryRunner;
|
||||
}
|
||||
catch (Throwable e) {
|
||||
closeAllSuppress(e, queryRunner);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private static void createSchema(Map<String, String> properties, String schema)
|
||||
throws SQLException
|
||||
{
|
||||
try (Connection connection = DriverManager.getConnection(properties.get("connection-url"));
|
||||
Statement statement = connection.createStatement()) {
|
||||
statement.execute("CREATE SCHEMA " + schema);
|
||||
}
|
||||
}
|
||||
|
||||
public static Session createSession()
|
||||
{
|
||||
return Session.builder()
|
||||
.setUser("user")
|
||||
.setSource("test")
|
||||
.setCatalog("jdbc")
|
||||
.setSchema(TPCH_SCHEMA)
|
||||
.setTimeZoneKey(UTC_KEY)
|
||||
.setLocale(ENGLISH)
|
||||
.build();
|
||||
}
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc;
|
||||
|
||||
import com.facebook.presto.spi.type.StandardTypes;
|
||||
import com.facebook.presto.spi.type.Type;
|
||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||
import com.fasterxml.jackson.databind.deser.std.FromStringDeserializer;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import io.airlift.json.JsonCodec;
|
||||
import io.airlift.json.JsonCodecFactory;
|
||||
import io.airlift.json.ObjectMapperProvider;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static com.facebook.presto.spi.type.BigintType.BIGINT;
|
||||
import static com.facebook.presto.spi.type.VarcharType.VARCHAR;
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static java.util.Locale.ENGLISH;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
final class MetadataUtil
|
||||
{
|
||||
private MetadataUtil() {}
|
||||
|
||||
public static final JsonCodec<JdbcColumnHandle> COLUMN_CODEC;
|
||||
public static final JsonCodec<JdbcTableHandle> TABLE_CODEC;
|
||||
public static final JsonCodec<JdbcOutputTableHandle> OUTPUT_TABLE_CODEC;
|
||||
|
||||
static {
|
||||
ObjectMapperProvider provider = new ObjectMapperProvider();
|
||||
provider.setJsonDeserializers(ImmutableMap.<Class<?>, JsonDeserializer<?>>of(Type.class, new TestingTypeDeserializer()));
|
||||
JsonCodecFactory codecFactory = new JsonCodecFactory(provider);
|
||||
COLUMN_CODEC = codecFactory.jsonCodec(JdbcColumnHandle.class);
|
||||
TABLE_CODEC = codecFactory.jsonCodec(JdbcTableHandle.class);
|
||||
OUTPUT_TABLE_CODEC = codecFactory.jsonCodec(JdbcOutputTableHandle.class);
|
||||
}
|
||||
|
||||
public static final class TestingTypeDeserializer
|
||||
extends FromStringDeserializer<Type>
|
||||
{
|
||||
private final Map<String, Type> types = ImmutableMap.<String, Type>of(
|
||||
StandardTypes.BIGINT, BIGINT,
|
||||
StandardTypes.VARCHAR, VARCHAR);
|
||||
|
||||
public TestingTypeDeserializer()
|
||||
{
|
||||
super(Type.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Type _deserialize(String value, DeserializationContext context)
|
||||
{
|
||||
Type type = types.get(value.toLowerCase(ENGLISH));
|
||||
checkArgument(type != null, "Unknown type %s", value);
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> void assertJsonRoundTrip(JsonCodec<T> codec, T object)
|
||||
{
|
||||
String json = codec.toJson(object);
|
||||
T copy = codec.fromJson(json);
|
||||
assertEquals(copy, object);
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import io.airlift.configuration.testing.ConfigAssertions;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class TestBaseJdbcConfig
|
||||
{
|
||||
@Test
|
||||
public void testDefaults()
|
||||
{
|
||||
ConfigAssertions.assertRecordedDefaults(ConfigAssertions.recordDefaults(BaseJdbcConfig.class)
|
||||
.setConnectionUrl(null)
|
||||
.setConnectionUser(null)
|
||||
.setConnectionPassword(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExplicitPropertyMappings()
|
||||
{
|
||||
Map<String, String> properties = new ImmutableMap.Builder<String, String>()
|
||||
.put("connection-url", "jdbc:h2:mem:config")
|
||||
.put("connection-user", "user")
|
||||
.put("connection-password", "password")
|
||||
.build();
|
||||
|
||||
BaseJdbcConfig expected = new BaseJdbcConfig()
|
||||
.setConnectionUrl("jdbc:h2:mem:config")
|
||||
.setConnectionUser("user")
|
||||
.setConnectionPassword("password");
|
||||
|
||||
ConfigAssertions.assertFullMapping(properties, expected);
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc;
|
||||
|
||||
import com.facebook.presto.spi.SchemaTableName;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.testng.annotations.AfterClass;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import static com.facebook.presto.plugin.jdbc.TestingDatabase.CONNECTOR_ID;
|
||||
import static com.facebook.presto.spi.type.BigintType.BIGINT;
|
||||
import static com.facebook.presto.spi.type.VarcharType.VARCHAR;
|
||||
import static java.util.Locale.ENGLISH;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertNotNull;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
@Test
|
||||
public class TestJdbcClient
|
||||
{
|
||||
private TestingDatabase database;
|
||||
private String catalogName;
|
||||
private JdbcClient jdbcClient;
|
||||
|
||||
@BeforeClass
|
||||
public void setUp()
|
||||
throws Exception
|
||||
{
|
||||
database = new TestingDatabase();
|
||||
catalogName = database.getConnection().getCatalog();
|
||||
jdbcClient = database.getJdbcClient();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public void tearDown()
|
||||
throws Exception
|
||||
{
|
||||
database.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMetadata()
|
||||
throws Exception
|
||||
{
|
||||
assertTrue(jdbcClient.getSchemaNames().containsAll(ImmutableSet.of("example", "tpch")));
|
||||
assertEquals(jdbcClient.getTableNames("example"), ImmutableList.of(new SchemaTableName("example", "numbers")));
|
||||
assertEquals(jdbcClient.getTableNames("tpch"), ImmutableList.of(
|
||||
new SchemaTableName("tpch", "lineitem"),
|
||||
new SchemaTableName("tpch", "orders")));
|
||||
|
||||
SchemaTableName schemaTableName = new SchemaTableName("example", "numbers");
|
||||
JdbcTableHandle table = jdbcClient.getTableHandle(schemaTableName);
|
||||
assertNotNull(table, "table is null");
|
||||
assertEquals(table.getCatalogName(), catalogName.toUpperCase(ENGLISH));
|
||||
assertEquals(table.getSchemaName(), "EXAMPLE");
|
||||
assertEquals(table.getTableName(), "NUMBERS");
|
||||
assertEquals(table.getSchemaTableName(), schemaTableName);
|
||||
assertEquals(jdbcClient.getColumns(table), ImmutableList.of(
|
||||
new JdbcColumnHandle(CONNECTOR_ID, "TEXT", VARCHAR),
|
||||
new JdbcColumnHandle(CONNECTOR_ID, "VALUE", BIGINT)));
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc;
|
||||
|
||||
import io.airlift.testing.EquivalenceTester;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import static com.facebook.presto.plugin.jdbc.MetadataUtil.COLUMN_CODEC;
|
||||
import static com.facebook.presto.plugin.jdbc.MetadataUtil.assertJsonRoundTrip;
|
||||
import static com.facebook.presto.spi.type.BigintType.BIGINT;
|
||||
import static com.facebook.presto.spi.type.VarcharType.VARCHAR;
|
||||
|
||||
public class TestJdbcColumnHandle
|
||||
{
|
||||
@Test
|
||||
public void testJsonRoundTrip()
|
||||
{
|
||||
assertJsonRoundTrip(COLUMN_CODEC, new JdbcColumnHandle("connectorId", "columnName", VARCHAR));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEquivalence()
|
||||
{
|
||||
EquivalenceTester.equivalenceTester()
|
||||
.addEquivalentGroup(
|
||||
new JdbcColumnHandle("connectorId", "columnName", VARCHAR),
|
||||
new JdbcColumnHandle("connectorId", "columnName", VARCHAR),
|
||||
new JdbcColumnHandle("connectorId", "columnName", BIGINT),
|
||||
new JdbcColumnHandle("connectorId", "columnName", VARCHAR))
|
||||
.addEquivalentGroup(
|
||||
new JdbcColumnHandle("connectorIdX", "columnName", VARCHAR),
|
||||
new JdbcColumnHandle("connectorIdX", "columnName", VARCHAR),
|
||||
new JdbcColumnHandle("connectorIdX", "columnName", BIGINT),
|
||||
new JdbcColumnHandle("connectorIdX", "columnName", VARCHAR))
|
||||
.addEquivalentGroup(
|
||||
new JdbcColumnHandle("connectorId", "columnNameX", VARCHAR),
|
||||
new JdbcColumnHandle("connectorId", "columnNameX", VARCHAR),
|
||||
new JdbcColumnHandle("connectorId", "columnNameX", BIGINT),
|
||||
new JdbcColumnHandle("connectorId", "columnNameX", VARCHAR))
|
||||
.check();
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
public class TestJdbcConnectorFactory
|
||||
{
|
||||
@Test
|
||||
public void test()
|
||||
throws Exception
|
||||
{
|
||||
JdbcConnectorFactory connectorFactory = new JdbcConnectorFactory(
|
||||
"test",
|
||||
new TestingH2JdbcModule(),
|
||||
ImmutableMap.<String, String>of(),
|
||||
getClass().getClassLoader());
|
||||
|
||||
connectorFactory.create("test", TestingH2JdbcModule.createProperties());
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc;
|
||||
|
||||
import com.facebook.presto.tests.AbstractTestQueries;
|
||||
import io.airlift.tpch.TpchTable;
|
||||
|
||||
import static com.facebook.presto.plugin.jdbc.JdbcQueryRunner.createJdbcQueryRunner;
|
||||
|
||||
public class TestJdbcDistributedQueries
|
||||
extends AbstractTestQueries
|
||||
{
|
||||
public TestJdbcDistributedQueries()
|
||||
throws Exception
|
||||
{
|
||||
super(createJdbcQueryRunner(TpchTable.getTables()));
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc;
|
||||
|
||||
import com.facebook.presto.spi.ColumnHandle;
|
||||
import com.facebook.presto.spi.HostAddress;
|
||||
import com.facebook.presto.spi.SchemaTableName;
|
||||
import com.facebook.presto.spi.TupleDomain;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.facebook.presto.plugin.jdbc.TestingDatabase.CONNECTOR_ID;
|
||||
import static org.testng.Assert.assertFalse;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
public class TestJdbcHandleResolver
|
||||
{
|
||||
private static final JdbcHandleResolver RESOLVER = new JdbcHandleResolver(new JdbcConnectorId(CONNECTOR_ID));
|
||||
|
||||
@Test
|
||||
public void testCanHandle()
|
||||
throws Exception
|
||||
{
|
||||
assertTrue(RESOLVER.canHandle(createTableHandle(CONNECTOR_ID)));
|
||||
assertFalse(RESOLVER.canHandle(createTableHandle("unknown")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCanHandleRecordSet()
|
||||
{
|
||||
assertTrue(RESOLVER.canHandle(createSplit(CONNECTOR_ID)));
|
||||
assertFalse(RESOLVER.canHandle(createSplit("unknown")));
|
||||
}
|
||||
|
||||
private static JdbcTableHandle createTableHandle(String connectorId)
|
||||
{
|
||||
return new JdbcTableHandle(connectorId, new SchemaTableName("schema", "table"), "catalog", "schema", "table");
|
||||
}
|
||||
|
||||
private static JdbcSplit createSplit(String connectorId)
|
||||
{
|
||||
List<HostAddress> address = ImmutableList.of();
|
||||
return new JdbcSplit(connectorId, "catalog", "schema", "table", "connectionUrl", ImmutableMap.<String, String>of(), TupleDomain.<ColumnHandle>all(),
|
||||
"", address, true, "", "", "", "", System.nanoTime(), 1, false, "");
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc;
|
||||
|
||||
import com.facebook.presto.tests.AbstractTestIntegrationSmokeTest;
|
||||
|
||||
import static com.facebook.presto.plugin.jdbc.JdbcQueryRunner.createJdbcQueryRunner;
|
||||
import static io.airlift.tpch.TpchTable.ORDERS;
|
||||
|
||||
public class TestJdbcIntegrationSmokeTest
|
||||
extends AbstractTestIntegrationSmokeTest
|
||||
{
|
||||
public TestJdbcIntegrationSmokeTest()
|
||||
throws Exception
|
||||
{
|
||||
super(createJdbcQueryRunner(ORDERS));
|
||||
}
|
||||
}
|
@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc;
|
||||
|
||||
import com.facebook.presto.spi.ColumnMetadata;
|
||||
import com.facebook.presto.spi.ConnectorSession;
|
||||
import com.facebook.presto.spi.ConnectorTableMetadata;
|
||||
import com.facebook.presto.spi.PrestoException;
|
||||
import com.facebook.presto.spi.SchemaTableName;
|
||||
import com.facebook.presto.spi.TableNotFoundException;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.testng.annotations.AfterMethod;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import static com.facebook.presto.plugin.jdbc.TestingDatabase.CONNECTOR_ID;
|
||||
import static com.facebook.presto.spi.StandardErrorCode.NOT_FOUND;
|
||||
import static com.facebook.presto.spi.StandardErrorCode.PERMISSION_DENIED;
|
||||
import static com.facebook.presto.spi.type.BigintType.BIGINT;
|
||||
import static com.facebook.presto.spi.type.TimeZoneKey.UTC_KEY;
|
||||
import static com.facebook.presto.spi.type.VarcharType.VARCHAR;
|
||||
import static java.util.Locale.ENGLISH;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertNull;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
import static org.testng.Assert.fail;
|
||||
|
||||
@Test(singleThreaded = true)
|
||||
public class TestJdbcMetadata
|
||||
{
|
||||
private static final ConnectorSession SESSION = new ConnectorSession("user", UTC_KEY, ENGLISH, System.currentTimeMillis(), null);
|
||||
|
||||
private TestingDatabase database;
|
||||
private JdbcMetadata metadata;
|
||||
private JdbcTableHandle tableHandle;
|
||||
|
||||
@BeforeMethod
|
||||
public void setUp()
|
||||
throws Exception
|
||||
{
|
||||
database = new TestingDatabase();
|
||||
metadata = new JdbcMetadata(new JdbcConnectorId(CONNECTOR_ID), database.getJdbcClient(), new JdbcMetadataConfig());
|
||||
tableHandle = metadata.getTableHandle(SESSION, new SchemaTableName("example", "numbers"));
|
||||
}
|
||||
|
||||
@AfterMethod(alwaysRun = true)
|
||||
public void tearDown()
|
||||
throws Exception
|
||||
{
|
||||
database.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListSchemaNames()
|
||||
{
|
||||
assertTrue(metadata.listSchemaNames(SESSION).containsAll(ImmutableSet.of("example", "tpch")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetTableHandle()
|
||||
{
|
||||
JdbcTableHandle tableHandle = metadata.getTableHandle(SESSION, new SchemaTableName("example", "numbers"));
|
||||
assertEquals(metadata.getTableHandle(SESSION, new SchemaTableName("example", "numbers")), tableHandle);
|
||||
assertNull(metadata.getTableHandle(SESSION, new SchemaTableName("example", "unknown")));
|
||||
assertNull(metadata.getTableHandle(SESSION, new SchemaTableName("unknown", "numbers")));
|
||||
assertNull(metadata.getTableHandle(SESSION, new SchemaTableName("unknown", "unknown")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetColumnHandles()
|
||||
{
|
||||
// known table
|
||||
assertEquals(metadata.getColumnHandles(tableHandle), ImmutableMap.of(
|
||||
"text", new JdbcColumnHandle(CONNECTOR_ID, "TEXT", VARCHAR),
|
||||
"value", new JdbcColumnHandle(CONNECTOR_ID, "VALUE", BIGINT)));
|
||||
|
||||
// unknown table
|
||||
unknownTableColumnHandle(new JdbcTableHandle(CONNECTOR_ID, new SchemaTableName("unknown", "unknown"), "unknown", "unknown", "unknown"));
|
||||
unknownTableColumnHandle(new JdbcTableHandle(CONNECTOR_ID, new SchemaTableName("example", "numbers"), null, "example", "unknown"));
|
||||
}
|
||||
|
||||
private void unknownTableColumnHandle(JdbcTableHandle tableHandle)
|
||||
{
|
||||
try {
|
||||
metadata.getColumnHandles(tableHandle);
|
||||
fail("Expected getColumnHandle of unknown table to throw a TableNotFoundException");
|
||||
}
|
||||
catch (TableNotFoundException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTableMetadata()
|
||||
{
|
||||
// known table
|
||||
ConnectorTableMetadata tableMetadata = metadata.getTableMetadata(tableHandle);
|
||||
assertEquals(tableMetadata.getTable(), new SchemaTableName("example", "numbers"));
|
||||
assertEquals(tableMetadata.getColumns(), ImmutableList.of(
|
||||
new ColumnMetadata("text", VARCHAR, false),
|
||||
new ColumnMetadata("value", BIGINT, false)));
|
||||
|
||||
// unknown tables should produce null
|
||||
unknownTableMetadata(new JdbcTableHandle(CONNECTOR_ID, new SchemaTableName("u", "numbers"), null, "unknown", "unknown"));
|
||||
unknownTableMetadata(new JdbcTableHandle(CONNECTOR_ID, new SchemaTableName("example", "numbers"), null, "example", "unknown"));
|
||||
unknownTableMetadata(new JdbcTableHandle(CONNECTOR_ID, new SchemaTableName("example", "numbers"), null, "unknown", "numbers"));
|
||||
}
|
||||
|
||||
private void unknownTableMetadata(JdbcTableHandle tableHandle)
|
||||
{
|
||||
try {
|
||||
metadata.getTableMetadata(tableHandle);
|
||||
fail("Expected getTableMetadata of unknown table to throw a TableNotFoundException");
|
||||
}
|
||||
catch (TableNotFoundException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListTables()
|
||||
{
|
||||
// all schemas
|
||||
assertEquals(ImmutableSet.copyOf(metadata.listTables(SESSION, null)), ImmutableSet.of(
|
||||
new SchemaTableName("example", "numbers"),
|
||||
new SchemaTableName("tpch", "orders"),
|
||||
new SchemaTableName("tpch", "lineitem")));
|
||||
|
||||
// specific schema
|
||||
assertEquals(ImmutableSet.copyOf(metadata.listTables(SESSION, "example")), ImmutableSet.of(
|
||||
new SchemaTableName("example", "numbers")));
|
||||
assertEquals(ImmutableSet.copyOf(metadata.listTables(SESSION, "tpch")), ImmutableSet.of(
|
||||
new SchemaTableName("tpch", "orders"),
|
||||
new SchemaTableName("tpch", "lineitem")));
|
||||
|
||||
// unknown schema
|
||||
assertEquals(ImmutableSet.copyOf(metadata.listTables(SESSION, "unknown")), ImmutableSet.of());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getColumnMetadata()
|
||||
{
|
||||
assertEquals(
|
||||
metadata.getColumnMetadata(tableHandle, new JdbcColumnHandle(CONNECTOR_ID, "text", VARCHAR)),
|
||||
new ColumnMetadata("text", VARCHAR, false));
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = PrestoException.class)
|
||||
public void testCreateTable()
|
||||
{
|
||||
metadata.createTable(SESSION, new ConnectorTableMetadata(
|
||||
new SchemaTableName("example", "foo"),
|
||||
ImmutableList.of(new ColumnMetadata("text", VARCHAR, false))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDropTableTable()
|
||||
{
|
||||
try {
|
||||
metadata.dropTable(tableHandle);
|
||||
fail("expected exception");
|
||||
}
|
||||
catch (PrestoException e) {
|
||||
assertEquals(e.getErrorCode(), PERMISSION_DENIED.toErrorCode());
|
||||
}
|
||||
|
||||
JdbcMetadataConfig config = new JdbcMetadataConfig().setAllowDropTable(true);
|
||||
metadata = new JdbcMetadata(new JdbcConnectorId(CONNECTOR_ID), database.getJdbcClient(), config);
|
||||
metadata.dropTable(tableHandle);
|
||||
|
||||
try {
|
||||
metadata.getTableMetadata(tableHandle);
|
||||
fail("expected exception");
|
||||
}
|
||||
catch (PrestoException e) {
|
||||
assertEquals(e.getErrorCode(), NOT_FOUND.toErrorCode());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static io.airlift.configuration.testing.ConfigAssertions.assertFullMapping;
|
||||
import static io.airlift.configuration.testing.ConfigAssertions.assertRecordedDefaults;
|
||||
import static io.airlift.configuration.testing.ConfigAssertions.recordDefaults;
|
||||
|
||||
public class TestJdbcMetadataConfig
|
||||
{
|
||||
@Test
|
||||
public void testDefaults()
|
||||
{
|
||||
assertRecordedDefaults(recordDefaults(JdbcMetadataConfig.class)
|
||||
.setAllowDropTable(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExplicitPropertyMappings()
|
||||
{
|
||||
Map<String, String> properties = new ImmutableMap.Builder<String, String>()
|
||||
.put("allow-drop-table", "true")
|
||||
.build();
|
||||
|
||||
JdbcMetadataConfig expected = new JdbcMetadataConfig()
|
||||
.setAllowDropTable(true);
|
||||
|
||||
assertFullMapping(properties, expected);
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc;
|
||||
|
||||
import com.facebook.presto.spi.type.Type;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import static com.facebook.presto.plugin.jdbc.MetadataUtil.OUTPUT_TABLE_CODEC;
|
||||
import static com.facebook.presto.plugin.jdbc.MetadataUtil.assertJsonRoundTrip;
|
||||
import static com.facebook.presto.spi.type.VarcharType.VARCHAR;
|
||||
|
||||
public class TestJdbcOutputTableHandle
|
||||
{
|
||||
@Test
|
||||
public void testJsonRoundTrip()
|
||||
{
|
||||
JdbcOutputTableHandle handle = new JdbcOutputTableHandle(
|
||||
"connectorId",
|
||||
"catalog",
|
||||
"schema",
|
||||
"table",
|
||||
ImmutableList.of("abc", "xyz"),
|
||||
ImmutableList.<Type>of(VARCHAR, VARCHAR),
|
||||
"test",
|
||||
"tmp_table",
|
||||
"jdbc:junk",
|
||||
ImmutableMap.of("user", "test"));
|
||||
|
||||
assertJsonRoundTrip(OUTPUT_TABLE_CODEC, handle);
|
||||
}
|
||||
}
|
@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc;
|
||||
|
||||
import com.facebook.presto.spi.RecordCursor;
|
||||
import com.facebook.presto.spi.RecordSet;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import org.testng.annotations.AfterClass;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.facebook.presto.spi.type.BigintType.BIGINT;
|
||||
import static com.facebook.presto.spi.type.VarcharType.VARCHAR;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertFalse;
|
||||
|
||||
@Test
|
||||
public class TestJdbcRecordSet
|
||||
{
|
||||
private TestingDatabase database;
|
||||
private JdbcClient jdbcClient;
|
||||
private JdbcSplit split;
|
||||
private Map<String, JdbcColumnHandle> columnHandles;
|
||||
|
||||
@BeforeClass
|
||||
public void setUp()
|
||||
throws Exception
|
||||
{
|
||||
database = new TestingDatabase();
|
||||
jdbcClient = database.getJdbcClient();
|
||||
split = database.getSplit("example", "numbers");
|
||||
columnHandles = database.getColumnHandles("example", "numbers");
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public void tearDown()
|
||||
throws Exception
|
||||
{
|
||||
database.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetColumnTypes()
|
||||
throws Exception
|
||||
{
|
||||
RecordSet recordSet = new JdbcRecordSet(jdbcClient, split, ImmutableList.of(
|
||||
new JdbcColumnHandle("test", "text", VARCHAR),
|
||||
new JdbcColumnHandle("test", "value", BIGINT)));
|
||||
assertEquals(recordSet.getColumnTypes(), ImmutableList.of(VARCHAR, BIGINT));
|
||||
|
||||
recordSet = new JdbcRecordSet(jdbcClient, split, ImmutableList.of(
|
||||
new JdbcColumnHandle("test", "value", BIGINT),
|
||||
new JdbcColumnHandle("test", "text", VARCHAR)));
|
||||
assertEquals(recordSet.getColumnTypes(), ImmutableList.of(BIGINT, VARCHAR));
|
||||
|
||||
recordSet = new JdbcRecordSet(jdbcClient, split, ImmutableList.of(
|
||||
new JdbcColumnHandle("test", "value", BIGINT),
|
||||
new JdbcColumnHandle("test", "value", BIGINT),
|
||||
new JdbcColumnHandle("test", "text", VARCHAR)));
|
||||
assertEquals(recordSet.getColumnTypes(), ImmutableList.of(BIGINT, BIGINT, VARCHAR));
|
||||
|
||||
recordSet = new JdbcRecordSet(jdbcClient, split, ImmutableList.<JdbcColumnHandle>of());
|
||||
assertEquals(recordSet.getColumnTypes(), ImmutableList.of());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCursorSimple()
|
||||
throws Exception
|
||||
{
|
||||
RecordSet recordSet = new JdbcRecordSet(jdbcClient, split, ImmutableList.of(
|
||||
columnHandles.get("text"),
|
||||
columnHandles.get("value")));
|
||||
|
||||
try (RecordCursor cursor = recordSet.cursor()) {
|
||||
assertEquals(cursor.getType(0), VARCHAR);
|
||||
assertEquals(cursor.getType(1), BIGINT);
|
||||
|
||||
Map<String, Long> data = new LinkedHashMap<>();
|
||||
while (cursor.advanceNextPosition()) {
|
||||
data.put(cursor.getSlice(0).toStringUtf8(), cursor.getLong(1));
|
||||
assertFalse(cursor.isNull(0));
|
||||
assertFalse(cursor.isNull(1));
|
||||
}
|
||||
|
||||
assertEquals(data, ImmutableMap.<String, Long>builder()
|
||||
.put("one", 1L)
|
||||
.put("two", 2L)
|
||||
.put("three", 3L)
|
||||
.put("ten", 10L)
|
||||
.put("eleven", 11L)
|
||||
.put("twelve", 12L)
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCursorMixedOrder()
|
||||
throws Exception
|
||||
{
|
||||
RecordSet recordSet = new JdbcRecordSet(jdbcClient, split, ImmutableList.of(
|
||||
columnHandles.get("value"),
|
||||
columnHandles.get("value"),
|
||||
columnHandles.get("text")));
|
||||
|
||||
try (RecordCursor cursor = recordSet.cursor()) {
|
||||
assertEquals(cursor.getType(0), BIGINT);
|
||||
assertEquals(cursor.getType(1), BIGINT);
|
||||
assertEquals(cursor.getType(2), VARCHAR);
|
||||
|
||||
Map<String, Long> data = new LinkedHashMap<>();
|
||||
while (cursor.advanceNextPosition()) {
|
||||
assertEquals(cursor.getLong(0), cursor.getLong(1));
|
||||
data.put(cursor.getSlice(2).toStringUtf8(), cursor.getLong(0));
|
||||
}
|
||||
|
||||
assertEquals(data, ImmutableMap.<String, Long>builder()
|
||||
.put("one", 1L)
|
||||
.put("two", 2L)
|
||||
.put("three", 3L)
|
||||
.put("ten", 10L)
|
||||
.put("eleven", 11L)
|
||||
.put("twelve", 12L)
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIdempotentClose()
|
||||
{
|
||||
RecordSet recordSet = new JdbcRecordSet(jdbcClient, split, ImmutableList.of(
|
||||
columnHandles.get("value"),
|
||||
columnHandles.get("value"),
|
||||
columnHandles.get("text")));
|
||||
|
||||
RecordCursor cursor = recordSet.cursor();
|
||||
cursor.close();
|
||||
cursor.close();
|
||||
}
|
||||
}
|
@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc;
|
||||
|
||||
import com.facebook.presto.spi.ColumnHandle;
|
||||
import com.facebook.presto.spi.ConnectorPartitionResult;
|
||||
import com.facebook.presto.spi.ConnectorSplitSource;
|
||||
import com.facebook.presto.spi.Domain;
|
||||
import com.facebook.presto.spi.Range;
|
||||
import com.facebook.presto.spi.RecordCursor;
|
||||
import com.facebook.presto.spi.RecordSet;
|
||||
import com.facebook.presto.spi.SchemaTableName;
|
||||
import com.facebook.presto.spi.SortedRangeSet;
|
||||
import com.facebook.presto.spi.TupleDomain;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import org.testng.annotations.AfterClass;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.google.common.collect.Iterables.getOnlyElement;
|
||||
import static io.airlift.concurrent.MoreFutures.getFutureValue;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertNotNull;
|
||||
|
||||
@Test
|
||||
public class TestJdbcRecordSetProvider
|
||||
{
|
||||
private TestingDatabase database;
|
||||
private JdbcClient jdbcClient;
|
||||
private JdbcSplit split;
|
||||
|
||||
private JdbcTableHandle table;
|
||||
private JdbcColumnHandle textColumn;
|
||||
private JdbcColumnHandle valueColumn;
|
||||
|
||||
@BeforeClass
|
||||
public void setUp()
|
||||
throws Exception
|
||||
{
|
||||
database = new TestingDatabase();
|
||||
jdbcClient = database.getJdbcClient();
|
||||
split = database.getSplit("example", "numbers");
|
||||
|
||||
table = jdbcClient.getTableHandle(new SchemaTableName("example", "numbers"));
|
||||
|
||||
Map<String, JdbcColumnHandle> columns = database.getColumnHandles("example", "numbers");
|
||||
textColumn = columns.get("text");
|
||||
valueColumn = columns.get("value");
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public void tearDown()
|
||||
throws Exception
|
||||
{
|
||||
database.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetRecordSet()
|
||||
throws Exception
|
||||
{
|
||||
JdbcRecordSetProvider recordSetProvider = new JdbcRecordSetProvider(jdbcClient);
|
||||
RecordSet recordSet = recordSetProvider.getRecordSet(split, ImmutableList.of(textColumn, valueColumn));
|
||||
assertNotNull(recordSet, "recordSet is null");
|
||||
|
||||
RecordCursor cursor = recordSet.cursor();
|
||||
assertNotNull(cursor, "cursor is null");
|
||||
|
||||
Map<String, Long> data = new LinkedHashMap<>();
|
||||
while (cursor.advanceNextPosition()) {
|
||||
data.put(cursor.getSlice(0).toStringUtf8(), cursor.getLong(1));
|
||||
}
|
||||
assertEquals(data, ImmutableMap.<String, Long>builder()
|
||||
.put("one", 1L)
|
||||
.put("two", 2L)
|
||||
.put("three", 3L)
|
||||
.put("ten", 10L)
|
||||
.put("eleven", 11L)
|
||||
.put("twelve", 12L)
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTupleDomain()
|
||||
throws Exception
|
||||
{
|
||||
// single value
|
||||
getCursor(table, ImmutableList.of(textColumn, valueColumn), TupleDomain.withColumnDomains(
|
||||
ImmutableMap.<ColumnHandle, Domain>of(textColumn, Domain.singleValue("foo"))
|
||||
));
|
||||
|
||||
// multiple values (string)
|
||||
getCursor(table, ImmutableList.of(textColumn, valueColumn), TupleDomain.withColumnDomains(
|
||||
ImmutableMap.<ColumnHandle, Domain>of(textColumn, Domain.union(ImmutableList.of(Domain.singleValue("foo"), Domain.singleValue("bar"))))
|
||||
));
|
||||
|
||||
// inequality (string)
|
||||
getCursor(table, ImmutableList.of(textColumn, valueColumn), TupleDomain.withColumnDomains(
|
||||
ImmutableMap.<ColumnHandle, Domain>of(textColumn, Domain.create(SortedRangeSet.of(Range.greaterThan("foo")), false))
|
||||
));
|
||||
|
||||
getCursor(table, ImmutableList.of(textColumn, valueColumn), TupleDomain.withColumnDomains(
|
||||
ImmutableMap.<ColumnHandle, Domain>of(textColumn, Domain.create(SortedRangeSet.of(Range.greaterThan("foo")), false))
|
||||
));
|
||||
|
||||
getCursor(table, ImmutableList.of(textColumn, valueColumn), TupleDomain.withColumnDomains(
|
||||
ImmutableMap.<ColumnHandle, Domain>of(textColumn, Domain.create(SortedRangeSet.of(Range.lessThanOrEqual("foo")), false))
|
||||
));
|
||||
|
||||
getCursor(table, ImmutableList.of(textColumn, valueColumn), TupleDomain.withColumnDomains(
|
||||
ImmutableMap.<ColumnHandle, Domain>of(textColumn, Domain.create(SortedRangeSet.of(Range.lessThan("foo")), false))
|
||||
));
|
||||
|
||||
// is null
|
||||
getCursor(table, ImmutableList.of(textColumn, valueColumn), TupleDomain.withColumnDomains(
|
||||
ImmutableMap.<ColumnHandle, Domain>of(textColumn, Domain.onlyNull(String.class))
|
||||
));
|
||||
|
||||
// not null
|
||||
getCursor(table, ImmutableList.of(textColumn, valueColumn), TupleDomain.withColumnDomains(
|
||||
ImmutableMap.<ColumnHandle, Domain>of(textColumn, Domain.notNull(String.class))
|
||||
));
|
||||
|
||||
// specific value or null
|
||||
getCursor(table, ImmutableList.of(textColumn, valueColumn), TupleDomain.withColumnDomains(
|
||||
ImmutableMap.<ColumnHandle, Domain>of(textColumn, Domain.union(ImmutableList.of(Domain.singleValue("foo"), Domain.onlyNull(String.class))))
|
||||
));
|
||||
|
||||
getCursor(table, ImmutableList.of(textColumn, valueColumn), TupleDomain.withColumnDomains(
|
||||
ImmutableMap.<ColumnHandle, Domain>of(textColumn, Domain.create(SortedRangeSet.of(Range.range("bar", true, "foo", true)), false))
|
||||
));
|
||||
|
||||
getCursor(table, ImmutableList.of(textColumn, valueColumn), TupleDomain.withColumnDomains(
|
||||
ImmutableMap.<ColumnHandle, Domain>of(textColumn, Domain.create(SortedRangeSet.of(
|
||||
Range.range("bar", true, "foo", true),
|
||||
Range.range("hello", false, "world", false)),
|
||||
false
|
||||
))
|
||||
));
|
||||
|
||||
getCursor(table, ImmutableList.of(textColumn, valueColumn), TupleDomain.withColumnDomains(
|
||||
ImmutableMap.<ColumnHandle, Domain>of(
|
||||
textColumn,
|
||||
Domain.create(SortedRangeSet.of(
|
||||
Range.range("bar", true, "foo", true),
|
||||
Range.range("hello", false, "world", false),
|
||||
Range.equal("apple"),
|
||||
Range.equal("banana"),
|
||||
Range.equal("zoo")),
|
||||
false
|
||||
),
|
||||
|
||||
valueColumn,
|
||||
Domain.create(SortedRangeSet.of(
|
||||
Range.range(1, true, 5, true),
|
||||
Range.range(10, false, 20, false)),
|
||||
true
|
||||
)
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
private RecordCursor getCursor(JdbcTableHandle jdbcTableHandle, List<JdbcColumnHandle> columns, TupleDomain<ColumnHandle> domain)
|
||||
throws InterruptedException
|
||||
{
|
||||
ConnectorPartitionResult partitions = jdbcClient.getPartitions(jdbcTableHandle, domain);
|
||||
ConnectorSplitSource splits = jdbcClient.getPartitionSplits((JdbcPartition) getOnlyElement(partitions.getPartitions()));
|
||||
JdbcSplit split = (JdbcSplit) getOnlyElement(getFutureValue(splits.getNextBatch(1000)));
|
||||
|
||||
JdbcRecordSetProvider recordSetProvider = new JdbcRecordSetProvider(jdbcClient);
|
||||
RecordSet recordSet = recordSetProvider.getRecordSet(split, columns);
|
||||
|
||||
return recordSet.cursor();
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc;
|
||||
|
||||
import com.facebook.presto.spi.ColumnHandle;
|
||||
import com.facebook.presto.spi.HostAddress;
|
||||
import com.facebook.presto.spi.TupleDomain;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import io.airlift.json.JsonCodec;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static io.airlift.json.JsonCodec.jsonCodec;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
public class TestJdbcSplit
|
||||
{
|
||||
List<HostAddress> address = ImmutableList.of();
|
||||
private final JdbcSplit split = new JdbcSplit("connectorId", "catalog", "schemaName", "tableName", "connectionUrl", ImmutableMap.<String, String>of(), TupleDomain.<ColumnHandle>all(),
|
||||
"", address, true, "", "", "", "", System.nanoTime(), 1, false, "");
|
||||
|
||||
@Test
|
||||
public void testAddresses()
|
||||
{
|
||||
// split uses "example" scheme so no addresses are available and is not remotely accessible
|
||||
assertEquals(split.getAddresses(), ImmutableList.of());
|
||||
assertEquals(split.isRemotelyAccessible(), true);
|
||||
|
||||
JdbcSplit jdbcSplit = new JdbcSplit("connectorId", "catalog", "schemaName", "tableName", "connectionUrl", ImmutableMap.<String, String>of(), TupleDomain.<ColumnHandle>all(),
|
||||
"", address, true, "", "", "", "", System.nanoTime(), 1, false, "");
|
||||
assertEquals(jdbcSplit.getAddresses(), ImmutableList.of());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJsonRoundTrip()
|
||||
{
|
||||
JsonCodec<JdbcSplit> codec = jsonCodec(JdbcSplit.class);
|
||||
String json = codec.toJson(split);
|
||||
JdbcSplit copy = codec.fromJson(json);
|
||||
assertEquals(copy.getConnectorId(), split.getConnectorId());
|
||||
assertEquals(copy.getSchemaName(), split.getSchemaName());
|
||||
assertEquals(copy.getTableName(), split.getTableName());
|
||||
|
||||
assertEquals(copy.getAddresses(), ImmutableList.of());
|
||||
assertEquals(copy.isRemotelyAccessible(), true);
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc;
|
||||
|
||||
import com.facebook.presto.spi.SchemaTableName;
|
||||
import io.airlift.testing.EquivalenceTester;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import static com.facebook.presto.plugin.jdbc.MetadataUtil.TABLE_CODEC;
|
||||
import static com.facebook.presto.plugin.jdbc.MetadataUtil.assertJsonRoundTrip;
|
||||
|
||||
public class TestJdbcTableHandle
|
||||
{
|
||||
@Test
|
||||
public void testJsonRoundTrip()
|
||||
{
|
||||
assertJsonRoundTrip(TABLE_CODEC, new JdbcTableHandle("connectorId", new SchemaTableName("schema", "table"), "jdbcCatalog", "jdbcSchema", "jdbcTable"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEquivalence()
|
||||
{
|
||||
EquivalenceTester.equivalenceTester()
|
||||
.addEquivalentGroup(
|
||||
new JdbcTableHandle("connectorId", new SchemaTableName("schema", "table"), "jdbcCatalog", "jdbcSchema", "jdbcTable"),
|
||||
new JdbcTableHandle("connectorId", new SchemaTableName("schema", "table"), "jdbcCatalogX", "jdbcSchema", "jdbcTable"),
|
||||
new JdbcTableHandle("connectorId", new SchemaTableName("schema", "table"), "jdbcCatalog", "jdbcSchemaX", "jdbcTable"),
|
||||
new JdbcTableHandle("connectorId", new SchemaTableName("schema", "table"), "jdbcCatalog", "jdbcSchema", "jdbcTableX"))
|
||||
.addEquivalentGroup(
|
||||
new JdbcTableHandle("connectorIdX", new SchemaTableName("schema", "table"), "jdbcCatalog", "jdbcSchema", "jdbcTable"),
|
||||
new JdbcTableHandle("connectorIdX", new SchemaTableName("schema", "table"), "jdbcCatalogX", "jdbcSchema", "jdbcTable"),
|
||||
new JdbcTableHandle("connectorIdX", new SchemaTableName("schema", "table"), "jdbcCatalog", "jdbcSchemaX", "jdbcTable"),
|
||||
new JdbcTableHandle("connectorIdX", new SchemaTableName("schema", "table"), "jdbcCatalog", "jdbcSchema", "jdbcTableX"))
|
||||
.addEquivalentGroup(
|
||||
new JdbcTableHandle("connectorId", new SchemaTableName("schemaX", "table"), "jdbcCatalog", "jdbcSchema", "jdbcTable"),
|
||||
new JdbcTableHandle("connectorId", new SchemaTableName("schemaX", "table"), "jdbcCatalogX", "jdbcSchema", "jdbcTable"),
|
||||
new JdbcTableHandle("connectorId", new SchemaTableName("schemaX", "table"), "jdbcCatalog", "jdbcSchemaX", "jdbcTable"),
|
||||
new JdbcTableHandle("connectorId", new SchemaTableName("schemaX", "table"), "jdbcCatalog", "jdbcSchema", "jdbcTableX"))
|
||||
.check();
|
||||
}
|
||||
}
|
@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc;
|
||||
|
||||
import com.facebook.presto.plugin.jdbc.cache.JdbcCacheConfig;
|
||||
import com.facebook.presto.plugin.jdbc.subtable.JdbcSubTableConfig;
|
||||
import com.facebook.presto.spi.ColumnHandle;
|
||||
import com.facebook.presto.spi.ConnectorPartitionResult;
|
||||
import com.facebook.presto.spi.ConnectorSplitSource;
|
||||
import com.facebook.presto.spi.SchemaTableName;
|
||||
import com.facebook.presto.spi.TupleDomain;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import org.h2.Driver;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.collect.Iterables.getOnlyElement;
|
||||
import static io.airlift.concurrent.MoreFutures.getFutureValue;
|
||||
|
||||
final class TestingDatabase
|
||||
implements AutoCloseable
|
||||
{
|
||||
public static final String CONNECTOR_ID = "test";
|
||||
|
||||
private final Connection connection;
|
||||
private final JdbcClient jdbcClient;
|
||||
|
||||
public TestingDatabase()
|
||||
throws SQLException
|
||||
{
|
||||
String connectionUrl = "jdbc:h2:mem:test" + System.nanoTime();
|
||||
jdbcClient = new BaseJdbcClient(
|
||||
new JdbcConnectorId(CONNECTOR_ID),
|
||||
new BaseJdbcConfig().setConnectionUrl(connectionUrl),
|
||||
"\"",
|
||||
new Driver(),
|
||||
new JdbcSubTableConfig(),
|
||||
new JdbcCacheConfig());
|
||||
|
||||
connection = DriverManager.getConnection(connectionUrl);
|
||||
connection.createStatement().execute("CREATE SCHEMA example");
|
||||
|
||||
connection.createStatement().execute("CREATE TABLE example.numbers(text varchar primary key, value bigint)");
|
||||
connection.createStatement().execute("INSERT INTO example.numbers(text, value) VALUES " +
|
||||
"('one', 1)," +
|
||||
"('two', 2)," +
|
||||
"('three', 3)," +
|
||||
"('ten', 10)," +
|
||||
"('eleven', 11)," +
|
||||
"('twelve', 12)" +
|
||||
"");
|
||||
connection.createStatement().execute("CREATE SCHEMA tpch");
|
||||
connection.createStatement().execute("CREATE TABLE tpch.orders(orderkey bigint primary key, custkey bigint)");
|
||||
connection.createStatement().execute("CREATE TABLE tpch.lineitem(orderkey bigint primary key, partkey bigint)");
|
||||
|
||||
connection.commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
throws SQLException
|
||||
{
|
||||
connection.close();
|
||||
}
|
||||
|
||||
public Connection getConnection()
|
||||
{
|
||||
return connection;
|
||||
}
|
||||
|
||||
public JdbcClient getJdbcClient()
|
||||
{
|
||||
return jdbcClient;
|
||||
}
|
||||
|
||||
public JdbcSplit getSplit(String schemaName, String tableName)
|
||||
throws InterruptedException
|
||||
{
|
||||
JdbcTableHandle jdbcTableHandle = jdbcClient.getTableHandle(new SchemaTableName(schemaName, tableName));
|
||||
ConnectorPartitionResult partitions = jdbcClient.getPartitions(jdbcTableHandle, TupleDomain.<ColumnHandle>all());
|
||||
ConnectorSplitSource splits = jdbcClient.getPartitionSplits((JdbcPartition) getOnlyElement(partitions.getPartitions()));
|
||||
return (JdbcSplit) getOnlyElement(getFutureValue(splits.getNextBatch(1000)));
|
||||
}
|
||||
|
||||
public Map<String, JdbcColumnHandle> getColumnHandles(String schemaName, String tableName)
|
||||
{
|
||||
JdbcTableHandle tableHandle = jdbcClient.getTableHandle(new SchemaTableName(schemaName, tableName));
|
||||
List<JdbcColumnHandle> columns = jdbcClient.getColumns(tableHandle);
|
||||
checkArgument(columns != null, "table not found: %s.%s", schemaName, tableName);
|
||||
|
||||
ImmutableMap.Builder<String, JdbcColumnHandle> columnHandles = ImmutableMap.builder();
|
||||
for (JdbcColumnHandle column : columns) {
|
||||
columnHandles.put(column.getColumnMetadata().getName(), column);
|
||||
}
|
||||
return columnHandles.build();
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.plugin.jdbc;
|
||||
|
||||
import com.facebook.presto.plugin.jdbc.cache.JdbcCacheConfig;
|
||||
import com.facebook.presto.plugin.jdbc.subtable.JdbcSubTableConfig;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.inject.Binder;
|
||||
import com.google.inject.Module;
|
||||
import com.google.inject.Provides;
|
||||
import org.h2.Driver;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static io.airlift.configuration.ConfigBinder.configBinder;
|
||||
import static java.lang.String.format;
|
||||
|
||||
class TestingH2JdbcModule
|
||||
implements Module
|
||||
{
|
||||
@Override
|
||||
public void configure(Binder binder)
|
||||
{
|
||||
configBinder(binder).bindConfig(BaseJdbcConfig.class);
|
||||
}
|
||||
|
||||
@Provides
|
||||
public JdbcClient provideJdbcClient(JdbcConnectorId id, BaseJdbcConfig config)
|
||||
{
|
||||
return new BaseJdbcClient(id, config, "\"", new Driver(),
|
||||
new JdbcSubTableConfig(),
|
||||
new JdbcCacheConfig());
|
||||
}
|
||||
|
||||
public static Map<String, String> createProperties()
|
||||
{
|
||||
return ImmutableMap.<String, String>builder()
|
||||
.put("connection-url", format("jdbc:h2:mem:test%s;DB_CLOSE_DELAY=-1", System.nanoTime()))
|
||||
.build();
|
||||
}
|
||||
}
|
@ -0,0 +1,127 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.facebook.presto</groupId>
|
||||
<artifactId>presto-root</artifactId>
|
||||
<version>0.107</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>presto-benchmark-driver</artifactId>
|
||||
<name>presto-benchmark-driver</name>
|
||||
|
||||
<properties>
|
||||
<air.main.basedir>${project.parent.basedir}</air.main.basedir>
|
||||
<main-class>com.facebook.presto.benchmark.driver.PrestoBenchmarkDriver</main-class>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.facebook.presto</groupId>
|
||||
<artifactId>presto-client</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>airline</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>discovery</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>http-client</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>json</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>units</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>log-manager</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.inject</groupId>
|
||||
<artifactId>javax.inject</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-math3</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- for testing -->
|
||||
<dependency>
|
||||
<groupId>org.testng</groupId>
|
||||
<artifactId>testng</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<shadedArtifactAttached>true</shadedArtifactAttached>
|
||||
<shadedClassifierName>executable</shadedClassifierName>
|
||||
<transformers>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||
<manifestEntries>
|
||||
<Main-Class>${main-class}</Main-Class>
|
||||
</manifestEntries>
|
||||
</transformer>
|
||||
</transformers>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.skife.maven</groupId>
|
||||
<artifactId>really-executable-jar-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<flags>-Xmx1G</flags>
|
||||
<classifier>executable</classifier>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>really-executable-jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.benchmark.driver;
|
||||
|
||||
import com.facebook.presto.client.ClientSession;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.net.HostAndPort;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class BenchmarkDriver
|
||||
implements Closeable
|
||||
{
|
||||
private final ClientSession clientSession;
|
||||
private final List<BenchmarkQuery> queries;
|
||||
private final BenchmarkResultsStore resultsStore;
|
||||
private final BenchmarkQueryRunner queryRunner;
|
||||
|
||||
public BenchmarkDriver(BenchmarkResultsStore resultsStore,
|
||||
ClientSession clientSession,
|
||||
Iterable<BenchmarkQuery> queries,
|
||||
int warm,
|
||||
int runs,
|
||||
boolean debug,
|
||||
int maxFailures,
|
||||
Optional<HostAndPort> socksProxy)
|
||||
{
|
||||
this.resultsStore = checkNotNull(resultsStore, "resultsStore is null");
|
||||
this.clientSession = checkNotNull(clientSession, "clientSession is null");
|
||||
this.queries = ImmutableList.copyOf(checkNotNull(queries, "queries is null"));
|
||||
|
||||
queryRunner = new BenchmarkQueryRunner(warm, runs, debug, maxFailures, clientSession.getServer(), socksProxy);
|
||||
}
|
||||
|
||||
public void run(Suite suite)
|
||||
throws Exception
|
||||
{
|
||||
// select queries to run
|
||||
List<BenchmarkQuery> queries = suite.selectQueries(this.queries);
|
||||
if (queries.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ClientSession session = ClientSession.withSessionProperties(clientSession, suite.getSessionProperties());
|
||||
|
||||
// select schemas to use
|
||||
List<BenchmarkSchema> benchmarkSchemas;
|
||||
if (!suite.getSchemaNameTemplates().isEmpty()) {
|
||||
List<String> schemas = queryRunner.getSchemas(session);
|
||||
benchmarkSchemas = suite.selectSchemas(schemas);
|
||||
}
|
||||
else {
|
||||
benchmarkSchemas = ImmutableList.of(new BenchmarkSchema(session.getSchema()));
|
||||
}
|
||||
if (benchmarkSchemas.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (BenchmarkSchema benchmarkSchema : benchmarkSchemas) {
|
||||
for (BenchmarkQuery benchmarkQuery : queries) {
|
||||
session = ClientSession.withCatalogAndSchema(session, session.getCatalog(), benchmarkSchema.getName());
|
||||
BenchmarkQueryResult result = queryRunner.execute(suite, session, benchmarkQuery);
|
||||
|
||||
resultsStore.store(benchmarkSchema, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
queryRunner.close();
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.benchmark.driver;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
public class BenchmarkDriverExecutionException
|
||||
extends RuntimeException
|
||||
{
|
||||
public BenchmarkDriverExecutionException(String message, RuntimeException cause)
|
||||
{
|
||||
super(requireNonNull(message, "message is null"), requireNonNull(cause, "cause is null"));
|
||||
}
|
||||
}
|
@ -0,0 +1,217 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.benchmark.driver;
|
||||
|
||||
import com.facebook.presto.client.ClientSession;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.net.HostAndPort;
|
||||
import io.airlift.command.Option;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static java.nio.charset.StandardCharsets.US_ASCII;
|
||||
import static java.util.Locale.ENGLISH;
|
||||
|
||||
public class BenchmarkDriverOptions
|
||||
{
|
||||
@Option(name = "--server", title = "server", description = "Presto server location (default: localhost:8080)")
|
||||
public String server = "localhost:8080";
|
||||
|
||||
@Option(name = "--user", title = "user", description = "Username")
|
||||
public String user = System.getProperty("user.name");
|
||||
|
||||
@Option(name = "--catalog", title = "catalog", description = "Default catalog (default: default)")
|
||||
public String catalog = "default";
|
||||
|
||||
@Option(name = "--schema", title = "schema", description = "Default schema (default: default)")
|
||||
public String schema = "default";
|
||||
|
||||
@Option(name = "--suite", title = "suite", description = "Suite to execute")
|
||||
public List<String> suites = new ArrayList<>();
|
||||
|
||||
@Option(name = "--suite-config", title = "suite-config", description = "Suites configuration file (default: suite.json)")
|
||||
public String suiteConfigFile = "suite.json";
|
||||
|
||||
@Option(name = "--sql", title = "sql", description = "Directory containing sql files (default: sql)")
|
||||
public String sqlTemplateDir = "sql";
|
||||
|
||||
@Option(name = "--query", title = "query", description = "Queries to execute")
|
||||
public List<String> queries = new ArrayList<>();
|
||||
|
||||
@Option(name = "--debug", title = "debug", description = "Enable debug information (default: false)")
|
||||
public boolean debug;
|
||||
|
||||
@Option(name = "--session", title = "session", description = "Session property (property can be used multiple times; format is key=value)")
|
||||
public final List<ClientSessionProperty> sessionProperties = new ArrayList<>();
|
||||
|
||||
@Option(name = "--runs", title = "runs", description = "Number of times to run each query (default: 3)")
|
||||
public int runs = 3;
|
||||
|
||||
@Option(name = "--warm", title = "warm", description = "Number of times to run each query for a warm-up (default: 1)")
|
||||
public int warm = 1;
|
||||
|
||||
@Option(name = "--max-failures", title = "max failures", description = "Max number of consecutive failures before benchmark fails")
|
||||
public int maxFailures = 10;
|
||||
|
||||
@Option(name = "--socks", title = "socks", description = "Socks proxy to use")
|
||||
public HostAndPort socksProxy;
|
||||
|
||||
public ClientSession getClientSession()
|
||||
{
|
||||
return new ClientSession(
|
||||
parseServer(server),
|
||||
user,
|
||||
"presto-benchmark",
|
||||
catalog,
|
||||
schema,
|
||||
TimeZone.getDefault().getID(),
|
||||
Locale.getDefault(),
|
||||
toProperties(this.sessionProperties),
|
||||
debug);
|
||||
}
|
||||
|
||||
private static URI parseServer(String server)
|
||||
{
|
||||
server = server.toLowerCase(ENGLISH);
|
||||
if (server.startsWith("http://") || server.startsWith("https://")) {
|
||||
return URI.create(server);
|
||||
}
|
||||
|
||||
HostAndPort host = HostAndPort.fromString(server);
|
||||
try {
|
||||
return new URI("http", null, host.getHostText(), host.getPortOrDefault(80), null, null, null);
|
||||
}
|
||||
catch (URISyntaxException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static Map<String, String> toProperties(List<ClientSessionProperty> sessionProperties)
|
||||
{
|
||||
ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
|
||||
for (ClientSessionProperty sessionProperty : sessionProperties) {
|
||||
String name = sessionProperty.getName();
|
||||
if (sessionProperty.getCatalog().isPresent()) {
|
||||
name = sessionProperty.getCatalog().get() + "." + name;
|
||||
}
|
||||
builder.put(name, sessionProperty.getValue());
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public static final class ClientSessionProperty
|
||||
{
|
||||
private static final Splitter NAME_VALUE_SPLITTER = Splitter.on('=').limit(2);
|
||||
private static final Splitter NAME_SPLITTER = Splitter.on('.');
|
||||
private final Optional<String> catalog;
|
||||
private final String name;
|
||||
private final String value;
|
||||
|
||||
public ClientSessionProperty(String property)
|
||||
{
|
||||
List<String> nameValue = NAME_VALUE_SPLITTER.splitToList(property);
|
||||
checkArgument(nameValue.size() == 2, "Session property: %s", property);
|
||||
|
||||
List<String> nameParts = NAME_SPLITTER.splitToList(nameValue.get(0));
|
||||
checkArgument(nameParts.size() == 1 || nameParts.size() == 2, "Invalid session property: %s", property);
|
||||
if (nameParts.size() == 1) {
|
||||
catalog = Optional.empty();
|
||||
name = nameParts.get(0);
|
||||
}
|
||||
else {
|
||||
catalog = Optional.of(nameParts.get(0));
|
||||
name = nameParts.get(1);
|
||||
}
|
||||
value = nameValue.get(1);
|
||||
|
||||
verifyProperty(catalog, name, value);
|
||||
}
|
||||
|
||||
public ClientSessionProperty(Optional<String> catalog, String name, String value)
|
||||
{
|
||||
this.catalog = checkNotNull(catalog, "catalog is null");
|
||||
this.name = checkNotNull(name, "name is null");
|
||||
this.value = checkNotNull(value, "value is null");
|
||||
|
||||
verifyProperty(catalog, name, value);
|
||||
}
|
||||
|
||||
private static void verifyProperty(Optional<String> catalog, String name, String value)
|
||||
{
|
||||
checkArgument(!catalog.isPresent() || !catalog.get().isEmpty(), "Invalid session property: %s.%s:%s", catalog, name, value);
|
||||
checkArgument(!name.isEmpty(), "Session property name is empty");
|
||||
|
||||
CharsetEncoder charsetEncoder = US_ASCII.newEncoder();
|
||||
checkArgument(catalog.orElse("").indexOf('=') < 0, "Session property catalog must not contain '=': %s", name);
|
||||
checkArgument(charsetEncoder.canEncode(catalog.orElse("")), "Session property catalog is not US_ASCII: %s", name);
|
||||
checkArgument(name.indexOf('=') < 0, "Session property name must not contain '=': %s", name);
|
||||
checkArgument(charsetEncoder.canEncode(name), "Session property name is not US_ASCII: %s", name);
|
||||
checkArgument(charsetEncoder.canEncode(value), "Session property value is not US_ASCII: %s", value);
|
||||
}
|
||||
|
||||
public Optional<String> getCatalog()
|
||||
{
|
||||
return catalog;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getValue()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return (catalog.isPresent() ? catalog.get() + '.' : "") + name + '=' + value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hash(catalog, name, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null || getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
ClientSessionProperty other = (ClientSessionProperty) obj;
|
||||
return Objects.equals(this.catalog, other.catalog) &&
|
||||
Objects.equals(this.name, other.name) &&
|
||||
Objects.equals(this.value, other.value);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.benchmark.driver;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.base.Splitter.MapSplitter;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.io.Files;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public final class BenchmarkQuery
|
||||
{
|
||||
private static final Splitter SECTION_SPLITTER = Splitter.on(Pattern.compile("\n\\s*=+\\s*\n", Pattern.MULTILINE)).limit(2).trimResults();
|
||||
private static final MapSplitter TAGS_SPLITTER = Splitter.on("\n").trimResults().withKeyValueSeparator('=');
|
||||
|
||||
private final String name;
|
||||
private final Map<String, String> tags;
|
||||
private final String sql;
|
||||
|
||||
public BenchmarkQuery(File file)
|
||||
throws IOException
|
||||
{
|
||||
checkNotNull(file, "file is null");
|
||||
|
||||
name = Files.getNameWithoutExtension(file.getName());
|
||||
|
||||
// file can have 2 sections separated by a line of equals signs
|
||||
String text = Files.toString(file, StandardCharsets.UTF_8);
|
||||
List<String> sections = SECTION_SPLITTER.splitToList(text);
|
||||
if (sections.size() == 2) {
|
||||
this.tags = ImmutableMap.copyOf(TAGS_SPLITTER.split(sections.get(0)));
|
||||
this.sql = sections.get(1);
|
||||
}
|
||||
else {
|
||||
// no tags
|
||||
this.tags = ImmutableMap.of();
|
||||
this.sql = sections.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
public static Function<BenchmarkQuery, String> queryNameGetter()
|
||||
{
|
||||
return query -> query.getName();
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
public Map<String, String> getTags()
|
||||
{
|
||||
return tags;
|
||||
}
|
||||
|
||||
public String getSql()
|
||||
{
|
||||
return sql;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return MoreObjects.toStringHelper(this)
|
||||
.add("name", name)
|
||||
.add("tags", tags)
|
||||
.add("sql", sql)
|
||||
.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.benchmark.driver;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
import io.airlift.units.Duration;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
import static java.util.concurrent.TimeUnit.NANOSECONDS;
|
||||
|
||||
public class BenchmarkQueryResult
|
||||
{
|
||||
public enum Status
|
||||
{
|
||||
PASS, FAIL
|
||||
}
|
||||
|
||||
private static final Stat FAIL_STAT = new Stat(new double[0]);
|
||||
|
||||
public static BenchmarkQueryResult passResult(Suite suite, BenchmarkQuery benchmarkQuery, Stat wallTimeNanos, Stat processCpuTimeNanos, Stat queryCpuTimeNanos)
|
||||
{
|
||||
return new BenchmarkQueryResult(suite, benchmarkQuery, Status.PASS, Optional.empty(), wallTimeNanos, processCpuTimeNanos, queryCpuTimeNanos);
|
||||
}
|
||||
|
||||
public static BenchmarkQueryResult failResult(Suite suite, BenchmarkQuery benchmarkQuery, String errorMessage)
|
||||
{
|
||||
return new BenchmarkQueryResult(suite, benchmarkQuery, Status.FAIL, Optional.of(errorMessage), FAIL_STAT, FAIL_STAT, FAIL_STAT);
|
||||
}
|
||||
|
||||
private final Suite suite;
|
||||
private final BenchmarkQuery benchmarkQuery;
|
||||
private final Status status;
|
||||
private final Optional<String> errorMessage;
|
||||
private final Stat wallTimeNanos;
|
||||
private final Stat processCpuTimeNanos;
|
||||
private final Stat queryCpuTimeNanos;
|
||||
|
||||
private BenchmarkQueryResult(
|
||||
Suite suite,
|
||||
BenchmarkQuery benchmarkQuery,
|
||||
Status status,
|
||||
Optional<String> errorMessage,
|
||||
Stat wallTimeNanos,
|
||||
Stat processCpuTimeNanos,
|
||||
Stat queryCpuTimeNanos)
|
||||
{
|
||||
this.suite = checkNotNull(suite, "suite is null");
|
||||
this.benchmarkQuery = checkNotNull(benchmarkQuery, "benchmarkQuery is null");
|
||||
this.status = checkNotNull(status, "status is null");
|
||||
this.errorMessage = requireNonNull(errorMessage, "errorMessage is null");
|
||||
this.wallTimeNanos = checkNotNull(wallTimeNanos, "wallTimeNanos is null");
|
||||
this.processCpuTimeNanos = checkNotNull(processCpuTimeNanos, "processCpuTimeNanos is null");
|
||||
this.queryCpuTimeNanos = checkNotNull(queryCpuTimeNanos, "queryCpuTimeNanos is null");
|
||||
}
|
||||
|
||||
public Suite getSuite()
|
||||
{
|
||||
return suite;
|
||||
}
|
||||
|
||||
public BenchmarkQuery getBenchmarkQuery()
|
||||
{
|
||||
return benchmarkQuery;
|
||||
}
|
||||
|
||||
public Status getStatus()
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
public Optional<String> getErrorMessage()
|
||||
{
|
||||
return errorMessage;
|
||||
}
|
||||
|
||||
public Stat getWallTimeNanos()
|
||||
{
|
||||
return wallTimeNanos;
|
||||
}
|
||||
|
||||
public Stat getProcessCpuTimeNanos()
|
||||
{
|
||||
return processCpuTimeNanos;
|
||||
}
|
||||
|
||||
public Stat getQueryCpuTimeNanos()
|
||||
{
|
||||
return queryCpuTimeNanos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return MoreObjects.toStringHelper(this)
|
||||
.add("suite", suite.getName())
|
||||
.add("benchmarkQuery", benchmarkQuery.getName())
|
||||
.add("status", status)
|
||||
.add("wallTimeMedian", new Duration(wallTimeNanos.getMedian(), NANOSECONDS).convertToMostSuccinctTimeUnit())
|
||||
.add("wallTimeMean", new Duration(wallTimeNanos.getMean(), NANOSECONDS).convertToMostSuccinctTimeUnit())
|
||||
.add("wallTimeStd", new Duration(wallTimeNanos.getStandardDeviation(), NANOSECONDS).convertToMostSuccinctTimeUnit())
|
||||
.add("processCpuTimeMedian", new Duration(processCpuTimeNanos.getMedian(), NANOSECONDS).convertToMostSuccinctTimeUnit())
|
||||
.add("processCpuTimeMean", new Duration(processCpuTimeNanos.getMean(), NANOSECONDS).convertToMostSuccinctTimeUnit())
|
||||
.add("processCpuTimeStd", new Duration(processCpuTimeNanos.getStandardDeviation(), NANOSECONDS).convertToMostSuccinctTimeUnit())
|
||||
.add("queryCpuTimeMedian", new Duration(queryCpuTimeNanos.getMedian(), NANOSECONDS).convertToMostSuccinctTimeUnit())
|
||||
.add("queryCpuTimeMean", new Duration(queryCpuTimeNanos.getMean(), NANOSECONDS).convertToMostSuccinctTimeUnit())
|
||||
.add("queryCpuTimeStd", new Duration(queryCpuTimeNanos.getStandardDeviation(), NANOSECONDS).convertToMostSuccinctTimeUnit())
|
||||
.add("error", errorMessage)
|
||||
.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,279 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.benchmark.driver;
|
||||
|
||||
import com.facebook.presto.client.ClientSession;
|
||||
import com.facebook.presto.client.QueryError;
|
||||
import com.facebook.presto.client.QueryResults;
|
||||
import com.facebook.presto.client.StatementClient;
|
||||
import com.facebook.presto.client.StatementStats;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.net.HostAndPort;
|
||||
import io.airlift.discovery.client.ServiceDescriptor;
|
||||
import io.airlift.discovery.client.ServiceDescriptorsRepresentation;
|
||||
import io.airlift.http.client.HttpClient;
|
||||
import io.airlift.http.client.HttpClientConfig;
|
||||
import io.airlift.http.client.JsonResponseHandler;
|
||||
import io.airlift.http.client.Request;
|
||||
import io.airlift.http.client.jetty.JettyHttpClient;
|
||||
import io.airlift.json.JsonCodec;
|
||||
import io.airlift.units.Duration;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static com.facebook.presto.benchmark.driver.BenchmarkQueryResult.failResult;
|
||||
import static com.facebook.presto.benchmark.driver.BenchmarkQueryResult.passResult;
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static io.airlift.http.client.HttpUriBuilder.uriBuilderFrom;
|
||||
import static io.airlift.http.client.JsonResponseHandler.createJsonResponseHandler;
|
||||
import static io.airlift.http.client.Request.Builder.prepareGet;
|
||||
import static io.airlift.http.client.StringResponseHandler.createStringResponseHandler;
|
||||
import static io.airlift.json.JsonCodec.jsonCodec;
|
||||
import static java.lang.Long.parseLong;
|
||||
import static java.lang.String.format;
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
|
||||
public class BenchmarkQueryRunner
|
||||
implements Closeable
|
||||
{
|
||||
private final int warm;
|
||||
private final int runs;
|
||||
private final boolean debug;
|
||||
private final int maxFailures;
|
||||
|
||||
private final HttpClient httpClient;
|
||||
private final List<URI> nodes;
|
||||
private final JsonCodec<QueryResults> queryResultsCodec;
|
||||
|
||||
private int failures;
|
||||
|
||||
public BenchmarkQueryRunner(int warm, int runs, boolean debug, int maxFailures, URI serverUri, Optional<HostAndPort> socksProxy)
|
||||
{
|
||||
checkArgument(warm >= 0, "warm is negative");
|
||||
this.warm = warm;
|
||||
|
||||
checkArgument(runs >= 1, "runs must be at least 1");
|
||||
this.runs = runs;
|
||||
|
||||
checkArgument(maxFailures >= 0, "maxFailures must be at least 0");
|
||||
this.maxFailures = maxFailures;
|
||||
|
||||
this.debug = debug;
|
||||
|
||||
this.queryResultsCodec = jsonCodec(QueryResults.class);
|
||||
|
||||
checkNotNull(socksProxy, "socksProxy is null");
|
||||
HttpClientConfig httpClientConfig = new HttpClientConfig();
|
||||
if (socksProxy.isPresent()) {
|
||||
httpClientConfig.setSocksProxy(socksProxy.get());
|
||||
}
|
||||
|
||||
this.httpClient = new JettyHttpClient(httpClientConfig.setConnectTimeout(new Duration(10, TimeUnit.SECONDS)));
|
||||
|
||||
nodes = getAllNodes(checkNotNull(serverUri, "serverUri is null"));
|
||||
}
|
||||
|
||||
@SuppressWarnings("AssignmentToForLoopParameter")
|
||||
public BenchmarkQueryResult execute(Suite suite, ClientSession session, BenchmarkQuery query)
|
||||
{
|
||||
failures = 0;
|
||||
for (int i = 0; i < warm; ) {
|
||||
try {
|
||||
execute(session, query.getName(), query.getSql());
|
||||
i++;
|
||||
failures = 0;
|
||||
}
|
||||
catch (BenchmarkDriverExecutionException e) {
|
||||
return failResult(suite, query, e.getCause().getMessage());
|
||||
}
|
||||
catch (Exception e) {
|
||||
handleFailure(e);
|
||||
}
|
||||
}
|
||||
|
||||
double[] wallTimeNanos = new double[runs];
|
||||
double[] processCpuTimeNanos = new double[runs];
|
||||
double[] queryCpuTimeNanos = new double[runs];
|
||||
for (int i = 0; i < runs; ) {
|
||||
try {
|
||||
long startCpuTime = getTotalCpuTime();
|
||||
long startWallTime = System.nanoTime();
|
||||
|
||||
StatementStats statementStats = execute(session, query.getName(), query.getSql());
|
||||
|
||||
long endWallTime = System.nanoTime();
|
||||
long endCpuTime = getTotalCpuTime();
|
||||
|
||||
wallTimeNanos[i] = endWallTime - startWallTime;
|
||||
processCpuTimeNanos[i] = endCpuTime - startCpuTime;
|
||||
queryCpuTimeNanos[i] = MILLISECONDS.toNanos(statementStats.getCpuTimeMillis());
|
||||
|
||||
i++;
|
||||
failures = 0;
|
||||
}
|
||||
catch (BenchmarkDriverExecutionException e) {
|
||||
return failResult(suite, query, e.getCause().getMessage());
|
||||
}
|
||||
catch (Exception e) {
|
||||
handleFailure(e);
|
||||
}
|
||||
}
|
||||
|
||||
return passResult(
|
||||
suite,
|
||||
query,
|
||||
new Stat(wallTimeNanos),
|
||||
new Stat(processCpuTimeNanos),
|
||||
new Stat(queryCpuTimeNanos));
|
||||
}
|
||||
|
||||
public List<String> getSchemas(ClientSession session)
|
||||
{
|
||||
failures = 0;
|
||||
while (true) {
|
||||
// start query
|
||||
StatementClient client = new StatementClient(httpClient, queryResultsCodec, session, "show schemas");
|
||||
|
||||
// read query output
|
||||
ImmutableList.Builder<String> schemas = ImmutableList.builder();
|
||||
while (client.isValid() && client.advance()) {
|
||||
// we do not process the output
|
||||
Iterable<List<Object>> data = client.current().getData();
|
||||
if (data != null) {
|
||||
for (List<Object> objects : data) {
|
||||
schemas.add(objects.get(0).toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// verify final state
|
||||
if (client.isClosed()) {
|
||||
throw new IllegalStateException("Query aborted by user");
|
||||
}
|
||||
|
||||
if (client.isGone()) {
|
||||
throw new IllegalStateException("Query is gone (server restarted?)");
|
||||
}
|
||||
|
||||
QueryError resultsError = client.finalResults().getError();
|
||||
if (resultsError != null) {
|
||||
RuntimeException cause = null;
|
||||
if (resultsError.getFailureInfo() != null) {
|
||||
cause = resultsError.getFailureInfo().toException();
|
||||
}
|
||||
handleFailure(cause);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
return schemas.build();
|
||||
}
|
||||
}
|
||||
|
||||
private StatementStats execute(ClientSession session, String name, String query)
|
||||
{
|
||||
// start query
|
||||
StatementClient client = new StatementClient(httpClient, queryResultsCodec, session, query);
|
||||
|
||||
// read query output
|
||||
while (client.isValid() && client.advance()) {
|
||||
// we do not process the output
|
||||
}
|
||||
|
||||
// verify final state
|
||||
if (client.isClosed()) {
|
||||
throw new IllegalStateException("Query aborted by user");
|
||||
}
|
||||
|
||||
if (client.isGone()) {
|
||||
throw new IllegalStateException("Query is gone (server restarted?)");
|
||||
}
|
||||
|
||||
QueryError resultsError = client.finalResults().getError();
|
||||
if (resultsError != null) {
|
||||
RuntimeException cause = null;
|
||||
if (resultsError.getFailureInfo() != null) {
|
||||
cause = resultsError.getFailureInfo().toException();
|
||||
}
|
||||
|
||||
throw new BenchmarkDriverExecutionException(format("Query %s failed: %s", name, resultsError.getMessage()), cause);
|
||||
}
|
||||
|
||||
return client.finalResults().getStats();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
httpClient.close();
|
||||
}
|
||||
|
||||
@SuppressWarnings("CallToPrintStackTrace")
|
||||
public void handleFailure(Exception e)
|
||||
{
|
||||
if (debug) {
|
||||
if (e == null) {
|
||||
e = new RuntimeException("Unknown error");
|
||||
}
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
failures++;
|
||||
|
||||
if (failures > maxFailures) {
|
||||
throw new RuntimeException("To many consecutive failures");
|
||||
}
|
||||
|
||||
try {
|
||||
TimeUnit.SECONDS.sleep(5);
|
||||
}
|
||||
catch (InterruptedException interruptedException) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw Throwables.propagate(interruptedException);
|
||||
}
|
||||
}
|
||||
|
||||
private long getTotalCpuTime()
|
||||
{
|
||||
long totalCpuTime = 0;
|
||||
for (URI server : nodes) {
|
||||
URI addressUri = uriBuilderFrom(server).replacePath("/v1/jmx/mbean/java.lang:type=OperatingSystem/ProcessCpuTime").build();
|
||||
String data = httpClient.execute(prepareGet().setUri(addressUri).build(), createStringResponseHandler()).getBody();
|
||||
totalCpuTime += parseLong(data.trim());
|
||||
}
|
||||
return TimeUnit.NANOSECONDS.toNanos(totalCpuTime);
|
||||
}
|
||||
|
||||
private List<URI> getAllNodes(URI server)
|
||||
{
|
||||
Request request = prepareGet().setUri(uriBuilderFrom(server).replacePath("/v1/service/presto").build()).build();
|
||||
JsonResponseHandler<ServiceDescriptorsRepresentation> responseHandler = createJsonResponseHandler(jsonCodec(ServiceDescriptorsRepresentation.class));
|
||||
ServiceDescriptorsRepresentation serviceDescriptors = httpClient.execute(request, responseHandler);
|
||||
|
||||
ImmutableList.Builder<URI> addresses = ImmutableList.builder();
|
||||
for (ServiceDescriptor serviceDescriptor : serviceDescriptors.getServiceDescriptors()) {
|
||||
String httpUri = serviceDescriptor.getProperties().get("http");
|
||||
if (httpUri != null) {
|
||||
addresses.add(URI.create(httpUri));
|
||||
}
|
||||
}
|
||||
return addresses.build();
|
||||
}
|
||||
}
|
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.benchmark.driver;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import static com.google.common.base.CharMatcher.anyOf;
|
||||
import static com.google.common.base.Functions.forMap;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.collect.Iterables.getFirst;
|
||||
import static com.google.common.collect.Iterables.transform;
|
||||
import static java.util.concurrent.TimeUnit.NANOSECONDS;
|
||||
|
||||
public class BenchmarkResultsPrinter
|
||||
implements BenchmarkResultsStore
|
||||
{
|
||||
private final List<String> tagNames;
|
||||
|
||||
public BenchmarkResultsPrinter(Iterable<Suite> suites, Iterable<BenchmarkQuery> queries)
|
||||
{
|
||||
this(getSelectedQueryTagNames(suites, queries));
|
||||
}
|
||||
|
||||
private static List<String> getSelectedQueryTagNames(Iterable<Suite> suites, Iterable<BenchmarkQuery> queries)
|
||||
{
|
||||
SortedSet<String> tags = new TreeSet<>();
|
||||
for (Suite suite : suites) {
|
||||
for (BenchmarkQuery query : suite.selectQueries(queries)) {
|
||||
tags.addAll(query.getTags().keySet());
|
||||
}
|
||||
|
||||
for (RegexTemplate regexTemplate : suite.getSchemaNameTemplates()) {
|
||||
tags.addAll(regexTemplate.getFieldNames());
|
||||
}
|
||||
}
|
||||
return ImmutableList.copyOf(tags);
|
||||
}
|
||||
|
||||
public BenchmarkResultsPrinter(List<String> tagNames)
|
||||
{
|
||||
this.tagNames = checkNotNull(tagNames, "tagNames is null");
|
||||
|
||||
// print header row
|
||||
printRow(ImmutableList.builder()
|
||||
.add("suite")
|
||||
.add("query")
|
||||
.addAll(tagNames)
|
||||
.add("wallTimeP50")
|
||||
.add("wallTimeMean")
|
||||
.add("wallTimeStd")
|
||||
.add("processCpuTimeP50")
|
||||
.add("processCpuTimeMean")
|
||||
.add("processCpuTimeStd")
|
||||
.add("queryCpuTimeP50")
|
||||
.add("queryCpuTimeMean")
|
||||
.add("queryCpuTimeStd")
|
||||
.add("status")
|
||||
.add("error")
|
||||
.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void store(BenchmarkSchema benchmarkSchema, BenchmarkQueryResult result)
|
||||
{
|
||||
Map<String, String> tags = new LinkedHashMap<>();
|
||||
tags.putAll(result.getBenchmarkQuery().getTags());
|
||||
tags.putAll(benchmarkSchema.getTags());
|
||||
|
||||
// only print first line of error message
|
||||
Optional<String> errorMessage = result.getErrorMessage().map(error -> getFirst(Splitter.on(anyOf("\r\n")).trimResults().split(error), ""));
|
||||
|
||||
printRow(ImmutableList.builder()
|
||||
.add(result.getSuite().getName())
|
||||
.add(result.getBenchmarkQuery().getName())
|
||||
.addAll(transform(tagNames, forMap(tags, "")))
|
||||
.add(NANOSECONDS.toMillis((long) result.getWallTimeNanos().getMedian()))
|
||||
.add(NANOSECONDS.toMillis((long) result.getWallTimeNanos().getMean()))
|
||||
.add(NANOSECONDS.toMillis((long) result.getWallTimeNanos().getStandardDeviation()))
|
||||
.add(NANOSECONDS.toMillis((long) result.getProcessCpuTimeNanos().getMedian()))
|
||||
.add(NANOSECONDS.toMillis((long) result.getProcessCpuTimeNanos().getMean()))
|
||||
.add(NANOSECONDS.toMillis((long) result.getProcessCpuTimeNanos().getStandardDeviation()))
|
||||
.add(NANOSECONDS.toMillis((long) result.getQueryCpuTimeNanos().getMedian()))
|
||||
.add(NANOSECONDS.toMillis((long) result.getQueryCpuTimeNanos().getMean()))
|
||||
.add(NANOSECONDS.toMillis((long) result.getQueryCpuTimeNanos().getStandardDeviation()))
|
||||
.add(result.getStatus().toString().toLowerCase())
|
||||
.add(errorMessage.orElse(""))
|
||||
.build());
|
||||
}
|
||||
|
||||
@SuppressWarnings("UseOfSystemOutOrSystemErr")
|
||||
private static void printRow(Iterable<?> values)
|
||||
{
|
||||
System.out.println(Joiner.on('\t').join(values));
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.benchmark.driver;
|
||||
|
||||
public interface BenchmarkResultsStore
|
||||
{
|
||||
void store(BenchmarkSchema benchmarkSchema, BenchmarkQueryResult result);
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.benchmark.driver;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class BenchmarkSchema
|
||||
{
|
||||
private final String name;
|
||||
private final Map<String, String> tags;
|
||||
|
||||
public BenchmarkSchema(String name)
|
||||
{
|
||||
this(name, ImmutableMap.<String, String>of());
|
||||
}
|
||||
|
||||
public BenchmarkSchema(String name, Map<String, String> tags)
|
||||
{
|
||||
this.name = name;
|
||||
this.tags = tags;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
public Map<String, String> getTags()
|
||||
{
|
||||
return tags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return MoreObjects.toStringHelper(this)
|
||||
.add("name", name)
|
||||
.add("tags", tags)
|
||||
.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.benchmark.driver;
|
||||
|
||||
import com.facebook.presto.client.ClientSession;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import io.airlift.command.Command;
|
||||
import io.airlift.command.HelpOption;
|
||||
import io.airlift.log.Level;
|
||||
import io.airlift.log.Logging;
|
||||
import io.airlift.log.LoggingConfiguration;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.google.common.io.ByteStreams.nullOutputStream;
|
||||
import static io.airlift.command.SingleCommand.singleCommand;
|
||||
import static java.util.function.Function.identity;
|
||||
|
||||
@Command(name = "presto-benchmark", description = "Presto benchmark driver")
|
||||
public class PrestoBenchmarkDriver
|
||||
{
|
||||
@Inject
|
||||
public HelpOption helpOption;
|
||||
|
||||
@Inject
|
||||
public BenchmarkDriverOptions benchmarkDriverOptions = new BenchmarkDriverOptions();
|
||||
|
||||
public static void main(String[] args)
|
||||
throws Exception
|
||||
{
|
||||
new PrestoBenchmarkDriver().run(args);
|
||||
}
|
||||
|
||||
protected void run(String[] args)
|
||||
throws Exception
|
||||
{
|
||||
PrestoBenchmarkDriver prestoBenchmarkDriver = singleCommand(PrestoBenchmarkDriver.class).parse(args);
|
||||
|
||||
if (prestoBenchmarkDriver.helpOption.showHelpIfRequested()) {
|
||||
return;
|
||||
}
|
||||
|
||||
BenchmarkDriverOptions driverOptions = prestoBenchmarkDriver.benchmarkDriverOptions;
|
||||
|
||||
initializeLogging(driverOptions.debug);
|
||||
|
||||
// select suites
|
||||
List<Suite> suites = Suite.readSuites(new File(driverOptions.suiteConfigFile));
|
||||
if (!driverOptions.suites.isEmpty()) {
|
||||
suites = suites.stream()
|
||||
.filter(suite -> driverOptions.suites.contains(suite.getName()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
suites = ImmutableList.copyOf(suites);
|
||||
|
||||
// load queries
|
||||
File queriesDir = new File(driverOptions.sqlTemplateDir);
|
||||
List<BenchmarkQuery> allQueries = readQueries(queriesDir);
|
||||
|
||||
// select queries to run
|
||||
Set<BenchmarkQuery> queries;
|
||||
if (driverOptions.queries.isEmpty()) {
|
||||
queries = suites.stream()
|
||||
.map(suite -> suite.selectQueries(allQueries))
|
||||
.flatMap(List::stream)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
else {
|
||||
queries = driverOptions.queries.stream()
|
||||
.map(Pattern::compile)
|
||||
.map(pattern -> allQueries.stream().filter(query -> pattern.matcher(query.getName()).matches()))
|
||||
.flatMap(identity())
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
// create results store
|
||||
BenchmarkResultsStore resultsStore = getResultsStore(suites, queries);
|
||||
|
||||
// create session
|
||||
ClientSession session = driverOptions.getClientSession();
|
||||
|
||||
try (BenchmarkDriver benchmarkDriver = new BenchmarkDriver(
|
||||
resultsStore,
|
||||
session,
|
||||
queries,
|
||||
driverOptions.warm,
|
||||
driverOptions.runs,
|
||||
driverOptions.debug,
|
||||
driverOptions.maxFailures,
|
||||
Optional.ofNullable(driverOptions.socksProxy))) {
|
||||
for (Suite suite : suites) {
|
||||
benchmarkDriver.run(suite);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected BenchmarkResultsStore getResultsStore(List<Suite> suites, Set<BenchmarkQuery> queries)
|
||||
{
|
||||
return new BenchmarkResultsPrinter(suites, queries);
|
||||
}
|
||||
|
||||
private static List<BenchmarkQuery> readQueries(File queriesDir)
|
||||
throws IOException
|
||||
{
|
||||
File[] files = queriesDir.listFiles();
|
||||
if (files == null) {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
Arrays.sort(files);
|
||||
|
||||
ImmutableList.Builder<BenchmarkQuery> queries = ImmutableList.builder();
|
||||
for (File file : files) {
|
||||
String fileName = file.getName();
|
||||
if (fileName.endsWith(".sql")) {
|
||||
queries.add(new BenchmarkQuery(file));
|
||||
}
|
||||
}
|
||||
return queries.build();
|
||||
}
|
||||
|
||||
@SuppressWarnings("UseOfSystemOutOrSystemErr")
|
||||
public static void initializeLogging(boolean debug)
|
||||
{
|
||||
// unhook out and err while initializing logging or logger will print to them
|
||||
PrintStream out = System.out;
|
||||
PrintStream err = System.err;
|
||||
try {
|
||||
if (debug) {
|
||||
Logging logging = Logging.initialize();
|
||||
logging.configure(new LoggingConfiguration());
|
||||
logging.setLevel("com.facebook.presto", Level.DEBUG);
|
||||
}
|
||||
else {
|
||||
System.setOut(new PrintStream(nullOutputStream()));
|
||||
System.setErr(new PrintStream(nullOutputStream()));
|
||||
|
||||
Logging logging = Logging.initialize();
|
||||
logging.configure(new LoggingConfiguration());
|
||||
logging.disableConsole();
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
finally {
|
||||
System.setOut(out);
|
||||
System.setErr(err);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.benchmark.driver;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.ImmutableBiMap;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class RegexTemplate
|
||||
{
|
||||
private static final Method NAMED_GROUPS_METHOD;
|
||||
|
||||
static {
|
||||
try {
|
||||
NAMED_GROUPS_METHOD = Pattern.class.getDeclaredMethod("namedGroups");
|
||||
NAMED_GROUPS_METHOD.setAccessible(true);
|
||||
}
|
||||
catch (NoSuchMethodException e) {
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
}
|
||||
|
||||
private final String template;
|
||||
private final Pattern pattern;
|
||||
private final List<String> fieldNames;
|
||||
|
||||
public RegexTemplate(String template)
|
||||
{
|
||||
this.template = checkNotNull(template, "template is null");
|
||||
|
||||
try {
|
||||
this.pattern = Pattern.compile(template);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new IllegalArgumentException("Invalid template: " + template, e);
|
||||
}
|
||||
|
||||
Map<String, Integer> namedGroups;
|
||||
try {
|
||||
namedGroups = (Map<String, Integer>) NAMED_GROUPS_METHOD.invoke(pattern);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
ImmutableSortedMap<Integer, String> sortedGroups = ImmutableSortedMap.copyOf(ImmutableBiMap.copyOf(namedGroups).inverse());
|
||||
this.fieldNames = ImmutableList.copyOf(sortedGroups.values());
|
||||
}
|
||||
|
||||
public List<String> getFieldNames()
|
||||
{
|
||||
return fieldNames;
|
||||
}
|
||||
|
||||
public Optional<Map<String, String>> parse(String value)
|
||||
{
|
||||
checkNotNull(value, "value is null");
|
||||
|
||||
Matcher matcher = pattern.matcher(value);
|
||||
if (!matcher.matches()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
ImmutableMap.Builder<String, String> fieldsBuilder = ImmutableMap.builder();
|
||||
for (int index = 0; index < fieldNames.size(); index++) {
|
||||
String fieldName = fieldNames.get(index);
|
||||
String fieldValue = matcher.group(index + 1);
|
||||
if (fieldValue != null) {
|
||||
fieldsBuilder.put(fieldName, fieldValue);
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, String> fields = fieldsBuilder.build();
|
||||
return Optional.of(fields);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return template;
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.benchmark.driver;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
import org.apache.commons.math3.stat.descriptive.moment.Mean;
|
||||
import org.apache.commons.math3.stat.descriptive.moment.StandardDeviation;
|
||||
import org.apache.commons.math3.stat.descriptive.rank.Median;
|
||||
|
||||
public class Stat
|
||||
{
|
||||
private final double mean;
|
||||
private final double standardDeviation;
|
||||
private final double median;
|
||||
|
||||
public Stat(double[] values)
|
||||
{
|
||||
mean = new Mean().evaluate(values);
|
||||
standardDeviation = new StandardDeviation().evaluate(values);
|
||||
median = new Median().evaluate(values);
|
||||
}
|
||||
|
||||
public double getMean()
|
||||
{
|
||||
return mean;
|
||||
}
|
||||
|
||||
public double getStandardDeviation()
|
||||
{
|
||||
return standardDeviation;
|
||||
}
|
||||
|
||||
public double getMedian()
|
||||
{
|
||||
return median;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return MoreObjects.toStringHelper(this)
|
||||
.add("mean", mean)
|
||||
.add("standardDeviation", standardDeviation)
|
||||
.add("median", median)
|
||||
.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.benchmark.driver;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static io.airlift.json.JsonCodec.mapJsonCodec;
|
||||
|
||||
public class Suite
|
||||
{
|
||||
private final String name;
|
||||
private final Map<String, String> sessionProperties;
|
||||
private final List<RegexTemplate> schemaNameTemplates;
|
||||
private final List<Pattern> queryNamePatterns;
|
||||
|
||||
public Suite(String name, Map<String, String> sessionProperties, Iterable<RegexTemplate> schemaNameTemplates, Iterable<Pattern> queryNamePatterns)
|
||||
{
|
||||
this.name = checkNotNull(name, "name is null");
|
||||
this.sessionProperties = sessionProperties == null ? ImmutableMap.<String, String>of() : ImmutableMap.copyOf(sessionProperties);
|
||||
this.schemaNameTemplates = ImmutableList.copyOf(checkNotNull(schemaNameTemplates, "schemaNameTemplates is null"));
|
||||
this.queryNamePatterns = ImmutableList.copyOf(checkNotNull(queryNamePatterns, "queryNamePatterns is null"));
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
public Map<String, String> getSessionProperties()
|
||||
{
|
||||
return sessionProperties;
|
||||
}
|
||||
|
||||
public List<RegexTemplate> getSchemaNameTemplates()
|
||||
{
|
||||
return schemaNameTemplates;
|
||||
}
|
||||
|
||||
public List<Pattern> getQueryNamePatterns()
|
||||
{
|
||||
return queryNamePatterns;
|
||||
}
|
||||
|
||||
public List<BenchmarkSchema> selectSchemas(Iterable<String> schemas)
|
||||
{
|
||||
if (schemaNameTemplates.isEmpty()) {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
ImmutableList.Builder<BenchmarkSchema> benchmarkSchemas = ImmutableList.builder();
|
||||
for (RegexTemplate schemaNameTemplate : schemaNameTemplates) {
|
||||
for (String schema : schemas) {
|
||||
Optional<Map<String, String>> tags = schemaNameTemplate.parse(schema);
|
||||
if (tags.isPresent()) {
|
||||
benchmarkSchemas.add(new BenchmarkSchema(schema, tags.get()));
|
||||
}
|
||||
}
|
||||
}
|
||||
return benchmarkSchemas.build();
|
||||
}
|
||||
|
||||
public List<BenchmarkQuery> selectQueries(Iterable<BenchmarkQuery> queries)
|
||||
{
|
||||
if (getQueryNamePatterns().isEmpty()) {
|
||||
return ImmutableList.copyOf(queries);
|
||||
}
|
||||
|
||||
List<BenchmarkQuery> filteredQueries = StreamSupport.stream(queries.spliterator(), false)
|
||||
.filter(query -> getQueryNamePatterns().stream().anyMatch(pattern -> pattern.matcher(query.getName()).matches()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return ImmutableList.copyOf(filteredQueries);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return MoreObjects.toStringHelper(this)
|
||||
.add("name", name)
|
||||
.add("sessionProperties", sessionProperties)
|
||||
.add("queryNamePatterns", queryNamePatterns)
|
||||
.toString();
|
||||
}
|
||||
|
||||
public static List<Suite> readSuites(File file)
|
||||
throws IOException
|
||||
{
|
||||
checkNotNull(file, "file is null");
|
||||
checkArgument(file.canRead(), "Can not read file: %s" + file);
|
||||
byte[] json = Files.readAllBytes(file.toPath());
|
||||
Map<String, OptionsJson> options = mapJsonCodec(String.class, OptionsJson.class).fromJson(json);
|
||||
ImmutableList.Builder<Suite> runOptions = ImmutableList.builder();
|
||||
for (Entry<String, OptionsJson> entry : options.entrySet()) {
|
||||
runOptions.add(entry.getValue().toSuite(entry.getKey()));
|
||||
}
|
||||
return runOptions.build();
|
||||
}
|
||||
|
||||
public static class OptionsJson
|
||||
{
|
||||
private final List<String> schema;
|
||||
private final Map<String, String> session;
|
||||
private final List<String> query;
|
||||
|
||||
@JsonCreator
|
||||
public OptionsJson(
|
||||
@JsonProperty("schema") List<String> schema,
|
||||
@JsonProperty("session") Map<String, String> session,
|
||||
@JsonProperty("query") List<String> query)
|
||||
{
|
||||
this.schema = checkNotNull(ImmutableList.copyOf(schema), "schema is null");
|
||||
this.session = checkNotNull(ImmutableMap.copyOf(session), "session is null");
|
||||
this.query = checkNotNull(query, "query is null");
|
||||
}
|
||||
|
||||
public Suite toSuite(String name)
|
||||
{
|
||||
ImmutableList.Builder<Pattern> queryNameTemplates = ImmutableList.builder();
|
||||
for (String q : query) {
|
||||
queryNameTemplates.add(Pattern.compile(q));
|
||||
}
|
||||
ImmutableList.Builder<RegexTemplate> schemaNameTemplates = ImmutableList.builder();
|
||||
for (String s : schema) {
|
||||
schemaNameTemplates.add(new RegexTemplate(s));
|
||||
}
|
||||
return new Suite(name, session, schemaNameTemplates.build(), queryNameTemplates.build());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.benchmark.driver;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
public class RegexTemplateTest
|
||||
{
|
||||
@Test
|
||||
public void test()
|
||||
throws Exception
|
||||
{
|
||||
RegexTemplate regexTemplate = new RegexTemplate("tpch_sf(?<scale>.*?)_(?<format>.*?)_(?<compression>.*?)");
|
||||
|
||||
assertEquals(regexTemplate.getFieldNames(), ImmutableList.of("scale", "format", "compression"));
|
||||
assertEquals(regexTemplate.parse("tpch_sf100_orc_zlib"), Optional.of(ImmutableMap.of("scale", "100", "format", "orc", "compression", "zlib")));
|
||||
assertEquals(regexTemplate.parse("foo_tpch_sf100_orc_zlib"), Optional.empty());
|
||||
assertEquals(regexTemplate.parse("tpch_sf100_orc"), Optional.empty());
|
||||
assertEquals(regexTemplate.parse(""), Optional.empty());
|
||||
|
||||
regexTemplate = new RegexTemplate("tpch_sf(?<scale>.*?)_(?<format>.*?)_(?<compression>.*?)\\.sql");
|
||||
assertEquals(regexTemplate.parse("tpch_sf100_orc_zlib.sql"), Optional.of(ImmutableMap.of("scale", "100", "format", "orc", "compression", "zlib")));
|
||||
assertEquals(regexTemplate.parse("tpch_sf100_orc_zlibXsql"), Optional.empty());
|
||||
assertEquals(regexTemplate.parse("tpch_sf100_orc_zlib.sqlFoo"), Optional.empty());
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
{
|
||||
"legacy_readers": {
|
||||
"schema": [ "(?<scale>tiny)", "sf(?<scale>.)" ],
|
||||
"session": {
|
||||
"enable_optimized_readers": "false"
|
||||
},
|
||||
"query": ["sum_quantity.*", "sum_discount.*"]
|
||||
},
|
||||
"optimized_readers": {
|
||||
"schema": [ "(?<scale>tiny)", "sf(?<scale>.)" ],
|
||||
"session": {
|
||||
"enable_optimized_readers": "true"
|
||||
},
|
||||
"query": ["sum_quantity.*", "sum_discount.*"]
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
format=generate
|
||||
scale=1
|
||||
=====
|
||||
select count(discount)
|
||||
from tpch_sf1_rcbinary_lineitem
|
@ -0,0 +1,4 @@
|
||||
format=generate
|
||||
=====
|
||||
select count(discount)
|
||||
from lineitem
|
@ -0,0 +1,4 @@
|
||||
format=generate
|
||||
=====
|
||||
select count(quantity)
|
||||
from lineitem
|
@ -0,0 +1,95 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<artifactId>presto-root</artifactId>
|
||||
<groupId>com.facebook.presto</groupId>
|
||||
<version>0.107</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>presto-benchmark</artifactId>
|
||||
<name>presto-benchmark</name>
|
||||
|
||||
<properties>
|
||||
<air.main.basedir>${project.parent.basedir}</air.main.basedir>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.facebook.presto</groupId>
|
||||
<artifactId>presto-spi</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.facebook.presto</groupId>
|
||||
<artifactId>presto-main</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.facebook.presto</groupId>
|
||||
<artifactId>presto-tpch</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
<artifactId>annotations</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>json</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>log</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>units</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jetbrains</groupId>
|
||||
<artifactId>annotations</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- for benchmark run -->
|
||||
<dependency>
|
||||
<groupId>io.airlift</groupId>
|
||||
<artifactId>bootstrap</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.ws.rs</groupId>
|
||||
<artifactId>javax.ws.rs-api</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- for testing -->
|
||||
<dependency>
|
||||
<groupId>org.testng</groupId>
|
||||
<artifactId>testng</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.benchmark;
|
||||
|
||||
import io.airlift.units.DataSize;
|
||||
import io.airlift.units.Duration;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static com.facebook.presto.benchmark.FormatUtils.formatCount;
|
||||
import static com.facebook.presto.benchmark.FormatUtils.formatCountRate;
|
||||
import static com.facebook.presto.benchmark.FormatUtils.formatDataRate;
|
||||
import static com.facebook.presto.benchmark.FormatUtils.formatDataSize;
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static io.airlift.units.DataSize.Unit.BYTE;
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
import static java.util.concurrent.TimeUnit.NANOSECONDS;
|
||||
|
||||
public abstract class AbstractBenchmark
|
||||
{
|
||||
private final String benchmarkName;
|
||||
private final int warmupIterations;
|
||||
private final int measuredIterations;
|
||||
|
||||
protected AbstractBenchmark(String benchmarkName, int warmupIterations, int measuredIterations)
|
||||
{
|
||||
checkNotNull(benchmarkName, "benchmarkName is null");
|
||||
checkArgument(warmupIterations >= 0, "warmupIterations must not be negative");
|
||||
checkArgument(measuredIterations >= 0, "measuredIterations must not be negative");
|
||||
|
||||
this.benchmarkName = benchmarkName;
|
||||
this.warmupIterations = warmupIterations;
|
||||
this.measuredIterations = measuredIterations;
|
||||
}
|
||||
|
||||
public String getBenchmarkName()
|
||||
{
|
||||
return benchmarkName;
|
||||
}
|
||||
|
||||
protected int getWarmupIterations()
|
||||
{
|
||||
return warmupIterations;
|
||||
}
|
||||
|
||||
protected int getMeasuredIterations()
|
||||
{
|
||||
return measuredIterations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize any state necessary to run benchmark. This is run once at start up.
|
||||
*/
|
||||
protected void setUp()
|
||||
{
|
||||
// Default: no-op
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the benchmark and returns the result metrics
|
||||
*/
|
||||
protected abstract Map<String, Long> runOnce();
|
||||
|
||||
/**
|
||||
* Clean up any state from the benchmark. This is run once after all the iterations are complete.
|
||||
*/
|
||||
protected void tearDown()
|
||||
{
|
||||
// Default: no-op
|
||||
}
|
||||
|
||||
public void runBenchmark()
|
||||
{
|
||||
runBenchmark(null);
|
||||
}
|
||||
|
||||
public void runBenchmark(@Nullable BenchmarkResultHook benchmarkResultHook)
|
||||
{
|
||||
AverageBenchmarkResults averageBenchmarkResults = new AverageBenchmarkResults();
|
||||
setUp();
|
||||
try {
|
||||
for (int i = 0; i < warmupIterations; i++) {
|
||||
runOnce();
|
||||
}
|
||||
for (int i = 0; i < measuredIterations; i++) {
|
||||
Map<String, Long> results = runOnce();
|
||||
if (benchmarkResultHook != null) {
|
||||
benchmarkResultHook.addResults(results);
|
||||
}
|
||||
averageBenchmarkResults.addResults(results);
|
||||
}
|
||||
}
|
||||
catch (Throwable t) {
|
||||
throw new RuntimeException("Exception in " + getBenchmarkName(), t);
|
||||
}
|
||||
finally {
|
||||
tearDown();
|
||||
}
|
||||
if (benchmarkResultHook != null) {
|
||||
benchmarkResultHook.finished();
|
||||
}
|
||||
|
||||
Map<String, Double> resultsAvg = averageBenchmarkResults.getAverageResultsValues();
|
||||
Duration cpuNanos = new Duration(resultsAvg.get("cpu_nanos"), NANOSECONDS);
|
||||
|
||||
long inputRows = resultsAvg.get("input_rows").longValue();
|
||||
DataSize inputBytes = new DataSize(resultsAvg.get("input_bytes"), BYTE);
|
||||
|
||||
long outputRows = resultsAvg.get("output_rows").longValue();
|
||||
DataSize outputBytes = new DataSize(resultsAvg.get("output_bytes"), BYTE);
|
||||
|
||||
System.out.printf("%35s :: %8.3f cpu ms :: in %5s, %6s, %8s, %8s :: out %5s, %6s, %8s, %8s%n",
|
||||
getBenchmarkName(),
|
||||
cpuNanos.getValue(MILLISECONDS),
|
||||
|
||||
formatCount(inputRows),
|
||||
formatDataSize(inputBytes, true),
|
||||
formatCountRate(inputRows, cpuNanos, true),
|
||||
formatDataRate(inputBytes, cpuNanos, true),
|
||||
|
||||
formatCount(outputRows),
|
||||
formatDataSize(outputBytes, true),
|
||||
formatCountRate(outputRows, cpuNanos, true),
|
||||
formatDataRate(outputBytes, cpuNanos, true));
|
||||
}
|
||||
}
|
@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.benchmark;
|
||||
|
||||
import com.facebook.presto.Session;
|
||||
import com.facebook.presto.execution.TaskId;
|
||||
import com.facebook.presto.execution.TaskStateMachine;
|
||||
import com.facebook.presto.memory.MemoryPool;
|
||||
import com.facebook.presto.memory.MemoryPoolId;
|
||||
import com.facebook.presto.memory.QueryContext;
|
||||
import com.facebook.presto.operator.Driver;
|
||||
import com.facebook.presto.operator.OperatorFactory;
|
||||
import com.facebook.presto.operator.TaskContext;
|
||||
import com.facebook.presto.operator.TaskStats;
|
||||
import com.facebook.presto.spi.type.Type;
|
||||
import com.facebook.presto.testing.LocalQueryRunner;
|
||||
import com.facebook.presto.util.CpuTimer;
|
||||
import com.facebook.presto.util.CpuTimer.CpuDuration;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import io.airlift.units.DataSize;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
import static com.facebook.presto.spi.type.TimeZoneKey.UTC_KEY;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static io.airlift.units.DataSize.Unit.BYTE;
|
||||
import static io.airlift.units.DataSize.Unit.GIGABYTE;
|
||||
import static io.airlift.units.DataSize.Unit.MEGABYTE;
|
||||
import static java.util.Locale.ENGLISH;
|
||||
import static java.util.concurrent.TimeUnit.NANOSECONDS;
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
|
||||
/**
|
||||
* Abstract template for benchmarks that want to test the performance of an Operator.
|
||||
*/
|
||||
public abstract class AbstractOperatorBenchmark
|
||||
extends AbstractBenchmark
|
||||
{
|
||||
protected final LocalQueryRunner localQueryRunner;
|
||||
|
||||
protected AbstractOperatorBenchmark(
|
||||
LocalQueryRunner localQueryRunner,
|
||||
String benchmarkName,
|
||||
int warmupIterations,
|
||||
int measuredIterations)
|
||||
{
|
||||
super(benchmarkName, warmupIterations, measuredIterations);
|
||||
this.localQueryRunner = checkNotNull(localQueryRunner, "localQueryRunner is null");
|
||||
}
|
||||
|
||||
protected OperatorFactory createTableScanOperator(int operatorId, String tableName, String... columnNames)
|
||||
{
|
||||
return localQueryRunner.createTableScanOperator(operatorId, tableName, columnNames);
|
||||
}
|
||||
|
||||
protected OperatorFactory createHashProjectOperator(int operatorId, List<Type> types)
|
||||
{
|
||||
return localQueryRunner.createHashProjectOperator(operatorId, types);
|
||||
}
|
||||
|
||||
protected abstract List<Driver> createDrivers(TaskContext taskContext);
|
||||
|
||||
protected void execute(TaskContext taskContext)
|
||||
{
|
||||
List<Driver> drivers = createDrivers(taskContext);
|
||||
|
||||
boolean done = false;
|
||||
while (!done) {
|
||||
boolean processed = false;
|
||||
for (Driver driver : drivers) {
|
||||
if (!driver.isFinished()) {
|
||||
driver.process();
|
||||
processed = true;
|
||||
}
|
||||
}
|
||||
done = !processed;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, Long> runOnce()
|
||||
{
|
||||
Session session = Session.builder()
|
||||
.setUser("user")
|
||||
.setSource("source")
|
||||
.setCatalog("catalog")
|
||||
.setSchema("schema")
|
||||
.setTimeZoneKey(UTC_KEY)
|
||||
.setLocale(ENGLISH)
|
||||
.setSystemProperties(ImmutableMap.of("optimizer.optimize-hash-generation", "true"))
|
||||
.build();
|
||||
ExecutorService executor = localQueryRunner.getExecutor();
|
||||
MemoryPool memoryPool = new MemoryPool(new MemoryPoolId("test"), new DataSize(1, GIGABYTE), false);
|
||||
TaskContext taskContext = new QueryContext(false, new DataSize(256, MEGABYTE), memoryPool, executor)
|
||||
.addTaskContext(new TaskStateMachine(new TaskId("query", "stage", "task"), executor),
|
||||
session,
|
||||
new DataSize(256, MEGABYTE),
|
||||
new DataSize(1, MEGABYTE),
|
||||
false,
|
||||
false);
|
||||
|
||||
CpuTimer cpuTimer = new CpuTimer();
|
||||
execute(taskContext);
|
||||
CpuDuration executionTime = cpuTimer.elapsedTime();
|
||||
|
||||
TaskStats taskStats = taskContext.getTaskStats();
|
||||
long inputRows = taskStats.getRawInputPositions();
|
||||
long inputBytes = taskStats.getRawInputDataSize().toBytes();
|
||||
long outputRows = taskStats.getOutputPositions();
|
||||
long outputBytes = taskStats.getOutputDataSize().toBytes();
|
||||
|
||||
double inputMegaBytes = new DataSize(inputBytes, BYTE).getValue(MEGABYTE);
|
||||
|
||||
return ImmutableMap.<String, Long>builder()
|
||||
// legacy computed values
|
||||
.put("elapsed_millis", executionTime.getWall().toMillis())
|
||||
.put("input_rows_per_second", (long) (inputRows / executionTime.getWall().getValue(SECONDS)))
|
||||
.put("output_rows_per_second", (long) (outputRows / executionTime.getWall().getValue(SECONDS)))
|
||||
.put("input_megabytes", (long) inputMegaBytes)
|
||||
.put("input_megabytes_per_second", (long) (inputMegaBytes / executionTime.getWall().getValue(SECONDS)))
|
||||
|
||||
.put("wall_nanos", executionTime.getWall().roundTo(NANOSECONDS))
|
||||
.put("cpu_nanos", executionTime.getCpu().roundTo(NANOSECONDS))
|
||||
.put("user_nanos", executionTime.getUser().roundTo(NANOSECONDS))
|
||||
.put("input_rows", inputRows)
|
||||
.put("input_bytes", inputBytes)
|
||||
.put("output_rows", outputRows)
|
||||
.put("output_bytes", outputBytes)
|
||||
|
||||
.build();
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.benchmark;
|
||||
|
||||
import com.facebook.presto.operator.Driver;
|
||||
import com.facebook.presto.operator.DriverContext;
|
||||
import com.facebook.presto.operator.DriverFactory;
|
||||
import com.facebook.presto.operator.OperatorFactory;
|
||||
import com.facebook.presto.operator.TaskContext;
|
||||
import com.facebook.presto.testing.LocalQueryRunner;
|
||||
import com.facebook.presto.testing.NullOutputOperator.NullOutputOperatorFactory;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class AbstractSimpleOperatorBenchmark
|
||||
extends AbstractOperatorBenchmark
|
||||
{
|
||||
protected AbstractSimpleOperatorBenchmark(
|
||||
LocalQueryRunner localQueryRunner,
|
||||
String benchmarkName,
|
||||
int warmupIterations,
|
||||
int measuredIterations)
|
||||
{
|
||||
super(localQueryRunner, benchmarkName, warmupIterations, measuredIterations);
|
||||
}
|
||||
|
||||
protected abstract List<? extends OperatorFactory> createOperatorFactories();
|
||||
|
||||
protected DriverFactory createDriverFactory()
|
||||
{
|
||||
List<OperatorFactory> operatorFactories = new ArrayList<>(createOperatorFactories());
|
||||
|
||||
operatorFactories.add(new NullOutputOperatorFactory(999, Iterables.getLast(operatorFactories).getTypes()));
|
||||
|
||||
return new DriverFactory(true, true, operatorFactories);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Driver> createDrivers(TaskContext taskContext)
|
||||
{
|
||||
DriverFactory driverFactory = createDriverFactory();
|
||||
DriverContext driverContext = taskContext.addPipelineContext(true, true).addDriverContext();
|
||||
Driver driver = driverFactory.createDriver(driverContext);
|
||||
return ImmutableList.of(driver);
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.benchmark;
|
||||
|
||||
import com.facebook.presto.operator.Driver;
|
||||
import com.facebook.presto.operator.TaskContext;
|
||||
import com.facebook.presto.testing.LocalQueryRunner;
|
||||
import com.facebook.presto.testing.NullOutputOperator.NullOutputFactory;
|
||||
import org.intellij.lang.annotations.Language;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public abstract class AbstractSqlBenchmark
|
||||
extends AbstractOperatorBenchmark
|
||||
{
|
||||
@Language("SQL")
|
||||
private final String query;
|
||||
|
||||
protected AbstractSqlBenchmark(
|
||||
LocalQueryRunner localQueryRunner,
|
||||
String benchmarkName,
|
||||
int warmupIterations,
|
||||
int measuredIterations,
|
||||
@Language("SQL") String query)
|
||||
{
|
||||
super(localQueryRunner, benchmarkName, warmupIterations, measuredIterations);
|
||||
this.query = query;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Driver> createDrivers(TaskContext taskContext)
|
||||
{
|
||||
return localQueryRunner.createDrivers(query, new NullOutputFactory(), taskContext);
|
||||
}
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.benchmark;
|
||||
|
||||
import com.facebook.presto.testing.LocalQueryRunner;
|
||||
|
||||
import static com.facebook.presto.benchmark.BenchmarkQueryRunner.createLocalQueryRunner;
|
||||
|
||||
public abstract class ArrayComparisonBenchmark
|
||||
{
|
||||
public static void main(String... args)
|
||||
{
|
||||
LocalQueryRunner localQueryRunner = createLocalQueryRunner();
|
||||
new ArrayEqualsBenchmark(localQueryRunner).runBenchmark(new SimpleLineBenchmarkResultWriter(System.out));
|
||||
new ArrayLessThanBenchmark(localQueryRunner).runBenchmark(new SimpleLineBenchmarkResultWriter(System.out));
|
||||
new ArrayGreaterThanBenchmark(localQueryRunner).runBenchmark(new SimpleLineBenchmarkResultWriter(System.out));
|
||||
new ArrayNotEqualBenchmark(localQueryRunner).runBenchmark(new SimpleLineBenchmarkResultWriter(System.out));
|
||||
new ArrayLessThanOrEqualBenchmark(localQueryRunner).runBenchmark(new SimpleLineBenchmarkResultWriter(System.out));
|
||||
new ArrayGreaterThanOrEqualBenchmark(localQueryRunner).runBenchmark(new SimpleLineBenchmarkResultWriter(System.out));
|
||||
}
|
||||
|
||||
public static class ArrayEqualsBenchmark
|
||||
extends AbstractSqlBenchmark
|
||||
{
|
||||
public ArrayEqualsBenchmark(LocalQueryRunner localQueryRunner)
|
||||
{
|
||||
super(localQueryRunner, "array_equals", 5, 50, "SELECT COUNT_IF(ARRAY [orderkey, orderkey + 1, orderkey + 2] = ARRAY[orderkey + 1, orderkey + 2, orderkey + 3]) FROM orders");
|
||||
}
|
||||
}
|
||||
|
||||
public static class ArrayLessThanBenchmark
|
||||
extends AbstractSqlBenchmark
|
||||
{
|
||||
public ArrayLessThanBenchmark(LocalQueryRunner localQueryRunner)
|
||||
{
|
||||
super(localQueryRunner, "array_less_than", 5, 50, "SELECT COUNT_IF(ARRAY [quantity, quantity + 5] < ARRAY[quantity, quantity + 5, quantity + 3]) FROM lineitem");
|
||||
}
|
||||
}
|
||||
|
||||
public static class ArrayGreaterThanBenchmark
|
||||
extends AbstractSqlBenchmark
|
||||
{
|
||||
public ArrayGreaterThanBenchmark(LocalQueryRunner localQueryRunner)
|
||||
{
|
||||
super(localQueryRunner, "array_greater_than", 5, 50, "SELECT COUNT_IF(ARRAY [quantity, quantity + 6] > ARRAY[quantity, quantity + 5, quantity + 3]) FROM lineitem");
|
||||
}
|
||||
}
|
||||
|
||||
public static class ArrayNotEqualBenchmark
|
||||
extends AbstractSqlBenchmark
|
||||
{
|
||||
public ArrayNotEqualBenchmark(LocalQueryRunner localQueryRunner)
|
||||
{
|
||||
super(localQueryRunner, "array_not_equal", 5, 50, "SELECT COUNT_IF(ARRAY [orderkey, orderkey + 1, orderkey + 2] != ARRAY[orderkey + 1, orderkey + 2, orderkey + 3]) FROM orders");
|
||||
}
|
||||
}
|
||||
|
||||
public static class ArrayLessThanOrEqualBenchmark
|
||||
extends AbstractSqlBenchmark
|
||||
{
|
||||
public ArrayLessThanOrEqualBenchmark(LocalQueryRunner localQueryRunner)
|
||||
{
|
||||
super(localQueryRunner, "array_less_than_or_equal", 5, 50, "SELECT COUNT_IF(ARRAY [quantity, quantity + 5, quantity + 2] <= ARRAY[quantity, quantity + 5, quantity + 3]) FROM lineitem");
|
||||
}
|
||||
}
|
||||
|
||||
public static class ArrayGreaterThanOrEqualBenchmark
|
||||
extends AbstractSqlBenchmark
|
||||
{
|
||||
public ArrayGreaterThanOrEqualBenchmark(LocalQueryRunner localQueryRunner)
|
||||
{
|
||||
super(localQueryRunner, "array_greater_than_or_equal", 5, 50, "SELECT COUNT_IF(ARRAY [quantity, quantity + 6] >= ARRAY[quantity, quantity + 5, quantity + 3]) FROM lineitem");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.benchmark;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class AverageBenchmarkResults
|
||||
implements BenchmarkResultHook
|
||||
{
|
||||
private final Map<String, Long> resultsSum = new LinkedHashMap<>();
|
||||
private int resultsCount;
|
||||
|
||||
@Override
|
||||
public BenchmarkResultHook addResults(Map<String, Long> results)
|
||||
{
|
||||
checkNotNull(results, "results is null");
|
||||
for (Entry<String, Long> entry : results.entrySet()) {
|
||||
Long currentSum = resultsSum.get(entry.getKey());
|
||||
if (currentSum == null) {
|
||||
currentSum = 0L;
|
||||
}
|
||||
resultsSum.put(entry.getKey(), currentSum + entry.getValue());
|
||||
}
|
||||
resultsCount++;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public Map<String, Double> getAverageResultsValues()
|
||||
{
|
||||
return Maps.transformValues(resultsSum, input -> 1.0 * input / resultsCount);
|
||||
}
|
||||
|
||||
public Map<String, String> getAverageResultsStrings()
|
||||
{
|
||||
return Maps.transformValues(resultsSum, input -> String.format("%,3.2f", 1.0 * input / resultsCount));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finished()
|
||||
{
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.benchmark;
|
||||
|
||||
import com.facebook.presto.Session;
|
||||
import com.facebook.presto.metadata.InMemoryNodeManager;
|
||||
import com.facebook.presto.testing.LocalQueryRunner;
|
||||
import com.facebook.presto.tpch.TpchConnectorFactory;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import static com.facebook.presto.Session.SessionBuilder;
|
||||
import static com.facebook.presto.spi.type.TimeZoneKey.UTC_KEY;
|
||||
import static com.facebook.presto.tpch.TpchMetadata.TINY_SCHEMA_NAME;
|
||||
import static java.util.Locale.ENGLISH;
|
||||
|
||||
public final class BenchmarkQueryRunner
|
||||
{
|
||||
private BenchmarkQueryRunner()
|
||||
{
|
||||
}
|
||||
|
||||
public static LocalQueryRunner createLocalQueryRunnerHashEnabled()
|
||||
{
|
||||
return createLocalQueryRunner(true);
|
||||
}
|
||||
|
||||
public static LocalQueryRunner createLocalQueryRunner()
|
||||
{
|
||||
return createLocalQueryRunner(false);
|
||||
}
|
||||
public static LocalQueryRunner createLocalQueryRunner(boolean hashingEnabled)
|
||||
{
|
||||
SessionBuilder sessionBuilder = Session
|
||||
.builder()
|
||||
.setUser("user")
|
||||
.setSource("test")
|
||||
.setCatalog("tpch")
|
||||
.setSchema(TINY_SCHEMA_NAME)
|
||||
.setTimeZoneKey(UTC_KEY)
|
||||
.setLocale(ENGLISH);
|
||||
|
||||
if (hashingEnabled) {
|
||||
sessionBuilder.setSystemProperties(ImmutableMap.of("optimizer.optimize_hash_generation", "true"));
|
||||
}
|
||||
|
||||
Session session = sessionBuilder.build();
|
||||
LocalQueryRunner localQueryRunner = new LocalQueryRunner(session);
|
||||
|
||||
// add tpch
|
||||
InMemoryNodeManager nodeManager = localQueryRunner.getNodeManager();
|
||||
localQueryRunner.createCatalog("tpch", new TpchConnectorFactory(nodeManager, 1), ImmutableMap.<String, String>of());
|
||||
|
||||
return localQueryRunner;
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.benchmark;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public interface BenchmarkResultHook
|
||||
{
|
||||
BenchmarkResultHook addResults(Map<String, Long> results);
|
||||
|
||||
void finished();
|
||||
}
|
@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.benchmark;
|
||||
|
||||
import com.facebook.presto.testing.LocalQueryRunner;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.io.Files;
|
||||
import io.airlift.log.Logger;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.facebook.presto.testing.LocalQueryRunner.createHashEnabledQueryRunner;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class BenchmarkSuite
|
||||
{
|
||||
private static final Logger LOGGER = Logger.get(BenchmarkSuite.class);
|
||||
|
||||
public static List<AbstractBenchmark> createBenchmarks(LocalQueryRunner localQueryRunner, LocalQueryRunner hashEnabledLocalQueryRunner)
|
||||
{
|
||||
return ImmutableList.<AbstractBenchmark>of(
|
||||
// hand built benchmarks
|
||||
new CountAggregationBenchmark(localQueryRunner),
|
||||
new DoubleSumAggregationBenchmark(localQueryRunner),
|
||||
new HashAggregationBenchmark(localQueryRunner),
|
||||
new PredicateFilterBenchmark(localQueryRunner),
|
||||
new RawStreamingBenchmark(localQueryRunner),
|
||||
new Top100Benchmark(localQueryRunner),
|
||||
new OrderByBenchmark(localQueryRunner),
|
||||
new HashBuildBenchmark(localQueryRunner),
|
||||
new HashJoinBenchmark(localQueryRunner),
|
||||
new HashBuildAndJoinBenchmark(localQueryRunner),
|
||||
new HashBuildAndJoinBenchmark(hashEnabledLocalQueryRunner),
|
||||
new HandTpchQuery1(localQueryRunner),
|
||||
new HandTpchQuery6(localQueryRunner),
|
||||
|
||||
// sql benchmarks
|
||||
new GroupBySumWithArithmeticSqlBenchmark(localQueryRunner),
|
||||
new CountAggregationSqlBenchmark(localQueryRunner),
|
||||
new SqlDoubleSumAggregationBenchmark(localQueryRunner),
|
||||
new CountWithFilterSqlBenchmark(localQueryRunner),
|
||||
new GroupByAggregationSqlBenchmark(localQueryRunner),
|
||||
new PredicateFilterSqlBenchmark(localQueryRunner),
|
||||
new RawStreamingSqlBenchmark(localQueryRunner),
|
||||
new Top100SqlBenchmark(localQueryRunner),
|
||||
new SqlHashJoinBenchmark(localQueryRunner),
|
||||
new SqlJoinWithPredicateBenchmark(localQueryRunner),
|
||||
new LongMaxAggregationSqlBenchmark(localQueryRunner),
|
||||
new VarBinaryMaxAggregationSqlBenchmark(localQueryRunner),
|
||||
new SqlDistinctMultipleFields(localQueryRunner),
|
||||
new SqlDistinctSingleField(localQueryRunner),
|
||||
new SqlTpchQuery1(localQueryRunner),
|
||||
new SqlTpchQuery6(localQueryRunner),
|
||||
new SqlLikeBenchmark(localQueryRunner),
|
||||
new SqlInBenchmark(localQueryRunner),
|
||||
new SqlSemiJoinInPredicateBenchmark(localQueryRunner),
|
||||
new SqlRegexpLikeBenchmark(localQueryRunner),
|
||||
new SqlApproximatePercentileBenchmark(localQueryRunner),
|
||||
new SqlBetweenBenchmark(localQueryRunner),
|
||||
|
||||
// statistics benchmarks
|
||||
new StatisticsBenchmark.LongVarianceBenchmark(localQueryRunner),
|
||||
new StatisticsBenchmark.LongVariancePopBenchmark(localQueryRunner),
|
||||
new StatisticsBenchmark.DoubleVarianceBenchmark(localQueryRunner),
|
||||
new StatisticsBenchmark.DoubleVariancePopBenchmark(localQueryRunner),
|
||||
new StatisticsBenchmark.LongStdDevBenchmark(localQueryRunner),
|
||||
new StatisticsBenchmark.LongStdDevPopBenchmark(localQueryRunner),
|
||||
new StatisticsBenchmark.DoubleStdDevBenchmark(localQueryRunner),
|
||||
new StatisticsBenchmark.DoubleStdDevPopBenchmark(localQueryRunner),
|
||||
|
||||
// array comparison benchmarks
|
||||
new ArrayComparisonBenchmark.ArrayEqualsBenchmark(localQueryRunner),
|
||||
new ArrayComparisonBenchmark.ArrayLessThanBenchmark(localQueryRunner),
|
||||
new ArrayComparisonBenchmark.ArrayGreaterThanBenchmark(localQueryRunner),
|
||||
new ArrayComparisonBenchmark.ArrayNotEqualBenchmark(localQueryRunner),
|
||||
new ArrayComparisonBenchmark.ArrayLessThanOrEqualBenchmark(localQueryRunner),
|
||||
new ArrayComparisonBenchmark.ArrayGreaterThanOrEqualBenchmark(localQueryRunner),
|
||||
|
||||
new SqlApproximateCountDistinctLongBenchmark(localQueryRunner),
|
||||
new SqlApproximateCountDistinctDoubleBenchmark(localQueryRunner),
|
||||
new SqlApproximateCountDistinctVarBinaryBenchmark(localQueryRunner)
|
||||
);
|
||||
}
|
||||
|
||||
private final LocalQueryRunner localQueryRunner;
|
||||
private final LocalQueryRunner hashEnabledLocalQueryRunner;
|
||||
private final String outputDirectory;
|
||||
|
||||
public BenchmarkSuite(LocalQueryRunner localQueryRunner, String outputDirectory)
|
||||
{
|
||||
this.localQueryRunner = localQueryRunner;
|
||||
this.hashEnabledLocalQueryRunner = createHashEnabledQueryRunner(localQueryRunner);
|
||||
this.outputDirectory = checkNotNull(outputDirectory, "outputDirectory is null");
|
||||
}
|
||||
|
||||
private static File createOutputFile(String fileName)
|
||||
throws IOException
|
||||
{
|
||||
File outputFile = new File(fileName);
|
||||
Files.createParentDirs(outputFile);
|
||||
return outputFile;
|
||||
}
|
||||
|
||||
public void runAllBenchmarks()
|
||||
throws IOException
|
||||
{
|
||||
List<AbstractBenchmark> benchmarks = createBenchmarks(localQueryRunner, hashEnabledLocalQueryRunner);
|
||||
|
||||
LOGGER.info("=== Pre-running all benchmarks for JVM warmup ===");
|
||||
for (AbstractBenchmark benchmark : benchmarks) {
|
||||
benchmark.runBenchmark();
|
||||
}
|
||||
|
||||
LOGGER.info("=== Actually running benchmarks for metrics ===");
|
||||
for (AbstractBenchmark benchmark : benchmarks) {
|
||||
try (OutputStream jsonOut = new FileOutputStream(createOutputFile(String.format("%s/json/%s.json", outputDirectory, benchmark.getBenchmarkName())));
|
||||
OutputStream jsonAvgOut = new FileOutputStream(createOutputFile(String.format("%s/json-avg/%s.json", outputDirectory, benchmark.getBenchmarkName())));
|
||||
OutputStream csvOut = new FileOutputStream(createOutputFile(String.format("%s/csv/%s.csv", outputDirectory, benchmark.getBenchmarkName())));
|
||||
OutputStream odsOut = new FileOutputStream(createOutputFile(String.format("%s/ods/%s.json", outputDirectory, benchmark.getBenchmarkName())))) {
|
||||
benchmark.runBenchmark(
|
||||
new ForwardingBenchmarkResultWriter(
|
||||
ImmutableList.of(
|
||||
new JsonBenchmarkResultWriter(jsonOut),
|
||||
new JsonAvgBenchmarkResultWriter(jsonAvgOut),
|
||||
new SimpleLineBenchmarkResultWriter(csvOut),
|
||||
new OdsBenchmarkResultWriter("presto.benchmark." + benchmark.getBenchmarkName(), odsOut)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class ForwardingBenchmarkResultWriter
|
||||
implements BenchmarkResultHook
|
||||
{
|
||||
private final List<BenchmarkResultHook> benchmarkResultHooks;
|
||||
|
||||
private ForwardingBenchmarkResultWriter(List<BenchmarkResultHook> benchmarkResultHooks)
|
||||
{
|
||||
checkNotNull(benchmarkResultHooks, "benchmarkResultWriters is null");
|
||||
this.benchmarkResultHooks = ImmutableList.copyOf(benchmarkResultHooks);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BenchmarkResultHook addResults(Map<String, Long> results)
|
||||
{
|
||||
checkNotNull(results, "results is null");
|
||||
for (BenchmarkResultHook benchmarkResultHook : benchmarkResultHooks) {
|
||||
benchmarkResultHook.addResults(results);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finished()
|
||||
{
|
||||
for (BenchmarkResultHook benchmarkResultHook : benchmarkResultHooks) {
|
||||
benchmarkResultHook.finished();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.benchmark;
|
||||
|
||||
import com.facebook.presto.operator.AggregationOperator.AggregationOperatorFactory;
|
||||
import com.facebook.presto.operator.OperatorFactory;
|
||||
import com.facebook.presto.sql.planner.plan.AggregationNode.Step;
|
||||
import com.facebook.presto.testing.LocalQueryRunner;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import static com.facebook.presto.benchmark.BenchmarkQueryRunner.createLocalQueryRunner;
|
||||
import static com.facebook.presto.operator.aggregation.CountAggregation.COUNT;
|
||||
|
||||
public class CountAggregationBenchmark
|
||||
extends AbstractSimpleOperatorBenchmark
|
||||
{
|
||||
public CountAggregationBenchmark(LocalQueryRunner localQueryRunner)
|
||||
{
|
||||
super(localQueryRunner, "count_agg", 10, 100);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<? extends OperatorFactory> createOperatorFactories()
|
||||
{
|
||||
OperatorFactory tableScanOperator = createTableScanOperator(0, "orders", "orderkey");
|
||||
AggregationOperatorFactory aggregationOperator = new AggregationOperatorFactory(1, Step.SINGLE, ImmutableList.of(COUNT.bind(ImmutableList.of(0), Optional.empty(), Optional.empty(), 1.0)));
|
||||
return ImmutableList.of(tableScanOperator, aggregationOperator);
|
||||
}
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
new CountAggregationBenchmark(createLocalQueryRunner()).runBenchmark(new SimpleLineBenchmarkResultWriter(System.out));
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.benchmark;
|
||||
|
||||
import com.facebook.presto.testing.LocalQueryRunner;
|
||||
|
||||
import static com.facebook.presto.benchmark.BenchmarkQueryRunner.createLocalQueryRunner;
|
||||
|
||||
public class CountAggregationSqlBenchmark
|
||||
extends AbstractSqlBenchmark
|
||||
{
|
||||
public CountAggregationSqlBenchmark(LocalQueryRunner localQueryRunner)
|
||||
{
|
||||
super(localQueryRunner, "sql_count_agg", 10, 100, "select count(*) from orders");
|
||||
}
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
new CountAggregationSqlBenchmark(createLocalQueryRunner()).runBenchmark(new SimpleLineBenchmarkResultWriter(System.out));
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.benchmark;
|
||||
|
||||
import com.facebook.presto.testing.LocalQueryRunner;
|
||||
|
||||
import static com.facebook.presto.benchmark.BenchmarkQueryRunner.createLocalQueryRunner;
|
||||
|
||||
public class CountWithFilterSqlBenchmark
|
||||
extends AbstractSqlBenchmark
|
||||
{
|
||||
public CountWithFilterSqlBenchmark(LocalQueryRunner localQueryRunner)
|
||||
{
|
||||
super(localQueryRunner, "sql_count_with_filter", 10, 100, "SELECT count(*) from orders where orderstatus = 'F'");
|
||||
}
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
new CountWithFilterSqlBenchmark(createLocalQueryRunner()).runBenchmark(new SimpleLineBenchmarkResultWriter(System.out));
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.benchmark;
|
||||
|
||||
import com.facebook.presto.operator.AggregationOperator.AggregationOperatorFactory;
|
||||
import com.facebook.presto.operator.OperatorFactory;
|
||||
import com.facebook.presto.sql.planner.plan.AggregationNode.Step;
|
||||
import com.facebook.presto.testing.LocalQueryRunner;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import static com.facebook.presto.benchmark.BenchmarkQueryRunner.createLocalQueryRunner;
|
||||
import static com.facebook.presto.operator.aggregation.DoubleSumAggregation.DOUBLE_SUM;
|
||||
|
||||
public class DoubleSumAggregationBenchmark
|
||||
extends AbstractSimpleOperatorBenchmark
|
||||
{
|
||||
public DoubleSumAggregationBenchmark(LocalQueryRunner localQueryRunner)
|
||||
{
|
||||
super(localQueryRunner, "double_sum_agg", 10, 100);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<? extends OperatorFactory> createOperatorFactories()
|
||||
{
|
||||
OperatorFactory tableScanOperator = createTableScanOperator(0, "orders", "totalprice");
|
||||
AggregationOperatorFactory aggregationOperator = new AggregationOperatorFactory(1, Step.SINGLE, ImmutableList.of(DOUBLE_SUM.bind(ImmutableList.of(0), Optional.empty(), Optional.empty(), 1.0)));
|
||||
return ImmutableList.of(tableScanOperator, aggregationOperator);
|
||||
}
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
new DoubleSumAggregationBenchmark(createLocalQueryRunner()).runBenchmark(new SimpleLineBenchmarkResultWriter(System.out));
|
||||
}
|
||||
}
|
@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.benchmark;
|
||||
|
||||
import io.airlift.units.DataSize;
|
||||
import io.airlift.units.Duration;
|
||||
|
||||
import java.math.RoundingMode;
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
import static io.airlift.units.DataSize.Unit.BYTE;
|
||||
import static java.lang.String.format;
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
|
||||
// TODO: these should be in airlift
|
||||
final class FormatUtils
|
||||
{
|
||||
private FormatUtils() {}
|
||||
|
||||
public static String formatCount(long count)
|
||||
{
|
||||
double fractional = count;
|
||||
String unit = "";
|
||||
if (fractional > 1000) {
|
||||
fractional /= 1000;
|
||||
unit = "K";
|
||||
}
|
||||
if (fractional > 1000) {
|
||||
fractional /= 1000;
|
||||
unit = "M";
|
||||
}
|
||||
if (fractional > 1000) {
|
||||
fractional /= 1000;
|
||||
unit = "B";
|
||||
}
|
||||
if (fractional > 1000) {
|
||||
fractional /= 1000;
|
||||
unit = "T";
|
||||
}
|
||||
if (fractional > 1000) {
|
||||
fractional /= 1000;
|
||||
unit = "Q";
|
||||
}
|
||||
|
||||
return format("%s%s", getFormat(fractional).format(fractional), unit);
|
||||
}
|
||||
|
||||
public static String formatCountRate(double count, Duration duration, boolean longForm)
|
||||
{
|
||||
double rate = count / duration.getValue(SECONDS);
|
||||
if (Double.isNaN(rate) || Double.isInfinite(rate)) {
|
||||
rate = 0;
|
||||
}
|
||||
|
||||
String rateString = formatCount((long) rate);
|
||||
if (longForm) {
|
||||
if (rateString.endsWith(" ")) {
|
||||
rateString = rateString.substring(0, rateString.length() - 1);
|
||||
}
|
||||
rateString += "/s";
|
||||
}
|
||||
return rateString;
|
||||
}
|
||||
|
||||
public static String formatDataSize(DataSize size, boolean longForm)
|
||||
{
|
||||
double fractional = size.toBytes();
|
||||
String unit = null;
|
||||
if (fractional >= 1024) {
|
||||
fractional /= 1024;
|
||||
unit = "K";
|
||||
}
|
||||
if (fractional >= 1024) {
|
||||
fractional /= 1024;
|
||||
unit = "M";
|
||||
}
|
||||
if (fractional >= 1024) {
|
||||
fractional /= 1024;
|
||||
unit = "G";
|
||||
}
|
||||
if (fractional >= 1024) {
|
||||
fractional /= 1024;
|
||||
unit = "T";
|
||||
}
|
||||
if (fractional >= 1024) {
|
||||
fractional /= 1024;
|
||||
unit = "P";
|
||||
}
|
||||
|
||||
if (unit == null) {
|
||||
unit = "B";
|
||||
}
|
||||
else if (longForm) {
|
||||
unit += "B";
|
||||
}
|
||||
|
||||
return format("%s%s", getFormat(fractional).format(fractional), unit);
|
||||
}
|
||||
|
||||
public static String formatDataRate(DataSize dataSize, Duration duration, boolean longForm)
|
||||
{
|
||||
double rate = dataSize.toBytes() / duration.getValue(SECONDS);
|
||||
if (Double.isNaN(rate) || Double.isInfinite(rate)) {
|
||||
rate = 0;
|
||||
}
|
||||
|
||||
String rateString = formatDataSize(new DataSize(rate, BYTE), false);
|
||||
if (longForm) {
|
||||
if (!rateString.endsWith("B")) {
|
||||
rateString += "B";
|
||||
}
|
||||
rateString += "/s";
|
||||
}
|
||||
return rateString;
|
||||
}
|
||||
|
||||
public static DecimalFormat getFormat(double value)
|
||||
{
|
||||
DecimalFormat format;
|
||||
if (value < 10) {
|
||||
// show up to two decimals to get 3 significant digits
|
||||
format = new DecimalFormat("#.##");
|
||||
}
|
||||
else if (value < 100) {
|
||||
// show up to one decimal to get 3 significant digits
|
||||
format = new DecimalFormat("#.#");
|
||||
}
|
||||
else {
|
||||
// show no decimals -- we have enough digits in the integer part
|
||||
format = new DecimalFormat("#");
|
||||
}
|
||||
|
||||
format.setRoundingMode(RoundingMode.HALF_UP);
|
||||
return format;
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.benchmark;
|
||||
|
||||
import com.facebook.presto.testing.LocalQueryRunner;
|
||||
|
||||
import static com.facebook.presto.benchmark.BenchmarkQueryRunner.createLocalQueryRunner;
|
||||
|
||||
public class GroupByAggregationSqlBenchmark
|
||||
extends AbstractSqlBenchmark
|
||||
{
|
||||
public GroupByAggregationSqlBenchmark(LocalQueryRunner localQueryRunner)
|
||||
{
|
||||
super(localQueryRunner, "sql_groupby_agg", 15, 100, "select orderstatus, sum(totalprice) from orders group by orderstatus");
|
||||
}
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
new GroupByAggregationSqlBenchmark(createLocalQueryRunner()).runBenchmark(new SimpleLineBenchmarkResultWriter(System.out));
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.benchmark;
|
||||
|
||||
import com.facebook.presto.testing.LocalQueryRunner;
|
||||
|
||||
import static com.facebook.presto.benchmark.BenchmarkQueryRunner.createLocalQueryRunner;
|
||||
|
||||
public class GroupBySumWithArithmeticSqlBenchmark
|
||||
extends AbstractSqlBenchmark
|
||||
{
|
||||
public GroupBySumWithArithmeticSqlBenchmark(LocalQueryRunner localQueryRunner)
|
||||
{
|
||||
super(localQueryRunner,
|
||||
"sql_groupby_agg_with_arithmetic",
|
||||
1,
|
||||
4,
|
||||
"select linestatus, sum(orderkey - partkey) from lineitem group by linestatus");
|
||||
}
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
new GroupBySumWithArithmeticSqlBenchmark(createLocalQueryRunner()).runBenchmark(new SimpleLineBenchmarkResultWriter(System.out));
|
||||
}
|
||||
}
|
@ -0,0 +1,324 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.benchmark;
|
||||
|
||||
import com.facebook.presto.benchmark.HandTpchQuery1.TpchQuery1Operator.TpchQuery1OperatorFactory;
|
||||
import com.facebook.presto.operator.DriverContext;
|
||||
import com.facebook.presto.operator.HashAggregationOperator.HashAggregationOperatorFactory;
|
||||
import com.facebook.presto.operator.Operator;
|
||||
import com.facebook.presto.operator.OperatorContext;
|
||||
import com.facebook.presto.operator.OperatorFactory;
|
||||
import com.facebook.presto.spi.Page;
|
||||
import com.facebook.presto.spi.PageBuilder;
|
||||
import com.facebook.presto.spi.block.Block;
|
||||
import com.facebook.presto.spi.type.Type;
|
||||
import com.facebook.presto.sql.planner.plan.AggregationNode.Step;
|
||||
import com.facebook.presto.testing.LocalQueryRunner;
|
||||
import com.facebook.presto.util.DateTimeUtils;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.primitives.Ints;
|
||||
import io.airlift.units.DataSize;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import static com.facebook.presto.benchmark.BenchmarkQueryRunner.createLocalQueryRunner;
|
||||
import static com.facebook.presto.operator.aggregation.AverageAggregations.DOUBLE_AVERAGE;
|
||||
import static com.facebook.presto.operator.aggregation.AverageAggregations.LONG_AVERAGE;
|
||||
import static com.facebook.presto.operator.aggregation.CountAggregation.COUNT;
|
||||
import static com.facebook.presto.operator.aggregation.DoubleSumAggregation.DOUBLE_SUM;
|
||||
import static com.facebook.presto.operator.aggregation.LongSumAggregation.LONG_SUM;
|
||||
import static com.facebook.presto.spi.type.BigintType.BIGINT;
|
||||
import static com.facebook.presto.spi.type.DateType.DATE;
|
||||
import static com.facebook.presto.spi.type.DoubleType.DOUBLE;
|
||||
import static com.facebook.presto.spi.type.VarcharType.VARCHAR;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static io.airlift.units.DataSize.Unit.MEGABYTE;
|
||||
|
||||
public class HandTpchQuery1
|
||||
extends AbstractSimpleOperatorBenchmark
|
||||
{
|
||||
public HandTpchQuery1(LocalQueryRunner localQueryRunner)
|
||||
{
|
||||
super(localQueryRunner, "hand_tpch_query_1", 1, 5);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<? extends OperatorFactory> createOperatorFactories()
|
||||
{
|
||||
// select
|
||||
// returnflag,
|
||||
// linestatus,
|
||||
// sum(quantity) as sum_qty,
|
||||
// sum(extendedprice) as sum_base_price,
|
||||
// sum(extendedprice * (1 - discount)) as sum_disc_price,
|
||||
// sum(extendedprice * (1 - discount) * (1 + tax)) as sum_charge,
|
||||
// avg(quantity) as avg_qty,
|
||||
// avg(extendedprice) as avg_price,
|
||||
// avg(discount) as avg_disc,
|
||||
// count(*) as count_order
|
||||
// from
|
||||
// lineitem
|
||||
// where
|
||||
// shipdate <= '1998-09-02'
|
||||
// group by
|
||||
// returnflag,
|
||||
// linestatus
|
||||
// order by
|
||||
// returnflag,
|
||||
// linestatus
|
||||
|
||||
OperatorFactory tableScanOperator = createTableScanOperator(
|
||||
0,
|
||||
"lineitem",
|
||||
"returnflag",
|
||||
"linestatus",
|
||||
"quantity",
|
||||
"extendedprice",
|
||||
"discount",
|
||||
"tax",
|
||||
"shipdate");
|
||||
|
||||
TpchQuery1OperatorFactory tpchQuery1Operator = new TpchQuery1OperatorFactory(1);
|
||||
HashAggregationOperatorFactory aggregationOperator = new HashAggregationOperatorFactory(
|
||||
2,
|
||||
ImmutableList.of(tpchQuery1Operator.getTypes().get(0), tpchQuery1Operator.getTypes().get(1)),
|
||||
Ints.asList(0, 1),
|
||||
Step.SINGLE,
|
||||
ImmutableList.of(
|
||||
LONG_SUM.bind(ImmutableList.of(2), Optional.empty(), Optional.empty(), 1.0),
|
||||
DOUBLE_SUM.bind(ImmutableList.of(3), Optional.empty(), Optional.empty(), 1.0),
|
||||
DOUBLE_SUM.bind(ImmutableList.of(4), Optional.empty(), Optional.empty(), 1.0),
|
||||
LONG_AVERAGE.bind(ImmutableList.of(2), Optional.empty(), Optional.empty(), 1.0),
|
||||
DOUBLE_AVERAGE.bind(ImmutableList.of(5), Optional.empty(), Optional.empty(), 1.0),
|
||||
DOUBLE_AVERAGE.bind(ImmutableList.of(6), Optional.empty(), Optional.empty(), 1.0),
|
||||
COUNT.bind(ImmutableList.of(2), Optional.empty(), Optional.empty(), 1.0)
|
||||
),
|
||||
Optional.empty(),
|
||||
Optional.empty(),
|
||||
10_000,
|
||||
new DataSize(16, MEGABYTE));
|
||||
|
||||
return ImmutableList.of(tableScanOperator, tpchQuery1Operator, aggregationOperator);
|
||||
}
|
||||
|
||||
public static class TpchQuery1Operator
|
||||
implements com.facebook.presto.operator.Operator // TODO: use import when Java 7 compiler bug is fixed
|
||||
{
|
||||
private static final ImmutableList<Type> TYPES = ImmutableList.<Type>of(
|
||||
VARCHAR,
|
||||
VARCHAR,
|
||||
BIGINT,
|
||||
DOUBLE,
|
||||
DOUBLE,
|
||||
DOUBLE,
|
||||
DOUBLE);
|
||||
|
||||
public static class TpchQuery1OperatorFactory
|
||||
implements OperatorFactory
|
||||
{
|
||||
private final int operatorId;
|
||||
|
||||
public TpchQuery1OperatorFactory(int operatorId)
|
||||
{
|
||||
this.operatorId = operatorId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Type> getTypes()
|
||||
{
|
||||
return TYPES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Operator createOperator(DriverContext driverContext)
|
||||
{
|
||||
OperatorContext operatorContext = driverContext.addOperatorContext(operatorId, TpchQuery1Operator.class.getSimpleName());
|
||||
return new TpchQuery1Operator(operatorContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private final OperatorContext operatorContext;
|
||||
private final PageBuilder pageBuilder;
|
||||
private boolean finishing;
|
||||
|
||||
public TpchQuery1Operator(OperatorContext operatorContext)
|
||||
{
|
||||
this.operatorContext = checkNotNull(operatorContext, "operatorContext is null");
|
||||
this.pageBuilder = new PageBuilder(TYPES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OperatorContext getOperatorContext()
|
||||
{
|
||||
return operatorContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Type> getTypes()
|
||||
{
|
||||
return TYPES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish()
|
||||
{
|
||||
finishing = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFinished()
|
||||
{
|
||||
return finishing && pageBuilder.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean needsInput()
|
||||
{
|
||||
return !pageBuilder.isFull();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addInput(Page page)
|
||||
{
|
||||
checkNotNull(page, "page is null");
|
||||
checkState(!pageBuilder.isFull(), "Output buffer is full");
|
||||
checkState(!finishing, "Operator is finished");
|
||||
|
||||
filterAndProjectRowOriented(pageBuilder,
|
||||
page.getBlock(0),
|
||||
page.getBlock(1),
|
||||
page.getBlock(2),
|
||||
page.getBlock(3),
|
||||
page.getBlock(4),
|
||||
page.getBlock(5),
|
||||
page.getBlock(6));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page getOutput()
|
||||
{
|
||||
// only return a page if the page buffer isFull or we are finishing and the page buffer has data
|
||||
if (pageBuilder.isFull() || (finishing && !pageBuilder.isEmpty())) {
|
||||
Page page = pageBuilder.build();
|
||||
pageBuilder.reset();
|
||||
return page;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static final int MAX_SHIP_DATE = DateTimeUtils.parseDate("1998-09-02");
|
||||
|
||||
private static void filterAndProjectRowOriented(PageBuilder pageBuilder,
|
||||
Block returnFlagBlock,
|
||||
Block lineStatusBlock,
|
||||
Block quantityBlock,
|
||||
Block extendedPriceBlock,
|
||||
Block discountBlock,
|
||||
Block taxBlock,
|
||||
Block shipDateBlock)
|
||||
{
|
||||
int rows = returnFlagBlock.getPositionCount();
|
||||
for (int position = 0; position < rows; position++) {
|
||||
if (shipDateBlock.isNull(position)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int shipDate = (int) DATE.getLong(shipDateBlock, position);
|
||||
|
||||
// where
|
||||
// shipdate <= '1998-09-02'
|
||||
if (shipDate <= MAX_SHIP_DATE) {
|
||||
// returnflag,
|
||||
// linestatus
|
||||
// quantity
|
||||
// extendedprice
|
||||
// extendedprice * (1 - discount)
|
||||
// extendedprice * (1 - discount) * (1 + tax)
|
||||
// discount
|
||||
|
||||
pageBuilder.declarePosition();
|
||||
if (returnFlagBlock.isNull(position)) {
|
||||
pageBuilder.getBlockBuilder(0).appendNull();
|
||||
}
|
||||
else {
|
||||
VARCHAR.appendTo(returnFlagBlock, position, pageBuilder.getBlockBuilder(0));
|
||||
}
|
||||
if (lineStatusBlock.isNull(position)) {
|
||||
pageBuilder.getBlockBuilder(1).appendNull();
|
||||
}
|
||||
else {
|
||||
VARCHAR.appendTo(lineStatusBlock, position, pageBuilder.getBlockBuilder(1));
|
||||
}
|
||||
|
||||
long quantity = BIGINT.getLong(quantityBlock, position);
|
||||
double extendedPrice = DOUBLE.getDouble(extendedPriceBlock, position);
|
||||
double discount = DOUBLE.getDouble(discountBlock, position);
|
||||
double tax = DOUBLE.getDouble(taxBlock, position);
|
||||
|
||||
boolean quantityIsNull = quantityBlock.isNull(position);
|
||||
boolean extendedPriceIsNull = extendedPriceBlock.isNull(position);
|
||||
boolean discountIsNull = discountBlock.isNull(position);
|
||||
boolean taxIsNull = taxBlock.isNull(position);
|
||||
|
||||
if (quantityIsNull) {
|
||||
pageBuilder.getBlockBuilder(2).appendNull();
|
||||
}
|
||||
else {
|
||||
BIGINT.writeLong(pageBuilder.getBlockBuilder(2), quantity);
|
||||
}
|
||||
|
||||
if (extendedPriceIsNull) {
|
||||
pageBuilder.getBlockBuilder(3).appendNull();
|
||||
}
|
||||
else {
|
||||
DOUBLE.writeDouble(pageBuilder.getBlockBuilder(3), extendedPrice);
|
||||
}
|
||||
|
||||
if (extendedPriceIsNull || discountIsNull) {
|
||||
pageBuilder.getBlockBuilder(4).appendNull();
|
||||
}
|
||||
else {
|
||||
DOUBLE.writeDouble(pageBuilder.getBlockBuilder(4), extendedPrice * (1 - discount));
|
||||
}
|
||||
|
||||
if (extendedPriceIsNull || discountIsNull || taxIsNull) {
|
||||
pageBuilder.getBlockBuilder(5).appendNull();
|
||||
}
|
||||
else {
|
||||
DOUBLE.writeDouble(pageBuilder.getBlockBuilder(5), extendedPrice * (1 - discount) * (1 + tax));
|
||||
}
|
||||
|
||||
if (discountIsNull) {
|
||||
pageBuilder.getBlockBuilder(6).appendNull();
|
||||
}
|
||||
else {
|
||||
DOUBLE.writeDouble(pageBuilder.getBlockBuilder(6), discount);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
new HandTpchQuery1(createLocalQueryRunner()).runBenchmark(new SimpleLineBenchmarkResultWriter(System.out));
|
||||
}
|
||||
}
|
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.benchmark;
|
||||
|
||||
import com.facebook.presto.operator.AggregationOperator.AggregationOperatorFactory;
|
||||
import com.facebook.presto.operator.FilterAndProjectOperator;
|
||||
import com.facebook.presto.operator.OperatorFactory;
|
||||
import com.facebook.presto.operator.PageProcessor;
|
||||
import com.facebook.presto.spi.ConnectorSession;
|
||||
import com.facebook.presto.spi.Page;
|
||||
import com.facebook.presto.spi.PageBuilder;
|
||||
import com.facebook.presto.spi.block.Block;
|
||||
import com.facebook.presto.spi.type.Type;
|
||||
import com.facebook.presto.sql.planner.plan.AggregationNode.Step;
|
||||
import com.facebook.presto.testing.LocalQueryRunner;
|
||||
import com.facebook.presto.util.DateTimeUtils;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import static com.facebook.presto.benchmark.BenchmarkQueryRunner.createLocalQueryRunner;
|
||||
import static com.facebook.presto.operator.aggregation.DoubleSumAggregation.DOUBLE_SUM;
|
||||
import static com.facebook.presto.spi.type.BigintType.BIGINT;
|
||||
import static com.facebook.presto.spi.type.DateType.DATE;
|
||||
import static com.facebook.presto.spi.type.DoubleType.DOUBLE;
|
||||
|
||||
public class HandTpchQuery6
|
||||
extends AbstractSimpleOperatorBenchmark
|
||||
{
|
||||
public HandTpchQuery6(LocalQueryRunner localQueryRunner)
|
||||
{
|
||||
super(localQueryRunner, "hand_tpch_query_6", 10, 100);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<? extends OperatorFactory> createOperatorFactories()
|
||||
{
|
||||
// select sum(extendedprice * discount) as revenue
|
||||
// from lineitem
|
||||
// where shipdate >= '1994-01-01'
|
||||
// and shipdate < '1995-01-01'
|
||||
// and discount >= 0.05
|
||||
// and discount <= 0.07
|
||||
// and quantity < 24;
|
||||
OperatorFactory tableScanOperator = createTableScanOperator(0, "lineitem", "extendedprice", "discount", "shipdate", "quantity");
|
||||
|
||||
FilterAndProjectOperator.FilterAndProjectOperatorFactory tpchQuery6Operator = new FilterAndProjectOperator.FilterAndProjectOperatorFactory(1, new TpchQuery6Processor(), ImmutableList.<Type>of(DOUBLE));
|
||||
|
||||
AggregationOperatorFactory aggregationOperator = new AggregationOperatorFactory(
|
||||
2,
|
||||
Step.SINGLE,
|
||||
ImmutableList.of(
|
||||
DOUBLE_SUM.bind(ImmutableList.of(0), Optional.empty(), Optional.empty(), 1.0)
|
||||
));
|
||||
|
||||
return ImmutableList.of(tableScanOperator, tpchQuery6Operator, aggregationOperator);
|
||||
}
|
||||
|
||||
public static class TpchQuery6Processor
|
||||
implements PageProcessor
|
||||
{
|
||||
private static final int MIN_SHIP_DATE = DateTimeUtils.parseDate("1994-01-01");
|
||||
private static final int MAX_SHIP_DATE = DateTimeUtils.parseDate("1995-01-01");
|
||||
|
||||
@Override
|
||||
public int process(ConnectorSession session, Page page, int start, int end, PageBuilder pageBuilder)
|
||||
{
|
||||
Block discountBlock = page.getBlock(1);
|
||||
int position = start;
|
||||
for (; position < end; position++) {
|
||||
// where shipdate >= '1994-01-01'
|
||||
// and shipdate < '1995-01-01'
|
||||
// and discount >= 0.05
|
||||
// and discount <= 0.07
|
||||
// and quantity < 24;
|
||||
if (filter(position, discountBlock, page.getBlock(2), page.getBlock(3))) {
|
||||
project(position, pageBuilder, page.getBlock(0), discountBlock);
|
||||
}
|
||||
}
|
||||
return position;
|
||||
}
|
||||
|
||||
private static void project(int position, PageBuilder pageBuilder, Block extendedPriceBlock, Block discountBlock)
|
||||
{
|
||||
if (discountBlock.isNull(position) || extendedPriceBlock.isNull(position)) {
|
||||
pageBuilder.getBlockBuilder(0).appendNull();
|
||||
}
|
||||
else {
|
||||
DOUBLE.writeDouble(pageBuilder.getBlockBuilder(0), DOUBLE.getDouble(extendedPriceBlock, position) * DOUBLE.getDouble(discountBlock, position));
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean filter(int position, Block discountBlock, Block shipDateBlock, Block quantityBlock)
|
||||
{
|
||||
return !shipDateBlock.isNull(position) && DATE.getLong(shipDateBlock, position) >= MIN_SHIP_DATE &&
|
||||
!shipDateBlock.isNull(position) && DATE.getLong(shipDateBlock, position) < MAX_SHIP_DATE &&
|
||||
!discountBlock.isNull(position) && DOUBLE.getDouble(discountBlock, position) >= 0.05 &&
|
||||
!discountBlock.isNull(position) && DOUBLE.getDouble(discountBlock, position) <= 0.07 &&
|
||||
!quantityBlock.isNull(position) && BIGINT.getLong(quantityBlock, position) < 24;
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
new HandTpchQuery6(createLocalQueryRunner()).runBenchmark(new SimpleLineBenchmarkResultWriter(System.out));
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.facebook.presto.benchmark;
|
||||
|
||||
import com.facebook.presto.operator.HashAggregationOperator.HashAggregationOperatorFactory;
|
||||
import com.facebook.presto.operator.OperatorFactory;
|
||||
import com.facebook.presto.spi.type.Type;
|
||||
import com.facebook.presto.sql.planner.plan.AggregationNode.Step;
|
||||
import com.facebook.presto.testing.LocalQueryRunner;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.primitives.Ints;
|
||||
import io.airlift.units.DataSize;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import static com.facebook.presto.benchmark.BenchmarkQueryRunner.createLocalQueryRunner;
|
||||
import static com.facebook.presto.operator.aggregation.DoubleSumAggregation.DOUBLE_SUM;
|
||||
import static io.airlift.units.DataSize.Unit.MEGABYTE;
|
||||
|
||||
public class HashAggregationBenchmark
|
||||
extends AbstractSimpleOperatorBenchmark
|
||||
{
|
||||
public HashAggregationBenchmark(LocalQueryRunner localQueryRunner)
|
||||
{
|
||||
super(localQueryRunner, "hash_agg", 5, 25);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<? extends OperatorFactory> createOperatorFactories()
|
||||
{
|
||||
OperatorFactory tableScanOperator = createTableScanOperator(0, "orders", "orderstatus", "totalprice");
|
||||
List<Type> types = ImmutableList.of(tableScanOperator.getTypes().get(0));
|
||||
HashAggregationOperatorFactory aggregationOperator = new HashAggregationOperatorFactory(1,
|
||||
types,
|
||||
Ints.asList(0),
|
||||
Step.SINGLE,
|
||||
ImmutableList.of(DOUBLE_SUM.bind(ImmutableList.of(1), Optional.empty(), Optional.empty(), 1.0)),
|
||||
Optional.empty(),
|
||||
Optional.empty(),
|
||||
100_000,
|
||||
new DataSize(16, MEGABYTE));
|
||||
return ImmutableList.of(tableScanOperator, aggregationOperator);
|
||||
}
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
new HashAggregationBenchmark(createLocalQueryRunner()).runBenchmark(new SimpleLineBenchmarkResultWriter(System.out));
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue