1#![forbid(unsafe_code)]
2
3use super::*;
4
5impl BindValue {
6 pub(crate) fn is_output_only(&self) -> bool {
7 matches!(self, BindValue::Output { .. })
8 || matches!(self, BindValue::ReturnOutput { .. })
9 || matches!(self, BindValue::ObjectOutput { .. })
10 || matches!(self, BindValue::Array { values, .. } if values.is_empty())
11 }
12
13 pub(crate) fn is_return_output(&self) -> bool {
14 matches!(self, BindValue::ReturnOutput { .. })
15 || matches!(
16 self,
17 BindValue::ObjectOutput {
18 is_return: true,
19 ..
20 }
21 )
22 }
23}
24
25pub(crate) fn write_bind_metadata_with_type(
26 writer: &mut TtcWriter,
27 value: &BindValue,
28 ora_type_num: u8,
29 csfrm: u8,
30 buffer_size: u32,
31 ttc_field_version: u8,
32) -> Result<()> {
33 let (flags, max_elements) = match value {
34 BindValue::Array { max_elements, .. } => {
35 (TNS_BIND_USE_INDICATORS | TNS_BIND_ARRAY, *max_elements)
36 }
37 _ => (TNS_BIND_USE_INDICATORS, 0),
38 };
39 let buffer_size = if ora_type_num == ORA_TYPE_NUM_JSON {
42 TNS_JSON_MAX_LENGTH
43 } else {
44 buffer_size
45 };
46 writer.write_u8(ora_type_num);
47 writer.write_u8(flags);
48 writer.write_u8(0);
49 writer.write_u8(0);
50 writer.write_ub4(buffer_size);
51 writer.write_ub4(max_elements);
52 let cont_flags = if matches!(
53 ora_type_num,
54 ORA_TYPE_NUM_CLOB | ORA_TYPE_NUM_BLOB | ORA_TYPE_NUM_VECTOR | ORA_TYPE_NUM_JSON
55 ) {
56 TNS_LOB_PREFETCH_FLAG
57 } else {
58 0
59 };
60 writer.write_ub8(cont_flags);
61 if let BindValue::ObjectOutput { oid, version, .. }
62 | BindValue::ObjectInput { oid, version, .. } = value
63 {
64 writer.write_bytes_with_two_lengths(Some(oid))?;
65 writer.write_ub4(*version);
66 } else {
67 writer.write_ub4(0);
68 writer.write_ub2(0);
69 }
70 if csfrm != 0 {
71 writer.write_ub2(TNS_CHARSET_UTF8);
72 } else {
73 writer.write_ub2(0);
74 }
75 writer.write_u8(csfrm);
76 let lob_prefetch_length = match ora_type_num {
79 ORA_TYPE_NUM_VECTOR => TNS_VECTOR_MAX_LENGTH,
80 ORA_TYPE_NUM_JSON => TNS_JSON_MAX_LENGTH,
81 _ => 0,
82 };
83 writer.write_ub4(lob_prefetch_length);
84 if version_gates::carries_oaccolid(ttc_field_version) {
93 writer.write_ub4(0); }
95 Ok(())
96}
97
98pub fn bind_value_type_info(value: &BindValue) -> Option<BindTypeInfo> {
99 let (ora_type_num, csfrm, buffer_size) = match value {
100 BindValue::Null => return None,
101 BindValue::TypedNull {
102 ora_type_num,
103 csfrm,
104 buffer_size,
105 }
106 | BindValue::Output {
107 ora_type_num,
108 csfrm,
109 buffer_size,
110 }
111 | BindValue::ReturnOutput {
112 ora_type_num,
113 csfrm,
114 buffer_size,
115 } => (*ora_type_num, *csfrm, (*buffer_size).max(1)),
116 BindValue::ObjectOutput { buffer_size, .. }
117 | BindValue::ObjectInput { buffer_size, .. } => {
118 (ORA_TYPE_NUM_OBJECT, 0, (*buffer_size).max(1))
119 }
120 BindValue::Text(value) => {
126 let buffer_size = u32::try_from(value.chars().count())
127 .unwrap_or(u32::MAX)
128 .saturating_mul(4)
129 .max(1);
130 (ORA_TYPE_NUM_VARCHAR, CS_FORM_IMPLICIT, buffer_size)
131 }
132 BindValue::Raw(value) => {
133 let buffer_size = u32::try_from(value.len()).unwrap_or(u32::MAX).max(1);
134 (ORA_TYPE_NUM_RAW, 0, buffer_size)
135 }
136 BindValue::Lob {
137 ora_type_num,
138 csfrm,
139 ..
140 } => (*ora_type_num, *csfrm, 1),
141 BindValue::Number(_) => (ORA_TYPE_NUM_NUMBER, 0, ORA_TYPE_SIZE_NUMBER),
142 BindValue::BinaryInteger(_) => (ORA_TYPE_NUM_BINARY_INTEGER, 0, ORA_TYPE_SIZE_NUMBER),
143 BindValue::Boolean(_) => (ORA_TYPE_NUM_BOOLEAN, 0, ORA_TYPE_SIZE_BOOLEAN),
144 BindValue::BinaryDouble(_) => (ORA_TYPE_NUM_BINARY_DOUBLE, 0, ORA_TYPE_SIZE_BINARY_DOUBLE),
145 BindValue::BinaryFloat(_) => (ORA_TYPE_NUM_BINARY_FLOAT, 0, ORA_TYPE_SIZE_BINARY_FLOAT),
146 BindValue::IntervalDS { .. } => (ORA_TYPE_NUM_INTERVAL_DS, 0, ORA_TYPE_SIZE_INTERVAL_DS),
147 BindValue::IntervalYM { .. } => (ORA_TYPE_NUM_INTERVAL_YM, 0, ORA_TYPE_SIZE_INTERVAL_YM),
148 BindValue::DateTime { .. } => (ORA_TYPE_NUM_DATE, 0, ORA_TYPE_SIZE_DATE),
149 BindValue::Timestamp { ora_type_num, .. } => (
150 *ora_type_num,
151 0,
152 if *ora_type_num == ORA_TYPE_NUM_TIMESTAMP_TZ {
153 ORA_TYPE_SIZE_TIMESTAMP_TZ
154 } else {
155 ORA_TYPE_SIZE_TIMESTAMP
156 },
157 ),
158 BindValue::TimestampTz { .. } => (ORA_TYPE_NUM_TIMESTAMP_TZ, 0, ORA_TYPE_SIZE_TIMESTAMP_TZ),
159 BindValue::Array {
160 ora_type_num,
161 csfrm,
162 buffer_size,
163 ..
164 } => (*ora_type_num, *csfrm, (*buffer_size).max(1)),
165 BindValue::Vector(_) => (ORA_TYPE_NUM_VECTOR, 0, TNS_VECTOR_MAX_LENGTH),
168 BindValue::Json(_) => (ORA_TYPE_NUM_JSON, 0, 1),
174 BindValue::Cursor { .. } => (ORA_TYPE_NUM_CURSOR, 0, 4),
175 };
176 Some(BindTypeInfo {
177 ora_type_num,
178 csfrm,
179 buffer_size,
180 })
181}
182
183pub fn define_metadata_from_bind(source: &ColumnMetadata, value: &BindValue) -> ColumnMetadata {
184 let Some(mut info) = bind_value_type_info(value) else {
185 return source.clone();
186 };
187 if source.ora_type_num == ORA_TYPE_NUM_CLOB
188 && matches!(
189 info.ora_type_num,
190 ORA_TYPE_NUM_CHAR | ORA_TYPE_NUM_LONG | ORA_TYPE_NUM_VARCHAR
191 )
192 {
193 info.ora_type_num = ORA_TYPE_NUM_LONG;
194 if source.csfrm != 0 {
195 info.csfrm = source.csfrm;
196 }
197 }
198 let mut metadata = source.clone();
199 metadata.ora_type_num = info.ora_type_num;
200 metadata.csfrm = info.csfrm;
201 if info.ora_type_num == ORA_TYPE_NUM_LONG {
202 metadata.buffer_size = TNS_MAX_LONG_LENGTH;
203 metadata.max_size = 0;
204 } else {
205 metadata.buffer_size = info.buffer_size.max(1);
206 metadata.max_size = info.buffer_size.max(1);
207 }
208 metadata
209}
210
211pub fn adjust_refetch_metadata(previous: &ColumnMetadata, current: &mut ColumnMetadata) -> bool {
218 if current.ora_type_num == ORA_TYPE_NUM_CLOB
219 && matches!(
220 previous.ora_type_num,
221 ORA_TYPE_NUM_CHAR | ORA_TYPE_NUM_LONG | ORA_TYPE_NUM_VARCHAR
222 )
223 {
224 current.ora_type_num = ORA_TYPE_NUM_LONG;
225 current.csfrm = previous.csfrm;
226 current.buffer_size = TNS_MAX_LONG_LENGTH;
227 current.max_size = 0;
228 return true;
229 }
230 if current.ora_type_num == ORA_TYPE_NUM_BLOB
231 && matches!(
232 previous.ora_type_num,
233 ORA_TYPE_NUM_RAW | ORA_TYPE_NUM_LONG_RAW
234 )
235 {
236 current.ora_type_num = ORA_TYPE_NUM_LONG_RAW;
237 current.csfrm = 0;
238 current.buffer_size = TNS_MAX_LONG_LENGTH;
239 current.max_size = 0;
240 return true;
241 }
242 false
243}
244
245pub fn output_bind(value: BindValue) -> BindValue {
246 match value {
247 BindValue::ObjectOutput {
248 schema,
249 type_name,
250 oid,
251 version,
252 buffer_size,
253 ..
254 } => BindValue::ObjectOutput {
255 schema,
256 type_name,
257 oid,
258 version,
259 buffer_size: buffer_size.max(1),
260 is_return: false,
261 },
262 value => {
263 let info = bind_value_type_info(&value).unwrap_or(BindTypeInfo {
264 ora_type_num: ORA_TYPE_NUM_VARCHAR,
265 csfrm: CS_FORM_IMPLICIT,
266 buffer_size: 1,
267 });
268 BindValue::Output {
269 ora_type_num: info.ora_type_num,
270 csfrm: info.csfrm,
271 buffer_size: info.buffer_size,
272 }
273 }
274 }
275}
276
277pub fn returning_output_bind(value: BindValue) -> BindValue {
278 match value {
279 BindValue::ObjectOutput {
280 schema,
281 type_name,
282 oid,
283 version,
284 buffer_size,
285 ..
286 } => BindValue::ObjectOutput {
287 schema,
288 type_name,
289 oid,
290 version,
291 buffer_size: buffer_size.max(1),
292 is_return: true,
293 },
294 value => {
295 let info = bind_value_type_info(&value).unwrap_or(BindTypeInfo {
296 ora_type_num: ORA_TYPE_NUM_VARCHAR,
297 csfrm: CS_FORM_IMPLICIT,
298 buffer_size: 1,
299 });
300 BindValue::ReturnOutput {
301 ora_type_num: info.ora_type_num,
302 csfrm: info.csfrm,
303 buffer_size: info.buffer_size,
304 }
305 }
306 }
307}
308
309pub fn cursor_bind_template() -> BindValue {
310 BindValue::TypedNull {
311 ora_type_num: ORA_TYPE_NUM_CURSOR,
312 csfrm: 0,
313 buffer_size: 4,
314 }
315}
316
317pub fn is_cursor_bind_template(value: &BindValue) -> bool {
318 matches!(
319 value,
320 BindValue::TypedNull {
321 ora_type_num: ORA_TYPE_NUM_CURSOR,
322 ..
323 }
324 )
325}
326
327pub fn public_dbtype_name_from_type_name(type_name: &str) -> &'static str {
328 match type_name {
329 "NUMBER" | "DB_TYPE_NUMBER" | "int" | "float" | "Decimal" => "DB_TYPE_NUMBER",
330 "NATIVE_INT" | "DB_TYPE_BINARY_INTEGER" => "DB_TYPE_BINARY_INTEGER",
331 "NATIVE_FLOAT" | "DB_TYPE_BINARY_DOUBLE" => "DB_TYPE_BINARY_DOUBLE",
332 "DB_TYPE_BINARY_FLOAT" | "BINARY_FLOAT" => "DB_TYPE_BINARY_FLOAT",
333 "DB_TYPE_BOOLEAN" | "BOOLEAN" | "bool" => "DB_TYPE_BOOLEAN",
334 "DB_TYPE_INTERVAL_DS" | "INTERVAL DAY TO SECOND" | "timedelta" => "DB_TYPE_INTERVAL_DS",
335 "DB_TYPE_INTERVAL_YM" | "INTERVAL YEAR TO MONTH" | "IntervalYM" => "DB_TYPE_INTERVAL_YM",
336 "DB_TYPE_BFILE" | "BFILE" => "DB_TYPE_BFILE",
337 "DB_TYPE_JSON" | "JSON" => "DB_TYPE_JSON",
338 "STRING" | "DB_TYPE_VARCHAR" | "str" => "DB_TYPE_VARCHAR",
339 "DB_TYPE_CHAR" => "DB_TYPE_CHAR",
340 "DB_TYPE_NCHAR" => "DB_TYPE_NCHAR",
341 "DB_TYPE_NVARCHAR" => "DB_TYPE_NVARCHAR",
342 "DB_TYPE_CLOB" | "CLOB" => "DB_TYPE_CLOB",
343 "DB_TYPE_NCLOB" | "NCLOB" => "DB_TYPE_NCLOB",
344 "DB_TYPE_BLOB" | "BLOB" => "DB_TYPE_BLOB",
345 "DB_TYPE_LONG" | "LONG" | "LONG_STRING" => "DB_TYPE_LONG",
346 "DB_TYPE_LONG_NVARCHAR" | "LONG NVARCHAR" => "DB_TYPE_LONG_NVARCHAR",
347 "DB_TYPE_LONG_RAW" | "LONG RAW" | "LONG_BINARY" => "DB_TYPE_LONG_RAW",
348 "DB_TYPE_RAW" | "BINARY" | "bytes" => "DB_TYPE_RAW",
349 "ROWID" | "DB_TYPE_ROWID" => "DB_TYPE_ROWID",
350 "DB_TYPE_UROWID" => "DB_TYPE_UROWID",
351 "DATETIME" | "DB_TYPE_DATE" | "date" | "datetime" => "DB_TYPE_DATE",
352 "DB_TYPE_TIMESTAMP" | "TIMESTAMP" => "DB_TYPE_TIMESTAMP",
353 "DB_TYPE_TIMESTAMP_LTZ" | "TIMESTAMP WITH LOCAL TIME ZONE" => "DB_TYPE_TIMESTAMP_LTZ",
354 "DB_TYPE_TIMESTAMP_TZ" | "TIMESTAMP WITH TIME ZONE" => "DB_TYPE_TIMESTAMP_TZ",
355 "DB_TYPE_CURSOR" | "CURSOR" => "DB_TYPE_CURSOR",
356 "DB_TYPE_VECTOR" | "VECTOR" => "DB_TYPE_VECTOR",
357 _ => "DB_TYPE_VARCHAR",
358 }
359}
360
361pub fn column_metadata_is_xmltype(metadata: &ColumnMetadata) -> bool {
362 metadata
363 .object_schema
364 .as_deref()
365 .is_some_and(|schema| schema.eq_ignore_ascii_case("SYS"))
366 && metadata
367 .object_type_name
368 .as_deref()
369 .is_some_and(|name| name.eq_ignore_ascii_case("XMLTYPE"))
370}
371
372pub fn public_dbtype_name_from_column_metadata(metadata: &ColumnMetadata) -> &'static str {
373 if column_metadata_is_xmltype(metadata) {
374 return "DB_TYPE_XMLTYPE";
375 }
376 match (metadata.ora_type_num, metadata.csfrm) {
377 (ORA_TYPE_NUM_LONG, CS_FORM_NCHAR) => "DB_TYPE_LONG_NVARCHAR",
378 (ORA_TYPE_NUM_LONG, _) => "DB_TYPE_LONG",
379 (ORA_TYPE_NUM_LONG_RAW, _) => "DB_TYPE_LONG_RAW",
380 (ORA_TYPE_NUM_VARCHAR, CS_FORM_NCHAR) => "DB_TYPE_NVARCHAR",
381 (ORA_TYPE_NUM_CHAR, CS_FORM_NCHAR) => "DB_TYPE_NCHAR",
382 (ORA_TYPE_NUM_CHAR, _) => "DB_TYPE_CHAR",
383 (ORA_TYPE_NUM_VARCHAR, _) => "DB_TYPE_VARCHAR",
384 (ORA_TYPE_NUM_RAW, _) => "DB_TYPE_RAW",
385 (ORA_TYPE_NUM_ROWID, _) => "DB_TYPE_ROWID",
386 (ORA_TYPE_NUM_UROWID, _) => "DB_TYPE_UROWID",
387 (ORA_TYPE_NUM_BINARY_DOUBLE, _) => "DB_TYPE_BINARY_DOUBLE",
388 (ORA_TYPE_NUM_BINARY_FLOAT, _) => "DB_TYPE_BINARY_FLOAT",
389 (ORA_TYPE_NUM_BINARY_INTEGER, _) => "DB_TYPE_BINARY_INTEGER",
390 (ORA_TYPE_NUM_NUMBER, _) => "DB_TYPE_NUMBER",
391 (ORA_TYPE_NUM_CURSOR, _) => "DB_TYPE_CURSOR",
392 (ORA_TYPE_NUM_OBJECT, _) => "DB_TYPE_OBJECT",
393 (ORA_TYPE_NUM_CLOB, CS_FORM_NCHAR) => "DB_TYPE_NCLOB",
394 (ORA_TYPE_NUM_CLOB, _) => "DB_TYPE_CLOB",
395 (ORA_TYPE_NUM_BLOB, _) => "DB_TYPE_BLOB",
396 (ORA_TYPE_NUM_BFILE, _) => "DB_TYPE_BFILE",
397 (ORA_TYPE_NUM_DATE, _) => "DB_TYPE_DATE",
398 (ORA_TYPE_NUM_TIMESTAMP, _) => "DB_TYPE_TIMESTAMP",
399 (ORA_TYPE_NUM_TIMESTAMP_LTZ, _) => "DB_TYPE_TIMESTAMP_LTZ",
400 (ORA_TYPE_NUM_TIMESTAMP_TZ, _) => "DB_TYPE_TIMESTAMP_TZ",
401 (ORA_TYPE_NUM_INTERVAL_DS, _) => "DB_TYPE_INTERVAL_DS",
402 (ORA_TYPE_NUM_INTERVAL_YM, _) => "DB_TYPE_INTERVAL_YM",
403 (ORA_TYPE_NUM_BOOLEAN, _) => "DB_TYPE_BOOLEAN",
404 (ORA_TYPE_NUM_VECTOR, _) => "DB_TYPE_VECTOR",
405 (ORA_TYPE_NUM_JSON, _) => "DB_TYPE_JSON",
406 _ => "DB_TYPE_VARCHAR",
407 }
408}
409
410pub fn public_dbtype_size_info(dbtype_name: &str) -> (u32, u32) {
414 match dbtype_name {
415 "DB_TYPE_BFILE" => (0, 4000),
416 "DB_TYPE_BINARY_DOUBLE" => (0, ORA_TYPE_SIZE_BINARY_DOUBLE),
417 "DB_TYPE_BINARY_FLOAT" => (0, ORA_TYPE_SIZE_BINARY_FLOAT),
418 "DB_TYPE_BINARY_INTEGER" | "DB_TYPE_NUMBER" => (0, ORA_TYPE_SIZE_NUMBER),
419 "DB_TYPE_BLOB" | "DB_TYPE_CLOB" | "DB_TYPE_NCLOB" => (0, 112),
420 "DB_TYPE_BOOLEAN" => (0, ORA_TYPE_SIZE_BOOLEAN),
421 "DB_TYPE_CHAR" | "DB_TYPE_NCHAR" => (2000, 4),
422 "DB_TYPE_CURSOR" => (0, 4),
423 "DB_TYPE_DATE" => (0, ORA_TYPE_SIZE_DATE),
424 "DB_TYPE_INTERVAL_DS" => (0, ORA_TYPE_SIZE_INTERVAL_DS),
425 "DB_TYPE_INTERVAL_YM" => (0, 5),
426 "DB_TYPE_LONG" | "DB_TYPE_LONG_NVARCHAR" | "DB_TYPE_LONG_RAW" => (0, TNS_MAX_LONG_LENGTH),
427 "DB_TYPE_NVARCHAR" | "DB_TYPE_VARCHAR" => (4000, 4),
428 "DB_TYPE_RAW" => (4000, 1),
429 "DB_TYPE_ROWID" => (0, ORA_TYPE_SIZE_ROWID),
430 "DB_TYPE_TIMESTAMP" | "DB_TYPE_TIMESTAMP_LTZ" => (0, ORA_TYPE_SIZE_TIMESTAMP),
431 "DB_TYPE_TIMESTAMP_TZ" => (0, ORA_TYPE_SIZE_TIMESTAMP_TZ),
432 "DB_TYPE_JSON" | "DB_TYPE_VECTOR" => (0, 1),
433 _ => (0, 0),
434 }
435}
436
437pub fn check_fetch_conversion(
446 source: &ColumnMetadata,
447 to_ora_type_num: u8,
448 to_csfrm: u8,
449) -> Option<ColumnMetadata> {
450 const CHAR_TYPES: [u8; 3] = [ORA_TYPE_NUM_CHAR, ORA_TYPE_NUM_LONG, ORA_TYPE_NUM_VARCHAR];
451 let from = source.ora_type_num;
452 let to = to_ora_type_num;
453 if from == to {
454 return Some(source.clone());
455 }
456 let supported = match from {
457 ORA_TYPE_NUM_BINARY_DOUBLE | ORA_TYPE_NUM_BINARY_FLOAT => {
458 matches!(
459 to,
460 ORA_TYPE_NUM_BINARY_INTEGER
461 | ORA_TYPE_NUM_BINARY_DOUBLE
462 | ORA_TYPE_NUM_BINARY_FLOAT
463 | ORA_TYPE_NUM_NUMBER
464 ) || CHAR_TYPES.contains(&to)
465 }
466 ORA_TYPE_NUM_BINARY_INTEGER => to == ORA_TYPE_NUM_NUMBER || CHAR_TYPES.contains(&to),
467 ORA_TYPE_NUM_BLOB => {
468 if matches!(to, ORA_TYPE_NUM_RAW | ORA_TYPE_NUM_LONG_RAW) {
469 let mut metadata = source.clone();
470 metadata.ora_type_num = ORA_TYPE_NUM_LONG_RAW;
471 metadata.csfrm = 0;
472 metadata.buffer_size = TNS_MAX_LONG_LENGTH;
473 metadata.max_size = 0;
474 return Some(metadata);
475 }
476 false
477 }
478 ORA_TYPE_NUM_CHAR | ORA_TYPE_NUM_LONG | ORA_TYPE_NUM_VARCHAR => {
479 matches!(
480 to,
481 ORA_TYPE_NUM_BINARY_DOUBLE
482 | ORA_TYPE_NUM_BINARY_FLOAT
483 | ORA_TYPE_NUM_NUMBER
484 | ORA_TYPE_NUM_BINARY_INTEGER
485 ) || CHAR_TYPES.contains(&to)
486 }
487 ORA_TYPE_NUM_CLOB => {
488 if CHAR_TYPES.contains(&to) {
489 let mut metadata = source.clone();
490 metadata.ora_type_num = ORA_TYPE_NUM_LONG;
491 metadata.buffer_size = TNS_MAX_LONG_LENGTH;
492 metadata.max_size = 0;
493 return Some(metadata);
494 }
495 false
496 }
497 ORA_TYPE_NUM_DATE
498 | ORA_TYPE_NUM_TIMESTAMP
499 | ORA_TYPE_NUM_TIMESTAMP_LTZ
500 | ORA_TYPE_NUM_TIMESTAMP_TZ => {
501 matches!(
502 to,
503 ORA_TYPE_NUM_DATE
504 | ORA_TYPE_NUM_TIMESTAMP
505 | ORA_TYPE_NUM_TIMESTAMP_LTZ
506 | ORA_TYPE_NUM_TIMESTAMP_TZ
507 ) || CHAR_TYPES.contains(&to)
508 }
509 ORA_TYPE_NUM_INTERVAL_DS | ORA_TYPE_NUM_INTERVAL_YM | ORA_TYPE_NUM_ROWID => {
510 CHAR_TYPES.contains(&to)
511 }
512 ORA_TYPE_NUM_NUMBER => {
513 matches!(
514 to,
515 ORA_TYPE_NUM_BINARY_INTEGER
516 | ORA_TYPE_NUM_BINARY_DOUBLE
517 | ORA_TYPE_NUM_BINARY_FLOAT
518 ) || CHAR_TYPES.contains(&to)
519 }
520 ORA_TYPE_NUM_JSON => {
521 if matches!(to, ORA_TYPE_NUM_CHAR | ORA_TYPE_NUM_VARCHAR) {
539 let mut metadata = source.clone();
540 metadata.ora_type_num = ORA_TYPE_NUM_VARCHAR;
541 metadata.csfrm = CS_FORM_IMPLICIT;
542 metadata.buffer_size = TNS_MAX_LONG_LENGTH;
543 metadata.max_size = 0;
544 return Some(metadata);
545 }
546 if to == ORA_TYPE_NUM_RAW {
550 let mut metadata = source.clone();
551 metadata.ora_type_num = ORA_TYPE_NUM_RAW;
552 metadata.csfrm = 0;
553 metadata.buffer_size = TNS_MAX_LONG_LENGTH;
554 metadata.max_size = 0;
555 return Some(metadata);
556 }
557 false
558 }
559 ORA_TYPE_NUM_VECTOR => {
560 if CHAR_TYPES.contains(&to) {
564 let mut metadata = source.clone();
565 metadata.ora_type_num = ORA_TYPE_NUM_LONG;
566 metadata.csfrm = CS_FORM_IMPLICIT;
567 metadata.buffer_size = TNS_MAX_LONG_LENGTH;
568 metadata.max_size = 0;
569 return Some(metadata);
570 }
571 if to == ORA_TYPE_NUM_CLOB {
572 let mut metadata = source.clone();
573 metadata.ora_type_num = ORA_TYPE_NUM_CLOB;
574 return Some(metadata);
575 }
576 false
577 }
578 _ => false,
579 };
580 let _ = to_csfrm;
581 if supported {
582 Some(source.clone())
583 } else {
584 None
585 }
586}
587
588pub fn public_dbtype_name_from_oracle_type_name(type_name: &str) -> &'static str {
589 let upper = type_name.to_ascii_uppercase();
590 if upper.starts_with("TIMESTAMP") {
591 if upper.contains("LOCAL TIME ZONE") || upper.contains("LOCAL TZ") {
592 return "DB_TYPE_TIMESTAMP_LTZ";
593 }
594 if upper.contains("TIME ZONE") || upper.contains("WITH TZ") {
595 return "DB_TYPE_TIMESTAMP_TZ";
596 }
597 return "DB_TYPE_TIMESTAMP";
598 }
599 match upper.as_str() {
600 "CHAR" => "DB_TYPE_CHAR",
601 "NCHAR" => "DB_TYPE_NCHAR",
602 "VARCHAR2" | "VARCHAR" => "DB_TYPE_VARCHAR",
603 "NVARCHAR2" | "NVARCHAR" => "DB_TYPE_NVARCHAR",
604 "RAW" => "DB_TYPE_RAW",
605 "DATE" => "DB_TYPE_DATE",
606 "TIMESTAMP" => "DB_TYPE_TIMESTAMP",
607 "TIMESTAMP WITH TIME ZONE" | "TIMESTAMP WITH TZ" => "DB_TYPE_TIMESTAMP_TZ",
608 "TIMESTAMP WITH LOCAL TIME ZONE" | "TIMESTAMP WITH LOCAL TZ" => "DB_TYPE_TIMESTAMP_LTZ",
609 "CLOB" => "DB_TYPE_CLOB",
610 "NCLOB" => "DB_TYPE_NCLOB",
611 "BLOB" => "DB_TYPE_BLOB",
612 "XMLTYPE" => "DB_TYPE_XMLTYPE",
613 "BINARY_FLOAT" => "DB_TYPE_BINARY_FLOAT",
614 "BINARY_DOUBLE" => "DB_TYPE_BINARY_DOUBLE",
615 "NUMBER" | "INTEGER" | "SMALLINT" | "REAL" | "DOUBLE PRECISION" | "FLOAT" => {
616 "DB_TYPE_NUMBER"
617 }
618 "BOOLEAN" | "PL/SQL BOOLEAN" => "DB_TYPE_BOOLEAN",
623 "BINARY_INTEGER" | "PLS_INTEGER" | "PL/SQL BINARY INTEGER" | "PL/SQL PLS INTEGER" => {
624 "DB_TYPE_BINARY_INTEGER"
625 }
626 "LONG" => "DB_TYPE_LONG",
627 "LONG RAW" => "DB_TYPE_LONG_RAW",
628 "ROWID" => "DB_TYPE_ROWID",
629 "UROWID" => "DB_TYPE_UROWID",
630 "BFILE" => "DB_TYPE_BFILE",
631 "JSON" => "DB_TYPE_JSON",
632 "VECTOR" => "DB_TYPE_VECTOR",
633 "INTERVAL DAY TO SECOND" => "DB_TYPE_INTERVAL_DS",
634 "INTERVAL YEAR TO MONTH" => "DB_TYPE_INTERVAL_YM",
635 _ => "DB_TYPE_OBJECT",
638 }
639}
640
641pub fn dbobject_attr_precision_scale(
642 type_name: &str,
643 precision: Option<i8>,
644 scale: Option<i8>,
645) -> (i8, i8) {
646 match type_name.to_ascii_uppercase().as_str() {
647 "NUMBER" => (
648 precision.unwrap_or(if scale == Some(0) { 38 } else { 0 }),
649 scale.unwrap_or(-127),
650 ),
651 "INTEGER" | "SMALLINT" => (precision.unwrap_or(38), scale.unwrap_or(0)),
652 "REAL" => (precision.unwrap_or(63), scale.unwrap_or(-127)),
653 "DOUBLE PRECISION" | "FLOAT" => (precision.unwrap_or(126), scale.unwrap_or(-127)),
654 _ => (0, 0),
655 }
656}
657
658pub fn dbobject_attr_max_size(type_name: &str, length: Option<u32>) -> u32 {
659 let length = length.unwrap_or(0);
660 match type_name.to_ascii_uppercase().as_str() {
661 "NCHAR" | "NVARCHAR2" | "NVARCHAR" => length.saturating_mul(2),
662 _ => length,
663 }
664}
665
666pub fn dbobject_rowtype_attr_max_size(
667 type_name: &str,
668 data_length: Option<u32>,
669 char_length: Option<u32>,
670) -> u32 {
671 match type_name.to_ascii_uppercase().as_str() {
672 "CHAR" | "VARCHAR" | "VARCHAR2" | "RAW" => data_length.unwrap_or(0),
673 "NCHAR" | "NVARCHAR" | "NVARCHAR2" => dbobject_attr_max_size(
674 type_name,
675 char_length.filter(|length| *length > 0).or(data_length),
676 ),
677 _ => 0,
678 }
679}
680
681pub fn public_dbtype_name_from_bind(value: &BindValue) -> &'static str {
682 match value {
683 BindValue::TypedNull {
684 ora_type_num,
685 csfrm,
686 ..
687 }
688 | BindValue::Output {
689 ora_type_num,
690 csfrm,
691 ..
692 }
693 | BindValue::ReturnOutput {
694 ora_type_num,
695 csfrm,
696 ..
697 }
698 | BindValue::Array {
699 ora_type_num,
700 csfrm,
701 ..
702 } => public_dbtype_name_from_type_info(*ora_type_num, *csfrm),
703 BindValue::ObjectOutput { .. } | BindValue::ObjectInput { .. } => "DB_TYPE_OBJECT",
704 BindValue::Text(_) => "DB_TYPE_VARCHAR",
705 BindValue::Raw(_) => "DB_TYPE_RAW",
706 BindValue::Lob {
707 ora_type_num,
708 csfrm,
709 ..
710 } => match (*ora_type_num, *csfrm) {
711 (ORA_TYPE_NUM_BLOB, _) => "DB_TYPE_BLOB",
712 (ORA_TYPE_NUM_CLOB, CS_FORM_NCHAR) => "DB_TYPE_NCLOB",
713 (ORA_TYPE_NUM_CLOB, _) => "DB_TYPE_CLOB",
714 _ => "DB_TYPE_CLOB",
715 },
716 BindValue::Number(_) => "DB_TYPE_NUMBER",
717 BindValue::BinaryInteger(_) => "DB_TYPE_BINARY_INTEGER",
718 BindValue::BinaryDouble(_) => "DB_TYPE_BINARY_DOUBLE",
719 BindValue::BinaryFloat(_) => "DB_TYPE_BINARY_FLOAT",
720 BindValue::Boolean(_) => "DB_TYPE_BOOLEAN",
721 BindValue::IntervalDS { .. } => "DB_TYPE_INTERVAL_DS",
722 BindValue::IntervalYM { .. } => "DB_TYPE_INTERVAL_YM",
723 BindValue::DateTime { .. } => "DB_TYPE_DATE",
724 BindValue::Timestamp { ora_type_num, .. } => match *ora_type_num {
725 ORA_TYPE_NUM_TIMESTAMP_LTZ => "DB_TYPE_TIMESTAMP_LTZ",
726 ORA_TYPE_NUM_TIMESTAMP_TZ => "DB_TYPE_TIMESTAMP_TZ",
727 _ => "DB_TYPE_TIMESTAMP",
728 },
729 BindValue::TimestampTz { .. } => "DB_TYPE_TIMESTAMP_TZ",
730 BindValue::Vector(_) => "DB_TYPE_VECTOR",
731 BindValue::Json(_) => "DB_TYPE_JSON",
732 BindValue::Cursor { .. } => "DB_TYPE_CURSOR",
733 BindValue::Null => "DB_TYPE_VARCHAR",
734 }
735}
736
737pub fn bind_template_from_type_name(type_name: &str, size: u32) -> BindValue {
738 let text_buffer_size = if size == 0 { 4000 } else { size.max(1) };
739 let nchar_buffer_size = text_buffer_size.saturating_mul(4);
740 match type_name {
741 "NUMBER" | "DB_TYPE_NUMBER" | "int" | "float" | "Decimal" => BindValue::TypedNull {
742 ora_type_num: ORA_TYPE_NUM_NUMBER,
743 csfrm: 0,
744 buffer_size: ORA_TYPE_SIZE_NUMBER,
745 },
746 "NATIVE_INT" | "DB_TYPE_BINARY_INTEGER" => BindValue::TypedNull {
747 ora_type_num: ORA_TYPE_NUM_BINARY_INTEGER,
748 csfrm: 0,
749 buffer_size: ORA_TYPE_SIZE_NUMBER,
750 },
751 "NATIVE_FLOAT" | "DB_TYPE_BINARY_DOUBLE" => BindValue::TypedNull {
752 ora_type_num: ORA_TYPE_NUM_BINARY_DOUBLE,
753 csfrm: 0,
754 buffer_size: ORA_TYPE_SIZE_BINARY_DOUBLE,
755 },
756 "DB_TYPE_BINARY_FLOAT" | "BINARY_FLOAT" => BindValue::TypedNull {
757 ora_type_num: ORA_TYPE_NUM_BINARY_FLOAT,
758 csfrm: 0,
759 buffer_size: ORA_TYPE_SIZE_BINARY_FLOAT,
760 },
761 "DB_TYPE_BOOLEAN" | "BOOLEAN" | "bool" => BindValue::TypedNull {
762 ora_type_num: ORA_TYPE_NUM_BOOLEAN,
763 csfrm: 0,
764 buffer_size: ORA_TYPE_SIZE_BOOLEAN,
765 },
766 "DB_TYPE_INTERVAL_DS" | "INTERVAL DAY TO SECOND" | "timedelta" => BindValue::TypedNull {
767 ora_type_num: ORA_TYPE_NUM_INTERVAL_DS,
768 csfrm: 0,
769 buffer_size: ORA_TYPE_SIZE_INTERVAL_DS,
770 },
771 "DB_TYPE_INTERVAL_YM" | "INTERVAL YEAR TO MONTH" | "IntervalYM" => BindValue::TypedNull {
772 ora_type_num: ORA_TYPE_NUM_INTERVAL_YM,
773 csfrm: 0,
774 buffer_size: ORA_TYPE_SIZE_INTERVAL_YM,
775 },
776 "STRING" | "DB_TYPE_VARCHAR" | "DB_TYPE_CHAR" | "str" => BindValue::TypedNull {
777 ora_type_num: ORA_TYPE_NUM_VARCHAR,
778 csfrm: CS_FORM_IMPLICIT,
779 buffer_size: text_buffer_size,
780 },
781 "DB_TYPE_NCHAR" | "DB_TYPE_NVARCHAR" => BindValue::TypedNull {
782 ora_type_num: ORA_TYPE_NUM_VARCHAR,
783 csfrm: CS_FORM_NCHAR,
784 buffer_size: nchar_buffer_size,
785 },
786 "DB_TYPE_CLOB" | "CLOB" => BindValue::TypedNull {
787 ora_type_num: ORA_TYPE_NUM_LONG,
788 csfrm: CS_FORM_IMPLICIT,
789 buffer_size: TNS_MAX_LONG_LENGTH,
790 },
791 "DB_TYPE_NCLOB" | "NCLOB" => BindValue::TypedNull {
792 ora_type_num: ORA_TYPE_NUM_LONG,
793 csfrm: CS_FORM_NCHAR,
794 buffer_size: TNS_MAX_LONG_LENGTH,
795 },
796 "DB_TYPE_BLOB" | "BLOB" => BindValue::TypedNull {
797 ora_type_num: ORA_TYPE_NUM_LONG_RAW,
798 csfrm: 0,
799 buffer_size: TNS_MAX_LONG_LENGTH,
800 },
801 "DB_TYPE_LONG" | "LONG" | "LONG_STRING" => BindValue::TypedNull {
802 ora_type_num: ORA_TYPE_NUM_LONG,
803 csfrm: CS_FORM_IMPLICIT,
804 buffer_size: TNS_MAX_LONG_LENGTH,
805 },
806 "DB_TYPE_LONG_NVARCHAR" | "LONG NVARCHAR" => BindValue::TypedNull {
807 ora_type_num: ORA_TYPE_NUM_LONG,
808 csfrm: CS_FORM_NCHAR,
809 buffer_size: TNS_MAX_LONG_LENGTH,
810 },
811 "DB_TYPE_LONG_RAW" | "LONG RAW" | "LONG_BINARY" => BindValue::TypedNull {
812 ora_type_num: ORA_TYPE_NUM_LONG_RAW,
813 csfrm: 0,
814 buffer_size: TNS_MAX_LONG_LENGTH,
815 },
816 "DB_TYPE_RAW" | "BINARY" | "bytes" => BindValue::TypedNull {
817 ora_type_num: ORA_TYPE_NUM_RAW,
818 csfrm: 0,
819 buffer_size: size.max(1).max(4000),
820 },
821 "ROWID" | "DB_TYPE_ROWID" | "DB_TYPE_UROWID" => BindValue::TypedNull {
822 ora_type_num: ORA_TYPE_NUM_VARCHAR,
823 csfrm: CS_FORM_IMPLICIT,
824 buffer_size: 5267,
825 },
826 "DATETIME" | "DB_TYPE_DATE" | "date" | "datetime" => BindValue::TypedNull {
827 ora_type_num: ORA_TYPE_NUM_DATE,
828 csfrm: 0,
829 buffer_size: ORA_TYPE_SIZE_DATE,
830 },
831 "DB_TYPE_TIMESTAMP" | "TIMESTAMP" => BindValue::TypedNull {
832 ora_type_num: ORA_TYPE_NUM_TIMESTAMP,
833 csfrm: 0,
834 buffer_size: ORA_TYPE_SIZE_TIMESTAMP,
835 },
836 "DB_TYPE_TIMESTAMP_LTZ" | "TIMESTAMP WITH LOCAL TIME ZONE" => BindValue::TypedNull {
837 ora_type_num: ORA_TYPE_NUM_TIMESTAMP_LTZ,
838 csfrm: 0,
839 buffer_size: ORA_TYPE_SIZE_TIMESTAMP,
840 },
841 "DB_TYPE_TIMESTAMP_TZ" | "TIMESTAMP WITH TIME ZONE" => BindValue::TypedNull {
842 ora_type_num: ORA_TYPE_NUM_TIMESTAMP_TZ,
843 csfrm: 0,
844 buffer_size: ORA_TYPE_SIZE_TIMESTAMP_TZ,
845 },
846 "DB_TYPE_CURSOR" | "CURSOR" => cursor_bind_template(),
847 "DB_TYPE_VECTOR" | "VECTOR" => BindValue::TypedNull {
848 ora_type_num: ORA_TYPE_NUM_VECTOR,
849 csfrm: 0,
850 buffer_size: TNS_VECTOR_MAX_LENGTH,
851 },
852 "DB_TYPE_JSON" | "JSON" => BindValue::TypedNull {
853 ora_type_num: ORA_TYPE_NUM_JSON,
854 csfrm: 0,
855 buffer_size: TNS_VECTOR_MAX_LENGTH,
856 },
857 _ => BindValue::Null,
858 }
859}
860
861pub fn dbobject_element_bind_type_info(dbtype_name: &str, max_size: u32) -> BindTypeInfo {
862 let buffer_size = max_size.max(1);
863 let (ora_type_num, csfrm, buffer_size) = match dbtype_name {
864 "DB_TYPE_NUMBER" => (ORA_TYPE_NUM_NUMBER, 0, ORA_TYPE_SIZE_NUMBER),
865 "DB_TYPE_RAW" | "DB_TYPE_BLOB" => (ORA_TYPE_NUM_RAW, 0, buffer_size.max(4000)),
866 "DB_TYPE_NCHAR" | "DB_TYPE_NVARCHAR" | "DB_TYPE_NCLOB" => {
867 (ORA_TYPE_NUM_VARCHAR, CS_FORM_NCHAR, buffer_size.max(4000))
868 }
869 "DB_TYPE_DATE" => (ORA_TYPE_NUM_DATE, 0, ORA_TYPE_SIZE_DATE),
870 "DB_TYPE_TIMESTAMP" => (ORA_TYPE_NUM_TIMESTAMP, 0, ORA_TYPE_SIZE_TIMESTAMP),
871 "DB_TYPE_TIMESTAMP_LTZ" => (ORA_TYPE_NUM_TIMESTAMP_LTZ, 0, ORA_TYPE_SIZE_TIMESTAMP),
872 "DB_TYPE_TIMESTAMP_TZ" => (ORA_TYPE_NUM_TIMESTAMP_TZ, 0, ORA_TYPE_SIZE_TIMESTAMP_TZ),
873 _ => (
874 ORA_TYPE_NUM_VARCHAR,
875 CS_FORM_IMPLICIT,
876 buffer_size.max(4000),
877 ),
878 };
879 BindTypeInfo {
880 ora_type_num,
881 csfrm,
882 buffer_size,
883 }
884}
885
886pub(crate) fn public_dbtype_name_from_type_info(ora_type_num: u8, csfrm: u8) -> &'static str {
887 match (ora_type_num, csfrm) {
888 (ORA_TYPE_NUM_BINARY_DOUBLE, _) => "DB_TYPE_BINARY_DOUBLE",
889 (ORA_TYPE_NUM_BINARY_FLOAT, _) => "DB_TYPE_BINARY_FLOAT",
890 (ORA_TYPE_NUM_INTERVAL_DS, _) => "DB_TYPE_INTERVAL_DS",
891 (ORA_TYPE_NUM_INTERVAL_YM, _) => "DB_TYPE_INTERVAL_YM",
892 (ORA_TYPE_NUM_BOOLEAN, _) => "DB_TYPE_BOOLEAN",
893 (ORA_TYPE_NUM_BINARY_INTEGER, _) => "DB_TYPE_BINARY_INTEGER",
894 (ORA_TYPE_NUM_NUMBER, _) => "DB_TYPE_NUMBER",
895 (ORA_TYPE_NUM_CHAR, CS_FORM_NCHAR) | (ORA_TYPE_NUM_VARCHAR, CS_FORM_NCHAR) => {
896 "DB_TYPE_NVARCHAR"
897 }
898 (ORA_TYPE_NUM_CHAR, _) => "DB_TYPE_CHAR",
899 (ORA_TYPE_NUM_VARCHAR, _) => "DB_TYPE_VARCHAR",
900 (ORA_TYPE_NUM_LONG, CS_FORM_NCHAR) => "DB_TYPE_LONG_NVARCHAR",
901 (ORA_TYPE_NUM_LONG, _) => "DB_TYPE_LONG",
902 (ORA_TYPE_NUM_LONG_RAW, _) => "DB_TYPE_LONG_RAW",
903 (ORA_TYPE_NUM_RAW, _) => "DB_TYPE_RAW",
904 (ORA_TYPE_NUM_DATE, _) => "DB_TYPE_DATE",
905 (ORA_TYPE_NUM_TIMESTAMP, _) => "DB_TYPE_TIMESTAMP",
906 (ORA_TYPE_NUM_TIMESTAMP_LTZ, _) => "DB_TYPE_TIMESTAMP_LTZ",
907 (ORA_TYPE_NUM_TIMESTAMP_TZ, _) => "DB_TYPE_TIMESTAMP_TZ",
908 (ORA_TYPE_NUM_CURSOR, _) => "DB_TYPE_CURSOR",
909 (ORA_TYPE_NUM_OBJECT, _) => "DB_TYPE_OBJECT",
910 (ORA_TYPE_NUM_VECTOR, _) => "DB_TYPE_VECTOR",
911 (ORA_TYPE_NUM_JSON, _) => "DB_TYPE_JSON",
912 _ => "DB_TYPE_VARCHAR",
913 }
914}
915
916pub(crate) fn bind_metadata(value: &BindValue) -> (u8, u8, u32) {
917 bind_value_type_info(value)
918 .map(|info| (info.ora_type_num, info.csfrm, info.buffer_size))
919 .unwrap_or((ORA_TYPE_NUM_VARCHAR, CS_FORM_IMPLICIT, 1))
920}
921
922pub(crate) fn write_bind_value(writer: &mut TtcWriter, value: &BindValue, csfrm: u8) -> Result<()> {
923 match value {
924 BindValue::TypedNull {
925 ora_type_num: ORA_TYPE_NUM_CURSOR,
926 ..
927 } => {
928 writer.write_u8(1);
929 writer.write_u8(0);
930 Ok(())
931 }
932 BindValue::TypedNull {
937 ora_type_num: ORA_TYPE_NUM_BOOLEAN,
938 ..
939 } => {
940 writer.write_u8(TNS_ESCAPE_CHAR);
941 writer.write_u8(1);
942 Ok(())
943 }
944 BindValue::Null | BindValue::TypedNull { .. } => {
945 writer.write_u8(0);
946 Ok(())
947 }
948 BindValue::Output { .. } | BindValue::ReturnOutput { .. } => {
949 writer.write_u8(0);
950 Ok(())
951 }
952 BindValue::ObjectOutput { .. } => {
953 writer.write_ub4(0);
956 writer.write_ub4(0);
957 writer.write_ub4(0);
958 writer.write_ub2(0);
959 writer.write_ub4(0);
960 writer.write_ub4(TNS_OBJ_TOP_LEVEL);
961 Ok(())
962 }
963 BindValue::ObjectInput { oid, image, .. } => write_dbobject_bind(writer, oid, image),
964 BindValue::Text(value) => {
965 if csfrm == CS_FORM_NCHAR {
970 let bytes = encode_text_value(value, csfrm);
971 writer.write_bytes_with_length(&bytes)
972 } else {
973 writer.write_bytes_with_length(value.as_bytes())
974 }
975 }
976 BindValue::Raw(value) => writer.write_bytes_with_length(value),
977 BindValue::Lob { locator, .. } => writer.write_bytes_with_two_lengths(Some(locator)),
978 BindValue::Number(value) | BindValue::BinaryInteger(value) => {
979 let bytes = encode_number_text(value)?;
980 writer.write_bytes_with_length(&bytes)
981 }
982 BindValue::Boolean(value) => {
985 let bytes: &[u8] = if *value { &[1, 1] } else { &[0] };
986 writer.write_bytes_with_length(bytes)
987 }
988 BindValue::BinaryDouble(value) => {
989 let bytes = encode_binary_double(*value);
990 writer.write_bytes_with_length(&bytes)
991 }
992 BindValue::BinaryFloat(value) => {
993 let bytes = encode_binary_float(*value as f32);
994 writer.write_bytes_with_length(&bytes)
995 }
996 BindValue::IntervalDS {
997 days,
998 seconds,
999 microseconds,
1000 } => {
1001 let nanoseconds = microseconds
1002 .checked_mul(1000)
1003 .ok_or(ProtocolError::TtcDecode(
1004 "INTERVAL DS fractional seconds out of range",
1005 ))?;
1006 let bytes = encode_interval_ds(*days, *seconds, nanoseconds)?;
1007 writer.write_bytes_with_length(&bytes)
1008 }
1009 BindValue::IntervalYM { years, months } => {
1010 let bytes = encode_interval_ym(*years, *months)?;
1011 writer.write_bytes_with_length(&bytes)
1012 }
1013 BindValue::DateTime {
1014 year,
1015 month,
1016 day,
1017 hour,
1018 minute,
1019 second,
1020 } => {
1021 let bytes = encode_oracle_date(*year, *month, *day, *hour, *minute, *second)?;
1022 writer.write_bytes_with_length(&bytes)
1023 }
1024 BindValue::Timestamp {
1025 year,
1026 month,
1027 day,
1028 hour,
1029 minute,
1030 second,
1031 nanosecond,
1032 ora_type_num,
1033 } => {
1034 let bytes = if matches!(*ora_type_num, ORA_TYPE_NUM_TIMESTAMP_TZ) {
1035 encode_oracle_timestamp_tz(
1036 *year,
1037 *month,
1038 *day,
1039 *hour,
1040 *minute,
1041 *second,
1042 *nanosecond,
1043 )?
1044 } else {
1045 encode_oracle_timestamp(*year, *month, *day, *hour, *minute, *second, *nanosecond)?
1046 };
1047 writer.write_bytes_with_length(&bytes)
1048 }
1049 BindValue::TimestampTz {
1050 year,
1051 month,
1052 day,
1053 hour,
1054 minute,
1055 second,
1056 nanosecond,
1057 offset_minutes,
1058 } => {
1059 let bytes = encode_oracle_timestamp_tz_with_offset(
1060 *year,
1061 *month,
1062 *day,
1063 *hour,
1064 *minute,
1065 *second,
1066 *nanosecond,
1067 *offset_minutes,
1068 )?;
1069 writer.write_bytes_with_length(&bytes)
1070 }
1071 BindValue::Array {
1072 values,
1073 csfrm: array_csfrm,
1074 ..
1075 } => {
1076 writer.write_ub4(u32::try_from(values.len()).map_err(|_| {
1077 ProtocolError::InvalidPacketLength {
1078 length: values.len(),
1079 minimum: 0,
1080 }
1081 })?);
1082 for value in values {
1083 match value {
1084 Some(value) => write_bind_value(writer, value, *array_csfrm)?,
1085 None => writer.write_u8(0),
1086 }
1087 }
1088 Ok(())
1089 }
1090 BindValue::Vector(vector) => {
1093 let image = crate::vector::encode_vector_checked(vector)?;
1094 crate::vector::write_vector_image(writer, &image)
1095 }
1096 BindValue::Json(image) => crate::vector::write_vector_image(writer, image),
1099 BindValue::Cursor { cursor_id } => {
1100 if *cursor_id == 0 {
1101 writer.write_u8(1);
1102 writer.write_u8(0);
1103 } else {
1104 writer.write_ub4(1);
1105 writer.write_ub4(*cursor_id);
1106 }
1107 Ok(())
1108 }
1109 }
1110}
1111
1112pub(crate) fn encode_text_value(value: &str, csfrm: u8) -> Vec<u8> {
1113 if csfrm == CS_FORM_NCHAR {
1114 let mut bytes = Vec::with_capacity(value.len().saturating_mul(2));
1115 for unit in value.encode_utf16() {
1116 bytes.extend_from_slice(&unit.to_be_bytes());
1117 }
1118 bytes
1119 } else {
1120 value.as_bytes().to_vec()
1121 }
1122}