Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 123 additions & 34 deletions benches/value.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use core::fmt;
use std::hint::black_box;

use criterion::{Criterion, criterion_group, criterion_main};
Expand All @@ -10,59 +11,147 @@ pub enum Char {
Character,
}

fn vanilla() -> String {
format!(
"SELECT `{}` from `{}` where `character` = {}",
"character",
"character".to_owned(),
"foobar"
)
fn small_raw(value: i32) -> Result<String, fmt::Error> {
let mut str = String::new();
str.write_str("SELECT ")?;
str.write_str(&Char::Id.quoted())?;
str.write_str(" FROM ")?;
str.write_str(&Char::Table.quoted())?;
str.write_str(" WHERE ")?;
for _ in black_box(0..9) {
str.write_str(&Char::Id.quoted())?;
str.write_str(" = ")?;
write!(str, "{value}")?;
str.write_str(" AND ")?;
}
str.write_str("1=1")?;

Ok(str)
}

fn small_select(value: i32) -> SelectStatement {
Query::select()
.column(Char::Character)
.from(Char::Table)
.and_where(Expr::col(Char::Character).eq(value))
.and_where(Expr::col(Char::Character).eq(value))
.and_where(Expr::col(Char::Character).eq(value))
.and_where(Expr::col(Char::Character).eq(value))
.and_where(Expr::col(Char::Character).eq(value))
.and_where(Expr::col(Char::Character).eq(value))
.and_where(Expr::col(Char::Character).eq(value))
.and_where(Expr::col(Char::Character).eq(value))
.and_where(Expr::col(Char::Character).eq(value))
.and_where(Expr::col(Char::Character).eq(value))
.to_owned()
}

fn select() -> SelectStatement {
fn large_raw(value: &jiff::Zoned) -> Result<String, fmt::Error> {
let mut str = String::new();
str.write_str("SELECT ")?;
str.write_str(&Char::Character.quoted())?;
str.write_str(" FROM ")?;
str.write_str(&Char::Table.quoted())?;
str.write_str(" WHERE ")?;

for _ in 0..9 {
str.write_str(&Char::Character.quoted())?;
str.write_str(" = '")?;
write!(str, "{value}")?;
str.write_str("' AND ")?;
}

str.write_str("1=1")?;

Ok(str)
}

fn large_select(value: jiff::Zoned) -> SelectStatement {
Query::select()
.column(Char::Character)
.from(Char::Table)
.and_where(Expr::col(Char::Character).eq("foobar"))
.and_where(Expr::col(Char::Character).eq("foobar"))
.and_where(Expr::col(Char::Character).eq("foobar"))
.and_where(Expr::col(Char::Character).eq("foobar"))
.and_where(Expr::col(Char::Character).eq("foobar"))
.and_where(Expr::col(Char::Character).eq("foobar"))
.and_where(Expr::col(Char::Character).eq("foobar"))
.and_where(Expr::col(Char::Character).eq("foobar"))
.and_where(Expr::col(Char::Character).eq("foobar"))
.and_where(Expr::col(Char::Character).eq("foobar"))
.and_where(Expr::col(Char::Character).eq(value.clone()))
.and_where(Expr::col(Char::Character).eq(value.clone()))
.and_where(Expr::col(Char::Character).eq(value.clone()))
.and_where(Expr::col(Char::Character).eq(value.clone()))
.and_where(Expr::col(Char::Character).eq(value.clone()))
.and_where(Expr::col(Char::Character).eq(value.clone()))
.and_where(Expr::col(Char::Character).eq(value.clone()))
.and_where(Expr::col(Char::Character).eq(value.clone()))
.and_where(Expr::col(Char::Character).eq(value.clone()))
.and_where(Expr::col(Char::Character).eq(value))
.to_owned()
}

fn criterion_benchmark(c: &mut Criterion) {
let mut group = c.benchmark_group("value");
group.bench_function("vanilla", |b| b.iter(vanilla));
group.bench_function("select", |b| b.iter(select));
let value = black_box(jiff::Zoned::now());

group.bench_function("select_construction/small", |b| {
b.iter(|| small_select(black_box(123)))
});
group.bench_function("select_construction/small/raw", |b| {
b.iter(|| small_raw(black_box(123)).unwrap())
});

group.bench_function("select_construction/large", |b| {
b.iter(|| large_select(value.clone()))
});

group.bench_function("select_construction/large/raw", |b| {
b.iter(|| large_raw(&value).unwrap())
});

let select_small = black_box(small_select(black_box(123)));
group.bench_function("select_and_build/small/mysql", |b| {
b.iter(|| select_small.build(MysqlQueryBuilder))
});
group.bench_function("select_and_build/small/pg", |b| {
b.iter(|| select_small.build(PostgresQueryBuilder))
});
group.bench_function("select_and_build/small/sqlite", |b| {
b.iter(|| select_small.build(SqliteQueryBuilder))
});
group.bench_function("select_and_to_string/small/mysql", |b| {
b.iter(|| select_small.to_string(MysqlQueryBuilder))
});
group.bench_function("select_and_to_string/small/pg", |b| {
b.iter(|| select_small.to_string(PostgresQueryBuilder))
});
group.bench_function("select_and_to_string/small/sqlite", |b| {
b.iter(|| select_small.to_string(SqliteQueryBuilder))
});

let select = black_box(select());
group.bench_function("select_and_build::mysql", |b| {
b.iter(|| select.build(MysqlQueryBuilder))
let select_large = black_box(large_select(value));
group.bench_function("select_and_build/large/mysql", |b| {
b.iter(|| select_large.build(MysqlQueryBuilder))
});
group.bench_function("select_and_build::pg", |b| {
b.iter(|| select.build(PostgresQueryBuilder))
group.bench_function("select_and_build/large/pg", |b| {
b.iter(|| select_large.build(PostgresQueryBuilder))
});
group.bench_function("select_and_build::sqlite", |b| {
b.iter(|| select.build(SqliteQueryBuilder))
group.bench_function("select_and_build/large/sqlite", |b| {
b.iter(|| select_large.build(SqliteQueryBuilder))
});
group.bench_function("select_and_to_string::mysql", |b| {
b.iter(|| select.to_string(MysqlQueryBuilder))
group.bench_function("select_and_to_string/large/mysql", |b| {
b.iter(|| select_large.to_string(MysqlQueryBuilder))
});
group.bench_function("select_and_to_string::pg", |b| {
b.iter(|| select.to_string(PostgresQueryBuilder))
group.bench_function("select_and_to_string/large/pg", |b| {
b.iter(|| select_large.to_string(PostgresQueryBuilder))
});
group.bench_function("select_and_to_string::sqlite", |b| {
b.iter(|| select.to_string(SqliteQueryBuilder))
group.bench_function("select_and_to_string/large/sqlite", |b| {
b.iter(|| select_large.to_string(SqliteQueryBuilder))
});

group.finish();
}

criterion_group!(benches, criterion_benchmark);
fn config() -> Criterion {
Criterion::default().measurement_time(std::time::Duration::new(10, 0))
}

criterion_group!(
name = benches;
config = config();
targets = criterion_benchmark
);
criterion_main!(benches);
2 changes: 1 addition & 1 deletion sea-query-diesel/src/backend/mysql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ impl TransformValue for Mysql {
))]
Value::Decimal(_) => bail!("Enable feature with-rust_decimal-mysql"),
#[cfg(feature = "with-bigdecimal")]
Value::BigDecimal(v) => build!(Numeric, v.map(|v| *v)),
Value::BigDecimal(v) => build!(Numeric, v),
#[cfg(feature = "with-json")]
Value::Json(v) => build!(Json, v),
#[cfg(feature = "with-ipnetwork")]
Expand Down
2 changes: 1 addition & 1 deletion sea-query-diesel/src/backend/postgres.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ impl TransformValue for Pg {
))]
Value::Decimal(_) => bail!("Enable feature with-rust_decimal-postgres"),
#[cfg(feature = "with-bigdecimal")]
Value::BigDecimal(v) => build!(Numeric, v.map(|v| *v)),
Value::BigDecimal(v) => build!(Numeric, v),
#[cfg(feature = "with-json")]
Value::Json(v) => build!(Json, v),
#[cfg(feature = "with-ipnetwork")]
Expand Down
2 changes: 1 addition & 1 deletion sea-query-postgres/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ impl ToSql for PostgresValue {
#[cfg(feature = "with-bigdecimal")]
Value::BigDecimal(v) => {
use bigdecimal::ToPrimitive;
v.as_deref()
v.as_ref()
.map(|v| v.to_f64().expect("Fail to convert bigdecimal as f64"))
.to_sql(ty, out)
}
Expand Down
2 changes: 1 addition & 1 deletion sea-query-sqlx/src/sqlx_mysql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ impl sqlx::IntoArguments<'_, sqlx::mysql::MySql> for SqlxValues {
}
#[cfg(feature = "with-bigdecimal")]
Value::BigDecimal(d) => {
let _ = args.add(d.as_deref());
let _ = args.add(d.as_ref());
}
#[cfg(feature = "with-json")]
Value::Json(j) => {
Expand Down
2 changes: 1 addition & 1 deletion sea-query-sqlx/src/sqlx_postgres.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ impl sqlx::IntoArguments<'_, sqlx::postgres::Postgres> for SqlxValues {
}
#[cfg(feature = "with-bigdecimal")]
Value::BigDecimal(d) => {
let _ = args.add(d.as_deref());
let _ = args.add(d.as_ref());
}
#[cfg(feature = "with-json")]
Value::Json(j) => {
Expand Down
24 changes: 12 additions & 12 deletions src/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -280,15 +280,15 @@ pub enum Value {

#[cfg(feature = "with-jiff")]
#[cfg_attr(docsrs, doc(cfg(feature = "with-jiff")))]
JiffDateTime(Option<Box<jiff::civil::DateTime>>),
JiffDateTime(Option<jiff::civil::DateTime>),

#[cfg(feature = "with-jiff")]
#[cfg_attr(docsrs, doc(cfg(feature = "with-jiff")))]
JiffTimestamp(Option<Box<Timestamp>>),
JiffTimestamp(Option<Timestamp>),

#[cfg(feature = "with-jiff")]
#[cfg_attr(docsrs, doc(cfg(feature = "with-jiff")))]
JiffZoned(Option<Box<Zoned>>),
JiffZoned(Option<Zoned>),

#[cfg(feature = "with-uuid")]
#[cfg_attr(docsrs, doc(cfg(feature = "with-uuid")))]
Expand All @@ -300,11 +300,11 @@ pub enum Value {

#[cfg(feature = "with-bigdecimal")]
#[cfg_attr(docsrs, doc(cfg(feature = "with-bigdecimal")))]
BigDecimal(Option<Box<BigDecimal>>),
BigDecimal(Option<BigDecimal>),

#[cfg(feature = "postgres-array")]
#[cfg_attr(docsrs, doc(cfg(feature = "postgres-array")))]
Array(ArrayType, Option<Box<Vec<Value>>>),
Array(ArrayType, Option<Vec<Value>>),

#[cfg(feature = "postgres-vector")]
#[cfg_attr(docsrs, doc(cfg(feature = "postgres-vector")))]
Expand All @@ -327,8 +327,8 @@ pub enum Value {
pub const VALUE_SIZE: usize = check_value_size();

const fn check_value_size() -> usize {
if std::mem::size_of::<Value>() > 32 {
panic!("the size of Value shouldn't be greater than 32 bytes")
if std::mem::size_of::<Value>() > 104 {
Copy link
Member

@tyt2y3 tyt2y3 Aug 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sad, this basically makes this check useless, unless we relax it in debug mode and stricten it in release mode.
but our CI don't run release mode, so there is no checks anyway.
given that sqlx-binder is still WIP, I wouldn't act on this until there is full sqlx support and #943 is merged.

panic!("the size of Value shouldn't be greater than 104 bytes")
}
std::mem::size_of::<Value>()
}
Expand Down Expand Up @@ -557,19 +557,17 @@ impl Value {
#[cfg(feature = "with-jiff")]
#[cfg_attr(docsrs, doc(cfg(feature = "with-jiff")))]
Self::JiffDateTime(_) => {
Self::JiffDateTime(Some(jiff::civil::date(1970, 1, 1).at(0, 0, 0, 0).into()))
Self::JiffDateTime(Some(jiff::civil::date(1970, 1, 1).at(0, 0, 0, 0)))
}

#[cfg(feature = "with-jiff")]
#[cfg_attr(docsrs, doc(cfg(feature = "with-jiff")))]
Self::JiffTimestamp(_) => Self::JiffTimestamp(Some(Timestamp::UNIX_EPOCH.into())),
Self::JiffTimestamp(_) => Self::JiffTimestamp(Some(Timestamp::UNIX_EPOCH)),

#[cfg(feature = "with-jiff")]
#[cfg_attr(docsrs, doc(cfg(feature = "with-jiff")))]
Self::JiffZoned(_) => Self::JiffZoned(Some(
Timestamp::UNIX_EPOCH
.to_zoned(jiff::tz::TimeZone::UTC)
.into(),
Timestamp::UNIX_EPOCH.to_zoned(jiff::tz::TimeZone::UTC),
)),

#[cfg(feature = "with-uuid")]
Expand Down Expand Up @@ -815,6 +813,7 @@ type_to_value!(Vec<u8>, Bytes, VarBinary(StringLen::None));
type_to_value!(String, String, String(StringLen::None));

#[cfg(any(feature = "with-bigdecimal", feature = "with-jiff"))]
#[allow(unused)]
macro_rules! type_to_box_value {
( $type: ty, $name: ident, $col_type: expr ) => {
impl From<$type> for Value {
Expand Down Expand Up @@ -854,4 +853,5 @@ macro_rules! type_to_box_value {
}

#[cfg(any(feature = "with-bigdecimal", feature = "with-jiff"))]
#[allow(unused)]
use type_to_box_value;
8 changes: 4 additions & 4 deletions src/value/hashable_value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -328,23 +328,23 @@ mod tests {
Into::<Value>::into(vec![0i32, 1, 2]),
Value::Array(
ArrayType::Int,
Some(Box::new(vec![
Some(vec![
Value::Int(Some(0)),
Value::Int(Some(1)),
Value::Int(Some(2))
]))
])
)
);

assert_eq!(
Into::<Value>::into(vec![0f32, 1.0, 2.0]),
Value::Array(
ArrayType::Float,
Some(Box::new(vec![
Some(vec![
Value::Float(Some(0f32)),
Value::Float(Some(1.0)),
Value::Float(Some(2.0))
]))
])
)
);

Expand Down
4 changes: 2 additions & 2 deletions src/value/with_array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ where
fn from(x: Vec<T>) -> Value {
Value::Array(
T::array_type(),
Some(Box::new(x.into_iter().map(|e| e.into()).collect())),
Some(x.into_iter().map(|e| e.into()).collect()),
)
}
}
Expand Down Expand Up @@ -131,7 +131,7 @@ impl Value {

pub fn as_ref_array(&self) -> Option<&Vec<Value>> {
match self {
Self::Array(_, v) => v.as_ref().map(|v| v.as_ref()),
Self::Array(_, v) => v.as_ref(),
_ => panic!("not Value::Array"),
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/value/with_bigdecimal.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::*;

type_to_box_value!(BigDecimal, BigDecimal, Decimal(None));
type_to_value!(BigDecimal, BigDecimal, Decimal(None));

impl Value {
pub fn is_big_decimal(&self) -> bool {
Expand All @@ -9,7 +9,7 @@ impl Value {

pub fn as_ref_big_decimal(&self) -> Option<&BigDecimal> {
match self {
Self::BigDecimal(v) => v.as_ref().map(|x| x.as_ref()),
Self::BigDecimal(v) => v.as_ref(),
_ => panic!("not Value::BigDecimal"),
}
}
Expand Down
Loading