Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JDBC driver prepared statement set* methods #31494

Merged
merged 9 commits into from
Jun 27, 2018

Conversation

astefan
Copy link
Contributor

@astefan astefan commented Jun 21, 2018

Fixes #31493

@astefan astefan requested review from costin, nik9000 and imotov June 21, 2018 07:00
}

@Override
public void setBytes(int parameterIndex, byte[] x) throws SQLException {
throw new UnsupportedOperationException("Bytes not implemented yet");
setObject(parameterIndex, x);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why isn't Types specified as in the methods above?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

return;
}

setDate(parameterIndex, new Date(TypeConverter.convertFromCalendarToUTC(x.getTime(), cal)));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should call setObject directly not setDate (with 2 params) which effectively is setDate(paramIndex,x,NULL).
The 2 arg method should invoke the 3 arg one not vice-versa since the former is a subset of the latter.

return;
}

setTime(parameterIndex, new Time(TypeConverter.convertFromCalendarToUTC(x.getTime(), cal)));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comments as above.

}

@Override
public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException {
throw new UnsupportedOperationException("Dates not implemented yet");
if (cal == null) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

// this is also a way to check early for the validity of the desired sql type
targetJDBCType = JDBCType.valueOf(targetSqlType);
} catch (IllegalArgumentException e) {
throw new SQLException(e.getMessage());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The exception should be more precise, either SQLDataException or its parent SQLNonTransientException.
The same comment applies for the rest of the method.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

}

