1#![forbid(unsafe_code)]
2
3use super::*;
4
5pub fn build_lob_read_payload_with_seq(
6 locator: &[u8],
7 offset: u64,
8 amount: u64,
9 seq_num: u8,
10 ttc_field_version: u8,
11) -> Result<Vec<u8>> {
12 let locator_len =
13 u32::try_from(locator.len()).map_err(|_| ProtocolError::InvalidPacketLength {
14 length: locator.len(),
15 minimum: 0,
16 })?;
17 let mut writer = TtcWriter::new();
18 writer.write_function_code_with_seq(TNS_FUNC_LOB_OP, seq_num);
19 if ttc_field_version >= TNS_CCAP_FIELD_VERSION_23_1_EXT_1 {
20 writer.write_ub8(0);
21 }
22 writer.write_u8(1);
23 writer.write_ub4(locator_len);
24 writer.write_u8(0);
25 writer.write_ub4(0);
26 writer.write_ub4(0);
27 writer.write_ub4(0);
28 writer.write_u8(0);
29 writer.write_u8(0);
30 writer.write_u8(0);
31 writer.write_ub4(TNS_LOB_OP_READ);
32 writer.write_u8(0);
33 writer.write_u8(0);
34 writer.write_ub8(offset);
35 writer.write_ub8(0);
36 writer.write_u8(1);
37 for _ in 0..3 {
38 writer.write_u16be(0);
39 }
40 writer.write_raw(locator);
41 writer.write_ub8(amount);
42 Ok(writer.into_bytes())
43}
44
45#[allow(clippy::too_many_arguments)]
46pub(crate) fn write_lob_op_header(
47 writer: &mut TtcWriter,
48 locator: &[u8],
49 seq_num: u8,
50 ttc_field_version: u8,
51 operation: u32,
52 dest_length: u32,
53 source_offset: u64,
54 dest_offset: u64,
55 pointer_charset: bool,
56 pointer_null_lob: bool,
57 send_amount: bool,
58) -> Result<()> {
59 let locator_len =
60 u32::try_from(locator.len()).map_err(|_| ProtocolError::InvalidPacketLength {
61 length: locator.len(),
62 minimum: 0,
63 })?;
64 writer.write_function_code_with_seq(TNS_FUNC_LOB_OP, seq_num);
65 if ttc_field_version >= TNS_CCAP_FIELD_VERSION_23_1_EXT_1 {
66 writer.write_ub8(0);
67 }
68 writer.write_u8(1);
69 writer.write_ub4(locator_len);
70 writer.write_u8(0);
71 writer.write_ub4(dest_length);
72 writer.write_ub4(0);
73 writer.write_ub4(0);
74 writer.write_u8(u8::from(pointer_charset));
75 writer.write_u8(0);
76 writer.write_u8(u8::from(pointer_null_lob));
77 writer.write_ub4(operation);
78 writer.write_u8(0);
79 writer.write_u8(0);
80 writer.write_ub8(source_offset);
81 writer.write_ub8(dest_offset);
82 writer.write_u8(u8::from(send_amount));
83 for _ in 0..3 {
84 writer.write_u16be(0);
85 }
86 writer.write_raw(locator);
87 Ok(())
88}
89
90pub fn build_lob_create_temp_payload_with_seq(
91 ora_type_num: u8,
92 csfrm: u8,
93 seq_num: u8,
94 ttc_field_version: u8,
95) -> Result<Vec<u8>> {
96 let mut writer = TtcWriter::new();
97 write_lob_op_header(
98 &mut writer,
99 &[0; 40],
100 seq_num,
101 ttc_field_version,
102 TNS_LOB_OP_CREATE_TEMP,
103 TNS_DURATION_SESSION,
104 u64::from(csfrm),
105 u64::from(ora_type_num),
106 true,
107 true,
108 false,
109 )?;
110 writer.write_ub4(TNS_CHARSET_UTF8.into());
111 Ok(writer.into_bytes())
112}
113
114pub fn build_lob_write_payload_with_seq(
115 locator: &[u8],
116 offset: u64,
117 data: &[u8],
118 seq_num: u8,
119 ttc_field_version: u8,
120) -> Result<Vec<u8>> {
121 let mut writer = TtcWriter::new();
122 write_lob_op_header(
123 &mut writer,
124 locator,
125 seq_num,
126 ttc_field_version,
127 TNS_LOB_OP_WRITE,
128 0,
129 offset,
130 0,
131 false,
132 false,
133 false,
134 )?;
135 writer.write_u8(TNS_MSG_TYPE_LOB_DATA);
136 writer.write_bytes_with_length(data)?;
137 Ok(writer.into_bytes())
138}
139
140pub fn build_lob_trim_payload_with_seq(
141 locator: &[u8],
142 new_size: u64,
143 seq_num: u8,
144 ttc_field_version: u8,
145) -> Result<Vec<u8>> {
146 let mut writer = TtcWriter::new();
147 write_lob_op_header(
148 &mut writer,
149 locator,
150 seq_num,
151 ttc_field_version,
152 TNS_LOB_OP_TRIM,
153 0,
154 0,
155 0,
156 false,
157 false,
158 true,
159 )?;
160 writer.write_ub8(new_size);
161 Ok(writer.into_bytes())
162}
163
164pub fn lob_locator_is_temporary(locator: &[u8]) -> bool {
165 locator
166 .get(TNS_LOB_LOC_OFFSET_FLAG_1)
167 .is_some_and(|flags| flags & TNS_LOB_LOC_FLAGS_ABSTRACT != 0)
168 || locator
169 .get(TNS_LOB_LOC_OFFSET_FLAG_4)
170 .is_some_and(|flags| flags & TNS_LOB_LOC_FLAGS_TEMP != 0)
171}
172
173pub fn build_lob_free_temp_payload_with_seq(
174 locators: &[Vec<u8>],
175 seq_num: u8,
176 ttc_field_version: u8,
177) -> Result<Vec<u8>> {
178 let total_size = locators.iter().try_fold(0u32, |total, locator| {
179 let locator_len =
180 u32::try_from(locator.len()).map_err(|_| ProtocolError::InvalidPacketLength {
181 length: locator.len(),
182 minimum: 0,
183 })?;
184 total
185 .checked_add(locator_len)
186 .ok_or(ProtocolError::PacketTooLarge { length: usize::MAX })
187 })?;
188 let mut writer = TtcWriter::new();
189 writer.write_function_code_with_seq(TNS_FUNC_LOB_OP, seq_num);
190 if ttc_field_version >= TNS_CCAP_FIELD_VERSION_23_1_EXT_1 {
191 writer.write_ub8(0);
192 }
193 writer.write_u8(1);
194 writer.write_ub4(total_size);
195 writer.write_u8(0);
196 writer.write_ub4(0);
197 writer.write_ub4(0);
198 writer.write_ub4(0);
199 writer.write_u8(0);
200 writer.write_u8(0);
201 writer.write_u8(0);
202 writer.write_ub4(TNS_LOB_OP_FREE_TEMP | TNS_LOB_OP_ARRAY);
203 writer.write_u8(0);
204 writer.write_ub4(0);
205 writer.write_ub8(0);
206 writer.write_ub8(0);
207 writer.write_u8(0);
208 writer.write_u8(0);
209 writer.write_ub4(0);
210 writer.write_u8(0);
211 writer.write_ub4(0);
212 writer.write_u8(0);
213 writer.write_ub4(0);
214 for locator in locators {
215 writer.write_raw(locator);
216 }
217 Ok(writer.into_bytes())
218}
219
220pub fn parse_lob_read_response(
221 payload: &[u8],
222 capabilities: ClientCapabilities,
223 locator: &[u8],
224) -> Result<LobReadResult> {
225 parse_lob_op_response(payload, capabilities, locator, false, true)
226}
227
228pub fn parse_lob_create_temp_response(
229 payload: &[u8],
230 capabilities: ClientCapabilities,
231) -> Result<LobReadResult> {
232 parse_lob_op_response(payload, capabilities, &[0; 40], true, false)
233}
234
235pub fn parse_lob_write_response(
236 payload: &[u8],
237 capabilities: ClientCapabilities,
238 locator: &[u8],
239) -> Result<LobReadResult> {
240 parse_lob_op_response(payload, capabilities, locator, false, false)
241}
242
243pub fn parse_lob_trim_response(
244 payload: &[u8],
245 capabilities: ClientCapabilities,
246 locator: &[u8],
247) -> Result<LobReadResult> {
248 parse_lob_op_response(payload, capabilities, locator, false, true)
249}
250
251pub fn parse_lob_free_temp_response(
252 payload: &[u8],
253 capabilities: ClientCapabilities,
254 returned_parameter_len: usize,
255) -> Result<()> {
256 let mut reader = TtcReader::new(payload);
257 while reader.remaining() > 0 {
258 let message_type = reader.read_u8()?;
259 match message_type {
260 0 => {}
261 TNS_MSG_TYPE_STATUS => {
262 let _call_status = reader.read_ub4()?;
263 let _seq = reader.read_ub2()?;
264 }
265 TNS_MSG_TYPE_SERVER_SIDE_PIGGYBACK => {
266 let _ = skip_server_side_piggyback(&mut reader)?;
267 }
268 TNS_MSG_TYPE_END_OF_RESPONSE => break,
269 TNS_MSG_TYPE_ERROR => {
270 let info = parse_server_error_info(&mut reader, capabilities.ttc_field_version)?;
271 if info.number != 0 {
272 return Err(ProtocolError::ServerError(info.message));
273 }
274 }
275 TNS_MSG_TYPE_PARAMETER => reader.skip(returned_parameter_len)?,
276 _ => {
277 return Err(ProtocolError::UnknownMessageType {
278 message_type,
279 position: reader.position().saturating_sub(1),
280 })
281 }
282 }
283 }
284 Ok(())
285}
286
287pub fn parse_plain_function_response(
293 payload: &[u8],
294 capabilities: ClientCapabilities,
295) -> Result<bool> {
296 let mut reader = TtcReader::new(payload);
297 let mut txn_in_progress = false;
298 while reader.remaining() > 0 {
299 let message_type = reader.read_u8()?;
300 match message_type {
301 0 => {}
302 TNS_MSG_TYPE_STATUS => {
303 let call_status = reader.read_ub4()?;
304 let _seq = reader.read_ub2()?;
305 txn_in_progress = call_status & TNS_EOCS_FLAGS_TXN_IN_PROGRESS != 0;
306 }
307 TNS_MSG_TYPE_SERVER_SIDE_PIGGYBACK => {
308 let _ = skip_server_side_piggyback(&mut reader)?;
309 }
310 TNS_MSG_TYPE_END_OF_RESPONSE => break,
311 TNS_MSG_TYPE_ERROR => {
312 let info = parse_server_error_info(&mut reader, capabilities.ttc_field_version)?;
313 txn_in_progress = info.call_status & TNS_EOCS_FLAGS_TXN_IN_PROGRESS != 0;
316 if info.number != 0 {
317 return Err(ProtocolError::ServerError(info.message));
318 }
319 }
320 _ => break,
321 }
322 }
323 Ok(txn_in_progress)
324}
325
326pub(crate) fn parse_lob_op_response(
327 payload: &[u8],
328 capabilities: ClientCapabilities,
329 locator: &[u8],
330 is_create_temp: bool,
331 read_amount: bool,
332) -> Result<LobReadResult> {
333 let mut reader = TtcReader::new(payload);
334 let mut result = LobReadResult {
335 locator: locator.to_vec(),
336 ..LobReadResult::default()
337 };
338 while reader.remaining() > 0 {
339 let message_type = reader.read_u8()?;
340 match message_type {
341 0 => {}
342 TNS_MSG_TYPE_LOB_DATA => {
343 result.data = reader.read_bytes()?;
344 }
345 TNS_MSG_TYPE_PARAMETER => {
346 if !result.locator.is_empty() {
347 result.locator = reader.read_raw(result.locator.len())?.to_vec();
348 }
349 if is_create_temp {
350 let _charset = reader.read_ub2()?;
351 reader.skip(1)?;
352 } else if read_amount {
353 let amount = reader.read_sb8()?;
354 if amount > 0 {
355 result.amount = amount as u64;
356 }
357 }
358 }
359 TNS_MSG_TYPE_STATUS => {
360 let _call_status = reader.read_ub4()?;
361 let _seq = reader.read_ub2()?;
362 }
363 TNS_MSG_TYPE_SERVER_SIDE_PIGGYBACK => {
364 let _ = skip_server_side_piggyback(&mut reader)?;
365 }
366 TNS_MSG_TYPE_END_OF_RESPONSE => break,
367 TNS_MSG_TYPE_ERROR => {
368 let info = parse_server_error_info(&mut reader, capabilities.ttc_field_version)?;
369 if info.number != 0 {
370 return Err(ProtocolError::ServerError(info.message));
371 }
372 }
373 _ => {
374 return Err(ProtocolError::UnknownMessageType {
375 message_type,
376 position: reader.position().saturating_sub(1),
377 })
378 }
379 }
380 }
381 Ok(result)
382}