1 | /* |
2 | Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. |
3 | |
4 | The MySQL Connector/C is licensed under the terms of the GPLv2 |
5 | <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most |
6 | MySQL Connectors. There are special exceptions to the terms and |
7 | conditions of the GPLv2 as it is applied to this software, see the |
8 | FLOSS License Exception |
9 | <http://www.mysql.com/about/legal/licensing/foss-exception.html>. |
10 | |
11 | This program is free software; you can redistribute it and/or modify |
12 | it under the terms of the GNU General Public License as published |
13 | by the Free Software Foundation; version 2 of the License. |
14 | |
15 | This program is distributed in the hope that it will be useful, but |
16 | WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
17 | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
18 | for more details. |
19 | |
20 | You should have received a copy of the GNU General Public License along |
21 | with this program; if not, write to the Free Software Foundation, Inc., |
22 | 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
23 | */ |
24 | #include "my_test.h" |
25 | |
26 | /* helper functions */ |
27 | enum { MAX_COLUMN_LENGTH= 255 }; |
28 | |
29 | typedef struct st_stmt_fetch |
30 | { |
31 | const char *query; |
32 | unsigned stmt_no; |
33 | MYSQL_STMT *handle; |
34 | my_bool is_open; |
35 | MYSQL_BIND *bind_array; |
36 | char **out_data; |
37 | unsigned long *out_data_length; |
38 | unsigned column_count; |
39 | unsigned row_count; |
40 | } Stmt_fetch; |
41 | |
42 | MYSQL_STMT *open_cursor(MYSQL *mysql, const char *query) |
43 | { |
44 | int rc; |
45 | const ulong type= (ulong)CURSOR_TYPE_READ_ONLY; |
46 | |
47 | MYSQL_STMT *stmt= mysql_stmt_init(mysql); |
48 | rc= mysql_stmt_prepare(stmt, SL(query)); |
49 | if (rc) { |
50 | diag("Error: %s" , mysql_stmt_error(stmt)); |
51 | return NULL; |
52 | } |
53 | mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type); |
54 | return stmt; |
55 | } |
56 | |
57 | /* |
58 | Create statement handle, prepare it with statement, execute and allocate |
59 | fetch buffers. |
60 | */ |
61 | |
62 | int stmt_fetch_init(MYSQL *mysql, Stmt_fetch *fetch, unsigned int stmt_no_arg, |
63 | const char *query_arg) |
64 | { |
65 | unsigned long type= CURSOR_TYPE_READ_ONLY; |
66 | int rc; |
67 | unsigned int i; |
68 | MYSQL_RES *metadata; |
69 | |
70 | /* Save query and statement number for error messages */ |
71 | fetch->stmt_no= stmt_no_arg; |
72 | fetch->query= query_arg; |
73 | |
74 | fetch->handle= mysql_stmt_init(mysql); |
75 | |
76 | rc= mysql_stmt_prepare(fetch->handle, SL(fetch->query)); |
77 | FAIL_IF(rc, mysql_stmt_error(fetch->handle)); |
78 | |
79 | /* |
80 | The attribute is sent to server on execute and asks to open read-only |
81 | for result set |
82 | */ |
83 | mysql_stmt_attr_set(fetch->handle, STMT_ATTR_CURSOR_TYPE, |
84 | (const void*) &type); |
85 | |
86 | rc= mysql_stmt_execute(fetch->handle); |
87 | FAIL_IF(rc, mysql_stmt_error(fetch->handle)); |
88 | |
89 | /* Find out total number of columns in result set */ |
90 | metadata= mysql_stmt_result_metadata(fetch->handle); |
91 | fetch->column_count= mysql_num_fields(metadata); |
92 | mysql_free_result(metadata); |
93 | |
94 | /* |
95 | Now allocate bind handles and buffers for output data: |
96 | calloc memory to reduce number of MYSQL_BIND members we need to |
97 | set up. |
98 | */ |
99 | |
100 | fetch->bind_array= (MYSQL_BIND *) calloc(1, sizeof(MYSQL_BIND) * |
101 | fetch->column_count); |
102 | fetch->out_data= (char**) calloc(1, sizeof(char*) * fetch->column_count); |
103 | fetch->out_data_length= (ulong*) calloc(1, sizeof(ulong) * |
104 | fetch->column_count); |
105 | for (i= 0; i < fetch->column_count; ++i) |
106 | { |
107 | fetch->out_data[i]= (char*) calloc(1, MAX_COLUMN_LENGTH); |
108 | fetch->bind_array[i].buffer_type= MYSQL_TYPE_STRING; |
109 | fetch->bind_array[i].buffer= fetch->out_data[i]; |
110 | fetch->bind_array[i].buffer_length= MAX_COLUMN_LENGTH; |
111 | fetch->bind_array[i].length= fetch->out_data_length + i; |
112 | } |
113 | |
114 | mysql_stmt_bind_result(fetch->handle, fetch->bind_array); |
115 | |
116 | fetch->row_count= 0; |
117 | fetch->is_open= TRUE; |
118 | |
119 | /* Ready for reading rows */ |
120 | return OK; |
121 | } |
122 | |
123 | |
124 | int fill_tables(MYSQL *mysql, const char **query_list, unsigned query_count) |
125 | { |
126 | int rc; |
127 | const char **query; |
128 | for (query= query_list; query < query_list + query_count; |
129 | ++query) |
130 | { |
131 | rc= mysql_query(mysql, *query); |
132 | check_mysql_rc(rc, mysql); |
133 | } |
134 | return OK; |
135 | } |
136 | |
137 | int stmt_fetch_fetch_row(Stmt_fetch *fetch) |
138 | { |
139 | int rc; |
140 | unsigned i; |
141 | |
142 | if ((rc= mysql_stmt_fetch(fetch->handle)) == 0) |
143 | { |
144 | ++fetch->row_count; |
145 | for (i= 0; i < fetch->column_count; ++i) |
146 | { |
147 | fetch->out_data[i][fetch->out_data_length[i]]= '\0'; |
148 | } |
149 | } |
150 | else |
151 | fetch->is_open= FALSE; |
152 | |
153 | return rc; |
154 | } |
155 | |
156 | void stmt_fetch_close(Stmt_fetch *fetch) |
157 | { |
158 | unsigned i; |
159 | |
160 | for (i= 0; i < fetch->column_count; ++i) |
161 | free(fetch->out_data[i]); |
162 | free(fetch->out_data); |
163 | free(fetch->out_data_length); |
164 | free(fetch->bind_array); |
165 | mysql_stmt_close(fetch->handle); |
166 | } |
167 | |
168 | |
169 | |
170 | enum fetch_type { USE_ROW_BY_ROW_FETCH= 0, USE_STORE_RESULT= 1 }; |
171 | |
172 | int fetch_n(MYSQL *mysql, const char **query_list, unsigned query_count, |
173 | enum fetch_type fetch_type) |
174 | { |
175 | unsigned open_statements= query_count; |
176 | int rc, error_count= 0; |
177 | Stmt_fetch *fetch_array= (Stmt_fetch*) calloc(1, sizeof(Stmt_fetch) * |
178 | query_count); |
179 | Stmt_fetch *fetch; |
180 | |
181 | for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch) |
182 | { |
183 | if (stmt_fetch_init(mysql, fetch, (unsigned int)(fetch - fetch_array), |
184 | query_list[fetch - fetch_array])) |
185 | return FAIL; |
186 | } |
187 | |
188 | if (fetch_type == USE_STORE_RESULT) |
189 | { |
190 | for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch) |
191 | { |
192 | rc= mysql_stmt_store_result(fetch->handle); |
193 | FAIL_IF(rc, mysql_stmt_error(fetch->handle)); |
194 | } |
195 | } |
196 | |
197 | while (open_statements) |
198 | { |
199 | for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch) |
200 | { |
201 | if (fetch->is_open && (rc= stmt_fetch_fetch_row(fetch))) |
202 | { |
203 | open_statements--; |
204 | /* |
205 | We try to fetch from the rest of the statements in case of |
206 | error |
207 | */ |
208 | if (rc != MYSQL_NO_DATA) |
209 | error_count++; |
210 | } |
211 | } |
212 | } |
213 | if (!error_count) |
214 | { |
215 | unsigned total_row_count= 0; |
216 | for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch) |
217 | total_row_count+= fetch->row_count; |
218 | } |
219 | for (fetch= fetch_array; fetch < fetch_array + query_count; ++fetch) |
220 | stmt_fetch_close(fetch); |
221 | free(fetch_array); |
222 | |
223 | return (error_count) ? FAIL:OK; |
224 | } |
225 | |
226 | static int test_basic_cursors(MYSQL *mysql) |
227 | { |
228 | const char *basic_tables[]= |
229 | { |
230 | "DROP TABLE IF EXISTS t1, t2" , |
231 | |
232 | "CREATE TABLE t1 " |
233 | "(id INTEGER NOT NULL PRIMARY KEY, " |
234 | " name VARCHAR(20) NOT NULL)" , |
235 | |
236 | "INSERT INTO t1 (id, name) VALUES " |
237 | " (2, 'Ja'), (3, 'Ede'), " |
238 | " (4, 'Haag'), (5, 'Kabul'), " |
239 | " (6, 'Almere'), (7, 'Utrecht'), " |
240 | " (8, 'Qandahar'), (9, 'Amsterdam'), " |
241 | " (10, 'Amersfoort'), (11, 'Constantine')" , |
242 | |
243 | "CREATE TABLE t2 " |
244 | "(id INTEGER NOT NULL PRIMARY KEY, " |
245 | " name VARCHAR(20) NOT NULL)" , |
246 | |
247 | "INSERT INTO t2 (id, name) VALUES " |
248 | " (4, 'Guam'), (5, 'Aruba'), " |
249 | " (6, 'Angola'), (7, 'Albania'), " |
250 | " (8, 'Anguilla'), (9, 'Argentina'), " |
251 | " (10, 'Azerbaijan'), (11, 'Afghanistan'), " |
252 | " (12, 'Burkina Faso'), (13, 'Faroe Islands')" |
253 | }; |
254 | |
255 | const char *queries[]= |
256 | { |
257 | "SELECT * FROM t1" , |
258 | "SELECT * FROM t2" |
259 | }; |
260 | |
261 | |
262 | FAIL_IF(fill_tables(mysql, basic_tables, sizeof(basic_tables)/sizeof(*basic_tables)), "fill_tables failed" ); |
263 | |
264 | FAIL_IF(fetch_n(mysql, queries, sizeof(queries)/sizeof(*queries), USE_ROW_BY_ROW_FETCH), "fetch_n failed" ); |
265 | FAIL_IF(fetch_n(mysql, queries, sizeof(queries)/sizeof(*queries), USE_STORE_RESULT), "fetch_n failed" ); |
266 | return OK; |
267 | } |
268 | |
269 | |
270 | static int test_cursors_with_union(MYSQL *mysql) |
271 | { |
272 | const char *queries[]= |
273 | { |
274 | "SELECT t1.name FROM t1 UNION SELECT t2.name FROM t2" , |
275 | "SELECT t1.id FROM t1 WHERE t1.id < 5" |
276 | }; |
277 | FAIL_IF(fetch_n(mysql, queries, sizeof(queries)/sizeof(*queries), USE_ROW_BY_ROW_FETCH), "fetch_n failed" ); |
278 | FAIL_IF(fetch_n(mysql, queries, sizeof(queries)/sizeof(*queries), USE_STORE_RESULT), "fetch_n failed" ); |
279 | |
280 | return OK; |
281 | } |
282 | |
283 | |
284 | static int test_cursors_with_procedure(MYSQL *mysql) |
285 | { |
286 | const char *queries[]= |
287 | { |
288 | "SELECT * FROM t1 procedure analyse()" |
289 | }; |
290 | FAIL_IF(fetch_n(mysql, queries, sizeof(queries)/sizeof(*queries), USE_ROW_BY_ROW_FETCH), "fetch_n failed" ); |
291 | FAIL_IF(fetch_n(mysql, queries, sizeof(queries)/sizeof(*queries), USE_STORE_RESULT), "fetch_n failed" ); |
292 | |
293 | return OK; |
294 | } |
295 | |
296 | /* |
297 | Bug#21206: memory corruption when too many cursors are opened at once |
298 | |
299 | Memory corruption happens when more than 1024 cursors are open |
300 | simultaneously. |
301 | */ |
302 | static int test_bug21206(MYSQL *mysql) |
303 | { |
304 | int retcode= OK; |
305 | |
306 | const size_t cursor_count= 1025; |
307 | |
308 | const char *create_table[]= |
309 | { |
310 | "DROP TABLE IF EXISTS t1" , |
311 | "CREATE TABLE t1 (i INT)" , |
312 | "INSERT INTO t1 VALUES (1), (2), (3)" |
313 | }; |
314 | const char *query= "SELECT * FROM t1" ; |
315 | |
316 | Stmt_fetch *fetch_array= |
317 | (Stmt_fetch*) calloc(cursor_count, sizeof(Stmt_fetch)); |
318 | |
319 | Stmt_fetch *fetch; |
320 | |
321 | FAIL_IF(fill_tables(mysql, create_table, sizeof(create_table) / sizeof(*create_table)), "fill_tables failed" ); |
322 | |
323 | for (fetch= fetch_array; fetch < fetch_array + cursor_count; ++fetch) |
324 | { |
325 | if ((retcode= stmt_fetch_init(mysql, fetch, (unsigned int)(fetch - fetch_array), query))) |
326 | break; |
327 | } |
328 | |
329 | for (fetch= fetch_array; fetch < fetch_array + cursor_count; ++fetch) |
330 | stmt_fetch_close(fetch); |
331 | |
332 | free(fetch_array); |
333 | |
334 | return retcode; |
335 | } |
336 | |
337 | static int test_bug10729(MYSQL *mysql) |
338 | { |
339 | MYSQL_STMT *stmt; |
340 | MYSQL_BIND my_bind[1]; |
341 | char a[21]; |
342 | int rc; |
343 | const char *stmt_text; |
344 | int i= 0; |
345 | const char *name_array[3]= { "aaa" , "bbb" , "ccc" }; |
346 | ulong type; |
347 | |
348 | mysql_query(mysql, "drop table if exists t1" ); |
349 | mysql_query(mysql, "create table t1 (id integer not null primary key," |
350 | "name VARCHAR(20) NOT NULL)" ); |
351 | rc= mysql_query(mysql, "insert into t1 (id, name) values " |
352 | "(1, 'aaa'), (2, 'bbb'), (3, 'ccc')" ); |
353 | check_mysql_rc(rc, mysql); |
354 | |
355 | stmt= mysql_stmt_init(mysql); |
356 | FAIL_IF(!stmt, mysql_error(mysql)); |
357 | |
358 | type= (ulong) CURSOR_TYPE_READ_ONLY; |
359 | rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type); |
360 | check_stmt_rc(rc, stmt); |
361 | stmt_text= "select name from t1" ; |
362 | rc= mysql_stmt_prepare(stmt, SL(stmt_text)); |
363 | check_stmt_rc(rc, stmt); |
364 | |
365 | memset(my_bind, '\0', sizeof(my_bind)); |
366 | my_bind[0].buffer_type= MYSQL_TYPE_STRING; |
367 | my_bind[0].buffer= (void*) a; |
368 | my_bind[0].buffer_length= sizeof(a); |
369 | mysql_stmt_bind_result(stmt, my_bind); |
370 | |
371 | for (i= 0; i < 3; i++) |
372 | { |
373 | int row_no= 0; |
374 | rc= mysql_stmt_execute(stmt); |
375 | check_stmt_rc(rc, stmt); |
376 | while ((rc= mysql_stmt_fetch(stmt)) == 0) |
377 | { |
378 | FAIL_UNLESS(strcmp(a, name_array[row_no]) == 0, "a != name_array[row_no]" ); |
379 | ++row_no; |
380 | } |
381 | FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA" ); |
382 | } |
383 | rc= mysql_stmt_close(stmt); |
384 | |
385 | rc= mysql_query(mysql, "drop table t1" ); |
386 | check_mysql_rc(rc, mysql); |
387 | |
388 | return OK; |
389 | } |
390 | |
391 | /* Bug#10736: cursors and subqueries, memroot management */ |
392 | |
393 | static int test_bug10736(MYSQL *mysql) |
394 | { |
395 | MYSQL_STMT *stmt; |
396 | MYSQL_BIND my_bind[1]; |
397 | char a[21]; |
398 | int rc; |
399 | const char *stmt_text; |
400 | int i= 0; |
401 | ulong type; |
402 | |
403 | rc= mysql_query(mysql, "drop table if exists t1" ); |
404 | check_mysql_rc(rc, mysql); |
405 | rc= mysql_query(mysql, "create table t1 (id integer not null primary key," |
406 | "name VARCHAR(20) NOT NULL)" ); |
407 | check_mysql_rc(rc, mysql); |
408 | rc= mysql_query(mysql, "insert into t1 (id, name) values " |
409 | "(1, 'aaa'), (2, 'bbb'), (3, 'ccc')" ); |
410 | check_mysql_rc(rc, mysql); |
411 | |
412 | stmt= mysql_stmt_init(mysql); |
413 | |
414 | type= (ulong) CURSOR_TYPE_READ_ONLY; |
415 | rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type); |
416 | check_stmt_rc(rc, stmt); |
417 | stmt_text= "select name from t1 where name=(select name from t1 where id=2)" ; |
418 | rc= mysql_stmt_prepare(stmt, SL(stmt_text)); |
419 | check_stmt_rc(rc, stmt); |
420 | |
421 | memset(my_bind, '\0', sizeof(my_bind)); |
422 | my_bind[0].buffer_type= MYSQL_TYPE_STRING; |
423 | my_bind[0].buffer= (void*) a; |
424 | my_bind[0].buffer_length= sizeof(a); |
425 | mysql_stmt_bind_result(stmt, my_bind); |
426 | |
427 | for (i= 0; i < 3; i++) |
428 | { |
429 | int row_no= 0; |
430 | rc= mysql_stmt_execute(stmt); |
431 | check_stmt_rc(rc, stmt); |
432 | while ((rc= mysql_stmt_fetch(stmt)) == 0) |
433 | ++row_no; |
434 | FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA" ); |
435 | } |
436 | rc= mysql_stmt_close(stmt); |
437 | |
438 | rc= mysql_query(mysql, "drop table t1" ); |
439 | check_mysql_rc(rc, mysql); |
440 | |
441 | return OK; |
442 | } |
443 | |
444 | /* Bug#10794: cursors, packets out of order */ |
445 | |
446 | static int test_bug10794(MYSQL *mysql) |
447 | { |
448 | MYSQL_STMT *stmt, *stmt1; |
449 | MYSQL_BIND my_bind[2]; |
450 | char a[21]; |
451 | int id_val; |
452 | ulong a_len; |
453 | int rc; |
454 | const char *stmt_text; |
455 | int i= 0; |
456 | ulong type; |
457 | |
458 | rc= mysql_query(mysql, "drop table if exists t1" ); |
459 | check_mysql_rc(rc, mysql); |
460 | rc= mysql_query(mysql, "create table t1 (id integer not null primary key," |
461 | "name varchar(20) not null)" ); |
462 | check_mysql_rc(rc, mysql); |
463 | |
464 | stmt= mysql_stmt_init(mysql); |
465 | stmt_text= "insert into t1 (id, name) values (?, ?)" ; |
466 | rc= mysql_stmt_prepare(stmt, SL(stmt_text)); |
467 | check_stmt_rc(rc, stmt); |
468 | |
469 | memset(my_bind, '\0', sizeof(my_bind)); |
470 | my_bind[0].buffer_type= MYSQL_TYPE_LONG; |
471 | my_bind[0].buffer= (void*) &id_val; |
472 | my_bind[1].buffer_type= MYSQL_TYPE_STRING; |
473 | my_bind[1].buffer= (void*) a; |
474 | my_bind[1].length= &a_len; |
475 | rc= mysql_stmt_bind_param(stmt, my_bind); |
476 | check_stmt_rc(rc, stmt); |
477 | for (i= 0; i < 42; i++) |
478 | { |
479 | id_val= (i+1)*10; |
480 | sprintf(a, "a%d" , i); |
481 | a_len= (unsigned long)strlen(a); /* safety against broken sprintf */ |
482 | rc= mysql_stmt_execute(stmt); |
483 | check_stmt_rc(rc, stmt); |
484 | } |
485 | stmt_text= "select name from t1" ; |
486 | rc= mysql_stmt_prepare(stmt, SL(stmt_text)); |
487 | type= (ulong) CURSOR_TYPE_READ_ONLY; |
488 | mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type); |
489 | stmt1= mysql_stmt_init(mysql); |
490 | mysql_stmt_attr_set(stmt1, STMT_ATTR_CURSOR_TYPE, (const void*) &type); |
491 | memset(my_bind, '\0', sizeof(my_bind)); |
492 | my_bind[0].buffer_type= MYSQL_TYPE_STRING; |
493 | my_bind[0].buffer= (void*) a; |
494 | my_bind[0].buffer_length= sizeof(a); |
495 | my_bind[0].length= &a_len; |
496 | rc= mysql_stmt_bind_result(stmt, my_bind); |
497 | check_stmt_rc(rc, stmt); |
498 | rc= mysql_stmt_execute(stmt); |
499 | check_stmt_rc(rc, stmt); |
500 | rc= mysql_stmt_fetch(stmt); |
501 | check_stmt_rc(rc, stmt); |
502 | /* Don't optimize: an attribute of the original test case */ |
503 | mysql_stmt_free_result(stmt); |
504 | mysql_stmt_reset(stmt); |
505 | stmt_text= "select name from t1 where id=10" ; |
506 | rc= mysql_stmt_prepare(stmt1, SL(stmt_text)); |
507 | check_stmt_rc(rc, stmt1); |
508 | rc= mysql_stmt_bind_result(stmt1, my_bind); |
509 | check_stmt_rc(rc, stmt1); |
510 | rc= mysql_stmt_execute(stmt1); |
511 | check_stmt_rc(rc, stmt1); |
512 | while (1) |
513 | { |
514 | rc= mysql_stmt_fetch(stmt1); |
515 | if (rc == MYSQL_NO_DATA) |
516 | { |
517 | break; |
518 | } |
519 | check_stmt_rc(rc, stmt1); |
520 | } |
521 | mysql_stmt_close(stmt); |
522 | mysql_stmt_close(stmt1); |
523 | |
524 | rc= mysql_query(mysql, "drop table t1" ); |
525 | check_mysql_rc(rc, mysql); |
526 | |
527 | return OK; |
528 | } |
529 | |
530 | /* Bug#10760: cursors, crash in a fetch after rollback. */ |
531 | |
532 | static int test_bug10760(MYSQL *mysql) |
533 | { |
534 | MYSQL_STMT *stmt; |
535 | MYSQL_BIND my_bind[1]; |
536 | int rc; |
537 | const char *stmt_text; |
538 | char id_buf[20]; |
539 | ulong id_len; |
540 | int i= 0; |
541 | ulong type; |
542 | |
543 | rc= mysql_query(mysql, "drop table if exists t1, t2" ); |
544 | check_mysql_rc(rc, mysql); |
545 | |
546 | /* create tables */ |
547 | rc= mysql_query(mysql, "create table t1 (id integer not null primary key)" |
548 | " engine=MyISAM" ); |
549 | check_mysql_rc(rc, mysql);; |
550 | for (; i < 42; ++i) |
551 | { |
552 | char buf[100]; |
553 | sprintf(buf, "insert into t1 (id) values (%d)" , i+1); |
554 | rc= mysql_query(mysql, buf); |
555 | check_mysql_rc(rc, mysql);; |
556 | } |
557 | mysql_autocommit(mysql, FALSE); |
558 | /* create statement */ |
559 | stmt= mysql_stmt_init(mysql); |
560 | type= (ulong) CURSOR_TYPE_READ_ONLY; |
561 | mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type); |
562 | |
563 | /* |
564 | 1: check that a deadlock within the same connection |
565 | is resolved and an error is returned. The deadlock is modelled |
566 | as follows: |
567 | con1: open cursor for select * from t1; |
568 | con1: insert into t1 (id) values (1) |
569 | */ |
570 | stmt_text= "select id from t1 order by 1" ; |
571 | rc= mysql_stmt_prepare(stmt, SL(stmt_text)); |
572 | check_stmt_rc(rc, stmt);; |
573 | rc= mysql_stmt_execute(stmt); |
574 | check_stmt_rc(rc, stmt);; |
575 | rc= mysql_query(mysql, "update t1 set id=id+100" ); |
576 | /* |
577 | If cursors are not materialized, the update will return an error; |
578 | we mainly test that it won't deadlock. |
579 | */ |
580 | /* FAIL_IF(!rc, "Error expected"); */ |
581 | /* |
582 | 2: check that MyISAM tables used in cursors survive |
583 | COMMIT/ROLLBACK. |
584 | */ |
585 | rc= mysql_rollback(mysql); /* should not close the cursor */ |
586 | check_mysql_rc(rc, mysql);; |
587 | rc= mysql_stmt_fetch(stmt); |
588 | check_stmt_rc(rc, stmt);; |
589 | |
590 | /* |
591 | 3: check that cursors to InnoDB tables are closed (for now) by |
592 | COMMIT/ROLLBACK. |
593 | */ |
594 | if (check_variable(mysql, "@@have_innodb" , "YES" )) |
595 | { |
596 | stmt_text= "select id from t1 order by 1" ; |
597 | rc= mysql_stmt_prepare(stmt, SL(stmt_text)); |
598 | check_stmt_rc(rc, stmt);; |
599 | |
600 | rc= mysql_query(mysql, "alter table t1 engine=InnoDB" ); |
601 | check_mysql_rc(rc, mysql);; |
602 | |
603 | memset(my_bind, '\0', sizeof(my_bind)); |
604 | my_bind[0].buffer_type= MYSQL_TYPE_STRING; |
605 | my_bind[0].buffer= (void*) id_buf; |
606 | my_bind[0].buffer_length= sizeof(id_buf); |
607 | my_bind[0].length= &id_len; |
608 | check_stmt_rc(rc, stmt);; |
609 | mysql_stmt_bind_result(stmt, my_bind); |
610 | |
611 | rc= mysql_stmt_execute(stmt); |
612 | rc= mysql_stmt_fetch(stmt); |
613 | FAIL_UNLESS(rc == 0, "rc != 0" ); |
614 | rc= mysql_rollback(mysql); /* should close the cursor */ |
615 | } |
616 | |
617 | mysql_stmt_close(stmt); |
618 | rc= mysql_query(mysql, "drop table t1" ); |
619 | check_mysql_rc(rc, mysql); |
620 | rc= mysql_autocommit(mysql, TRUE); /* restore default */ |
621 | check_mysql_rc(rc, mysql); |
622 | |
623 | return OK; |
624 | } |
625 | |
626 | /* Bug#11172: cursors, crash on a fetch from a datetime column */ |
627 | |
628 | static int test_bug11172(MYSQL *mysql) |
629 | { |
630 | MYSQL_STMT *stmt; |
631 | MYSQL_BIND bind_in[1], bind_out[2]; |
632 | MYSQL_TIME hired; |
633 | int rc; |
634 | const char *stmt_text; |
635 | int i= 0, id; |
636 | ulong type; |
637 | |
638 | rc= mysql_query(mysql, "drop table if exists t1" ); |
639 | check_mysql_rc(rc, mysql); |
640 | rc= mysql_query(mysql, "create table t1 (id integer not null primary key," |
641 | "hired date not null)" ); |
642 | check_mysql_rc(rc, mysql); |
643 | rc= mysql_query(mysql, |
644 | "insert into t1 (id, hired) values (1, '1933-08-24'), " |
645 | "(2, '1965-01-01'), (3, '1949-08-17'), (4, '1945-07-07'), " |
646 | "(5, '1941-05-15'), (6, '1978-09-15'), (7, '1936-03-28')" ); |
647 | check_mysql_rc(rc, mysql); |
648 | stmt= mysql_stmt_init(mysql); |
649 | FAIL_IF(!stmt, mysql_error(mysql)); |
650 | stmt_text= "SELECT id, hired FROM t1 WHERE hired=?" ; |
651 | rc= mysql_stmt_prepare(stmt, SL(stmt_text)); |
652 | check_stmt_rc(rc, stmt); |
653 | |
654 | type= (ulong) CURSOR_TYPE_READ_ONLY; |
655 | mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type); |
656 | |
657 | memset(bind_in, '\0', sizeof(bind_in)); |
658 | memset(bind_out, '\0', sizeof(bind_out)); |
659 | memset(&hired, '\0', sizeof(hired)); |
660 | hired.year= 1965; |
661 | hired.month= 1; |
662 | hired.day= 1; |
663 | bind_in[0].buffer_type= MYSQL_TYPE_DATE; |
664 | bind_in[0].buffer= (void*) &hired; |
665 | bind_in[0].buffer_length= sizeof(hired); |
666 | bind_out[0].buffer_type= MYSQL_TYPE_LONG; |
667 | bind_out[0].buffer= (void*) &id; |
668 | bind_out[1]= bind_in[0]; |
669 | |
670 | for (i= 0; i < 3; i++) |
671 | { |
672 | rc= mysql_stmt_bind_param(stmt, bind_in); |
673 | check_stmt_rc(rc, stmt); |
674 | rc= mysql_stmt_bind_result(stmt, bind_out); |
675 | check_stmt_rc(rc, stmt); |
676 | rc= mysql_stmt_execute(stmt); |
677 | check_stmt_rc(rc, stmt); |
678 | while ((rc= mysql_stmt_fetch(stmt)) == 0); |
679 | FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA" ); |
680 | if (!mysql_stmt_free_result(stmt)) |
681 | mysql_stmt_reset(stmt); |
682 | } |
683 | mysql_stmt_close(stmt); |
684 | mysql_rollback(mysql); |
685 | mysql_rollback(mysql); |
686 | |
687 | rc= mysql_query(mysql, "drop table t1" ); |
688 | check_mysql_rc(rc, mysql); |
689 | |
690 | return OK; |
691 | } |
692 | |
693 | /* Bug#11656: cursors, crash on a fetch from a query with distinct. */ |
694 | |
695 | static int test_bug11656(MYSQL *mysql) |
696 | { |
697 | MYSQL_STMT *stmt; |
698 | MYSQL_BIND my_bind[2]; |
699 | int rc; |
700 | const char *stmt_text; |
701 | char buf[2][20]; |
702 | int i= 0; |
703 | ulong type; |
704 | |
705 | rc= mysql_query(mysql, "drop table if exists t1" ); |
706 | check_mysql_rc(rc, mysql); |
707 | |
708 | rc= mysql_query(mysql, "create table t1 (" |
709 | "server varchar(40) not null, " |
710 | "test_kind varchar(1) not null, " |
711 | "test_id varchar(30) not null , " |
712 | "primary key (server,test_kind,test_id))" ); |
713 | check_mysql_rc(rc, mysql); |
714 | |
715 | stmt_text= "select distinct test_kind, test_id from t1 " |
716 | "where server in (?, ?)" ; |
717 | stmt= mysql_stmt_init(mysql); |
718 | FAIL_IF(!stmt, mysql_error(mysql)); |
719 | rc= mysql_stmt_prepare(stmt, SL(stmt_text)); |
720 | check_stmt_rc(rc, stmt); |
721 | type= (ulong) CURSOR_TYPE_READ_ONLY; |
722 | mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type); |
723 | |
724 | memset(my_bind, '\0', sizeof(my_bind)); |
725 | strcpy(buf[0], "pcint502_MY2" ); |
726 | strcpy(buf[1], "*" ); |
727 | for (i=0; i < 2; i++) |
728 | { |
729 | my_bind[i].buffer_type= MYSQL_TYPE_STRING; |
730 | my_bind[i].buffer= (uchar* *)&buf[i]; |
731 | my_bind[i].buffer_length= (unsigned long)strlen(buf[i]); |
732 | } |
733 | rc= mysql_stmt_bind_param(stmt, my_bind); |
734 | check_stmt_rc(rc, stmt); |
735 | |
736 | rc= mysql_stmt_execute(stmt); |
737 | check_stmt_rc(rc, stmt); |
738 | |
739 | rc= mysql_stmt_fetch(stmt); |
740 | FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA" ); |
741 | |
742 | mysql_stmt_close(stmt); |
743 | rc= mysql_query(mysql, "drop table t1" ); |
744 | check_mysql_rc(rc, mysql); |
745 | |
746 | return OK; |
747 | } |
748 | |
749 | /* Cursors: opening a cursor to a compilicated query with ORDER BY */ |
750 | |
751 | static int test_bug11901(MYSQL *mysql) |
752 | { |
753 | MYSQL_STMT *stmt; |
754 | MYSQL_BIND my_bind[2]; |
755 | int rc; |
756 | char workdept[20]; |
757 | ulong workdept_len; |
758 | uint32 empno; |
759 | const ulong type= (ulong)CURSOR_TYPE_READ_ONLY; |
760 | const char *stmt_text; |
761 | |
762 | |
763 | stmt_text= "drop table if exists t1, t2" ; |
764 | rc= mysql_real_query(mysql, SL(stmt_text)); |
765 | check_mysql_rc(rc, mysql); |
766 | |
767 | stmt_text= "create table t1 (" |
768 | " empno int(11) not null, firstname varchar(20) not null," |
769 | " midinit varchar(20) not null, lastname varchar(20) not null," |
770 | " workdept varchar(6) not null, salary double not null," |
771 | " bonus float not null, primary key (empno), " |
772 | " unique key (workdept, empno) " |
773 | ") default charset=latin1 collate=latin1_bin" ; |
774 | rc= mysql_real_query(mysql, SL(stmt_text)); |
775 | check_mysql_rc(rc, mysql); |
776 | |
777 | stmt_text= "insert into t1 values " |
778 | "(10, 'CHRISTINE', 'I', 'HAAS', 'A00', 52750, 1000)," |
779 | "(20, 'MICHAEL', 'L', 'THOMPSON', 'B01', 41250, 800), " |
780 | "(30, 'SALLY', 'A', 'KWAN', 'C01', 38250, 800), " |
781 | "(50, 'JOHN', 'B', 'GEYER', 'E01', 40175, 800), " |
782 | "(60, 'IRVING', 'F', 'STERN', 'D11', 32250, 500), " |
783 | "(70, 'EVA', 'D', 'PULASKI', 'D21', 36170, 700), " |
784 | "(90, 'EILEEN', 'W', 'HENDERSON', 'E11', 29750, 600), " |
785 | "(100, 'THEODORE', 'Q', 'SPENSER', 'E21', 26150, 500), " |
786 | "(110, 'VINCENZO', 'G', 'LUCCHESSI', 'A00', 46500, 900), " |
787 | "(120, 'SEAN', '', 'O\\'CONNELL', 'A00', 29250, 600), " |
788 | "(130, 'DOLORES', 'M', 'QUINTANA', 'C01', 23800, 500), " |
789 | "(140, 'HEATHER', 'A', 'NICHOLLS', 'C01', 28420, 600), " |
790 | "(150, 'BRUCE', '', 'ADAMSON', 'D11', 25280, 500), " |
791 | "(160, 'ELIZABETH', 'R', 'PIANKA', 'D11', 22250, 400), " |
792 | "(170, 'MASATOSHI', 'J', 'YOSHIMURA', 'D11', 24680, 500), " |
793 | "(180, 'MARILYN', 'S', 'SCOUTTEN', 'D11', 21340, 500), " |
794 | "(190, 'JAMES', 'H', 'WALKER', 'D11', 20450, 400), " |
795 | "(200, 'DAVID', '', 'BROWN', 'D11', 27740, 600), " |
796 | "(210, 'WILLIAM', 'T', 'JONES', 'D11', 18270, 400), " |
797 | "(220, 'JENNIFER', 'K', 'LUTZ', 'D11', 29840, 600), " |
798 | "(230, 'JAMES', 'J', 'JEFFERSON', 'D21', 22180, 400), " |
799 | "(240, 'SALVATORE', 'M', 'MARINO', 'D21', 28760, 600), " |
800 | "(250, 'DANIEL', 'S', 'SMITH', 'D21', 19180, 400), " |
801 | "(260, 'SYBIL', 'P', 'JOHNSON', 'D21', 17250, 300), " |
802 | "(270, 'MARIA', 'L', 'PEREZ', 'D21', 27380, 500), " |
803 | "(280, 'ETHEL', 'R', 'SCHNEIDER', 'E11', 26250, 500), " |
804 | "(290, 'JOHN', 'R', 'PARKER', 'E11', 15340, 300), " |
805 | "(300, 'PHILIP', 'X', 'SMITH', 'E11', 17750, 400), " |
806 | "(310, 'MAUDE', 'F', 'SETRIGHT', 'E11', 15900, 300), " |
807 | "(320, 'RAMLAL', 'V', 'MEHTA', 'E21', 19950, 400), " |
808 | "(330, 'WING', '', 'LEE', 'E21', 25370, 500), " |
809 | "(340, 'JASON', 'R', 'GOUNOT', 'E21', 23840, 500)" ; |
810 | |
811 | rc= mysql_real_query(mysql, SL(stmt_text)); |
812 | check_mysql_rc(rc, mysql); |
813 | |
814 | stmt_text= "create table t2 (" |
815 | " deptno varchar(6) not null, deptname varchar(20) not null," |
816 | " mgrno int(11) not null, location varchar(20) not null," |
817 | " admrdept varchar(6) not null, refcntd int(11) not null," |
818 | " refcntu int(11) not null, primary key (deptno)" |
819 | ") default charset=latin1 collate=latin1_bin" ; |
820 | rc= mysql_real_query(mysql, SL(stmt_text)); |
821 | check_mysql_rc(rc, mysql); |
822 | |
823 | stmt_text= "insert into t2 values " |
824 | "('A00', 'SPIFFY COMPUTER SERV', 10, '', 'A00', 0, 0), " |
825 | "('B01', 'PLANNING', 20, '', 'A00', 0, 0), " |
826 | "('C01', 'INFORMATION CENTER', 30, '', 'A00', 0, 0), " |
827 | "('D01', 'DEVELOPMENT CENTER', 0, '', 'A00', 0, 0)," |
828 | "('D11', 'MANUFACTURING SYSTEM', 60, '', 'D01', 0, 0), " |
829 | "('D21', 'ADMINISTRATION SYSTE', 70, '', 'D01', 0, 0), " |
830 | "('E01', 'SUPPORT SERVICES', 50, '', 'A00', 0, 0), " |
831 | "('E11', 'OPERATIONS', 90, '', 'E01', 0, 0), " |
832 | "('E21', 'SOFTWARE SUPPORT', 100,'', 'E01', 0, 0)" ; |
833 | rc= mysql_real_query(mysql, SL(stmt_text)); |
834 | check_mysql_rc(rc, mysql); |
835 | |
836 | stmt_text= "select t1.empno, t1.workdept " |
837 | "from (t1 left join t2 on t2.deptno = t1.workdept) " |
838 | "where t2.deptno in " |
839 | " (select t2.deptno " |
840 | " from (t1 left join t2 on t2.deptno = t1.workdept) " |
841 | " where t1.empno = ?) " |
842 | "order by 1" ; |
843 | stmt= mysql_stmt_init(mysql); |
844 | FAIL_IF(!stmt, mysql_error(mysql)); |
845 | rc= mysql_stmt_prepare(stmt, SL(stmt_text)); |
846 | check_stmt_rc(rc, stmt); |
847 | mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type); |
848 | check_stmt_rc(rc, stmt); |
849 | |
850 | |
851 | memset(my_bind, '\0', sizeof(my_bind)); |
852 | |
853 | my_bind[0].buffer_type= MYSQL_TYPE_LONG; |
854 | my_bind[0].buffer= &empno; |
855 | rc= mysql_stmt_bind_param(stmt, my_bind); |
856 | check_stmt_rc(rc, stmt); |
857 | |
858 | my_bind[1].buffer_type= MYSQL_TYPE_VAR_STRING; |
859 | my_bind[1].buffer= (void*) workdept; |
860 | my_bind[1].buffer_length= sizeof(workdept); |
861 | my_bind[1].length= &workdept_len; |
862 | |
863 | rc= mysql_stmt_bind_result(stmt, my_bind); |
864 | check_stmt_rc(rc, stmt); |
865 | |
866 | empno= 10; |
867 | |
868 | /* ERROR: next statement causes a server crash */ |
869 | rc= mysql_stmt_execute(stmt); |
870 | check_stmt_rc(rc, stmt); |
871 | |
872 | mysql_stmt_close(stmt); |
873 | |
874 | rc= mysql_query(mysql, "drop table t1, t2" ); |
875 | check_mysql_rc(rc, mysql); |
876 | |
877 | return OK; |
878 | } |
879 | |
880 | /* Bug#11904: mysql_stmt_attr_set CURSOR_TYPE_READ_ONLY grouping wrong result */ |
881 | |
882 | static int test_bug11904(MYSQL *mysql) |
883 | { |
884 | MYSQL_STMT *stmt1; |
885 | int rc; |
886 | const char *stmt_text; |
887 | const ulong type= (ulong)CURSOR_TYPE_READ_ONLY; |
888 | MYSQL_BIND my_bind[2]; |
889 | int country_id=0; |
890 | char row_data[11]= {0}; |
891 | |
892 | /* create tables */ |
893 | rc= mysql_query(mysql, "DROP TABLE IF EXISTS bug11904b" ); |
894 | check_mysql_rc(rc, mysql); |
895 | rc= mysql_query(mysql, "CREATE TABLE bug11904b (id int, name char(10), primary key(id, name))" ); |
896 | check_mysql_rc(rc, mysql); |
897 | |
898 | rc= mysql_query(mysql, "INSERT INTO bug11904b VALUES (1, 'sofia'), (1,'plovdiv')," |
899 | " (1,'varna'), (2,'LA'), (2,'new york'), (3,'heidelberg')," |
900 | " (3,'berlin'), (3, 'frankfurt')" ); |
901 | |
902 | check_mysql_rc(rc, mysql); |
903 | mysql_commit(mysql); |
904 | /* create statement */ |
905 | stmt1= mysql_stmt_init(mysql); |
906 | mysql_stmt_attr_set(stmt1, STMT_ATTR_CURSOR_TYPE, (const void*) &type); |
907 | |
908 | stmt_text= "SELECT id, MIN(name) FROM bug11904b GROUP BY id ORDER BY id" ; |
909 | |
910 | rc= mysql_stmt_prepare(stmt1, SL(stmt_text)); |
911 | check_stmt_rc(rc, stmt1); |
912 | |
913 | memset(my_bind, 0, sizeof(my_bind)); |
914 | my_bind[0].buffer_type= MYSQL_TYPE_LONG; |
915 | my_bind[0].buffer=& country_id; |
916 | my_bind[0].buffer_length= 0; |
917 | my_bind[0].length= 0; |
918 | |
919 | my_bind[1].buffer_type= MYSQL_TYPE_STRING; |
920 | my_bind[1].buffer=& row_data; |
921 | my_bind[1].buffer_length= sizeof(row_data) - 1; |
922 | my_bind[1].length= 0; |
923 | |
924 | rc= mysql_stmt_bind_result(stmt1, my_bind); |
925 | check_stmt_rc(rc, stmt1); |
926 | |
927 | rc= mysql_stmt_execute(stmt1); |
928 | check_stmt_rc(rc, stmt1); |
929 | |
930 | rc= mysql_stmt_fetch(stmt1); |
931 | check_stmt_rc(rc, stmt1); |
932 | FAIL_UNLESS(country_id == 1, "country_id != 1" ); |
933 | FAIL_UNLESS(memcmp(row_data, "plovdiv" , 7) == 0, "row_data != 'plovdiv'" ); |
934 | |
935 | rc= mysql_stmt_fetch(stmt1); |
936 | check_stmt_rc(rc, stmt1); |
937 | FAIL_UNLESS(country_id == 2, "country_id != 2" ); |
938 | FAIL_UNLESS(memcmp(row_data, "LA" , 2) == 0, "row_data != 'LA'" ); |
939 | |
940 | rc= mysql_stmt_fetch(stmt1); |
941 | check_stmt_rc(rc, stmt1); |
942 | FAIL_UNLESS(country_id == 3, "country_id != 3" ); |
943 | FAIL_UNLESS(memcmp(row_data, "berlin" , 6) == 0, "row_data != 'Berlin'" ); |
944 | |
945 | rc= mysql_stmt_close(stmt1); |
946 | check_stmt_rc(rc, stmt1); |
947 | |
948 | rc= mysql_query(mysql, "drop table bug11904b" ); |
949 | check_mysql_rc(rc, mysql); |
950 | |
951 | return OK; |
952 | } |
953 | |
954 | |
955 | /* Bug#12243: multiple cursors, crash in a fetch after commit. */ |
956 | |
957 | static int test_bug12243(MYSQL *mysql) |
958 | { |
959 | MYSQL_STMT *stmt1, *stmt2; |
960 | int rc; |
961 | const char *stmt_text; |
962 | ulong type; |
963 | |
964 | if (!check_variable(mysql, "@@have_innodb" , "YES" )) |
965 | { |
966 | diag("Skip -> Test required InnoDB" ); |
967 | return SKIP; |
968 | } |
969 | |
970 | /* create tables */ |
971 | rc= mysql_query(mysql, "drop table if exists t1" ); |
972 | check_mysql_rc(rc, mysql); |
973 | rc= mysql_query(mysql, "create table t1 (a int) engine=InnoDB" ); |
974 | check_mysql_rc(rc, mysql); |
975 | rc= mysql_query(mysql, "insert into t1 (a) values (1), (2)" ); |
976 | check_mysql_rc(rc, mysql); |
977 | mysql_autocommit(mysql, FALSE); |
978 | /* create statement */ |
979 | stmt1= mysql_stmt_init(mysql); |
980 | stmt2= mysql_stmt_init(mysql); |
981 | type= (ulong) CURSOR_TYPE_READ_ONLY; |
982 | rc= mysql_stmt_attr_set(stmt1, STMT_ATTR_CURSOR_TYPE, (const void*) &type); |
983 | check_stmt_rc(rc, stmt1); |
984 | rc= mysql_stmt_attr_set(stmt2, STMT_ATTR_CURSOR_TYPE, (const void*) &type); |
985 | check_stmt_rc(rc, stmt1); |
986 | |
987 | stmt_text= "select a from t1" ; |
988 | |
989 | rc= mysql_stmt_prepare(stmt1, SL(stmt_text)); |
990 | check_stmt_rc(rc, stmt1); |
991 | rc= mysql_stmt_execute(stmt1); |
992 | check_stmt_rc(rc, stmt1); |
993 | rc= mysql_stmt_fetch(stmt1); |
994 | check_stmt_rc(rc, stmt1); |
995 | |
996 | rc= mysql_stmt_prepare(stmt2, SL(stmt_text)); |
997 | check_stmt_rc(rc, stmt2); |
998 | rc= mysql_stmt_execute(stmt2); |
999 | check_stmt_rc(rc, stmt2); |
1000 | rc= mysql_stmt_fetch(stmt2); |
1001 | check_stmt_rc(rc, stmt2); |
1002 | |
1003 | rc= mysql_stmt_close(stmt1); |
1004 | check_stmt_rc(rc, stmt1); |
1005 | rc= mysql_commit(mysql); |
1006 | check_mysql_rc(rc, mysql); |
1007 | rc= mysql_stmt_fetch(stmt2); |
1008 | check_stmt_rc(rc, stmt2); |
1009 | |
1010 | mysql_stmt_close(stmt2); |
1011 | rc= mysql_query(mysql, "drop table t1" ); |
1012 | check_mysql_rc(rc, mysql); |
1013 | mysql_autocommit(mysql, TRUE); /* restore default */ |
1014 | |
1015 | return OK; |
1016 | } |
1017 | |
1018 | /* Bug#11909: wrong metadata if fetching from two cursors */ |
1019 | |
1020 | static int test_bug11909(MYSQL *mysql) |
1021 | { |
1022 | MYSQL_STMT *stmt1, *stmt2; |
1023 | MYSQL_BIND my_bind[7]; |
1024 | int rc; |
1025 | char firstname[20], midinit[20], lastname[20], workdept[20]; |
1026 | ulong firstname_len, midinit_len, lastname_len, workdept_len; |
1027 | uint32 empno; |
1028 | double salary; |
1029 | float bonus; |
1030 | const char *stmt_text; |
1031 | const ulong type= (ulong)CURSOR_TYPE_READ_ONLY; |
1032 | |
1033 | |
1034 | stmt_text= "drop table if exists t1" ; |
1035 | rc= mysql_real_query(mysql, SL(stmt_text)); |
1036 | check_mysql_rc(rc, mysql); |
1037 | |
1038 | stmt_text= "create table t1 (" |
1039 | " empno int(11) not null, firstname varchar(20) not null," |
1040 | " midinit varchar(20) not null, lastname varchar(20) not null," |
1041 | " workdept varchar(6) not null, salary double not null," |
1042 | " bonus float not null, primary key (empno)" |
1043 | ") default charset=latin1 collate=latin1_bin" ; |
1044 | rc= mysql_real_query(mysql, SL(stmt_text)); |
1045 | check_mysql_rc(rc, mysql); |
1046 | |
1047 | stmt_text= "insert into t1 values " |
1048 | "(10, 'CHRISTINE', 'I', 'HAAS', 'A00', 52750, 1000), " |
1049 | "(20, 'MICHAEL', 'L', 'THOMPSON', 'B01', 41250, 800)," |
1050 | "(30, 'SALLY', 'A', 'KWAN', 'C01', 38250, 800)," |
1051 | "(50, 'JOHN', 'B', 'GEYER', 'E01', 40175, 800), " |
1052 | "(60, 'IRVING', 'F', 'STERN', 'D11', 32250, 500)" ; |
1053 | rc= mysql_real_query(mysql, SL(stmt_text)); |
1054 | check_mysql_rc(rc, mysql); |
1055 | |
1056 | /* ****** Begin of trace ****** */ |
1057 | |
1058 | stmt_text= "SELECT empno, firstname, midinit, lastname," |
1059 | "workdept, salary, bonus FROM t1 ORDER BY empno" ; |
1060 | stmt1= mysql_stmt_init(mysql); |
1061 | FAIL_IF(!stmt1, mysql_error(mysql)); |
1062 | rc= mysql_stmt_prepare(stmt1, SL(stmt_text)); |
1063 | check_stmt_rc(rc, stmt1); |
1064 | mysql_stmt_attr_set(stmt1, STMT_ATTR_CURSOR_TYPE, |
1065 | (const void*) &type); |
1066 | |
1067 | memset(my_bind, '\0', sizeof(my_bind)); |
1068 | my_bind[0].buffer_type= MYSQL_TYPE_LONG; |
1069 | my_bind[0].buffer= (void*) &empno; |
1070 | |
1071 | my_bind[1].buffer_type= MYSQL_TYPE_VAR_STRING; |
1072 | my_bind[1].buffer= (void*) firstname; |
1073 | my_bind[1].buffer_length= sizeof(firstname); |
1074 | my_bind[1].length= &firstname_len; |
1075 | |
1076 | my_bind[2].buffer_type= MYSQL_TYPE_VAR_STRING; |
1077 | my_bind[2].buffer= (void*) midinit; |
1078 | my_bind[2].buffer_length= sizeof(midinit); |
1079 | my_bind[2].length= &midinit_len; |
1080 | |
1081 | my_bind[3].buffer_type= MYSQL_TYPE_VAR_STRING; |
1082 | my_bind[3].buffer= (void*) lastname; |
1083 | my_bind[3].buffer_length= sizeof(lastname); |
1084 | my_bind[3].length= &lastname_len; |
1085 | |
1086 | my_bind[4].buffer_type= MYSQL_TYPE_VAR_STRING; |
1087 | my_bind[4].buffer= (void*) workdept; |
1088 | my_bind[4].buffer_length= sizeof(workdept); |
1089 | my_bind[4].length= &workdept_len; |
1090 | |
1091 | my_bind[5].buffer_type= MYSQL_TYPE_DOUBLE; |
1092 | my_bind[5].buffer= (void*) &salary; |
1093 | |
1094 | my_bind[6].buffer_type= MYSQL_TYPE_FLOAT; |
1095 | my_bind[6].buffer= (void*) &bonus; |
1096 | rc= mysql_stmt_bind_result(stmt1, my_bind); |
1097 | check_stmt_rc(rc, stmt1); |
1098 | |
1099 | rc= mysql_stmt_execute(stmt1); |
1100 | check_stmt_rc(rc, stmt1); |
1101 | |
1102 | rc= mysql_stmt_fetch(stmt1); |
1103 | FAIL_UNLESS(rc == 0, "rc != 0" ); |
1104 | FAIL_UNLESS(empno == 10, "empno != 10" ); |
1105 | FAIL_UNLESS(strcmp(firstname, "CHRISTINE" "" ) == 0, "firstname != 'Christine'" ); |
1106 | FAIL_UNLESS(strcmp(midinit, "I" "" ) == 0, "" ); |
1107 | FAIL_UNLESS(strcmp(lastname, "HAAS" "" ) == 0, "lastname != 'HAAS'" ); |
1108 | FAIL_UNLESS(strcmp(workdept, "A00" "" ) == 0, "workdept != 'A00'" ); |
1109 | FAIL_UNLESS(salary == (double) 52750.0, "salary != 52750" ); |
1110 | FAIL_UNLESS(bonus == (float) 1000.0, "bonus =! 1000" ); |
1111 | |
1112 | stmt_text = "SELECT empno, firstname FROM t1" ; |
1113 | stmt2= mysql_stmt_init(mysql); |
1114 | FAIL_IF(!stmt2, mysql_error(mysql)); |
1115 | rc= mysql_stmt_prepare(stmt2, SL(stmt_text)); |
1116 | check_stmt_rc(rc, stmt2); |
1117 | mysql_stmt_attr_set(stmt2, STMT_ATTR_CURSOR_TYPE, |
1118 | (const void*) &type); |
1119 | rc= mysql_stmt_bind_result(stmt2, my_bind); |
1120 | check_stmt_rc(rc, stmt2); |
1121 | |
1122 | rc= mysql_stmt_execute(stmt2); |
1123 | check_stmt_rc(rc, stmt2); |
1124 | |
1125 | rc= mysql_stmt_fetch(stmt2); |
1126 | FAIL_UNLESS(rc == 0, "rc != 0" ) |
1127 | |
1128 | FAIL_UNLESS(empno == 10, "empno != 10" ); |
1129 | FAIL_UNLESS(strcmp(firstname, "CHRISTINE" "" ) == 0, "firstname != 'Christine'" ); |
1130 | |
1131 | rc= mysql_stmt_reset(stmt2); |
1132 | check_stmt_rc(rc, stmt2); |
1133 | |
1134 | /* ERROR: next statement should return 0 */ |
1135 | |
1136 | rc= mysql_stmt_fetch(stmt1); |
1137 | FAIL_UNLESS(rc == 0, "rc != 0" ); |
1138 | |
1139 | mysql_stmt_close(stmt1); |
1140 | mysql_stmt_close(stmt2); |
1141 | rc= mysql_rollback(mysql); |
1142 | check_mysql_rc(rc, mysql); |
1143 | |
1144 | rc= mysql_query(mysql, "drop table t1" ); |
1145 | check_mysql_rc(rc, mysql); |
1146 | |
1147 | return OK; |
1148 | } |
1149 | |
1150 | /* Bug#13488: wrong column metadata when fetching from cursor */ |
1151 | |
1152 | static int test_bug13488(MYSQL *mysql) |
1153 | { |
1154 | MYSQL_BIND my_bind[3]; |
1155 | MYSQL_STMT *stmt1; |
1156 | int rc, f1, f2, f3, i; |
1157 | const ulong type= CURSOR_TYPE_READ_ONLY; |
1158 | const char *query= "select f1, f2, f3 from t1 left join t2 on f1=f2 where f1=1" ; |
1159 | |
1160 | |
1161 | rc= mysql_query(mysql, "drop table if exists t1, t2" ); |
1162 | check_mysql_rc(rc, mysql); |
1163 | rc= mysql_query(mysql, "create table t1 (f1 int not null primary key)" ); |
1164 | check_mysql_rc(rc, mysql); |
1165 | rc= mysql_query(mysql, "create table t2 (f2 int not null primary key, " |
1166 | "f3 int not null)" ); |
1167 | check_mysql_rc(rc, mysql); |
1168 | rc= mysql_query(mysql, "insert into t1 values (1), (2)" ); |
1169 | check_mysql_rc(rc, mysql); |
1170 | rc= mysql_query(mysql, "insert into t2 values (1,2), (2,4)" ); |
1171 | check_mysql_rc(rc, mysql); |
1172 | |
1173 | memset(my_bind, 0, sizeof(my_bind)); |
1174 | for (i= 0; i < 3; i++) |
1175 | { |
1176 | my_bind[i].buffer_type= MYSQL_TYPE_LONG; |
1177 | my_bind[i].buffer_length= 4; |
1178 | my_bind[i].length= 0; |
1179 | } |
1180 | my_bind[0].buffer=&f1; |
1181 | my_bind[1].buffer=&f2; |
1182 | my_bind[2].buffer=&f3; |
1183 | |
1184 | stmt1= mysql_stmt_init(mysql); |
1185 | rc= mysql_stmt_attr_set(stmt1,STMT_ATTR_CURSOR_TYPE, (const void *)&type); |
1186 | check_stmt_rc(rc, stmt1); |
1187 | |
1188 | rc= mysql_stmt_prepare(stmt1, SL(query)); |
1189 | check_stmt_rc(rc, stmt1); |
1190 | |
1191 | rc= mysql_stmt_execute(stmt1); |
1192 | check_stmt_rc(rc, stmt1); |
1193 | |
1194 | rc= mysql_stmt_bind_result(stmt1, my_bind); |
1195 | check_stmt_rc(rc, stmt1); |
1196 | |
1197 | rc= mysql_stmt_fetch(stmt1); |
1198 | check_stmt_rc(rc, stmt1); |
1199 | |
1200 | rc= mysql_stmt_free_result(stmt1); |
1201 | check_stmt_rc(rc, stmt1); |
1202 | |
1203 | rc= mysql_stmt_reset(stmt1); |
1204 | check_stmt_rc(rc, stmt1); |
1205 | |
1206 | rc= mysql_stmt_close(stmt1); |
1207 | check_stmt_rc(rc, stmt1); |
1208 | |
1209 | FAIL_UNLESS(f1 == 1, "f1 != 1" ); |
1210 | FAIL_UNLESS(f2 == 1, "f2 != 1" ); |
1211 | FAIL_UNLESS(f3 == 2, "f3 != 2" ); |
1212 | rc= mysql_query(mysql, "drop table t1, t2" ); |
1213 | check_mysql_rc(rc, mysql); |
1214 | |
1215 | return OK; |
1216 | } |
1217 | |
1218 | /* |
1219 | Bug#13524: warnings of a previous command are not reset when fetching |
1220 | from a cursor. |
1221 | */ |
1222 | |
1223 | static int test_bug13524(MYSQL *mysql) |
1224 | { |
1225 | MYSQL_STMT *stmt; |
1226 | int rc; |
1227 | unsigned int warning_count; |
1228 | const ulong type= CURSOR_TYPE_READ_ONLY; |
1229 | const char *query= "select * from t1" ; |
1230 | |
1231 | |
1232 | rc= mysql_query(mysql, "drop table if exists t1, t2" ); |
1233 | check_mysql_rc(rc, mysql); |
1234 | rc= mysql_query(mysql, "create table t1 (a int not null primary key)" ); |
1235 | check_mysql_rc(rc, mysql); |
1236 | rc= mysql_query(mysql, "insert into t1 values (1), (2), (3), (4)" ); |
1237 | check_mysql_rc(rc, mysql); |
1238 | |
1239 | stmt= mysql_stmt_init(mysql); |
1240 | rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type); |
1241 | check_stmt_rc(rc, stmt); |
1242 | |
1243 | rc= mysql_stmt_prepare(stmt, SL(query)); |
1244 | check_stmt_rc(rc, stmt); |
1245 | |
1246 | rc= mysql_stmt_execute(stmt); |
1247 | check_stmt_rc(rc, stmt); |
1248 | |
1249 | rc= mysql_stmt_fetch(stmt); |
1250 | check_stmt_rc(rc, stmt); |
1251 | |
1252 | warning_count= mysql_warning_count(mysql); |
1253 | FAIL_UNLESS(warning_count == 0, "warning_count != 0" ); |
1254 | |
1255 | /* Check that DROP TABLE produced a warning (no such table) */ |
1256 | rc= mysql_query(mysql, "drop table if exists t2" ); |
1257 | check_mysql_rc(rc, mysql); |
1258 | warning_count= mysql_warning_count(mysql); |
1259 | FAIL_UNLESS(warning_count == 1, "warning_count != 1" ); |
1260 | |
1261 | /* |
1262 | Check that fetch from a cursor cleared the warning from the previous |
1263 | command. |
1264 | */ |
1265 | rc= mysql_stmt_fetch(stmt); |
1266 | check_stmt_rc(rc, stmt); |
1267 | warning_count= mysql_warning_count(mysql); |
1268 | FAIL_UNLESS(warning_count == 0, "warning_count != 0" ); |
1269 | |
1270 | /* Cleanup */ |
1271 | mysql_stmt_close(stmt); |
1272 | rc= mysql_query(mysql, "drop table t1" ); |
1273 | check_mysql_rc(rc, mysql); |
1274 | |
1275 | return OK; |
1276 | } |
1277 | |
1278 | /* |
1279 | Bug#14845 "mysql_stmt_fetch returns MYSQL_NO_DATA when COUNT(*) is 0" |
1280 | */ |
1281 | |
1282 | static int test_bug14845(MYSQL *mysql) |
1283 | { |
1284 | MYSQL_STMT *stmt; |
1285 | int rc; |
1286 | const ulong type= CURSOR_TYPE_READ_ONLY; |
1287 | const char *query= "select count(*) from t1 where 1 = 0" ; |
1288 | |
1289 | |
1290 | rc= mysql_query(mysql, "drop table if exists t1" ); |
1291 | check_mysql_rc(rc, mysql); |
1292 | rc= mysql_query(mysql, "create table t1 (id int(11) default null, " |
1293 | "name varchar(20) default null)" |
1294 | "engine=MyISAM DEFAULT CHARSET=utf8" ); |
1295 | check_mysql_rc(rc, mysql); |
1296 | rc= mysql_query(mysql, "insert into t1 values (1,'abc'),(2,'def')" ); |
1297 | check_mysql_rc(rc, mysql); |
1298 | |
1299 | stmt= mysql_stmt_init(mysql); |
1300 | rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type); |
1301 | check_stmt_rc(rc, stmt); |
1302 | |
1303 | rc= mysql_stmt_prepare(stmt, SL(query)); |
1304 | check_stmt_rc(rc, stmt); |
1305 | |
1306 | rc= mysql_stmt_execute(stmt); |
1307 | check_stmt_rc(rc, stmt); |
1308 | |
1309 | rc= mysql_stmt_fetch(stmt); |
1310 | FAIL_UNLESS(rc == 0, "" ); |
1311 | |
1312 | rc= mysql_stmt_fetch(stmt); |
1313 | FAIL_UNLESS(rc == MYSQL_NO_DATA, "" ); |
1314 | |
1315 | /* Cleanup */ |
1316 | mysql_stmt_close(stmt); |
1317 | rc= mysql_query(mysql, "drop table t1" ); |
1318 | check_mysql_rc(rc, mysql); |
1319 | return OK; |
1320 | } |
1321 | |
1322 | /* |
1323 | Bug#14210 "Simple query with > operator on large table gives server |
1324 | crash" |
1325 | */ |
1326 | |
1327 | static int test_bug14210(MYSQL *mysql) |
1328 | { |
1329 | MYSQL_STMT *stmt; |
1330 | int rc, i; |
1331 | const char *stmt_text; |
1332 | ulong type; |
1333 | |
1334 | rc= mysql_query(mysql, "drop table if exists t1" ); |
1335 | check_mysql_rc(rc, mysql); |
1336 | /* |
1337 | To trigger the problem the table must be InnoDB, although the problem |
1338 | itself is not InnoDB related. In case the table is MyISAM this test |
1339 | is harmless. |
1340 | */ |
1341 | rc= mysql_query(mysql, "create table t1 (a varchar(255)) engine=InnoDB" ); |
1342 | check_mysql_rc(rc, mysql); |
1343 | rc= mysql_query(mysql, "insert into t1 (a) values (repeat('a', 256))" ); |
1344 | check_mysql_rc(rc, mysql); |
1345 | rc= mysql_query(mysql, "set @@session.max_heap_table_size=16384" ); |
1346 | |
1347 | /* Create a big enough table (more than max_heap_table_size) */ |
1348 | for (i= 0; i < 8; i++) |
1349 | { |
1350 | rc= mysql_query(mysql, "insert into t1 (a) select a from t1" ); |
1351 | check_mysql_rc(rc, mysql); |
1352 | } |
1353 | /* create statement */ |
1354 | stmt= mysql_stmt_init(mysql); |
1355 | type= (ulong) CURSOR_TYPE_READ_ONLY; |
1356 | mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type); |
1357 | |
1358 | stmt_text= "select a from t1" ; |
1359 | |
1360 | rc= mysql_stmt_prepare(stmt, SL(stmt_text)); |
1361 | check_stmt_rc(rc, stmt); |
1362 | rc= mysql_stmt_execute(stmt); |
1363 | while ((rc= mysql_stmt_fetch(stmt)) == 0); |
1364 | FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA" ); |
1365 | |
1366 | rc= mysql_stmt_close(stmt); |
1367 | |
1368 | rc= mysql_query(mysql, "drop table t1" ); |
1369 | check_mysql_rc(rc, mysql); |
1370 | rc= mysql_query(mysql, "set @@session.max_heap_table_size=default" ); |
1371 | check_mysql_rc(rc, mysql); |
1372 | |
1373 | return OK; |
1374 | } |
1375 | |
1376 | /* |
1377 | Bug#24179 "select b into $var" fails with --cursor_protocol" |
1378 | The failure is correct, check that the returned message is meaningful. |
1379 | */ |
1380 | |
1381 | static int test_bug24179(MYSQL *mysql) |
1382 | { |
1383 | int rc; |
1384 | MYSQL_STMT *stmt; |
1385 | |
1386 | stmt= open_cursor(mysql, "select 1 into @a" ); |
1387 | rc= mysql_stmt_execute(stmt); |
1388 | FAIL_UNLESS(rc, "Error expected" ); |
1389 | FAIL_UNLESS(mysql_stmt_errno(stmt) == 1323, "stmt_errno != 1323" ); |
1390 | mysql_stmt_close(stmt); |
1391 | |
1392 | return OK; |
1393 | } |
1394 | |
1395 | /** |
1396 | Bug#32265 Server returns different metadata if prepared statement is used |
1397 | */ |
1398 | |
1399 | static int test_bug32265(MYSQL *mysql) |
1400 | { |
1401 | int rc; |
1402 | MYSQL_STMT *stmt; |
1403 | MYSQL_FIELD *field; |
1404 | MYSQL_RES *metadata; |
1405 | |
1406 | if (mysql_get_server_version(mysql) < 50100) { |
1407 | diag("Test requires MySQL Server version 5.1 or above" ); |
1408 | return SKIP; |
1409 | } |
1410 | |
1411 | rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1" ); |
1412 | check_mysql_rc(rc, mysql); |
1413 | rc= mysql_query(mysql, "DROP VIEW IF EXISTS v1" ); |
1414 | rc= mysql_query(mysql, "CREATE TABLE t1 (a INTEGER)" ); |
1415 | check_mysql_rc(rc, mysql); |
1416 | rc= mysql_query(mysql, "INSERT INTO t1 VALUES (1)" ); |
1417 | check_mysql_rc(rc, mysql); |
1418 | rc= mysql_query(mysql, "CREATE VIEW v1 AS SELECT * FROM t1" ); |
1419 | check_mysql_rc(rc, mysql); |
1420 | |
1421 | stmt= open_cursor(mysql, "SELECT * FROM t1" ); |
1422 | rc= mysql_stmt_execute(stmt); |
1423 | check_stmt_rc(rc, stmt); |
1424 | metadata= mysql_stmt_result_metadata(stmt); |
1425 | field= mysql_fetch_field(metadata); |
1426 | FAIL_UNLESS(field, "couldn't fetch field" ); |
1427 | FAIL_UNLESS(strcmp(field->table, "t1" ) == 0, "table != t1" ); |
1428 | FAIL_UNLESS(strcmp(field->org_table, "t1" ) == 0, "org_table != t1" ); |
1429 | FAIL_UNLESS(strcmp(field->db, schema) == 0, "db != schema" ); |
1430 | mysql_free_result(metadata); |
1431 | mysql_stmt_close(stmt); |
1432 | |
1433 | stmt= open_cursor(mysql, "SELECT a '' FROM t1 ``" ); |
1434 | rc= mysql_stmt_execute(stmt); |
1435 | check_stmt_rc(rc, stmt); |
1436 | metadata= mysql_stmt_result_metadata(stmt); |
1437 | field= mysql_fetch_field(metadata); |
1438 | FAIL_UNLESS(strcmp(field->table, "" ) == 0, "field != ''" ); |
1439 | FAIL_UNLESS(strcmp(field->org_table, "t1" ) == 0, "org_table != t1" ); |
1440 | FAIL_UNLESS(strcmp(field->db, schema) == 0, "db != schema" ); |
1441 | mysql_free_result(metadata); |
1442 | mysql_stmt_close(stmt); |
1443 | |
1444 | stmt= open_cursor(mysql, "SELECT a '' FROM t1 ``" ); |
1445 | rc= mysql_stmt_execute(stmt); |
1446 | check_stmt_rc(rc, stmt); |
1447 | metadata= mysql_stmt_result_metadata(stmt); |
1448 | field= mysql_fetch_field(metadata); |
1449 | FAIL_UNLESS(strcmp(field->table, "" ) == 0, "table != ''" ); |
1450 | FAIL_UNLESS(strcmp(field->org_table, "t1" ) == 0, "org_table != t1" ); |
1451 | FAIL_UNLESS(strcmp(field->db, schema) == 0, "db != schema" ); |
1452 | mysql_free_result(metadata); |
1453 | mysql_stmt_close(stmt); |
1454 | |
1455 | stmt= open_cursor(mysql, "SELECT * FROM v1" ); |
1456 | rc= mysql_stmt_execute(stmt); |
1457 | check_stmt_rc(rc, stmt); |
1458 | metadata= mysql_stmt_result_metadata(stmt); |
1459 | field= mysql_fetch_field(metadata); |
1460 | FAIL_UNLESS(strcmp(field->table, "v1" ) == 0, "table != v1" ); |
1461 | FAIL_UNLESS(strcmp(field->org_table, "v1" ) == 0, "org_table != v1" ); |
1462 | FAIL_UNLESS(strcmp(field->db, schema) == 0, "db != schema" ); |
1463 | mysql_free_result(metadata); |
1464 | mysql_stmt_close(stmt); |
1465 | |
1466 | stmt= open_cursor(mysql, "SELECT * FROM v1 /* SIC */ GROUP BY 1" ); |
1467 | rc= mysql_stmt_execute(stmt); |
1468 | check_stmt_rc(rc, stmt); |
1469 | metadata= mysql_stmt_result_metadata(stmt); |
1470 | field= mysql_fetch_field(metadata); |
1471 | FAIL_UNLESS(strcmp(field->table, "v1" ) == 0, "table != v1" ); |
1472 | FAIL_UNLESS(strcmp(field->org_table, "v1" ) == 0, "org_table != v1" ); |
1473 | FAIL_UNLESS(strcmp(field->db, schema) == 0, "schema != db" ); |
1474 | mysql_free_result(metadata); |
1475 | mysql_stmt_close(stmt); |
1476 | |
1477 | rc= mysql_query(mysql, "DROP VIEW v1" ); |
1478 | check_mysql_rc(rc, mysql); |
1479 | rc= mysql_query(mysql, "DROP TABLE t1" ); |
1480 | check_mysql_rc(rc, mysql); |
1481 | |
1482 | return OK; |
1483 | } |
1484 | |
1485 | /** |
1486 | Bug#38486 Crash when using cursor protocol |
1487 | */ |
1488 | |
1489 | static int test_bug38486(MYSQL *mysql) |
1490 | { |
1491 | MYSQL_STMT *stmt; |
1492 | const char *stmt_text; |
1493 | int rc; |
1494 | unsigned long type= CURSOR_TYPE_READ_ONLY; |
1495 | |
1496 | stmt= mysql_stmt_init(mysql); |
1497 | rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*)&type); |
1498 | check_stmt_rc(rc, stmt); |
1499 | stmt_text= "CREATE TABLE t1 (a INT)" ; |
1500 | rc= mysql_stmt_prepare(stmt, SL(stmt_text)); |
1501 | check_stmt_rc(rc, stmt); |
1502 | rc= mysql_stmt_execute(stmt); |
1503 | mysql_stmt_close(stmt); |
1504 | |
1505 | stmt= mysql_stmt_init(mysql); |
1506 | rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*)&type); |
1507 | check_stmt_rc(rc, stmt); |
1508 | stmt_text= "INSERT INTO t1 VALUES (1)" ; |
1509 | rc= mysql_stmt_prepare(stmt, SL(stmt_text)); |
1510 | check_stmt_rc(rc, stmt); |
1511 | rc= mysql_stmt_execute(stmt); |
1512 | check_stmt_rc(rc, stmt); |
1513 | mysql_stmt_close(stmt); |
1514 | |
1515 | return OK; |
1516 | } |
1517 | |
1518 | static int test_bug8880(MYSQL *mysql) |
1519 | { |
1520 | MYSQL_STMT *stmt_list[2], **stmt; |
1521 | MYSQL_STMT **stmt_list_end= (MYSQL_STMT**) stmt_list + 2; |
1522 | int rc; |
1523 | |
1524 | |
1525 | rc= mysql_query(mysql, "drop table if exists t1" ); |
1526 | check_mysql_rc(rc, mysql); |
1527 | rc= mysql_query(mysql, "create table t1 (a int not null primary key, b int)" ); |
1528 | check_mysql_rc(rc, mysql); |
1529 | rc= mysql_query(mysql, "insert into t1 values (1,1)" ); |
1530 | check_mysql_rc(rc, mysql); |
1531 | /* |
1532 | when inserting 2 rows everything works well |
1533 | mysql_query(mysql, "INSERT INTO t1 VALUES (1,1),(2,2)"); |
1534 | */ |
1535 | for (stmt= stmt_list; stmt < stmt_list_end; stmt++) |
1536 | *stmt= open_cursor(mysql, "select a from t1" ); |
1537 | for (stmt= stmt_list; stmt < stmt_list_end; stmt++) |
1538 | { |
1539 | rc= mysql_stmt_execute(*stmt); |
1540 | check_stmt_rc(rc, *stmt); |
1541 | } |
1542 | for (stmt= stmt_list; stmt < stmt_list_end; stmt++) |
1543 | mysql_stmt_close(*stmt); |
1544 | return OK; |
1545 | } |
1546 | |
1547 | static int test_bug9159(MYSQL *mysql) |
1548 | { |
1549 | MYSQL_STMT *stmt; |
1550 | int rc; |
1551 | const char *stmt_text= "select a, b from t1" ; |
1552 | const unsigned long type= CURSOR_TYPE_READ_ONLY; |
1553 | |
1554 | |
1555 | mysql_query(mysql, "drop table if exists t1" ); |
1556 | mysql_query(mysql, "create table t1 (a int not null primary key, b int)" ); |
1557 | rc= mysql_query(mysql, "insert into t1 values (1,1)" ); |
1558 | check_mysql_rc(rc, mysql); |
1559 | |
1560 | stmt= mysql_stmt_init(mysql); |
1561 | mysql_stmt_prepare(stmt, SL(stmt_text)); |
1562 | mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void *)&type); |
1563 | |
1564 | mysql_stmt_execute(stmt); |
1565 | mysql_stmt_close(stmt); |
1566 | rc= mysql_query(mysql, "drop table if exists t1" ); |
1567 | check_mysql_rc(rc, mysql); |
1568 | return OK; |
1569 | } |
1570 | |
1571 | /* |
1572 | We can't have more than one cursor open for a prepared statement. |
1573 | Test re-executions of a PS with cursor; mysql_stmt_reset must close |
1574 | the cursor attached to the statement, if there is one. |
1575 | */ |
1576 | |
1577 | static int test_bug9478(MYSQL *mysql) |
1578 | { |
1579 | MYSQL_STMT *stmt; |
1580 | MYSQL_BIND my_bind[1]; |
1581 | char a[6]; |
1582 | ulong a_len; |
1583 | int rc, i; |
1584 | |
1585 | mysql_query(mysql, "drop table if exists t1" ); |
1586 | mysql_query(mysql, "create table t1 (id integer not null primary key, " |
1587 | " name varchar(20) not null)" ); |
1588 | rc= mysql_query(mysql, "insert into t1 (id, name) values " |
1589 | " (1, 'aaa'), (2, 'bbb'), (3, 'ccc')" ); |
1590 | check_mysql_rc(rc, mysql); |
1591 | |
1592 | stmt= open_cursor(mysql, "select name from t1 where id=2" ); |
1593 | |
1594 | memset(my_bind, '\0', sizeof(my_bind)); |
1595 | my_bind[0].buffer_type= MYSQL_TYPE_STRING; |
1596 | my_bind[0].buffer= (char*) a; |
1597 | my_bind[0].buffer_length= sizeof(a); |
1598 | my_bind[0].length= &a_len; |
1599 | mysql_stmt_bind_result(stmt, my_bind); |
1600 | |
1601 | for (i= 0; i < 5; i++) |
1602 | { |
1603 | rc= mysql_stmt_execute(stmt); |
1604 | check_stmt_rc(rc, stmt); |
1605 | rc= mysql_stmt_fetch(stmt); |
1606 | check_stmt_rc(rc, stmt); |
1607 | |
1608 | /* |
1609 | The query above is a one-row result set. Therefore, there is no |
1610 | cursor associated with it, as the server won't bother with opening |
1611 | a cursor for a one-row result set. The first row was read from the |
1612 | server in the fetch above. But there is eof packet pending in the |
1613 | network. mysql_stmt_execute will flush the packet and successfully |
1614 | execute the statement. |
1615 | */ |
1616 | |
1617 | rc= mysql_stmt_execute(stmt); |
1618 | check_stmt_rc(rc, stmt); |
1619 | |
1620 | rc= mysql_stmt_fetch(stmt); |
1621 | check_stmt_rc(rc, stmt); |
1622 | rc= mysql_stmt_fetch(stmt); |
1623 | FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA" ); |
1624 | |
1625 | { |
1626 | char buff[8]; |
1627 | /* Fill in the fetch packet */ |
1628 | int4store(buff, stmt->stmt_id); |
1629 | buff[4]= 1; /* prefetch rows */ |
1630 | /* rc= ((*mysql->methods->advanced_command)(mysql, COM_STMT_FETCH, |
1631 | (uchar*) buff, |
1632 | sizeof(buff), 0,0,1,NULL) || |
1633 | (*mysql->methods->read_query_result)(mysql)); */ |
1634 | FAIL_UNLESS(rc, "error expected" ); |
1635 | } |
1636 | |
1637 | rc= mysql_stmt_execute(stmt); |
1638 | check_stmt_rc(rc, stmt); |
1639 | |
1640 | rc= mysql_stmt_fetch(stmt); |
1641 | check_stmt_rc(rc, stmt); |
1642 | |
1643 | rc= mysql_stmt_reset(stmt); |
1644 | check_stmt_rc(rc, stmt); |
1645 | rc= mysql_stmt_fetch(stmt); |
1646 | |
1647 | /* mariadb client supports GEOMETRY, so no error will |
1648 | be returned |
1649 | FAIL_UNLESS(rc && mysql_stmt_errno(stmt), "Error expected"); |
1650 | */ |
1651 | } |
1652 | rc= mysql_stmt_close(stmt); |
1653 | check_stmt_rc(rc, stmt); |
1654 | |
1655 | /* Test the case with a server side cursor */ |
1656 | stmt= open_cursor(mysql, "select name from t1" ); |
1657 | |
1658 | mysql_stmt_bind_result(stmt, my_bind); |
1659 | |
1660 | for (i= 0; i < 5; i++) |
1661 | { |
1662 | rc= mysql_stmt_execute(stmt); |
1663 | check_stmt_rc(rc, stmt); |
1664 | rc= mysql_stmt_fetch(stmt); |
1665 | check_stmt_rc(rc, stmt); |
1666 | rc= mysql_stmt_execute(stmt); |
1667 | check_stmt_rc(rc, stmt); |
1668 | |
1669 | while (! (rc= mysql_stmt_fetch(stmt))); |
1670 | FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA" ); |
1671 | |
1672 | rc= mysql_stmt_execute(stmt); |
1673 | check_stmt_rc(rc, stmt); |
1674 | |
1675 | rc= mysql_stmt_fetch(stmt); |
1676 | check_stmt_rc(rc, stmt); |
1677 | |
1678 | rc= mysql_stmt_reset(stmt); |
1679 | check_stmt_rc(rc, stmt); |
1680 | rc= mysql_stmt_fetch(stmt); |
1681 | FAIL_UNLESS(rc && mysql_stmt_errno(stmt), "Error expected" ); |
1682 | } |
1683 | |
1684 | rc= mysql_stmt_close(stmt); |
1685 | check_stmt_rc(rc, stmt); |
1686 | |
1687 | rc= mysql_query(mysql, "drop table t1" ); |
1688 | check_mysql_rc(rc, mysql); |
1689 | return OK; |
1690 | } |
1691 | |
1692 | /* Crash when opening a cursor to a query with DISTICNT and no key */ |
1693 | |
1694 | static int test_bug9520(MYSQL *mysql) |
1695 | { |
1696 | MYSQL_STMT *stmt; |
1697 | MYSQL_BIND my_bind[1]; |
1698 | char a[6]; |
1699 | ulong a_len; |
1700 | int rc, row_count= 0; |
1701 | |
1702 | |
1703 | mysql_query(mysql, "drop table if exists t1" ); |
1704 | mysql_query(mysql, "create table t1 (a char(5), b char(5), c char(5)," |
1705 | " primary key (a, b, c))" ); |
1706 | rc= mysql_query(mysql, "insert into t1 values ('x', 'y', 'z'), " |
1707 | " ('a', 'b', 'c'), ('k', 'l', 'm')" ); |
1708 | check_mysql_rc(rc, mysql); |
1709 | |
1710 | stmt= open_cursor(mysql, "select distinct b from t1" ); |
1711 | |
1712 | /* |
1713 | Not crashes with: |
1714 | stmt= open_cursor(mysql, "select distinct a from t1"); |
1715 | */ |
1716 | |
1717 | rc= mysql_stmt_execute(stmt); |
1718 | check_stmt_rc(rc, stmt); |
1719 | |
1720 | memset(my_bind, '\0', sizeof(my_bind)); |
1721 | my_bind[0].buffer_type= MYSQL_TYPE_STRING; |
1722 | my_bind[0].buffer= (char*) a; |
1723 | my_bind[0].buffer_length= sizeof(a); |
1724 | my_bind[0].length= &a_len; |
1725 | |
1726 | mysql_stmt_bind_result(stmt, my_bind); |
1727 | |
1728 | while (!(rc= mysql_stmt_fetch(stmt))) |
1729 | row_count++; |
1730 | |
1731 | FAIL_UNLESS(rc == MYSQL_NO_DATA, "rc != MYSQL_NO_DATA" ); |
1732 | |
1733 | FAIL_UNLESS(row_count == 3, "row_count != 3" ); |
1734 | |
1735 | mysql_stmt_close(stmt); |
1736 | |
1737 | rc= mysql_query(mysql, "drop table t1" ); |
1738 | check_mysql_rc(rc, mysql); |
1739 | return OK; |
1740 | } |
1741 | |
1742 | /* |
1743 | Error message is returned for unsupported features. |
1744 | Test also cursors with non-default PREFETCH_ROWS |
1745 | */ |
1746 | |
1747 | static int test_bug9643(MYSQL *mysql) |
1748 | { |
1749 | MYSQL_STMT *stmt; |
1750 | MYSQL_BIND my_bind[1]; |
1751 | int32 a; |
1752 | int rc; |
1753 | const char *stmt_text; |
1754 | int num_rows= 0; |
1755 | ulong type; |
1756 | ulong prefetch_rows= 5; |
1757 | |
1758 | |
1759 | mysql_query(mysql, "drop table if exists t1" ); |
1760 | mysql_query(mysql, "create table t1 (id integer not null primary key)" ); |
1761 | rc= mysql_query(mysql, "insert into t1 (id) values " |
1762 | " (1), (2), (3), (4), (5), (6), (7), (8), (9)" ); |
1763 | check_mysql_rc(rc, mysql); |
1764 | |
1765 | stmt= mysql_stmt_init(mysql); |
1766 | /* Not implemented in 5.0 */ |
1767 | type= (ulong) CURSOR_TYPE_SCROLLABLE; |
1768 | rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type); |
1769 | FAIL_UNLESS(rc, "Error expected" ); |
1770 | |
1771 | type= (ulong) CURSOR_TYPE_READ_ONLY; |
1772 | rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type); |
1773 | check_stmt_rc(rc, stmt); |
1774 | rc= mysql_stmt_attr_set(stmt, STMT_ATTR_PREFETCH_ROWS, |
1775 | (void*) &prefetch_rows); |
1776 | check_stmt_rc(rc, stmt); |
1777 | stmt_text= "select * from t1" ; |
1778 | rc= mysql_stmt_prepare(stmt, SL(stmt_text)); |
1779 | check_stmt_rc(rc, stmt); |
1780 | |
1781 | memset(my_bind, '\0', sizeof(my_bind)); |
1782 | my_bind[0].buffer_type= MYSQL_TYPE_LONG; |
1783 | my_bind[0].buffer= (void*) &a; |
1784 | my_bind[0].buffer_length= sizeof(a); |
1785 | mysql_stmt_bind_result(stmt, my_bind); |
1786 | |
1787 | rc= mysql_stmt_execute(stmt); |
1788 | check_stmt_rc(rc, stmt); |
1789 | |
1790 | while ((rc= mysql_stmt_fetch(stmt)) == 0) |
1791 | ++num_rows; |
1792 | FAIL_UNLESS(num_rows == 9, "num_rows != 9" ); |
1793 | |
1794 | rc= mysql_stmt_close(stmt); |
1795 | FAIL_UNLESS(rc == 0, "" ); |
1796 | |
1797 | rc= mysql_query(mysql, "drop table t1" ); |
1798 | check_mysql_rc(rc, mysql); |
1799 | return OK; |
1800 | } |
1801 | |
1802 | |
1803 | struct my_tests_st my_tests[] = { |
1804 | {"test_basic_cursors" , test_basic_cursors, TEST_CONNECTION_DEFAULT, 0, NULL , NULL}, |
1805 | {"test_cursors_with_union" , test_cursors_with_union, TEST_CONNECTION_DEFAULT, 0, NULL , NULL}, |
1806 | {"test_cursors_with_procedure" , test_cursors_with_procedure, TEST_CONNECTION_DEFAULT, 0, NULL , NULL}, |
1807 | {"test_bug21206" , test_bug21206, TEST_CONNECTION_DEFAULT, 0, NULL , NULL}, |
1808 | {"test_bug10729" , test_bug10729, TEST_CONNECTION_DEFAULT, 0, NULL , NULL}, |
1809 | {"test_bug10736" , test_bug10736, TEST_CONNECTION_DEFAULT, 0, NULL , NULL}, |
1810 | {"test_bug10794" , test_bug10794, TEST_CONNECTION_DEFAULT, 0, NULL , NULL}, |
1811 | {"test_bug10760" , test_bug10760, TEST_CONNECTION_DEFAULT, 0, NULL , NULL}, |
1812 | {"test_bug11172" , test_bug11172, TEST_CONNECTION_DEFAULT, 0, NULL , NULL}, |
1813 | {"test_bug11656" , test_bug11656, TEST_CONNECTION_DEFAULT, 0, NULL , NULL}, |
1814 | {"test_bug11901" , test_bug11901, TEST_CONNECTION_DEFAULT, 0, NULL , NULL}, |
1815 | {"test_bug11904" , test_bug11904, TEST_CONNECTION_DEFAULT, 0, NULL , NULL}, |
1816 | {"test_bug12243" , test_bug12243, TEST_CONNECTION_DEFAULT, 0, NULL , NULL}, |
1817 | {"test_bug11909" , test_bug11909, TEST_CONNECTION_DEFAULT, 0, NULL , NULL}, |
1818 | {"test_bug13488" , test_bug13488, TEST_CONNECTION_DEFAULT, 0, NULL , NULL}, |
1819 | {"test_bug13524" , test_bug13524, TEST_CONNECTION_DEFAULT, 0, NULL , NULL}, |
1820 | {"test_bug14845" , test_bug14845, TEST_CONNECTION_DEFAULT, 0, NULL , NULL}, |
1821 | {"test_bug14210" , test_bug14210, TEST_CONNECTION_DEFAULT, 0, NULL , NULL}, |
1822 | {"test_bug24179" , test_bug24179, TEST_CONNECTION_DEFAULT, 0, NULL , NULL}, |
1823 | {"test_bug32265" , test_bug32265, TEST_CONNECTION_DEFAULT, 0, NULL , NULL}, |
1824 | {"test_bug38486" , test_bug38486, TEST_CONNECTION_DEFAULT, 0, NULL , NULL}, |
1825 | {"test_bug8880" , test_bug8880, TEST_CONNECTION_DEFAULT, 0, NULL , NULL}, |
1826 | {"test_bug9159" , test_bug9159, TEST_CONNECTION_DEFAULT, 0, NULL , NULL}, |
1827 | {"test_bug9478" , test_bug9478, TEST_CONNECTION_DEFAULT, 0, NULL , NULL}, |
1828 | {"test_bug9520" , test_bug9520, TEST_CONNECTION_DEFAULT, 0, NULL , NULL}, |
1829 | {"test_bug9643" , test_bug9643, TEST_CONNECTION_DEFAULT, 0, NULL , NULL}, |
1830 | {NULL, NULL, 0, 0, NULL, NULL} |
1831 | }; |
1832 | |
1833 | int main(int argc, char **argv) |
1834 | { |
1835 | if (argc > 1) |
1836 | get_options(argc, argv); |
1837 | |
1838 | get_envvars(); |
1839 | |
1840 | run_tests(my_tests); |
1841 | |
1842 | return(exit_status()); |
1843 | } |
1844 | |