sqlx_core/mssql/protocol/
rpc.rs

1use bitflags::bitflags;
2use either::Either;
3
4use crate::io::Encode;
5use crate::mssql::io::MssqlBufMutExt;
6use crate::mssql::protocol::header::{AllHeaders, Header};
7use crate::mssql::MssqlArguments;
8
9pub(crate) struct RpcRequest<'a> {
10    pub(crate) transaction_descriptor: u64,
11
12    // the procedure can be encoded as a u16 of a built-in or the name for a custom one
13    pub(crate) procedure: Either<&'a str, Procedure>,
14    pub(crate) options: OptionFlags,
15    pub(crate) arguments: &'a MssqlArguments,
16}
17
18#[derive(Debug, Copy, Clone)]
19#[repr(u16)]
20#[allow(dead_code)]
21pub(crate) enum Procedure {
22    Cursor = 1,
23    CursorOpen = 2,
24    CursorPrepare = 3,
25    CursorExecute = 4,
26    CursorPrepareExecute = 5,
27    CursorUnprepare = 6,
28    CursorFetch = 7,
29    CursorOption = 8,
30    CursorClose = 9,
31    ExecuteSql = 10,
32    Prepare = 11,
33    Execute = 12,
34    PrepareExecute = 13,
35    PrepareExecuteRpc = 14,
36    Unprepare = 15,
37}
38
39bitflags! {
40    pub(crate) struct OptionFlags: u16 {
41        const WITH_RECOMPILE = 1;
42
43        // The server sends NoMetaData only if fNoMetadata is set to 1 in the request
44        const NO_META_DATA = 2;
45
46        // 1 if the metadata has not changed from the previous call and the server SHOULD reuse
47        // its cached metadata (the metadata MUST still be sent).
48        const REUSE_META_DATA = 4;
49    }
50}
51
52bitflags! {
53    pub(crate) struct StatusFlags: u8 {
54        // if the parameter is passed by reference (OUTPUT parameter) or
55        // 0 if parameter is passed by value
56        const BY_REF_VALUE = 1;
57
58        // 1 if the parameter being passed is to be the default value
59        const DEFAULT_VALUE = 2;
60
61        // 1 if the parameter that is being passed is encrypted. This flag is valid
62        // only when the column encryption feature is negotiated by client and server
63        // and is turned on
64        const ENCRYPTED = 8;
65    }
66}
67
68impl Encode<'_> for RpcRequest<'_> {
69    fn encode_with(&self, buf: &mut Vec<u8>, _: ()) {
70        AllHeaders(&[Header::TransactionDescriptor {
71            outstanding_request_count: 1,
72            transaction_descriptor: self.transaction_descriptor,
73        }])
74        .encode(buf);
75
76        match &self.procedure {
77            Either::Left(name) => {
78                buf.extend(&(name.len() as u16).to_le_bytes());
79                buf.put_utf16_str(name);
80            }
81
82            Either::Right(id) => {
83                buf.extend(&(0xffff_u16).to_le_bytes());
84                buf.extend(&(*id as u16).to_le_bytes());
85            }
86        }
87
88        buf.extend(&self.options.bits.to_le_bytes());
89        buf.extend(&self.arguments.data);
90    }
91}
92
93// TODO: Test serialization of this?