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