mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
sqlite: Handle C strs at FFI margins, fix lint (#8910)
Some of the FFI wrappers take in a byte slice that's presumed to be NUL capped. It's more ergonomic and safer to take in a &CStr which is impossible to get wrong because it's validated at the margins. Additionally, there were a few areas where a NUL was embedded directly into the source (i.e. "COMMIT(NUL)" which displayed as "COMMIT^@"). This had the interesting effect of breaking grep on the source code.
This commit is contained in:
1 parent
3805038dec
commit
3e2d4129fe
1 file changed
+82
-52
@@ -348,8 +348,14 @@ mod _sqlite3 {
|
||||
return Ok(Self(None));
|
||||
}
|
||||
obj.downcast::<PyStr>()
|
||||
.map(|s| Self(Some(s)))
|
||||
.map_err(|_| vm.new_type_error("isolation_level must be str or None".to_owned()))
|
||||
.and_then(|s| {
|
||||
if s.contains_nuls() {
|
||||
Err(vm.new_value_error("isolation_level contains interior NULs".to_owned()))
|
||||
} else {
|
||||
Ok(Self(Some(s)))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -497,7 +503,7 @@ mod _sqlite3 {
|
||||
};
|
||||
|
||||
if let Err(exc) = f() {
|
||||
context.result_exception(vm, exc, "user-defined function raised exception\0")
|
||||
context.result_exception(vm, exc, c"user-defined function raised exception")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -517,7 +523,7 @@ mod _sqlite3 {
|
||||
return context.result_exception(
|
||||
vm,
|
||||
exc,
|
||||
"user-defined aggregate's '__init__' method raised error\0",
|
||||
c"user-defined aggregate's '__init__' method raised error",
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -661,13 +667,21 @@ mod _sqlite3 {
|
||||
context.result_exception(
|
||||
vm,
|
||||
exc,
|
||||
&format!("user-defined aggregate's '{name}' method not defined\0"),
|
||||
CStr::from_bytes_until_nul(
|
||||
format!("user-defined aggregate's '{name}' method not defined\0")
|
||||
.as_bytes(),
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
} else {
|
||||
context.result_exception(
|
||||
vm,
|
||||
exc,
|
||||
&format!("user-defined aggregate's '{name}' method raised error\0"),
|
||||
CStr::from_bytes_until_nul(
|
||||
format!("user-defined aggregate's '{name}' method raised error\0")
|
||||
.as_bytes(),
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -695,13 +709,21 @@ mod _sqlite3 {
|
||||
context.result_exception(
|
||||
vm,
|
||||
exc,
|
||||
&format!("user-defined aggregate's '{name}' method not defined\0"),
|
||||
CStr::from_bytes_until_nul(
|
||||
format!("user-defined aggregate's '{name}' method not defined\0")
|
||||
.as_bytes(),
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
} else {
|
||||
context.result_exception(
|
||||
vm,
|
||||
exc,
|
||||
&format!("user-defined aggregate's '{name}' method raised error\0"),
|
||||
CStr::from_bytes_until_nul(
|
||||
format!("user-defined aggregate's '{name}' method raised error\0")
|
||||
.as_bytes(),
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1016,7 +1038,7 @@ mod _sqlite3 {
|
||||
&& *self.autocommit.lock() == AutocommitMode::Disabled
|
||||
&& !db.is_autocommit()
|
||||
{
|
||||
db._exec(b"ROLLBACK\0", vm)
|
||||
db._exec(c"ROLLBACK", vm)
|
||||
} else {
|
||||
Ok(())
|
||||
};
|
||||
@@ -1041,7 +1063,7 @@ mod _sqlite3 {
|
||||
begin_statement_ptr_from_isolation_level(isolation_level, vm)?;
|
||||
}
|
||||
if args.autocommit == AutocommitMode::Disabled {
|
||||
db._exec(b"BEGIN\0", vm)?;
|
||||
db._exec(c"BEGIN", vm)?;
|
||||
}
|
||||
Ok(db)
|
||||
}
|
||||
@@ -1154,8 +1176,8 @@ mod _sqlite3 {
|
||||
AutocommitMode::Legacy => db.implicit_commit(vm),
|
||||
AutocommitMode::Enabled => Ok(()),
|
||||
AutocommitMode::Disabled => {
|
||||
db._exec(b"COMMIT\0", vm)?;
|
||||
db._exec(b"BEGIN\0", vm)
|
||||
db._exec(c"COMMIT", vm)?;
|
||||
db._exec(c"BEGIN", vm)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1169,13 +1191,13 @@ mod _sqlite3 {
|
||||
if db.is_autocommit() {
|
||||
Ok(())
|
||||
} else {
|
||||
db._exec(b"ROLLBACK\0", vm)
|
||||
db._exec(c"ROLLBACK", vm)
|
||||
}
|
||||
}
|
||||
AutocommitMode::Enabled => Ok(()),
|
||||
AutocommitMode::Disabled => {
|
||||
db._exec(b"ROLLBACK\0", vm)?;
|
||||
db._exec(b"BEGIN\0", vm)
|
||||
db._exec(c"ROLLBACK", vm)?;
|
||||
db._exec(c"BEGIN", vm)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1218,9 +1240,7 @@ mod _sqlite3 {
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: Make it build without clippy::manual_c_str_literals
|
||||
#[pymethod]
|
||||
#[allow(clippy::manual_c_str_literals)]
|
||||
fn backup(zelf: &Py<Self>, args: BackupArgs, vm: &VirtualMachine) -> PyResult<()> {
|
||||
let BackupArgs {
|
||||
target,
|
||||
@@ -1240,7 +1260,7 @@ mod _sqlite3 {
|
||||
name_cstring = name.to_cstring(vm)?;
|
||||
name_cstring.as_ptr()
|
||||
} else {
|
||||
b"main\0".as_ptr().cast()
|
||||
c"main".as_ptr()
|
||||
};
|
||||
|
||||
let sleep_ms = (sleep * 1000.0) as c_int;
|
||||
@@ -1248,9 +1268,8 @@ mod _sqlite3 {
|
||||
let db = zelf.db_lock(vm)?;
|
||||
let target_db = target.db_lock(vm)?;
|
||||
|
||||
let handle = unsafe {
|
||||
sqlite3_backup_init(target_db.db, b"main\0".as_ptr().cast(), db.db, name_ptr)
|
||||
};
|
||||
let handle =
|
||||
unsafe { sqlite3_backup_init(target_db.db, c"main".as_ptr(), db.db, name_ptr) };
|
||||
|
||||
if handle.is_null() {
|
||||
return Err(target_db.error_extended(vm));
|
||||
@@ -1302,7 +1321,7 @@ mod _sqlite3 {
|
||||
check_num_params(&db, args.narg, "narg", vm)?;
|
||||
let Some(data) = CallbackData::new(args.func, vm) else {
|
||||
return db.create_function(
|
||||
name.as_ptr(),
|
||||
&name,
|
||||
args.narg,
|
||||
flags,
|
||||
null_mut(),
|
||||
@@ -1315,7 +1334,7 @@ mod _sqlite3 {
|
||||
};
|
||||
|
||||
db.create_function(
|
||||
name.as_ptr(),
|
||||
&name,
|
||||
args.narg,
|
||||
flags,
|
||||
Box::into_raw(Box::new(data)).cast(),
|
||||
@@ -1338,7 +1357,7 @@ mod _sqlite3 {
|
||||
check_num_params(&db, args.narg, "n_arg", vm)?;
|
||||
let Some(data) = CallbackData::new(args.aggregate_class, vm) else {
|
||||
return db.create_function(
|
||||
name.as_ptr(),
|
||||
&name,
|
||||
args.narg,
|
||||
SQLITE_UTF8,
|
||||
null_mut(),
|
||||
@@ -1351,7 +1370,7 @@ mod _sqlite3 {
|
||||
};
|
||||
|
||||
db.create_function(
|
||||
name.as_ptr(),
|
||||
&name,
|
||||
args.narg,
|
||||
SQLITE_UTF8,
|
||||
Box::into_raw(Box::new(data)).cast(),
|
||||
@@ -1663,13 +1682,13 @@ mod _sqlite3 {
|
||||
AutocommitMode::Enabled => {
|
||||
// If there's a pending transaction, commit it
|
||||
if !db.is_autocommit() {
|
||||
db._exec(b"COMMIT | ||||