Skip to content
Merged
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
30 changes: 30 additions & 0 deletions mysql-dual-conn/init.sql
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,33 @@ CREATE USER IF NOT EXISTS 'stagebuster'@'%' IDENTIFIED BY 'camundaPassword';
GRANT ALL PRIVILEGES ON camunda.* TO 'stagebuster'@'%';

FLUSH PRIVILEGES;

-- Column-type fidelity fixture (keploy/keploy#4426).
--
-- The OMS datasource runs with useServerPrepStmts=true, so a SELECT over
-- this table comes back as a binary-protocol result set — the wire format
-- whose FLOAT/DOUBLE columns keploy decoded as their raw IEEE-754 bit
-- pattern rather than their value, corrupting mocks.yaml at record time.
--
-- The BIGINT UNSIGNED column covers the other half: values above MaxInt64
-- have no lossless float64 form, so a mock format that routes them through
-- one collapses distinct rows onto the same number.
USE myntra_oms;

CREATE TABLE IF NOT EXISTS numeric_fidelity (
id INT PRIMARY KEY,
label VARCHAR(32) NOT NULL,
price_f FLOAT NOT NULL,
ratio_d DOUBLE NOT NULL,
big_u BIGINT UNSIGNED NOT NULL
);

INSERT INTO numeric_fidelity (id, label, price_f, ratio_d, big_u) VALUES
-- 9.99 is the value from the bug report: read as a numeric cast it
-- surfaces as 1.0926057e+09 (FLOAT) / 4.621813488089437e+18 (DOUBLE).
(1, 'nine-ninety-nine', 9.99, 9.99, 18446744073709551615),
(2, 'negative', -0.5, -1234.5678, 9223372036854775808),
(3, 'zero', 0, 0, 0),
(4, 'whole', 10, 10, 4294967296),
(5, 'small', 1.5, 2.2250738585072014e-308, 1)
ON DUPLICATE KEY UPDATE label = VALUES(label);
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,51 @@ public List<Map<String, Object>> queryCamunda() {
* cascade into "Connection closing due to no matching mock found" and
* tear down the TCP connection.
*/
/**
* Selects FLOAT / DOUBLE / BIGINT UNSIGNED columns over the OMS
* datasource, which runs with useServerPrepStmts=true.
*
* The {@code id >= ?} predicate is load-bearing, not filler: without
* a bound parameter JdbcTemplate issues a plain Statement, which
* Connector/J sends as COM_QUERY and MySQL answers with a *text*
* result set — every value a length-encoded string, which is not the
* code path this fixture exists to cover. The parameter forces a
* server-side prepared statement, so the rows come back as a
* binary-protocol result set carrying raw IEEE-754 bytes.
*
* This is the read path for keploy/keploy#4426: keploy decoded the
* FLOAT and DOUBLE wire bytes as a numeric cast instead of an
* IEEE-754 reinterpret, so a column holding 9.99 was recorded as
* 1.0926057e+09 / 4.621813488089437e+18. The corruption happened at
* record time, so it survived re-recording and replay asserted
* against a value the database never returned.
*
* big_u covers the neighbouring defect: a BIGINT UNSIGNED above
* MaxInt64 has no lossless float64 form, so any mock format that
* routes it through one collapses distinct rows onto one number.
*/
@GetMapping("/api/oms/numerics")
public List<Map<String, Object>> numerics() {
return omsJdbc.queryForList(
"SELECT id, label, price_f, ratio_d, big_u FROM numeric_fidelity "
+ "WHERE id >= ? ORDER BY id",
0);
}

/**
* Binds a FLOAT parameter, exercising the COM_STMT_EXECUTE decode
* path rather than the result-set one. The bound value is a float32
* on the wire and comes back out of the mock file as a float64, so
* keploy's parameter matcher has to compare the two at float32
* precision — widening instead means a correctly recorded FLOAT
* parameter never matches itself and replay finds no mock.
*/
@GetMapping("/api/oms/float-param/{v}")
public List<Map<String, Object>> floatParam(@PathVariable("v") float v) {
return omsJdbc.queryForList(
"SELECT id, label, price_f FROM numeric_fidelity WHERE price_f = ? ORDER BY id", v);
}

@GetMapping("/api/oms/stmt-reset/{n}")
public List<Integer> stmtReset(@PathVariable("n") int n) {
return omsJdbc.execute((java.sql.Connection conn) -> {
Expand Down
Loading