Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
During `BIND` for prepared statements, pgjdbc sends `javax.sql.Timestamp`s with timezone data (UTC offset), even if the target data type is `timestamp` (not `timestamptz`). According to the PG docs [0], the timezone is optional, but Readyset errors if there is timezone information in the string that is sent. Interestingly, pgjdbc will send along only the hour offset, truncating the minutes data, if there's no minutes offset for the timezone (as is the case for most timezones). Note that this "appending timezone data" applies to the text format transfer as pgjdbc only transfers timestamps in the text format. This patch extends the existing timestamp and timestamptz parsing by checking for any trailing text in the input timestamp string, and attempts to parse it into a timezone offset. Also included is a benchmark that compares parsing the timezone offset versus reparsing the entire input string with a "pgjdbc- friendly" format string. Parsing just for the offset is 40% faster than reparsing the entire string: timestamp_text_parse/offsets time: [281.25 ns 282.11 ns 283.06 ns] timestamp_text_reparse/reparse time: [485.31 ns 486.00 ns 486.81 ns] [0] https://www.postgresql.org/docs/current/datatype-datetime.html Fixes: REA-2662 Release-Note-Core: Support timestamps in prepared statements from the Java PG driver, pgjdbc. Change-Id: Ie861d63d1c0ec8d13778857c18204c86585d834d Reviewed-on: https://gerrit.readyset.name/c/readyset/+/6932 Tested-by: Buildkite CI Reviewed-by: Ethan Donowitz <ethan@readyset.io>
- Loading branch information
1 parent
a11beff
commit 7a14b00
Showing
4 changed files
with
171 additions
and
9 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
use std::str::FromStr; | ||
|
||
use chrono::{DateTime, FixedOffset, NaiveDateTime, TimeZone}; | ||
use criterion::{black_box, criterion_group, criterion_main, Bencher, Criterion}; | ||
|
||
const TIMESTAMP_FORMAT: &str = "%Y-%m-%d %H:%M:%S%.f"; | ||
const TIMESTAMP_FORMAT_PGJDBC: &str = "%Y-%m-%d %H:%M:%S%.f %#z"; | ||
|
||
/// Benches `NaiveDateTime::parse_from_str()`, letting it fail, and reparsing | ||
/// via `DateTime::parse_from_str()` with a "PGJDBC-formatted" timestamp string. | ||
fn timestamp_text_parse_reparse(c: &mut Criterion) { | ||
let run_benchmark = |b: &mut Bencher| { | ||
b.iter(|| { | ||
{ | ||
let input = "2024-02-13 18:35:23.176-08"; | ||
let res = NaiveDateTime::parse_from_str(input, TIMESTAMP_FORMAT); | ||
if res.is_err() { | ||
let _ = DateTime::<FixedOffset>::parse_from_str(input, TIMESTAMP_FORMAT_PGJDBC) | ||
.unwrap(); | ||
} | ||
}; | ||
black_box(()) | ||
}) | ||
}; | ||
|
||
c.benchmark_group("timestamp_text_reparse") | ||
.bench_function("reparse", run_benchmark); | ||
} | ||
|
||
/// Benches `NaiveDateTime::parse_and_remainder()`, and passing the `remainder` to | ||
/// `FixedOffset::from_str()` - modifying the `remainder` to be "timezone formatted" | ||
/// as PGJDBC drops the minutes from the UTC offset (for most timezones). | ||
fn timestamp_text_parse_offsets(c: &mut Criterion) { | ||
let run_benchmark = |b: &mut Bencher| { | ||
b.iter(|| { | ||
{ | ||
let input = "2024-02-13 18:35:23.176-08"; | ||
let (datetime, timezone_tag) = | ||
NaiveDateTime::parse_and_remainder(input, TIMESTAMP_FORMAT).unwrap(); | ||
|
||
let mut pgjdbc_tz_tag = timezone_tag.to_owned(); | ||
pgjdbc_tz_tag.push_str(String::from("00").as_str()); | ||
let offset = FixedOffset::from_str(&pgjdbc_tz_tag).unwrap(); | ||
let _ = offset.from_utc_datetime(&datetime); | ||
}; | ||
black_box(()) | ||
}) | ||
}; | ||
|
||
c.benchmark_group("timestamp_text_parse") | ||
.bench_function("offsets", run_benchmark); | ||
} | ||
|
||
criterion_group!( | ||
benches, | ||
timestamp_text_parse_offsets, | ||
timestamp_text_parse_reparse | ||
); | ||
criterion_main!(benches); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters