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: StateAll elements but the last one, may not be null. The last one must be null.
native_error: i32Error 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§
source§impl Record
impl Record
sourcepub fn with_capacity(capacity: usize) -> Self
pub fn with_capacity(capacity: usize) -> Self
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
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(())
}sourcepub fn fill_from(
&mut self,
handle: &impl Diagnostics + ?Sized,
record_number: i16
) -> bool
pub fn fill_from(
&mut self,
handle: &impl Diagnostics + ?Sized,
record_number: i16
) -> bool
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
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(())
}