oracle/sql_type/object.rs
1// Rust-oracle - Rust binding for Oracle database
2//
3// URL: https://github.com/kubo/rust-oracle
4//
5//-----------------------------------------------------------------------------
6// Copyright (c) 2017-2018 Kubo Takehiro <kubo@jiubao.org>. All rights reserved.
7// This program is free software: you can modify it and/or redistribute it
8// under the terms of:
9//
10// (i) the Universal Permissive License v 1.0 or at your option, any
11// later version (http://oss.oracle.com/licenses/upl); and/or
12//
13// (ii) the Apache License v 2.0. (http://www.apache.org/licenses/LICENSE-2.0)
14//-----------------------------------------------------------------------------
15
16use crate::chkerr;
17use crate::connection::Conn;
18use crate::sql_type::collection::{Indices, Iter, Values};
19use crate::sql_type::FromSql;
20use crate::sql_type::OracleType;
21use crate::sql_type::ToSql;
22use crate::to_rust_str;
23use crate::util::write_literal;
24use crate::AssertSend;
25use crate::Connection;
26use crate::Context;
27use crate::DpiObject;
28use crate::DpiObjectAttr;
29use crate::DpiObjectType;
30use crate::Error;
31use crate::Result;
32use crate::SqlValue;
33use odpic_sys::dpi_impl::DPI_NUMBER_AS_TEXT_CHARS;
34use odpic_sys::*;
35use std::cmp;
36use std::fmt;
37use std::mem::{self, MaybeUninit};
38use std::os::raw::c_char;
39use std::sync::Arc;
40
41unsafe fn release_dpi_data(data: &dpiData, native_type_num: u32) {
42 if data.isNull == 0 {
43 match native_type_num {
44 DPI_NATIVE_TYPE_LOB => {
45 dpiLob_release(data.value.asLOB);
46 }
47 DPI_NATIVE_TYPE_OBJECT => {
48 dpiObject_release(data.value.asObject);
49 }
50 DPI_NATIVE_TYPE_ROWID => {
51 dpiRowid_release(data.value.asRowid);
52 }
53 _ => (),
54 }
55 }
56}
57
58/// Oracle-specific collection data type
59///
60/// This type corresponds to varray and nested table data types.
61/// See [Oracle manual](https://docs.oracle.com/database/122/ADOBJ/collection-data-types.htm).
62///
63/// ```no_run
64/// # use oracle::*;
65/// let conn = Connection::connect("scott", "tiger", "")?;
66///
67/// // MDSYS.SDO_ELEM_INFO_ARRAY is defined as VARRAY (1048576) of NUMBER.
68/// let objtype = conn.object_type("MDSYS.SDO_ELEM_INFO_ARRAY")?;
69///
70/// // Create a new collection
71/// let mut obj = objtype.new_collection()?;
72/// obj.push(&1);
73/// obj.push(&3);
74/// assert_eq!(obj.to_string(), "MDSYS.SDO_ELEM_INFO_ARRAY(1, 3)");
75/// # Ok::<(), Error>(())
76/// ```
77///
78/// Note: Methods in the type may be changed in future.
79pub struct Collection {
80 conn: Conn,
81 pub(crate) handle: DpiObject,
82 objtype: ObjectType,
83}
84
85impl Collection {
86 pub(crate) fn new(conn: Conn, handle: DpiObject, objtype: ObjectType) -> Collection {
87 Collection {
88 conn,
89 handle,
90 objtype,
91 }
92 }
93
94 pub(crate) fn ctxt(&self) -> &Context {
95 self.conn.ctxt()
96 }
97
98 fn handle(&self) -> *mut dpiObject {
99 self.handle.raw
100 }
101
102 /// Returns type information.
103 pub fn object_type(&self) -> &ObjectType {
104 &self.objtype
105 }
106
107 /// Returns the number of elements.
108 ///
109 /// This counts also deleted elements. See "Comments" about [OCICollSize()][].
110 ///
111 /// [OCICollSize()]: https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-B8F6665F-12F1-43DB-A27E-82A2A655D701
112 pub fn size(&self) -> Result<i32> {
113 let mut size = 0;
114 chkerr!(self.ctxt(), dpiObject_getSize(self.handle(), &mut size));
115 Ok(size)
116 }
117
118 /// Returns an iterator visiting all values with indices in the collection.
119 ///
120 /// ```
121 /// # use oracle::{Error, Result};
122 /// # use oracle::test_util;
123 /// # let conn = test_util::connect()?;
124 /// // Creates VARRAY type and gets the type information
125 /// conn.execute("create or replace type string_varray is varray(20) of varchar2(60)", &[])?;
126 /// let objtype = conn.object_type("STRING_VARRAY")?;
127 ///
128 /// // Creates a VARRAY instance and appends three elements.
129 /// let mut coll = objtype.new_collection()?;
130 /// coll.push(&"First Element")?;
131 /// coll.push(&"Second Element")?;
132 /// coll.push(&"Third Element")?;
133 ///
134 /// let vec = coll
135 /// .iter::<String>() // iterator returning Result<(i32, String)>
136 /// .collect::<Result<Vec<_>>>()?;
137 /// assert_eq!(vec[0], (0, "First Element".to_string()));
138 /// assert_eq!(vec[1], (1, "Second Element".to_string()));
139 /// assert_eq!(vec[2], (2, "Third Element".to_string()));
140 ///
141 /// // Creates Table type and gets the type information
142 /// conn.execute("create or replace type string_table is table of varchar2(60)", &[])?;
143 /// let objtype = conn.object_type("STRING_TABLE")?;
144 ///
145 /// // Creates a TABLE instance, appends four elements and makes a hole.
146 /// let mut coll = objtype.new_collection()?;
147 /// coll.push(&"First Element")?;
148 /// coll.push(&"Second Element")?;
149 /// coll.push(&"Third Element")?;
150 /// coll.push(&"Fourth Element")?;
151 /// coll.remove(2)?; // Remove "Third Element"
152 ///
153 /// // iterator returning Result<(i32, String)>
154 /// let mut iter = coll.iter::<String>();
155 /// assert_eq!(iter.next().unwrap()?, (0, "First Element".to_string()));
156 /// assert_eq!(iter.next().unwrap()?, (1, "Second Element".to_string()));
157 /// assert_eq!(iter.next().unwrap()?, (3, "Fourth Element".to_string()));
158 /// assert!(iter.next().is_none());
159 /// # // check fused
160 /// # assert!(iter.next().is_none());
161 /// # // backward
162 /// # assert_eq!(iter.next_back().unwrap()?, (3, "Fourth Element".to_string()));
163 /// # assert_eq!(iter.next_back().unwrap()?, (1, "Second Element".to_string()));
164 /// # assert_eq!(iter.next_back().unwrap()?, (0, "First Element".to_string()));
165 /// # assert!(iter.next_back().is_none());
166 /// # // check fused
167 /// # assert!(iter.next_back().is_none());
168 ///
169 /// # Ok::<(), Box<dyn std::error::Error>>(())
170 /// ```
171 pub fn iter<T>(&self) -> Iter<T>
172 where
173 T: FromSql,
174 {
175 Iter::new(self)
176 }
177
178 /// Returns an iterator visiting all indices in the collection.
179 ///
180 /// ```
181 /// # use oracle::{Error, Result};
182 /// # use oracle::test_util;
183 /// # let conn = test_util::connect()?;
184 /// // Creates Table type and gets the type information
185 /// conn.execute("create or replace type string_table is table of varchar2(60)", &[])?;
186 /// let objtype = conn.object_type("STRING_TABLE")?;
187 ///
188 /// // Creates a TABLE instance, appends four elements and makes a hole.
189 /// let mut coll = objtype.new_collection()?;
190 /// coll.push(&"First Element")?; // index 0
191 /// coll.push(&"Second Element")?; // index 1
192 /// coll.push(&"Third Element")?; // index 2
193 /// coll.push(&"Fourth Element")?; // index 3
194 /// coll.remove(2)?; // remote index 2
195 /// // coll's indices are 0, 1 and 3.
196 ///
197 /// let mut indices = coll.indices();
198 /// assert_eq!(indices.next().unwrap().unwrap(), 0);
199 /// assert_eq!(indices.next().unwrap().unwrap(), 1);
200 /// assert_eq!(indices.next().unwrap().unwrap(), 3);
201 /// assert!(indices.next().is_none());
202 /// # // check fused or not
203 /// # assert!(indices.next().is_none());
204 /// # // backward
205 /// # assert_eq!(indices.next_back().unwrap()?, 3);
206 /// # assert_eq!(indices.next_back().unwrap()?, 1);
207 /// # assert_eq!(indices.next_back().unwrap()?, 0);
208 /// # assert!(indices.next_back().is_none());
209 /// # // check fused or not
210 /// # assert!(indices.next_back().is_none());
211 /// # Ok::<(), Box<dyn std::error::Error>>(())
212 /// ```
213 pub fn indices(&self) -> Indices {
214 Indices::new(self)
215 }
216
217 /// Returns an iterator visiting all values in the collection.
218 ///
219 /// ```
220 /// # use oracle::{Error, Result};
221 /// # use oracle::test_util;
222 /// # let conn = test_util::connect()?;
223 /// // Creates VARRAY type and gets the type information
224 /// conn.execute("create or replace type string_varray3 is varray(20) of varchar2(60)", &[])?;
225 /// let objtype = conn.object_type("STRING_VARRAY3")?;
226 ///
227 /// // Creates a VARRAY instance and appends three elements.
228 /// let mut coll = objtype.new_collection()?;
229 /// coll.push(&"First Element");
230 /// coll.push(&"Second Element");
231 /// coll.push(&"Third Element");
232 ///
233 /// let mut iter = coll.values::<String>();
234 /// assert_eq!(iter.next().unwrap()?, "First Element".to_string());
235 /// assert_eq!(iter.next().unwrap()?, "Second Element".to_string());
236 /// assert_eq!(iter.next().unwrap()?, "Third Element".to_string());
237 /// assert!(iter.next().is_none());
238 /// # // check fused
239 /// # assert!(iter.next().is_none());
240 /// # // backward
241 /// # assert_eq!(iter.next_back().unwrap()?, "Third Element".to_string());
242 /// # assert_eq!(iter.next_back().unwrap()?, "Second Element".to_string());
243 /// # assert_eq!(iter.next_back().unwrap()?, "First Element".to_string());
244 /// # assert!(iter.next_back().is_none());
245 /// # // check fused
246 /// # assert!(iter.next_back().is_none());
247 ///
248 /// # Ok::<(), Box<dyn std::error::Error>>(())
249 /// ```
250 pub fn values<T>(&self) -> Values<T>
251 where
252 T: FromSql,
253 {
254 Values::new(self)
255 }
256
257 /// Returns the first index.
258 ///
259 /// Use this method if indexes of the collection isn't continuous.
260 pub fn first_index(&self) -> Result<i32> {
261 let mut index = 0;
262 let mut exists = 0;
263 chkerr!(
264 self.ctxt(),
265 dpiObject_getFirstIndex(self.handle(), &mut index, &mut exists)
266 );
267 if exists != 0 {
268 Ok(index)
269 } else {
270 Err(Error::no_data_found())
271 }
272 }
273
274 /// Returns the last index.
275 ///
276 /// Use this method if indexes of the collection isn't continuous.
277 pub fn last_index(&self) -> Result<i32> {
278 let mut index = 0;
279 let mut exists = 0;
280 chkerr!(
281 self.ctxt(),
282 dpiObject_getLastIndex(self.handle(), &mut index, &mut exists)
283 );
284 if exists != 0 {
285 Ok(index)
286 } else {
287 Err(Error::no_data_found())
288 }
289 }
290
291 /// Returns the next index following the specified index.
292 ///
293 /// Use this method if indexes of the collection isn't continuous.
294 pub fn next_index(&self, index: i32) -> Result<i32> {
295 let mut next = 0;
296 let mut exists = 0;
297 chkerr!(
298 self.ctxt(),
299 dpiObject_getNextIndex(self.handle(), index, &mut next, &mut exists)
300 );
301 if exists != 0 {
302 Ok(next)
303 } else {
304 Err(Error::no_data_found())
305 }
306 }
307
308 /// Returns the previous index following the specified index.
309 ///
310 /// Use this method if indexes of the collection isn't continuous.
311 pub fn prev_index(&self, index: i32) -> Result<i32> {
312 let mut prev = 0;
313 let mut exists = 0;
314 chkerr!(
315 self.ctxt(),
316 dpiObject_getPrevIndex(self.handle(), index, &mut prev, &mut exists)
317 );
318 if exists != 0 {
319 Ok(prev)
320 } else {
321 Err(Error::no_data_found())
322 }
323 }
324
325 /// Returns whether an element exists at the specified index.
326 pub fn exist(&self, index: i32) -> Result<bool> {
327 let mut exists = 0;
328 chkerr!(
329 self.ctxt(),
330 dpiObject_getElementExistsByIndex(self.handle(), index, &mut exists)
331 );
332 Ok(exists != 0)
333 }
334
335 /// Returns the value of the element at the specified index.
336 pub fn get<T>(&self, index: i32) -> Result<T>
337 where
338 T: FromSql,
339 {
340 let oratype = self.objtype.element_oracle_type().unwrap();
341 let mut data = unsafe { mem::zeroed() };
342 let mut buf = [0 as c_char; DPI_NUMBER_AS_TEXT_CHARS as usize];
343 match oratype {
344 &OracleType::Number(_, _) | &OracleType::Float(_) => unsafe {
345 dpiData_setBytes(&mut data, buf.as_mut_ptr(), buf.len() as u32);
346 },
347 _ => (),
348 }
349 let res;
350 let native_type_num;
351 {
352 let sql_value = SqlValue::from_oratype(self.conn.clone(), oratype, &mut data)?;
353 native_type_num = sql_value.native_type_num();
354 chkerr!(
355 self.ctxt(),
356 dpiObject_getElementValueByIndex(
357 self.handle(),
358 index,
359 native_type_num,
360 sql_value.data()?
361 )
362 );
363 res = sql_value.get();
364 }
365 unsafe { release_dpi_data(&data, native_type_num) };
366 res
367 }
368
369 /// Sets the value to the element at the specified index.
370 pub fn set(&mut self, index: i32, value: &dyn ToSql) -> Result<()> {
371 let oratype = self.objtype.element_oracle_type().unwrap();
372 let mut data = unsafe { mem::zeroed() };
373 let mut sql_value = SqlValue::from_oratype(self.conn.clone(), oratype, &mut data)?;
374 sql_value.set(value)?;
375 chkerr!(
376 self.ctxt(),
377 dpiObject_setElementValueByIndex(
378 self.handle(),
379 index,
380 sql_value.native_type_num(),
381 sql_value.data()?
382 )
383 );
384 Ok(())
385 }
386
387 /// Appends an element to the end of the collection.
388 pub fn push(&mut self, value: &dyn ToSql) -> Result<()> {
389 let oratype = self.objtype.element_oracle_type().unwrap();
390 let mut data = unsafe { mem::zeroed() };
391 let mut sql_value = SqlValue::from_oratype(self.conn.clone(), oratype, &mut data)?;
392 sql_value.set(value)?;
393 chkerr!(
394 self.ctxt(),
395 dpiObject_appendElement(
396 self.handle(),
397 sql_value.native_type_num(),
398 sql_value.data()?
399 )
400 );
401 Ok(())
402 }
403
404 /// Remove the element at the specified index.
405 /// Note that the position ordinals of the remaining elements are not changed.
406 /// The operation creates **holes** in the collection.
407 pub fn remove(&mut self, index: i32) -> Result<()> {
408 chkerr!(
409 self.ctxt(),
410 dpiObject_deleteElementByIndex(self.handle(), index)
411 );
412 Ok(())
413 }
414
415 /// Trims a number of elements from the end of a collection.
416 ///
417 /// If the number of of elements to trim exceeds the current size
418 /// of the collection an error is returned.
419 pub fn trim(&mut self, len: usize) -> Result<()> {
420 chkerr!(self.ctxt(), dpiObject_trim(self.handle(), len as u32));
421 Ok(())
422 }
423}
424
425impl Clone for Collection {
426 fn clone(&self) -> Collection {
427 Collection::new(self.conn.clone(), self.handle.clone(), self.objtype.clone())
428 }
429}
430
431impl FromSql for Collection {
432 fn from_sql(val: &SqlValue) -> Result<Collection> {
433 val.to_collection()
434 }
435}
436
437impl ToSql for Collection {
438 fn oratype(&self, _conn: &Connection) -> Result<OracleType> {
439 Ok(OracleType::Object(self.object_type().clone()))
440 }
441 fn to_sql(&self, val: &mut SqlValue) -> Result<()> {
442 val.set_collection(self)
443 }
444}
445
446impl fmt::Display for Collection {
447 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
448 write!(f, "{}(", self.objtype)?;
449 if let Ok(index) = self.first_index() {
450 let mut idx = index;
451 let oratype = self.objtype.element_oracle_type().unwrap();
452 loop {
453 write_literal(f, &self.get(idx), oratype)?;
454 if let Ok(index) = self.next_index(idx) {
455 idx = index;
456 write!(f, ", ")?;
457 } else {
458 break;
459 }
460 }
461 }
462 write!(f, ")")
463 }
464}
465
466impl fmt::Debug for Collection {
467 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
468 let oratype = self.objtype.element_oracle_type().unwrap();
469 write!(f, "Collection({} collection of {}: ", self.objtype, oratype)?;
470 if let Ok(index) = self.first_index() {
471 let mut idx = index;
472 loop {
473 write_literal(f, &self.get(idx), oratype)?;
474 if let Ok(index) = self.next_index(idx) {
475 idx = index;
476 write!(f, ", ")?;
477 } else {
478 break;
479 }
480 }
481 }
482 write!(f, ")")
483 }
484}
485
486impl AssertSend for Collection {}
487
488/// Oracle-specific object data type
489///
490/// ```no_run
491/// # use oracle::*;
492/// let conn = Connection::connect("scott", "tiger", "")?;
493///
494/// // MDSYS.SDO_GEOMETRY
495/// // https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-683FF8C5-A773-4018-932D-2AF6EC8BC119
496/// let geom_type = conn.object_type("MDSYS.SDO_GEOMETRY")?;
497/// let point_type = conn.object_type("MDSYS.SDO_POINT_TYPE")?;
498///
499/// // Create a new object
500/// let mut obj = geom_type.new_object()?;
501/// let mut point = point_type.new_object()?;
502/// point.set("X", &-79)?;
503/// point.set("Y", &37)?;
504/// obj.set("SDO_GTYPE", &2001)?;
505/// obj.set("SDO_POINT", &point)?;
506/// assert_eq!(obj.to_string(), "MDSYS.SDO_GEOMETRY(2001, NULL, MDSYS.SDO_POINT_TYPE(-79, 37, NULL), NULL, NULL)");
507///
508/// // Gets an attribute value.
509/// let gtype: i32 = obj.get("SDO_GTYPE")?;
510/// assert_eq!(gtype, 2001);
511/// # Ok::<(), Error>(())
512/// ```
513///
514/// Note: Methods in the type may be changed in future.
515pub struct Object {
516 conn: Conn,
517 pub(crate) handle: DpiObject,
518 objtype: ObjectType,
519}
520
521impl Object {
522 pub(crate) fn new(conn: Conn, handle: DpiObject, objtype: ObjectType) -> Object {
523 Object {
524 conn,
525 handle,
526 objtype,
527 }
528 }
529
530 pub(crate) fn ctxt(&self) -> &Context {
531 self.conn.ctxt()
532 }
533
534 pub(crate) fn handle(&self) -> *mut dpiObject {
535 self.handle.raw
536 }
537
538 /// Returns type information.
539 pub fn object_type(&self) -> &ObjectType {
540 &self.objtype
541 }
542
543 fn type_attr(&self, name: &str) -> Result<&ObjectTypeAttr> {
544 for attr in self.objtype.attributes() {
545 if attr.name() == name {
546 return Ok(attr);
547 }
548 }
549 Err(Error::invalid_attribute_name(name))
550 }
551
552 pub(crate) fn get_by_attr<T>(&self, attr: &ObjectTypeAttr) -> Result<T>
553 where
554 T: FromSql,
555 {
556 let mut data = unsafe { mem::zeroed() };
557 let mut buf = [0 as c_char; DPI_NUMBER_AS_TEXT_CHARS as usize];
558 match &attr.oratype {
559 &OracleType::Number(_, _) | &OracleType::Float(_) => unsafe {
560 dpiData_setBytes(&mut data, buf.as_mut_ptr(), buf.len() as u32);
561 },
562 _ => (),
563 }
564 let res;
565 let native_type_num;
566 {
567 let sql_value = SqlValue::from_oratype(self.conn.clone(), &attr.oratype, &mut data)?;
568 native_type_num = sql_value.native_type_num();
569 chkerr!(
570 self.ctxt(),
571 dpiObject_getAttributeValue(
572 self.handle(),
573 attr.handle.raw(),
574 native_type_num,
575 sql_value.data()?
576 )
577 );
578 res = sql_value.get();
579 }
580 unsafe { release_dpi_data(&data, native_type_num) };
581 res
582 }
583
584 /// Gets an value at the specified attribute.
585 pub fn get<T>(&self, name: &str) -> Result<T>
586 where
587 T: FromSql,
588 {
589 self.get_by_attr(self.type_attr(name)?)
590 }
591
592 /// Sets the value to the specified attribute.
593 pub fn set(&mut self, name: &str, value: &dyn ToSql) -> Result<()> {
594 let attrtype = self.type_attr(name)?;
595 let mut data = unsafe { mem::zeroed() };
596 let mut sql_value =
597 SqlValue::from_oratype(self.conn.clone(), &attrtype.oratype, &mut data)?;
598 sql_value.set(value)?;
599 chkerr!(
600 self.ctxt(),
601 dpiObject_setAttributeValue(
602 self.handle(),
603 attrtype.handle.raw(),
604 sql_value.native_type_num(),
605 sql_value.data()?
606 )
607 );
608 Ok(())
609 }
610}
611
612impl Clone for Object {
613 fn clone(&self) -> Object {
614 Object::new(self.conn.clone(), self.handle.clone(), self.objtype.clone())
615 }
616}
617
618impl FromSql for Object {
619 fn from_sql(val: &SqlValue) -> Result<Object> {
620 val.to_object()
621 }
622}
623
624impl ToSql for Object {
625 fn oratype(&self, _conn: &Connection) -> Result<OracleType> {
626 Ok(OracleType::Object(self.object_type().clone()))
627 }
628 fn to_sql(&self, val: &mut SqlValue) -> Result<()> {
629 val.set_object(self)
630 }
631}
632
633impl fmt::Display for Object {
634 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
635 write!(f, "{}(", self.objtype)?;
636 let mut first = true;
637 for attr in self.objtype.attributes() {
638 if first {
639 first = false;
640 } else {
641 write!(f, ", ")?;
642 }
643 write_literal(f, &self.get_by_attr(attr), &attr.oratype)?;
644 }
645 write!(f, ")")
646 }
647}
648
649impl fmt::Debug for Object {
650 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
651 write!(f, "Object({}(", self.objtype)?;
652 let mut first = true;
653 for attr in self.objtype.attributes() {
654 if first {
655 first = false;
656 } else {
657 write!(f, ", ")?;
658 }
659 write!(f, "{}({}): ", attr.name(), attr.oracle_type())?;
660 write_literal(f, &self.get_by_attr(attr), &attr.oratype)?;
661 }
662 write!(f, "))")
663 }
664}
665
666impl AssertSend for Object {}
667
668/// Type information about Object or Collection data type
669///
670/// This is for not only Object type information but also
671/// collection type information.
672///
673/// # Examples
674///
675/// Gets MDSYS.SDO_GEOMETRY object type information.
676///
677/// ```no_run
678/// # use oracle::*;
679/// let conn = Connection::connect("scott", "tiger", "")?;
680/// let objtype = conn.object_type("MDSYS.SDO_GEOMETRY");
681/// # Ok::<(), Error>(())
682/// ```
683///
684/// Gets object type infomration in query.
685///
686/// ```no_run
687/// # use oracle::*; use oracle::sql_type::*;
688/// let conn = Connection::connect("scott", "tiger", "")?;
689/// // conn.execute("create table location (name varchar2(60), loc sdo_geometry)", &[]);
690/// let mut stmt = conn
691/// .statement("select loc from location where name = '...'")
692/// .build()?;
693/// let rows = stmt.query(&[])?;
694/// let objtype = if let OracleType::Object(ref objtype) = *rows.column_info()[0].oracle_type() {
695/// objtype
696/// } else {
697/// panic!("Not an object type")
698/// };
699/// # Ok::<(), Error>(())
700/// ```
701#[derive(Clone)]
702pub struct ObjectType {
703 pub(crate) internal: Arc<ObjectTypeInternal>,
704}
705
706impl ObjectType {
707 pub(crate) fn from_dpi_object_type(conn: Conn, handle: DpiObjectType) -> Result<ObjectType> {
708 Ok(ObjectType {
709 internal: Arc::new(ObjectTypeInternal::from_dpi_object_type(conn, handle)?),
710 })
711 }
712
713 pub(crate) fn handle(&self) -> &DpiObjectType {
714 &self.internal.handle
715 }
716
717 /// Gets schema name
718 pub fn schema(&self) -> &str {
719 &self.internal.schema
720 }
721
722 /// Gets object name
723 pub fn name(&self) -> &str {
724 &self.internal.name
725 }
726
727 /// Gets package name if it is a PL/SQL type.
728 /// Otherwise, `None`.
729 pub fn package_name(&self) -> Option<&str> {
730 if let Some(ref pkg_name) = self.internal.package_name {
731 Some(pkg_name)
732 } else {
733 None
734 }
735 }
736
737 /// True when it is a collectoin. Otherwise false.
738 pub fn is_collection(&self) -> bool {
739 self.internal.elem_oratype.is_some()
740 }
741
742 /// Gets the Oracle type of elements if it is a collection.
743 /// Otherwise, `None`.
744 pub fn element_oracle_type(&self) -> Option<&OracleType> {
745 if let Some(ref oratype) = self.internal.elem_oratype {
746 Some(oratype)
747 } else {
748 None
749 }
750 }
751
752 /// Gets the number of attributes if it isn't a collection.
753 /// Otherwise, 0.
754 pub fn num_attributes(&self) -> usize {
755 self.internal.attrs.len()
756 }
757
758 /// Gets a vector of attribute information if it isn't a collection.
759 /// Otherwise, a zero-length vector.
760 ///
761 /// # Examples
762 ///
763 /// Prints attribute information of `MDSYS.SDO_GEOMETRY`.
764 ///
765 /// ```no_run
766 /// # use oracle::*;
767 /// let conn = Connection::connect("scott", "tiger", "")?;
768 /// let objtype = conn.object_type("MDSYS.SDO_GEOMETRY")?;
769 /// for attr in objtype.attributes() {
770 /// println!("{:-20} {}", attr.name(), attr.oracle_type());
771 /// }
772 /// # Ok::<(), Error>(())
773 /// ```
774 pub fn attributes(&self) -> &[ObjectTypeAttr] {
775 &self.internal.attrs
776 }
777
778 /// Create a new Oracle object.
779 pub fn new_object(&self) -> Result<Object> {
780 if self.is_collection() {
781 return Err(Error::invalid_operation(format!(
782 "{}.{} isn't object type.",
783 self.schema(),
784 self.name()
785 )));
786 }
787 let conn = &self.internal.conn;
788 let mut handle = DpiObject::null();
789 chkerr!(
790 conn.ctxt(),
791 dpiObjectType_createObject(self.internal.handle.raw(), &mut handle.raw)
792 );
793 Ok(Object::new(conn.clone(), handle, self.clone()))
794 }
795
796 /// Create a new collection.
797 pub fn new_collection(&self) -> Result<Collection> {
798 if !self.is_collection() {
799 return Err(Error::invalid_operation(format!(
800 "{}.{} isn't collection type.",
801 self.schema(),
802 self.name()
803 )));
804 }
805 let conn = &self.internal.conn;
806 let mut handle = DpiObject::null();
807 chkerr!(
808 conn.ctxt(),
809 dpiObjectType_createObject(self.internal.handle.raw(), &mut handle.raw)
810 );
811 Ok(Collection::new(conn.clone(), handle, self.clone()))
812 }
813}
814
815impl cmp::PartialEq for ObjectType {
816 fn eq(&self, other: &Self) -> bool {
817 self.internal == other.internal
818 }
819}
820
821impl fmt::Display for ObjectType {
822 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
823 write!(f, "{}", self.internal)
824 }
825}
826
827impl fmt::Debug for ObjectType {
828 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
829 write!(f, "{:?}", self.internal)
830 }
831}
832
833/// Object type attribute information
834///
835/// See [ObjectType.attributes()](struct.ObjectType.html#method.attributes)
836pub struct ObjectTypeAttr {
837 conn: Conn,
838 handle: DpiObjectAttr,
839 name: String,
840 oratype: OracleType,
841}
842
843impl ObjectTypeAttr {
844 fn new(conn: Conn, handle: DpiObjectAttr) -> Result<ObjectTypeAttr> {
845 let mut info = MaybeUninit::uninit();
846 chkerr!(
847 conn.ctxt(),
848 dpiObjectAttr_getInfo(handle.raw(), info.as_mut_ptr())
849 );
850 let info = unsafe { info.assume_init() };
851 Ok(ObjectTypeAttr {
852 oratype: OracleType::from_type_info(&conn, &info.typeInfo)?,
853 conn,
854 handle,
855 name: to_rust_str(info.name, info.nameLength),
856 })
857 }
858
859 /// Gets the attribute name
860 pub fn name(&self) -> &str {
861 &self.name
862 }
863
864 /// Gets the attribute type
865 pub fn oracle_type(&self) -> &OracleType {
866 &self.oratype
867 }
868}
869
870impl Clone for ObjectTypeAttr {
871 fn clone(&self) -> ObjectTypeAttr {
872 ObjectTypeAttr {
873 conn: self.conn.clone(),
874 handle: self.handle.clone(),
875 name: self.name.clone(),
876 oratype: self.oratype.clone(),
877 }
878 }
879}
880
881impl fmt::Debug for ObjectTypeAttr {
882 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
883 write!(
884 f,
885 "ObjectTypeAttr {{ handle: {:?}, name: {:?}, oratype: {:?} }}",
886 self.handle.raw(),
887 self.name,
888 self.oratype
889 )
890 }
891}
892
893//
894// ObjectTypeInternal
895//
896
897pub(crate) struct ObjectTypeInternal {
898 conn: Conn,
899 handle: DpiObjectType,
900 schema: String,
901 name: String,
902 package_name: Option<String>,
903 elem_oratype: Option<OracleType>,
904 attrs: Vec<ObjectTypeAttr>,
905}
906
907impl ObjectTypeInternal {
908 fn from_dpi_object_type(conn: Conn, handle: DpiObjectType) -> Result<ObjectTypeInternal> {
909 let mut info = MaybeUninit::uninit();
910 chkerr!(
911 conn.ctxt(),
912 dpiObjectType_getInfo(handle.raw(), info.as_mut_ptr())
913 );
914 let info = unsafe { info.assume_init() };
915 let (elem_oratype, attrs) = if info.isCollection != 0 {
916 match OracleType::from_type_info(&conn, &info.elementTypeInfo) {
917 Ok(oratype) => (Some(oratype), Vec::new()),
918 Err(err) => return Err(err),
919 }
920 } else {
921 let attrnum = info.numAttributes as usize;
922 let mut handles = Vec::<DpiObjectAttr>::with_capacity(attrnum);
923 chkerr!(
924 conn.ctxt(),
925 dpiObjectType_getAttributes(
926 handle.raw(),
927 info.numAttributes,
928 // The following code works only when
929 // the size of `*mut dpiObjectAttr` equals to that of `DpiObjectAttr`.
930 handles.as_mut_ptr() as *mut *mut dpiObjectAttr
931 )
932 );
933 unsafe {
934 handles.set_len(attrnum);
935 }
936 let attrs: Result<Vec<_>> = handles
937 .into_iter()
938 .map(|handle| ObjectTypeAttr::new(conn.clone(), handle))
939 .collect();
940 (None, attrs?)
941 };
942 Ok(ObjectTypeInternal {
943 conn,
944 handle,
945 schema: to_rust_str(info.schema, info.schemaLength),
946 name: to_rust_str(info.name, info.nameLength),
947 package_name: if info.packageNameLength != 0 {
948 Some(to_rust_str(info.packageName, info.packageNameLength))
949 } else {
950 None
951 },
952 elem_oratype,
953 attrs,
954 })
955 }
956}
957
958impl cmp::PartialEq for ObjectTypeInternal {
959 fn eq(&self, other: &Self) -> bool {
960 self.handle.raw() == other.handle.raw()
961 }
962}
963
964impl fmt::Display for ObjectTypeInternal {
965 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
966 write!(f, "{}.{}", self.schema, self.name)
967 }
968}
969
970impl fmt::Debug for ObjectTypeInternal {
971 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
972 if self.elem_oratype.is_some() {
973 write!(
974 f,
975 "ObjectType({}.{} collection of {})",
976 self.schema,
977 self.name,
978 self.elem_oratype.as_ref().unwrap()
979 )
980 } else {
981 write!(f, "ObjectType({}.{}(", self.schema, self.name)?;
982 let mut first = true;
983 for attr in &self.attrs {
984 if first {
985 first = false;
986 } else {
987 write!(f, ", ")?;
988 }
989 write!(f, "{} {}", attr.name(), attr.oracle_type())?;
990 }
991 write!(f, "))")
992 }
993 }
994}