From db3a28953779337e6972c1ce416602140382160a Mon Sep 17 00:00:00 2001 From: Sergii Puliaiev Date: Wed, 21 Oct 2020 14:14:46 -0700 Subject: [PATCH 1/2] 1) Support of logging to custom domains 2) Support of HTTP insecure mode 3) Support of Client connection field 4) Bump to API version 50.0 --- README.md | 5 +- pom.xml | 466 +++++++++--------- .../ascendix/jdbc/salesforce/ForceDriver.java | 47 +- .../connection/ForceConnection.java | 24 +- .../connection/ForceConnectionInfo.java | 4 + .../salesforce/connection/ForceService.java | 43 +- .../jdbc/salesforce/ForceDriverTest.java | 22 +- 7 files changed, 337 insertions(+), 274 deletions(-) diff --git a/README.md b/README.md index d7764d0..46b917b 100644 --- a/README.md +++ b/README.md @@ -64,12 +64,15 @@ jdbc:ascendix:salesforce://;sessionId=uniqueIdAssociatedWithTheSession | _password_ |Login password associated with the specified username.
**Warning!** A password provided should contains your password and secret key joined in one string.| | _sessionId_ | Unique ID associated with this session. | | _loginDomain_ | Top-level domain for a login request.
Default value is _login.salesforce.com_.
Set _test.salesforce.com_ value to use sandbox. | +| _https_ | Switch to use HTTP protocol instead of HTTPS
Default value is _true_| +| _api_ | Api version to use.
Default value is _50.0_.
Set _test.salesforce.com_ value to use sandbox. | +| _client_ | Client Id to use.
Default value is empty. | ## Supported features 1. Queries support native SOQL; 2. Nested queries are supported; -3. Request caching support on local drive. Canching supports 2 modes: global and session. Global mode means that the cached result will be accessible for all system users for certain JVM session. Session cache mode works for each Salesforce connection session separately. Both modes cache stores request result while JVM still running but no longer than for 1 hour. The cache mode can be enabled with a prefix of SOQL query. How to use: +3. Request caching support on local drive. Caching supports 2 modes: global and session. Global mode means that the cached result will be accessible for all system users for certain JVM session. Session cache mode works for each Salesforce connection session separately. Both modes cache stores request result while JVM still running but no longer than for 1 hour. The cache mode can be enabled with a prefix of SOQL query. How to use: * Global cache mode: ```SQL CACHE GLOBAL SELECT Id, Name FROM Account diff --git a/pom.xml b/pom.xml index e70786f..f807b94 100644 --- a/pom.xml +++ b/pom.xml @@ -1,233 +1,233 @@ - - 4.0.0 - com.ascendix.salesforce - salesforce-jdbc - 1.2-SNAPSHOT - pom - - - sf-auth-client - sf-jdbc-driver - - - - 1.8 - 1.8 - UTF-8 - - 1.18.0 - 1.7.25 - 1.25.0 - 3.8 - 4.1 - - 4.12 - 1.3 - - 3.7.0 - 2.5 - 2.21.0 - 3.0.1 - 3.1.0 - 3.1.0 - 2.8.2 - 2.0 - 43.0.0 - 3.0.5 - 3.5.2 - 4.2 - 1.4.10-java7 - 2.4 - - - - - acx.com-maven-repo - default_url - - - - - - - org.projectlombok - lombok - ${lombok.version} - - - org.slf4j - slf4j-api - ${slf4j.version} - - - - com.google.oauth-client - google-oauth-client - ${google-oauth-client.version} - - - org.apache.httpcomponents - httpclient - - - - - com.google.http-client - google-http-client-jackson2 - ${google-oauth-client.version} - - - - com.ascendix.salesforce - sf-auth-client - ${project.parent.version} - - - - org.mule.tools - salesforce-soql-parser - ${salesforce-soql-parser.version} - - - com.force.api - force-partner-api - ${force-partner-api.version} - - - org.mapdb - mapdb - ${mapdb.version} - - - org.apache.commons - commons-lang3 - ${commons-lang3.version} - - - org.antlr - antlr - ${antlr.version} - - - org.apache.commons - commons-collections4 - ${commons-collections4.version} - - - org.apache.directory.studio - org.apache.commons.io - ${org.apache.commons.io.version} - - - - - junit - junit - ${junit.version} - test - - - com.opencsv - opencsv - ${opencsv.version} - test - - - com.thoughtworks.xstream - xstream - ${xstream.version} - test - - - - - - - org.projectlombok - lombok - provided - - - org.slf4j - slf4j-api - - - com.google.oauth-client - google-oauth-client - - - com.google.http-client - google-http-client-jackson2 - - - - - - mulesoft-releases - MuleSoft Releases Repository - http://repository.mulesoft.org/releases/ - default - - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - ${maven-compiler-plugin.version} - - - org.apache.maven.plugins - maven-surefire-plugin - ${maven-surefire-plugin.version} - - - org.apache.maven.plugins - maven-jar-plugin - ${maven-jar-plugin.version} - - - org.codehaus.mojo - versions-maven-plugin - ${versions-maven-plugin.version} - - - org.apache.maven.plugins - maven-assembly-plugin - ${maven-assembly-plugin.version} - - - org.apache.maven.plugins - maven-source-plugin - ${maven-source-plugin.version} - - - org.apache.maven.plugins - maven-deploy-plugin - ${maven-deploy-plugin.version} - - true - - - - - - - - org.apache.maven.plugins - maven-source-plugin - - - attach-sources - - jar - - - - - - - \ No newline at end of file + + 4.0.0 + com.ascendix.salesforce + salesforce-jdbc + 1.2-SNAPSHOT + pom + + + sf-auth-client + sf-jdbc-driver + + + + 1.8 + 1.8 + UTF-8 + + 1.18.0 + 1.7.25 + 1.25.0 + 3.8 + 4.1 + + 4.12 + 1.3 + + 3.7.0 + 2.5 + 2.21.0 + 3.0.1 + 3.1.0 + 3.1.0 + 2.8.2 + 2.0 + 50.0.0 + 3.0.5 + 3.5.2 + 4.2 + 1.4.6 + 2.4 + + + + + acx.com-maven-repo + default_url + + + + + + + org.projectlombok + lombok + ${lombok.version} + + + org.slf4j + slf4j-api + ${slf4j.version} + + + + com.google.oauth-client + google-oauth-client + ${google-oauth-client.version} + + + org.apache.httpcomponents + httpclient + + + + + com.google.http-client + google-http-client-jackson2 + ${google-oauth-client.version} + + + + com.ascendix.salesforce + sf-auth-client + ${project.parent.version} + + + + org.mule.tools + salesforce-soql-parser + ${salesforce-soql-parser.version} + + + com.force.api + force-partner-api + ${force-partner-api.version} + + + org.mapdb + mapdb + ${mapdb.version} + + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + + + org.antlr + antlr + ${antlr.version} + + + org.apache.commons + commons-collections4 + ${commons-collections4.version} + + + org.apache.directory.studio + org.apache.commons.io + ${org.apache.commons.io.version} + + + + + junit + junit + ${junit.version} + test + + + com.opencsv + opencsv + ${opencsv.version} + test + + + com.thoughtworks.xstream + xstream + ${xstream.version} + test + + + + + + + org.projectlombok + lombok + provided + + + org.slf4j + slf4j-api + + + com.google.oauth-client + google-oauth-client + + + com.google.http-client + google-http-client-jackson2 + + + + + + mulesoft-releases + MuleSoft Releases Repository + http://repository.mulesoft.org/releases/ + default + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + + org.apache.maven.plugins + maven-surefire-plugin + ${maven-surefire-plugin.version} + + + org.apache.maven.plugins + maven-jar-plugin + ${maven-jar-plugin.version} + + + org.codehaus.mojo + versions-maven-plugin + ${versions-maven-plugin.version} + + + org.apache.maven.plugins + maven-assembly-plugin + ${maven-assembly-plugin.version} + + + org.apache.maven.plugins + maven-source-plugin + ${maven-source-plugin.version} + + + org.apache.maven.plugins + maven-deploy-plugin + ${maven-deploy-plugin.version} + + true + + + + + + + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + + jar + + + + + + + diff --git a/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/ForceDriver.java b/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/ForceDriver.java index 8cbc6d7..50b5120 100644 --- a/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/ForceDriver.java +++ b/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/ForceDriver.java @@ -28,7 +28,8 @@ public class ForceDriver implements Driver { private static final String ACCEPTABLE_URL = "jdbc:ascendix:salesforce"; private static final Pattern URL_PATTERN = Pattern.compile("\\A" + ACCEPTABLE_URL + "://(.*)"); - private static final Pattern URL_HAS_AUTHORIZATION_SEGMENT = Pattern.compile("\\A" + ACCEPTABLE_URL + "://([^:]+):([^@]+)@.*"); + private static final Pattern URL_HAS_AUTHORIZATION_SEGMENT = Pattern.compile("\\A" + ACCEPTABLE_URL + "://([^:]+):([^@]+)@([^?]*)([?](.*))?"); + private static final Pattern PARAM_STANDARD_PATTERN = Pattern.compile("(([^=]+)=([^&]*)&?)"); static { try { @@ -55,9 +56,13 @@ public Connection connect(String url, Properties properties) throws SQLException properties.putAll(connStringProps); ForceConnectionInfo info = new ForceConnectionInfo(); info.setUserName(properties.getProperty("user")); + info.setClientName(properties.getProperty("client")); info.setPassword(properties.getProperty("password")); info.setSessionId(properties.getProperty("sessionId")); info.setSandbox(resolveSandboxProperty(properties)); + info.setHttps(resolveBooleanProperty(properties, "https", true)); + info.setApiVersion(resolveStringProperty(properties, "api", ForceService.DEFAULT_API_VERSION)); + info.setLoginDomain(resolveStringProperty(properties, "loginDomain", ForceService.DEFAULT_LOGIN_DOMAIN)); PartnerConnection partnerConnection = ForceService.createPartnerConnection(info); return new ForceConnection(partnerConnection); @@ -78,16 +83,46 @@ private static Boolean resolveSandboxProperty(Properties properties) { return null; } + private static Boolean resolveBooleanProperty(Properties properties, String propertyName, boolean defaultValue) { + String boolValue = properties.getProperty(propertyName); + if (boolValue != null) { + return Boolean.valueOf(boolValue); + } + return defaultValue; + } + + private static String resolveStringProperty(Properties properties, String propertyName, String defaultValue) { + String boolValue = properties.getProperty(propertyName); + if (boolValue != null) { + return boolValue; + } + return defaultValue; + } - protected Properties getConnStringProperties(String url) throws IOException { + + protected Properties getConnStringProperties(String urlString) throws IOException { Properties result = new Properties(); String urlProperties = null; - Matcher stdMatcher = URL_PATTERN.matcher(url); - Matcher authMatcher = URL_HAS_AUTHORIZATION_SEGMENT.matcher(url); - + Matcher stdMatcher = URL_PATTERN.matcher(urlString); + Matcher authMatcher = URL_HAS_AUTHORIZATION_SEGMENT.matcher(urlString); + if (authMatcher.matches()) { - urlProperties = "user=" + authMatcher.group(1) + "\npassword=" + authMatcher.group(2); + result.put("user", authMatcher.group(1)); + result.put("password", authMatcher.group(2)); + result.put("loginDomain", authMatcher.group(3)); + if (authMatcher.groupCount() > 4 && authMatcher.group(5) != null) { + // has some other parameters - parse them from standard URL format like + // ?param1=value1¶m2=value2 + String parameters = authMatcher.group(5); + Matcher matcher = PARAM_STANDARD_PATTERN.matcher(parameters); + while(matcher.find()) { + String param = matcher.group(2); + String value = 3 >= matcher.groupCount() ? matcher.group(3) : null; + result.put(param, value); + } + + } } else if (stdMatcher.matches()) { urlProperties = stdMatcher.group(1); urlProperties = urlProperties.replaceAll(";", "\n"); diff --git a/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/connection/ForceConnection.java b/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/connection/ForceConnection.java index 71ddebf..0fe589f 100644 --- a/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/connection/ForceConnection.java +++ b/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/connection/ForceConnection.java @@ -30,8 +30,10 @@ public class ForceConnection implements Connection { private final PartnerConnection partnerConnection; private final DatabaseMetaData metadata; private static final String SF_JDBC_DRIVER_NAME = "SF JDBC driver"; + private static final Logger logger = Logger.getLogger(SF_JDBC_DRIVER_NAME); private Map connectionCache = new HashMap<>(); + Properties clientInfo = new Properties(); public ForceConnection(PartnerConnection partnerConnection) { this.partnerConnection = partnerConnection; @@ -74,20 +76,19 @@ public boolean isWrapperFor(Class iface) { @Override public Statement createStatement() { - Logger.getLogger(SF_JDBC_DRIVER_NAME) - .info(Object.class.getEnclosingMethod().getName()); + logger.info("[Conn] createStatement 1 IMPLEMENTED "); return null; } @Override public CallableStatement prepareCall(String sql) { - Logger.getLogger(SF_JDBC_DRIVER_NAME).info(Object.class.getEnclosingMethod().getName()); + logger.info("[Conn] prepareCall NOT_IMPLEMENTED "+sql); return null; } @Override public String nativeSQL(String sql) { - Logger.getLogger(SF_JDBC_DRIVER_NAME).info(Object.class.getEnclosingMethod().getName()); + logger.info("[Conn] nativeSQL NOT_IMPLEMENTED "+sql); return null; } @@ -314,25 +315,26 @@ public boolean isValid(int timeout) throws SQLException { @Override public void setClientInfo(String name, String value) throws SQLClientInfoException { // TODO Auto-generated method stub - + logger.info("[Conn] setClientInfo 1 IMPLEMENTED "+name+"="+value); + clientInfo.setProperty(name, value); } @Override public void setClientInfo(Properties properties) throws SQLClientInfoException { - // TODO Auto-generated method stub - + logger.info("[Conn] setClientInfo 2 IMPLEMENTED properties<>"); + properties.stringPropertyNames().forEach(propName -> clientInfo.setProperty(propName, properties.getProperty(propName))); } @Override public String getClientInfo(String name) throws SQLException { - // TODO Auto-generated method stub - return null; + logger.info("[Conn] getClientInfo 1 IMPLEMENTED for '"+name+"'"); + return clientInfo.getProperty(name); } @Override public Properties getClientInfo() throws SQLException { - // TODO Auto-generated method stub - return null; + logger.info("[Conn] getClientInfo 2 IMPLEMENTED "); + return clientInfo; } @Override diff --git a/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/connection/ForceConnectionInfo.java b/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/connection/ForceConnectionInfo.java index cd666e0..c9c8002 100644 --- a/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/connection/ForceConnectionInfo.java +++ b/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/connection/ForceConnectionInfo.java @@ -11,4 +11,8 @@ public class ForceConnectionInfo { private String password; private String sessionId; private Boolean sandbox; + private Boolean https = true; + private String apiVersion = ForceService.DEFAULT_API_VERSION; + private String loginDomain; + private String clientName; } diff --git a/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/connection/ForceService.java b/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/connection/ForceService.java index 5e1c94c..cc07f38 100644 --- a/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/connection/ForceService.java +++ b/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/connection/ForceService.java @@ -8,6 +8,7 @@ import lombok.experimental.UtilityClass; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.StringUtils; import org.mapdb.DB; import org.mapdb.DBMaker; import org.mapdb.HTreeMap; @@ -19,11 +20,11 @@ @Slf4j public class ForceService { - private static final String DEFAULT_LOGIN_DOMAIN = "login.salesforce.com"; + public static final String DEFAULT_LOGIN_DOMAIN = "login.salesforce.com"; private static final String SANDBOX_LOGIN_DOMAIN = "test.salesforce.com"; private static final long CONNECTION_TIMEOUT = TimeUnit.SECONDS.toMillis(10); private static final long READ_TIMEOUT = TimeUnit.SECONDS.toMillis(30); - private static final String DEFAULT_API_VERSION = "43.0"; + public static final String DEFAULT_API_VERSION = "50.0"; public static final int EXPIRE_AFTER_CREATE = 60; public static final int EXPIRE_STORE_SIZE = 16; @@ -76,26 +77,32 @@ private static PartnerConnection createConnectionByUserCredential(ForceConnectio ConnectorConfig partnerConfig = new ConnectorConfig(); partnerConfig.setUsername(info.getUserName()); partnerConfig.setPassword(info.getPassword()); - if (info.getSandbox() != null) { - partnerConfig.setAuthEndpoint(buildAuthEndpoint(info.getSandbox())); - return Connector.newConnection(partnerConfig); - } - try { - partnerConfig.setAuthEndpoint(buildAuthEndpoint(false)); - return Connector.newConnection(partnerConfig); - } catch (ConnectionException ce) { - partnerConfig.setAuthEndpoint(buildAuthEndpoint(true)); - return Connector.newConnection(partnerConfig); - } - } + PartnerConnection connection; - private static String buildAuthEndpoint(boolean sandbox) { - if (sandbox) { - return String.format("https://%s/services/Soap/u/%s", SANDBOX_LOGIN_DOMAIN, DEFAULT_API_VERSION); + if (info.getSandbox() != null) { + partnerConfig.setAuthEndpoint(buildAuthEndpoint(info)); + connection = Connector.newConnection(partnerConfig); } else { - return String.format("https://%s/services/Soap/u/%s", DEFAULT_LOGIN_DOMAIN, DEFAULT_API_VERSION); + try { + info.setSandbox(false); + partnerConfig.setAuthEndpoint(buildAuthEndpoint(info)); + connection = Connector.newConnection(partnerConfig); + } catch (ConnectionException ce) { + info.setSandbox(true); + partnerConfig.setAuthEndpoint(buildAuthEndpoint(info)); + connection = Connector.newConnection(partnerConfig); + } + } + if (connection != null && StringUtils.isNotBlank(info.getClientName())) { + connection.setCallOptions(info.getClientName(), null); } + return connection; + } + private static String buildAuthEndpoint(ForceConnectionInfo info) { + String protocol = info.getHttps() ? "https" : "http"; + String domain = info.getSandbox() ? SANDBOX_LOGIN_DOMAIN : info.getLoginDomain() != null ? info.getLoginDomain() : DEFAULT_LOGIN_DOMAIN; + return String.format("%s://%s/services/Soap/u/%s", protocol, domain, info.getApiVersion()); } } diff --git a/sf-jdbc-driver/src/test/java/com/ascendix/jdbc/salesforce/ForceDriverTest.java b/sf-jdbc-driver/src/test/java/com/ascendix/jdbc/salesforce/ForceDriverTest.java index 7c68395..93b57d7 100644 --- a/sf-jdbc-driver/src/test/java/com/ascendix/jdbc/salesforce/ForceDriverTest.java +++ b/sf-jdbc-driver/src/test/java/com/ascendix/jdbc/salesforce/ForceDriverTest.java @@ -8,9 +8,7 @@ import java.sql.SQLException; import java.util.Properties; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; public class ForceDriverTest { @@ -49,10 +47,24 @@ public void testConnect_WhenWrongURL() throws SQLException { @Test public void testGetConnStringProperties_StandartUrlFormat() throws IOException { Properties actuals = driver.getConnStringProperties("jdbc:ascendix:salesforce://test@test.ru:aaaa!aaa@login.salesforce.ru"); - - assertEquals(2, actuals.size()); + + assertEquals(3, actuals.size()); + assertTrue(actuals.containsKey("user")); + assertEquals("test@test.ru", actuals.getProperty("user")); + assertEquals("aaaa!aaa", actuals.getProperty("password")); + assertEquals("login.salesforce.ru", actuals.getProperty("loginDomain")); + } + + @Test + public void testGetConnStringProperties_StandartUrlFormatHttpsApi() throws IOException { + Properties actuals = driver.getConnStringProperties("jdbc:ascendix:salesforce://test@test.ru:aaaa!aaa@login.salesforce.ru?https=false&api=48.0"); + + assertEquals(5, actuals.size()); assertTrue(actuals.containsKey("user")); assertEquals("test@test.ru", actuals.getProperty("user")); assertEquals("aaaa!aaa", actuals.getProperty("password")); + assertEquals("login.salesforce.ru", actuals.getProperty("loginDomain")); + assertEquals("false", actuals.getProperty("https")); + assertEquals("48.0", actuals.getProperty("api")); } } From 969d4dd04e7165f01049677ad18915439d4760ea Mon Sep 17 00:00:00 2001 From: Sergii Puliaiev Date: Wed, 21 Oct 2020 16:23:40 -0700 Subject: [PATCH 2/2] 1) Logging refactoring and more log information 2) Implementation of more query and metadata methods, used by IntelliJ for PreparedStatement 3) Implementation of Dummy Metadata evaluation for ResultSet (Needed for IntelliJ) 4) IgnoreCase for Table names and Column names (Needed for IntelliJ) --- .../ascendix/jdbc/salesforce/ForceDriver.java | 8 +- .../connection/ForceConnection.java | 56 +++-- .../salesforce/delegates/PartnerService.java | 13 +- .../jdbc/salesforce/metadata/ColumnMap.java | 17 ++ .../metadata/ForceDatabaseMetaData.java | 209 ++++++++++++----- .../salesforce/resultset/CachedResultSet.java | 8 + .../statement/ForcePreparedStatement.java | 218 ++++++++++++------ .../statement/SoqlQueryAnalyzer.java | 2 +- 8 files changed, 361 insertions(+), 170 deletions(-) diff --git a/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/ForceDriver.java b/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/ForceDriver.java index 50b5120..9d44fcb 100644 --- a/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/ForceDriver.java +++ b/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/ForceDriver.java @@ -26,6 +26,9 @@ @Slf4j public class ForceDriver implements Driver { + private static final String SF_JDBC_DRIVER_NAME = "SF JDBC driver"; + private static final Logger logger = Logger.getLogger(SF_JDBC_DRIVER_NAME); + private static final String ACCEPTABLE_URL = "jdbc:ascendix:salesforce"; private static final Pattern URL_PATTERN = Pattern.compile("\\A" + ACCEPTABLE_URL + "://(.*)"); private static final Pattern URL_HAS_AUTHORIZATION_SEGMENT = Pattern.compile("\\A" + ACCEPTABLE_URL + "://([^:]+):([^@]+)@([^?]*)([?](.*))?"); @@ -33,6 +36,7 @@ public class ForceDriver implements Driver { static { try { + logger.info("[ForceDriver] registration"); DriverManager.registerDriver(new ForceDriver()); } catch (Exception e) { throw new RuntimeException("Failed register ForceDriver: " + e.getMessage(), e); @@ -56,8 +60,8 @@ public Connection connect(String url, Properties properties) throws SQLException properties.putAll(connStringProps); ForceConnectionInfo info = new ForceConnectionInfo(); info.setUserName(properties.getProperty("user")); - info.setClientName(properties.getProperty("client")); info.setPassword(properties.getProperty("password")); + info.setClientName(properties.getProperty("client")); info.setSessionId(properties.getProperty("sessionId")); info.setSandbox(resolveSandboxProperty(properties)); info.setHttps(resolveBooleanProperty(properties, "https", true)); @@ -100,7 +104,7 @@ private static String resolveStringProperty(Properties properties, String proper } - protected Properties getConnStringProperties(String urlString) throws IOException { + protected static Properties getConnStringProperties(String urlString) throws IOException { Properties result = new Properties(); String urlProperties = null; diff --git a/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/connection/ForceConnection.java b/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/connection/ForceConnection.java index 0fe589f..751b216 100644 --- a/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/connection/ForceConnection.java +++ b/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/connection/ForceConnection.java @@ -50,6 +50,7 @@ public DatabaseMetaData getMetaData() { @Override public PreparedStatement prepareStatement(String soql) { + logger.info("[Conn] prepareStatement IMPLEMENTED "+soql); return new ForcePreparedStatement(this, soql); } @@ -77,7 +78,7 @@ public boolean isWrapperFor(Class iface) { @Override public Statement createStatement() { logger.info("[Conn] createStatement 1 IMPLEMENTED "); - return null; + return new ForcePreparedStatement(this); } @Override @@ -100,26 +101,22 @@ public void setAutoCommit(boolean autoCommit) { @Override public boolean getAutoCommit() throws SQLException { - // TODO Auto-generated method stub - return false; + return true; } @Override public void commit() throws SQLException { - // TODO Auto-generated method stub - + logger.info("[Conn] commit NOT_IMPLEMENTED "); } @Override public void rollback() throws SQLException { - // TODO Auto-generated method stub - + logger.info("[Conn] rollback NOT_IMPLEMENTED "); } @Override public void close() throws SQLException { - // TODO Auto-generated method stub - + logger.info("[Conn] close NOT_IMPLEMENTED "); } @Override @@ -143,13 +140,13 @@ public boolean isReadOnly() throws SQLException { @Override public void setCatalog(String catalog) throws SQLException { // TODO Auto-generated method stub - + logger.info("[Conn] setCatalog NOT_IMPLEMENTED set to '"+catalog+"'"); } @Override public String getCatalog() throws SQLException { - // TODO Auto-generated method stub - return null; + logger.info("[Conn] getCatalog IMPLEMENTED returning "+ForceDatabaseMetaData.DEFAULT_CATALOG); + return ForceDatabaseMetaData.DEFAULT_CATALOG; } @Override @@ -178,26 +175,26 @@ public void clearWarnings() throws SQLException { @Override public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { - Logger.getLogger(SF_JDBC_DRIVER_NAME).info(Object.class.getEnclosingMethod().getName()); - return null; + logger.info("[Conn] createStatement 2 IMPLEMENTED"); + return new ForcePreparedStatement(this); } @Override public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { - Logger.getLogger(SF_JDBC_DRIVER_NAME).info(Object.class.getEnclosingMethod().getName()); - return null; + logger.info("[Conn] prepareStatement 1 IMPLEMENTED "+sql); + return new ForcePreparedStatement(this, sql); } @Override public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { - Logger.getLogger(SF_JDBC_DRIVER_NAME).info(Object.class.getEnclosingMethod().getName()); + logger.info("[Conn] prepareCall NOT_IMPLEMENTED "+sql); return null; } @Override public Map> getTypeMap() throws SQLException { - Logger.getLogger(SF_JDBC_DRIVER_NAME).info(Object.class.getEnclosingMethod().getName()); + logger.info("[Conn] getTypeMap NOT_IMPLEMENTED "); return null; } @@ -233,52 +230,52 @@ public Savepoint setSavepoint(String name) throws SQLException { @Override public void rollback(Savepoint savepoint) throws SQLException { - // TODO Auto-generated method stub + logger.info("[Conn] rollback Savepoint NOT_IMPLEMENTED"); } @Override public void releaseSavepoint(Savepoint savepoint) throws SQLException { - // TODO Auto-generated method stub + logger.info("[Conn] releaseSavepoint NOT_IMPLEMENTED"); } @Override public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { - Logger.getLogger(SF_JDBC_DRIVER_NAME).info(Object.class.getEnclosingMethod().getName()); - return null; + logger.info("[Conn] createStatement 3 NOT_IMPLEMENTED"); + return new ForcePreparedStatement(this); } @Override public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { - Logger.getLogger(SF_JDBC_DRIVER_NAME).info(Object.class.getEnclosingMethod().getName()); + logger.info("[Conn] prepareStatement 2 NOT_IMPLEMENTED "+sql ); return null; } @Override public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { - Logger.getLogger(SF_JDBC_DRIVER_NAME).info(Object.class.getEnclosingMethod().getName()); + logger.info("[Conn] prepareCall 2 NOT_IMPLEMENTED "+sql ); return null; } @Override public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { - Logger.getLogger(SF_JDBC_DRIVER_NAME).info(Object.class.getEnclosingMethod().getName()); + logger.info("[Conn] prepareStatement 3 NOT_IMPLEMENTED "+sql ); return null; } @Override public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { - Logger.getLogger(SF_JDBC_DRIVER_NAME).info(Object.class.getEnclosingMethod().getName()); + logger.info("[Conn] prepareStatement 4 NOT_IMPLEMENTED "+sql ); return null; } @Override public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { - Logger.getLogger(SF_JDBC_DRIVER_NAME).info(Object.class.getEnclosingMethod().getName()); + logger.info("[Conn] prepareStatement 5 NOT_IMPLEMENTED "+sql ); return null; } @@ -309,7 +306,8 @@ public SQLXML createSQLXML() throws SQLException { @Override public boolean isValid(int timeout) throws SQLException { // TODO Auto-generated method stub - return false; + logger.info("[Conn] isValid NOT_IMPLEMENTED "); + return true; } @Override @@ -352,7 +350,7 @@ public Struct createStruct(String typeName, Object[] attributes) throws SQLExcep @Override public void setSchema(String schema) throws SQLException { // TODO Auto-generated method stub - + logger.info("[Conn] setSchema NOT_IMPLEMENTED "); } @Override diff --git a/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/delegates/PartnerService.java b/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/delegates/PartnerService.java index a13477d..2b53ff4 100644 --- a/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/delegates/PartnerService.java +++ b/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/delegates/PartnerService.java @@ -19,10 +19,14 @@ import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import java.util.logging.Logger; import java.util.stream.Collectors; public class PartnerService { + private static final String SF_JDBC_DRIVER_NAME = "SF JDBC driver"; + private static final Logger logger = Logger.getLogger(SF_JDBC_DRIVER_NAME); + private PartnerConnection partnerConnection; private List sObjectTypesCache; @@ -31,17 +35,22 @@ public PartnerService(PartnerConnection partnerConnection) { } public List getTables() { + logger.info("[PartnerService] getTables IMPLEMENTED "); List sObjects = getSObjectsDescription(); - return sObjects.stream() + List
tables = sObjects.stream() .map(this::convertToTable) .collect(Collectors.toList()); + logger.info("[PartnerService] getTables tables count="+tables.size()); + return tables; } public DescribeSObjectResult describeSObject(String sObjectType) throws ConnectionException { + logger.info("[PartnerService] describeSObject "+sObjectType); return partnerConnection.describeSObject(sObjectType); } private Table convertToTable(DescribeSObjectResult so) { + logger.info("[PartnerService] convertToTable "+so.getName()); List fields = Arrays.asList(so.getFields()); List columns = fields.stream() .map(this::convertToColumn) @@ -83,6 +92,7 @@ private List getSObjectTypes() throws ConnectionException { sObjectTypesCache = Arrays.stream(sobs) .map(DescribeGlobalSObjectResult::getName) .collect(Collectors.toList()); + logger.info("[PartnerService] getSObjectTypes count="+sObjectTypesCache.size()); } return sObjectTypesCache; @@ -127,6 +137,7 @@ private List> toBatches(List objects, int batchSize) { } public List query(String soql, List expectedSchema) throws ConnectionException { + logger.info("[PartnerService] query "+soql); List resultRows = Collections.synchronizedList(new LinkedList<>()); QueryResult queryResult = null; do { diff --git a/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/metadata/ColumnMap.java b/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/metadata/ColumnMap.java index 9a6a896..8dd213f 100644 --- a/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/metadata/ColumnMap.java +++ b/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/metadata/ColumnMap.java @@ -18,6 +18,11 @@ public V put(K key, V value) { return value; } + public ColumnMap add(K key, V value) { + put(key, value); + return this; + } + public V get(K key) { int index = columnNames.indexOf(key); return index != -1 ? values.get(index) : null; @@ -30,4 +35,16 @@ public V get(K key) { public V getByIndex(int index) { return values.get(index - 1); } + + public int size() { + return columnNames.size(); + } + + public ArrayList getColumnNames() { + return columnNames; + } + + public ArrayList getValues() { + return values; + } } diff --git a/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/metadata/ForceDatabaseMetaData.java b/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/metadata/ForceDatabaseMetaData.java index 62518ce..84b048d 100644 --- a/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/metadata/ForceDatabaseMetaData.java +++ b/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/metadata/ForceDatabaseMetaData.java @@ -3,6 +3,7 @@ import com.ascendix.jdbc.salesforce.connection.ForceConnection; import com.ascendix.jdbc.salesforce.delegates.PartnerService; import com.ascendix.jdbc.salesforce.resultset.CachedResultSet; +import com.ascendix.jdbc.salesforce.statement.ForcePreparedStatement; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.Pair; @@ -15,11 +16,18 @@ import java.sql.Types; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; +import java.util.logging.Logger; import java.util.stream.Collectors; public class ForceDatabaseMetaData implements DatabaseMetaData, Serializable { - private static final String DEFAULT_SCHEMA = "Salesforce"; + private static final String SF_JDBC_DRIVER_NAME = "SF JDBC driver"; + private static final Logger logger = Logger.getLogger(SF_JDBC_DRIVER_NAME); + + public static final String DEFAULT_SCHEMA = "Salesforce"; + public static final String DEFAULT_CATALOG = "database"; + public static final String DEFAULT_TABLE_TYPE = "TABLE"; + private transient PartnerService partnerService; private transient ForceConnection connection; private List
tablesCache; @@ -32,34 +40,46 @@ public ForceDatabaseMetaData(ForceConnection connection) { @Override public ResultSet getTables(String catalog, String schemaPattern, String tableNamePattern, String[] types) { - List> maps = new ArrayList<>(); + logger.info("[Meta] getTables catalog="+catalog+" schema="+schemaPattern+" table="+tableNamePattern); + List> rows = new ArrayList<>(); + ColumnMap firstRow = null; for (Table table : getTables()) { - ColumnMap map = new ColumnMap<>(); - map.put("TABLE_CAT", null); - map.put("TABLE_SCHEM", null); - map.put("TABLE_NAME", table.getName()); - map.put("TABLE_TYPE", "TABLE"); - map.put("REMARKS", table.getComments()); - map.put("TYPE_CAT", null); - map.put("TYPE_SCHEM", null); - map.put("TYPE_NAME", null); - map.put("SELF_REFERENCING_COL_NAME", null); - map.put("REF_GENERATION", null); - maps.add(map); + if(tableNamePattern == null || "%".equals(tableNamePattern.trim()) || table.getName().equalsIgnoreCase(tableNamePattern)) { + ColumnMap map = new ColumnMap<>(); + map.put("TABLE_CAT", DEFAULT_CATALOG); + map.put("TABLE_SCHEM", DEFAULT_SCHEMA); + map.put("TABLE_NAME", table.getName()); + map.put("TABLE_TYPE", DEFAULT_TABLE_TYPE); + map.put("REMARKS", table.getComments()); + map.put("TYPE_CAT", null); + map.put("TYPE_SCHEM", null); + map.put("TYPE_NAME", null); + map.put("SELF_REFERENCING_COL_NAME", null); + map.put("REF_GENERATION", null); + rows.add(map); + if (firstRow == null) { + firstRow = map; + } + } } - return new CachedResultSet(maps); + logger.info("[Meta] getTables RESULT catalog="+catalog+" schema="+schemaPattern+" table="+tableNamePattern+ + "\n firstRowFound="+(firstRow!=null?"yes":"no")+ " TablesFound="+rows.size()); + return new CachedResultSet(rows, ForcePreparedStatement.dummyMetaData(firstRow)); } private List
getTables() { if (tablesCache == null) { + logger.info("[Meta] getTables requested - fetching"); tablesCache = partnerService.getTables(); + } else { + logger.info("[Meta] getTables requested - from cache"); } return tablesCache; } public Table findTableInfo(String tableName) { return getTables().stream() - .filter(table -> tableName.equals(table.getName())) + .filter(table -> table.getName().equalsIgnoreCase(tableName)) .findFirst() .orElse(null); } @@ -67,14 +87,15 @@ public Table findTableInfo(String tableName) { @Override public ResultSet getColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) { AtomicInteger ordinal = new AtomicInteger(1); - return new CachedResultSet(getTables().stream() - .filter(table -> tableNamePattern == null || table.getName().equals(tableNamePattern)) + logger.info("[Meta] getColumns catalog="+catalog+" schema="+schemaPattern+" table="+tableNamePattern+" column="+columnNamePattern ); + List> rows = getTables().stream() + .filter(table -> tableNamePattern == null || "%".equals(tableNamePattern.trim()) || table.getName().equalsIgnoreCase(tableNamePattern)) .flatMap(table -> table.getColumns().stream()) - .filter(column -> columnNamePattern == null || column.getName().equals(columnNamePattern)) + .filter(column -> columnNamePattern == null || "%".equals(columnNamePattern.trim())|| column.getName().equalsIgnoreCase(columnNamePattern)) .map(column -> new ColumnMap() {{ TypeInfo typeInfo = lookupTypeInfo(column.getType()); - put("TABLE_CAT", null); - put("TABLE_SCHEM", null); + put("TABLE_CAT", DEFAULT_CATALOG); + put("TABLE_SCHEM", DEFAULT_SCHEMA); put("TABLE_NAME", column.getTable().getName()); put("COLUMN_NAME", column.getName()); put("DATA_TYPE", typeInfo != null ? typeInfo.sqlDataType : Types.OTHER); @@ -100,8 +121,11 @@ public ResultSet getColumns(String catalog, String schemaPattern, String tableNa column.isNillable() ? DatabaseMetaData.columnNullable : DatabaseMetaData.columnNoNulls); }}) - .collect(Collectors.toList()) - ); + .collect(Collectors.toList()); + ColumnMap firstRow = rows.size() > 0 ? rows.get(0) : null; + logger.info("[Meta] getColumns RESULT catalog="+catalog+" schema="+schemaPattern+" table="+tableNamePattern+" column="+columnNamePattern + + "\n firstRowFound="+(firstRow!=null?"yes":"no")+ " ColumnsFound="+rows.size()); + return new CachedResultSet(rows, ForcePreparedStatement.dummyMetaData(firstRow)); } public static TypeInfo lookupTypeInfo(String forceTypeName) { @@ -112,42 +136,67 @@ public static TypeInfo lookupTypeInfo(String forceTypeName) { .orElse(OTHER_TYPE_INFO); } + public static TypeInfo lookupTypeInfoFromJavaType(String javaTypeName) { + if (javaTypeName == null) { + javaTypeName = "string"; + } + if (javaTypeName.equals("java.lang.Boolean")) { + javaTypeName = "boolean"; + } + if (javaTypeName.equals("java.lang.String")) { + javaTypeName = "string"; + } + String typeName = javaTypeName; + return Arrays.stream(TYPE_INFO_DATA) + .filter(entry -> typeName.equals(entry.typeName)) + .findAny() + .orElse(OTHER_TYPE_INFO); + } + @Override public ResultSet getSchemas() throws SQLException { ColumnMap row = new ColumnMap<>(); row.put("TABLE_SCHEM", DEFAULT_SCHEMA); - row.put("TABLE_CATALOG", null); + row.put("TABLE_CATALOG", DEFAULT_CATALOG); row.put("IS_DEFAULT", true); - return new CachedResultSet(row); + return new CachedResultSet(row, ForcePreparedStatement.dummyMetaData(row)); } @Override public ResultSet getPrimaryKeys(String catalog, String schema, String tableName) throws SQLException { + logger.info("[Meta] getPrimaryKeys RESULT catalog="+catalog+" schema="+schema+" table="+tableName); List> maps = new ArrayList<>(); + ColumnMap firstRow = null; for (Table table : getTables()) { - if (table.getName().equals(tableName)) { + if (tableName == null || "%".equals(tableName.trim()) || table.getName().equalsIgnoreCase(tableName)) { for (Column column : table.getColumns()) { if (column.getName().equalsIgnoreCase("Id")) { ColumnMap map = new ColumnMap<>(); - map.put("TABLE_CAT", null); - map.put("TABLE_SCHEM", null); + map.put("TABLE_CAT", DEFAULT_CATALOG); + map.put("TABLE_SCHEM", DEFAULT_SCHEMA); map.put("TABLE_NAME", table.getName()); map.put("COLUMN_NAME", "" + column.getName()); map.put("KEY_SEQ", 0); map.put("PK_NAME", "FakePK" + counter); maps.add(map); + if (firstRow == null) { + firstRow = map; } } } } - return new CachedResultSet(maps); + } + logger.info("[Meta] getPrimaryKeys RESULT catalog="+catalog+" schema="+schema+" table="+tableName+ + "\n firstRowFound="+(firstRow!=null?"yes":"no")+ " KeysFound="+maps.size()); + return new CachedResultSet(maps, ForcePreparedStatement.dummyMetaData(firstRow)); } @Override public ResultSet getImportedKeys(String catalog, String schema, String tableName) throws SQLException { List> maps = new ArrayList<>(); + ColumnMap firstRow = null; for (Table table : getTables()) { - if (table.getName().equals(tableName)) { + if (tableName == null || "%".equals(tableName.trim()) || table.getName().equalsIgnoreCase(tableName)) { for (Column column : table.getColumns()) { if (column.getReferencedTable() != null && column.getReferencedColumn() != null) { ColumnMap map = new ColumnMap<>(); @@ -167,23 +216,27 @@ public ResultSet getImportedKeys(String catalog, String schema, String tableName map.put("DEFERRABILITY", 0); counter++; maps.add(map); + if (firstRow == null) { + firstRow = map; } } } } - return new CachedResultSet(maps); + } + return new CachedResultSet(maps, ForcePreparedStatement.dummyMetaData(firstRow)); } @Override public ResultSet getIndexInfo(String catalog, String schema, String tableName, boolean unique, boolean approximate) { List> maps = new ArrayList<>(); + ColumnMap firstRow = null; for (Table table : getTables()) { - if (table.getName().equals(tableName)) { + if (tableName == null || "%".equals(tableName.trim()) || table.getName().equalsIgnoreCase(tableName)) { for (Column column : table.getColumns()) { if (column.getName().equalsIgnoreCase("Id")) { ColumnMap map = new ColumnMap<>(); - map.put("TABLE_CAT", null); - map.put("TABLE_SCHEM", null); + map.put("TABLE_CAT", DEFAULT_CATALOG); + map.put("TABLE_SCHEM", DEFAULT_SCHEMA); map.put("TABLE_NAME", table.getName()); map.put("NON_UNIQUE", true); map.put("INDEX_QUALIFIER", null); @@ -197,17 +250,23 @@ public ResultSet getIndexInfo(String catalog, String schema, String tableName, b map.put("FILTER_CONDITION", null); maps.add(map); + + if (firstRow == null) { + firstRow = map; } } } } - return new CachedResultSet(maps); + } + return new CachedResultSet(maps, ForcePreparedStatement.dummyMetaData(firstRow)); } @SuppressWarnings("unchecked") @Override public ResultSet getCatalogs() throws SQLException { - return new CachedResultSet(Collections.EMPTY_LIST); + ColumnMap row = new ColumnMap<>(); + row.put("TABLE_CAT", DEFAULT_CATALOG); + return new CachedResultSet(row, ForcePreparedStatement.dummyMetaData(row)); } public static class TypeInfo { @@ -263,6 +322,7 @@ public TypeInfo(String typeName, int sqlDataType, int precision, int minScale, i @Override public ResultSet getTypeInfo() throws SQLException { + ColumnMap firstRow = null; List> rows = new ArrayList<>(); for (TypeInfo typeInfo : TYPE_INFO_DATA) { ColumnMap row = new ColumnMap<>(); @@ -287,13 +347,16 @@ public ResultSet getTypeInfo() throws SQLException { row.put("TYPE_SUB", 1); rows.add(row); + if (firstRow == null) { + firstRow = row; + } } - return new CachedResultSet(rows); + return new CachedResultSet(rows, ForcePreparedStatement.dummyMetaData(firstRow)); } @Override public T unwrap(Class iface) throws SQLException { - // TODO Auto-generated method stub + logger.info("[Meta] unwrap requested NOT_IMPLEMENTED ifaceType="+iface.getName()); return null; } @@ -318,7 +381,7 @@ public boolean allTablesAreSelectable() throws SQLException { @Override public String getURL() throws SQLException { // TODO Auto-generated method stub - return ""; + return null; } @Override @@ -364,7 +427,7 @@ public String getDatabaseProductName() throws SQLException { @Override public String getDatabaseProductVersion() throws SQLException { - return "39"; + return "50"; } @Override @@ -374,7 +437,7 @@ public String getDriverName() throws SQLException { @Override public String getDriverVersion() throws SQLException { - return "1.1"; + return "1.2"; } @Override @@ -384,7 +447,7 @@ public int getDriverMajorVersion() { @Override public int getDriverMinorVersion() { - return 0; + return 2; } @Override @@ -660,7 +723,7 @@ public boolean supportsLimitedOuterJoins() throws SQLException { @Override public String getSchemaTerm() throws SQLException { // TODO Auto-generated method stub - return ""; + return DEFAULT_SCHEMA; } @Override @@ -672,7 +735,7 @@ public String getProcedureTerm() throws SQLException { @Override public String getCatalogTerm() throws SQLException { // TODO Auto-generated method stub - return ""; + return DEFAULT_CATALOG; } @Override @@ -684,7 +747,7 @@ public boolean isCatalogAtStart() throws SQLException { @Override public String getCatalogSeparator() throws SQLException { // TODO Auto-generated method stub - return ""; + return "."; } @Override @@ -1009,60 +1072,71 @@ public boolean dataDefinitionIgnoredInTransactions() throws SQLException { public ResultSet getProcedures(String catalog, String schemaPattern, String procedureNamePattern) throws SQLException { // TODO Auto-generated method stub - return null; + logger.info("[Meta] getProcedures requested NOT_IMPLEMENTED catalog="+catalog+" schema="+schemaPattern+" proc="+procedureNamePattern); + return new CachedResultSet(Collections.EMPTY_LIST, null); } @Override public ResultSet getProcedureColumns(String catalog, String schemaPattern, String procedureNamePattern, String columnNamePattern) throws SQLException { // TODO Auto-generated method stub - return null; + logger.info("[Meta] getProcedureColumns requested NOT_IMPLEMENTED catalog="+catalog+" schema="+schemaPattern+" procs="+procedureNamePattern+" col="+columnNamePattern); + return new CachedResultSet(Collections.EMPTY_LIST, null); } @Override public ResultSet getTableTypes() throws SQLException { - // TODO Auto-generated method stub - return null; + logger.info("[Meta] getTableTypes requested IMPLEMENTED"); + ColumnMap row = new ColumnMap<>(); + row.put("TABLE_TYPE", DEFAULT_TABLE_TYPE); + return new CachedResultSet(row, ForcePreparedStatement.dummyMetaData(row)); } @Override public ResultSet getColumnPrivileges(String catalog, String schema, String table, String columnNamePattern) throws SQLException { + logger.info("[Meta] getColumnPrivileges requested NOT_IMPLEMENTED catalog="+catalog+" schema="+schema+" table="+table+" column="+columnNamePattern); // TODO Auto-generated method stub - return null; + return new CachedResultSet(Collections.EMPTY_LIST, null); } @Override public ResultSet getTablePrivileges(String catalog, String schemaPattern, String tableNamePattern) throws SQLException { + logger.info("[Meta] getTablePrivileges requested NOT_IMPLEMENTED catalog="+catalog+" schema="+schemaPattern+" table="+tableNamePattern); // TODO Auto-generated method stub - return null; + return new CachedResultSet(Collections.EMPTY_LIST, null); } @Override public ResultSet getBestRowIdentifier(String catalog, String schema, String table, int scope, boolean nullable) throws SQLException { + logger.info("[Meta] getBestRowIdentifier requested NOT_IMPLEMENTED catalog="+catalog+" schema="+schema+" table="+table); // TODO Auto-generated method stub - return null; + return new CachedResultSet(Collections.EMPTY_LIST, null); } @Override public ResultSet getVersionColumns(String catalog, String schema, String table) throws SQLException { + logger.info("[Meta] getVersionColumns requested NOT_IMPLEMENTED catalog="+catalog+" schema="+schema+" table="+table); // TODO Auto-generated method stub - return null; + return new CachedResultSet(Collections.EMPTY_LIST, null); } @Override public ResultSet getExportedKeys(String catalog, String schema, String table) throws SQLException { + logger.info("[Meta] getExportedKeys requested NOT_IMPLEMENTED catalog="+catalog+" schema="+schema+" table="+table); // TODO Auto-generated method stub - return null; + return new CachedResultSet(Collections.EMPTY_LIST, null); } @Override public ResultSet getCrossReference(String parentCatalog, String parentSchema, String parentTable, String foreignCatalog, String foreignSchema, String foreignTable) throws SQLException { + logger.info("[Meta] getCrossReference requested NOT_IMPLEMENTED parentCat="+parentCatalog+" parentSc="+parentSchema+" parentTable="+parentTable+" catalog="+foreignCatalog+" schema="+foreignSchema+" table="+foreignTable); + // TODO Auto-generated method stub - return null; + return new CachedResultSet(Collections.EMPTY_LIST, null); } @Override @@ -1141,7 +1215,8 @@ public boolean supportsBatchUpdates() throws SQLException { public ResultSet getUDTs(String catalog, String schemaPattern, String typeNamePattern, int[] types) throws SQLException { // TODO Auto-generated method stub - return null; + logger.info("[Meta] getUDTs requested NOT_IMPLEMENTED"); + return new CachedResultSet(Collections.EMPTY_LIST, null); } @Override @@ -1177,20 +1252,23 @@ public boolean supportsGetGeneratedKeys() throws SQLException { @Override public ResultSet getSuperTypes(String catalog, String schemaPattern, String typeNamePattern) throws SQLException { // TODO Auto-generated method stub - return null; + logger.info("[Meta] getSuperTypes requested NOT_IMPLEMENTED catalog="+catalog+" schema="+schemaPattern+" type="+typeNamePattern); + return new CachedResultSet(Collections.EMPTY_LIST, null); } @Override public ResultSet getSuperTables(String catalog, String schemaPattern, String tableNamePattern) throws SQLException { // TODO Auto-generated method stub - return null; + logger.info("[Meta] getSuperTables requested NOT_IMPLEMENTED catalog="+catalog+" schema="+schemaPattern+" table="+tableNamePattern); + return new CachedResultSet(Collections.EMPTY_LIST, null); } @Override public ResultSet getAttributes(String catalog, String schemaPattern, String typeNamePattern, String attributeNamePattern) throws SQLException { // TODO Auto-generated method stub - return null; + logger.info("[Meta] getAttributes requested NOT_IMPLEMENTED catalog="+catalog+" schema="+schemaPattern+" type="+typeNamePattern+" attr="+attributeNamePattern); + return new CachedResultSet(Collections.EMPTY_LIST, null); } @Override @@ -1246,6 +1324,7 @@ public boolean supportsStatementPooling() throws SQLException { @Override public RowIdLifetime getRowIdLifetime() throws SQLException { // TODO Auto-generated method stub + logger.info("[Meta] getRowIdLifetime requested NOT_IMPLEMENTED"); return null; } @@ -1269,28 +1348,32 @@ public boolean autoCommitFailureClosesAllResultSets() throws SQLException { @Override public ResultSet getClientInfoProperties() throws SQLException { // TODO Auto-generated method stub - return null; + logger.info("[Meta] getClientInfoProperties requested NOT_IMPLEMENTED"); + return new CachedResultSet(Collections.EMPTY_LIST, null); } @Override public ResultSet getFunctions(String catalog, String schemaPattern, String functionNamePattern) throws SQLException { // TODO Auto-generated method stub - return null; + logger.info("[Meta] getSuperTables requested NOT_IMPLEMENTED catalog="+catalog+" schema="+schemaPattern+" func="+functionNamePattern); + return new CachedResultSet(Collections.EMPTY_LIST, null); } @Override public ResultSet getFunctionColumns(String catalog, String schemaPattern, String functionNamePattern, String columnNamePattern) throws SQLException { // TODO Auto-generated method stub - return null; + logger.info("[Meta] getSuperTables requested NOT_IMPLEMENTED catalog="+catalog+" schema="+schemaPattern+" func="+functionNamePattern+" column="+columnNamePattern); + return new CachedResultSet(Collections.EMPTY_LIST, null); } @Override public ResultSet getPseudoColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) throws SQLException { // TODO Auto-generated method stub - return null; + logger.info("[Meta] getPseudoColumns requested NOT_IMPLEMENTED catalog="+catalog+" schema="+schemaPattern+" table="+tableNamePattern+" column="+columnNamePattern); + return new CachedResultSet(Collections.EMPTY_LIST, null); } @Override diff --git a/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/resultset/CachedResultSet.java b/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/resultset/CachedResultSet.java index 78fc9a5..bedca9d 100644 --- a/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/resultset/CachedResultSet.java +++ b/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/resultset/CachedResultSet.java @@ -55,6 +55,10 @@ public CachedResultSet(ColumnMap singleRow) { this(Arrays.asList(singleRow)); } + public CachedResultSet(ColumnMap singleRow, ResultSetMetaData metadata) { + this(Arrays.asList(singleRow), metadata); + } + public Object getObject(String columnName) throws SQLException { return rows.get(getIndex()).get(columnName.toUpperCase()); } @@ -63,6 +67,10 @@ public Object getObject(int columnIndex) throws SQLException { return rows.get(getIndex()).getByIndex(columnIndex); } + protected void addRow(ColumnMap row) { + rows.add(row); + } + private int getIndex() { if (index == null) { index = -1; diff --git a/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/statement/ForcePreparedStatement.java b/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/statement/ForcePreparedStatement.java index 5757982..957e1fb 100644 --- a/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/statement/ForcePreparedStatement.java +++ b/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/statement/ForcePreparedStatement.java @@ -47,6 +47,8 @@ import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.function.Function; +import java.util.logging.Level; +import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -54,6 +56,9 @@ public class ForcePreparedStatement implements PreparedStatement { + private static final String SF_JDBC_DRIVER_NAME = "SF JDBC driver"; + private static final Logger logger = Logger.getLogger(SF_JDBC_DRIVER_NAME); + private final static String CACHE_HINT = "(?is)\\A\\s*(CACHE\\s*(GLOBAL|SESSION)).*"; private final static int GB = 1073741824; @@ -68,7 +73,7 @@ protected enum CacheMode { private int fetchSize; private int maxRows; private List parameters = new ArrayList<>(); - private final CacheMode cacheMode; + private CacheMode cacheMode; private static DB cacheDb = DBMaker.tempFileDB().closeOnJvmShutdown().make(); // TODO: Join caches and move it to ForceConnection class. Divide to session @@ -84,7 +89,13 @@ protected enum CacheMode { .expireStoreSize(1 * GB) .create(); + public ForcePreparedStatement(ForceConnection connection) { + logger.info("[PrepStat] constructor conn IMPLEMENTED "); + this.connection = connection; + } + public ForcePreparedStatement(ForceConnection connection, String soql) { + logger.info("[PrepStat] constructor soql IMPLEMENTED "+soql); this.connection = connection; this.cacheMode = getCacheMode(soql); this.soqlQuery = removeCacheHints(soql); @@ -96,6 +107,7 @@ public static RuntimeException rethrowAsNonChecked(Throwab @Override public ResultSet executeQuery() throws SQLException { + logger.info("[PrepStat] executeQuery IMPLEMENTED "+soqlQuery); return cacheMode == CacheMode.NO_CACHE ? query() : dataCache.computeIfAbsent(getCacheKey(), s -> { @@ -109,6 +121,11 @@ public ResultSet executeQuery() throws SQLException { } private ResultSet query() throws SQLException { + logger.info("[PrepStat] query IMPLEMENTED "+soqlQuery); + if ("SELECT 'keep alive'".equals(soqlQuery)) { + logger.info("[PrepStat] query KEEP ALIVE "); + return new CachedResultSet(Collections.emptyList(), getMetaData()); + } try { String preparedSoql = prepareQuery(); List forceQueryResult = getPartnerService().query(preparedSoql, getFieldDefinitions()); @@ -125,6 +142,7 @@ private ResultSet query() throws SQLException { } private String prepareQuery() { + logger.info("[PrepStat] prepareQuery IMPLEMENTED "+soqlQuery); return setParams(soqlQuery); } @@ -166,6 +184,7 @@ private String getCacheKey() { } public List getParameters() { + logger.info("[PrepStat] getParameters IMPLEMENTED "+soqlQuery); int paramsCountInQuery = StringUtils.countMatches(soqlQuery, '?'); if (parameters.size() < paramsCountInQuery) { parameters.addAll(Collections.nCopies(paramsCountInQuery - parameters.size(), null)); @@ -174,6 +193,7 @@ public List getParameters() { } protected String setParams(String soql) { + logger.info("[PrepStat] setParams IMPLEMENTED "+soql); String result = soql; for (Object param : getParameters()) { String paramRepresentation = convertToSoqlParam(param); @@ -217,8 +237,42 @@ protected static Class getParamClass(Object paramValue) { return paramClass; } + public static ResultSetMetaData dummyMetaData(ColumnMap row) { + if (row == null) { + return null; + } + try { + logger.info("[PrepStat] dummyMetaData IMPLEMENTED "); + RowSetMetaDataImpl result = new RowSetMetaDataImpl(); + int columnsCount = row.size(); + result.setColumnCount(columnsCount); + for (int i = 1; i <= columnsCount; i++) { + String fieldName = row.getColumnNames().get(i-1); + result.setAutoIncrement(i, false); + result.setColumnName(i, fieldName); + result.setColumnLabel(i, fieldName); + Object value = row.getValues().get(i-1); + String javaTypeName = value == null ? "string" : value.getClass().getName(); + ForceDatabaseMetaData.TypeInfo typeInfo = ForceDatabaseMetaData.lookupTypeInfoFromJavaType(javaTypeName); + logger.info("[PrepStat] dummyMetaData ("+i+") "+fieldName+" : "+javaTypeName+" => "+typeInfo.sqlDataType); + result.setColumnType(i, typeInfo.sqlDataType); + result.setColumnTypeName(i, typeInfo.typeName); + result.setPrecision(i, typeInfo.precision); + result.setSchemaName(i, ForceDatabaseMetaData.DEFAULT_SCHEMA); + result.setCatalogName(i, ForceDatabaseMetaData.DEFAULT_CATALOG); + result.setTableName(i, null); + } + return result; + } catch (Exception e) { + // Ignore for metadata - just return empty + logger.log(Level.WARNING, "Failed to compile dummy metadata information", e); + return null; + } + } + private ResultSetMetaData loadMetaData() throws SQLException { try { + logger.info("[PrepStat] loadMetaData IMPLEMENTED "+soqlQuery); if (metadata == null) { RowSetMetaDataImpl result = new RowSetMetaDataImpl(); SoqlQueryAnalyzer queryAnalyzer = getQueryAnalyzer(); @@ -235,7 +289,8 @@ private ResultSetMetaData loadMetaData() throws SQLException { result.setColumnType(i, typeInfo.sqlDataType); result.setColumnTypeName(i, typeInfo.typeName); result.setPrecision(i, typeInfo.precision); - result.setSchemaName(i, "Salesforce"); + result.setSchemaName(i, ForceDatabaseMetaData.DEFAULT_SCHEMA); + result.setCatalogName(i, ForceDatabaseMetaData.DEFAULT_CATALOG); result.setTableName(i, queryAnalyzer.getFromObjectName()); } metadata = result; @@ -247,6 +302,7 @@ private ResultSetMetaData loadMetaData() throws SQLException { } private List flatten(List fieldDefinitions) { + logger.info("[PrepStat] flatten IMPLEMENTED "+soqlQuery); return (List) fieldDefinitions.stream() .flatMap(def -> def instanceof List ? ((List) def).stream() @@ -320,18 +376,14 @@ public int getMaxRows() throws SQLException { } public void setArray(int i, Array x) throws SQLException { - String methodName = this.getClass().getSimpleName() + "." + new Object() { - }.getClass().getEnclosingMethod().getName(); - throw new UnsupportedOperationException("The " + methodName + " is not implemented yet."); - + logger.info("[PrepStat] setArray NOT_IMPLEMENTED "+soqlQuery); + throw new UnsupportedOperationException("The setArray is not implemented yet."); } public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException { - String methodName = this.getClass().getSimpleName() + "." + new Object() { - }.getClass().getEnclosingMethod().getName(); - throw new UnsupportedOperationException("The " + methodName + " is not implemented yet."); - + logger.info("[PrepStat] setAsciiStream NOT_IMPLEMENTED "+soqlQuery); + throw new UnsupportedOperationException("The setAsciiStream is not implemented yet."); } public void setBigDecimal(int parameterIndex, BigDecimal x) @@ -340,6 +392,7 @@ public void setBigDecimal(int parameterIndex, BigDecimal x) } protected void addParameter(int parameterIndex, Object x) { + logger.info("[PrepStat] addParameter "+parameterIndex+" IMPLEMENTED "+soqlQuery); parameterIndex--; if (parameters.size() < parameterIndex) { parameters.addAll(Collections.nCopies(parameterIndex - parameters.size(), null)); @@ -349,17 +402,13 @@ protected void addParameter(int parameterIndex, Object x) { public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException { - String methodName = this.getClass().getSimpleName() + "." + new Object() { - }.getClass().getEnclosingMethod().getName(); - throw new UnsupportedOperationException("The " + methodName + " is not implemented yet."); - + logger.info("[PrepStat] setBinaryStream NOT_IMPLEMENTED "+soqlQuery); + throw new UnsupportedOperationException("The setBinaryStream is not implemented yet."); } public void setBlob(int i, Blob x) throws SQLException { - String methodName = this.getClass().getSimpleName() + "." + new Object() { - }.getClass().getEnclosingMethod().getName(); - throw new UnsupportedOperationException("The " + methodName + " is not implemented yet."); - + logger.info("[PrepStat] setBlob NOT_IMPLEMENTED "+soqlQuery); + throw new UnsupportedOperationException("The setBlob is not implemented yet."); } public void setBoolean(int parameterIndex, boolean x) throws SQLException { @@ -367,29 +416,24 @@ public void setBoolean(int parameterIndex, boolean x) throws SQLException { } public void setByte(int parameterIndex, byte x) throws SQLException { - String methodName = this.getClass().getSimpleName() + "." + new Object() { - }.getClass().getEnclosingMethod().getName(); - throw new UnsupportedOperationException("The " + methodName + " is not implemented yet."); + logger.info("[PrepStat] setByte NOT_IMPLEMENTED "+soqlQuery); + throw new UnsupportedOperationException("The setByte is not implemented yet."); } public void setBytes(int parameterIndex, byte[] x) throws SQLException { - String methodName = this.getClass().getSimpleName() + "." + new Object() { - }.getClass().getEnclosingMethod().getName(); - throw new UnsupportedOperationException("The " + methodName + " is not implemented yet."); - + logger.info("[PrepStat] setBytes NOT_IMPLEMENTED "+soqlQuery); + throw new UnsupportedOperationException("The setBytes is not implemented yet."); } public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException { - String methodName = this.getClass().getSimpleName() + "." + new Object() { - }.getClass().getEnclosingMethod().getName(); - throw new UnsupportedOperationException("The " + methodName + " is not implemented yet."); + logger.info("[PrepStat] setCharacterStream NOT_IMPLEMENTED "+soqlQuery); + throw new UnsupportedOperationException("The setCharacterStream is not implemented yet."); } public void setClob(int i, Clob x) throws SQLException { - String methodName = this.getClass().getSimpleName() + "." + new Object() { - }.getClass().getEnclosingMethod().getName(); - throw new UnsupportedOperationException("The " + methodName + " is not implemented yet."); + logger.info("[PrepStat] setClob NOT_IMPLEMENTED "+soqlQuery); + throw new UnsupportedOperationException("The setClob is not implemented yet."); } public void setDate(int parameterIndex, Date x) throws SQLException { @@ -398,9 +442,8 @@ public void setDate(int parameterIndex, Date x) throws SQLException { public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { - String methodName = this.getClass().getSimpleName() + "." + new Object() { - }.getClass().getEnclosingMethod().getName(); - throw new UnsupportedOperationException("The " + methodName + " is not implemented yet."); + logger.info("[PrepStat] setDate NOT_IMPLEMENTED "+soqlQuery); + throw new UnsupportedOperationException("The setDate is not implemented yet."); } public void setDouble(int parameterIndex, double x) throws SQLException { @@ -429,23 +472,20 @@ public void setNull(int paramIndex, int sqlType, String typeName) } public void setObject(int parameterIndex, Object x) throws SQLException { - String methodName = this.getClass().getSimpleName() + "." + new Object() { - }.getClass().getEnclosingMethod().getName(); - throw new UnsupportedOperationException("The " + methodName + " is not implemented yet."); + logger.info("[PrepStat] setObject 1 NOT_IMPLEMENTED "+soqlQuery); + throw new UnsupportedOperationException("The setObject 1 is not implemented yet."); } public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException { - String methodName = this.getClass().getSimpleName() + "." + new Object() { - }.getClass().getEnclosingMethod().getName(); - throw new UnsupportedOperationException("The " + methodName + " is not implemented yet."); + logger.info("[PrepStat] setObject 2 NOT_IMPLEMENTED "+soqlQuery); + throw new UnsupportedOperationException("The setObject 2 is not implemented yet."); } public void setObject(int parameterIndex, Object x, int targetSqlType, int scale) throws SQLException { - String methodName = this.getClass().getSimpleName() + "." + new Object() { - }.getClass().getEnclosingMethod().getName(); - throw new UnsupportedOperationException("The " + methodName + " is not implemented yet."); + logger.info("[PrepStat] setObject 3 NOT_IMPLEMENTED "+soqlQuery); + throw new UnsupportedOperationException("The setObject 3 is not implemented yet."); } public void setRef(int i, Ref x) throws SQLException { @@ -506,12 +546,20 @@ public void setUnicodeStream(int parameterIndex, InputStream x, int length) @Override public ResultSet executeQuery(String sql) throws SQLException { - throw new RuntimeException("Not yet implemented."); + logger.info("[PrepStat] executeQuery IMPLEMENTED "+sql); + this.cacheMode = getCacheMode(sql); + this.soqlQuery = removeCacheHints(sql); + + return executeQuery(); } @Override public int executeUpdate(String sql) throws SQLException { - // TODO Auto-generated method stub + logger.info("[PrepStat] executeUpdate IMPLEMENTED "+sql); + this.cacheMode = getCacheMode(sql); + this.soqlQuery = removeCacheHints(sql); + + executeQuery(); return 0; } @@ -577,25 +625,29 @@ public void setCursorName(String name) throws SQLException { @Override public boolean execute(String sql) throws SQLException { - // TODO Auto-generated method stub + logger.info("[PrepStat] execute IMPLEMENTED "+sql); + this.cacheMode = getCacheMode(sql); + this.soqlQuery = removeCacheHints(sql); + + executeQuery(); return false; } @Override public ResultSet getResultSet() throws SQLException { - // TODO Auto-generated method stub + logger.info("[PrepStat] getResultSet NOT_IMPLEMENTED "+soqlQuery); return null; } @Override public int getUpdateCount() throws SQLException { - // TODO Auto-generated method stub - return 0; + logger.info("[PrepStat] getUpdateCount NOT_IMPLEMENTED "+soqlQuery); + return -1; } @Override public boolean getMoreResults() throws SQLException { - // TODO Auto-generated method stub + logger.info("[PrepStat] getMoreResults NOT_IMPLEMENTED "+soqlQuery); return false; } @@ -619,37 +671,35 @@ public int getResultSetConcurrency() throws SQLException { @Override public int getResultSetType() throws SQLException { - // TODO Auto-generated method stub + logger.info("[PrepStat] getResultSetType NOT_IMPLEMENTED "+soqlQuery); return 0; } @Override public void addBatch(String sql) throws SQLException { - // TODO Auto-generated method stub - + logger.info("[PrepStat] addBatch NOT_IMPLEMENTED "+sql); } @Override public void clearBatch() throws SQLException { - // TODO Auto-generated method stub - + logger.info("[PrepStat] clearBatch NOT_IMPLEMENTED "+soqlQuery); } @Override public int[] executeBatch() throws SQLException { - // TODO Auto-generated method stub + logger.info("[PrepStat] executeBatch NOT_IMPLEMENTED "+soqlQuery); return null; } @Override public Connection getConnection() throws SQLException { - // TODO Auto-generated method stub + logger.info("[PrepStat] getConnection NOT_IMPLEMENTED "+soqlQuery); return null; } @Override public boolean getMoreResults(int current) throws SQLException { - // TODO Auto-generated method stub + logger.info("[PrepStat] getMoreResults NOT_IMPLEMENTED "+soqlQuery); return false; } @@ -661,38 +711,38 @@ public ResultSet getGeneratedKeys() throws SQLException { @Override public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { - // TODO Auto-generated method stub - return 0; + logger.info("[PrepStat] executeUpdate 1 NOT_IMPLEMENTED "+sql); + return executeUpdate(sql); } @Override public int executeUpdate(String sql, int[] columnIndexes) throws SQLException { - // TODO Auto-generated method stub - return 0; + logger.info("[PrepStat] executeUpdate 2 NOT_IMPLEMENTED "+sql); + return executeUpdate(sql); } @Override public int executeUpdate(String sql, String[] columnNames) throws SQLException { - // TODO Auto-generated method stub - return 0; + logger.info("[PrepStat] executeUpdate 3 NOT_IMPLEMENTED "+sql); + return executeUpdate(sql); } @Override public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { - // TODO Auto-generated method stub - return false; + logger.info("[PrepStat] execute 1 NOT_IMPLEMENTED "+sql); + return executeUpdate(sql) > 0; } @Override public boolean execute(String sql, int[] columnIndexes) throws SQLException { - // TODO Auto-generated method stub - return false; + logger.info("[PrepStat] execute 2 NOT_IMPLEMENTED "+sql); + return executeUpdate(sql) > 0; } @Override public boolean execute(String sql, String[] columnNames) throws SQLException { - // TODO Auto-generated method stub - return false; + logger.info("[PrepStat] execute 3 NOT_IMPLEMENTED "+sql); + return executeUpdate(sql) > 0; } @Override @@ -745,24 +795,26 @@ public boolean isWrapperFor(Class iface) throws SQLException { @Override public int executeUpdate() throws SQLException { - // TODO Auto-generated method stub - return 0; + logger.info("[PrepStat] executeUpdate 2 NOT_IMPLEMENTED "+soqlQuery); + return executeUpdate(soqlQuery); } @Override public void clearParameters() throws SQLException { + logger.info("[PrepStat] clearParameters 2 NOT_IMPLEMENTED "+soqlQuery); // TODO Auto-generated method stub } @Override public boolean execute() throws SQLException { - // TODO Auto-generated method stub - return false; + logger.info("[PrepStat] execute NOT_IMPLEMENTED "+soqlQuery); + return executeUpdate(soqlQuery) > 0; } @Override public void addBatch() throws SQLException { + logger.info("[PrepStat] addBatch NOT_IMPLEMENTED "+soqlQuery); // TODO Auto-generated method stub } @@ -770,95 +822,111 @@ public void addBatch() throws SQLException { @Override public void setRowId(int parameterIndex, RowId x) throws SQLException { // TODO Auto-generated method stub + logger.info("[PrepStat] setRowId NOT_IMPLEMENTED "+soqlQuery); } @Override public void setNString(int parameterIndex, String value) throws SQLException { + logger.info("[PrepStat] setNString NOT_IMPLEMENTED "+soqlQuery); // TODO Auto-generated method stub } @Override public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException { + logger.info("[PrepStat] setNCharacterStream NOT_IMPLEMENTED "+soqlQuery); // TODO Auto-generated method stub } @Override public void setNClob(int parameterIndex, NClob value) throws SQLException { + logger.info("[PrepStat] setNClob NOT_IMPLEMENTED "+soqlQuery); // TODO Auto-generated method stub } @Override public void setClob(int parameterIndex, Reader reader, long length) throws SQLException { + logger.info("[PrepStat] setClob NOT_IMPLEMENTED "+soqlQuery); // TODO Auto-generated method stub } @Override public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException { + logger.info("[PrepStat] setBlob NOT_IMPLEMENTED "+soqlQuery); // TODO Auto-generated method stub } @Override public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException { + logger.info("[PrepStat] setNClob NOT_IMPLEMENTED "+soqlQuery); // TODO Auto-generated method stub } @Override public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException { + logger.info("[PrepStat] setSQLXML NOT_IMPLEMENTED "+soqlQuery); // TODO Auto-generated method stub } @Override public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException { + logger.info("[PrepStat] setAsciiStream NOT_IMPLEMENTED "+soqlQuery); // TODO Auto-generated method stub } @Override public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException { + logger.info("[PrepStat] setBinaryStream NOT_IMPLEMENTED "+soqlQuery); // TODO Auto-generated method stub } @Override public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException { + logger.info("[PrepStat] setCharacterStream NOT_IMPLEMENTED "+soqlQuery); // TODO Auto-generated method stub } @Override public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException { + logger.info("[PrepStat] setAsciiStream NOT_IMPLEMENTED "+soqlQuery); // TODO Auto-generated method stub } @Override public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException { + logger.info("[PrepStat] setBinaryStream NOT_IMPLEMENTED "+soqlQuery); // TODO Auto-generated method stub } @Override public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException { + logger.info("[PrepStat] setCharacterStream NOT_IMPLEMENTED "+soqlQuery); // TODO Auto-generated method stub } @Override public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException { + logger.info("[PrepStat] setNCharacterStream NOT_IMPLEMENTED "+soqlQuery); // TODO Auto-generated method stub } @Override public void setClob(int parameterIndex, Reader reader) throws SQLException { + logger.info("[PrepStat] setClob NOT_IMPLEMENTED "+soqlQuery); // TODO Auto-generated method stub } @@ -866,12 +934,14 @@ public void setClob(int parameterIndex, Reader reader) throws SQLException { @Override public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException { // TODO Auto-generated method stub + logger.info("[PrepStat] setBlob NOT_IMPLEMENTED "+soqlQuery); } @Override public void setNClob(int parameterIndex, Reader reader) throws SQLException { // TODO Auto-generated method stub + logger.info("[PrepStat] setNClob NOT_IMPLEMENTED "+soqlQuery); } diff --git a/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/statement/SoqlQueryAnalyzer.java b/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/statement/SoqlQueryAnalyzer.java index 1b0393a..baff74b 100644 --- a/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/statement/SoqlQueryAnalyzer.java +++ b/sf-jdbc-driver/src/main/java/com/ascendix/jdbc/salesforce/statement/SoqlQueryAnalyzer.java @@ -115,7 +115,7 @@ public List getFieldDefinitions() { private Field findField(String name, DescribeSObjectResult objectDesc, Function nameFetcher) { return Arrays.stream(objectDesc.getFields()) - .filter(field -> name.equals(nameFetcher.apply(field))) + .filter(field -> name.equalsIgnoreCase(nameFetcher.apply(field))) .findFirst() .orElseThrow(() -> new IllegalArgumentException("Unknown field name \"" + name + "\" in object \"" + objectDesc.getName() + "\"")); }