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