mirror of
https://github.com/MariaDB/server.git
synced 2025-01-19 21:42:35 +01:00
eaf34dd8e3
- client side part is simple and may be considered stable - server side part now just joggles with THD state to save execution state and has no additional locking wisdom. Lot's of it are to be rewritten. include/mysql.h: Cursor patch to push into the main tree, client library part (considered stable): - new statement attribute STMT_ATTR_CURSOR_TYPE - MYSQL_STMT::flags to store statement cursor type - MYSQL_STMT::server_status to store server status (i. e. if the server was able to open a cursor for this query). include/mysql_com.h: Cursor patch to push into the main tree, client library part (considered stable): - new COMmand, COM_FETCH, to fetch K rows from read-only cursor. By design should support scrollable cursors as well. - a few new server statuses: SERVER_STATUS_CURSOR_EXISTS is sent by server in reply to COM_EXECUTE, when cursor was successfully opened for this query SERVER_STATUS_LAST_ROW_SENT is sent along with the last row to prevent one more round trip just for finding out that all rows were fetched from this cursor (this is server mem savier also). - and finally, all possible values of STMT_ATTR_CURSOR_TYPE, while now we support only CURSORT_TYPE_NO_CURSOR and CURSOR_TYPE_READ_ONLY libmysql/libmysql.c: Cursor patch to push into the main tree, client library part (considered stable): - simple additions to mysql_stmt_fetch implementation to read data from an opened cursor: we can read up to iteration count rows per one request; read rows are buffered in the same way as rows of mysql_stmt_store_result. - now send stmt->flags to server to let him now if we wish to have a cursor for this statement. - support for setting/getting statement cursor type. libmysqld/examples/Makefile.am: Testing cursors was originally implemented in C++. Now when these tests go into client_test, it's time to convert it to C++ as well. libmysqld/lib_sql.cc: - cleanup: send_fields flags are now named. sql/ha_innodb.cc: - cleanup: send_fields flags are now named. sql/mysql_priv.h: - cursors support: declaration for server-side handler of COM_FETCH sql/protocol.cc: - cleanup: send_fields flags are now named. - we can't anymore assert that field_types[field_pos] is sensible: if we have COM_EXCUTE(stmt1), COM_EXECUTE(stmt2), COM_FETCH(stmt1) field_types[field_pos] will point to fields of stmt2. sql/protocol.h: - cleanup: send_fields flag_s_ are now named. sql/protocol_cursor.cc: - cleanup: send_fields flags are now named. sql/repl_failsafe.cc: - cleanup: send_fields flags are now named. sql/slave.cc: - cleanup: send_fields flags are now named. sql/sp.cc: - cleanup: send_fields flags are now named. sql/sp_head.cc: - cleanup: send_fields flags are now named. sql/sql_acl.cc: - cleanup: send_fields flags are now named. sql/sql_class.cc: - cleanup: send_fields flags are now named. sql/sql_class.h: - cleanup: send_fields flags are now named. sql/sql_error.cc: - cleanup: send_fields flags are now named. sql/sql_handler.cc: - cleanup: send_fields flags are now named. sql/sql_help.cc: - cleanup: send_fields flags are now named. sql/sql_parse.cc: Server side support for cursors: - handle COM_FETCH - enforce assumption that whenever we free thd->free_list, we reset it to zero. This way it's much easier to handle free_list in prepared statements implementation. sql/sql_prepare.cc: Server side support for cursors: - implementation of mysql_stmt_fetch (fetch some rows from open cursor). - management of cursors memory is quite tricky now. - execute_stmt can't be reused anymore in mysql_stmt_execute and mysql_sql_stmt_execute sql/sql_repl.cc: - cleanup: send_fields flags are now named. sql/sql_select.cc: Server side support for cursors: - implementation of Cursor::open, Cursor::fetch (buggy when it comes to non-equi joins), cursor cleanups. - -4 -3 -0 constants indicating return value of sub_select and end_send are to be renamed to something more readable: it turned out to be not so simple, so it should come with the other patch. sql/sql_select.h: Server side support for cursors: - declaration of Cursor class. - JOIN::fetch_limit contains runtime value of rows fetched via cursor. sql/sql_show.cc: - cleanup: send_fields flags are now named. sql/sql_table.cc: - cleanup: send_fields flags are now named. sql/sql_union.cc: - if there was a cursor, don't cleanup unit: we'll need it to fetch the rest of the rows. tests/Makefile.am: Now client_test is in C++. tests/client_test.cc: A few elementary tests for cursors. BitKeeper/etc/ignore: Added libmysqld/examples/client_test.cc to the ignore list
220 lines
6.3 KiB
C++
220 lines
6.3 KiB
C++
/* Copyright (C) 1995-2002 MySQL AB
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
|
|
|
/**********************************************************************
|
|
This file contains the implementation of error and warnings related
|
|
|
|
- Whenever an error or warning occurred, it pushes it to a warning list
|
|
that the user can retrieve with SHOW WARNINGS or SHOW ERRORS.
|
|
|
|
- For each statement, we return the number of warnings generated from this
|
|
command. Note that this can be different from @@warning_count as
|
|
we reset the warning list only for questions that uses a table.
|
|
This is done to allow on to do:
|
|
INSERT ...;
|
|
SELECT @@warning_count;
|
|
SHOW WARNINGS;
|
|
(If we would reset after each command, we could not retrieve the number
|
|
of warnings)
|
|
|
|
- When client requests the information using SHOW command, then
|
|
server processes from this list and returns back in the form of
|
|
resultset.
|
|
|
|
Supported syntaxes:
|
|
|
|
SHOW [COUNT(*)] ERRORS [LIMIT [offset,] rows]
|
|
SHOW [COUNT(*)] WARNINGS [LIMIT [offset,] rows]
|
|
SELECT @@warning_count, @@error_count;
|
|
|
|
***********************************************************************/
|
|
|
|
#include "mysql_priv.h"
|
|
#include "sp_rcontext.h"
|
|
|
|
/*
|
|
Store a new message in an error object
|
|
|
|
This is used to in group_concat() to register how many warnings we actually
|
|
got after the query has been executed.
|
|
*/
|
|
|
|
void MYSQL_ERROR::set_msg(THD *thd, const char *msg_arg)
|
|
{
|
|
msg= strdup_root(&thd->warn_root, msg_arg);
|
|
}
|
|
|
|
|
|
/*
|
|
Reset all warnings for the thread
|
|
|
|
SYNOPSIS
|
|
mysql_reset_errors()
|
|
thd Thread handle
|
|
|
|
IMPLEMENTATION
|
|
Don't reset warnings if this has already been called for this query.
|
|
This may happen if one gets a warning during the parsing stage,
|
|
in which case push_warnings() has already called this function.
|
|
*/
|
|
|
|
void mysql_reset_errors(THD *thd)
|
|
{
|
|
DBUG_ENTER("mysql_reset_errors");
|
|
if (thd->query_id != thd->warn_id)
|
|
{
|
|
thd->warn_id= thd->query_id;
|
|
free_root(&thd->warn_root,MYF(0));
|
|
bzero((char*) thd->warn_count, sizeof(thd->warn_count));
|
|
thd->warn_list.empty();
|
|
thd->row_count= 1; // by default point to row 1
|
|
}
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
/*
|
|
Push the warning/error to error list if there is still room in the list
|
|
|
|
SYNOPSIS
|
|
push_warning()
|
|
thd Thread handle
|
|
level Severity of warning (note, warning, error ...)
|
|
code Error number
|
|
msg Clear error message
|
|
|
|
RETURN
|
|
pointer on MYSQL_ERROR object
|
|
*/
|
|
|
|
MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level,
|
|
uint code, const char *msg)
|
|
{
|
|
DBUG_ENTER("push_warning");
|
|
if (thd->query_id != thd->warn_id)
|
|
mysql_reset_errors(thd);
|
|
|
|
MYSQL_ERROR *err= NULL;
|
|
|
|
if (thd->spcont && thd->spcont->find_handler(code))
|
|
DBUG_RETURN(NULL);
|
|
|
|
if (thd->warn_list.elements < thd->variables.max_error_count)
|
|
{
|
|
/*
|
|
The following code is here to change the allocation to not
|
|
use the thd->mem_root, which is freed after each query
|
|
*/
|
|
MEM_ROOT *old_root=my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC);
|
|
my_pthread_setspecific_ptr(THR_MALLOC, &thd->warn_root);
|
|
err= new MYSQL_ERROR(thd, code, level, msg);
|
|
if (err)
|
|
thd->warn_list.push_back(err);
|
|
my_pthread_setspecific_ptr(THR_MALLOC, old_root);
|
|
}
|
|
thd->warn_count[(uint) level]++;
|
|
thd->total_warn_count++;
|
|
DBUG_RETURN(err);
|
|
}
|
|
|
|
/*
|
|
Push the warning/error to error list if there is still room in the list
|
|
|
|
SYNOPSIS
|
|
push_warning_printf()
|
|
thd Thread handle
|
|
level Severity of warning (note, warning, error ...)
|
|
code Error number
|
|
msg Clear error message
|
|
*/
|
|
|
|
void push_warning_printf(THD *thd, MYSQL_ERROR::enum_warning_level level,
|
|
uint code, const char *format, ...)
|
|
{
|
|
va_list args;
|
|
char warning[ERRMSGSIZE+20];
|
|
DBUG_ENTER("push_warning_printf");
|
|
DBUG_PRINT("enter",("warning: %u", code));
|
|
|
|
va_start(args,format);
|
|
my_vsnprintf(warning, sizeof(warning), format, args);
|
|
va_end(args);
|
|
push_warning(thd, level, code, warning);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
/*
|
|
Send all notes, errors or warnings to the client in a result set
|
|
|
|
SYNOPSIS
|
|
mysqld_show_warnings()
|
|
thd Thread handler
|
|
levels_to_show Bitmap for which levels to show
|
|
|
|
DESCRIPTION
|
|
Takes into account the current LIMIT
|
|
|
|
RETURN VALUES
|
|
0 ok
|
|
1 Error sending data to client
|
|
*/
|
|
|
|
static const char *warning_level_names[]= {"Note", "Warning", "Error", "?"};
|
|
static int warning_level_length[]= { 4, 7, 5, 1 };
|
|
|
|
my_bool mysqld_show_warnings(THD *thd, ulong levels_to_show)
|
|
{
|
|
List<Item> field_list;
|
|
DBUG_ENTER("mysqld_show_warnings");
|
|
|
|
field_list.push_back(new Item_empty_string("Level", 7));
|
|
field_list.push_back(new Item_return_int("Code",4, MYSQL_TYPE_LONG));
|
|
field_list.push_back(new Item_empty_string("Message",MYSQL_ERRMSG_SIZE));
|
|
|
|
if (thd->protocol->send_fields(&field_list,
|
|
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
|
|
DBUG_RETURN(1);
|
|
|
|
MYSQL_ERROR *err;
|
|
SELECT_LEX *sel= &thd->lex->select_lex;
|
|
ha_rows offset= sel->offset_limit, limit= sel->select_limit;
|
|
Protocol *protocol=thd->protocol;
|
|
|
|
List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
|
|
while ((err= it++))
|
|
{
|
|
/* Skip levels that the user is not interested in */
|
|
if (!(levels_to_show & ((ulong) 1 << err->level)))
|
|
continue;
|
|
if (offset)
|
|
{
|
|
offset--;
|
|
continue;
|
|
}
|
|
protocol->prepare_for_resend();
|
|
protocol->store(warning_level_names[err->level],
|
|
warning_level_length[err->level], system_charset_info);
|
|
protocol->store((uint32) err->code);
|
|
protocol->store(err->msg, strlen(err->msg), system_charset_info);
|
|
if (protocol->write())
|
|
DBUG_RETURN(1);
|
|
if (!--limit)
|
|
break;
|
|
}
|
|
send_eof(thd);
|
|
DBUG_RETURN(0);
|
|
}
|