oracle/
version.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::Context;
18use crate::Result;
19use odpic_sys::*;
20use std::fmt;
21use std::mem::MaybeUninit;
22use std::num::ParseIntError;
23use std::result;
24use std::str::FromStr;
25
26/// Oracle version information
27///
28/// # Examples
29///
30/// ```no_run
31/// # use oracle::*;
32/// let conn = Connection::connect("scott", "tiger", "")?;
33/// let client_version = Version::client()?;
34/// let (server_version, _) = conn.server_version()?;
35///
36/// println!("Client version:");
37/// println!("  1st part: {}", client_version.major());
38/// println!("  2nd part: {}", client_version.minor());
39/// println!("  3rd part: {}", client_version.update());
40/// println!("  4th part: {}", client_version.patch());
41/// println!("  5th part: {}", client_version.port_update());
42///
43/// println!("Server version: {}", server_version);
44/// # Ok::<(), Error>(())
45/// ```
46#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
47pub struct Version {
48    major: i32,
49    minor: i32,
50    update: i32,
51    patch: i32,
52    port_update: i32,
53}
54
55impl Version {
56    /// Creates a new version information
57    pub const fn new(major: i32, minor: i32, update: i32, patch: i32, port_update: i32) -> Version {
58        Version {
59            major,
60            minor,
61            update,
62            patch,
63            port_update,
64        }
65    }
66
67    /// Returns the version of Oracle client in use.
68    ///
69    /// # Examples
70    ///
71    /// ```
72    /// # use oracle::*;
73    /// let client_ver = Version::client()?;
74    /// println!("Oracle Client Version: {}", client_ver);
75    /// # Ok::<(), Error>(())
76    /// ```
77    pub fn client() -> Result<Version> {
78        let ctx = Context::new0()?;
79        let mut ver = MaybeUninit::uninit();
80        chkerr!(
81            &ctx,
82            dpiContext_getClientVersion(ctx.context, ver.as_mut_ptr())
83        );
84        Ok(Version::new_from_dpi_ver(unsafe { ver.assume_init() }))
85    }
86
87    pub(crate) fn new_from_dpi_ver(ver: dpiVersionInfo) -> Version {
88        Version::new(
89            ver.versionNum,
90            ver.releaseNum,
91            ver.updateNum,
92            ver.portReleaseNum,
93            ver.portUpdateNum,
94        )
95    }
96
97    /// Gets 1st part of Oracle version number
98    pub fn major(&self) -> i32 {
99        self.major
100    }
101
102    /// Gets 2nd part of Oracle version number
103    pub fn minor(&self) -> i32 {
104        self.minor
105    }
106
107    /// Gets 3rd part of Oracle version number
108    pub fn update(&self) -> i32 {
109        self.update
110    }
111
112    /// Gets 4th part of Oracle version number
113    pub fn patch(&self) -> i32 {
114        self.patch
115    }
116
117    /// Gets 5th part of Oracle version number
118    pub fn port_update(&self) -> i32 {
119        self.port_update
120    }
121}
122
123impl fmt::Display for Version {
124    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
125        write!(
126            f,
127            "{}.{}.{}.{}.{}",
128            self.major, self.minor, self.update, self.patch, self.port_update
129        )
130    }
131}
132
133impl FromStr for Version {
134    type Err = ParseIntError;
135
136    fn from_str(s: &str) -> result::Result<Self, Self::Err> {
137        let mut iter = s.split('.').fuse();
138        let major = iter.next().map_or(Ok(0), |s| s.parse::<i32>())?;
139        let minor = iter.next().map_or(Ok(0), |s| s.parse::<i32>())?;
140        let update = iter.next().map_or(Ok(0), |s| s.parse::<i32>())?;
141        let patch = iter.next().map_or(Ok(0), |s| s.parse::<i32>())?;
142        let port_update = iter.next().map_or(Ok(0), |s| s.parse::<i32>())?;
143        Ok(Version::new(major, minor, update, patch, port_update))
144    }
145}
146
147#[cfg(test)]
148mod tests {
149    use super::*;
150    use crate::test_util;
151
152    #[test]
153    fn to_string() {
154        assert_eq!(Version::new(12, 1, 2, 3, 4).to_string(), "12.1.2.3.4");
155    }
156
157    #[test]
158    fn from_str() {
159        assert_eq!(
160            "12".parse::<Version>().unwrap(),
161            Version::new(12, 0, 0, 0, 0)
162        );
163        assert_eq!(
164            "12.1".parse::<Version>().unwrap(),
165            Version::new(12, 1, 0, 0, 0)
166        );
167        assert_eq!(
168            "12.1.2".parse::<Version>().unwrap(),
169            Version::new(12, 1, 2, 0, 0)
170        );
171        assert_eq!(
172            "12.1.2.3".parse::<Version>().unwrap(),
173            Version::new(12, 1, 2, 3, 0)
174        );
175        assert_eq!(
176            "12.1.2.3.4".parse::<Version>().unwrap(),
177            Version::new(12, 1, 2, 3, 4)
178        );
179    }
180
181    #[test]
182    fn client_version() {
183        let ver = Version::client().unwrap();
184        let conn = test_util::connect().unwrap();
185        let mut ver_from_query = conn.query_row_as::<String>("SELECT client_version FROM v$session_connect_info WHERE sid = SYS_CONTEXT('USERENV', 'SID')", &[]).unwrap();
186        // The fifth numeral of client_version may be "01" through "12" such as "23.4.0.24.05".
187        // Replace it with "23.4.0.24.5" to pass this test.
188        if let Some(pos) = ver_from_query.len().checked_sub(2) {
189            if ver_from_query.as_bytes()[pos] == b'0' {
190                ver_from_query.remove(pos);
191            }
192        }
193        assert_eq!(ver.to_string(), ver_from_query);
194    }
195}