feat(mysql): reuse byte buffers for UTF-8 strings
This commit is contained in:
parent
d14fd84709
commit
66bdcf8153
|
|
@ -73,21 +73,27 @@ where
|
|||
row.get_opt::<T, I>(index).and_then(|result| result.ok())
|
||||
}
|
||||
|
||||
/// 字节转 String:合法 UTF-8(绝大多数场景)时直接复用入参缓冲零拷贝,
|
||||
/// 仅在非法序列时退化为 lossy 替换。from_utf8_lossy(&b).to_string() 即使
|
||||
/// 对合法输入也会多一次分配+拷贝。
|
||||
fn bytes_to_string_lossy(bytes: Vec<u8>) -> String {
|
||||
String::from_utf8(bytes).unwrap_or_else(|err| String::from_utf8_lossy(err.as_bytes()).into_owned())
|
||||
}
|
||||
|
||||
fn get_str(row: &mysql_async::Row, idx: usize) -> String {
|
||||
row_get::<String, _>(row, idx)
|
||||
.or_else(|| row_get::<Vec<u8>, _>(row, idx).map(|b| String::from_utf8_lossy(&b).to_string()))
|
||||
.or_else(|| row_get::<Vec<u8>, _>(row, idx).map(bytes_to_string_lossy))
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn get_str_by_name(row: &mysql_async::Row, name: &str) -> String {
|
||||
row_get::<String, _>(row, name)
|
||||
.or_else(|| row_get::<Vec<u8>, _>(row, name).map(|b| String::from_utf8_lossy(&b).to_string()))
|
||||
.or_else(|| row_get::<Vec<u8>, _>(row, name).map(bytes_to_string_lossy))
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn get_opt_str(row: &mysql_async::Row, name: &str) -> Option<String> {
|
||||
row_get::<String, _>(row, name)
|
||||
.or_else(|| row_get::<Vec<u8>, _>(row, name).map(|b| String::from_utf8_lossy(&b).to_string()))
|
||||
row_get::<String, _>(row, name).or_else(|| row_get::<Vec<u8>, _>(row, name).map(bytes_to_string_lossy))
|
||||
}
|
||||
|
||||
/// First non-empty string value among the named columns (e.g. Doris `CatalogName`
|
||||
|
|
@ -279,7 +285,7 @@ fn mysql_bytes_to_json(bytes: Vec<u8>, column: &mysql_async::Column) -> serde_js
|
|||
.map(serde_json::Value::String)
|
||||
.unwrap_or_else(|| super::binary_value_to_json(&bytes));
|
||||
}
|
||||
serde_json::Value::String(String::from_utf8_lossy(&bytes).to_string())
|
||||
serde_json::Value::String(bytes_to_string_lossy(bytes))
|
||||
}
|
||||
|
||||
/// Map a MySQL column to a user-facing type name for the result-grid header.
|
||||
|
|
@ -3364,11 +3370,7 @@ pub async fn show_create_table_ddl(pool: &MySqlPool, database: &str, table: &str
|
|||
let row = rows.first().ok_or("DDL not found")?;
|
||||
row.get_opt::<String, usize>(1)
|
||||
.and_then(|result| result.ok())
|
||||
.or_else(|| {
|
||||
row.get_opt::<Vec<u8>, usize>(1)
|
||||
.and_then(|result| result.ok())
|
||||
.map(|b| String::from_utf8_lossy(&b).to_string())
|
||||
})
|
||||
.or_else(|| row.get_opt::<Vec<u8>, usize>(1).and_then(|result| result.ok()).map(bytes_to_string_lossy))
|
||||
.ok_or_else(|| "Failed to read DDL".to_string())
|
||||
}
|
||||
|
||||
|
|
@ -3551,11 +3553,7 @@ pub async fn show_create_table_ddl_from(
|
|||
let row = rows.first().ok_or("DDL not found")?;
|
||||
row.get_opt::<String, usize>(1)
|
||||
.and_then(|result| result.ok())
|
||||
.or_else(|| {
|
||||
row.get_opt::<Vec<u8>, usize>(1)
|
||||
.and_then(|result| result.ok())
|
||||
.map(|b| String::from_utf8_lossy(&b).to_string())
|
||||
})
|
||||
.or_else(|| row.get_opt::<Vec<u8>, usize>(1).and_then(|result| result.ok()).map(bytes_to_string_lossy))
|
||||
.ok_or_else(|| "Failed to read DDL".to_string())
|
||||
}
|
||||
|
||||
|
|
@ -3910,6 +3908,15 @@ mod tests {
|
|||
use crate::db::connection_timeout;
|
||||
use mysql_async::consts::ColumnFlags;
|
||||
|
||||
#[test]
|
||||
fn bytes_to_string_reuses_valid_utf8_and_falls_back_lossy() {
|
||||
assert_eq!(super::bytes_to_string_lossy("héllo 世界".as_bytes().to_vec()), "héllo 世界");
|
||||
assert_eq!(super::bytes_to_string_lossy(vec![]), "");
|
||||
// 非法 UTF-8 序列退化为替换字符,与 from_utf8_lossy 语义一致
|
||||
let invalid = vec![0x66, 0x6f, 0xff, 0x6f];
|
||||
assert_eq!(super::bytes_to_string_lossy(invalid.clone()), String::from_utf8_lossy(&invalid));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mysql_column_type_names_map_to_friendly_names() {
|
||||
use mysql_async::consts::ColumnType::*;
|
||||
|
|
|
|||
Loading…
Reference in New Issue