Struct odbc_api::handles::Record

source ·
pub struct Record {
    pub state: State,
    pub native_error: i32,
    pub message: Vec<SqlChar>,
}
Expand description

ODBC Diagnostic Record

The description method of the std::error::Error trait only returns the message. Use std::fmt::Display to retrieve status code and other information.

Fields§

§state: State

All elements but the last one, may not be null. The last one must be null.

§native_error: i32

Error code returned by Driver manager or driver

§message: Vec<SqlChar>

Buffer containing the error message. The buffer already has the correct size, and there is no terminating zero at the end.

Implementations§

Creates an empty diagnostic record with at least the specified capacity for the message. Using a buffer with a size different from zero then filling the diagnostic record may safe a second function call to SQLGetDiagRec.

Examples found in repository?
src/handles/logging.rs (line 13)
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
pub fn log_diagnostics(handle: &(impl Diagnostics + ?Sized)) {
    if log::max_level() < Level::Warn {
        // Early return to safe work creating all these log records in case we would not log
        // anyhing.
        return;
    }

    let mut rec = Record::with_capacity(512);
    let mut rec_number = 1;

    // Log results, while there are diagnostic records
    while rec.fill_from(handle, rec_number) {
        warn!("{}", rec);
        // Prevent overflow. This is not that unlikely to happen, since some `execute` or `fetch`
        // calls can cause diagnostic messages for each row
        if rec_number == i16::MAX {
            warn!("Too many diagnostic records were generated. Not all could be logged.");
            break;
        }
        rec_number += 1;
    }
}
More examples
Hide additional examples
src/error.rs (line 233)
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
    pub fn into_result_with(
        self,
        handle: &impl Diagnostics,
        error_for_truncation: bool,
        no_data: Option<T>,
        need_data: Option<T>,
    ) -> Result<T, Error> {
        match self {
            // The function has been executed successfully. Holds result.
            SqlResult::Success(value) => Ok(value),
            // The function has been executed successfully. There have been warnings. Holds result.
            SqlResult::SuccessWithInfo(value) => {
                log_diagnostics(handle);

                // This is only relevant then bulk fetching values into a buffer. As such this check
                // would perform unnecessary work in most cases. When bulk fetching it should be up
                // for the application to decide wether this is considered an error or not.
                if error_for_truncation {
                    check_for_truncation(handle)?;
                }

                Ok(value)
            }
            SqlResult::Error { function } => {
                let mut record = DiagnosticRecord::with_capacity(512);
                if record.fill_from(handle, 1) {
                    log_diagnostics(handle);
                    Err(Error::Diagnostics { record, function })
                } else {
                    // Anecdotal ways to reach this code paths:
                    //
                    // * Inserting a 64Bit integers into an Oracle Database.
                    // * Specifying invalid drivers (e.g. missing .so the driver itself depends on)
                    Err(Error::NoDiagnostics { function })
                }
            }
            SqlResult::NoData => {
                Ok(no_data.expect("Unexepcted SQL_NO_DATA returned by ODBC function"))
            }
            SqlResult::NeedData => {
                Ok(need_data.expect("Unexepcted SQL_NEED_DATA returned by ODBC function"))
            }
            SqlResult::StillExecuting => panic!(
                "SqlResult must not be converted to result while the function is still executing."
            ),
        }
    }
}

fn check_for_truncation(handle: &impl Diagnostics) -> Result<(), Error> {
    let mut empty = [];
    let mut rec_number = 1;
    while let Some(result) = handle.diagnostic_record(1, &mut empty) {
        if result.state == State::STRING_DATA_RIGHT_TRUNCATION {
            return Err(Error::TooLargeValueForBuffer);
        } else if rec_number == i16::MAX {
            // Many diagnostic records may be produced with a single call. Especially in case of
            // bulk fetching, or inserting. Sadly this could mask truncation errors.
            let mut record = DiagnosticRecord::with_capacity(512);
            record.fill_from(handle, i16::MAX);
            return Err(Error::TooManyDiagnostics { record });
        }
        rec_number += 1;
    }
    Ok(())
}

Fill this diagnostic Record from any ODBC handle.

Return

true if a record has been found, false if not.

Examples found in repository?
src/handles/logging.rs (line 17)
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
pub fn log_diagnostics(handle: &(impl Diagnostics + ?Sized)) {
    if log::max_level() < Level::Warn {
        // Early return to safe work creating all these log records in case we would not log
        // anyhing.
        return;
    }

    let mut rec = Record::with_capacity(512);
    let mut rec_number = 1;

    // Log results, while there are diagnostic records
    while rec.fill_from(handle, rec_number) {
        warn!("{}", rec);
        // Prevent overflow. This is not that unlikely to happen, since some `execute` or `fetch`
        // calls can cause diagnostic messages for each row
        if rec_number == i16::MAX {
            warn!("Too many diagnostic records were generated. Not all could be logged.");
            break;
        }
        rec_number += 1;
    }
}
More examples
Hide additional examples
src/error.rs (line 234)
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
    pub fn into_result_with(
        self,
        handle: &impl Diagnostics,
        error_for_truncation: bool,
        no_data: Option<T>,
        need_data: Option<T>,
    ) -> Result<T, Error> {
        match self {
            // The function has been executed successfully. Holds result.
            SqlResult::Success(value) => Ok(value),
            // The function has been executed successfully. There have been warnings. Holds result.
            SqlResult::SuccessWithInfo(value) => {
                log_diagnostics(handle);

                // This is only relevant then bulk fetching values into a buffer. As such this check
                // would perform unnecessary work in most cases. When bulk fetching it should be up
                // for the application to decide wether this is considered an error or not.
                if error_for_truncation {
                    check_for_truncation(handle)?;
                }

                Ok(value)
            }
            SqlResult::Error { function } => {
                let mut record = DiagnosticRecord::with_capacity(512);
                if record.fill_from(handle, 1) {
                    log_diagnostics(handle);
                    Err(Error::Diagnostics { record, function })
                } else {
                    // Anecdotal ways to reach this code paths:
                    //
                    // * Inserting a 64Bit integers into an Oracle Database.
                    // * Specifying invalid drivers (e.g. missing .so the driver itself depends on)
                    Err(Error::NoDiagnostics { function })
                }
            }
            SqlResult::NoData => {
                Ok(no_data.expect("Unexepcted SQL_NO_DATA returned by ODBC function"))
            }
            SqlResult::NeedData => {
                Ok(need_data.expect("Unexepcted SQL_NEED_DATA returned by ODBC function"))
            }
            SqlResult::StillExecuting => panic!(
                "SqlResult must not be converted to result while the function is still executing."
            ),
        }
    }
}

fn check_for_truncation(handle: &impl Diagnostics) -> Result<(), Error> {
    let mut empty = [];
    let mut rec_number = 1;
    while let Some(result) = handle.diagnostic_record(1, &mut empty) {
        if result.state == State::STRING_DATA_RIGHT_TRUNCATION {
            return Err(Error::TooLargeValueForBuffer);
        } else if rec_number == i16::MAX {
            // Many diagnostic records may be produced with a single call. Especially in case of
            // bulk fetching, or inserting. Sadly this could mask truncation errors.
            let mut record = DiagnosticRecord::with_capacity(512);
            record.fill_from(handle, i16::MAX);
            return Err(Error::TooManyDiagnostics { record });
        }
        rec_number += 1;
    }
    Ok(())
}

Trait Implementations§

Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more
Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Converts the given value to a String. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.