diff options
author | unknown <konstantin@mysql.com> | 2005-05-12 11:16:12 +0400 |
---|---|---|
committer | unknown <konstantin@mysql.com> | 2005-05-12 11:16:12 +0400 |
commit | 2a8556f32deb10ecf2b1f857a1038330b38af53f (patch) | |
tree | 554b6292888722f7406c34e5af18657d1bab8645 /tests | |
parent | edcdc57bff956bccd085de326d200a698919ac5c (diff) | |
download | mariadb-git-2a8556f32deb10ecf2b1f857a1038330b38af53f.tar.gz |
A fix and test case for Bug#9478 "mysql_stmt_attr_set mysql_stmt_execute"
(crash on attempt to re-execute a statement with an open cursor) +
post-review fixes.
include/errmsg.h:
Add a special error message when we attempt to mysql_stmt_fetch
from a statement which has no result set.
libmysql/errmsg.c:
Error message text for CR_NO_RESULT_SET
libmysql/libmysql.c:
Move the code which frees result sets on client and closes the cursor
on server, resets long data state on client and server.
This makes one function out of two (mysql_stmt_reset and
mysql_stmt_free_result), thus aggregating all related reset work
in one place.
sql-common/client.c:
Fix one place where we flushed the pending result set of a statement,
but didn't set unbuffered_fetch_cancelled flag.
sql/share/errmsg.txt:
Fix format of ER_UNKNOWN_STMT_HANDLER error message (needs to
be fixed separately in 4.1). Add two new error messages
for the case when we fetch from when there is no cursor
and for the case when we attempt to execute a statement while there is
a cursor.
sql/sql_prepare.cc:
Return error when we fetch while there is no open cursor and
when we call execute while there is a pending cursor.
Fix mysql_stmt_reset to close the open cursor if there is any.
sql/sql_select.cc:
free_items and free_root moved to Cursor::close().
sql/sql_select.h:
A comment added.
tests/mysql_client_test.c:
A test case for Bug#9478, test the case of mysql_stmt_reset
called for client-side cached result set and for the case with open cursor.
All strcpy replaced with strmov (review request).
Diffstat (limited to 'tests')
-rw-r--r-- | tests/mysql_client_test.c | 197 |
1 files changed, 175 insertions, 22 deletions
diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 6ab5843803e..da57fbabaf2 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -2269,7 +2269,7 @@ static void test_ps_conj_select() check_execute(stmt, rc); int_data= 1; - strcpy(str_data, "hh"); + strmov(str_data, "hh"); str_length= strlen(str_data); rc= mysql_stmt_execute(stmt); @@ -7288,7 +7288,7 @@ static void test_decimal_bug() rc= mysql_stmt_bind_param(stmt, bind); check_execute(stmt, rc); - strcpy(data, "8.0"); + strmov(data, "8.0"); rc= mysql_stmt_execute(stmt); check_execute(stmt, rc); @@ -7306,7 +7306,7 @@ static void test_decimal_bug() rc= mysql_stmt_fetch(stmt); DIE_UNLESS(rc == MYSQL_NO_DATA); - strcpy(data, "5.61"); + strmov(data, "5.61"); rc= mysql_stmt_execute(stmt); check_execute(stmt, rc); @@ -7331,7 +7331,7 @@ static void test_decimal_bug() rc= mysql_stmt_fetch(stmt); DIE_UNLESS(rc == MYSQL_NO_DATA); - strcpy(data, "10.22"); is_null= 0; + strmov(data, "10.22"); is_null= 0; rc= mysql_stmt_execute(stmt); check_execute(stmt, rc); @@ -8510,13 +8510,13 @@ static void test_sqlmode() myquery(rc); /* PIPES_AS_CONCAT */ - strcpy(query, "SET SQL_MODE= \"PIPES_AS_CONCAT\""); + strmov(query, "SET SQL_MODE= \"PIPES_AS_CONCAT\""); if (!opt_silent) fprintf(stdout, "\n With %s", query); rc= mysql_query(mysql, query); myquery(rc); - strcpy(query, "INSERT INTO test_piping VALUES(?||?)"); + strmov(query, "INSERT INTO test_piping VALUES(?||?)"); if (!opt_silent) fprintf(stdout, "\n query: %s", query); stmt= mysql_simple_prepare(mysql, query); @@ -8542,7 +8542,7 @@ static void test_sqlmode() rc= mysql_stmt_bind_param(stmt, bind); check_execute(stmt, rc); - strcpy(c1, "My"); strcpy(c2, "SQL"); + strmov(c1, "My"); strmov(c2, "SQL"); rc= mysql_stmt_execute(stmt); check_execute(stmt, rc); @@ -8552,20 +8552,20 @@ static void test_sqlmode() rc= mysql_query(mysql, "DELETE FROM test_piping"); myquery(rc); - strcpy(query, "SELECT connection_id ()"); + strmov(query, "SELECT connection_id ()"); if (!opt_silent) fprintf(stdout, "\n query: %s", query); stmt= mysql_simple_prepare(mysql, query); check_stmt_r(stmt); /* ANSI */ - strcpy(query, "SET SQL_MODE= \"ANSI\""); + strmov(query, "SET SQL_MODE= \"ANSI\""); if (!opt_silent) fprintf(stdout, "\n With %s", query); rc= mysql_query(mysql, query); myquery(rc); - strcpy(query, "INSERT INTO test_piping VALUES(?||?)"); + strmov(query, "INSERT INTO test_piping VALUES(?||?)"); if (!opt_silent) fprintf(stdout, "\n query: %s", query); stmt= mysql_simple_prepare(mysql, query); @@ -8576,7 +8576,7 @@ static void test_sqlmode() rc= mysql_stmt_bind_param(stmt, bind); check_execute(stmt, rc); - strcpy(c1, "My"); strcpy(c2, "SQL"); + strmov(c1, "My"); strmov(c2, "SQL"); rc= mysql_stmt_execute(stmt); check_execute(stmt, rc); @@ -8584,7 +8584,7 @@ static void test_sqlmode() verify_col_data("test_piping", "name", "MySQL"); /* ANSI mode spaces ... */ - strcpy(query, "SELECT connection_id ()"); + strmov(query, "SELECT connection_id ()"); if (!opt_silent) fprintf(stdout, "\n query: %s", query); stmt= mysql_simple_prepare(mysql, query); @@ -8604,13 +8604,13 @@ static void test_sqlmode() mysql_stmt_close(stmt); /* IGNORE SPACE MODE */ - strcpy(query, "SET SQL_MODE= \"IGNORE_SPACE\""); + strmov(query, "SET SQL_MODE= \"IGNORE_SPACE\""); if (!opt_silent) fprintf(stdout, "\n With %s", query); rc= mysql_query(mysql, query); myquery(rc); - strcpy(query, "SELECT connection_id ()"); + strmov(query, "SELECT connection_id ()"); if (!opt_silent) fprintf(stdout, "\n query: %s", query); stmt= mysql_simple_prepare(mysql, query); @@ -9115,7 +9115,7 @@ static void test_bug2248() /* This too should not hang but should return proper error */ rc= mysql_stmt_fetch(stmt); - DIE_UNLESS(rc == MYSQL_NO_DATA); + DIE_UNLESS(rc == 1); /* This too should not hang but should not bark */ rc= mysql_stmt_store_result(stmt); @@ -9124,7 +9124,7 @@ static void test_bug2248() /* This should return proper error */ rc= mysql_stmt_fetch(stmt); check_execute_r(stmt, rc); - DIE_UNLESS(rc == MYSQL_NO_DATA); + DIE_UNLESS(rc == 1); mysql_stmt_close(stmt); @@ -10266,7 +10266,7 @@ static void test_union_param() my_bool my_null= FALSE; myheader("test_union_param"); - strcpy(my_val, "abc"); + strmov(my_val, "abc"); query= (char*)"select ? as my_col union distinct select ?"; stmt= mysql_simple_prepare(mysql, query); @@ -10548,14 +10548,14 @@ static void test_bug3796() if (!opt_silent) printf("Concat result: '%s'\n", out_buff); check_execute(stmt, rc); - strcpy(canonical_buff, concat_arg0); + strmov(canonical_buff, concat_arg0); strcat(canonical_buff, "ONE"); DIE_UNLESS(strlen(canonical_buff) == out_length && strncmp(out_buff, canonical_buff, out_length) == 0); rc= mysql_stmt_fetch(stmt); check_execute(stmt, rc); - strcpy(canonical_buff + strlen(concat_arg0), "TWO"); + strmov(canonical_buff + strlen(concat_arg0), "TWO"); DIE_UNLESS(strlen(canonical_buff) == out_length && strncmp(out_buff, canonical_buff, out_length) == 0); if (!opt_silent) @@ -10852,7 +10852,8 @@ static void test_view() rc= mysql_stmt_prepare(stmt, query, strlen(query)); check_execute(stmt, rc); - strcpy(str_data, "TEST"); + strmov(str_data, "TEST"); + bzero(bind, sizeof(bind)); bind[0].buffer_type= FIELD_TYPE_STRING; bind[0].buffer= (char *)&str_data; bind[0].buffer_length= 50; @@ -10971,8 +10972,9 @@ static void test_view_2where() " AENAME,T0001.DEPENDVARS AS DEPENDVARS,T0001.INACTIVE AS " " INACTIVE from LTDX T0001 where (T0001.SRTF2 = 0)"); myquery(rc); + bzero(bind, sizeof(bind)); for (i=0; i < 8; i++) { - strcpy(parms[i], "1"); + strmov(parms[i], "1"); bind[i].buffer_type = MYSQL_TYPE_VAR_STRING; bind[i].buffer = (char *)&parms[i]; bind[i].buffer_length = 100; @@ -11019,6 +11021,7 @@ static void test_view_star() myquery(rc); rc= mysql_query(mysql, "CREATE VIEW vt1 AS SELECT a FROM t1"); myquery(rc); + bzero(bind, sizeof(bind)); for (i= 0; i < 2; i++) { sprintf((char *)&parms[i], "%d", i); bind[i].buffer_type = MYSQL_TYPE_VAR_STRING; @@ -11084,6 +11087,7 @@ static void test_view_insert() rc= mysql_stmt_prepare(select_stmt, query, strlen(query)); check_execute(select_stmt, rc); + bzero(bind, sizeof(bind)); bind[0].buffer_type = FIELD_TYPE_LONG; bind[0].buffer = (char *)&my_val; bind[0].length = &my_length; @@ -11187,6 +11191,7 @@ static void test_view_insert_fields() " F7F8 AS F7F8, F6N4 AS F6N4, F5C8 AS F5C8, F9D8 AS F9D8" " from t1 T0001"); + bzero(bind, sizeof(bind)); for (i= 0; i < 11; i++) { l[i]= 20; @@ -11194,7 +11199,7 @@ static void test_view_insert_fields() bind[i].is_null= 0; bind[i].buffer= (char *)&parm[i]; - strcpy(parm[i], "1"); + strmov(parm[i], "1"); bind[i].buffer_length= 2; bind[i].length= &l[i]; } @@ -12707,6 +12712,7 @@ from t2);"); rc= mysql_query(mysql, "DROP VIEW v1"); myquery(rc); rc= mysql_query(mysql, "DROP TABLE t1, t2"); + mysql_free_result(res); myquery(rc); } @@ -12924,6 +12930,152 @@ static void test_bug9520() /* + We can't have more than one cursor open for a prepared statement. + Test re-executions of a PS with cursor; mysql_stmt_reset must close + the cursor attached to the statement, if there is one. +*/ + +static void test_bug9478() +{ + MYSQL_STMT *stmt; + MYSQL_BIND bind[1]; + char a[6]; + ulong a_len; + int rc, i; + + myheader("test_bug9478"); + + mysql_query(mysql, "drop table if exists t1"); + mysql_query(mysql, "create table t1 (id integer not null primary key, " + " name varchar(20) not null)"); + rc= mysql_query(mysql, "insert into t1 (id, name) values " + " (1, 'aaa'), (2, 'bbb'), (3, 'ccc')"); + myquery(rc); + + stmt= open_cursor("select name from t1 where id=2"); + + bzero(bind, sizeof(bind)); + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer= (char*) a; + bind[0].buffer_length= sizeof(a); + bind[0].length= &a_len; + mysql_stmt_bind_result(stmt, bind); + + for (i= 0; i < 5; i++) + { + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + if (!opt_silent && i == 0) + printf("Fetched row: %s\n", a); + + /* + The query above is a one-row result set. Therefore, there is no + cursor associated with it, as the server won't bother with opening + a cursor for a one-row result set. The first row was read from the + server in the fetch above. But there is eof packet pending in the + network. mysql_stmt_execute will flush the packet and successfully + execute the statement. + */ + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + if (!opt_silent && i == 0) + printf("Fetched row: %s\n", a); + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + if (!opt_silent && i == 0) + printf("Fetched row: %s\n", a); + + rc= mysql_stmt_reset(stmt); + check_execute(stmt, rc); + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc && mysql_stmt_errno(stmt)); + if (!opt_silent && i == 0) + printf("Got error (as expected): %s\n", mysql_stmt_error(stmt)); + } + rc= mysql_stmt_close(stmt); + DIE_UNLESS(rc == 0); + + /* Test the case with a server side cursor */ + stmt= open_cursor("select name from t1"); + + mysql_stmt_bind_result(stmt, bind); + + for (i= 0; i < 5; i++) + { + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + if (!opt_silent && i == 0) + printf("Fetched row: %s\n", a); + /* + Although protocol-wise an attempt to execute a statement which + already has an open cursor associated with it will yield an error, + the client library behavior tested here is consistent with + the non-cursor execution scenario: mysql_stmt_execute will + silently close the cursor if necessary. + */ + { + char buff[9]; + bzero(buff, sizeof(buff)); + /* Fill in the execute packet */ + int4store(buff, stmt->stmt_id); + int4store(buff+5, 1); + rc= ((*mysql->methods->advanced_command)(mysql, COM_EXECUTE, buff, + sizeof(buff), 0,0,1) || + (*mysql->methods->read_query_result)(mysql)); + DIE_UNLESS(rc); + if (!opt_silent && i == 0) + printf("Got error (as expected): %s\n", mysql_error(mysql)); + } + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + while (! (rc= mysql_stmt_fetch(stmt))) + { + if (!opt_silent && i == 0) + printf("Fetched row: %s\n", a); + } + DIE_UNLESS(rc == MYSQL_NO_DATA); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + if (!opt_silent && i == 0) + printf("Fetched row: %s\n", a); + + rc= mysql_stmt_reset(stmt); + check_execute(stmt, rc); + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc && mysql_stmt_errno(stmt)); + if (!opt_silent && i == 0) + printf("Got error (as expected): %s\n", mysql_stmt_error(stmt)); + } + + rc= mysql_stmt_close(stmt); + DIE_UNLESS(rc == 0); + + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); +} + + +/* Read and parse arguments and MySQL options from my.cnf */ @@ -13153,6 +13305,7 @@ static struct my_tests_st my_tests[]= { { "test_bug8880", test_bug8880 }, { "test_bug9159", test_bug9159 }, { "test_bug9520", test_bug9520 }, + { "test_bug9478", test_bug9478 }, { 0, 0 } }; |