1/*
2Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
3
4The 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
6MySQL Connectors. There are special exceptions to the terms and
7conditions of the GPLv2 as it is applied to this software, see the
8FLOSS License Exception
9<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
10
11This program is free software; you can redistribute it and/or modify
12it under the terms of the GNU General Public License as published
13by the Free Software Foundation; version 2 of the License.
14
15This program is distributed in the hope that it will be useful, but
16WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18for more details.
19
20You should have received a copy of the GNU General Public License along
21with this program; if not, write to the Free Software Foundation, Inc.,
2251 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23*/
24#include "my_test.h"
25
26/* helper functions */
27enum { MAX_COLUMN_LENGTH= 255 };
28
29typedef 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
42MYSQL_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
62int 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
124int 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
137int 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
156void 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
170enum fetch_type { USE_ROW_BY_ROW_FETCH= 0, USE_STORE_RESULT= 1 };
171
172int 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
226static 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
270static 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
284static 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*/
302static 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
337static 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
393static 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
446static 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
532static 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
628static 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
695static 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
751static 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
882static 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
957static 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
1020static 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
1152static 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
1223static 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
1282static 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
1327static 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
1381static 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
1399static 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
1489static 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
1518static 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
1547static 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
1577static 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
1694static 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
1747static 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
1803struct 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
1833int 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