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