Loading include/errmsg.h +2 −1 Original line number Diff line number Diff line Loading @@ -96,6 +96,7 @@ extern const char *client_errors[]; /* Error messages */ #define CR_NO_DATA 2051 #define CR_NO_STMT_METADATA 2052 #define CR_NO_RESULT_SET 2053 #define CR_ERROR_LAST /*Copy last error nr:*/ 2053 #define CR_NOT_IMPLEMENTED 2054 #define CR_ERROR_LAST /*Copy last error nr:*/ 2054 /* Add error numbers before CR_ERROR_LAST and change it accordingly. */ include/mysql.h +7 −1 Original line number Diff line number Diff line Loading @@ -664,6 +664,7 @@ typedef struct st_mysql_stmt unsigned char **row); unsigned long stmt_id; /* Id for prepared statement */ unsigned long flags; /* i.e. type of cursor to open */ unsigned long prefetch_rows; /* number of rows per one COM_FETCH */ /* Copied from mysql->server_status after execute/fetch to know server-side cursor status for this statement. Loading Loading @@ -702,7 +703,12 @@ enum enum_stmt_attr_type unsigned long with combination of cursor flags (read only, for update, etc) */ STMT_ATTR_CURSOR_TYPE STMT_ATTR_CURSOR_TYPE, /* Amount of rows to retrieve from server per one fetch if using cursors. Accepts unsigned long attribute in the range 1 - ulong_max */ STMT_ATTR_PREFETCH_ROWS }; Loading libmysql/errmsg.c +3 −0 Original line number Diff line number Diff line Loading @@ -81,6 +81,7 @@ const char *client_errors[]= "Attempt to read column without prior row fetch", "Prepared statement contains no metadata", "Attempt to read a row while there is no result set associated with the statement", "This feature is not implemented yet", "" }; Loading Loading @@ -143,6 +144,7 @@ const char *client_errors[]= "Attempt to read column without prior row fetch", "Prepared statement contains no metadata", "Attempt to read a row while there is no result set associated with the statement", "This feature is not implemented yet", "" }; Loading Loading @@ -203,6 +205,7 @@ const char *client_errors[]= "Attempt to read column without prior row fetch", "Prepared statement contains no metadata", "Attempt to read a row while there is no result set associated with the statement", "This feature is not implemented yet", "" }; #endif Loading libmysql/libmysql.c +33 −7 Original line number Diff line number Diff line Loading @@ -1733,6 +1733,9 @@ myodbc_remove_escape(MYSQL *mysql,char *name) /******************* Declarations ***********************************/ /* Default number of rows fetched per one COM_FETCH command. */ #define DEFAULT_PREFETCH_ROWS 1UL /* These functions are called by function pointer MYSQL_STMT::read_row_func. Loading @@ -1758,6 +1761,7 @@ static my_bool setup_one_fetch_function(MYSQL_BIND *bind, MYSQL_FIELD *field); #define RESET_SERVER_SIDE 1 #define RESET_LONG_DATA 2 #define RESET_STORE_RESULT 4 static my_bool reset_stmt_handle(MYSQL_STMT *stmt, uint flags); Loading Loading @@ -1998,6 +2002,7 @@ mysql_stmt_init(MYSQL *mysql) stmt->state= MYSQL_STMT_INIT_DONE; stmt->mysql= mysql; stmt->read_row_func= stmt_read_row_no_data; stmt->prefetch_rows= DEFAULT_PREFETCH_ROWS; /* The rest of statement members was bzeroed inside malloc */ DBUG_RETURN(stmt); Loading Loading @@ -2056,7 +2061,7 @@ mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, ulong length) /* This is second prepare with another statement */ char buff[MYSQL_STMT_HEADER]; /* 4 bytes - stmt id */ if (reset_stmt_handle(stmt, RESET_LONG_DATA)) if (reset_stmt_handle(stmt, RESET_LONG_DATA | RESET_STORE_RESULT)) DBUG_RETURN(1); /* These members must be reset for API to Loading Loading @@ -2711,7 +2716,7 @@ stmt_read_row_from_cursor(MYSQL_STMT *stmt, unsigned char **row) result->rows= 0; /* Send row request to the server */ int4store(buff, stmt->stmt_id); int4store(buff + 4, 1); /* number of rows to fetch */ int4store(buff + 4, stmt->prefetch_rows); /* number of rows to fetch */ if (cli_advanced_command(mysql, COM_FETCH, buff, sizeof(buff), NullS, 0, 1)) { Loading Loading @@ -2769,12 +2774,29 @@ my_bool STDCALL mysql_stmt_attr_set(MYSQL_STMT *stmt, stmt->update_max_length= value ? *(const my_bool*) value : 0; break; case STMT_ATTR_CURSOR_TYPE: stmt->flags= value ? *(const unsigned long *) value : 0; { ulong cursor_type; cursor_type= value ? *(ulong*) value : 0UL; if (cursor_type > (ulong) CURSOR_TYPE_READ_ONLY) goto err_not_implemented; stmt->flags= cursor_type; break; default: } case STMT_ATTR_PREFETCH_ROWS: { ulong prefetch_rows= value ? *(ulong*) value : DEFAULT_PREFETCH_ROWS; if (value == 0) return TRUE; stmt->prefetch_rows= prefetch_rows; break; } default: goto err_not_implemented; } return FALSE; err_not_implemented: set_stmt_error(stmt, CR_NOT_IMPLEMENTED, unknown_sqlstate); return TRUE; } Loading Loading @@ -2851,7 +2873,7 @@ int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt) DBUG_RETURN(1); } if (reset_stmt_handle(stmt, 0)) if (reset_stmt_handle(stmt, RESET_STORE_RESULT)) DBUG_RETURN(1); /* No need to check for stmt->state: if the statement wasn't Loading Loading @@ -4859,7 +4881,11 @@ static my_bool reset_stmt_handle(MYSQL_STMT *stmt, uint flags) MYSQL_DATA *result= &stmt->result; my_bool has_cursor= stmt->read_row_func == stmt_read_row_from_cursor; if (result->data) /* Reset stored result set if so was requested or it's a part of cursor fetch. */ if (result->data && (has_cursor || (flags & RESET_STORE_RESULT))) { /* Result buffered */ free_root(&result->alloc, MYF(MY_KEEP_PREALLOC)); Loading Loading @@ -4918,7 +4944,7 @@ my_bool STDCALL mysql_stmt_free_result(MYSQL_STMT *stmt) DBUG_ENTER("mysql_stmt_free_result"); /* Free the client side and close the server side cursor if there is one */ DBUG_RETURN(reset_stmt_handle(stmt, RESET_LONG_DATA)); DBUG_RETURN(reset_stmt_handle(stmt, RESET_LONG_DATA | RESET_STORE_RESULT)); } /******************************************************************** Loading tests/mysql_client_test.c +63 −0 Original line number Diff line number Diff line Loading @@ -13078,6 +13078,68 @@ static void test_bug9478() } /* Error message is returned for unsupported features. Test also cursors with non-default PREFETCH_ROWS */ static void test_bug9643() { MYSQL_STMT *stmt; MYSQL_BIND bind[1]; int32 a; int rc; const char *stmt_text; int num_rows= 0; ulong type; ulong prefetch_rows= 5; myheader("test_bug9643"); mysql_query(mysql, "drop table if exists t1"); mysql_query(mysql, "create table t1 (id integer not null primary key)"); rc= mysql_query(mysql, "insert into t1 (id) values " " (1), (2), (3), (4), (5), (6), (7), (8), (9)"); myquery(rc); stmt= mysql_stmt_init(mysql); /* Not implemented in 5.0 */ type= (ulong) CURSOR_TYPE_SCROLLABLE; rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type); DIE_UNLESS(rc); if (! opt_silent) printf("Got error (as expected): %s\n", mysql_stmt_error(stmt)); type= (ulong) CURSOR_TYPE_READ_ONLY; rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type); check_execute(stmt, rc); rc= mysql_stmt_attr_set(stmt, STMT_ATTR_PREFETCH_ROWS, (void*) &prefetch_rows); check_execute(stmt, rc); stmt_text= "select * from t1"; rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); check_execute(stmt, rc); bzero(bind, sizeof(bind)); bind[0].buffer_type= MYSQL_TYPE_LONG; bind[0].buffer= (void*) &a; bind[0].buffer_length= sizeof(a); mysql_stmt_bind_result(stmt, bind); rc= mysql_stmt_execute(stmt); check_execute(stmt, rc); while ((rc= mysql_stmt_fetch(stmt)) == 0) ++num_rows; DIE_UNLESS(num_rows == 9); 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 */ Loading Loading @@ -13309,6 +13371,7 @@ static struct my_tests_st my_tests[]= { { "test_bug9159", test_bug9159 }, { "test_bug9520", test_bug9520 }, { "test_bug9478", test_bug9478 }, { "test_bug9643", test_bug9643 }, { 0, 0 } }; Loading Loading
include/errmsg.h +2 −1 Original line number Diff line number Diff line Loading @@ -96,6 +96,7 @@ extern const char *client_errors[]; /* Error messages */ #define CR_NO_DATA 2051 #define CR_NO_STMT_METADATA 2052 #define CR_NO_RESULT_SET 2053 #define CR_ERROR_LAST /*Copy last error nr:*/ 2053 #define CR_NOT_IMPLEMENTED 2054 #define CR_ERROR_LAST /*Copy last error nr:*/ 2054 /* Add error numbers before CR_ERROR_LAST and change it accordingly. */
include/mysql.h +7 −1 Original line number Diff line number Diff line Loading @@ -664,6 +664,7 @@ typedef struct st_mysql_stmt unsigned char **row); unsigned long stmt_id; /* Id for prepared statement */ unsigned long flags; /* i.e. type of cursor to open */ unsigned long prefetch_rows; /* number of rows per one COM_FETCH */ /* Copied from mysql->server_status after execute/fetch to know server-side cursor status for this statement. Loading Loading @@ -702,7 +703,12 @@ enum enum_stmt_attr_type unsigned long with combination of cursor flags (read only, for update, etc) */ STMT_ATTR_CURSOR_TYPE STMT_ATTR_CURSOR_TYPE, /* Amount of rows to retrieve from server per one fetch if using cursors. Accepts unsigned long attribute in the range 1 - ulong_max */ STMT_ATTR_PREFETCH_ROWS }; Loading
libmysql/errmsg.c +3 −0 Original line number Diff line number Diff line Loading @@ -81,6 +81,7 @@ const char *client_errors[]= "Attempt to read column without prior row fetch", "Prepared statement contains no metadata", "Attempt to read a row while there is no result set associated with the statement", "This feature is not implemented yet", "" }; Loading Loading @@ -143,6 +144,7 @@ const char *client_errors[]= "Attempt to read column without prior row fetch", "Prepared statement contains no metadata", "Attempt to read a row while there is no result set associated with the statement", "This feature is not implemented yet", "" }; Loading Loading @@ -203,6 +205,7 @@ const char *client_errors[]= "Attempt to read column without prior row fetch", "Prepared statement contains no metadata", "Attempt to read a row while there is no result set associated with the statement", "This feature is not implemented yet", "" }; #endif Loading
libmysql/libmysql.c +33 −7 Original line number Diff line number Diff line Loading @@ -1733,6 +1733,9 @@ myodbc_remove_escape(MYSQL *mysql,char *name) /******************* Declarations ***********************************/ /* Default number of rows fetched per one COM_FETCH command. */ #define DEFAULT_PREFETCH_ROWS 1UL /* These functions are called by function pointer MYSQL_STMT::read_row_func. Loading @@ -1758,6 +1761,7 @@ static my_bool setup_one_fetch_function(MYSQL_BIND *bind, MYSQL_FIELD *field); #define RESET_SERVER_SIDE 1 #define RESET_LONG_DATA 2 #define RESET_STORE_RESULT 4 static my_bool reset_stmt_handle(MYSQL_STMT *stmt, uint flags); Loading Loading @@ -1998,6 +2002,7 @@ mysql_stmt_init(MYSQL *mysql) stmt->state= MYSQL_STMT_INIT_DONE; stmt->mysql= mysql; stmt->read_row_func= stmt_read_row_no_data; stmt->prefetch_rows= DEFAULT_PREFETCH_ROWS; /* The rest of statement members was bzeroed inside malloc */ DBUG_RETURN(stmt); Loading Loading @@ -2056,7 +2061,7 @@ mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, ulong length) /* This is second prepare with another statement */ char buff[MYSQL_STMT_HEADER]; /* 4 bytes - stmt id */ if (reset_stmt_handle(stmt, RESET_LONG_DATA)) if (reset_stmt_handle(stmt, RESET_LONG_DATA | RESET_STORE_RESULT)) DBUG_RETURN(1); /* These members must be reset for API to Loading Loading @@ -2711,7 +2716,7 @@ stmt_read_row_from_cursor(MYSQL_STMT *stmt, unsigned char **row) result->rows= 0; /* Send row request to the server */ int4store(buff, stmt->stmt_id); int4store(buff + 4, 1); /* number of rows to fetch */ int4store(buff + 4, stmt->prefetch_rows); /* number of rows to fetch */ if (cli_advanced_command(mysql, COM_FETCH, buff, sizeof(buff), NullS, 0, 1)) { Loading Loading @@ -2769,12 +2774,29 @@ my_bool STDCALL mysql_stmt_attr_set(MYSQL_STMT *stmt, stmt->update_max_length= value ? *(const my_bool*) value : 0; break; case STMT_ATTR_CURSOR_TYPE: stmt->flags= value ? *(const unsigned long *) value : 0; { ulong cursor_type; cursor_type= value ? *(ulong*) value : 0UL; if (cursor_type > (ulong) CURSOR_TYPE_READ_ONLY) goto err_not_implemented; stmt->flags= cursor_type; break; default: } case STMT_ATTR_PREFETCH_ROWS: { ulong prefetch_rows= value ? *(ulong*) value : DEFAULT_PREFETCH_ROWS; if (value == 0) return TRUE; stmt->prefetch_rows= prefetch_rows; break; } default: goto err_not_implemented; } return FALSE; err_not_implemented: set_stmt_error(stmt, CR_NOT_IMPLEMENTED, unknown_sqlstate); return TRUE; } Loading Loading @@ -2851,7 +2873,7 @@ int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt) DBUG_RETURN(1); } if (reset_stmt_handle(stmt, 0)) if (reset_stmt_handle(stmt, RESET_STORE_RESULT)) DBUG_RETURN(1); /* No need to check for stmt->state: if the statement wasn't Loading Loading @@ -4859,7 +4881,11 @@ static my_bool reset_stmt_handle(MYSQL_STMT *stmt, uint flags) MYSQL_DATA *result= &stmt->result; my_bool has_cursor= stmt->read_row_func == stmt_read_row_from_cursor; if (result->data) /* Reset stored result set if so was requested or it's a part of cursor fetch. */ if (result->data && (has_cursor || (flags & RESET_STORE_RESULT))) { /* Result buffered */ free_root(&result->alloc, MYF(MY_KEEP_PREALLOC)); Loading Loading @@ -4918,7 +4944,7 @@ my_bool STDCALL mysql_stmt_free_result(MYSQL_STMT *stmt) DBUG_ENTER("mysql_stmt_free_result"); /* Free the client side and close the server side cursor if there is one */ DBUG_RETURN(reset_stmt_handle(stmt, RESET_LONG_DATA)); DBUG_RETURN(reset_stmt_handle(stmt, RESET_LONG_DATA | RESET_STORE_RESULT)); } /******************************************************************** Loading
tests/mysql_client_test.c +63 −0 Original line number Diff line number Diff line Loading @@ -13078,6 +13078,68 @@ static void test_bug9478() } /* Error message is returned for unsupported features. Test also cursors with non-default PREFETCH_ROWS */ static void test_bug9643() { MYSQL_STMT *stmt; MYSQL_BIND bind[1]; int32 a; int rc; const char *stmt_text; int num_rows= 0; ulong type; ulong prefetch_rows= 5; myheader("test_bug9643"); mysql_query(mysql, "drop table if exists t1"); mysql_query(mysql, "create table t1 (id integer not null primary key)"); rc= mysql_query(mysql, "insert into t1 (id) values " " (1), (2), (3), (4), (5), (6), (7), (8), (9)"); myquery(rc); stmt= mysql_stmt_init(mysql); /* Not implemented in 5.0 */ type= (ulong) CURSOR_TYPE_SCROLLABLE; rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type); DIE_UNLESS(rc); if (! opt_silent) printf("Got error (as expected): %s\n", mysql_stmt_error(stmt)); type= (ulong) CURSOR_TYPE_READ_ONLY; rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type); check_execute(stmt, rc); rc= mysql_stmt_attr_set(stmt, STMT_ATTR_PREFETCH_ROWS, (void*) &prefetch_rows); check_execute(stmt, rc); stmt_text= "select * from t1"; rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); check_execute(stmt, rc); bzero(bind, sizeof(bind)); bind[0].buffer_type= MYSQL_TYPE_LONG; bind[0].buffer= (void*) &a; bind[0].buffer_length= sizeof(a); mysql_stmt_bind_result(stmt, bind); rc= mysql_stmt_execute(stmt); check_execute(stmt, rc); while ((rc= mysql_stmt_fetch(stmt)) == 0) ++num_rows; DIE_UNLESS(num_rows == 9); 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 */ Loading Loading @@ -13309,6 +13371,7 @@ static struct my_tests_st my_tests[]= { { "test_bug9159", test_bug9159 }, { "test_bug9520", test_bug9520 }, { "test_bug9478", test_bug9478 }, { "test_bug9643", test_bug9643 }, { 0, 0 } }; Loading