Skip to content

Commit

Permalink
[NOID] moved JdbcUtil and LoadJdbcConfig from core to full
Browse files Browse the repository at this point in the history
  • Loading branch information
vga91 committed Apr 17, 2024
1 parent a2d661d commit 80ccb68
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 70 deletions.
6 changes: 4 additions & 2 deletions full/src/main/java/apoc/load/Jdbc.java
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,8 @@ private Object convert(Object value, int sqlType) {
ZoneId zoneId = config.getZoneId();
if (Types.TIMESTAMP == sqlType) {
if (zoneId != null) {
return ((java.sql.Timestamp)value).toInstant()
return ((java.sql.Timestamp) value)
.toInstant()
.atZone(zoneId)
.toOffsetDateTime();
} else {
Expand All @@ -290,7 +291,8 @@ private Object convert(Object value, int sqlType) {
}
if (Types.TIMESTAMP_WITH_TIMEZONE == sqlType) {
if (zoneId != null) {
return ((java.sql.Timestamp)value).toInstant()
return ((java.sql.Timestamp) value)
.toInstant()
.atZone(zoneId)
.toOffsetDateTime();
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,26 +18,18 @@
*/
package apoc.load.util;

import us.fatehi.utility.datasource.DatabaseConnectionSource;
import us.fatehi.utility.datasource.DatabaseConnectionSources;
import us.fatehi.utility.datasource.MultiUseUserCredentials;

import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.login.LoginContext;
import apoc.util.Util;
import java.net.URI;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.sql.Connection;
import java.sql.DriverManager;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.login.LoginContext;
import us.fatehi.utility.datasource.DatabaseConnectionSource;
import us.fatehi.utility.datasource.DatabaseConnectionSources;
import us.fatehi.utility.datasource.MultiUseUserCredentials;

public class JdbcUtil {

Expand All @@ -47,8 +39,11 @@ public class JdbcUtil {
private JdbcUtil() {}

public static DatabaseConnectionSource getConnection(String jdbcUrl, LoadJdbcConfig config) throws Exception {
if(config.hasCredentials()) {
return createConnection(jdbcUrl, config.getCredentials().getUser(), config.getCredentials().getPassword());
if (config.hasCredentials()) {
return createConnection(
jdbcUrl,
config.getCredentials().getUser(),
config.getCredentials().getPassword());
} else {
URI uri = new URI(jdbcUrl.substring("jdbc:".length()));
String userInfo = uri.getUserInfo();
Expand All @@ -58,11 +53,12 @@ public static DatabaseConnectionSource getConnection(String jdbcUrl, LoadJdbcCon
String[] user = userInfo.split(":");
return createConnection(cleanUrl, user[0], user[1]);
}
return DriverManager.getConnection(jdbcUrl);
return DatabaseConnectionSources.newDatabaseConnectionSource(jdbcUrl, new MultiUseUserCredentials());
}
}

private static Connection createConnection(String jdbcUrl, String userName, String password) throws Exception {
private static DatabaseConnectionSource createConnection(String jdbcUrl, String userName, String password)
throws Exception {
if (jdbcUrl.contains(";auth=kerberos")) {
String client = System.getProperty("java.security.auth.login.config.client", "KerberosClient");
LoginContext lc = new LoginContext(client, callbacks -> {
Expand All @@ -74,12 +70,15 @@ private static Connection createConnection(String jdbcUrl, String userName, Stri
lc.login();
Subject subject = lc.getSubject();
try {
return Subject.doAs(subject, (PrivilegedExceptionAction<DatabaseConnectionSource>) () -> DatabaseConnectionSources.newDatabaseConnectionSource(jdbcUrl, new MultiUseUserCredentials(userName, password)));
return Subject.doAs(subject, (PrivilegedExceptionAction<DatabaseConnectionSource>)
() -> DatabaseConnectionSources.newDatabaseConnectionSource(
jdbcUrl, new MultiUseUserCredentials(userName, password)));
} catch (PrivilegedActionException pae) {
throw pae.getException();
}
} else {
return DriverManager.getConnection(jdbcUrl, userName, password);
return DatabaseConnectionSources.newDatabaseConnectionSource(
jdbcUrl, new MultiUseUserCredentials(userName, password));
}
}

Expand Down
3 changes: 1 addition & 2 deletions full/src/main/java/apoc/model/Model.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@
import schemacrawler.schema.*;
import schemacrawler.schemacrawler.SchemaCrawlerOptions;
import schemacrawler.schemacrawler.SchemaCrawlerOptionsBuilder;
import schemacrawler.schemacrawler.SchemaInfoLevelBuilder;
import schemacrawler.utility.SchemaCrawlerUtility;
import schemacrawler.tools.utility.SchemaCrawlerUtility;

@Extended
public class Model {
Expand Down
113 changes: 68 additions & 45 deletions full/src/test/java/apoc/load/MySQLJdbcTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@

import static apoc.util.TestUtil.testCall;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import apoc.util.MySQLContainerExtension;
import apoc.util.TestUtil;
import apoc.util.Util;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZonedDateTime;
import java.util.Map;
import org.junit.AfterClass;
import org.junit.BeforeClass;
Expand All @@ -16,37 +21,29 @@
import org.neo4j.test.rule.DbmsRule;
import org.neo4j.test.rule.ImpermanentDbmsRule;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZonedDateTime;
import java.util.Map;

import static apoc.util.TestUtil.testCall;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

@RunWith(Enclosed.class)
public class MySQLJdbcTest extends AbstractJdbcTest {

public static class MySQLJdbcLatestVersionTest {

@ClassRule
public static MySQLContainerExtension mysql = new MySQLContainerExtension("mysql:8.0.31");

@ClassRule
public static DbmsRule db = new ImpermanentDbmsRule();

@BeforeClass
public static void setUpContainer() {
mysql.start();
TestUtil.registerProcedure(db, Jdbc.class);
}

@AfterClass
public static void tearDown() {
mysql.stop();
db.shutdown();
}

@Test
public void testLoadJdbc() {
MySQLJdbcTest.testLoadJdbc(db, mysql);
Expand All @@ -57,9 +54,9 @@ public void testIssue3496() {
MySQLJdbcTest.testIssue3496(db, mysql);
}
}

public static class MySQLJdbcFiveVersionTest {

@ClassRule
public static MySQLContainerExtension mysql = new MySQLContainerExtension("mysql:5.7");

Expand Down Expand Up @@ -90,34 +87,58 @@ public void testIssue3496() {
}

private static void testLoadJdbc(DbmsRule db, MySQLContainerExtension mysql) {
// with the config {timezone: 'UTC'} and `preserveInstants=true&connectionTimeZone=SERVER` to make the result deterministic,
// since `TIMESTAMP` values are automatically converted from the session time zone to UTC for storage, and vice versa.
testCall(db, "CALL apoc.load.jdbc($url, $table, [], {timezone: 'UTC'})",
// with the config {timezone: 'UTC'} and `preserveInstants=true&connectionTimeZone=SERVER` to make the result
// deterministic,
// since `TIMESTAMP` values are automatically converted from the session time zone to UTC for storage, and vice
// versa.
testCall(
db,
"CALL apoc.load.jdbc($url, $table, [], {timezone: 'UTC'})",
Util.map(
"url", mysql.getJdbcUrl() + "&preserveInstants=true&connectionTimeZone=SERVER",
"table", "country"),
"url",
mysql.getJdbcUrl() + "&preserveInstants=true&connectionTimeZone=SERVER",
"table",
"country"),
row -> {
Map<String, Object> expected = Util.map(
"Code", "NLD",
"Name", "Netherlands",
"Continent", "Europe",
"Region", "Western Europe",
"SurfaceArea", 41526f,
"IndepYear", 1581,
"Population", 15864000,
"LifeExpectancy", 78.3f,
"GNP", 371362f,
"GNPOld", 360478f,
"LocalName", "Nederland",
"GovernmentForm", "Constitutional Monarchy",
"HeadOfState", "Beatrix",
"Capital", 5,
"Code2", "NL",
"myTime", LocalTime.of(1, 0, 0),
"myTimeStamp", ZonedDateTime.parse("2003-01-01T01:00Z"),
"myDate", LocalDate.parse("2003-01-01"),
"myYear", LocalDate.parse("2003-01-01")
);
"Code",
"NLD",
"Name",
"Netherlands",
"Continent",
"Europe",
"Region",
"Western Europe",
"SurfaceArea",
41526f,
"IndepYear",
1581,
"Population",
15864000,
"LifeExpectancy",
78.3f,
"GNP",
371362f,
"GNPOld",
360478f,
"LocalName",
"Nederland",
"GovernmentForm",
"Constitutional Monarchy",
"HeadOfState",
"Beatrix",
"Capital",
5,
"Code2",
"NL",
"myTime",
LocalTime.of(1, 0, 0),
"myTimeStamp",
ZonedDateTime.parse("2003-01-01T01:00Z"),
"myDate",
LocalDate.parse("2003-01-01"),
"myYear",
LocalDate.parse("2003-01-01"));
Map actual = (Map) row.get("row");
Object myDateTime = actual.remove("myDateTime");
assertTrue(myDateTime instanceof LocalDateTime);
Expand All @@ -126,22 +147,24 @@ private static void testLoadJdbc(DbmsRule db, MySQLContainerExtension mysql) {
}

private static void testIssue3496(DbmsRule db, MySQLContainerExtension mysql) {
testCall(db, "CALL apoc.load.jdbc($url,'SELECT DATE(NOW()), NOW(), CURDATE(), CURTIME(), UTC_DATE(), UTC_TIME(), UTC_TIMESTAMP(), DATE(UTC_TIMESTAMP());')",
testCall(
db,
"CALL apoc.load.jdbc($url,'SELECT DATE(NOW()), NOW(), CURDATE(), CURTIME(), UTC_DATE(), UTC_TIME(), UTC_TIMESTAMP(), DATE(UTC_TIMESTAMP());')",
Util.map("url", mysql.getJdbcUrl()),
r -> {
Map row = (Map) r.get("row");
assertEquals(8, row.size());

assertTrue(row.get("UTC_DATE()") instanceof LocalDate);
assertTrue(row.get("CURDATE()") instanceof LocalDate);

assertTrue(row.get("UTC_TIMESTAMP()") instanceof LocalDateTime);
assertTrue(row.get("NOW()") instanceof LocalDateTime);
assertTrue(row.get("DATE(UTC_TIMESTAMP())") instanceof LocalDate);
assertTrue(row.get("DATE(NOW())") instanceof LocalDate);

assertTrue(row.get("CURTIME()") instanceof LocalTime);
assertTrue(row.get("UTC_TIME()") instanceof LocalTime);
});
}
}
}
46 changes: 42 additions & 4 deletions full/src/test/java/apoc/model/ModelTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,27 @@ public void testLoadJdbcSchema() {
assertEquals(29, columns.size());

List<String> countryNodes = filterColumnsByTableName(columns, "country");
List<String> expectedCountryCols = Arrays.asList("Code", "Name", "Continent", "Region", "SurfaceArea", "IndepYear", "Population", "LifeExpectancy", "GNP", "GNPOld", "LocalName", "GovernmentForm", "HeadOfState", "Capital", "Code2",
"myTime", "myDateTime", "myTimeStamp", "myDate", "myYear");
List<String> expectedCountryCols = Arrays.asList(
"Code",
"Name",
"Continent",
"Region",
"SurfaceArea",
"IndepYear",
"Population",
"LifeExpectancy",
"GNP",
"GNPOld",
"LocalName",
"GovernmentForm",
"HeadOfState",
"Capital",
"Code2",
"myTime",
"myDateTime",
"myTimeStamp",
"myDate",
"myYear");
assertEquals(expectedCountryCols, countryNodes);

List<String> cityNodes = filterColumnsByTableName(columns, "city");
Expand Down Expand Up @@ -195,8 +214,27 @@ public void testLoadJdbcSchemaWithWriteOperation() {
assertEquals(29, columns.size());

List<String> countryNodes = filterColumnsByTableName(columns, "country");
List<String> expectedCountryCols = Arrays.asList("Code", "Name", "Continent", "Region", "SurfaceArea", "IndepYear", "Population", "LifeExpectancy", "GNP", "GNPOld", "LocalName", "GovernmentForm", "HeadOfState", "Capital", "Code2",
"myTime", "myDateTime", "myTimeStamp", "myDate", "myYear");
List<String> expectedCountryCols = Arrays.asList(
"Code",
"Name",
"Continent",
"Region",
"SurfaceArea",
"IndepYear",
"Population",
"LifeExpectancy",
"GNP",
"GNPOld",
"LocalName",
"GovernmentForm",
"HeadOfState",
"Capital",
"Code2",
"myTime",
"myDateTime",
"myTimeStamp",
"myDate",
"myYear");
assertEquals(expectedCountryCols, countryNodes);

List<String> cityNodes = filterColumnsByTableName(columns, "city");
Expand Down

0 comments on commit 80ccb68

Please sign in to comment.