summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <konstantin@mysql.com>2005-05-16 18:27:21 +0400
committerunknown <konstantin@mysql.com>2005-05-16 18:27:21 +0400
commit1bb1bc69935a234fcb72088e1065712ac59f475b (patch)
treee6dfafb73cbb2de3614c02947064cf7fc10404ab
parent6f4c2486439dfcbaab7e1686860385282562d442 (diff)
downloadmariadb-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.h3
-rw-r--r--include/mysql.h8
-rw-r--r--libmysql/errmsg.c3
-rw-r--r--libmysql/libmysql.c40
-rw-r--r--tests/mysql_client_test.c63
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 }
};