1--TEST--
2mysqli_stmt_execute() - bind in execute
3--EXTENSIONS--
4mysqli
5--SKIPIF--
6<?php
7require_once 'skipifconnectfailure.inc';
8if (!$IS_MYSQLND) {
9    die("skip only available in mysqlnd");
10}
11?>
12--FILE--
13<?php
14require_once "connect.inc";
15
16require 'table.inc';
17
18mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
19
20// first, control case
21$id = 1;
22$abc = 'abc';
23$stmt = $link->prepare('SELECT label, ? AS anon, ? AS num FROM test WHERE id=?');
24$stmt->bind_param('sss', ...[&$abc, 42, $id]);
25$stmt->execute();
26assert($stmt->get_result()->fetch_assoc() === ['label'=>'a', 'anon'=>'abc', 'num' => '42']);
27$stmt = null;
28
29// 1. same as the control case, but skipping the middle-man (bind_param)
30$stmt = $link->prepare('SELECT label, ? AS anon, ? AS num FROM test WHERE id=?');
31$stmt->execute([&$abc, 42, $id]);
32assert($stmt->get_result()->fetch_assoc() === ['label'=>'a', 'anon'=>'abc', 'num' => '42']);
33$stmt = null;
34
35// 2. param number has to match - missing 1 parameter
36$stmt = $link->prepare('SELECT label, ? AS anon, ? AS num FROM test WHERE id=?');
37try {
38    $stmt->execute([&$abc, 42]);
39} catch (ValueError $e) {
40    echo '[001] '.$e->getMessage()."\n";
41}
42$stmt = null;
43
44// 3. Too many parameters
45$stmt = $link->prepare('SELECT label, ? AS anon, ? AS num FROM test WHERE id=?');
46try {
47    $stmt->execute([&$abc, null, $id, 24]);
48} catch (ValueError $e) {
49    echo '[002] '.$e->getMessage()."\n";
50}
51$stmt = null;
52
53// 4. param number has to match - missing all parameters
54$stmt = $link->prepare('SELECT label, ? AS anon, ? AS num FROM test WHERE id=?');
55try {
56    $stmt->execute([]);
57} catch (ValueError $e) {
58    echo '[003] '.$e->getMessage()."\n";
59}
60$stmt = null;
61
62// 5. param number has to match - missing argument to execute()
63$stmt = $link->prepare('SELECT label, ? AS anon, ? AS num FROM test WHERE id=?');
64try {
65    $stmt->execute();
66} catch (mysqli_sql_exception $e) {
67    echo '[004] '.$e->getMessage()."\n";
68}
69$stmt = null;
70
71// 6. wrong argument to execute()
72$stmt = $link->prepare('SELECT label, ? AS anon, ? AS num FROM test WHERE id=?');
73try {
74    $stmt->execute(42);
75} catch (TypeError $e) {
76    echo '[005] '.$e->getMessage()."\n";
77}
78$stmt = null;
79
80// 7. objects are not arrays and are not accepted
81$stmt = $link->prepare('SELECT label, ? AS anon, ? AS num FROM test WHERE id=?');
82try {
83    $stmt->execute((object)[&$abc, 42, $id]);
84} catch (TypeError $e) {
85    echo '[006] '.$e->getMessage()."\n";
86}
87$stmt = null;
88
89// 8. arrays by reference work too
90$stmt = $link->prepare('SELECT label, ? AS anon, ? AS num FROM test WHERE id=?');
91$arr = [&$abc, 42, $id];
92$arr2 = &$arr;
93$stmt->execute($arr2);
94assert($stmt->get_result()->fetch_assoc() === ['label'=>'a', 'anon'=>'abc', 'num' => '42']);
95$stmt = null;
96
97// 9. no placeholders in statement. nothing to bind in an empty array
98$stmt = $link->prepare('SELECT label FROM test WHERE id=1');
99$stmt->execute([]);
100assert($stmt->get_result()->fetch_assoc() === ['label'=>'a']);
101$stmt = null;
102
103// 10. once bound the values are persisted. Just like in PDO
104$stmt = $link->prepare('SELECT label, ? AS anon, ? AS num FROM test WHERE id=?');
105$stmt->execute(['abc', 42, $id]);
106assert($stmt->get_result()->fetch_assoc() === ['label'=>'a', 'anon'=>'abc', 'num' => '42']);
107$stmt->execute(); // no argument here. Values are already bound
108assert($stmt->get_result()->fetch_assoc() === ['label'=>'a', 'anon'=>'abc', 'num' => '42']);
109try {
110    $stmt->execute([]); // no params here. PDO doesn't throw an error, but mysqli does
111} catch (ValueError $e) {
112    echo '[007] '.$e->getMessage()."\n";
113}
114$stmt = null;
115
116// 11. mixing binding styles not possible. Also, NULL should stay NULL when bound as string
117$stmt = $link->prepare('SELECT label, ? AS anon, ? AS num FROM test WHERE id=?');
118$stmt->bind_param('sss', ...['abc', 42, null]);
119$stmt->execute([null, null, $id]);
120assert($stmt->get_result()->fetch_assoc() === ['label'=>'a', 'anon'=>null, 'num' => null]);
121$stmt = null;
122
123// 12. Only list arrays are allowed
124$stmt = $link->prepare('SELECT label, ? AS anon, ? AS num FROM test WHERE id=?');
125try {
126    $stmt->execute(['A'=>'abc', 2=>42, null=>$id]);
127} catch (ValueError $e) {
128    echo '[008] '.$e->getMessage()."\n";
129}
130$stmt = null;
131
132
133mysqli_close($link);
134?>
135--CLEAN--
136<?php
137require_once "clean_table.inc";
138?>
139--EXPECT--
140[001] mysqli_stmt::execute(): Argument #1 ($params) must consist of exactly 3 elements, 2 present
141[002] mysqli_stmt::execute(): Argument #1 ($params) must consist of exactly 3 elements, 4 present
142[003] mysqli_stmt::execute(): Argument #1 ($params) must consist of exactly 3 elements, 0 present
143[004] No data supplied for parameters in prepared statement
144[005] mysqli_stmt::execute(): Argument #1 ($params) must be of type ?array, int given
145[006] mysqli_stmt::execute(): Argument #1 ($params) must be of type ?array, stdClass given
146[007] mysqli_stmt::execute(): Argument #1 ($params) must consist of exactly 3 elements, 0 present
147[008] mysqli_stmt::execute(): Argument #1 ($params) must be a list array
148