Enhance change_falukant_user_money: Implement money clamping logic to ensure updates stay within numeric(10,2) limits, improving data integrity and error handling.
This commit is contained in:
@@ -158,46 +158,62 @@ impl BaseWorker {
|
|||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We must ensure the resulting money fits in numeric(10,2).
|
||||||
|
// numeric(10,2) max absolute value is < 10^8 (100_000_000) before rounding.
|
||||||
|
// Fetch current money for the user and clamp the delta if needed.
|
||||||
|
const QUERY_GET_MONEY: &str = r#"
|
||||||
|
SELECT money FROM falukant_data.falukant_user WHERE id = $1;
|
||||||
|
"#;
|
||||||
|
conn.prepare("get_money_for_clamp", QUERY_GET_MONEY)?;
|
||||||
|
let rows = conn.execute("get_money_for_clamp", &[&falukant_user_id])?;
|
||||||
|
|
||||||
|
let current_money: f64 = rows
|
||||||
|
.get(0)
|
||||||
|
.and_then(|r| r.get("money"))
|
||||||
|
.and_then(|v| v.parse::<f64>().ok())
|
||||||
|
.unwrap_or(0.0);
|
||||||
|
|
||||||
|
// compute tentative result
|
||||||
|
let tentative = current_money + money_change;
|
||||||
|
|
||||||
|
// numeric(10,2) allows values with absolute < 10^8 (100_000_000)
|
||||||
|
const MAX_ABS: f64 = 100_000_000.0 - 0.01; // leave room for scale
|
||||||
|
|
||||||
|
let adjusted_money_change = if tentative >= MAX_ABS {
|
||||||
|
let clipped = MAX_ABS - current_money;
|
||||||
|
eprintln!(
|
||||||
|
"[BaseWorker] Clamping money_change: tentative {} exceeds numeric(10,2) max, clipping to {}",
|
||||||
|
tentative, clipped
|
||||||
|
);
|
||||||
|
clipped
|
||||||
|
} else if tentative <= -MAX_ABS {
|
||||||
|
let clipped = -MAX_ABS - current_money;
|
||||||
|
eprintln!(
|
||||||
|
"[BaseWorker] Clamping money_change: tentative {} below min, clipping to {}",
|
||||||
|
tentative, clipped
|
||||||
|
);
|
||||||
|
clipped
|
||||||
|
} else {
|
||||||
|
money_change
|
||||||
|
};
|
||||||
|
|
||||||
// Send exact types matching the DB function signature:
|
// Send exact types matching the DB function signature:
|
||||||
// p_falukant_user_id integer, p_money_change numeric, p_activity text
|
|
||||||
let uid_i32: i32 = falukant_user_id;
|
let uid_i32: i32 = falukant_user_id;
|
||||||
let money_str = money_change.to_string(); // numeric accepts text
|
let money_str = format!("{:.2}", adjusted_money_change);
|
||||||
|
|
||||||
let p1: &(dyn ToSql + Sync) = &uid_i32;
|
let p1: &(dyn ToSql + Sync) = &uid_i32;
|
||||||
let p2: &(dyn ToSql + Sync) = &money_str;
|
let p2: &(dyn ToSql + Sync) = &money_str;
|
||||||
let p3: &(dyn ToSql + Sync) = &action;
|
let p3: &(dyn ToSql + Sync) = &action;
|
||||||
|
|
||||||
// Minimal logging
|
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"[BaseWorker] change_falukant_user_money: update_money(user_id={}, money_change='{}', action={})",
|
"[BaseWorker] change_falukant_user_money: update_money(user_id={}, money_change='{}', action={})",
|
||||||
uid_i32, money_str, action
|
uid_i32, money_str, action
|
||||||
);
|
);
|
||||||
|
|
||||||
// Try parameterized call first
|
// Execute parameterized
|
||||||
match conn.execute("update_money", &[p1, p2, p3]) {
|
let _ = conn.execute("update_money", &[p1, p2, p3])?;
|
||||||
Ok(_) => return Ok(()),
|
|
||||||
Err(err) => {
|
|
||||||
eprintln!(
|
|
||||||
"[BaseWorker] parameterized update_money failed: {err}, falling back to literal SQL",
|
|
||||||
|
|
||||||
);
|
|
||||||
// Fall back: build SQL with literals. Escape action safely (double single-quotes).
|
|
||||||
fn escape_sql_literal(s: &str) -> String {
|
|
||||||
s.replace('\'', "''")
|
|
||||||
}
|
|
||||||
|
|
||||||
let escaped_action = escape_sql_literal(action);
|
Ok(())
|
||||||
// money_str is already a numeric literal string (e.g. "3726" or "1597.12")
|
|
||||||
let sql = format!(
|
|
||||||
"SELECT falukant_data.update_money({}, {}::numeric, '{}');",
|
|
||||||
uid_i32, money_str, escaped_action
|
|
||||||
);
|
|
||||||
|
|
||||||
// Use query without parameters
|
|
||||||
let _ = conn.query(&sql)?;
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user