persistent-sqlite 2.13.3.1 can serialize UTCTime values that are not lexicographically ordered
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 3/5
- Thời gian dự kiến
- 1-2 ngày
- Mức phù hợp với người mới
- 68/100
Hướng nghiên cứu
Bắt đầu với bản tái hiện được cung cấp trong Main.hs và chạy các lệnh stack build && stack exec demo được nêu để quan sát các giá trị SQLite đã lưu và phép so sánh thất bại. Truy vết điểm vào của quá trình tuần tự hóa UTCTime trong persistent-sqlite, sau đó xác minh rằng assertion về thứ tự của bản tái hiện đã thành công, trong khi các timestamp có và không có phần giây lẻ vẫn được sắp xếp theo thứ tự thời gian.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
since persistent-sqlite 2.13.3.1 serializes UTCTime using %FT%T%QZ, lexicographic ordering becomes incorrect when timestamps are identical up to the second but differ in fractional precision:
a) 2018-12-31T23:47:07Z
b) 2018-12-31T23:47:07.002Z
^
This produces unexpected results when querying UTCTime columns; SQLite compares Z vs ., so it treats a) as greater, even though chronologically it is lesser.
In this case, mixed presence of the fractional part (Z vs .xxxZ) is what breaks ordering, but it can also happen anytime Z is compared with another value, such as
a) 2018-12-31T23:47:07.1Z
b) 2018-12-31T23:47:07.102Z
^
would also exhibit incorrect lexicographic ordering
related: https://github.com/yesodweb/persistent/pull/1585
suggestion: avoid storing the time zone specifier Z, to restore lexicographic ordering. According to https://www.sqlite.org/datatype3.html#date_and_time_datatype , an example ISO8601 string is ("YYYY-MM-DD HH:MM:SS.SSS"), therefore emitting with UTCTime format %FT%T%Q (no Z), should be sufficient. (alternatively, use a fixed-length encoding)
demo below:
cabal-version: 2.4
name: demo
version: 0.1.0.0
build-type: Simple
executable demo
main-is: Main.hs
hs-source-dirs: .
default-language: Haskell2010
build-depends: base >= 4.14 && < 5, persistent, persistent-sqlite == 2.13.3.1, time, text, HUnit
{-# LANGUAGE GHC2024, OverloadedStrings, QuasiQuotes, TemplateHaskell, TypeFamilies, UndecidableInstances #-}
module Main where
import Control.Monad.IO.Class
import Data.Maybe (fromJust)
import Data.Text (Text)
import Data.Time (UTCTime, parseTimeM, defaultTimeLocale, addUTCTime)
import Database.Persist
import Database.Persist.Sql
import Database.Persist.Sqlite (runSqlite)
import Database.Persist.TH
import Test.HUnit (assertEqual, assertBool)
share
[mkPersist sqlSettings, mkMigrate "migrateAll"]
[persistLowerCase|
Thing
time UTCTime
deriving Show
|]
main :: IO ()
main = runSqlite ":memory:" $ do
runMigration migrateAll
let time0 = fromJust $ parseTimeM True defaultTimeLocale "%FT%T%QZ" "2018-12-31T23:47:07Z" :: UTCTime
let time0plus2ms = addUTCTime 0.002 time0
liftIO $ putStrLn $ "time0 = " ++ show time0
liftIO $ putStrLn $ "time0plus2ms = " ++ show time0plus2ms
_ <- insert (Thing time0)
_ <- insert (Thing time0plus2ms)
stored <- rawSql
"SELECT time FROM thing ORDER BY rowid"
[]
liftIO $ do
putStrLn "Stored SQLite values:"
mapM_ print (stored :: [Single Text])
putStrLn ""
liftIO $ putStrLn $ "rowsLtTime0plus2ms <- selectList [ThingTime <. time0plus2ms] []"
rowsLtTime0plus2ms <- selectList [ThingTime <. time0plus2ms] []
liftIO $ do
putStrLn $ "Rows where ThingTime < time0plus2ms: " ++ show (length rowsLtTime0plus2ms)
mapM_ print rowsLtTime0plus2ms
liftIO $ assertBool "(time0 < time0plus2ms)" (time0 < time0plus2ms)
liftIO $ assertEqual "Expected one row earlier than time0plus2ms" 1 (length rowsLtTime0plus2ms)
$ stack build && stack exec demo
demo> build (exe) with ghc-9.10.3
Preprocessing executable 'demo' for demo-0.1.0.0...
Building executable 'demo' for demo-0.1.0.0...
[1 of 1] Compiling Main [Source file changed]
[2 of 2] Linking .stack-work\dist\1a191874\build\demo\demo.exe [Objects changed]
demo> copy/register
Installing executable demo in C:\dev\repro2\.stack-work\install\b4648b89\bin
Migrating: CREATE TABLE "thing"("id" INTEGER PRIMARY KEY,"time" TIMESTAMP NOT NULL)
time0 = 2018-12-31 23:47:07 UTC
time0plus2ms = 2018-12-31 23:47:07.002 UTC
Stored SQLite values:
Single {unSingle = "2018-12-31T23:47:07Z"}
Single {unSingle = "2018-12-31T23:47:07.002Z"}
ltrows <- selectList [ThingTime <. time0plus2ms] []
Rows where ThingTime < time0plus2ms: 0
demo.EXE: HUnitFailure (Just (SrcLoc {srcLocPackage = "demo-0.1.0.0-HlclNsrU49f7ZwMNbAJYlP-demo", srcLocModule = "Main", srcLocFile = "Main.hs", srcLocStartLine = 61, srcLocStartCol = 14, srcLocEndLine = 61, srcLocEndCol = 25})) (ExpectedButGot (Just "Expected one row earlier than time0plus2ms") "1" "0")
- Ngôn ngữ chính
- Haskell
- Star
- 486
- Fork
- 307
- Chỉ số merge pull request
- Không có pull request nào được merge trong 30 ngày
Chuẩn bị môi trường
- Có Dockerfile hoặc tệp Docker Compose
- Có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của yesodweb/persistent
-
use aeson >= 2.3.0.0 to avoid HSEC-2026-0007Có thể đã có người làm Có pull request liên kết đang mở hoặc đã được merge. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 70/100
yesodweb/persistent#1635 · 1 bình luận · 1 reaction ·
-
Typos in Documentation for Database.Persist.QuasiCó thể đã có người làm @000wahab000 đã nhận 61 ngày trước. Đang mở
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 82/100
yesodweb/persistent#1634 ·
-
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 48/100
yesodweb/persistent#1643 ·
-
Độ khó 3/5 1-2 ngày Mức phù hợp với người mới 70/100
yesodweb/persistent#1642 ·
-
Độ khó 3/5 1-2 ngày Mức phù hợp với người mới 42/100
yesodweb/persistent#1641 ·
Tất cả issue của yesodweb/persistent
Issue tương tự
-
enhancement triage
Độ khó 1/5 1-3 giờ Mức phù hợp với người mới 66/100
simplex-chat/simplex-chat#8043 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
area:zones rules-correctness
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
-
needs triage type: bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 67/100
haskell/cabal#12525 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 3 ngày
-
validateXmirOptions error message is missing the word 'option'Có thể đã có người làm @opusstudiohq-max đã nhận 1 ngày trước. Đang mở
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 90/100
objectionary/phino#2256 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
30-minutes algorithm any-language codewars dart easy elixir hackerrank hacktoberfest haskell help wanted interview-prep julia leetcode lua open-source r scala students zig
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
Huerte/algo-solutions-python#163 ·
Maintainer thường phản hồi trong vòng 1 ngày