This commit is contained in:
parent
aa2ff7b2f0
commit
2f3113f55d
11742 changed files with 1223940 additions and 0 deletions
119
unikernel/duniverse/ocaml-caqti/shared/postgresql_conv.ml
Normal file
119
unikernel/duniverse/ocaml-caqti/shared/postgresql_conv.ml
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
(* Copyright (C) 2022--2023 Petter A. Urkedal <paurkedal@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version, with the LGPL-3.0 Linking Exception.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* and the LGPL-3.0 Linking Exception along with this library. If not, see
|
||||
* <http://www.gnu.org/licenses/> and <https://spdx.org>, respectively.
|
||||
*)
|
||||
|
||||
open Caqti_platform
|
||||
open Printf
|
||||
|
||||
let bool_of_pgstring = function
|
||||
| "t" -> true
|
||||
| "f" -> false
|
||||
| _ -> invalid_arg "Pg_ext.bool_of_string"
|
||||
|
||||
let pgstring_of_bool = function true -> "t" | false -> "f"
|
||||
|
||||
let pdate_of_pgstring = Conv.pdate_of_iso8601
|
||||
|
||||
let pgstring_of_ptime x =
|
||||
Ptime.to_rfc3339 ~space:true ~tz_offset_s:0 ~frac_s:6 x
|
||||
|
||||
let pgstring_of_ptime_span t =
|
||||
let is_neg = Ptime.Span.compare t Ptime.Span.zero < 0 in
|
||||
let d, ps = Ptime.Span.(to_d_ps (abs t ))in
|
||||
let buf = Buffer.create 32 in
|
||||
if d <> 0 then bprintf buf "%d days " (if is_neg then -d else d);
|
||||
let s, ps = Int64.(div ps 1_000_000_000_000L |> to_int,
|
||||
rem ps 1_000_000_000_000L) in
|
||||
let hour, s = s / 3600, s mod 3600 in
|
||||
let minute, s = s / 60, s mod 60 in
|
||||
if is_neg then Buffer.add_char buf '-';
|
||||
bprintf buf "%02d:%02d:%02d" hour minute s;
|
||||
if ps <> 0L then bprintf buf ".%06Ld" (Int64.div ps 1_000_000L);
|
||||
Buffer.contents buf
|
||||
|
||||
let ps_of_decimal s =
|
||||
try
|
||||
(match String.length s with
|
||||
| 2 ->
|
||||
Ok (Int64.(mul (of_string s) 1_000_000_000_000L))
|
||||
| n when n < 2 ->
|
||||
Error "Missing digits in seconds of interval string."
|
||||
| _ when s.[2] <> '.' ->
|
||||
Error "Expected period after seconds in interval string."
|
||||
| n ->
|
||||
let buf = Bytes.make 14 '0' in
|
||||
Bytes.blit_string s 0 buf 0 2;
|
||||
Bytes.blit_string s 3 buf 2 (min 12 (n - 3));
|
||||
Ok (Int64.of_string (Bytes.to_string buf)))
|
||||
with Failure _ ->
|
||||
Error "Seconds in interval string is not numeric."
|
||||
|
||||
let ps_of_hms s =
|
||||
(match String.split_on_char ':' s with
|
||||
| [hours; minutes; seconds] ->
|
||||
(try
|
||||
let hour = int_of_string hours in
|
||||
let minute = int_of_string minutes in
|
||||
(match ps_of_decimal seconds with
|
||||
| Ok ps ->
|
||||
let hm = Int64.of_int (abs hour * 60 + minute) in
|
||||
let ps = Int64.(add ps (mul hm 60_000_000_000_000L)) in
|
||||
Ok (if s.[0] = '-' then Int64.neg ps else ps)
|
||||
| Error msg -> Error msg)
|
||||
with Failure _ ->
|
||||
Error "Non-integer hour or minute in interval string.")
|
||||
| _ ->
|
||||
Error "Expected HH:MM:SS[.F] in interval string.")
|
||||
|
||||
let ptime_span_of_pgstring s =
|
||||
let span_of_d_ps (d, ps) =
|
||||
let d, ps =
|
||||
if Int64.compare ps Int64.zero >= 0
|
||||
then (d, ps)
|
||||
else (d - 1, Int64.add ps 86_400_000_000_000_000L) in
|
||||
(match Ptime.Span.of_d_ps (d, ps) with
|
||||
| Some t -> Ok t
|
||||
| None -> Error "Out for range for Ptime.span.") in
|
||||
try
|
||||
(match String.split_on_char ' ' s with
|
||||
| [d; "days"] ->
|
||||
span_of_d_ps (int_of_string d, 0L)
|
||||
| [d; "days"; hms] ->
|
||||
Result.bind (ps_of_hms hms) @@ fun ps ->
|
||||
span_of_d_ps (int_of_string d, ps)
|
||||
| [hms] ->
|
||||
Result.bind (ps_of_hms hms) @@ fun ps ->
|
||||
span_of_d_ps (0, ps)
|
||||
| _ ->
|
||||
Error "Unhandled interval format.")
|
||||
with Failure _ ->
|
||||
Error "Non-integer days in interval string."
|
||||
|
||||
let cause_of_sqlstate sqlstate =
|
||||
(match sqlstate.[0], sqlstate.[1], sqlstate with
|
||||
| '2', '3', "23001" -> `Restrict_violation
|
||||
| '2', '3', "23502" -> `Not_null_violation
|
||||
| '2', '3', "23503" -> `Foreign_key_violation
|
||||
| '2', '3', "23505" -> `Unique_violation
|
||||
| '2', '3', "23514" -> `Check_violation
|
||||
| '2', '3', "23P01" -> `Exclusion_violation
|
||||
| '2', '3', _ -> `Integrity_constraint_violation__don't_match
|
||||
| '5', '3', "53100" -> `Disk_full
|
||||
| '5', '3', "53200" -> `Out_of_memory
|
||||
| '5', '3', "53300" -> `Too_many_connections
|
||||
| '5', '3', "53400" -> `Configuration_limit_exceeded
|
||||
| '5', '3', _ -> `Insufficient_resources__don't_match
|
||||
| _ -> `Unspecified__don't_match)
|
||||
Loading…
Add table
Add a link
Reference in a new issue