tiberius/tds/codec/
rpc_request.rs

1use super::{AllHeaderTy, Encode, ALL_HEADERS_LEN_TX};
2use crate::{tds::codec::ColumnData, BytesMutWithTypeInfo, Result};
3use bytes::{BufMut, BytesMut};
4use enumflags2::{bitflags, BitFlags};
5use std::borrow::BorrowMut;
6use std::borrow::Cow;
7
8#[bitflags]
9#[repr(u8)]
10#[derive(Copy, Clone, Debug, PartialEq, Eq)]
11pub enum RpcStatus {
12    ByRefValue = 1 << 0,
13    DefaultValue = 1 << 1,
14    // reserved
15    Encrypted = 1 << 3,
16}
17
18#[bitflags]
19#[repr(u16)]
20#[derive(Copy, Clone, Debug, PartialEq, Eq)]
21pub enum RpcOption {
22    WithRecomp = 1 << 0,
23    NoMeta = 1 << 1,
24    ReuseMeta = 1 << 2,
25}
26
27#[derive(Debug)]
28pub struct TokenRpcRequest<'a> {
29    proc_id: RpcProcIdValue<'a>,
30    flags: BitFlags<RpcOption>,
31    params: Vec<RpcParam<'a>>,
32    transaction_desc: [u8; 8],
33}
34
35impl<'a> TokenRpcRequest<'a> {
36    pub fn new<I>(proc_id: I, params: Vec<RpcParam<'a>>, transaction_desc: [u8; 8]) -> Self
37    where
38        I: Into<RpcProcIdValue<'a>>,
39    {
40        Self {
41            proc_id: proc_id.into(),
42            flags: BitFlags::empty(),
43            params,
44            transaction_desc,
45        }
46    }
47}
48
49#[derive(Debug)]
50pub struct RpcParam<'a> {
51    pub name: Cow<'a, str>,
52    pub flags: BitFlags<RpcStatus>,
53    pub value: ColumnData<'a>,
54}
55
56/// 2.2.6.6 RPC Request
57#[allow(dead_code)]
58#[repr(u8)]
59#[derive(Clone, Copy, Debug)]
60pub enum RpcProcId {
61    CursorOpen = 2,
62    CursorFetch = 7,
63    CursorClose = 9,
64    ExecuteSQL = 10,
65    Prepare = 11,
66    Execute = 12,
67    PrepExec = 13,
68    Unprepare = 15,
69}
70
71#[derive(Debug)]
72#[allow(dead_code)]
73pub enum RpcProcIdValue<'a> {
74    Name(Cow<'a, str>),
75    Id(RpcProcId),
76}
77
78impl<'a, S> From<S> for RpcProcIdValue<'a>
79where
80    S: Into<Cow<'a, str>>,
81{
82    fn from(s: S) -> Self {
83        Self::Name(s.into())
84    }
85}
86
87impl<'a> From<RpcProcId> for RpcProcIdValue<'a> {
88    fn from(id: RpcProcId) -> Self {
89        Self::Id(id)
90    }
91}
92
93impl<'a> Encode<BytesMut> for TokenRpcRequest<'a> {
94    fn encode(self, dst: &mut BytesMut) -> Result<()> {
95        dst.put_u32_le(ALL_HEADERS_LEN_TX as u32);
96        dst.put_u32_le(ALL_HEADERS_LEN_TX as u32 - 4);
97        dst.put_u16_le(AllHeaderTy::TransactionDescriptor as u16);
98        dst.put_slice(&self.transaction_desc);
99        dst.put_u32_le(1);
100
101        match self.proc_id {
102            RpcProcIdValue::Id(ref id) => {
103                let val = (0xffff_u32) | ((*id as u16) as u32) << 16;
104                dst.put_u32_le(val);
105            }
106            RpcProcIdValue::Name(ref _name) => {
107                //let (left_bytes, _) = try!(write_varchar::<u16>(&mut cursor, name, 0));
108                //assert_eq!(left_bytes, 0);
109                todo!()
110            }
111        }
112
113        dst.put_u16_le(self.flags.bits());
114
115        for param in self.params.into_iter() {
116            param.encode(dst)?;
117        }
118
119        Ok(())
120    }
121}
122
123impl<'a> Encode<BytesMut> for RpcParam<'a> {
124    fn encode(self, dst: &mut BytesMut) -> Result<()> {
125        let len_pos = dst.len();
126        let mut length = 0u8;
127
128        dst.put_u8(length);
129
130        for codepoint in self.name.encode_utf16() {
131            length += 1;
132            dst.put_u16_le(codepoint);
133        }
134
135        dst.put_u8(self.flags.bits());
136
137        let mut dst_fi = BytesMutWithTypeInfo::new(dst);
138        self.value.encode(&mut dst_fi)?;
139
140        let dst: &mut [u8] = dst.borrow_mut();
141        dst[len_pos] = length;
142
143        Ok(())
144    }
145}