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 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#[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 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}