Skip to content

Commit 953fb6c

Browse files
Sam Morrisoniamed2
andauthored
Add binary interval parsing (#237)
* Add binary interval parsing * Fix argument types in functions Co-authored-by: Eric Davies <[email protected]> * Add function explanation * Bump version * Fix variable name Co-authored-by: Eric Davies <[email protected]>
1 parent 19ae93d commit 953fb6c

File tree

3 files changed

+47
-2
lines changed

3 files changed

+47
-2
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "LibPQ"
22
uuid = "194296ae-ab2e-5f79-8cd4-7183a0a5a0d1"
33
license = "MIT"
4-
version = "1.8.1"
4+
version = "1.9.0"
55

66
[deps]
77
BinaryProvider = "b99e7846-7c00-51b0-8f62-c81ae34c0232"

src/parsing.jl

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,47 @@ function _interval_regex()
434434
return Regex(String(take!(io)))
435435
end
436436

437+
function _split_period(period::T, ::Type{P}) where {T<:Period,P<:Period}
438+
q, r = divrem(period, convert(T, P(1)))
439+
return P(q), r
440+
end
441+
442+
# Splits internal interval types into the expected period types from
443+
# https://www.postgresql.org/docs/10/datatype-datetime.html#DATATYPE-INTERVAL-INPUT
444+
function _split_periods(months, days, microseconds)
445+
periods = Period[]
446+
447+
push!(periods, _split_period(months, Year)...)
448+
push!(periods, _split_period(days, Week)...)
449+
450+
seconds, ms = _split_period(microseconds, Second)
451+
minutes, seconds = _split_period(seconds, Minute)
452+
hours, minutes = _split_period(minutes, Hour)
453+
454+
push!(periods, hours, minutes, seconds, ms)
455+
filter!(!iszero, periods)
456+
457+
return Dates.CompoundPeriod(periods)
458+
end
459+
460+
# Parse binary into postgres interval
461+
function Base.parse(
462+
::Type{Dates.CompoundPeriod}, pqv::PQBinaryValue{PQ_SYSTEM_TYPES[:interval]}
463+
)
464+
current_pointer = data_pointer(pqv)
465+
466+
microsecond = Microsecond(ntoh(unsafe_load(Ptr{Int64}(current_pointer))))
467+
current_pointer += sizeof(Int64)
468+
469+
day = Day(ntoh(unsafe_load(Ptr{Int32}(current_pointer))))
470+
current_pointer += sizeof(Int32)
471+
472+
month = Month(ntoh(unsafe_load(Ptr{Int32}(current_pointer))))
473+
474+
# Split combined periods to match the output from text queries
475+
return _split_periods(Month(month), Day(day), Microsecond(microsecond))
476+
end
477+
437478
# parse the iso_8601 interval output format
438479
# https://www.postgresql.org/docs/10/datatype-datetime.html#DATATYPE-INTERVAL-OUTPUT
439480
function pqparse(::Type{Dates.CompoundPeriod}, str::AbstractString)

test/runtests.jl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1153,7 +1153,6 @@ end
11531153
binary_not_implemented_types = [
11541154
Decimal,
11551155
Time,
1156-
Dates.CompoundPeriod,
11571156
Array,
11581157
OffsetArray,
11591158
]
@@ -1235,6 +1234,11 @@ end
12351234
("INTERVAL '1000 years 7 weeks'", Dates.CompoundPeriod(Period[Year(1000), Day(7 * 7)])),
12361235
("INTERVAL '1 day -1 hour'", Dates.CompoundPeriod(Period[Day(1), Hour(-1)])),
12371236
("INTERVAL '-1 month 1 day'", Dates.CompoundPeriod(Period[Month(-1), Day(1)])),
1237+
# With fields specification
1238+
("INTERVAL '1 day 2:03:04' HOUR TO MINUTE", Dates.CompoundPeriod(Period[Day(1), Hour(2), Minute(3)])),
1239+
# With precision
1240+
("INTERVAL '6.1001 seconds' SECOND(0)", Dates.CompoundPeriod(Period[Second(6)])),
1241+
("INTERVAL '6.1001 seconds' SECOND(2)", Dates.CompoundPeriod(Period[Second(6), Millisecond(100)])),
12381242
("'{{{1,2,3},{4,5,6}}}'::int2[]", Array{Union{Int16, Missing}}(reshape(Int16[1 2 3; 4 5 6], 1, 2, 3))),
12391243
("'{}'::int2[]", Union{Missing, Int16}[]),
12401244
("'{{{1,2,3},{4,5,6}}}'::int4[]", Array{Union{Int32, Missing}}(reshape(Int32[1 2 3; 4 5 6], 1, 2, 3))),

0 commit comments

Comments
 (0)