8000 Encoding client message · postgres-haskell/postgres-wire@f3bf8a6 · GitHub
[go: up one dir, main page]

Skip to content

Commit f3bf8a6

Browse files
Encoding client message
1 parent 2e1ccce commit f3bf8a6

File tree

2 files changed

+67
-9
lines changed

2 files changed

+67
-9
lines changed

src/Database/PostgreSQL/Protocol/Encoders.hs

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@ import Data.Int
55
import Data.Monoid
66
import Data.ByteString.Lazy as BL
77
import Data.ByteString.Builder
8+
import Data.Foldable
9+
import qualified Data.Vector as V
810
import qualified Data.ByteString as B
911

1012
import Database.PostgreSQL.Protocol.Types
13+
1114
-- | Protocol Version 3.0, major version in the first word16
1215
currentVersion :: Int32
1316
currentVersion = 3 * 256 * 256
@@ -24,8 +27,55 @@ encodeStartMessage (StartupMessage uname dbname) =
2427
encodeStartMessage SSLRequest = undefined
2528

2629
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
2875

76+
encodeFormat :: Format -> Builder
77+
encodeFormat Text = int32BE 0
78+
encodeFormat Binary = int32BE 1
2979

3080
----------
3181
-- Utils
@@ -35,9 +85,10 @@ encodeClientMessage = undefined
3585
pgString :: B.ByteString -> Builder
3686
pgString s = byteString s <> word8 0
3787

38-
prependHeader :: Builder -> Char -> Builder
39-
prependHeader builder c =
88+
prependHeader :: Char -> Builder -> Builder
89+
prependHeader c builder =
4090
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)
4293
in char8 c <> int32BE len <> lazyByteString payload
4394

src/Database/PostgreSQL/Protocol/Types.hs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
module Database.PostgreSQL.Protocol.Types where
22

33
import Data.Word
4+
import Data.Int
45
import qualified Data.ByteString as B
56
import qualified Data.Vector as V
67

78
type PortalName = B.ByteString
89
type StatementName = B.ByteString
9-
type Oid = Word32
10+
type Oid = Int32
1011
-- maybe distinguish sql for extended query and simple query
1112
type StatementSQL = B.ByteString
1213
type PasswordText = B.ByteString
@@ -20,6 +21,7 @@ data TransactionStatus
2021
= TransactionIdle
2122
| TransactionInProgress
2223
| TransactionFailed
24+
deriving (Show)
2325

2426
data Format = Text | Binary
2527
deriving (Show)
@@ -34,14 +36,13 @@ data AuthResponse
3436
| AuthenticationGSS
3537
| AuthenticationSSPI
3638
| AuthenticationGSSContinue B.ByteString
39+
deriving (Show)
3740

3841
data ClientMessage
3942
= Bind PortalName StatementName
40-
(V.Vector Format) -- parameter format codes
43+
Format -- parameter format code, one format for all
4144
(V.Vector B.ByteString) -- the values of parameters
42-
(V.Vector Format) -- format codes of result,
43-
-- maybe chaneg to one number
44-
-- to apply code to all result columns
45+
Format -- to apply code to all result columns
4546
-- Postgres use one command `close` for closing both statements and
4647
-- portals, but we distinguish them
4748
| CloseStatement StatementName
@@ -53,17 +54,20 @@ data ClientMessage
5354
| Execute PortalName
5455
| Flush
5556
| Parse StatementName StatementSQL (V.Vector Oid)
57+
-- TODO maybe distinguish plain passwords and encrypted
5658
| PasswordMessage PasswordText
5759
| Query StatementSQL
5860
| Sync
5961
| Terminate
62+
deriving (Show)
6063

6164
type Username = B.ByteString
6265
type DatabaseName = B.ByteString
6366

6467
data StartMessage
6568
= StartupMessage Username DatabaseName
6669
| SSLRequest
70+
deriving (Show)
6771

6872

6973

@@ -117,4 +121,7 @@ data FieldDescription = FieldDescription
117121
-- * AuthenticationSCMCredential IS deprecated since postgres 9.1
118122
-- * NOTICE execute command can have number of rows to receive, but we
119123
-- dont support this feature
124+
-- * NOTICE bind command can have different formats for parameters and results
125+
-- but we assume that there will be one format for all. Maybe extend it in
126+
-- the future.
120127

0 commit comments

Comments
 (0)
0