print_table/
print_table.rs

1//! Directly executes an SQL query and prints the result set to standard out
2//!
3//! This example also offers an idea, how to set up error handling for your ODBC Application.
4extern crate odbc_safe;
5use odbc_safe::*;
6use std::str::from_utf8;
7
8// Setup error handling
9struct LastError(String);
10type MyResult<T> = Result<T, LastError>;
11
12impl<D: Diagnostics> From<D> for LastError {
13    fn from(source: D) -> Self {
14        let mut buffer = [0; 512];
15        match source.diagnostics(1, &mut buffer) {
16            ReturnOption::Success(dr) |
17            ReturnOption::Info(dr) => LastError(
18                from_utf8(&buffer[0..(dr.text_length as usize)])
19                    .unwrap()
20                    .to_owned(),
21            ),
22            ReturnOption::Error(()) => panic!("Error during fetching diagnostic record"),
23            ReturnOption::NoData(()) => LastError("No Diagnostic Record present".to_owned()),
24        }
25    }
26}
27
28trait ExtReturn<T> {
29    fn into_result(self) -> MyResult<T>;
30}
31
32impl<T, D> ExtReturn<T> for Return<T, D>
33where
34    D: Diagnostics,
35{
36    fn into_result(self) -> MyResult<T> {
37        match self {
38            Success(v) | Info(v) => Ok(v),
39            Error(d) => Err(d.into()),
40        }
41    }
42}
43
44// Actual application
45fn main() {
46
47    let env = Environment::new().unwrap();
48    let env = env.declare_version_3().unwrap();
49
50    match run(&env) {
51        Ok(()) => (),
52        Err(LastError(message)) => println!("An error occurred: {}", message),
53    }
54}
55
56fn run(env: &Environment<Odbc3>) -> MyResult<()> {
57
58    let conn = connect(&env)?;
59    let result_set = execute_query(&conn)?;
60    print_fields(result_set)
61}
62
63fn connect<V>(env: &Environment<V>) -> MyResult<Connection<impl AutocommitMode>>
64where
65    V: Version,
66{
67    let conn = DataSource::with_parent(env).unwrap();
68    conn.connect("TestDataSource", "", "").into_result()
69}
70
71fn execute_query<'a, AC: AutocommitMode>(conn: &'a Connection<AC>) -> MyResult<ResultSet<'a, 'a, 'a, Unprepared>> {
72    let stmt = Statement::with_parent(conn).unwrap();
73    match stmt.exec_direct("SELECT * FROM MOVIES") {
74        ReturnOption::Success(s) |
75        ReturnOption::Info(s) => Ok(s),
76        ReturnOption::NoData(_) => Err(LastError(
77            "Statement did not return a Result Set.".to_owned(),
78        )),
79        ReturnOption::Error(e) => Err(e.into()),
80    }
81}
82
83fn print_fields(result_set: ResultSet<Unprepared>) -> MyResult<()> {
84    let cols = result_set.num_result_cols().unwrap();
85    let mut buffer = [0u8; 512];
86    let mut cursor = match result_set.fetch() {
87        ReturnOption::Success(r) |
88        ReturnOption::Info(r) => r,
89        ReturnOption::NoData(_) => return Ok(()),
90        ReturnOption::Error(e) => return Err(e.into()),
91    };
92    loop {
93        for index in 1..(cols + 1) {
94            match cursor.get_data(index as u16, &mut buffer as &mut [u8]) {
95                ReturnOption::Success(ind) |
96                ReturnOption::Info(ind) => {
97                    match ind {
98                        Indicator::NoTotal => panic!("No Total"),
99                        Indicator::Null => println!("NULL"),
100                        Indicator::Length(l) => {
101                            print!("{}", from_utf8(&buffer[0..l as usize]).unwrap());
102                        }
103                    }
104                }
105                ReturnOption::NoData(_) => panic!("No Field Data"),
106                ReturnOption::Error(_) => return Err(cursor.into()),
107            }
108            print!(" | ");
109        }
110        cursor = match cursor.fetch() {
111            ReturnOption::Success(r) |
112            ReturnOption::Info(r) => r,
113            ReturnOption::NoData(_) => break Ok(()),
114            ReturnOption::Error(e) => break Err(e.into()),
115        };
116        println!("");
117    }
118}