diff options
author | unknown <konstantin@mysql.com> | 2005-05-16 18:27:21 +0400 |
---|---|---|
committer | unknown <konstantin@mysql.com> | 2005-05-16 18:27:21 +0400 |
commit | 1bb1bc69935a234fcb72088e1065712ac59f475b (patch) | |
tree | e6dfafb73cbb2de3614c02947064cf7fc10404ab | |
parent | 6f4c2486439dfcbaab7e1686860385282562d442 (diff) | |
download | mariadb-git-1bb1bc69935a234fcb72088e1065712ac59f475b.tar.gz |
A fix and a test case for Bug#9643 " CURSOR_TYPE_SCROLLABLE dos not work"
- check on the client the unsupported feature and return
an error message if it's been requested.
Additionally added API support for STMT_ATTR_PREFETCH_ROWS.
Post-review fixes.
include/errmsg.h:
Add a new error code for "Not implemented" client-side error message.
include/mysql.h:
Add a statement attribute STMT_ATTR_PREFETCH_ROWS - unsigned long
number of rows to fetch per one COM_FETCH command, used when there
is a read-only cursor.
Note, that we don't break compatibility by adding this new member
because MYSQL_STMT is always allocated inside the client library by
mysql_stmt_init.
libmysql/errmsg.c:
Text for the error message CR_NOT_IMPLEMENTED
libmysql/libmysql.c:
Implement support for STMT_ATTR_PREFETCH_ROWS
Return an error message on attempt to set an attribute of a prepared
statement which is not implemented yet. We probably should be doing
it in the server: currently the server just ignores unknown attributes.
tests/mysql_client_test.c:
A test case for Bug#9643 "CURSOR_TYPE_SCROLLABLE dos not work"
- check that an error message is returned for CURSOR_TYPE_SCROLLABLE.
Additionally, check setting of STMT_ATTR_PREFETCH_ROWS.
-rw-r--r-- | include/errmsg.h | 3 | ||||
-rw-r--r-- | include/mysql.h | 8 | ||||
-rw-r--r-- | libmysql/errmsg.c | 3 | ||||
-rw-r--r-- | libmysql/libmysql.c | 40 | ||||
-rw-r--r-- | tests/mysql_client_test.c | 63 |
5 files changed, 108 insertions, 9 deletions
diff --git a/include/errmsg.h b/include/errmsg.h index fd3da392df4..1dd5759c104 100644 --- a/include/errmsg.h +++ b/include/errmsg.h @@ -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. */ diff --git a/include/mysql.h b/include/mysql.h index 24f1961a260..1b2fb7825c8 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -663,6 +663,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. @@ -701,7 +702,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 }; diff --git a/libmysql/errmsg.c b/libmysql/errmsg.c index 5d183b478ef..9e1d70a47df 100644 --- a/libmysql/errmsg.c +++ b/libmysql/errmsg.c @@ -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", "" }; @@ -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", "" }; @@ -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 diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 3e6b29b7602..1823fda7aa5 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -1703,6 +1703,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. @@ -1728,6 +1731,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); @@ -1968,6 +1972,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); @@ -2026,7 +2031,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 @@ -2681,7 +2686,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)) { @@ -2739,12 +2744,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; + } + 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: - return TRUE; + goto err_not_implemented; } return FALSE; +err_not_implemented: + set_stmt_error(stmt, CR_NOT_IMPLEMENTED, unknown_sqlstate); + return TRUE; } @@ -2821,7 +2843,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 @@ -4826,7 +4848,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)); @@ -4885,7 +4911,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)); } /******************************************************************** diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index da57fbabaf2..5d647a2f693 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -13076,6 +13076,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 */ @@ -13306,6 +13368,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 } }; |