Skip to content

Commit a6e94de

Browse files
deonhuangijokarumawak
authored andcommitted
NIFI-2829 - Add Date and Time Format Support for PutSQL
Fix unit test for Date and Time type time zone problem Enhance Time type to record milliseconds This closes #1983. Signed-off-by: Koji Kawamura <ijokarumawak@apache.org>
1 parent 03bff7c commit a6e94de

2 files changed

Lines changed: 59 additions & 19 deletions

File tree

  • nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src

nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/PutSQL.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
import java.text.SimpleDateFormat;
7474
import java.time.Instant;
7575
import java.time.LocalDate;
76+
import java.time.LocalDateTime;
7677
import java.time.LocalTime;
7778
import java.time.ZoneId;
7879
import java.time.format.DateTimeFormatter;
@@ -119,7 +120,10 @@
119120
+ "hex: the string is hex encoded with all letters in upper case and no '0x' at the beginning. "
120121
+ "Dates/Times/Timestamps - "
121122
+ "Date, Time and Timestamp formats all support both custom formats or named format ('yyyy-MM-dd','ISO_OFFSET_DATE_TIME') "
122-
+ "as specified according to java.time.format.DateTimeFormatter.")
123+
+ "as specified according to java.time.format.DateTimeFormatter. "
124+
+ "If not specified, a long value input is expected to be an unix epoch (milli seconds from 1970/1/1), or a string value in "
125+
+ "'yyyy-MM-dd' format for Date, 'HH:mm:ss.SSS' for Time (some database engines e.g. Derby or MySQL do not support milliseconds and will truncate milliseconds), "
126+
+ "'yyyy-MM-dd HH:mm:ss.SSS' for Timestamp is used.")
123127
})
124128
@WritesAttributes({
125129
@WritesAttribute(attribute = "sql.generated.key", description = "If the database generated a key for an INSERT statement and the Obtain Generated Keys property is set to true, "
@@ -840,9 +844,6 @@ private void setParameter(final PreparedStatement stmt, final String attrName, f
840844
date = new Date(Long.parseLong(parameterValue));
841845
}else {
842846
String dateFormatString = "yyyy-MM-dd";
843-
if (!valueFormat.isEmpty()) {
844-
dateFormatString = valueFormat;
845-
}
846847
SimpleDateFormat dateFormat = new SimpleDateFormat(dateFormatString);
847848
java.util.Date parsedDate = dateFormat.parse(parameterValue);
848849
date = new Date(parsedDate.getTime());
@@ -863,17 +864,16 @@ private void setParameter(final PreparedStatement stmt, final String attrName, f
863864
time = new Time(Long.parseLong(parameterValue));
864865
} else {
865866
String timeFormatString = "HH:mm:ss.SSS";
866-
if (!valueFormat.isEmpty()) {
867-
timeFormatString = valueFormat;
868-
}
869867
SimpleDateFormat dateFormat = new SimpleDateFormat(timeFormatString);
870868
java.util.Date parsedDate = dateFormat.parse(parameterValue);
871869
time = new Time(parsedDate.getTime());
872870
}
873871
} else {
874872
final DateTimeFormatter dtFormatter = getDateTimeFormatter(valueFormat);
875873
LocalTime parsedTime = LocalTime.parse(parameterValue, dtFormatter);
876-
time = Time.valueOf(parsedTime);
874+
LocalDateTime localDateTime = parsedTime.atDate(LocalDate.ofEpochDay(0));
875+
Instant instant = localDateTime.atZone(ZoneId.systemDefault()).toInstant();
876+
time = new Time(instant.toEpochMilli());
877877
}
878878

879879
stmt.setTime(parameterIndex, time);
@@ -890,7 +890,7 @@ private void setParameter(final PreparedStatement stmt, final String attrName, f
890890
java.util.Date parsedDate = dateFormat.parse(parameterValue);
891891
lTimestamp = parsedDate.getTime();
892892
}
893-
}else {
893+
} else {
894894
final DateTimeFormatter dtFormatter = getDateTimeFormatter(valueFormat);
895895
TemporalAccessor accessor = dtFormatter.parse(parameterValue);
896896
java.util.Date parsedDate = java.util.Date.from(Instant.from(accessor));

nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestPutSQL.java

Lines changed: 50 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,20 @@
2929
import java.sql.ResultSet;
3030
import java.sql.SQLException;
3131
import java.sql.Statement;
32+
import java.sql.Time;
3233
import java.sql.Types;
3334
import java.text.ParseException;
3435
import java.text.SimpleDateFormat;
36+
import java.time.LocalDate;
37+
import java.time.LocalTime;
38+
import java.time.ZoneId;
39+
import java.time.format.DateTimeFormatter;
3540
import java.util.Arrays;
41+
import java.util.Calendar;
42+
import java.util.Date;
3643
import java.util.HashMap;
3744
import java.util.Map;
45+
import java.util.TimeZone;
3846

3947
import org.apache.commons.lang3.RandomUtils;
4048
import org.apache.nifi.controller.AbstractControllerService;
@@ -467,6 +475,34 @@ public void testUsingDateTimeValuesWithFormatAttribute() throws InitializationEx
467475
final String dateStr = "2002-02-02";
468476
final String timeStr = "12:02:02";
469477

478+
final String timeFormatString = "HH:mm:ss";
479+
final String dateFormatString ="yyyy-MM-dd";
480+
481+
482+
final DateTimeFormatter timeFormatter= DateTimeFormatter.ISO_LOCAL_TIME;
483+
LocalTime parsedTime = LocalTime.parse(timeStr, timeFormatter);
484+
Time expectedTime = Time.valueOf(parsedTime);
485+
486+
final DateTimeFormatter dateFormatter = DateTimeFormatter.ISO_LOCAL_DATE;
487+
LocalDate parsedDate = LocalDate.parse(dateStr, dateFormatter);
488+
Date expectedDate = new Date(Date.from(parsedDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant()).getTime());
489+
490+
final long expectedTimeInLong = expectedTime.getTime();
491+
final long expectedDateInLong = expectedDate.getTime();
492+
493+
//test with time zone GMT to avoid negative value unmatched with long pattern problem.
494+
SimpleDateFormat timeFormat = new SimpleDateFormat(timeFormatString);
495+
timeFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
496+
java.util.Date parsedTimeGMT = timeFormat.parse(timeStr);
497+
498+
SimpleDateFormat dateFormat = new SimpleDateFormat(dateFormatString);
499+
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
500+
java.util.Date parsedDateGMT = dateFormat.parse(dateStr);
501+
502+
Calendar gmtCalendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
503+
504+
505+
//test with ISO LOCAL format attribute
470506
Map<String, String> attributes = new HashMap<>();
471507
attributes.put("sql.args.1.type", String.valueOf(Types.TIME));
472508
attributes.put("sql.args.1.value", timeStr);
@@ -477,14 +513,16 @@ public void testUsingDateTimeValuesWithFormatAttribute() throws InitializationEx
477513

478514
runner.enqueue("INSERT INTO TIMESTAMPTEST3 (ID, ts1, ts2) VALUES (1, ?, ?)".getBytes(), attributes);
479515

516+
//test Long pattern without format attribute
480517
attributes = new HashMap<>();
481518
attributes.put("sql.args.1.type", String.valueOf(Types.TIME));
482-
attributes.put("sql.args.1.value", "68522000");
519+
attributes.put("sql.args.1.value", Long.toString(parsedTimeGMT.getTime()));
483520
attributes.put("sql.args.2.type", String.valueOf(Types.DATE));
484-
attributes.put("sql.args.2.value", "1012633200000");
521+
attributes.put("sql.args.2.value", Long.toString(parsedDateGMT.getTime()));
485522

486523
runner.enqueue("INSERT INTO TIMESTAMPTEST3 (ID, ts1, ts2) VALUES (2, ?, ?)".getBytes(), attributes);
487524

525+
//test with format attribute
488526
attributes = new HashMap<>();
489527
attributes.put("sql.args.1.type", String.valueOf(Types.TIME));
490528
attributes.put("sql.args.1.value", "120202000");
@@ -504,18 +542,18 @@ public void testUsingDateTimeValuesWithFormatAttribute() throws InitializationEx
504542
final ResultSet rs = stmt.executeQuery("SELECT * FROM TIMESTAMPTEST3 ORDER BY ID");
505543
assertTrue(rs.next());
506544
assertEquals(1, rs.getInt(1));
507-
assertEquals(68522000L, rs.getTime(2).getTime());
508-
assertEquals(1012633200000L, rs.getDate(3).getTime());
545+
assertEquals(expectedTimeInLong, rs.getTime(2).getTime());
546+
assertEquals(expectedDateInLong, rs.getDate(3).getTime());
509547

510548
assertTrue(rs.next());
511549
assertEquals(2, rs.getInt(1));
512-
assertEquals(68522000L, rs.getTime(2).getTime());
513-
assertEquals(1012633200000L, rs.getDate(3).getTime());
550+
assertEquals(parsedTimeGMT.getTime(), rs.getTime(2).getTime());
551+
assertEquals(parsedDateGMT.getTime(), rs.getDate(3,gmtCalendar).getTime());
514552

515553
assertTrue(rs.next());
516554
assertEquals(3, rs.getInt(1));
517-
assertEquals(68522000L, rs.getTime(2).getTime());
518-
assertEquals(1012633200000L, rs.getDate(3).getTime());
555+
assertEquals(expectedTimeInLong, rs.getTime(2).getTime());
556+
assertEquals(expectedDateInLong, rs.getDate(3).getTime());
519557

520558
assertFalse(rs.next());
521559
}
@@ -656,12 +694,13 @@ public void testUsingTimeValuesEpochAndString() throws InitializationException,
656694
final String art3TS = "12:02:02";
657695
final String timeFormatString = "HH:mm:ss";
658696
SimpleDateFormat dateFormat = new SimpleDateFormat(timeFormatString);
697+
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
659698
java.util.Date parsedDate = dateFormat.parse(arg2TS);
660699

700+
661701
final Map<String, String> attributes = new HashMap<>();
662702
attributes.put("sql.args.1.type", String.valueOf(Types.TIME));
663703
attributes.put("sql.args.1.value", Long.toString(parsedDate.getTime()));
664-
665704
attributes.put("sql.args.2.type", String.valueOf(Types.TIME));
666705
attributes.put("sql.args.2.value", art3TS);
667706
attributes.put("sql.args.2.format", timeFormatString);
@@ -674,9 +713,10 @@ public void testUsingTimeValuesEpochAndString() throws InitializationException,
674713
try (final Connection conn = service.getConnection()) {
675714
try (final Statement stmt = conn.createStatement()) {
676715
final ResultSet rs = stmt.executeQuery("SELECT * FROM TIMETESTS");
716+
677717
assertTrue(rs.next());
678718
assertEquals(1, rs.getInt(1));
679-
assertEquals(arg2TS, rs.getString(2));
719+
assertEquals(arg2TS, dateFormat.format(rs.getTime(2)));
680720
assertEquals(art3TS, rs.getString(3));
681721
assertFalse(rs.next());
682722
}

0 commit comments

Comments
 (0)