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