Commit dbf56e0eba6 for php.net

commit dbf56e0eba68c61385e9a2d15a3e3f5066f80ec4
Author: Kamil Tekiela <tekiela246@gmail.com>
Date:   Sun Dec 14 15:23:43 2025 +0000

    Squashed commit of the following:

    commit c4adcbe582faa263f11404ac89eb2cb80f2bdbca
    Author: Kamil Tekiela <tekiela246@gmail.com>
    Date:   Fri Oct 17 15:32:14 2025 +0100

        Add NEWS

    commit 84a6e675af9c1cf74c17f06aeca84cca358e064b
    Author: Kamil Tekiela <tekiela246@gmail.com>
    Date:   Fri Oct 17 14:49:26 2025 +0100

        Handle errors in mysqli_begin_transaction

diff --git a/NEWS b/NEWS
index ed2c4149a03..13f673a53c0 100644
--- a/NEWS
+++ b/NEWS
@@ -8,7 +8,7 @@ PHP                                                                        NEWS

 - Bz2:
   . Fixed bug GH-20620 (bzcompress overflow on large source size).
-    (David Carlier)
+    (David Carlier)

 - GD:
   . Fixed bug GH-20622 (imagestring/imagestringup overflow). (David Carlier)
@@ -70,6 +70,9 @@ PHP                                                                        NEWS
   . Fixed bug GH-20492 (mbstring compile warning due to non-strings).
     (ndossche)

+- mysqli:
+  . Make mysqli_begin_transaction() report errors properly. (Kamil Tekiela)
+
 - MySQLnd:
   . Fixed bug GH-20528 (Regression breaks mysql connexion using an IPv6 address
     enclosed in square brackets). (Remi)
diff --git a/ext/mysqli/mysqli_nonapi.c b/ext/mysqli/mysqli_nonapi.c
index 406d9286997..1f971d000fa 100644
--- a/ext/mysqli/mysqli_nonapi.c
+++ b/ext/mysqli/mysqli_nonapi.c
@@ -1022,6 +1022,7 @@ PHP_FUNCTION(mysqli_begin_transaction)
 	}

 	if (FAIL == mysqlnd_begin_transaction(mysql->mysql, flags, name)) {
+		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
 		RETURN_FALSE;
 	}
 	RETURN_TRUE;
@@ -1046,6 +1047,7 @@ PHP_FUNCTION(mysqli_savepoint)
 	}

 	if (FAIL == mysqlnd_savepoint(mysql->mysql, name)) {
+		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
 		RETURN_FALSE;
 	}
 	RETURN_TRUE;
@@ -1069,6 +1071,7 @@ PHP_FUNCTION(mysqli_release_savepoint)
 		RETURN_THROWS();
 	}
 	if (FAIL == mysqlnd_release_savepoint(mysql->mysql, name)) {
+		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
 		RETURN_FALSE;
 	}
 	RETURN_TRUE;
diff --git a/ext/mysqli/tests/mysqli_begin_transaction_error.phpt b/ext/mysqli/tests/mysqli_begin_transaction_error.phpt
new file mode 100644
index 00000000000..e4d63f366e8
--- /dev/null
+++ b/ext/mysqli/tests/mysqli_begin_transaction_error.phpt
@@ -0,0 +1,42 @@
+--TEST--
+mysqli_begin_transaction()
+--EXTENSIONS--
+mysqli
+--SKIPIF--
+<?php
+require_once 'skipifconnectfailure.inc';
+
+require_once 'connect.inc';
+if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket))
+    die(sprintf("skip Cannot connect, [%d] %s", mysqli_connect_errno(), mysqli_connect_error()));
+
+if (!have_innodb($link))
+    die(sprintf("skip Needs InnoDB support, [%d] %s", $link->errno, $link->error));
+?>
+--FILE--
+<?php
+require_once 'connect.inc';
+
+mysqli_report(MYSQLI_REPORT_ALL & ~MYSQLI_REPORT_INDEX);
+$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket);
+try {
+    mysqli_query($link, sprintf('KILL %d', mysqli_thread_id($link)));
+} catch (mysqli_sql_exception) {
+    // ignore
+}
+
+try {
+    mysqli_begin_transaction($link);
+} catch (mysqli_sql_exception $e) {
+    echo "Expecting an exception.\n";
+}
+
+echo "done!\n";
+?>
+--CLEAN--
+<?php
+    require_once 'clean_table.inc';
+?>
+--EXPECT--
+Expecting an exception.
+done!