1--TEST--
2mysqli_stmt_attr_set() - mysqlnd does not check for invalid codes
3--EXTENSIONS--
4mysqli
5--SKIPIF--
6<?php
7require_once 'skipifconnectfailure.inc';
8?>
9--FILE--
10<?php
11    require 'table.inc';
12
13    $valid_attr = array(MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH);
14    $valid_attr[] = MYSQLI_STMT_ATTR_CURSOR_TYPE;
15    $valid_attr[] =	MYSQLI_CURSOR_TYPE_NO_CURSOR;
16    $valid_attr[] =	MYSQLI_CURSOR_TYPE_READ_ONLY;
17    $valid_attr[] =	MYSQLI_CURSOR_TYPE_FOR_UPDATE;
18    $valid_attr[] =	MYSQLI_CURSOR_TYPE_SCROLLABLE;
19    $valid_attr[] = MYSQLI_STMT_ATTR_PREFETCH_ROWS;
20
21
22    $stmt = mysqli_stmt_init($link);
23    try {
24        mysqli_stmt_attr_set($stmt, 0, 0);
25    } catch (\Throwable $e) {
26        echo get_class($e) . ': ' . $e->getMessage() . PHP_EOL;
27    }
28
29    $stmt->prepare("SELECT * FROM test");
30    // Invalid Attribute (2nd argument)
31    try {
32        mysqli_stmt_attr_set($stmt, -1, 0);
33    } catch (\ValueError $e) {
34        echo $e->getMessage() . \PHP_EOL;
35    }
36    // Invalid mode for MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH
37    try {
38        $stmt->attr_set(MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH, -1);
39    } catch (\ValueError $e) {
40        echo $e->getMessage() . \PHP_EOL;
41    }
42    $stmt->close();
43
44    //
45    // MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH
46    //
47    // expecting max_length not to be set and be 0 in all cases
48    $stmt = mysqli_stmt_init($link);
49    $stmt->prepare("SELECT label FROM test");
50    $stmt->execute();
51    $stmt->store_result();
52    $res = $stmt->result_metadata();
53    $fields = $res->fetch_fields();
54    $max_lengths = array();
55    foreach ($fields as $k => $meta) {
56        $max_lengths[$meta->name] = $meta->max_length;
57        if ($meta->max_length !== 0)
58            printf("[007] max_length should be not set (= 0), got %s for field %s\n", $meta->max_length, $meta->name);
59    }
60    $res->close();
61    $stmt->close();
62
63    // MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH is no longer supported, expect no change in behavior.
64    $stmt = mysqli_stmt_init($link);
65    $stmt->prepare("SELECT label FROM test");
66    var_dump($stmt->attr_set(MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH, 1));
67    $res = $stmt->attr_get(MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH);
68    if ($res !== 1)
69        printf("[007.1] max_length should be 1, got %s\n", $res);
70    $stmt->execute();
71    $stmt->store_result();
72    $res = $stmt->result_metadata();
73    $fields = $res->fetch_fields();
74    $max_lengths = array();
75    foreach ($fields as $k => $meta) {
76        $max_lengths[$meta->name] = $meta->max_length;
77        if ($meta->max_length !== 0)
78            printf("[008] max_length should be not set (= 0), got %s for field %s\n", $meta->max_length, $meta->name);
79    }
80    $res->close();
81    $stmt->close();
82
83    // expecting max_length not to be set
84    $stmt = mysqli_stmt_init($link);
85    $stmt->prepare("SELECT label FROM test");
86    $stmt->attr_set(MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH, 0);
87    $res = $stmt->attr_get(MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH);
88    if ($res !== 0)
89        printf("[008.1] max_length should be 0, got %s\n", $res);
90    $stmt->execute();
91    $stmt->store_result();
92    $res = $stmt->result_metadata();
93    $fields = $res->fetch_fields();
94    $max_lengths = array();
95    foreach ($fields as $k => $meta) {
96        $max_lengths[$meta->name] = $meta->max_length;
97        if ($meta->max_length !== 0)
98            printf("[009] max_length should not be set (= 0), got %s for field %s\n", $meta->max_length, $meta->name);
99    }
100    $res->close();
101    $stmt->close();
102
103    //
104    // Cursors
105    //
106
107
108    $stmt = mysqli_stmt_init($link);
109    $stmt->prepare("SELECT id, label FROM test");
110
111    // Invalid cursor type
112    try {
113        $stmt->attr_set(MYSQLI_STMT_ATTR_CURSOR_TYPE, -1);
114    } catch (\ValueError $e) {
115        echo $e->getMessage() . \PHP_EOL;
116    }
117
118    if (false !== ($tmp = $stmt->attr_set(MYSQLI_STMT_ATTR_CURSOR_TYPE, MYSQLI_CURSOR_TYPE_FOR_UPDATE)))
119        printf("[011] Expecting boolean/false, got %s/%s\n", gettype($tmp), $tmp);
120
121    if (false !== ($tmp = $stmt->attr_set(MYSQLI_STMT_ATTR_CURSOR_TYPE, MYSQLI_CURSOR_TYPE_SCROLLABLE)))
122        printf("[012] Expecting boolean/false, got %s/%s\n", gettype($tmp), $tmp);
123
124    if (true !== ($tmp = $stmt->attr_set(MYSQLI_STMT_ATTR_CURSOR_TYPE, MYSQLI_CURSOR_TYPE_NO_CURSOR)))
125        printf("[013] Expecting boolean/true, got %s/%s\n", gettype($tmp), $tmp);
126
127    if (true !== ($tmp = $stmt->attr_set(MYSQLI_STMT_ATTR_CURSOR_TYPE, MYSQLI_CURSOR_TYPE_READ_ONLY)))
128        printf("[014] Expecting boolean/true, got %s/%s\n", gettype($tmp), $tmp);
129
130    $stmt->close();
131
132    $stmt = mysqli_stmt_init($link);
133    $stmt->prepare("SELECT id, label FROM test");
134    $stmt->execute();
135    $id = $label = NULL;
136    $stmt->bind_result($id, $label);
137    $results = array();
138    while ($stmt->fetch())
139        $results[$id] = $label;
140    $stmt->close();
141    if (empty($results))
142        printf("[015] Results should not be empty, subsequent tests will probably fail!\n");
143
144    $stmt = mysqli_stmt_init($link);
145    $stmt->prepare("SELECT id, label FROM test");
146    if (true !== ($tmp = $stmt->attr_set(MYSQLI_STMT_ATTR_CURSOR_TYPE, MYSQLI_CURSOR_TYPE_NO_CURSOR)))
147        printf("[016] Expecting boolean/true, got %s/%s\n", gettype($tmp), $tmp);
148    $stmt->execute();
149    $id = $label = NULL;
150    $stmt->bind_result($id, $label);
151    $results2 = array();
152    while ($stmt->fetch())
153        $results2[$id] = $label;
154    $stmt->close();
155    if ($results != $results2) {
156        printf("[017] Results should not differ. Dumping both result sets.\n");
157        var_dump($results);
158        var_dump($results2);
159    }
160
161    $stmt = mysqli_stmt_init($link);
162    $stmt->prepare("SELECT id, label FROM test");
163    if (true !== ($tmp = $stmt->attr_set(MYSQLI_STMT_ATTR_CURSOR_TYPE, MYSQLI_CURSOR_TYPE_READ_ONLY)))
164        printf("[018] Expecting boolean/true, got %s/%s\n", gettype($tmp), $tmp);
165    $stmt->execute();
166    $id = $label = NULL;
167    $stmt->bind_result($id, $label);
168    $results2 = array();
169    while ($stmt->fetch())
170        $results2[$id] = $label;
171    $stmt->close();
172    if ($results != $results2) {
173        printf("[019] Results should not differ. Dumping both result sets.\n");
174        var_dump($results);
175        var_dump($results2);
176    }
177
178
179    //
180    // MYSQLI_STMT_ATTR_PREFETCH_ROWS
181    //
182
183    $stmt = mysqli_stmt_init($link);
184    $stmt->prepare("SELECT id, label FROM test");
185    // Invalid prefetch value
186    try {
187        $stmt->attr_set(MYSQLI_STMT_ATTR_PREFETCH_ROWS, 0);
188    } catch (\ValueError $e) {
189        echo $e->getMessage() . \PHP_EOL;
190    }
191
192    if (true !== ($tmp = $stmt->attr_set(MYSQLI_STMT_ATTR_PREFETCH_ROWS, 1)))
193        printf("[020] Expecting boolean/true, got %s/%s\n", gettype($tmp), $tmp);
194    $stmt->execute();
195    $id = $label = NULL;
196    $stmt->bind_result($id, $label);
197    $results = array();
198    while ($stmt->fetch())
199        $results[$id] = $label;
200    $stmt->close();
201    if (empty($results))
202        printf("[021] Results should not be empty, subsequent tests will probably fail!\n");
203
204    /* prefetch is not supported
205    $stmt = mysqli_stmt_init($link);
206    $stmt->prepare("SELECT label FROM test");
207    if (false !== ($tmp = $stmt->attr_set(MYSQLI_STMT_ATTR_PREFETCH_ROWS, -1)))
208        printf("[022] Expecting boolean/false, got %s/%s\n", gettype($tmp), $tmp);
209    $stmt->close();
210
211    $stmt = mysqli_stmt_init($link);
212    $stmt->prepare("SELECT label FROM test");
213    if (true !== ($tmp = $stmt->attr_set(MYSQLI_STMT_ATTR_PREFETCH_ROWS, PHP_INT_MAX)))
214            printf("[023] Expecting boolean/true, got %s/%s\n", gettype($tmp), $tmp);
215    $stmt->close();
216
217    $stmt = mysqli_stmt_init($link);
218    $stmt->prepare("SELECT id, label FROM test");
219    if (true !== ($tmp = $stmt->attr_set(MYSQLI_STMT_ATTR_PREFETCH_ROWS, 2)))
220        printf("[024] Expecting boolean/true, got %s/%s\n", gettype($tmp), $tmp);
221    $stmt->execute();
222    $id = $label = NULL;
223    $stmt->bind_result($id, $label);
224    $results2 = array();
225    while ($stmt->fetch())
226        $results2[$id] = $label;
227    $stmt->close();
228    if ($results != $results2) {
229        printf("[025] Results should not differ. Dumping both result sets.\n");
230        var_dump($results);
231        var_dump($results2);
232    }
233    */
234
235    mysqli_close($link);
236    print "done!";
237?>
238--CLEAN--
239<?php
240    require_once 'clean_table.inc';
241?>
242--EXPECT--
243Error: mysqli_stmt object is not fully initialized
244mysqli_stmt_attr_set(): Argument #2 ($attribute) must be one of MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH, MYSQLI_STMT_ATTR_PREFETCH_ROWS, or STMT_ATTR_CURSOR_TYPE
245mysqli_stmt::attr_set(): Argument #2 ($value) must be 0 or 1 for attribute MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH
246bool(true)
247mysqli_stmt::attr_set(): Argument #2 ($value) must be one of the MYSQLI_CURSOR_TYPE_* constants for attribute MYSQLI_STMT_ATTR_CURSOR_TYPE
248mysqli_stmt::attr_set(): Argument #2 ($value) must be greater than 0 for attribute MYSQLI_STMT_ATTR_PREFETCH_ROWS
249done!
250