@@ -5,9 +5,12 @@ import Data.Int
5
5
import Data.Monoid
6
6
import Data.ByteString.Lazy as BL
7
7
import Data.ByteString.Builder
8
+ import Data.Foldable
9
+ import qualified Data.Vector as V
8
10
import qualified Data.ByteString as B
9
11
10
12
import Database.PostgreSQL.Protocol.Types
13
+
11
14
-- | Protocol Version 3.0, major version in the first word16
12
15
currentVersion :: Int32
13
16
currentVersion = 3 * 256 * 256
@@ -24,8 +27,55 @@ encodeStartMessage (StartupMessage uname dbname) =
24
27
encodeStartMessage SSLRequest = undefined
25
28
26
29
encodeClientMessage :: ClientMessage -> Builder
27
- encodeClientMessage = undefined
30
+ encodeClientMessage (Bind portalName stmtName paramFormat values resultFormat)
31
+ = prependHeader ' B' $
32
+ pgString portalName <>
33
+ pgString stmtName <>
34
+ -- the specified format code is applied to all parameters
35
+ int16BE 1 <>
36
+ encodeFormat paramFormat <>
37
+ int16BE (fromIntegral $ V. length values) <>
38
+ -- TODO -1 indicates a NULL parameter value. No value bytes
39
+ -- follow in the NULL case.
40
+ fold ((\ v -> int32BE (fromIntegral $ B. length v) <> byteString v)
41
+ <$> values) <>
42
+ -- the specified format code is applied to all result columns (if any)
43
+ int16BE 1 <>
44
+ encodeFormat resultFormat
45
+ encodeClientMessage (CloseStatement stmtName)
46
+ = prependHeader ' C' $ char8 ' S' <> pgString stmtName
47
+ encodeClientMessage (ClosePortal portalName)
48
+ = prependHeader ' C' $ char8 ' P' <> pgString portalName
49
+ encodeClientMessage (DescribeStatement stmtName)
50
+ = prependHeader ' D' $ char8 ' S' <> pgString stmtName
51
+ encodeClientMessage (DescribePortal portalName)
52
+ = prependHeader ' D' $ char8 ' P' <> pgString portalName
53
+ encodeClientMessage (Execute portalName)
54
+ = prependHeader ' E' $
55
+ pgString portalName <>
56
+ -- Maximum number of rows to return, if portal contains a query that
57
+ -- returns rows (ignored otherwise). Zero denotes "no limit".
58
+ int32BE 0
59
+ encodeClientMessage Flush
60
+ = prependHeader ' H' mempty
61
+ encodeClientMessage (Parse stmtName stmt oids)
62
+ = prependHeader ' P' $
63
+ pgString stmtName <>
64
+ pgString stmt <>
65
+ int16BE (fromIntegral $ V. length oids) <>
66
+ fold (int32BE <$> oids)
67
+ encodeClientMessage (PasswordMessage passText)
68
+ = prependHeader ' p' $ pgString passText
69
+ encodeClientMessage (Query stmt)
70
+ = prependHeader ' Q' $ pgString stmt
71
+ encodeClientMessage Sync
72
+ = prependHeader ' S' mempty
73
+ encodeClientMessage Terminate
74
+ = prependHeader ' X' mempty
28
75
76
+ encodeFormat :: Format -> Builder
77
+ encodeFormat Text = int32BE 0
78
+ encodeFormat Binary = int32BE 1
29
79
30
80
----------
31
81
-- Utils
@@ -35,9 +85,10 @@ encodeClientMessage = undefined
35
85
pgString :: B. ByteString -> Builder
36
86
pgString s = byteString s <> word8 0
37
87
38
- prependHeader :: Builder -> Char -> Builder
39
- prependHeader builder c =
88
+ prependHeader :: Char -> Builder -> Builder
89
+ prependHeader c builder =
40
90
let payload = toLazyByteString builder
41
- len = fromIntegral $ BL. length payload
91
+ -- Length includes itself but not the first message-type byte
92
+ len = 4 + fromIntegral (BL. length payload)
42
93
in char8 c <> int32BE len <> lazyByteString payload
43
94
0 commit comments