diff --git a/README.md b/README.md index a7f7761..04ea8ff 100755 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ Order-Status : 0.492 (0.575) Delivery : 6.109 (6.473) Stock-Level : 0.001 (0.001) -89.9205557572134 Tpmc +98 Tpmc ``` #### PG Wire Service run `cargo run --features="net"` to start server diff --git a/src/db.rs b/src/db.rs index bf7d4ad..7992027 100644 --- a/src/db.rs +++ b/src/db.rs @@ -23,7 +23,6 @@ use crate::utils::lru::SharedLruCache; use ahash::HashMap; use parking_lot::lock_api::{ArcRwLockReadGuard, ArcRwLockWriteGuard}; use parking_lot::{RawRwLock, RwLock}; -use sqlparser::ast::Statement; use std::cell::RefCell; use std::hash::RandomState; use std::marker::PhantomData; @@ -35,6 +34,7 @@ pub(crate) type ScalaFunctions = HashMap>; pub type Args = Vec<(&'static str, DataValue)>; +pub type Statement = sqlparser::ast::Statement; #[allow(dead_code)] pub(crate) enum MetaDataLock { diff --git a/src/types/mod.rs b/src/types/mod.rs index 303fcaf..d23630d 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -260,6 +260,20 @@ impl LogicalType { (LogicalType::Integer, _) | (_, LogicalType::UInteger) => Ok(LogicalType::Bigint), (LogicalType::Smallint, _) | (_, LogicalType::USmallint) => Ok(LogicalType::Integer), (LogicalType::Tinyint, _) | (_, LogicalType::UTinyint) => Ok(LogicalType::Smallint), + ( + LogicalType::Decimal(precision_0, scale_0), + LogicalType::Decimal(precision_1, scale_1), + ) => { + let fn_option = |num_0: &Option, num_1: &Option| match (num_0, num_1) { + (Some(num_0), Some(num_1)) => Some(*cmp::max(num_0, num_1)), + (Some(num), None) | (None, Some(num)) => Some(*num), + (None, None) => None, + }; + Ok(LogicalType::Decimal( + fn_option(precision_0, precision_1), + fn_option(scale_0, scale_1), + )) + } _ => Err(DatabaseError::Incomparable(left.clone(), right.clone())), } } diff --git a/src/types/value.rs b/src/types/value.rs index 6972f47..7173326 100644 --- a/src/types/value.rs +++ b/src/types/value.rs @@ -1496,6 +1496,7 @@ impl_scalar!(u8, UInt8); impl_scalar!(u16, UInt16); impl_scalar!(u32, UInt32); impl_scalar!(u64, UInt64); +impl_scalar!(Decimal, Decimal); impl From for DataValue { fn from(value: String) -> Self { @@ -1517,6 +1518,42 @@ impl From> for DataValue { } } +impl From<&NaiveDate> for DataValue { + fn from(value: &NaiveDate) -> Self { + DataValue::Date32(Some(value.num_days_from_ce())) + } +} + +impl From> for DataValue { + fn from(value: Option<&NaiveDate>) -> Self { + DataValue::Date32(value.map(|d| d.num_days_from_ce())) + } +} + +impl From<&NaiveDateTime> for DataValue { + fn from(value: &NaiveDateTime) -> Self { + DataValue::Date64(Some(value.and_utc().timestamp())) + } +} + +impl From> for DataValue { + fn from(value: Option<&NaiveDateTime>) -> Self { + DataValue::Date64(value.map(|d| d.and_utc().timestamp())) + } +} + +impl From<&NaiveTime> for DataValue { + fn from(value: &NaiveTime) -> Self { + DataValue::Time(Some(value.num_seconds_from_midnight())) + } +} + +impl From> for DataValue { + fn from(value: Option<&NaiveTime>) -> Self { + DataValue::Time(value.map(|d| d.num_seconds_from_midnight())) + } +} + impl From<&sqlparser::ast::Value> for DataValue { fn from(v: &sqlparser::ast::Value) -> Self { match v { diff --git a/tpcc/src/README.md b/tpcc/src/README.md index f0afa6f..df4a431 100644 --- a/tpcc/src/README.md +++ b/tpcc/src/README.md @@ -6,12 +6,12 @@ run `cargo run -p tpcc --release` to run tpcc - YMTC PC411-1024GB-B - Tips: TPCC currently only supports single thread ```shell -|New-Order| sc: 1084 lt: 0 fl: 11 -|Payment| sc: 1062 lt: 0 fl: 0 -|Order-Status| sc: 102 lt: 4 fl: 36 -|Delivery| sc: 107 lt: 0 fl: 0 -|Stock-Level| sc: 106 lt: 0 fl: 0 -in 723 sec. +|New-Order| sc: 1182 lt: 0 fl: 13 +|Payment| sc: 1155 lt: 0 fl: 0 +|Order-Status| sc: 115 lt: 1 fl: 29 +|Delivery| sc: 114 lt: 2 fl: 0 +|Stock-Level| sc: 115 lt: 0 fl: 0 +in 720 sec. (all must be [OK]) [transaction percentage] Payment: 43.0% (>=43.0%) [Ok] @@ -21,23 +21,23 @@ in 723 sec. [response time (at least 90%% passed)] New-Order: 100.0 [OK] Payment: 100.0 [OK] - Order-Status: 96.2 [OK] - Delivery: 100.0 [OK] + Order-Status: 99.1 [OK] + Delivery: 98.3 [OK] Stock-Level: 100.0 [OK] - New-Order Total: 1084 - Payment Total: 1062 - Order-Status Total: 106 - Delivery Total: 107 - Stock-Level Total: 106 + New-Order Total: 1182 + Payment Total: 1155 + Order-Status Total: 116 + Delivery Total: 116 + Stock-Level Total: 115 <90th Percentile RT (MaxRT)> - New-Order : 0.005 (0.007) - Payment : 0.084 (0.141) -Order-Status : 0.492 (0.575) - Delivery : 6.109 (6.473) + New-Order : 0.003 (0.011) + Payment : 0.078 (0.470) +Order-Status : 0.227 (0.240) + Delivery : 5.439 (27.702) Stock-Level : 0.001 (0.001) -89.9205557572134 Tpmc +98 Tpmc ``` ## Refer to diff --git a/tpcc/src/delivery.rs b/tpcc/src/delivery.rs index 25f32cc..50ae075 100644 --- a/tpcc/src/delivery.rs +++ b/tpcc/src/delivery.rs @@ -1,8 +1,9 @@ use crate::load::DIST_PER_WARE; use crate::{TpccArgs, TpccError, TpccTest, TpccTransaction}; use chrono::Utc; -use fnck_sql::db::DBTransaction; +use fnck_sql::db::{DBTransaction, Statement}; use fnck_sql::storage::Storage; +use fnck_sql::types::value::DataValue; use rand::prelude::ThreadRng; use rand::Rng; @@ -24,37 +25,86 @@ pub(crate) struct DeliveryTest; impl TpccTransaction for Delivery { type Args = DeliveryArgs; - fn run(tx: &mut DBTransaction, args: &Self::Args) -> Result<(), TpccError> { - let now = Utc::now().format("%Y-%m-%d %H:%M:%S").to_string(); + fn run( + tx: &mut DBTransaction, + args: &Self::Args, + statements: &[Statement], + ) -> Result<(), TpccError> { + let now = Utc::now().naive_utc(); for d_id in 1..DIST_PER_WARE + 1 { // "SELECT COALESCE(MIN(no_o_id),0) FROM new_orders WHERE no_d_id = ? AND no_w_id = ?" - let (_, tuple) = tx.run(format!("SELECT COALESCE(MIN(no_o_id),0) FROM new_orders WHERE no_d_id = {} AND no_w_id = {}", d_id, args.w_id))?; - let no_o_id = tuple[0].values[0].i32().unwrap(); + let (_, tuples) = tx.execute( + &statements[0], + vec![ + ("?1", DataValue::Int8(Some(d_id as i8))), + ("?2", DataValue::Int16(Some(args.w_id as i16))), + ], + )?; + let no_o_id = tuples[0].values[0].i32().unwrap(); if no_o_id == 0 { continue; } // "DELETE FROM new_orders WHERE no_o_id = ? AND no_d_id = ? AND no_w_id = ?" - let _ = tx.run(format!( - "DELETE FROM new_orders WHERE no_o_id = {} AND no_d_id = {} AND no_w_id = {}", - no_o_id, d_id, args.w_id - ))?; + let (_, tuples) = tx.execute( + &statements[1], + vec![ + ("?1", DataValue::Int32(Some(no_o_id))), + ("?2", DataValue::Int8(Some(d_id as i8))), + ("?3", DataValue::Int16(Some(args.w_id as i16))), + ], + )?; // "SELECT o_c_id FROM orders WHERE o_id = ? AND o_d_id = ? AND o_w_id = ?" - let (_, tuple) = tx.run(format!( - "SELECT o_c_id FROM orders WHERE o_id = {} AND o_d_id = {} AND o_w_id = {}", - no_o_id, d_id, args.w_id - ))?; - let c_id = tuple[0].values[0].i32().unwrap(); + let (_, tuples) = tx.execute( + &statements[2], + vec![ + ("?1", DataValue::Int32(Some(no_o_id))), + ("?2", DataValue::Int8(Some(d_id as i8))), + ("?3", DataValue::Int16(Some(args.w_id as i16))), + ], + )?; + let c_id = tuples[0].values[0].i32().unwrap(); // "UPDATE orders SET o_carrier_id = ? WHERE o_id = ? AND o_d_id = ? AND o_w_id = ?" - let _ = tx.run(format!("UPDATE orders SET o_carrier_id = {} WHERE o_id = {} AND o_d_id = {} AND o_w_id = {}", args.o_carrier_id, no_o_id, d_id, args.w_id))?; + let (_, tuples) = tx.execute( + &statements[3], + vec![ + ("?1", DataValue::Int8(Some(args.o_carrier_id as i8))), + ("?2", DataValue::Int32(Some(no_o_id))), + ("?3", DataValue::Int8(Some(d_id as i8))), + ("?4", DataValue::Int16(Some(args.w_id as i16))), + ], + )?; // "UPDATE order_line SET ol_delivery_d = ? WHERE ol_o_id = ? AND ol_d_id = ? AND ol_w_id = ?" - let _ = tx.run(format!("UPDATE order_line SET ol_delivery_d = '{}' WHERE ol_o_id = {} AND ol_d_id = {} AND ol_w_id = {}", now, no_o_id, d_id, args.w_id))?; + let (_, tuples) = tx.execute( + &statements[4], + vec![ + ("?1", DataValue::from(&now)), + ("?2", DataValue::Int32(Some(no_o_id))), + ("?3", DataValue::Int8(Some(d_id as i8))), + ("?4", DataValue::Int16(Some(args.w_id as i16))), + ], + )?; // "SELECT SUM(ol_amount) FROM order_line WHERE ol_o_id = ? AND ol_d_id = ? AND ol_w_id = ?" - let (_, tuple) = tx.run(format!("SELECT SUM(ol_amount) FROM order_line WHERE ol_o_id = {} AND ol_d_id = {} AND ol_w_id = {}", no_o_id, d_id, args.w_id))?; - let ol_total = tuple[0].values[0].decimal().unwrap(); + let (_, tuples) = tx.execute( + &statements[5], + vec![ + ("?1", DataValue::Int32(Some(no_o_id))), + ("?2", DataValue::Int8(Some(d_id as i8))), + ("?3", DataValue::Int16(Some(args.w_id as i16))), + ], + )?; + let ol_total = tuples[0].values[0].decimal().unwrap(); // "UPDATE customer SET c_balance = c_balance + ? , c_delivery_cnt = c_delivery_cnt + 1 WHERE c_id = ? AND c_d_id = ? AND c_w_id = ?" - let _ = tx.run(format!("UPDATE customer SET c_balance = c_balance + {} , c_delivery_cnt = c_delivery_cnt + 1 WHERE c_id = {} AND c_d_id = {} AND c_w_id = {}", ol_total, c_id, d_id, args.w_id))?; + let (_, tuples) = tx.execute( + &statements[6], + vec![ + ("?1", DataValue::Decimal(Some(ol_total))), + ("?2", DataValue::Int32(Some(c_id))), + ("?3", DataValue::Int8(Some(d_id as i8))), + ("?4", DataValue::Int16(Some(args.w_id as i16))), + ], + )?; } Ok(()) @@ -72,12 +122,13 @@ impl TpccTest for DeliveryTest { tx: &mut DBTransaction, num_ware: usize, _: &TpccArgs, + statements: &[Statement], ) -> Result<(), TpccError> { let w_id = rng.gen_range(0..num_ware) + 1; let o_carrier_id = rng.gen_range(1..10); let args = DeliveryArgs::new(w_id, o_carrier_id); - Delivery::run(tx, &args)?; + Delivery::run(tx, &args, statements)?; Ok(()) } diff --git a/tpcc/src/main.rs b/tpcc/src/main.rs index 637131d..8728203 100644 --- a/tpcc/src/main.rs +++ b/tpcc/src/main.rs @@ -7,7 +7,7 @@ use crate::rt_hist::RtHist; use crate::slev::SlevTest; use crate::utils::SeqGen; use clap::Parser; -use fnck_sql::db::{DBTransaction, DataBaseBuilder}; +use fnck_sql::db::{DBTransaction, DataBaseBuilder, Statement}; use fnck_sql::errors::DatabaseError; use fnck_sql::storage::Storage; use rand::prelude::ThreadRng; @@ -35,7 +35,11 @@ pub(crate) const RT_LIMITS: [Duration; 5] = [ pub(crate) trait TpccTransaction { type Args; - fn run(tx: &mut DBTransaction, args: &Self::Args) -> Result<(), TpccError>; + fn run( + tx: &mut DBTransaction, + args: &Self::Args, + statements: &[Statement], + ) -> Result<(), TpccError>; } pub(crate) trait TpccTest { @@ -47,6 +51,7 @@ pub(crate) trait TpccTest { tx: &mut DBTransaction, num_ware: usize, args: &TpccArgs, + statements: &[Statement], ) -> Result<(), TpccError>; } @@ -81,6 +86,56 @@ fn main() -> Result<(), TpccError> { Load::load_custs(&mut rng, &database, args.num_ware)?; Load::load_ord(&mut rng, &database, args.num_ware)?; + let test_statements = vec![ + vec![ + database.prepare("SELECT c.c_discount, c.c_last, c.c_credit, w.w_tax FROM customer AS c JOIN warehouse AS w ON c.c_w_id = w_id AND w.w_id = ?1 AND c.c_w_id = ?2 AND c.c_d_id = ?3 AND c.c_id = ?4")?, + database.prepare("SELECT c_discount, c_last, c_credit FROM customer WHERE c_w_id = ?1 AND c_d_id = ?2 AND c_id = ?3")?, + database.prepare("SELECT w_tax FROM warehouse WHERE w_id = ?1")?, + database.prepare("SELECT d_next_o_id, d_tax FROM district WHERE d_id = ?1 AND d_w_id = ?2")?, + database.prepare("UPDATE district SET d_next_o_id = ?1 + 1 WHERE d_id = ?2 AND d_w_id = ?3")?, + database.prepare("INSERT INTO orders (o_id, o_d_id, o_w_id, o_c_id, o_entry_d, o_ol_cnt, o_all_local) VALUES(?1, ?2, ?3, ?4, ?5, ?6, ?7)")?, + database.prepare("INSERT INTO new_orders (no_o_id, no_d_id, no_w_id) VALUES (?1,?2,?3)")?, + database.prepare("SELECT i_price, i_name, i_data FROM item WHERE i_id = ?1")?, + database.prepare("SELECT s_quantity, s_data, s_dist_01, s_dist_02, s_dist_03, s_dist_04, s_dist_05, s_dist_06, s_dist_07, s_dist_08, s_dist_09, s_dist_10 FROM stock WHERE s_i_id = ?1 AND s_w_id = ?2")?, + database.prepare("UPDATE stock SET s_quantity = ?1 WHERE s_i_id = ?2 AND s_w_id = ?3")?, + database.prepare("INSERT INTO order_line (ol_o_id, ol_d_id, ol_w_id, ol_number, ol_i_id, ol_supply_w_id, ol_quantity, ol_amount, ol_dist_info) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9)")?, + ], + vec![ + database.prepare("UPDATE warehouse SET w_ytd = w_ytd + ?1 WHERE w_id = ?2")?, + database.prepare("SELECT w_street_1, w_street_2, w_city, w_state, w_zip, w_name FROM warehouse WHERE w_id = ?1")?, + database.prepare("UPDATE district SET d_ytd = d_ytd + ?1 WHERE d_w_id = ?2 AND d_id = ?3")?, + database.prepare("SELECT d_street_1, d_street_2, d_city, d_state, d_zip, d_name FROM district WHERE d_w_id = ?1 AND d_id = ?2")?, + database.prepare("SELECT count(c_id) FROM customer WHERE c_w_id = ?1 AND c_d_id = ?2 AND c_last = ?3")?, + database.prepare("SELECT c_id FROM customer WHERE c_w_id = ?1 AND c_d_id = ?2 AND c_last = ?3 ORDER BY c_first")?, + database.prepare("SELECT c_first, c_middle, c_last, c_street_1, c_street_2, c_city, c_state, c_zip, c_phone, c_credit, c_credit_lim, c_discount, c_balance, c_since FROM customer WHERE c_w_id = ?1 AND c_d_id = ?2 AND c_id = ?3")?, + database.prepare("SELECT c_data FROM customer WHERE c_w_id = ?1 AND c_d_id = ?2 AND c_id = ?3")?, + database.prepare("UPDATE customer SET c_balance = ?1, c_data = ?2 WHERE c_w_id = ?3 AND c_d_id = ?4 AND c_id = ?5")?, + database.prepare("UPDATE customer SET c_balance = ?1 WHERE c_w_id = ?2 AND c_d_id = ?3 AND c_id = ?4")?, + database.prepare("INSERT OVERWRITE history(h_c_d_id, h_c_w_id, h_c_id, h_d_id, h_w_id, h_date, h_amount, h_data) VALUES(?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8)")?, + ], + vec![ + database.prepare("SELECT count(c_id) FROM customer WHERE c_w_id = ?1 AND c_d_id = ?2 AND c_last = ?3")?, + database.prepare("SELECT c_balance, c_first, c_middle, c_last FROM customer WHERE c_w_id = ?1 AND c_d_id = ?2 AND c_last = ?3 ORDER BY c_first")?, + database.prepare("SELECT c_balance, c_first, c_middle, c_last FROM customer WHERE c_w_id = ?1 AND c_d_id = ?2 AND c_id = ?3")?, + database.prepare("SELECT o_id, o_entry_d, COALESCE(o_carrier_id,0) FROM orders WHERE o_w_id = ?1 AND o_d_id = ?2 AND o_c_id = ?3 AND o_id = (SELECT MAX(o_id) FROM orders WHERE o_w_id = ?4 AND o_d_id = ?5 AND o_c_id = ?6)")?, + database.prepare("SELECT ol_i_id, ol_supply_w_id, ol_quantity, ol_amount, ol_delivery_d FROM order_line WHERE ol_w_id = ?1 AND ol_d_id = ?2 AND ol_o_id = ?3")? + ], + vec![ + database.prepare("SELECT COALESCE(MIN(no_o_id),0) FROM new_orders WHERE no_d_id = ?1 AND no_w_id = ?2")?, + database.prepare("DELETE FROM new_orders WHERE no_o_id = ?1 AND no_d_id = ?2 AND no_w_id = ?3")?, + database.prepare("SELECT o_c_id FROM orders WHERE o_id = ?1 AND o_d_id = ?2 AND o_w_id = ?3")?, + database.prepare("UPDATE orders SET o_carrier_id = ?1 WHERE o_id = ?2 AND o_d_id = ?3 AND o_w_id = ?4")?, + database.prepare("UPDATE order_line SET ol_delivery_d = ?1 WHERE ol_o_id = ?2 AND ol_d_id = ?3 AND ol_w_id = ?4")?, + database.prepare("SELECT SUM(ol_amount) FROM order_line WHERE ol_o_id = ?1 AND ol_d_id = ?2 AND ol_w_id = ?3")?, + database.prepare("UPDATE customer SET c_balance = c_balance + ?1 , c_delivery_cnt = c_delivery_cnt + 1 WHERE c_id = ?2 AND c_d_id = ?3 AND c_w_id = ?4")?, + ], + vec![ + database.prepare("SELECT d_next_o_id FROM district WHERE d_id = ?1 AND d_w_id = ?2")?, + database.prepare("SELECT DISTINCT ol_i_id FROM order_line WHERE ol_w_id = ?1 AND ol_d_id = ?2 AND ol_o_id < ?3 AND ol_o_id >= (?4 - 20)")?, + database.prepare("SELECT count(*) FROM stock WHERE s_w_id = ?1 AND s_i_id = ?2 AND s_quantity < ?3")?, + ], + ]; + let mut rt_hist = RtHist::new(); let mut success = [0usize; 5]; let mut late = [0usize; 5]; @@ -102,13 +157,15 @@ fn main() -> Result<(), TpccError> { while tpcc_start.elapsed() < duration { let i = seq_gen.get(); let tpcc_test = &tests[i]; + let statement = &test_statements[i]; let mut is_succeed = false; for j in 0..args.max_retry + 1 { let transaction_start = Instant::now(); let mut tx = database.new_transaction()?; - if let Err(err) = tpcc_test.do_transaction(&mut rng, &mut tx, args.num_ware, &tpcc_args) + if let Err(err) = + tpcc_test.do_transaction(&mut rng, &mut tx, args.num_ware, &tpcc_args, &statement) { failure[i] += 1; eprintln!( diff --git a/tpcc/src/new_ord.rs b/tpcc/src/new_ord.rs index 6ba87f4..3b1fea5 100644 --- a/tpcc/src/new_ord.rs +++ b/tpcc/src/new_ord.rs @@ -1,8 +1,9 @@ use crate::load::{nu_rand, CUST_PER_DIST, DIST_PER_WARE, MAX_ITEMS, MAX_NUM_ITEMS}; use crate::{other_ware, TpccArgs, TpccError, TpccTest, TpccTransaction, ALLOW_MULTI_WAREHOUSE_TX}; use chrono::Utc; -use fnck_sql::db::DBTransaction; +use fnck_sql::db::{DBTransaction, Statement}; use fnck_sql::storage::Storage; +use fnck_sql::types::value::DataValue; use rand::prelude::ThreadRng; use rand::Rng; use rust_decimal::Decimal; @@ -53,58 +54,99 @@ pub(crate) struct NewOrdTest; impl TpccTransaction for NewOrd { type Args = NewOrdArgs; - fn run(tx: &mut DBTransaction, args: &Self::Args) -> Result<(), TpccError> { + fn run( + tx: &mut DBTransaction, + args: &Self::Args, + statements: &[Statement], + ) -> Result<(), TpccError> { let mut price = vec![Decimal::default(); MAX_NUM_ITEMS]; let mut iname = vec![String::new(); MAX_NUM_ITEMS]; let mut stock = vec![0; MAX_NUM_ITEMS]; let mut bg = vec![String::new(); MAX_NUM_ITEMS]; let mut amt = vec![Decimal::default(); MAX_NUM_ITEMS]; - let now = Utc::now().format("%Y-%m-%d %H:%M:%S").to_string(); + let now = Utc::now().naive_utc(); let (c_discount, c_last, c_credit, w_tax) = if args.joins { // "SELECT c_discount, c_last, c_credit, w_tax FROM customer, warehouse WHERE w_id = ? AND c_w_id = w_id AND c_d_id = ? AND c_id = ?" - let (_, tuple) = tx.run(format!("SELECT c.c_discount, c.c_last, c.c_credit, w.w_tax FROM customer AS c JOIN warehouse AS w ON c.c_w_id = w_id AND w.w_id = {} AND c.c_w_id = {} AND c.c_d_id = {} AND c.c_id = {}", args.w_id, args.w_id, args.d_id, args.c_id))?; - let c_discount = tuple[0].values[0].decimal().unwrap(); - let c_last = tuple[0].values[1].utf8().unwrap(); - let c_credit = tuple[0].values[2].utf8().unwrap(); - let w_tax = tuple[0].values[3].decimal().unwrap(); + let (_, tuples) = tx.execute( + &statements[0], + vec![ + ("?1", DataValue::Int16(Some(args.w_id as i16))), + ("?2", DataValue::Int16(Some(args.w_id as i16))), + ("?3", DataValue::Int8(Some(args.d_id as i8))), + ("?4", DataValue::Int64(Some(args.c_id as i64))), + ], + )?; + let c_discount = tuples[0].values[0].decimal().unwrap(); + let c_last = tuples[0].values[1].utf8().unwrap(); + let c_credit = tuples[0].values[2].utf8().unwrap(); + let w_tax = tuples[0].values[3].decimal().unwrap(); (c_discount, c_last, c_credit, w_tax) } else { // "SELECT c_discount, c_last, c_credit FROM customer WHERE c_w_id = ? AND c_d_id = ? AND c_id = ?" - let (_, tuple) = tx.run(format!("SELECT c_discount, c_last, c_credit FROM customer WHERE c_w_id = {} AND c_d_id = {} AND c_id = {}", args.w_id, args.d_id, args.c_id))?; - let c_discount = tuple[0].values[0].decimal().unwrap(); - let c_last = tuple[0].values[1].utf8().unwrap(); - let c_credit = tuple[0].values[2].utf8().unwrap(); + let (_, tuples) = tx.execute( + &statements[1], + vec![ + ("?1", DataValue::Int16(Some(args.w_id as i16))), + ("?2", DataValue::Int8(Some(args.d_id as i8))), + ("?3", DataValue::Int32(Some(args.c_id as i32))), + ], + )?; + let c_discount = tuples[0].values[0].decimal().unwrap(); + let c_last = tuples[0].values[1].utf8().unwrap(); + let c_credit = tuples[0].values[2].utf8().unwrap(); // "SELECT w_tax FROM warehouse WHERE w_id = ?" - let (_, tuple) = tx.run(format!( - "SELECT w_tax FROM warehouse WHERE w_id = {}", - args.w_id - ))?; - let w_tax = tuple[0].values[0].decimal().unwrap(); + let (_, tuples) = tx.execute( + &statements[2], + vec![("?1", DataValue::Int16(Some(args.w_id as i16)))], + )?; + let w_tax = tuples[0].values[0].decimal().unwrap(); (c_discount, c_last, c_credit, w_tax) }; // "SELECT d_next_o_id, d_tax FROM district WHERE d_id = ? AND d_w_id = ? FOR UPDATE" - let (_, tuple) = tx.run(format!( - "SELECT d_next_o_id, d_tax FROM district WHERE d_id = {} AND d_w_id = {}", - args.d_id, args.w_id - ))?; - let d_next_o_id = tuple[0].values[0].i32().unwrap(); - let d_tax = tuple[0].values[1].decimal().unwrap(); + let (_, tuples) = tx.execute( + &statements[3], + vec![ + ("?1", DataValue::Int8(Some(args.d_id as i8))), + ("?2", DataValue::Int16(Some(args.w_id as i16))), + ], + )?; + let d_next_o_id = tuples[0].values[0].i32().unwrap(); + let d_tax = tuples[0].values[1].decimal().unwrap(); // "UPDATE district SET d_next_o_id = ? + 1 WHERE d_id = ? AND d_w_id = ?" - let _ = tx.run(format!( - "UPDATE district SET d_next_o_id = {} + 1 WHERE d_id = {} AND d_w_id = {}", - d_next_o_id, args.d_id, args.w_id - ))?; + let (_, tuples) = tx.execute( + &statements[4], + vec![ + ("?1", DataValue::Int32(Some(d_next_o_id))), + ("?2", DataValue::Int8(Some(args.d_id as i8))), + ("?3", DataValue::Int16(Some(args.w_id as i16))), + ], + )?; let o_id = d_next_o_id; // "INSERT INTO orders (o_id, o_d_id, o_w_id, o_c_id, o_entry_d, o_ol_cnt, o_all_local) VALUES(?, ?, ?, ?, ?, ?, ?)" - let _ = tx.run(format!("INSERT INTO orders (o_id, o_d_id, o_w_id, o_c_id, o_entry_d, o_ol_cnt, o_all_local) VALUES({}, {}, {}, {}, '{}', {}, {})", o_id, args.d_id, args.w_id, args.c_id, now, args.o_ol_cnt, args.o_all_local))?; + let (_, tuples) = tx.execute( + &statements[5], + vec![ + ("?1", DataValue::Int32(Some(o_id))), + ("?2", DataValue::Int8(Some(args.d_id as i8))), + ("?3", DataValue::Int16(Some(args.w_id as i16))), + ("?4", DataValue::Int32(Some(args.c_id as i32))), + ("?5", DataValue::from(&now)), + ("?6", DataValue::Int8(Some(args.o_ol_cnt as i8))), + ("?7", DataValue::Int8(Some(args.o_all_local as i8))), + ], + )?; // "INSERT INTO new_orders (no_o_id, no_d_id, no_w_id) VALUES (?,?,?) - let _ = tx.run(format!( - "INSERT INTO new_orders (no_o_id, no_d_id, no_w_id) VALUES ({},{},{})", - o_id, args.d_id, args.w_id - ))?; + let (_, tuples) = tx.execute( + &statements[6], + vec![ + ("?1", DataValue::Int32(Some(o_id))), + ("?2", DataValue::Int8(Some(args.d_id as i8))), + ("?3", DataValue::Int16(Some(args.w_id as i16))), + ], + )?; let mut ol_num_seq = vec![0; MAX_NUM_ITEMS]; for i in 0..args.o_ol_cnt { @@ -133,10 +175,10 @@ impl TpccTransaction for NewOrd { let ol_i_id = args.item_id[ol_num_seq[ol_number - 1]]; let ol_quantity = args.qty[ol_num_seq[ol_number - 1]]; // "SELECT i_price, i_name, i_data FROM item WHERE i_id = ?" - let (_, tuples) = tx.run(format!( - "SELECT i_price, i_name, i_data FROM item WHERE i_id = {}", - ol_i_id - ))?; + let (_, tuples) = tx.execute( + &statements[7], + vec![("?1", DataValue::Int32(Some(ol_i_id as i32)))], + )?; if tuples.is_empty() { return Err(TpccError::EmptyTuples); } @@ -148,7 +190,13 @@ impl TpccTransaction for NewOrd { iname[ol_num_seq[ol_number - 1]] = i_name; // "SELECT s_quantity, s_data, s_dist_01, s_dist_02, s_dist_03, s_dist_04, s_dist_05, s_dist_06, s_dist_07, s_dist_08, s_dist_09, s_dist_10 FROM stock WHERE s_i_id = ? AND s_w_id = ? FOR UPDATE" - let (_, tuples) = tx.run(format!("SELECT s_quantity, s_data, s_dist_01, s_dist_02, s_dist_03, s_dist_04, s_dist_05, s_dist_06, s_dist_07, s_dist_08, s_dist_09, s_dist_10 FROM stock WHERE s_i_id = {} AND s_w_id = {}", ol_i_id, ol_supply_w_id))?; + let (_, tuples) = tx.execute( + &statements[8], + vec![ + ("?1", DataValue::Int32(Some(ol_i_id as i32))), + ("?2", DataValue::Int16(Some(ol_supply_w_id as i16))), + ], + )?; let mut s_quantity = tuples[0].values[0].i16().unwrap(); let s_data = tuples[0].values[1].utf8().unwrap(); let s_dist_01 = tuples[0].values[2].utf8().unwrap(); @@ -180,10 +228,14 @@ impl TpccTransaction for NewOrd { s_quantity - ol_quantity as i16 + 91 }; // "UPDATE stock SET s_quantity = ? WHERE s_i_id = ? AND s_w_id = ?" - let _ = tx.run(format!( - "UPDATE stock SET s_quantity = {} WHERE s_i_id = {} AND s_w_id = {}", - s_quantity, ol_i_id, ol_supply_w_id - ))?; + let (_, tuples) = tx.execute( + &statements[9], + vec![ + ("?1", DataValue::Int16(Some(s_quantity))), + ("?2", DataValue::Int32(Some(ol_i_id as i32))), + ("?3", DataValue::Int16(Some(ol_supply_w_id as i16))), + ], + )?; // Tips: Integers always have 7 digits, so divide by 10 here let mut ol_amount = Decimal::from(ol_quantity) @@ -196,7 +248,20 @@ impl TpccTransaction for NewOrd { amt[ol_num_seq[ol_number - 1]] = ol_amount; // "INSERT INTO order_line (ol_o_id, ol_d_id, ol_w_id, ol_number, ol_i_id, ol_supply_w_id, ol_quantity, ol_amount, ol_dist_info) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)" - let _ = tx.run(format!("INSERT INTO order_line (ol_o_id, ol_d_id, ol_w_id, ol_number, ol_i_id, ol_supply_w_id, ol_quantity, ol_amount, ol_dist_info) VALUES ({}, {}, {}, {}, {}, {}, {}, {}, '{}')", o_id, args.d_id, args.w_id, ol_number, ol_i_id, ol_supply_w_id, ol_quantity, ol_amount, ol_dist_info))?; + let (_, tuples) = tx.execute( + &statements[10], + vec![ + ("?1", DataValue::Int32(Some(o_id))), + ("?2", DataValue::Int8(Some(args.d_id as i8))), + ("?3", DataValue::Int16(Some(args.w_id as i16))), + ("?4", DataValue::Int8(Some(ol_number as i8))), + ("?5", DataValue::Int32(Some(ol_i_id as i32))), + ("?6", DataValue::Int16(Some(ol_supply_w_id as i16))), + ("?7", DataValue::Int8(Some(ol_quantity as i8))), + ("?8", DataValue::Decimal(Some(ol_amount.round_dp(2)))), + ("?9", DataValue::from(ol_dist_info)), + ], + )?; } Ok(()) @@ -214,6 +279,7 @@ impl TpccTest for NewOrdTest { tx: &mut DBTransaction, num_ware: usize, args: &TpccArgs, + statements: &[Statement], ) -> Result<(), TpccError> { let mut all_local = 1; let notfound = MAX_ITEMS + 1; @@ -248,7 +314,7 @@ impl TpccTest for NewOrdTest { let args = NewOrdArgs::new( args.joins, w_id, d_id, c_id, ol_cnt, all_local, itemid, supware, qty, ); - NewOrd::run(tx, &args)?; + NewOrd::run(tx, &args, statements)?; Ok(()) } diff --git a/tpcc/src/order_stat.rs b/tpcc/src/order_stat.rs index 7364295..982b7a6 100644 --- a/tpcc/src/order_stat.rs +++ b/tpcc/src/order_stat.rs @@ -1,7 +1,8 @@ use crate::load::{last_name, nu_rand, CUST_PER_DIST, DIST_PER_WARE}; use crate::{TpccArgs, TpccError, TpccTest, TpccTransaction}; -use fnck_sql::db::DBTransaction; +use fnck_sql::db::{DBTransaction, Statement}; use fnck_sql::storage::Storage; +use fnck_sql::types::value::DataValue; use rand::prelude::ThreadRng; use rand::Rng; use rust_decimal::Decimal; @@ -39,13 +40,31 @@ pub(crate) struct OrderStatTest; impl TpccTransaction for OrderStat { type Args = OrderStatArgs; - fn run(tx: &mut DBTransaction, args: &Self::Args) -> Result<(), TpccError> { + fn run( + tx: &mut DBTransaction, + args: &Self::Args, + statements: &[Statement], + ) -> Result<(), TpccError> { let (c_balance, c_first, c_middle, c_last) = if args.by_name { // SELECT count(c_id) FROM customer WHERE c_w_id = ? AND c_d_id = ? AND c_last = ?" - let (_, tuples) = tx.run(format!("SELECT count(c_id) FROM customer WHERE c_w_id = {} AND c_d_id = {} AND c_last = '{}'", args.w_id, args.d_id, args.c_last))?; + let (_, tuples) = tx.execute( + &statements[0], + vec![ + ("?1", DataValue::Int16(Some(args.w_id as i16))), + ("?2", DataValue::Int8(Some(args.d_id as i8))), + ("?3", DataValue::from(args.c_last.clone())), + ], + )?; let mut name_cnt = tuples[0].values[0].i32().unwrap() as usize; - // SELECT count(c_id) FROM customer WHERE c_w_id = ? AND c_d_id = ? AND c_last = ?" - let (_, tuples) = tx.run(format!("SELECT c_balance, c_first, c_middle, c_last FROM customer WHERE c_w_id = {} AND c_d_id = {} AND c_last = '{}' ORDER BY c_first", args.w_id, args.d_id, args.c_last))?; + // SELECT c_balance, c_first, c_middle, c_last FROM customer WHERE c_w_id = ? AND c_d_id = ? AND c_last = ? ORDER BY c_first" + let (_, tuples) = tx.execute( + &statements[1], + vec![ + ("?1", DataValue::Int16(Some(args.w_id as i16))), + ("?2", DataValue::Int8(Some(args.d_id as i8))), + ("?3", DataValue::from(args.c_last.clone())), + ], + )?; if name_cnt % 2 == 1 { name_cnt += 1; @@ -64,15 +83,33 @@ impl TpccTransaction for OrderStat { (c_balance, c_first, c_middle, c_last) } else { // "SELECT c_balance, c_first, c_middle, c_last FROM customer WHERE c_w_id = ? AND c_d_id = ? AND c_id = ?" - let (_, tuples) = tx.run(format!("SELECT c_balance, c_first, c_middle, c_last FROM customer WHERE c_w_id = {} AND c_d_id = {} AND c_id = {}", args.w_id, args.d_id, args.c_id))?; + let (_, tuples) = tx.execute( + &statements[2], + vec![ + ("?1", DataValue::Int16(Some(args.w_id as i16))), + ("?2", DataValue::Int8(Some(args.d_id as i8))), + ("?3", DataValue::Int32(Some(args.c_id as i32))), + ], + )?; let c_balance = tuples[0].values[0].decimal().unwrap(); let c_first = tuples[0].values[1].utf8().unwrap(); let c_middle = tuples[0].values[2].utf8().unwrap(); let c_last = tuples[0].values[3].utf8().unwrap(); (c_balance, c_first, c_middle, c_last) }; + // TODO: Join Eq // "SELECT o_id, o_entry_d, COALESCE(o_carrier_id,0) FROM orders WHERE o_w_id = ? AND o_d_id = ? AND o_c_id = ? AND o_id = (SELECT MAX(o_id) FROM orders WHERE o_w_id = ? AND o_d_id = ? AND o_c_id = ?)" - let (_, tuples) = tx.run(format!("SELECT o_id, o_entry_d, COALESCE(o_carrier_id,0) FROM orders WHERE o_w_id = {} AND o_d_id = {} AND o_c_id = {} AND o_id = (SELECT MAX(o_id) FROM orders WHERE o_w_id = {} AND o_d_id = {} AND o_c_id = {})", args.w_id, args.d_id, args.c_id, args.w_id, args.d_id, args.c_id))?; + let (_, tuples) = tx.execute( + &statements[3], + vec![ + ("?1", DataValue::Int16(Some(args.w_id as i16))), + ("?2", DataValue::Int8(Some(args.d_id as i8))), + ("?3", DataValue::Int32(Some(args.c_id as i32))), + ("?4", DataValue::Int16(Some(args.w_id as i16))), + ("?5", DataValue::Int8(Some(args.d_id as i8))), + ("?6", DataValue::Int32(Some(args.c_id as i32))), + ], + )?; if tuples.is_empty() { return Err(TpccError::EmptyTuples); } @@ -80,7 +117,14 @@ impl TpccTransaction for OrderStat { // let o_entry_d = tuples[0].values[1].datetime().unwrap(); // let o_carrier_id = tuples[0].values[2].i32().unwrap(); // "SELECT ol_i_id, ol_supply_w_id, ol_quantity, ol_amount, ol_delivery_d FROM order_line WHERE ol_w_id = ? AND ol_d_id = ? AND ol_o_id = ?" - let (_, tuples) = tx.run(format!("SELECT ol_i_id, ol_supply_w_id, ol_quantity, ol_amount, ol_delivery_d FROM order_line WHERE ol_w_id = {} AND ol_d_id = {} AND ol_o_id = {}", args.w_id, args.d_id, o_id))?; + let (_, tuples) = tx.execute( + &statements[4], + vec![ + ("?1", DataValue::Int16(Some(args.w_id as i16))), + ("?2", DataValue::Int8(Some(args.d_id as i8))), + ("?3", DataValue::Int32(Some(o_id))), + ], + )?; // let ol_i_id = tuples[0].values[0].i32(); // let ol_supply_w_id = tuples[0].values[1].i16(); // let ol_quantity = tuples[0].values[2].i8(); @@ -102,6 +146,7 @@ impl TpccTest for OrderStatTest { tx: &mut DBTransaction, num_ware: usize, _: &TpccArgs, + statements: &[Statement], ) -> Result<(), TpccError> { let w_id = rng.gen_range(0..num_ware) + 1; let d_id = rng.gen_range(1..DIST_PER_WARE); @@ -110,7 +155,7 @@ impl TpccTest for OrderStatTest { let by_name = rng.gen_range(1..100) <= 60; let args = OrderStatArgs::new(w_id, d_id, by_name, c_id, c_last); - OrderStat::run(tx, &args)?; + OrderStat::run(tx, &args, statements)?; Ok(()) } diff --git a/tpcc/src/payment.rs b/tpcc/src/payment.rs index 4e6559e..93ba858 100644 --- a/tpcc/src/payment.rs +++ b/tpcc/src/payment.rs @@ -1,8 +1,9 @@ use crate::load::{last_name, nu_rand, CUST_PER_DIST, DIST_PER_WARE}; use crate::{other_ware, TpccArgs, TpccError, TpccTest, TpccTransaction, ALLOW_MULTI_WAREHOUSE_TX}; use chrono::Utc; -use fnck_sql::db::DBTransaction; +use fnck_sql::db::{DBTransaction, Statement}; use fnck_sql::storage::Storage; +use fnck_sql::types::value::DataValue; use rand::prelude::ThreadRng; use rand::Rng; use rust_decimal::Decimal; @@ -51,15 +52,25 @@ impl TpccTransaction for Payment { type Args = PaymentArgs; #[allow(unused_variables)] - fn run(tx: &mut DBTransaction, args: &Self::Args) -> Result<(), TpccError> { + fn run( + tx: &mut DBTransaction, + args: &Self::Args, + statements: &[Statement], + ) -> Result<(), TpccError> { + let now = Utc::now(); // "UPDATE warehouse SET w_ytd = w_ytd + ? WHERE w_id = ?" - let _ = tx.run(format!( - "UPDATE warehouse SET w_ytd = w_ytd + {} WHERE w_id = {}", - args.h_amount, args.w_id - ))?; - + let (_, tuples) = tx.execute( + &statements[0], + vec![ + ("?1", DataValue::Decimal(Some(args.h_amount))), + ("?2", DataValue::Int16(Some(args.w_id as i16))), + ], + )?; // "SELECT w_street_1, w_street_2, w_city, w_state, w_zip, w_name FROM warehouse WHERE w_id = ?" - let (_, tuples) = tx.run(format!("SELECT w_street_1, w_street_2, w_city, w_state, w_zip, w_name FROM warehouse WHERE w_id = {}", args.w_id))?; + let (_, tuples) = tx.execute( + &statements[1], + vec![("?1", DataValue::Int16(Some(args.w_id as i16)))], + )?; let w_street_1 = tuples[0].values[0].utf8().unwrap(); let w_street_2 = tuples[0].values[1].utf8().unwrap(); let w_city = tuples[0].values[2].utf8().unwrap(); @@ -68,13 +79,23 @@ impl TpccTransaction for Payment { let w_name = tuples[0].values[5].utf8().unwrap(); // "UPDATE district SET d_ytd = d_ytd + ? WHERE d_w_id = ? AND d_id = ?" - let _ = tx.run(format!( - "UPDATE district SET d_ytd = d_ytd + {} WHERE d_w_id = {} AND d_id = {}", - args.h_amount, args.w_id, args.d_id - ))?; + let (_, tuples) = tx.execute( + &statements[2], + vec![ + ("?1", DataValue::Decimal(Some(args.h_amount))), + ("?2", DataValue::Int16(Some(args.w_id as i16))), + ("?3", DataValue::Int8(Some(args.d_id as i8))), + ], + )?; // "SELECT d_street_1, d_street_2, d_city, d_state, d_zip, d_name FROM district WHERE d_w_id = ? AND d_id = ?" - let (_, tuples) = tx.run(format!("SELECT d_street_1, d_street_2, d_city, d_state, d_zip, d_name FROM district WHERE d_w_id = {} AND d_id = {}", args.w_id, args.d_id))?; + let (_, tuples) = tx.execute( + &statements[3], + vec![ + ("?1", DataValue::Int16(Some(args.w_id as i16))), + ("?2", DataValue::Int8(Some(args.d_id as i8))), + ], + )?; let d_street_1 = tuples[0].values[0].utf8().unwrap(); let d_street_2 = tuples[0].values[1].utf8().unwrap(); let d_city = tuples[0].values[2].utf8().unwrap(); @@ -85,11 +106,25 @@ impl TpccTransaction for Payment { let mut c_id = args.c_id as i32; if args.by_name { // "SELECT count(c_id) FROM customer WHERE c_w_id = ? AND c_d_id = ? AND c_last = ?" - let (_, tuples) = tx.run(format!("SELECT count(c_id) FROM customer WHERE c_w_id = {} AND c_d_id = {} AND c_last = '{}'", args.c_w_id, args.c_d_id, args.c_last))?; + let (_, tuples) = tx.execute( + &statements[4], + vec![ + ("?1", DataValue::Int16(Some(args.c_w_id as i16))), + ("?2", DataValue::Int8(Some(args.c_d_id as i8))), + ("?3", DataValue::from(args.c_last.clone())), + ], + )?; let mut name_cnt = tuples[0].values[0].i32().unwrap(); // "SELECT c_id FROM customer WHERE c_w_id = ? AND c_d_id = ? AND c_last = ? ORDER BY c_first" - let (_, tuples) = tx.run(format!("SELECT c_id FROM customer WHERE c_w_id = {} AND c_d_id = {} AND c_last = '{}' ORDER BY c_first", args.c_w_id, args.c_d_id, args.c_last))?; + let (_, tuples) = tx.execute( + &statements[5], + vec![ + ("?1", DataValue::Int16(Some(args.c_w_id as i16))), + ("?2", DataValue::Int8(Some(args.c_d_id as i8))), + ("?3", DataValue::from(args.c_last.clone())), + ], + )?; if name_cnt % 2 == 1 { name_cnt += 1; } @@ -98,7 +133,14 @@ impl TpccTransaction for Payment { } } // "SELECT c_first, c_middle, c_last, c_street_1, c_street_2, c_city, c_state, c_zip, c_phone, c_credit, c_credit_lim, c_discount, c_balance, c_since FROM customer WHERE c_w_id = ? AND c_d_id = ? AND c_id = ? FOR UPDATE" - let (_, tuples) = tx.run(format!("SELECT c_first, c_middle, c_last, c_street_1, c_street_2, c_city, c_state, c_zip, c_phone, c_credit, c_credit_lim, c_discount, c_balance, c_since FROM customer WHERE c_w_id = {} AND c_d_id = {} AND c_id = {}", args.c_w_id, args.c_d_id, c_id))?; + let (_, tuples) = tx.execute( + &statements[6], + vec![ + ("?1", DataValue::Int16(Some(args.c_w_id as i16))), + ("?2", DataValue::Int8(Some(args.c_d_id as i8))), + ("?3", DataValue::Int32(Some(c_id))), + ], + )?; let c_first = tuples[0].values[0].utf8().unwrap(); let c_middle = tuples[0].values[1].utf8().unwrap(); let c_last = tuples[0].values[2].utf8().unwrap(); @@ -118,30 +160,69 @@ impl TpccTransaction for Payment { if let Some(c_credit) = c_credit { if c_credit.contains("BC") { // "SELECT c_data FROM customer WHERE c_w_id = ? AND c_d_id = ? AND c_id = ?" - let (_, tuples) = tx.run(format!( - "SELECT c_data FROM customer WHERE c_w_id = {} AND c_d_id = {} AND c_id = {}", - args.c_w_id, args.c_d_id, c_id - ))?; + let (_, tuples) = tx.execute( + &statements[7], + vec![ + ("?1", DataValue::Int16(Some(args.c_w_id as i16))), + ("?2", DataValue::Int8(Some(args.c_d_id as i8))), + ("?3", DataValue::Int32(Some(c_id))), + ], + )?; let c_data = tuples[0].values[0].utf8().unwrap(); // https://github.com/AgilData/tpcc/blob/dfbabe1e35cc93b2bf2e107fc699eb29c2097e24/src/main/java/com/codefutures/tpcc/Payment.java#L284 // let c_new_data = format!("| {} {} {} {} {} {} {}", c_id, args.c_d_id, args.c_w_id, args.d_id, args.w_id, args.h_amount, ) // "UPDATE customer SET c_balance = ?, c_data = ? WHERE c_w_id = ? AND c_d_id = ? AND c_id = ?" - let _ = tx.run(format!("UPDATE customer SET c_balance = {}, c_data = '{}' WHERE c_w_id = {} AND c_d_id = {} AND c_id = {}", c_balance, c_data, args.c_w_id, args.c_d_id, c_id))?; + let (_, tuples) = tx.execute( + &statements[8], + vec![ + ("?1", DataValue::Decimal(Some(c_balance))), + ("?2", DataValue::from(c_data)), + ("?3", DataValue::Int16(Some(args.c_w_id as i16))), + ("?4", DataValue::Int8(Some(args.c_d_id as i8))), + ("?5", DataValue::Int32(Some(c_id))), + ], + )?; } else { // "UPDATE customer SET c_balance = ? WHERE c_w_id = ? AND c_d_id = ? AND c_id = ?" - let _ = tx.run(format!("UPDATE customer SET c_balance = {} WHERE c_w_id = {} AND c_d_id = {} AND c_id = {}", c_balance, args.c_w_id, args.c_d_id, c_id))?; + let (_, tuples) = tx.execute( + &statements[9], + vec![ + ("?1", DataValue::Decimal(Some(c_balance))), + ("?2", DataValue::Int16(Some(args.c_w_id as i16))), + ("?3", DataValue::Int8(Some(args.c_d_id as i8))), + ("?4", DataValue::Int32(Some(c_id))), + ], + )?; } } else { // "UPDATE customer SET c_balance = ? WHERE c_w_id = ? AND c_d_id = ? AND c_id = ?" - let _ = tx.run(format!("UPDATE customer SET c_balance = {} WHERE c_w_id = {} AND c_d_id = {} AND c_id = {}", c_balance, args.c_w_id, args.c_d_id, c_id))?; + let (_, tuples) = tx.execute( + &statements[9], + vec![ + ("?1", DataValue::Decimal(Some(c_balance))), + ("?2", DataValue::Int16(Some(args.c_w_id as i16))), + ("?3", DataValue::Int8(Some(args.c_d_id as i8))), + ("?4", DataValue::Int32(Some(c_id))), + ], + )?; } let h_data = format!("\\0{d_name} \\0"); - - let now = Utc::now().format("%Y-%m-%d %H:%M:%S").to_string(); // "INSERT INTO history(h_c_d_id, h_c_w_id, h_c_id, h_d_id, h_w_id, h_date, h_amount, h_data) VALUES(?, ?, ?, ?, ?, ?, ?, ?)" - let _ = tx.run(format!("INSERT OVERWRITE history(h_c_d_id, h_c_w_id, h_c_id, h_d_id, h_w_id, h_date, h_amount, h_data) VALUES({}, {}, {}, {}, {}, '{}', {}, '{}')", args.c_d_id, args.c_w_id, c_id, args.d_id, args.w_id, now, args.h_amount, h_data))?; + let (_, tuples) = tx.execute( + &statements[10], + vec![ + ("?1", DataValue::Int8(Some(args.c_d_id as i8))), + ("?2", DataValue::Int16(Some(args.c_w_id as i16))), + ("?3", DataValue::Int32(Some(c_id))), + ("?4", DataValue::Int8(Some(args.d_id as i8))), + ("?5", DataValue::Int16(Some(args.w_id as i16))), + ("?6", DataValue::from(&now.naive_utc())), + ("?7", DataValue::Decimal(Some(args.h_amount))), + ("?8", DataValue::from(h_data)), + ], + )?; Ok(()) } @@ -158,6 +239,7 @@ impl TpccTest for PaymentTest { tx: &mut DBTransaction, num_ware: usize, _: &TpccArgs, + statements: &[Statement], ) -> Result<(), TpccError> { let w_id = rng.gen_range(0..num_ware) + 1; let d_id = rng.gen_range(1..DIST_PER_WARE); @@ -187,7 +269,7 @@ impl TpccTest for PaymentTest { c_last, Decimal::from(h_amount), ); - Payment::run(tx, &args)?; + Payment::run(tx, &args, statements)?; Ok(()) } diff --git a/tpcc/src/slev.rs b/tpcc/src/slev.rs index 00b09df..042c0c5 100644 --- a/tpcc/src/slev.rs +++ b/tpcc/src/slev.rs @@ -1,7 +1,8 @@ use crate::load::DIST_PER_WARE; use crate::{TpccArgs, TpccError, TpccTest, TpccTransaction}; -use fnck_sql::db::DBTransaction; +use fnck_sql::db::{DBTransaction, Statement}; use fnck_sql::storage::Storage; +use fnck_sql::types::value::DataValue; use rand::prelude::ThreadRng; use rand::Rng; @@ -24,21 +25,40 @@ pub(crate) struct SlevTest; impl TpccTransaction for Slev { type Args = SlevArgs; - fn run(tx: &mut DBTransaction, args: &Self::Args) -> Result<(), TpccError> { + fn run( + tx: &mut DBTransaction, + args: &Self::Args, + statements: &[Statement], + ) -> Result<(), TpccError> { // "SELECT d_next_o_id FROM district WHERE d_id = ? AND d_w_id = ?" - let (_, tuples) = tx.run(format!( - "SELECT d_next_o_id FROM district WHERE d_id = {} AND d_w_id = {}", - args.d_id, args.w_id - ))?; + let (_, tuples) = tx.execute( + &statements[0], + vec![ + ("?1", DataValue::Int8(Some(args.d_id as i8))), + ("?2", DataValue::Int16(Some(args.w_id as i16))), + ], + )?; let d_next_o_id = tuples[0].values[0].i32().unwrap(); // "SELECT DISTINCT ol_i_id FROM order_line WHERE ol_w_id = ? AND ol_d_id = ? AND ol_o_id < ? AND ol_o_id >= (? - 20)" - let (_, tuples) = tx.run(format!("SELECT DISTINCT ol_i_id FROM order_line WHERE ol_w_id = {} AND ol_d_id = {} AND ol_o_id < {} AND ol_o_id >= ({} - 20)", args.w_id, args.d_id, d_next_o_id, d_next_o_id))?; + let (_, tuples) = tx.execute( + &statements[1], + vec![ + ("?1", DataValue::Int16(Some(args.w_id as i16))), + ("?2", DataValue::Int8(Some(args.d_id as i8))), + ("?3", DataValue::Int32(Some(d_next_o_id))), + ("?4", DataValue::Int32(Some(d_next_o_id))), + ], + )?; let ol_i_id = tuples[0].values[0].i32().unwrap(); // "SELECT count(*) FROM stock WHERE s_w_id = ? AND s_i_id = ? AND s_quantity < ?" - let (_, tuples) = tx.run(format!( - "SELECT count(*) FROM stock WHERE s_w_id = {} AND s_i_id = {} AND s_quantity < {}", - args.w_id, ol_i_id, args.level - ))?; + let (_, tuples) = tx.execute( + &statements[2], + vec![ + ("?1", DataValue::Int16(Some(args.w_id as i16))), + ("?2", DataValue::Int8(Some(ol_i_id as i8))), + ("?3", DataValue::Int16(Some(args.level as i16))), + ], + )?; // let i_count = tuples[0].values[0].i32().unwrap(); Ok(()) @@ -56,13 +76,14 @@ impl TpccTest for SlevTest { tx: &mut DBTransaction, num_ware: usize, _: &TpccArgs, + statements: &[Statement], ) -> Result<(), TpccError> { let w_id = rng.gen_range(0..num_ware) + 1; let d_id = rng.gen_range(1..DIST_PER_WARE); let level = rng.gen_range(10..20); let args = SlevArgs::new(w_id, d_id, level); - Slev::run(tx, &args)?; + Slev::run(tx, &args, statements)?; Ok(()) }