"""End-to-end INSERT benchmarks — single-row, executemany, and the gap. The single-row vs. executemany delta is the ``executemany`` win — we PREPARE+RELEASE once and BIND+EXECUTE per row, vs PREPARE+RELEASE per row. On any decent network this is 10-50x. """ from __future__ import annotations import contextlib import pytest import informix_db pytestmark = [pytest.mark.benchmark, pytest.mark.integration] def _setup_temp_table(conn: informix_db.Connection, name: str) -> None: cur = conn.cursor() with contextlib.suppress(informix_db.Error): cur.execute(f"DROP TABLE {name}") cur.execute( f"CREATE TABLE {name} (id INT, name VARCHAR(64), value FLOAT)" ) def _drop_temp_table(conn: informix_db.Connection, name: str) -> None: cur = conn.cursor() with contextlib.suppress(informix_db.Error): cur.execute(f"DROP TABLE {name}") def test_insert_single_row(benchmark, bench_conn: informix_db.Connection) -> None: """Single INSERT per call — full PREPARE+BIND+EXECUTE+RELEASE cycle.""" table = "p21_ins_single" _setup_temp_table(bench_conn, table) counter = [0] def run() -> None: counter[0] += 1 cur = bench_conn.cursor() cur.execute( f"INSERT INTO {table} VALUES (?, ?, ?)", (counter[0], f"name_{counter[0]}", float(counter[0])), ) cur.close() try: benchmark(run) finally: _drop_temp_table(bench_conn, table) def test_executemany_100_rows( benchmark, bench_conn: informix_db.Connection ) -> None: """100 INSERTs via executemany — one PREPARE, 100 BIND+EXECUTEs, one RELEASE.""" table = "p21_ins_emany_100" _setup_temp_table(bench_conn, table) counter = [0] def run() -> None: counter[0] += 1 base = counter[0] * 100 rows = [ (base + i, f"row_{base + i}", float(base + i)) for i in range(100) ] cur = bench_conn.cursor() cur.executemany( f"INSERT INTO {table} VALUES (?, ?, ?)", rows, ) cur.close() try: benchmark(run) finally: _drop_temp_table(bench_conn, table) def test_executemany_1000_rows( benchmark, bench_conn: informix_db.Connection ) -> None: """1000 INSERTs via executemany — sustained-batch throughput.""" table = "p21_ins_emany_1000" _setup_temp_table(bench_conn, table) counter = [0] def run() -> None: counter[0] += 1 base = counter[0] * 1000 rows = [ (base + i, f"row_{base + i}", float(base + i)) for i in range(1000) ] cur = bench_conn.cursor() cur.executemany( f"INSERT INTO {table} VALUES (?, ?, ?)", rows, ) cur.close() try: benchmark.pedantic(run, rounds=3, iterations=1) finally: _drop_temp_table(bench_conn, table)