private Calendar getDefaultCalendar() {
return Calendar.getInstance(cfg.timeZone(), Locale.ROOT);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This used to be a final field, why was it moved to a method?

@@ -378,4 +516,12 @@ public boolean execute(String sql, String[] columnNames) throws SQLException {
public long executeLargeUpdate() throws SQLException {
throw new SQLFeatureNotSupportedException("Batching not supported");
}

private boolean checkNull(int parameterIndex, Object o, int type) throws SQLException {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method name seems incorrect since it's not a check but a set. Something like setIfNull or handleNull is more appropriate.

Calendar c = (Calendar) cal.clone();
c.setTimeInMillis(value);

ZonedDateTime convertedDateTime = ZonedDateTime
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be a way to do the conversion without doing the raw math in there (not to mention the whole /1000, * 1000 losses approximation).

Why not use the ZoneId from the calendar to compute the offset:

ZonedDateTime zdt = Instant.ofEpochMillis(value).atZone(cal.getTimeZone().toZoneId());

or potentially use getOffset() instead of getRawOffset()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed the way the conversion is done


/**
* Converts object val from columnType to type
*/
@SuppressWarnings("unchecked")
static <T> T convert(Object val, JDBCType columnType, Class<T> type) throws SQLException {
static <T> T convert(Object val, JDBCType columnType, Class<T> type) throws SQLException, ClassCastException {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CCE is never a good idea to throw out - especially since it forces the caller to handle it.
It should be handled inside convert directly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

assertEquals("true", value(jps));
assertEquals(VARCHAR, jdbcType(jps));

SQLException sqle = expectThrows(SQLException.class, () -> jps.setObject(1, true, Types.TIMESTAMP));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should sit in its own test (setInvalidBooleanObject), something applied to the rest of the test suite.

@elasticmachine
Copy link
Collaborator

Pinging @elastic/es-search-aggs

@costin
Copy link
Member

costin commented Jun 22, 2018

LGTM

Copy link
Member

@nik9000 nik9000 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left a few small things. I'm super happy about the new test though!

|| x instanceof Float
|| x instanceof Double
|| x instanceof String)
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Usually we'd stick this on the end of the last line.

// converting to {@code java.util.Date} because this is the type supported by {@code XContentBuilder} for serialization
java.util.Date dateToSet;
if (x instanceof Timestamp) {
dateToSet = new java.util.Date(((Timestamp) x).getTime());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's round the fractional milliseconds. Are we sure that is right? I think it is worth a comment if we are. If not, worth thinking about some more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nik9000 I did it like this since ES deals with dates in milliseconds since epoch. The parameters will be serialized using a java.util.Date when being sent to ES in queries.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. I think maybe this is worth playing with some more and documenting any strange things that come out of it. Though I think it'd be fine to do in a followup.

|| x instanceof LocalDateTime
|| x instanceof Time
|| x instanceof java.util.Date) {
if (targetJDBCType == JDBCType.TIMESTAMP ) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you do these with a single instanceof? rather than check each one twice? Maybe call setParam(parameterIndex, dateToSet, Types.TIMESTAMP); on the result each time and return?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nik9000 Haven't found a better/easier-to-follow way of refactoring this block of code mostly due to the inner if-else for the target jdbc type. I have gotten rid of the else if bunch though.

}
}

private void checkKnownUnsupportedTypes(Object x) throws SQLFeatureNotSupportedException {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like it'd be cleaner to have this be the result of falling off the end of an if statement chain.

@@ -378,4 +514,12 @@ public boolean execute(String sql, String[] columnNames) throws SQLException {
public long executeLargeUpdate() throws SQLException {
throw new SQLFeatureNotSupportedException("Batching not supported");
}

private boolean setIfNull(int parameterIndex, Object o, int type) throws SQLException {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it might be easier to read the code without this method to be honest. It saves a line every time you call it makes me go "what is going on here?" every time I see it. Not sure.

// according to B-4 table from the jdbc4.2 spec
javaToJDBC.put(Calendar.class, JDBCType.TIMESTAMP);
javaToJDBC.put(java.util.Date.class, JDBCType.TIMESTAMP);
javaToJDBC.put(LocalDateTime.class, JDBCType.TIMESTAMP);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'd be nice if the map were unmodifiable.



static JDBCType fromJavaToJDBC(Class<?> clazz) throws SQLException {
for (Class<?> key : javaToJDBC.keySet()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer iterating over the map entries here.

assertEquals("Numeric " + randomLongNotShort + " out of range", sqle.getMessage());
}

public void testSettingFloatValues() throws SQLException {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I love these tests!

@astefan
Copy link
Contributor Author

astefan commented Jun 26, 2018

@nik9000 thank you for the review and the valuable comments. I've addressed most of them.

Copy link
Member

@nik9000 nik9000 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@astefan astefan merged commit 400db4f into elastic:master Jun 27, 2018
astefan added a commit that referenced this pull request Jun 27, 2018
Added setObject functionality and tests for it
@astefan
Copy link
Contributor Author

astefan commented Jun 27, 2018

Backported to 6.x as well.

jasontedor added a commit to majormoses/elasticsearch that referenced this pull request Jun 27, 2018
* elastic/master: (57 commits)
  HLRest: Fix test for explain API
  [TEST] Fix RemoteClusterConnectionTests
  Add Create Snapshot to High-Level Rest Client (elastic#31215)
  Remove legacy MetaDataStateFormat (elastic#31603)
  Add explain API to high-level REST client (elastic#31387)
  Preserve thread context when connecting to remote cluster (elastic#31574)
  Unify headers for full text queries
  Remove redundant 'minimum_should_match'
  JDBC driver prepared statement set* methods  (elastic#31494)
  [TEST] call yaml client close method from test suite (elastic#31591)
  ingest: Add ignore_missing property to foreach filter (elastic#22147) (elastic#31578)
  Fix a formatting issue in the docvalue_fields documentation. (elastic#31563)
  reduce log level at gradle configuration time
  [TEST] Close additional clients created while running yaml tests (elastic#31575)
  Docs: Clarify sensitive fields watcher encryption (elastic#31551)
  Watcher: Remove never executed code (elastic#31135)
  Add support for switching distribution for all integration tests (elastic#30874)
  Improve robustness of geo shape parser for malformed shapes (elastic#31449)
  QA: Create xpack yaml features (elastic#31403)
  Improve test times for tests using `RandomObjects::addFields` (elastic#31556)
  ...
dnhatn added a commit that referenced this pull request Jun 28, 2018
* master:
  Docs: Remove duplicate test setup
  Print output when the name checker IT fails (#31660)
  Fix syntax errors in get-snapshots docs (#31656)
  Docs: Fix description of percentile ranks example example (#31652)
  Add MultiSearchTemplate support to High Level Rest client (#30836)
  Add test for low-level client round-robin behaviour (#31616)
  SQL: Refactor package names of sql-proto and sql-shared-proto projects (#31622)
  Remove deprecation warnings to prepare for Gradle 5 (sourceSets.main.output.classesDirs) (#30389)
  Correct integTest enable logic (#31646)
  Fix missing get-snapshots docs reference #31645
  Do not check for Azure container existence (#31617)
  Merge AwsS3Service and InternalAwsS3Service in a S3Service class (#31580)
  Upgrade gradle wrapper to 4.8 (#31525)
  Only set vm.max_map_count if greater than default (#31512)
  Add Get Snapshots High Level REST API (#31537)
  QA: Merge query-builder-bwc to restart test (#30979)
  Update reindex.asciidoc (#31626)
  Docs: Skip xpack snippet tests if no xpack (#31619)
  mute CreateSnapshotRequestTests
  HLRest: Fix test for explain API
  [TEST] Fix RemoteClusterConnectionTests
  Add Create Snapshot to High-Level Rest Client (#31215)
  Remove legacy MetaDataStateFormat (#31603)
  Add explain API to high-level REST client (#31387)
  Preserve thread context when connecting to remote cluster (#31574)
  Unify headers for full text queries
  Remove redundant 'minimum_should_match'
  JDBC driver prepared statement set* methods  (#31494)
  [TEST] call yaml client close method from test suite (#31591)
dnhatn added a commit that referenced this pull request Jun 28, 2018
* 6.x:
  Docs: Remove duplicate test setup
  Docs: Fix description of percentile ranks example example (#31652)
  Remove deprecation warnings to prepare for Gradle 5 (sourceSets.main.output.classesDirs) (#30389)
  Do not check for Azure container existence (#31617)
  Merge AwsS3Service and InternalAwsS3Service in a S3Service class (#31580)
  Remove item listed in 6.3 notes that's not in 6.3 (#31623)
  remove unused import
  Upgrade gradle wrapper to 4.8 (#31525)
  Only set vm.max_map_count if greater than default (#31512)
  QA: Merge query-builder-bwc to restart test (#30979)
  Docs: Skip xpack snippet tests if no xpack (#31619)
  [TEST] Fix RemoteClusterConnectionTests
  Remove legacy MetaDataStateFormat (#31603)
  [TEST] call yaml client close method from test suite (#31591)
  [TEST] Close additional clients created while running yaml tests (#31575)
  Node selector per client rather than per request (#31471)
  Preserve thread context when connecting to remote cluster (#31574)
  Remove redundant 'minimum_should_match'
  Unify headers for full text queries
  JDBC driver prepared statement set* methods  (#31494)
  add logging breaking changes from 5.3 to 6.0 (#31583)
  Fix a formatting issue in the docvalue_fields documentation. (#31563)
  Improve robustness of geo shape parser for malformed shapes
  QA: Create xpack yaml features (#31403)
@colings86 colings86 removed the v7.0.0 label Feb 7, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants