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