mirror of
https://github.com/isar/rusqlite.git
synced 2024-11-23 00:39:20 +08:00
Merge pull request #1137 from gwenn/error_offset
Introduce SqlInputError with offset
This commit is contained in:
commit
7b0fb7d1b1
67
src/error.rs
67
src/error.rs
@ -128,6 +128,19 @@ pub enum Error {
|
|||||||
#[cfg(feature = "blob")]
|
#[cfg(feature = "blob")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "blob")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "blob")))]
|
||||||
BlobSizeError,
|
BlobSizeError,
|
||||||
|
/// Error referencing a specific token in the input SQL
|
||||||
|
#[cfg(feature = "modern_sqlite")] // 3.38.0
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "modern_sqlite")))]
|
||||||
|
SqlInputError {
|
||||||
|
/// error code
|
||||||
|
error: ffi::Error,
|
||||||
|
/// error message
|
||||||
|
msg: String,
|
||||||
|
/// SQL input
|
||||||
|
sql: String,
|
||||||
|
/// byte offset of the start of invalid token
|
||||||
|
offset: c_int,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for Error {
|
impl PartialEq for Error {
|
||||||
@ -172,6 +185,21 @@ impl PartialEq for Error {
|
|||||||
}
|
}
|
||||||
#[cfg(feature = "blob")]
|
#[cfg(feature = "blob")]
|
||||||
(Error::BlobSizeError, Error::BlobSizeError) => true,
|
(Error::BlobSizeError, Error::BlobSizeError) => true,
|
||||||
|
#[cfg(feature = "modern_sqlite")]
|
||||||
|
(
|
||||||
|
Error::SqlInputError {
|
||||||
|
error: e1,
|
||||||
|
msg: m1,
|
||||||
|
sql: s1,
|
||||||
|
offset: o1,
|
||||||
|
},
|
||||||
|
Error::SqlInputError {
|
||||||
|
error: e2,
|
||||||
|
msg: m2,
|
||||||
|
sql: s2,
|
||||||
|
offset: o2,
|
||||||
|
},
|
||||||
|
) => e1 == e2 && m1 == m2 && s1 == s2 && o1 == o2,
|
||||||
(..) => false,
|
(..) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -281,9 +309,15 @@ impl fmt::Display for Error {
|
|||||||
#[cfg(feature = "functions")]
|
#[cfg(feature = "functions")]
|
||||||
Error::GetAuxWrongType => write!(f, "get_aux called with wrong type"),
|
Error::GetAuxWrongType => write!(f, "get_aux called with wrong type"),
|
||||||
Error::MultipleStatement => write!(f, "Multiple statements provided"),
|
Error::MultipleStatement => write!(f, "Multiple statements provided"),
|
||||||
|
|
||||||
#[cfg(feature = "blob")]
|
#[cfg(feature = "blob")]
|
||||||
Error::BlobSizeError => "Blob size is insufficient".fmt(f),
|
Error::BlobSizeError => "Blob size is insufficient".fmt(f),
|
||||||
|
#[cfg(feature = "modern_sqlite")]
|
||||||
|
Error::SqlInputError {
|
||||||
|
ref msg,
|
||||||
|
offset,
|
||||||
|
ref sql,
|
||||||
|
..
|
||||||
|
} => write!(f, "{} in {} at offset {}", msg, sql, offset),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -331,6 +365,8 @@ impl error::Error for Error {
|
|||||||
|
|
||||||
#[cfg(feature = "blob")]
|
#[cfg(feature = "blob")]
|
||||||
Error::BlobSizeError => None,
|
Error::BlobSizeError => None,
|
||||||
|
#[cfg(feature = "modern_sqlite")]
|
||||||
|
Error::SqlInputError { ref error, .. } => Some(error),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -371,6 +407,35 @@ pub unsafe fn error_from_handle(db: *mut ffi::sqlite3, code: c_int) -> Error {
|
|||||||
error_from_sqlite_code(code, message)
|
error_from_sqlite_code(code, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cold]
|
||||||
|
#[cfg(not(all(feature = "modern_sqlite", not(feature = "bundled-sqlcipher"))))] // SQLite >= 3.38.0
|
||||||
|
pub unsafe fn error_with_offset(db: *mut ffi::sqlite3, code: c_int, _sql: &str) -> Error {
|
||||||
|
error_from_handle(db, code)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cold]
|
||||||
|
#[cfg(all(feature = "modern_sqlite", not(feature = "bundled-sqlcipher")))] // SQLite >= 3.38.0
|
||||||
|
pub unsafe fn error_with_offset(db: *mut ffi::sqlite3, code: c_int, sql: &str) -> Error {
|
||||||
|
if db.is_null() {
|
||||||
|
error_from_sqlite_code(code, None)
|
||||||
|
} else {
|
||||||
|
let error = ffi::Error::new(code);
|
||||||
|
let msg = errmsg_to_string(ffi::sqlite3_errmsg(db));
|
||||||
|
if ffi::ErrorCode::Unknown == error.code {
|
||||||
|
let offset = ffi::sqlite3_error_offset(db);
|
||||||
|
if offset >= 0 {
|
||||||
|
return Error::SqlInputError {
|
||||||
|
error,
|
||||||
|
msg,
|
||||||
|
sql: sql.to_owned(),
|
||||||
|
offset,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Error::SqliteFailure(error, Some(msg))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn check(code: c_int) -> Result<()> {
|
pub fn check(code: c_int) -> Result<()> {
|
||||||
if code != crate::ffi::SQLITE_OK {
|
if code != crate::ffi::SQLITE_OK {
|
||||||
Err(crate::error::error_from_sqlite_code(code, None))
|
Err(crate::error::error_from_sqlite_code(code, None))
|
||||||
|
@ -10,7 +10,7 @@ use std::sync::{Arc, Mutex};
|
|||||||
use super::ffi;
|
use super::ffi;
|
||||||
use super::str_for_sqlite;
|
use super::str_for_sqlite;
|
||||||
use super::{Connection, InterruptHandle, OpenFlags, Result};
|
use super::{Connection, InterruptHandle, OpenFlags, Result};
|
||||||
use crate::error::{error_from_handle, error_from_sqlite_code, Error};
|
use crate::error::{error_from_handle, error_from_sqlite_code, error_with_offset, Error};
|
||||||
use crate::raw_statement::RawStatement;
|
use crate::raw_statement::RawStatement;
|
||||||
use crate::statement::Statement;
|
use crate::statement::Statement;
|
||||||
use crate::version::version_number;
|
use crate::version::version_number;
|
||||||
@ -256,7 +256,9 @@ impl InnerConnection {
|
|||||||
rc
|
rc
|
||||||
};
|
};
|
||||||
// If there is an error, *ppStmt is set to NULL.
|
// If there is an error, *ppStmt is set to NULL.
|
||||||
self.decode_result(r)?;
|
if r != ffi::SQLITE_OK {
|
||||||
|
return Err(unsafe { error_with_offset(self.db, r, sql) });
|
||||||
|
}
|
||||||
// If the input text contains no SQL (if the input is an empty string or a
|
// If the input text contains no SQL (if the input is an empty string or a
|
||||||
// comment) then *ppStmt is set to NULL.
|
// comment) then *ppStmt is set to NULL.
|
||||||
let c_stmt: *mut ffi::sqlite3_stmt = c_stmt;
|
let c_stmt: *mut ffi::sqlite3_stmt = c_stmt;
|
||||||
|
@ -1535,4 +1535,21 @@ mod test {
|
|||||||
assert_eq!(0, stmt.is_explain());
|
assert_eq!(0, stmt.is_explain());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(all(feature = "modern_sqlite", not(feature = "bundled-sqlcipher")))] // SQLite >= 3.38.0
|
||||||
|
fn test_error_offset() -> Result<()> {
|
||||||
|
use crate::ffi::ErrorCode;
|
||||||
|
let db = Connection::open_in_memory()?;
|
||||||
|
let r = db.execute_batch("SELECT CURRENT_TIMESTANP;");
|
||||||
|
assert!(r.is_err());
|
||||||
|
match r.unwrap_err() {
|
||||||
|
Error::SqlInputError { error, offset, .. } => {
|
||||||
|
assert_eq!(error.code, ErrorCode::Unknown);
|
||||||
|
assert_eq!(offset, 7);
|
||||||
|
}
|
||||||
|
err => panic!("Unexpected error {}", err),
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user