diff --git a/README.md b/README.md
new file mode 100644
index 0000000..483eb95
--- /dev/null
+++ b/README.md
@@ -0,0 +1,31 @@
+# Presto OraclePlugin
+
+This is a plugin for Presto(ver. 0.231.1.) that allow you to use Oracle Jdbc Connection
+
+[![Presto-Connectors Member](https://img.shields.io/badge/presto--connectors-member-green.svg)](http://presto-connectors.ml)
+
+## Connection Configuration
+
+Create new properties file inside etc/catalog dir:
+
+ connector.name=oracle
+ # connection-url must me the URL to access Oracle via JDBC. It can be different depending on your environment.
+ # Another example of the URL would be jdbc:oracle:thin:@//ip:port/database. For more information, please go to the JDBC driver docs
+ connection-url=jdbc:oracle:thin://ip:port/database
+ connection-user=myuser
+ connection-password=
+
+Create a dir inside plugin dir called oracle. To make it easier you could copy mysql dir to oracle and remove the mysql-connector and prestodb-mysql jars. Finally put the prestodb-oracle in plugin/oracle folder. Here is the sptes:
+
+ cd $PRESTODB_HOME
+ cp -r plugin/mysql plugin/oracle
+ rm plugin/oracle/mysql-connector*
+ rm plugin/oracle/presto-mysql*
+ mv /home/Downloads/presto-oracle*.jar plugin/oracle
+
+## Building Presto Oracle JDBC Plugin
+
+ mvn clean install
+
+## Building Oracle Driver
+Oracle Driver is not available in common repositories, so you will need to download it from Oracle and install manually in your repository.
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..a27f8aa
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,381 @@
+
+
+ 4.0.0
+
+ 0.231.1
+
+ ml.prestoconnectors
+ presto-oracle
+ Presto - Oracle Connector
+ jar
+
+
+
+ marcelopaesrech
+ https://github.com/marcelopaesrech
+
+
+ jmrozanec
+ https://github.com/marcelopaesrech
+
+
+
+
+ https://github.com/marcelopaesrech/presto-oracle/issues
+ GitHub Issues
+
+
+
+ https://github.com/marcelopaesrech/presto-oracle
+ scm:git:git@github.com:marcelopaesrech/presto-oracle.git
+ scm:git:git@github.com:marcelopaesrech/presto-oracle.git
+ HEAD
+
+
+
+ UTF-8
+ UTF-8
+ UTF-8
+ 0.231.1
+ 1.3
+ 0.36
+ 0.189
+
+ 6.10
+ 2.9.10
+
+
+
+
+ ossrh
+ Release Repository
+ https://oss.sonatype.org/service/local/staging/deploy/maven2/
+
+
+ ossrh
+ Snapshots Repository
+ https://oss.sonatype.org/content/repositories/snapshots/
+
+
+
+
+
+
+
+ com.facebook.presto
+ presto-base-jdbc
+ ${dep.presto.version}
+
+
+
+ io.airlift
+ units
+ ${dep.airlift.version}
+
+
+
+ io.airlift
+ configuration
+ ${dep.airlift.config.version}
+
+
+
+ javax.validation
+ validation-api
+ 1.1.0.Final
+
+
+
+ log4j
+ log4j
+ 1.2.17
+
+
+
+
+ com.oracle
+ ojdbc8
+ 12.2.0.1.0
+
+
+
+
+ com.facebook.presto
+ presto-spi
+ ${dep.presto.version}
+ provided
+
+
+
+ io.airlift
+ slice
+ ${dep.slice.version}
+ provided
+
+
+
+ javax.inject
+ javax.inject
+ 1
+ provided
+
+
+
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+ 2.6.0-rc2
+ provided
+
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.6.0-rc2
+ provided
+
+
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ 5.4.2
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ 5.4.2
+ test
+
+
+
+ org.testng
+ testng
+ ${dep.testng.version}
+ test
+
+
+
+ com.facebook.airlift
+ testing
+ 0.187
+ test
+
+
+
+ com.facebook.airlift
+ json
+ 0.187
+ test
+
+
+
+ com.fasterxml.jackson.core
+ jackson-core
+ ${dep.jackson.version}
+ test
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ ${dep.jackson.version}
+ test
+
+
+
+ com.facebook.presto
+ presto-main
+ ${dep.presto.version}
+ test
+
+
+
+ com.facebook.presto
+ presto-main
+ ${dep.presto.version}
+ test
+ test-jar
+
+
+
+ com.facebook.presto
+ presto-tests
+ ${dep.presto.version}
+ test
+
+
+
+ com.facebook.presto
+ presto-parser
+ ${dep.presto.version}
+ test
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.1
+
+
+ 1.8
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+ 2.2.1
+
+
+ attach-sources
+
+ jar
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-clean-plugin
+ 2.5
+
+
+ org.apache.maven.plugins
+ maven-install-plugin
+ 2.5.1
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 2.4
+
+
+ org.apache.maven.plugins
+ maven-resources-plugin
+ 2.6
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+ 2.9.1
+
+
+ attach-javadocs
+
+ jar
+
+
+
+
+
+ org.codehaus.mojo
+ sonar-maven-plugin
+ 1.0
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 2.17
+
+
+ org.apache.maven.plugins
+ maven-deploy-plugin
+ 2.8.1
+
+
+ org.sonatype.plugins
+ nexus-staging-maven-plugin
+ 1.6.2
+ true
+
+ ossrh
+ https://oss.sonatype.org/
+ true
+
+
+
+ org.codehaus.mojo
+ findbugs-maven-plugin
+ 2.5.3
+
+
+ org.codehaus.mojo
+ clirr-maven-plugin
+ 2.6.1
+
+
+ org.codehaus.mojo
+ versions-maven-plugin
+ 2.1
+
+
+
+
+
+
+ org.apache.maven.wagon
+ wagon-webdav
+ 1.0-beta-2
+
+
+
+
+
+
+ release-sign-artifacts
+
+
+ performRelease
+ true
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-gpg-plugin
+ 1.5
+
+
+ sign-artifacts
+ verify
+
+ sign
+
+
+
+
+
+
+
+
+ ci
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+
+
+
+
+
+
+
diff --git a/src/checkstyle/checks.xml b/src/checkstyle/checks.xml
new file mode 100644
index 0000000..b8b20be
--- /dev/null
+++ b/src/checkstyle/checks.xml
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/com/facebook/presto/plugin/oracle/OracleClient.java b/src/main/java/com/facebook/presto/plugin/oracle/OracleClient.java
new file mode 100644
index 0000000..7ac9f89
--- /dev/null
+++ b/src/main/java/com/facebook/presto/plugin/oracle/OracleClient.java
@@ -0,0 +1,133 @@
+/*
+ * 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.oracle;
+
+import com.facebook.presto.plugin.jdbc.*;
+import com.facebook.presto.spi.ConnectorSession;
+import com.facebook.presto.spi.PrestoException;
+import com.facebook.presto.spi.type.Decimals;
+import com.google.common.collect.ImmutableSet;
+import oracle.jdbc.OracleDriver;
+import org.apache.log4j.Logger;
+
+import javax.inject.Inject;
+import java.sql.*;
+import java.util.*;
+
+import static com.facebook.presto.plugin.jdbc.DriverConnectionFactory.basicConnectionProperties;
+import static com.facebook.presto.plugin.jdbc.StandardReadMappings.decimalReadMapping;
+import static com.facebook.presto.spi.type.DecimalType.createDecimalType;
+import static java.lang.Math.max;
+
+/**
+ * Implementation of OracleClient. It describes table, schemas and columns behaviours.
+ * It allows to change the QueryBuilder to a custom one as well.
+ *
+ * @author Marcelo Paes Rech
+ *
+ */
+public class OracleClient extends BaseJdbcClient {
+
+ private static final Logger log = Logger.getLogger(OracleClient.class);
+
+ public static List ignoreSchemas = Arrays.asList("anonymous", "olapsys", "sys", "system", "xdb", "xs$null");
+
+ private static ConnectionFactory connectionFactory(BaseJdbcConfig config, OracleConfig oracleConfig) {
+ Properties connectionProperties = basicConnectionProperties(config);
+ if (oracleConfig.getConnectionTimeout() != null) {
+ connectionProperties.setProperty("oracle.net.CONNECT_TIMEOUT", String.valueOf(oracleConfig.getConnectionTimeout().toMillis()));
+ }
+ return new DriverConnectionFactory(new OracleDriver(), config.getConnectionUrl(), connectionProperties);
+ }
+
+ @Inject
+ public OracleClient(JdbcConnectorId connectorId, BaseJdbcConfig config,
+ OracleConfig oracleConfig) throws SQLException {
+ super(connectorId, config, "", connectionFactory(config, oracleConfig));
+ }
+
+ @Override
+ protected Collection listSchemas(Connection connection) {
+ try {
+ ResultSet resultSet = connection.getMetaData().getSchemas();
+ Throwable t = null;
+ try {
+ ImmutableSet.Builder schemaNames = ImmutableSet.builder();
+ while (resultSet.next()) {
+ String schemaName = resultSet.getString(1).toLowerCase();
+ if (!ignoreSchemas.contains(schemaName)) {
+ schemaNames.add(schemaName);
+ }
+ }
+ return schemaNames.build();
+ } catch (Throwable e) {
+ t = e;
+ throw e;
+ } finally {
+ if (resultSet != null) {
+ if (t != null) {
+ try {
+ resultSet.close();
+ } catch (Throwable t2) {
+ t.addSuppressed(t2);
+ }
+ } else {
+ resultSet.close();
+ }
+ }
+
+ }
+ } catch (SQLException ex) {
+ throw new PrestoException(JdbcErrorCode.JDBC_ERROR, ex);
+ }
+ }
+
+ @Override
+ protected ResultSet getTables(Connection connection, Optional schemaName, Optional tableName)
+ throws SQLException {
+ // Here we put TABLE and SYNONYM when the table schema is another user schema
+ DatabaseMetaData metadata = connection.getMetaData();
+ Optional escape = Optional.ofNullable(metadata.getSearchStringEscape());
+ return metadata.getTables(
+ schemaName.orElse(null),
+ null,
+ escapeNamePattern(tableName, escape).orElse(null),
+ new String[] {"TABLE", "VIEW", "SYNONYM"});
+ }
+
+ @Override
+ public Optional toPrestoType(ConnectorSession session, JdbcTypeHandle type) {
+ Optional tp = super.toPrestoType(session, type);
+ if (!tp.isPresent()) {
+ int columnSize = type.getColumnSize();
+ switch (type.getJdbcType()) {
+ case Types.NUMERIC:
+ case Types.DECIMAL:
+ int decimalDigits = type.getDecimalDigits();
+ if (decimalDigits == -127) {
+ decimalDigits = 0;
+ columnSize = 22;
+ }
+ int precision = columnSize + max(-decimalDigits, 0); // Map decimal(p, -s) (negative scale) to decimal(p+s, 0).
+ if (precision > Decimals.MAX_PRECISION) {
+ return Optional.empty();
+ }
+ return Optional.of(decimalReadMapping(createDecimalType(precision, max(decimalDigits, 0))));
+ }
+ } else {
+ return tp;
+ }
+ return Optional.empty();
+ }
+}
diff --git a/src/main/java/com/facebook/presto/plugin/oracle/OracleClientModule.java b/src/main/java/com/facebook/presto/plugin/oracle/OracleClientModule.java
new file mode 100644
index 0000000..7d50d77
--- /dev/null
+++ b/src/main/java/com/facebook/presto/plugin/oracle/OracleClientModule.java
@@ -0,0 +1,54 @@
+/*
+ * 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.oracle;
+
+import com.facebook.airlift.configuration.AbstractConfigurationAwareModule;
+import com.facebook.presto.plugin.jdbc.BaseJdbcConfig;
+import com.facebook.presto.plugin.jdbc.JdbcClient;
+import com.google.inject.Binder;
+import com.google.inject.Scopes;
+import oracle.jdbc.OracleDriver;
+
+import java.sql.SQLException;
+
+import static com.facebook.airlift.configuration.ConfigBinder.configBinder;
+import static com.google.common.base.Preconditions.checkArgument;
+
+/**
+ * Guice implementation to create the correct DI and binds
+ *
+ * @author Marcelo Paes Rech
+ *
+ */
+public class OracleClientModule extends AbstractConfigurationAwareModule {
+ @Override
+ protected void setup(Binder binder)
+ {
+ binder.bind(JdbcClient.class).to(OracleClient.class).in(Scopes.SINGLETON);
+ ensureCatalogIsEmpty(buildConfigObject(BaseJdbcConfig.class).getConnectionUrl());
+ configBinder(binder).bindConfig(OracleConfig.class);
+ }
+
+ private static void ensureCatalogIsEmpty(String connectionUrl)
+ {
+ try {
+ OracleDriver driver = new OracleDriver();
+ boolean bAccept = driver.acceptsURL(connectionUrl);
+ checkArgument(bAccept, "Invalid JDBC URL for Oracle connector");
+ }
+ catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/src/main/java/com/facebook/presto/plugin/oracle/OracleConfig.java b/src/main/java/com/facebook/presto/plugin/oracle/OracleConfig.java
new file mode 100644
index 0000000..b809d61
--- /dev/null
+++ b/src/main/java/com/facebook/presto/plugin/oracle/OracleConfig.java
@@ -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.plugin.oracle;
+
+import com.facebook.airlift.configuration.Config;
+
+import io.airlift.units.Duration;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * To get the custom properties to connect to the database. User, password and
+ * URL is provided by de BaseJdbcClient is not required. If there is another
+ * custom configuration it should be put in here.
+ *
+ * @author Marcelo Paes Rech
+ *
+ */
+public class OracleConfig {
+ private Duration connectionTimeout = new Duration(10, TimeUnit.SECONDS);
+
+ public Duration getConnectionTimeout()
+ {
+ return connectionTimeout;
+ }
+
+ @Config("oracle.connection-timeout")
+ public OracleConfig setConnectionTimeout(Duration connectionTimeout)
+ {
+ this.connectionTimeout = connectionTimeout;
+ return this;
+ }
+}
diff --git a/src/main/java/com/facebook/presto/plugin/oracle/OraclePlugin.java b/src/main/java/com/facebook/presto/plugin/oracle/OraclePlugin.java
new file mode 100644
index 0000000..e9142a2
--- /dev/null
+++ b/src/main/java/com/facebook/presto/plugin/oracle/OraclePlugin.java
@@ -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.plugin.oracle;
+
+import com.facebook.presto.plugin.jdbc.JdbcPlugin;
+
+/**
+ * Initial class injected into PrestoDB via SPI.
+ *
+ * @author Marcelo Paes Recg
+ *
+ */
+public class OraclePlugin extends JdbcPlugin {
+
+ /**
+ * Oracle Plugin Constructor
+ */
+ public OraclePlugin() {
+ //name of the connector and the module implementation
+ super("oracle", new OracleClientModule());
+ }
+}
diff --git a/src/main/resources/META-INF/services/com.facebook.presto.spi.Plugin b/src/main/resources/META-INF/services/com.facebook.presto.spi.Plugin
new file mode 100644
index 0000000..bc3b358
--- /dev/null
+++ b/src/main/resources/META-INF/services/com.facebook.presto.spi.Plugin
@@ -0,0 +1 @@
+com.facebook.presto.plugin.oracle.OraclePlugin
\ No newline at end of file
diff --git a/src/test/java/com/facebook/presto/plugin/oracle/OracleClientModuleTest.java b/src/test/java/com/facebook/presto/plugin/oracle/OracleClientModuleTest.java
new file mode 100644
index 0000000..73cbfc1
--- /dev/null
+++ b/src/test/java/com/facebook/presto/plugin/oracle/OracleClientModuleTest.java
@@ -0,0 +1,75 @@
+package com.facebook.presto.plugin.oracle;
+
+import com.facebook.presto.plugin.jdbc.BaseJdbcConfig;
+import com.facebook.presto.plugin.jdbc.JdbcColumnHandle;
+import com.facebook.presto.plugin.jdbc.JdbcConnectorId;
+import com.facebook.presto.plugin.jdbc.JdbcIdentity;
+import com.facebook.presto.spi.ConnectorSession;
+import com.facebook.presto.spi.SchemaTableName;
+import com.google.common.collect.ImmutableSet;
+import oracle.jdbc.OracleDriver;
+import org.apache.log4j.Logger;
+import org.junit.jupiter.api.Test;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.List;
+import java.util.Set;
+import static com.facebook.presto.testing.TestingSession.testSessionBuilder;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class OracleClientModuleTest {
+ private static final Logger log = Logger.getLogger(OracleClientModuleTest.class);
+ private static final ConnectorSession session = testSessionBuilder().build().toConnectorSession();
+
+ public static final String CONNECTOR_ID = "test";
+
+ @Test
+ public void connectUrlTest() throws SQLException {
+ String connectionUrl = "jdbc:oracle:thin:@//10.18.20.180:1521/MUDATA";
+ OracleDriver driver = new OracleDriver();
+ assertTrue(driver.acceptsURL(connectionUrl));
+ }
+
+ @Test
+ public void listSchemasTest() throws SQLException, ClassNotFoundException {
+ String connectionUrl = "jdbc:oracle:thin:@//10.18.20.180:1521/MUDATA";
+ Class.forName("oracle.jdbc.OracleDriver");
+ Connection connection =
+ DriverManager.getConnection(connectionUrl, "md_flight", "MD_FLIGHT_2018");
+ try (ResultSet resultSet = connection.getMetaData().getSchemas()) {
+ ImmutableSet.Builder schemaNames = ImmutableSet.builder();
+ while (resultSet.next()) {
+ String schemaName = resultSet.getString(1).toLowerCase();
+ log.info("Listing schemas: " + schemaName);
+ schemaNames.add(schemaName);
+ }
+ }
+ catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ log.info("end.");
+ }
+
+ @Test
+ public void getColumnsTest() throws SQLException, ClassNotFoundException {
+ String connectionUrl = "jdbc:oracle:thin:@//10.18.20.180:1521/MUDATA";
+ Class.forName("oracle.jdbc.OracleDriver");
+ JdbcConnectorId connectorId = new JdbcConnectorId(CONNECTOR_ID);
+ BaseJdbcConfig config = new BaseJdbcConfig();
+ config.setConnectionUrl(connectionUrl);
+ config.setConnectionUser("MD_BOOKING");
+ config.setConnectionPassword("MD_BOOKING_2019");
+ OracleConfig oracleConfig = new OracleConfig();
+ OracleClient client = new OracleClient(connectorId, config, oracleConfig);
+
+ List columns = client.getColumns(session,
+ client.getTableHandle(JdbcIdentity.from(session),
+ new SchemaTableName("md_booking", "t07_pass_load_factor")));
+ columns.forEach(c -> log.info(String.format("%s.%s", c.getColumnName(), c.getColumnType().toString())));
+ log.info("end.");
+ }
+}
\ No newline at end of file
diff --git a/src/test/resources/log4j.properties b/src/test/resources/log4j.properties
new file mode 100644
index 0000000..38f3c66
--- /dev/null
+++ b/src/test/resources/log4j.properties
@@ -0,0 +1,4 @@
+log4j.rootLogger=DEBUG, consoleAppender
+log4j.appender.consoleAppender=org.apache.log4j.ConsoleAppender
+log4j.appender.consoleAppender.layout=org.apache.log4j.PatternLayout
+log4j.appender.consoleAppender.layout.ConversionPattern=[%t] %-5p %c %x - %m%n
\ No newline at end of file