1--TEST--
2mysqli_stmt_bind_result()
3--EXTENSIONS--
4mysqli
5--SKIPIF--
6<?php
7require_once 'skipifconnectfailure.inc';
8?>
9--FILE--
10<?php
11    require 'table.inc';
12
13    $stmt = mysqli_stmt_init($link);
14    if (!mysqli_stmt_prepare($stmt, "SELECT id, label FROM test ORDER BY id LIMIT 1"))
15        printf("[002a] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
16
17    mysqli_stmt_close($stmt);
18    $stmt = mysqli_stmt_init($link);
19
20    $id = null;
21    $label = null;
22    $foo = null;
23
24    try {
25        mysqli_stmt_bind_result($stmt, $id);
26    } catch (Error $exception) {
27        echo $exception->getMessage() . "\n";
28    }
29
30    if (!mysqli_stmt_prepare($stmt, "SELECT id, label FROM test ORDER BY id LIMIT 1"))
31        printf("[004] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
32
33    try {
34        mysqli_stmt_bind_result($stmt, $id);
35    } catch (\ArgumentCountError $e) {
36        echo $e->getMessage() . PHP_EOL;
37    }
38
39    if (true !== ($tmp = mysqli_stmt_bind_result($stmt, $id, $label)))
40        printf("[006] Expecting boolean/true, got %s/%s\n", gettype($tmp), $tmp);
41
42    try {
43        mysqli_stmt_bind_result($stmt, $id, $label, $foo);
44    } catch (\ArgumentCountError $e) {
45        echo $e->getMessage() . PHP_EOL;
46    }
47
48    if (!mysqli_stmt_execute($stmt))
49        printf("[008] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
50
51    while (mysqli_stmt_fetch($stmt)) {
52        var_dump($id);
53        var_dump($label);
54    }
55    mysqli_stmt_close($stmt);
56
57
58    function func_mysqli_stmt_bind_result($link, $engine, $bind_type, $sql_type, $bind_value, $offset, $type_hint = null) {
59
60        if (!mysqli_query($link, "DROP TABLE IF EXISTS test")) {
61            printf("[%04d] [%d] %s\n", $offset, mysqli_errno($link), mysqli_error($link));
62            return false;
63        }
64
65        if (!mysqli_query($link, sprintf("CREATE TABLE test(id INT, label %s, PRIMARY KEY(id)) ENGINE = %s", $sql_type, $engine))) {
66            // don't bail - column type might not be supported by the server, ignore this
67            return false;
68        }
69
70        if (!$stmt = mysqli_stmt_init($link)) {
71            printf("[%04d] [%d] %s\n", $offset + 1, mysqli_errno($link), mysqli_error($link));
72            return false;
73        }
74
75        if (!mysqli_stmt_prepare($stmt, "INSERT INTO test(id, label) VALUES (?, ?)")) {
76            printf("[%04d] [%d] %s\n", $offset + 2, mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
77            return false;
78        }
79
80        $id = null;
81        if (!mysqli_stmt_bind_param($stmt, "i" . $bind_type, $id, $bind_value)) {
82            printf("[%04d] [%d] %s\n", $offset + 3, mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
83            return false;
84        }
85
86        for ($id = 1; $id < 4; $id++) {
87            if (!mysqli_stmt_execute($stmt)) {
88                printf("[%04d] [%d] %s\n", $offset + 3 + $id, mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
89                return false;
90            }
91        }
92        mysqli_stmt_close($stmt);
93
94        $stmt = mysqli_stmt_init($link);
95
96        if (!mysqli_stmt_prepare($stmt, "SELECT id, label FROM test")) {
97            printf("[%04d] [%d] %s\n", $offset + 7, mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
98            return false;
99        }
100
101        if (!mysqli_stmt_execute($stmt)) {
102            printf("[%04d] [%d] %s\n", $offset + 8, mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
103            return false;
104        }
105
106        $bind_res = null;
107        if (!mysqli_stmt_bind_result($stmt, $id, $bind_res)) {
108            printf("[%04d] [%d] %s\n", $offset + 9, mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
109            return false;
110        }
111        $num = 0;
112
113        while (mysqli_stmt_fetch($stmt)) {
114            if ($bind_res !== $bind_value && (!$type_hint || ($type_hint !== gettype($bind_res)))) {
115                printf("[%04d] [%d] Expecting %s/'%s' [type hint = %s], got %s/'%s'\n",
116                    $offset + 10, $num,
117                    gettype($bind_value), $bind_value, $type_hint,
118                    gettype($bind_res), $bind_res);
119                    return false;
120            }
121            $num++;
122        }
123
124        if ($num != 3) {
125            printf("[%04d] [%d] %s, expecting 3 results, got only %d results\n",
126                $offset + 11, mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt), $num);
127            return false;
128        }
129
130        return true;
131    }
132
133
134    function func_mysqli_stmt_bind_make_string($len) {
135
136        $ret = '';
137        for ($i = 0; $i < $len; $i++)
138            $ret .= chr(mt_rand(65, 90));
139
140        return $ret;
141    }
142
143    func_mysqli_stmt_bind_result($link, $engine, "i", "TINYINT", -11, 20);
144    func_mysqli_stmt_bind_result($link, $engine, "i", "TINYINT", NULL, 40);
145    func_mysqli_stmt_bind_result($link, $engine, "i", "TINYINT UNSIGNED", 1, 60);
146    func_mysqli_stmt_bind_result($link, $engine, "i", "TINYINT UNSIGNED", NULL, 80);
147
148    func_mysqli_stmt_bind_result($link, $engine, "i", "BOOL", 1, 100);
149    func_mysqli_stmt_bind_result($link, $engine, "i", "BOOL", NULL, 120);
150    func_mysqli_stmt_bind_result($link, $engine, "i", "BOOLEAN", 0, 140);
151    func_mysqli_stmt_bind_result($link, $engine, "i", "BOOLEAN", NULL, 160);
152
153    func_mysqli_stmt_bind_result($link, $engine, "i", "SMALLINT", -32768, 180);
154    func_mysqli_stmt_bind_result($link, $engine, "i", "SMALLINT", 32767, 200);
155    func_mysqli_stmt_bind_result($link, $engine, "i", "SMALLINT", NULL, 220);
156    func_mysqli_stmt_bind_result($link, $engine, "i", "SMALLINT UNSIGNED", 65535, 240);
157    func_mysqli_stmt_bind_result($link, $engine, "i", "SMALLINT UNSIGNED", NULL, 260);
158
159    func_mysqli_stmt_bind_result($link, $engine, "d", "MEDIUMINT", -8388608, 280, "integer");
160    func_mysqli_stmt_bind_result($link, $engine, "d", "MEDIUMINT", 8388607, 300, "integer");
161    func_mysqli_stmt_bind_result($link, $engine, "d", "MEDIUMINT", NULL, 320);
162    func_mysqli_stmt_bind_result($link, $engine, "d", "MEDIUMINT UNSIGNED", 16777215, 340, "integer");
163    func_mysqli_stmt_bind_result($link, $engine, "d", "MEDIUMINT UNSIGNED", NULL, 360);
164
165    func_mysqli_stmt_bind_result($link, $engine, "i", "INTEGER", (defined("PHP_INT_MAX")) ? max(-1 * PHP_INT_MAX + 1, -2147483648) : 1, 380);
166    func_mysqli_stmt_bind_result($link, $engine, "i", "INTEGER", -2147483647, 400, "integer");
167    func_mysqli_stmt_bind_result($link, $engine, "i", "INTEGER", (defined("PHP_INT_MAX")) ? min(2147483647, PHP_INT_MAX) : 1, 420);
168    func_mysqli_stmt_bind_result($link, $engine, "i", "INTEGER", NULL, 440);
169    func_mysqli_stmt_bind_result($link, $engine, "i", "INTEGER UNSIGNED", (defined("PHP_INT_MAX")) ? min(4294967295, 2147483647) : 1, 460);
170    func_mysqli_stmt_bind_result($link, $engine, "i", "INTEGER UNSIGNED", 4294967295, 480, (defined("PHP_INT_MAX") && (4294967295 > PHP_INT_MAX)) ? "string" : null);
171    func_mysqli_stmt_bind_result($link, $engine, "i", "INTEGER UNSIGNED", NULL, 500);
172
173    /* test is broken too: we bind "integer" but value is a float
174    func_mysqli_stmt_bind_result($link, $engine, "i", "BIGINT", -9223372036854775808, 520);
175    func_mysqli_stmt_bind_result($link, $engine, "i", "BIGINT UNSIGNED", 18446744073709551615, 560);
176    */
177    func_mysqli_stmt_bind_result($link, $engine, "i", "BIGINT", NULL, 540);
178    func_mysqli_stmt_bind_result($link, $engine, "i", "BIGINT UNSIGNED", NULL, 580);
179    func_mysqli_stmt_bind_result($link, $engine, "i", "BIGINT", -1, 1780);
180    func_mysqli_stmt_bind_result($link, $engine, "i", "BIGINT UNSIGNED", 1, 1800);
181    func_mysqli_stmt_bind_result($link, $engine, "i", "BIGINT", -1 * PHP_INT_MAX + 1, 1820);
182    func_mysqli_stmt_bind_result($link, $engine, "i", "BIGINT UNSIGNED", PHP_INT_MAX, 1840);
183
184    func_mysqli_stmt_bind_result($link, $engine, "d", "FLOAT", -9237.21, 600);
185    func_mysqli_stmt_bind_result($link, $engine, "d", "FLOAT", NULL, 620);
186    func_mysqli_stmt_bind_result($link, $engine, "d", "FLOAT UNSIGNED", 18467.5, 640);
187    func_mysqli_stmt_bind_result($link, $engine, "d", "FLOAT UNSIGNED ", NULL, 660);
188
189    // Yes, we need the temporary variable. The PHP casting will foul us otherwise.
190    func_mysqli_stmt_bind_result($link, $engine, "d", "DOUBLE(10,2)", '-99999999.99', 680, "double");
191    func_mysqli_stmt_bind_result($link, $engine, "d", "DOUBLE(10,2)", NULL, 700);
192    func_mysqli_stmt_bind_result($link, $engine, "d", "DOUBLE(10,2) UNSIGNED", '99999999.99' , 720, "double");
193    func_mysqli_stmt_bind_result($link, $engine, "d", "DOUBLE(10,2) UNSIGNED", NULL, 740);
194    func_mysqli_stmt_bind_result($link, $engine, "d", "DECIMAL(10,2)", '-99999999.99', 760, "string");
195    func_mysqli_stmt_bind_result($link, $engine, "d", "DECIMAL(10,2)", NULL, 780);
196    func_mysqli_stmt_bind_result($link, $engine, "d", "DECIMAL(10,2)", '99999999.99', 800, "string");
197    func_mysqli_stmt_bind_result($link, $engine, "d", "DECIMAL(10,2)", NULL, 820);
198
199    // don't care about date() strict TZ warnings...
200    func_mysqli_stmt_bind_result($link, $engine, "s", "DATE", @date('Y-m-d'), 840);
201    func_mysqli_stmt_bind_result($link, $engine, "s", "DATE NOT NULL", @date('Y-m-d'), 860);
202    func_mysqli_stmt_bind_result($link, $engine, "s", "DATE", NULL, 880);
203
204    func_mysqli_stmt_bind_result($link, $engine, "s", "DATETIME", @date('Y-m-d H:i:s'), 900);
205    func_mysqli_stmt_bind_result($link, $engine, "s", "DATETIME NOT NULL", @date('Y-m-d H:i:s'), 920);
206    func_mysqli_stmt_bind_result($link, $engine, "s", "DATETIME", NULL, 940);
207
208    func_mysqli_stmt_bind_result($link, $engine, "s", "TIMESTAMP", @date('Y-m-d H:i:s'), 960);
209
210    func_mysqli_stmt_bind_result($link, $engine, "s", "TIME", @date('H:i:s'), 980);
211    func_mysqli_stmt_bind_result($link, $engine, "s", "TIME NOT NULL", @date('H:i:s'), 1000);
212    func_mysqli_stmt_bind_result($link, $engine, "s", "TIME", NULL, 1020);
213
214    $tmp = intval(@date('Y'));
215    func_mysqli_stmt_bind_result($link, $engine, "s", "YEAR", $tmp, 1040, "string"); // YEAR is a string with implicit display width of 4
216    func_mysqli_stmt_bind_result($link, $engine, "s", "YEAR NOT NULL", $tmp, 1060, "string");
217    func_mysqli_stmt_bind_result($link, $engine, "s", "YEAR", NULL, 1080);
218
219    $string255 = func_mysqli_stmt_bind_make_string(255);
220    func_mysqli_stmt_bind_result($link, $engine, "s", "CHAR(1)", "a", 1110, 'string');
221    func_mysqli_stmt_bind_result($link, $engine, "s", "CHAR(255)", $string255, 1120, 'string');
222    func_mysqli_stmt_bind_result($link, $engine, "s", "CHAR(1) NOT NULL", "a", 1140, 'string');
223    func_mysqli_stmt_bind_result($link, $engine, "s", "CHAR(1)", NULL, 1160);
224
225    $string65k = func_mysqli_stmt_bind_make_string(65535);
226    func_mysqli_stmt_bind_result($link, $engine, "s", "VARCHAR(1)", "a", 1180, 'string');
227    func_mysqli_stmt_bind_result($link, $engine, "s", "VARCHAR(255)", $string255, 1200, 'string');
228    func_mysqli_stmt_bind_result($link, $engine, "s", "VARCHAR(65635)", $string65k, 1220, 'string');
229    func_mysqli_stmt_bind_result($link, $engine, "s", "VARCHAR(1) NOT NULL", "a", 1240, 'string');
230    func_mysqli_stmt_bind_result($link, $engine, "s", "VARCHAR(1)", NULL, 1260);
231
232    func_mysqli_stmt_bind_result($link, $engine, "s", "BINARY(1)", "a", 1280);
233    func_mysqli_stmt_bind_result($link, $engine, "s", "BINARY(1)", chr(0), 1300);
234    func_mysqli_stmt_bind_result($link, $engine, "s", "BINARY(1) NOT NULL", "b", 1320);
235    func_mysqli_stmt_bind_result($link, $engine, "s", "BINARY(1)", NULL, 1340);
236
237    func_mysqli_stmt_bind_result($link, $engine, "s", "VARBINARY(1)", "a", 1360);
238    func_mysqli_stmt_bind_result($link, $engine, "s", "VARBINARY(1)", chr(0), 1380);
239    func_mysqli_stmt_bind_result($link, $engine, "s", "VARBINARY(1) NOT NULL", "b", 1400);
240    func_mysqli_stmt_bind_result($link, $engine, "s", "VARBINARY(1)", NULL, 1420);
241
242    func_mysqli_stmt_bind_result($link, $engine, "s", "TINYBLOB", "a", 1440);
243    func_mysqli_stmt_bind_result($link, $engine, "s", "TINYBLOB", chr(0), 1460);
244    func_mysqli_stmt_bind_result($link, $engine, "s", "TINYBLOB NOT NULL", "b", 1480);
245    func_mysqli_stmt_bind_result($link, $engine, "s", "TINYBLOB", NULL, 1500);
246
247    func_mysqli_stmt_bind_result($link, $engine, "s", "TINYTEXT", "a", 1520, 'string');
248    func_mysqli_stmt_bind_result($link, $engine, "s", "TINYTEXT NOT NULL", "a", 1540, 'string');
249    func_mysqli_stmt_bind_result($link, $engine, "s", "TINYTEXT", NULL, 1560, 'string');
250
251    // Note: you cannot insert any blob values this way. But you can check the API at least partly this way
252    // Extra BLOB tests are in mysqli_stmt_send_long()
253    func_mysqli_stmt_bind_result($link, $engine, "b", "BLOB", "", 1580);
254    func_mysqli_stmt_bind_result($link, $engine, "b", "TEXT", "", 1600, 'string');
255    func_mysqli_stmt_bind_result($link, $engine, "b", "MEDIUMBLOB", "", 1620);
256    func_mysqli_stmt_bind_result($link, $engine, "b", "MEDIUMTEXT", "", 1640, 'string');
257
258    /* Is this one related? http://bugs.php.net/bug.php?id=35759 */
259    func_mysqli_stmt_bind_result($link, $engine, "b", "LONGBLOB", "", 1660);
260    func_mysqli_stmt_bind_result($link, $engine, "b", "LONGTEXT", "", 1680, 'string');
261
262    func_mysqli_stmt_bind_result($link, $engine, "s", "ENUM('a', 'b')", "a", 1700, 'string');
263    func_mysqli_stmt_bind_result($link, $engine, "s", "ENUM('a', 'b')", NULL, 1720, 'string');
264    func_mysqli_stmt_bind_result($link, $engine, "s", "SET('a', 'b')", "a", 1740, 'string');
265    func_mysqli_stmt_bind_result($link, $engine, "s", "SET('a', 'b')", NULL, 1760, 'string');
266
267    if (mysqli_get_server_version($link) >= 50600)
268        func_mysqli_stmt_bind_result($link, $engine, "s", "TIME(6)", "13:31:34.123456", 1770);
269
270    $stmt = mysqli_stmt_init($link);
271    if (!mysqli_stmt_prepare($stmt, "INSERT INTO test(id, label) VALUES (1000, 'z')"))
272        printf("[3001] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
273
274    $id = null;
275    try {
276        mysqli_stmt_bind_result($stmt, $id);
277    } catch (\ArgumentCountError $e) {
278        echo $e->getMessage() . \PHP_EOL;
279    }
280
281    mysqli_stmt_close($stmt);
282
283    mysqli_close($link);
284    print "done!";
285?>
286--CLEAN--
287<?php
288    require_once 'clean_table.inc';
289?>
290--EXPECTF--
291mysqli_stmt object is not fully initialized
292Number of bind variables doesn't match number of fields in prepared statement
293Number of bind variables doesn't match number of fields in prepared statement
294int(1)
295%s(1) "a"
296Number of bind variables doesn't match number of fields in prepared statement
297done!
298