mirror of
https://github.com/MariaDB/server.git
synced 2025-01-18 13:02:28 +01:00
Merge sinisa@bk-internal.mysql.com:/home/bk/mysql-4.0
into sinisa.nasamreza.org:/mnt/work/mysql-4.0
This commit is contained in:
commit
37817f60cc
20 changed files with 268 additions and 572 deletions
|
@ -1231,7 +1231,6 @@ dnl circular references.
|
|||
\$(top_builddir)/innobase/page/libpage.a\
|
||||
\$(top_builddir)/innobase/rem/librem.a\
|
||||
\$(top_builddir)/innobase/thr/libthr.a\
|
||||
\$(top_builddir)/innobase/com/libcom.a\
|
||||
\$(top_builddir)/innobase/sync/libsync.a\
|
||||
\$(top_builddir)/innobase/data/libdata.a\
|
||||
\$(top_builddir)/innobase/mach/libmach.a\
|
||||
|
|
|
@ -952,7 +952,7 @@ int main(int argc, char** argv)
|
|||
|
||||
exit_value= 0;
|
||||
fprintf(result_file,
|
||||
"/*!40001 SET @@session.max_insert_delayed_threads=0*/;\n");
|
||||
"/*!40019 SET @@session.max_insert_delayed_threads=0*/;\n");
|
||||
while (--argc >= 0)
|
||||
{
|
||||
if (dump_log_entries(*(argv++)))
|
||||
|
|
|
@ -25,13 +25,13 @@ noinst_HEADERS = btr0btr.h btr0btr.ic btr0cur.h btr0cur.ic \
|
|||
dict0mem.ic dict0types.h dyn0dyn.h dyn0dyn.ic eval0eval.h \
|
||||
eval0eval.ic eval0proc.h eval0proc.ic fil0fil.h fsp0fsp.h \
|
||||
fsp0fsp.ic fut0fut.h fut0fut.ic fut0lst.h fut0lst.ic \
|
||||
ha0ha.h ha0ha.ic hash0hash.h hash0hash.ic ib_odbc.h \
|
||||
ha0ha.h ha0ha.ic hash0hash.h hash0hash.ic \
|
||||
ibuf0ibuf.h ibuf0ibuf.ic ibuf0types.h lock0lock.h \
|
||||
lock0lock.ic lock0types.h log0log.h log0log.ic log0recv.h \
|
||||
log0recv.ic mach0data.h mach0data.ic makefilewin.i \
|
||||
mem0dbg.h mem0dbg.ic mem0mem.h mem0mem.ic mem0pool.h \
|
||||
mem0pool.ic mtr0log.h mtr0log.ic mtr0mtr.h mtr0mtr.ic \
|
||||
mtr0types.h odbc0odbc.h os0file.h os0proc.h os0proc.ic \
|
||||
mtr0types.h os0file.h os0proc.h os0proc.ic \
|
||||
os0shm.h os0shm.ic os0sync.h os0sync.ic os0thread.h \
|
||||
os0thread.ic page0cur.h page0cur.ic page0page.h \
|
||||
page0page.ic page0types.h pars0grm.h pars0opt.h \
|
||||
|
|
|
@ -1,149 +0,0 @@
|
|||
/******************************************************
|
||||
Innobase ODBC client library header; this is equivalent to
|
||||
the standard sql.h ODBC header file
|
||||
|
||||
(c) 1998 Innobase Oy
|
||||
|
||||
Created 2/22/1998 Heikki Tuuri
|
||||
*******************************************************/
|
||||
|
||||
#ifndef ib_odbc_h
|
||||
#define ib_odbc_h
|
||||
|
||||
typedef unsigned char UCHAR;
|
||||
typedef signed char SCHAR;
|
||||
typedef long int SDWORD;
|
||||
typedef short int SWORD;
|
||||
typedef unsigned long int UDWORD;
|
||||
typedef unsigned short int UWORD;
|
||||
|
||||
typedef void* PTR;
|
||||
|
||||
typedef void* HENV;
|
||||
typedef void* HDBC;
|
||||
typedef void* HSTMT;
|
||||
|
||||
typedef signed short RETCODE;
|
||||
|
||||
/* RETCODEs */
|
||||
#define SQL_NO_DATA_FOUND (-3)
|
||||
#define SQL_INVALID_HANDLE (-2)
|
||||
#define SQL_ERROR (-1)
|
||||
#define SQL_SUCCESS 0
|
||||
|
||||
/* Standard SQL datatypes, using ANSI type numbering */
|
||||
#define SQL_CHAR 1
|
||||
#define SQL_INTEGER 4
|
||||
#define SQL_VARCHAR 12
|
||||
|
||||
/* C datatype to SQL datatype mapping */
|
||||
#define SQL_C_CHAR SQL_CHAR
|
||||
#define SQL_C_LONG SQL_INTEGER
|
||||
|
||||
/* Special length value */
|
||||
#define SQL_NULL_DATA (-1)
|
||||
|
||||
#define SQL_PARAM_INPUT 1
|
||||
#define SQL_PARAM_OUTPUT 4
|
||||
|
||||
/* Null handles */
|
||||
#define SQL_NULL_HENV NULL
|
||||
#define SQL_NULL_HDBC NULL
|
||||
#define SQL_NULL_HSTM NULL
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
Allocates an SQL environment. */
|
||||
|
||||
RETCODE
|
||||
SQLAllocEnv(
|
||||
/*========*/
|
||||
/* out: SQL_SUCCESS */
|
||||
HENV* phenv); /* out: pointer to an environment handle */
|
||||
/**************************************************************************
|
||||
Allocates an SQL connection. */
|
||||
|
||||
RETCODE
|
||||
SQLAllocConnect(
|
||||
/*============*/
|
||||
/* out: SQL_SUCCESS */
|
||||
HENV henv, /* in: pointer to an environment handle */
|
||||
HDBC* phdbc); /* out: pointer to a connection handle */
|
||||
/**************************************************************************
|
||||
Allocates an SQL statement. */
|
||||
|
||||
RETCODE
|
||||
SQLAllocStmt(
|
||||
/*=========*/
|
||||
HDBC hdbc, /* in: SQL connection */
|
||||
HSTMT* phstmt); /* out: pointer to a statement handle */
|
||||
/**************************************************************************
|
||||
Connects to a database server process (establishes a connection and a
|
||||
session). */
|
||||
|
||||
RETCODE
|
||||
SQLConnect(
|
||||
/*=======*/
|
||||
/* out: SQL_SUCCESS */
|
||||
HDBC hdbc, /* in: SQL connection handle */
|
||||
UCHAR* szDSN, /* in: data source name (server name) */
|
||||
SWORD cbDSN, /* in: data source name length */
|
||||
UCHAR* szUID, /* in: user name */
|
||||
SWORD cbUID, /* in: user name length */
|
||||
UCHAR* szAuthStr, /* in: password */
|
||||
SWORD cbAuthStr); /* in: password length */
|
||||
/**************************************************************************
|
||||
Makes the server to parse and optimize an SQL string. */
|
||||
|
||||
RETCODE
|
||||
SQLPrepare(
|
||||
/*=======*/
|
||||
/* out: SQL_SUCCESS */
|
||||
HSTMT hstmt, /* in: statement handle */
|
||||
UCHAR* szSqlStr, /* in: SQL string */
|
||||
SDWORD cbSqlStr); /* in: SQL string length */
|
||||
/**************************************************************************
|
||||
Binds a parameter in a prepared statement. */
|
||||
|
||||
RETCODE
|
||||
SQLBindParameter(
|
||||
/*=============*/
|
||||
/* out: SQL_SUCCESS */
|
||||
HSTMT hstmt, /* in: statement handle */
|
||||
UWORD ipar, /* in: parameter index, starting from 1 */
|
||||
SWORD fParamType, /* in: SQL_PARAM_INPUT or SQL_PARAM_OUTPUT */
|
||||
SWORD fCType, /* in: SQL_C_CHAR, ... */
|
||||
SWORD fSqlType, /* in: SQL_CHAR, ... */
|
||||
UDWORD cbColDef, /* in: precision: ignored */
|
||||
SWORD ibScale, /* in: scale: ignored */
|
||||
PTR rgbValue, /* in: pointer to a buffer for the data */
|
||||
SDWORD cbValueMax, /* in: buffer size */
|
||||
SDWORD* pcbValue); /* in: pointer to a buffer for the data
|
||||
length or SQL_NULL_DATA */
|
||||
/**************************************************************************
|
||||
Executes a prepared statement where all parameters have been bound. */
|
||||
|
||||
RETCODE
|
||||
SQLExecute(
|
||||
/*=======*/
|
||||
/* out: SQL_SUCCESS or SQL_ERROR */
|
||||
HSTMT hstmt); /* in: statement handle */
|
||||
/**************************************************************************
|
||||
Queries an error message. */
|
||||
|
||||
RETCODE
|
||||
SQLError(
|
||||
/*=====*/
|
||||
/* out: SQL_SUCCESS or SQL_NO_DATA_FOUND */
|
||||
HENV henv, /* in: SQL_NULL_HENV */
|
||||
HDBC hdbc, /* in: SQL_NULL_HDBC */
|
||||
HSTMT hstmt, /* in: statement handle */
|
||||
UCHAR* szSqlState, /* in/out: SQLSTATE as a null-terminated string,
|
||||
(currently, always == "S1000") */
|
||||
SDWORD* pfNativeError, /* out: native error code */
|
||||
UCHAR* szErrorMsg, /* in/out: buffer for an error message as a
|
||||
null-terminated string */
|
||||
SWORD cbErrorMsgMax, /* in: buffer size for szErrorMsg */
|
||||
SWORD* pcbErrorMsg); /* out: error message length */
|
||||
|
||||
#endif
|
|
@ -1,20 +0,0 @@
|
|||
/******************************************************
|
||||
Innobase ODBC client library additional header
|
||||
|
||||
(c) 1998 Innobase Oy
|
||||
|
||||
Created 2/22/1998 Heikki Tuuri
|
||||
*******************************************************/
|
||||
|
||||
#ifndef odbc0odbc_h
|
||||
#define odbc0odbc_h
|
||||
|
||||
#include "ib_odbc.h"
|
||||
|
||||
/* Datagram size in communications */
|
||||
#define ODBC_DATAGRAM_SIZE 8192
|
||||
|
||||
/* Communication address maximum length in bytes */
|
||||
#define ODBC_ADDRESS_SIZE COM_MAX_ADDR_LEN
|
||||
|
||||
#endif
|
|
@ -21,7 +21,9 @@ extern int yydebug;
|
|||
/* If the following is set TRUE, the lexer will print the SQL string
|
||||
as it tokenizes it */
|
||||
|
||||
#ifdef UNIV_SQL_DEBUG
|
||||
extern ibool pars_print_lexed;
|
||||
#endif /* UNIV_SQL_DEBUG */
|
||||
|
||||
/* Global variable used while parsing a single procedure or query : the code is
|
||||
NOT re-entrant */
|
||||
|
@ -390,41 +392,18 @@ pars_procedure_definition(
|
|||
table */
|
||||
sym_node_t* param_list, /* in: parameter declaration list */
|
||||
que_node_t* stat_list); /* in: statement list */
|
||||
/*****************************************************************
|
||||
Reads stored procedure input parameter values from a buffer. */
|
||||
|
||||
void
|
||||
pars_proc_read_input_params_from_buf(
|
||||
/*=================================*/
|
||||
que_t* graph, /* in: query graph which contains a stored procedure */
|
||||
byte* buf); /* in: buffer */
|
||||
/*****************************************************************
|
||||
Writes stored procedure output parameter values to a buffer. */
|
||||
|
||||
ulint
|
||||
pars_proc_write_output_params_to_buf(
|
||||
/*=================================*/
|
||||
byte* buf, /* in: buffer which must be big enough */
|
||||
que_t* graph); /* in: query graph which contains a stored procedure */
|
||||
/*****************************************************************
|
||||
Parses a stored procedure call, when this is not within another stored
|
||||
procedure, that is, the client issues a procedure call directly. */
|
||||
procedure, that is, the client issues a procedure call directly.
|
||||
In MySQL/InnoDB, stored InnoDB procedures are invoked via the
|
||||
parsed procedure tree, not via InnoDB SQL, so this function is not used. */
|
||||
|
||||
que_fork_t*
|
||||
pars_stored_procedure_call(
|
||||
/*=======================*/
|
||||
/* out: query graph */
|
||||
sym_node_t* sym_node); /* in: stored procedure name */
|
||||
/*****************************************************************
|
||||
Writes info about query parameter markers (denoted with '?' in ODBC) into a
|
||||
buffer. */
|
||||
|
||||
ulint
|
||||
pars_write_query_param_info(
|
||||
/*========================*/
|
||||
/* out: number of bytes used for info in buf */
|
||||
byte* buf, /* in: buffer which must be big enough */
|
||||
que_fork_t* graph); /* in: parsed query graph */
|
||||
/**********************************************************************
|
||||
Completes a query graph by adding query thread and fork nodes
|
||||
above it and prepares the graph for running. The fork created is of
|
||||
|
|
|
@ -29,13 +29,14 @@ on 1/27/1998 */
|
|||
#include "trx0trx.h"
|
||||
#include "trx0roll.h"
|
||||
#include "lock0lock.h"
|
||||
#include "odbc0odbc.h"
|
||||
#include "eval0eval.h"
|
||||
|
||||
#ifdef UNIV_SQL_DEBUG
|
||||
/* If the following is set TRUE, the lexer will print the SQL string
|
||||
as it tokenizes it */
|
||||
|
||||
ibool pars_print_lexed = FALSE;
|
||||
#endif /* UNIV_SQL_DEBUG */
|
||||
|
||||
/* Global variable used while parsing a single procedure or query : the code is
|
||||
NOT re-entrant */
|
||||
|
@ -389,7 +390,7 @@ pars_resolve_exp_variables_and_types(
|
|||
}
|
||||
|
||||
if (!node) {
|
||||
printf("PARSER ERROR: Unresolved identifier %s\n",
|
||||
fprintf(stderr, "PARSER ERROR: Unresolved identifier %s\n",
|
||||
sym_node->name);
|
||||
}
|
||||
|
||||
|
@ -521,25 +522,6 @@ pars_resolve_exp_list_columns(
|
|||
}
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Retrieves the stored procedure definition for a procedure name. */
|
||||
static
|
||||
void
|
||||
pars_retrieve_procedure_def(
|
||||
/*========================*/
|
||||
sym_node_t* sym_node) /* in: procedure name node */
|
||||
{
|
||||
ut_a(sym_node);
|
||||
ut_a(que_node_get_type(sym_node) == QUE_NODE_SYMBOL);
|
||||
|
||||
sym_node->resolved = TRUE;
|
||||
sym_node->token_type = SYM_PROCEDURE_NAME;
|
||||
|
||||
sym_node->procedure_def = dict_procedure_get((char*)sym_node->name,
|
||||
NULL);
|
||||
ut_a(sym_node->procedure_def);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Retrieves the table definition for a table name id. */
|
||||
static
|
||||
|
@ -1662,218 +1644,21 @@ pars_procedure_definition(
|
|||
|
||||
/*****************************************************************
|
||||
Parses a stored procedure call, when this is not within another stored
|
||||
procedure, that is, the client issues a procedure call directly. */
|
||||
procedure, that is, the client issues a procedure call directly.
|
||||
In MySQL/InnoDB, stored InnoDB procedures are invoked via the
|
||||
parsed procedure tree, not via InnoDB SQL, so this function is not used. */
|
||||
|
||||
que_fork_t*
|
||||
pars_stored_procedure_call(
|
||||
/*=======================*/
|
||||
/* out: query graph */
|
||||
sym_node_t* sym_node) /* in: stored procedure name */
|
||||
sym_node_t* sym_node __attribute__((unused)))
|
||||
/* in: stored procedure name */
|
||||
{
|
||||
call_node_t* node;
|
||||
que_fork_t* fork;
|
||||
que_thr_t* thr;
|
||||
mem_heap_t* heap;
|
||||
|
||||
heap = pars_sym_tab_global->heap;
|
||||
|
||||
fork = que_fork_create(NULL, NULL, QUE_FORK_PROCEDURE_CALL, heap);
|
||||
fork->trx = NULL;
|
||||
|
||||
thr = que_thr_create(fork, heap);
|
||||
|
||||
node = mem_heap_alloc(heap, sizeof(call_node_t));
|
||||
|
||||
thr->child = node;
|
||||
|
||||
node->common.type = QUE_NODE_CALL;
|
||||
node->common.parent = thr;
|
||||
|
||||
sym_node->token_type = SYM_PROCEDURE_NAME;
|
||||
|
||||
pars_retrieve_procedure_def(sym_node);
|
||||
|
||||
node->procedure_def = sym_node->procedure_def;
|
||||
node->proc_name = sym_node;
|
||||
|
||||
node->sym_tab = pars_sym_tab_global;
|
||||
|
||||
pars_sym_tab_global->query_graph = fork;
|
||||
|
||||
return(fork);
|
||||
ut_error;
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
Writes info about query parameter markers (denoted with '?' in ODBC) into a
|
||||
buffer. */
|
||||
|
||||
ulint
|
||||
pars_write_query_param_info(
|
||||
/*========================*/
|
||||
/* out: number of bytes used for info in buf */
|
||||
byte* buf, /* in: buffer which must be big enough */
|
||||
que_fork_t* graph) /* in: parsed query graph */
|
||||
{
|
||||
que_thr_t* thr;
|
||||
call_node_t* call_node;
|
||||
dict_proc_t* procedure_def;
|
||||
que_t* stored_graph;
|
||||
proc_node_t* proc_node;
|
||||
sym_node_t* param;
|
||||
ulint n_params;
|
||||
ibool is_input;
|
||||
|
||||
/* We currently support parameter markers only in stored procedure
|
||||
calls, and there ALL procedure parameters must be marked with '?':
|
||||
no literal values are allowed */
|
||||
|
||||
thr = UT_LIST_GET_FIRST(graph->thrs);
|
||||
|
||||
n_params = 0;
|
||||
|
||||
if (que_node_get_type(thr->child) == QUE_NODE_CALL) {
|
||||
call_node = thr->child;
|
||||
|
||||
procedure_def = call_node->procedure_def;
|
||||
|
||||
stored_graph = dict_procedure_reserve_parsed_copy(
|
||||
procedure_def);
|
||||
proc_node = que_fork_get_child(stored_graph);
|
||||
|
||||
param = proc_node->param_list;
|
||||
|
||||
while (param) {
|
||||
if (param->param_type == PARS_INPUT) {
|
||||
is_input = TRUE;
|
||||
} else {
|
||||
is_input = FALSE;
|
||||
}
|
||||
|
||||
mach_write_to_1(buf + 4 + n_params, is_input);
|
||||
|
||||
n_params++;
|
||||
|
||||
param = que_node_get_next(param);
|
||||
}
|
||||
|
||||
dict_procedure_release_parsed_copy(stored_graph);
|
||||
}
|
||||
|
||||
mach_write_to_4(buf, n_params);
|
||||
|
||||
return(4 + n_params);
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
Reads stored procedure input parameter values from a buffer. */
|
||||
|
||||
void
|
||||
pars_proc_read_input_params_from_buf(
|
||||
/*=================================*/
|
||||
que_t* graph, /* in: query graph which contains a stored procedure */
|
||||
byte* buf) /* in: buffer */
|
||||
{
|
||||
que_thr_t* thr;
|
||||
proc_node_t* proc_node;
|
||||
sym_node_t* param;
|
||||
byte* ptr;
|
||||
ulint len;
|
||||
lint odbc_len;
|
||||
|
||||
ut_ad(graph->fork_type == QUE_FORK_PROCEDURE);
|
||||
|
||||
thr = UT_LIST_GET_FIRST(graph->thrs);
|
||||
|
||||
proc_node = thr->child;
|
||||
|
||||
ptr = buf;
|
||||
|
||||
param = proc_node->param_list;
|
||||
|
||||
while (param) {
|
||||
if (param->param_type == PARS_INPUT) {
|
||||
odbc_len = (lint)mach_read_from_4(ptr);
|
||||
|
||||
ptr += 4;
|
||||
|
||||
if (odbc_len == SQL_NULL_DATA) {
|
||||
len = UNIV_SQL_NULL;
|
||||
} else {
|
||||
len = (ulint)odbc_len;
|
||||
}
|
||||
|
||||
eval_node_copy_and_alloc_val(param, ptr, len);
|
||||
|
||||
if (len != UNIV_SQL_NULL) {
|
||||
ptr += len;
|
||||
}
|
||||
}
|
||||
|
||||
param = que_node_get_next(param);
|
||||
}
|
||||
|
||||
ut_ad(ptr - buf < ODBC_DATAGRAM_SIZE);
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
Writes stored procedure output parameter values to a buffer. */
|
||||
|
||||
ulint
|
||||
pars_proc_write_output_params_to_buf(
|
||||
/*=================================*/
|
||||
/* out: bytes used in buf */
|
||||
byte* buf, /* in: buffer which must be big enough */
|
||||
que_t* graph) /* in: query graph which contains a stored procedure */
|
||||
{
|
||||
que_thr_t* thr;
|
||||
proc_node_t* proc_node;
|
||||
sym_node_t* param;
|
||||
dfield_t* dfield;
|
||||
byte* ptr;
|
||||
ulint len;
|
||||
lint odbc_len;
|
||||
|
||||
ut_ad(graph->fork_type == QUE_FORK_PROCEDURE);
|
||||
|
||||
thr = UT_LIST_GET_FIRST(graph->thrs);
|
||||
|
||||
proc_node = thr->child;
|
||||
|
||||
ptr = buf;
|
||||
|
||||
param = proc_node->param_list;
|
||||
|
||||
while (param) {
|
||||
if (param->param_type == PARS_OUTPUT) {
|
||||
dfield = que_node_get_val(param);
|
||||
|
||||
len = dfield_get_len(dfield);
|
||||
|
||||
if (len == UNIV_SQL_NULL) {
|
||||
odbc_len = SQL_NULL_DATA;
|
||||
} else {
|
||||
odbc_len = (lint)len;
|
||||
}
|
||||
|
||||
mach_write_to_4(ptr, (ulint)odbc_len);
|
||||
|
||||
ptr += 4;
|
||||
|
||||
if (len != UNIV_SQL_NULL) {
|
||||
ut_memcpy(ptr, dfield_get_data(dfield), len);
|
||||
|
||||
ptr += len;
|
||||
}
|
||||
}
|
||||
|
||||
param = que_node_get_next(param);
|
||||
}
|
||||
|
||||
ut_ad(ptr - buf < ODBC_DATAGRAM_SIZE);
|
||||
|
||||
return((ulint)(ptr - buf));
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
Retrieves characters to the lexical analyzer. */
|
||||
|
||||
|
@ -1886,13 +1671,12 @@ pars_get_lex_chars(
|
|||
in the buffer */
|
||||
{
|
||||
int len;
|
||||
char print_buf[16];
|
||||
|
||||
len = pars_sym_tab_global->string_len
|
||||
- pars_sym_tab_global->next_char_pos;
|
||||
if (len == 0) {
|
||||
#ifdef YYDEBUG
|
||||
/* printf("SQL string ends\n"); */
|
||||
/* fputs("SQL string ends\n", stderr); */
|
||||
#endif
|
||||
*result = 0;
|
||||
|
||||
|
@ -1903,18 +1687,18 @@ pars_get_lex_chars(
|
|||
len = max_size;
|
||||
}
|
||||
|
||||
#ifdef UNIV_SQL_DEBUG
|
||||
if (pars_print_lexed) {
|
||||
|
||||
if (len >= 5) {
|
||||
len = 5;
|
||||
}
|
||||
|
||||
ut_memcpy(print_buf, pars_sym_tab_global->sql_string +
|
||||
pars_sym_tab_global->next_char_pos, len);
|
||||
print_buf[len] = '\0';
|
||||
|
||||
printf("%s", print_buf);
|
||||
|
||||
fwrite(pars_sym_tab_global->sql_string +
|
||||
pars_sym_tab_global->next_char_pos,
|
||||
1, len, stderr);
|
||||
}
|
||||
#endif /* UNIV_SQL_DEBUG */
|
||||
|
||||
ut_memcpy(buf, pars_sym_tab_global->sql_string +
|
||||
pars_sym_tab_global->next_char_pos, len);
|
||||
|
@ -1944,7 +1728,7 @@ yyerror(
|
|||
{
|
||||
ut_ad(s);
|
||||
|
||||
printf("PARSER ERROR: Syntax error in SQL string\n");
|
||||
fputs("PARSER ERROR: Syntax error in SQL string\n", stderr);
|
||||
|
||||
ut_error;
|
||||
}
|
||||
|
@ -1968,10 +1752,10 @@ pars_sql(
|
|||
|
||||
heap = mem_heap_create(256);
|
||||
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
/* Currently, the parser is not reentrant: */
|
||||
|
||||
ut_ad(mutex_own(&(dict_sys->mutex)));
|
||||
|
||||
#endif /* UNIV_SYNC_DEBUG */
|
||||
pars_sym_tab_global = sym_tab_create(heap);
|
||||
|
||||
len = ut_strlen(str);
|
||||
|
@ -1996,7 +1780,7 @@ pars_sql(
|
|||
|
||||
graph->sym_tab = pars_sym_tab_global;
|
||||
|
||||
/* printf("SQL graph size %lu\n", mem_heap_get_size(heap)); */
|
||||
/* fprintf(stderr, "SQL graph size %lu\n", mem_heap_get_size(heap)); */
|
||||
|
||||
return(graph);
|
||||
}
|
||||
|
|
|
@ -37,7 +37,6 @@ Created 10/8/1995 Heikki Tuuri
|
|||
#include "que0que.h"
|
||||
#include "srv0que.h"
|
||||
#include "log0recv.h"
|
||||
#include "odbc0odbc.h"
|
||||
#include "pars0pars.h"
|
||||
#include "usr0sess.h"
|
||||
#include "lock0lock.h"
|
||||
|
|
|
@ -13,3 +13,28 @@ Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Lo
|
|||
show tables like 't1';
|
||||
Tables_in_test (t1)
|
||||
drop table t1;
|
||||
select get_lock('crash_lock%20C', 10);
|
||||
get_lock('crash_lock%20C', 10)
|
||||
1
|
||||
create table t2 (a int primary key);
|
||||
insert into t2 values(1);
|
||||
create table t3 (id int);
|
||||
insert into t3 values(connection_id());
|
||||
update t2 set a = a + 1 + get_lock('crash_lock%20C', 10);
|
||||
select (@id := id) - id from t3;
|
||||
(@id := id) - id
|
||||
0
|
||||
kill @id;
|
||||
drop table t2,t3;
|
||||
Server shutdown in progress
|
||||
show binlog events from 79;
|
||||
Log_name Pos Event_type Server_id Orig_log_pos Info
|
||||
master-bin.001 79 Query 1 79 use `test`; create table t1 (a int primary key)
|
||||
master-bin.001 149 Query 1 149 use `test`; insert into t1 values (1),(1)
|
||||
master-bin.001 213 Query 1 213 use `test`; drop table t1
|
||||
master-bin.001 261 Query 1 261 use `test`; create table t2 (a int primary key)
|
||||
master-bin.001 331 Query 1 331 use `test`; insert into t2 values(1)
|
||||
master-bin.001 390 Query 1 390 use `test`; create table t3 (id int)
|
||||
master-bin.001 449 Query 1 449 use `test`; insert into t3 values(connection_id())
|
||||
master-bin.001 522 Query 1 522 use `test`; update t2 set a = a + 1 + get_lock('crash_lock%20C', 10)
|
||||
master-bin.001 613 Query 1 613 use `test`; drop table t2,t3
|
||||
|
|
|
@ -1 +1 @@
|
|||
--replicate-ignore-table=test.t1
|
||||
--replicate-ignore-table=test.t1 --replicate-ignore-table=test.t2 --replicate-ignore-table=test.t3
|
||||
|
|
|
@ -23,3 +23,33 @@ drop table t1;
|
|||
save_master_pos;
|
||||
connection slave;
|
||||
sync_with_master;
|
||||
|
||||
# Now test that even critical errors (connection killed)
|
||||
# are ignored if rules allow it.
|
||||
# The "kill" idea was copied from rpl000001.test.
|
||||
|
||||
connection master1;
|
||||
select get_lock('crash_lock%20C', 10);
|
||||
|
||||
connection master;
|
||||
create table t2 (a int primary key);
|
||||
insert into t2 values(1);
|
||||
create table t3 (id int);
|
||||
insert into t3 values(connection_id());
|
||||
send update t2 set a = a + 1 + get_lock('crash_lock%20C', 10);
|
||||
|
||||
connection master1;
|
||||
sleep 2;
|
||||
select (@id := id) - id from t3;
|
||||
kill @id;
|
||||
drop table t2,t3;
|
||||
connection master;
|
||||
--error 1053;
|
||||
reap;
|
||||
connection master1;
|
||||
show binlog events from 79;
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
# SQL slave thread should not have stopped (because table of the killed
|
||||
# query is in the ignore list).
|
||||
sync_with_master;
|
||||
|
|
|
@ -1543,13 +1543,11 @@ longlong Item_master_pos_wait::val_int()
|
|||
}
|
||||
longlong pos = args[1]->val_int();
|
||||
longlong timeout = (arg_count==3) ? args[2]->val_int() : 0 ;
|
||||
LOCK_ACTIVE_MI;
|
||||
if ((event_count = active_mi->rli.wait_for_pos(thd, log_name, pos, timeout)) == -2)
|
||||
{
|
||||
null_value = 1;
|
||||
event_count=0;
|
||||
}
|
||||
UNLOCK_ACTIVE_MI;
|
||||
return event_count;
|
||||
}
|
||||
|
||||
|
|
159
sql/log_event.cc
159
sql/log_event.cc
|
@ -53,6 +53,14 @@ static void pretty_print_str(FILE* file, char* str, int len)
|
|||
|
||||
#ifndef MYSQL_CLIENT
|
||||
|
||||
static void clear_all_errors(THD *thd, struct st_relay_log_info *rli)
|
||||
{
|
||||
thd->query_error = 0;
|
||||
thd->clear_error();
|
||||
*rli->last_slave_error = 0;
|
||||
rli->last_slave_errno = 0;
|
||||
}
|
||||
|
||||
inline int ignored_error_code(int err_code)
|
||||
{
|
||||
return ((err_code == ER_SLAVE_IGNORED_TABLE) ||
|
||||
|
@ -1803,8 +1811,7 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli)
|
|||
#else
|
||||
rli->future_group_master_log_pos= log_pos;
|
||||
#endif
|
||||
thd->query_error= 0; // clear error
|
||||
thd->clear_error();
|
||||
clear_all_errors(thd, rli);
|
||||
|
||||
if (db_ok(thd->db, replicate_do_db, replicate_ignore_db))
|
||||
{
|
||||
|
@ -1817,84 +1824,93 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli)
|
|||
VOID(pthread_mutex_unlock(&LOCK_thread_count));
|
||||
thd->slave_proxy_id = thread_id; // for temp tables
|
||||
|
||||
/*
|
||||
Sanity check to make sure the master did not get a really bad
|
||||
error on the query.
|
||||
*/
|
||||
if (ignored_error_code((expected_error = error_code)) ||
|
||||
!check_expected_error(thd,rli,expected_error))
|
||||
{
|
||||
mysql_log.write(thd,COM_QUERY,"%s",thd->query);
|
||||
DBUG_PRINT("query",("%s",thd->query));
|
||||
mysql_log.write(thd,COM_QUERY,"%s",thd->query);
|
||||
DBUG_PRINT("query",("%s",thd->query));
|
||||
if (ignored_error_code(expected_error = error_code) ||
|
||||
!check_expected_error(thd,rli,expected_error))
|
||||
mysql_parse(thd, thd->query, q_len);
|
||||
|
||||
else
|
||||
{
|
||||
/*
|
||||
Set a flag if we are inside an transaction so that we can restart
|
||||
the transaction from the start if we are killed
|
||||
|
||||
This will only be done if we are supporting transactional tables
|
||||
in the slave.
|
||||
The query got a really bad error on the master (thread killed etc),
|
||||
which could be inconsistent. Parse it to test the table names: if the
|
||||
replicate-*-do|ignore-table rules say "this query must be ignored" then
|
||||
we exit gracefully; otherwise we warn about the bad error and tell DBA
|
||||
to check/fix it.
|
||||
*/
|
||||
if (!strcmp(thd->query,"BEGIN"))
|
||||
rli->inside_transaction= opt_using_transactions;
|
||||
else if (!(strcmp(thd->query,"COMMIT") && strcmp(thd->query,"ROLLBACK")))
|
||||
rli->inside_transaction=0;
|
||||
|
||||
/*
|
||||
If we expected a non-zero error code, and we don't get the same error
|
||||
code, and none of them should be ignored.
|
||||
*/
|
||||
if ((expected_error != (actual_error = thd->net.last_errno)) &&
|
||||
expected_error &&
|
||||
!ignored_error_code(actual_error) &&
|
||||
!ignored_error_code(expected_error))
|
||||
if (mysql_test_parse_for_slave(thd, thd->query, q_len))
|
||||
/* Can ignore query */
|
||||
clear_all_errors(thd, rli);
|
||||
else
|
||||
{
|
||||
slave_print_error(rli, 0,
|
||||
"\
|
||||
slave_print_error(rli,expected_error,
|
||||
"query '%s' partially completed on the master \
|
||||
(error on master: %d) \
|
||||
and was aborted. There is a chance that your master is inconsistent at this \
|
||||
point. If you are sure that your master is ok, run this query manually on the\
|
||||
slave and then restart the slave with SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1;\
|
||||
START SLAVE; .", thd->query, expected_error);
|
||||
thd->query_error= 1;
|
||||
}
|
||||
goto end;
|
||||
}
|
||||
|
||||
/*
|
||||
Set a flag if we are inside an transaction so that we can restart
|
||||
the transaction from the start if we are killed
|
||||
|
||||
This will only be done if we are supporting transactional tables
|
||||
in the slave.
|
||||
*/
|
||||
if (!strcmp(thd->query,"BEGIN"))
|
||||
rli->inside_transaction= opt_using_transactions;
|
||||
else if (!(strcmp(thd->query,"COMMIT") && strcmp(thd->query,"ROLLBACK")))
|
||||
rli->inside_transaction=0;
|
||||
|
||||
/*
|
||||
If we expected a non-zero error code, and we don't get the same error
|
||||
code, and none of them should be ignored.
|
||||
*/
|
||||
if ((expected_error != (actual_error = thd->net.last_errno)) &&
|
||||
expected_error &&
|
||||
!ignored_error_code(actual_error) &&
|
||||
!ignored_error_code(expected_error))
|
||||
{
|
||||
slave_print_error(rli, 0,
|
||||
"\
|
||||
Query '%s' caused different errors on master and slave. \
|
||||
Error on master: '%s' (%d), Error on slave: '%s' (%d). \
|
||||
Default database: '%s'",
|
||||
query,
|
||||
ER_SAFE(expected_error),
|
||||
expected_error,
|
||||
actual_error ? thd->net.last_error: "no error",
|
||||
actual_error,
|
||||
print_slave_db_safe(db));
|
||||
thd->query_error= 1;
|
||||
}
|
||||
/*
|
||||
If we get the same error code as expected, or they should be ignored.
|
||||
*/
|
||||
else if (expected_error == actual_error ||
|
||||
ignored_error_code(actual_error))
|
||||
{
|
||||
thd->query_error = 0;
|
||||
thd->clear_error();
|
||||
*rli->last_slave_error = 0;
|
||||
rli->last_slave_errno = 0;
|
||||
}
|
||||
/*
|
||||
Other cases: mostly we expected no error and get one.
|
||||
*/
|
||||
else if (thd->query_error || thd->fatal_error)
|
||||
{
|
||||
slave_print_error(rli,actual_error,
|
||||
"Error '%s' on query '%s'. Default database: '%s'",
|
||||
(actual_error ? thd->net.last_error :
|
||||
"unexpected success or fatal error"),
|
||||
query,
|
||||
print_slave_db_safe(db));
|
||||
thd->query_error= 1;
|
||||
}
|
||||
}
|
||||
/*
|
||||
End of sanity check. If the test was wrong, the query got a really bad
|
||||
error on the master, which could be inconsistent, abort and tell DBA to
|
||||
check/fix it. check_expected_error() already printed the message to
|
||||
stderr and rli, and set thd->query_error to 1.
|
||||
query,
|
||||
ER_SAFE(expected_error),
|
||||
expected_error,
|
||||
actual_error ? thd->net.last_error: "no error",
|
||||
actual_error,
|
||||
print_slave_db_safe(db));
|
||||
thd->query_error= 1;
|
||||
}
|
||||
/*
|
||||
If we get the same error code as expected, or they should be ignored.
|
||||
*/
|
||||
else if (expected_error == actual_error ||
|
||||
ignored_error_code(actual_error))
|
||||
clear_all_errors(thd, rli);
|
||||
/*
|
||||
Other cases: mostly we expected no error and get one.
|
||||
*/
|
||||
else if (thd->query_error || thd->fatal_error)
|
||||
{
|
||||
slave_print_error(rli,actual_error,
|
||||
"Error '%s' on query '%s'. Default database: '%s'",
|
||||
(actual_error ? thd->net.last_error :
|
||||
"unexpected success or fatal error"),
|
||||
query,
|
||||
print_slave_db_safe(db));
|
||||
thd->query_error= 1;
|
||||
}
|
||||
} /* End of if (db_ok(... */
|
||||
|
||||
end:
|
||||
VOID(pthread_mutex_lock(&LOCK_thread_count));
|
||||
thd->db= 0; // prevent db from being freed
|
||||
thd->query= 0; // just to be sure
|
||||
|
@ -1939,8 +1955,7 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli,
|
|||
thd->db= (char*) rewrite_db(db);
|
||||
DBUG_ASSERT(thd->query == 0);
|
||||
thd->query = 0; // Should not be needed
|
||||
thd->query_error = 0;
|
||||
thd->clear_error();
|
||||
clear_all_errors(thd, rli);
|
||||
|
||||
if (!use_rli_only_for_errors)
|
||||
{
|
||||
|
|
|
@ -353,6 +353,7 @@ int quick_rm_table(enum db_type base,const char *db,
|
|||
bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list);
|
||||
bool mysql_change_db(THD *thd,const char *name);
|
||||
void mysql_parse(THD *thd,char *inBuf,uint length);
|
||||
bool mysql_test_parse_for_slave(THD *thd,char *inBuf,uint length);
|
||||
void mysql_init_select(LEX *lex);
|
||||
bool mysql_new_select(LEX *lex);
|
||||
void mysql_init_multi_delete(LEX *lex);
|
||||
|
|
|
@ -750,7 +750,7 @@ int load_master_data(THD* thd)
|
|||
We do not want anyone messing with the slave at all for the entire
|
||||
duration of the data load.
|
||||
*/
|
||||
LOCK_ACTIVE_MI;
|
||||
pthread_mutex_lock(&LOCK_active_mi);
|
||||
lock_slave_threads(active_mi);
|
||||
init_thread_mask(&restart_thread_mask,active_mi,0 /*not inverse*/);
|
||||
if (restart_thread_mask &&
|
||||
|
@ -759,7 +759,7 @@ int load_master_data(THD* thd)
|
|||
{
|
||||
send_error(&thd->net,error);
|
||||
unlock_slave_threads(active_mi);
|
||||
UNLOCK_ACTIVE_MI;
|
||||
pthread_mutex_unlock(&LOCK_active_mi);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -913,7 +913,7 @@ int load_master_data(THD* thd)
|
|||
{
|
||||
send_error(&thd->net, 0, "Failed purging old relay logs");
|
||||
unlock_slave_threads(active_mi);
|
||||
UNLOCK_ACTIVE_MI;
|
||||
pthread_mutex_unlock(&LOCK_active_mi);
|
||||
return 1;
|
||||
}
|
||||
pthread_mutex_lock(&active_mi->rli.data_lock);
|
||||
|
@ -934,7 +934,7 @@ int load_master_data(THD* thd)
|
|||
|
||||
err:
|
||||
unlock_slave_threads(active_mi);
|
||||
UNLOCK_ACTIVE_MI;
|
||||
pthread_mutex_unlock(&LOCK_active_mi);
|
||||
thd->proc_info = 0;
|
||||
|
||||
mc_mysql_close(&mysql); // safe to call since we always do mc_mysql_init()
|
||||
|
|
|
@ -1273,7 +1273,7 @@ byte *sys_var_insert_id::value_ptr(THD *thd, enum_var_type type)
|
|||
bool sys_var_slave_skip_counter::check(THD *thd, set_var *var)
|
||||
{
|
||||
int result= 0;
|
||||
LOCK_ACTIVE_MI;
|
||||
pthread_mutex_lock(&LOCK_active_mi);
|
||||
pthread_mutex_lock(&active_mi->rli.run_lock);
|
||||
if (active_mi->rli.slave_running)
|
||||
{
|
||||
|
@ -1281,14 +1281,14 @@ bool sys_var_slave_skip_counter::check(THD *thd, set_var *var)
|
|||
result=1;
|
||||
}
|
||||
pthread_mutex_unlock(&active_mi->rli.run_lock);
|
||||
UNLOCK_ACTIVE_MI;
|
||||
pthread_mutex_unlock(&LOCK_active_mi);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool sys_var_slave_skip_counter::update(THD *thd, set_var *var)
|
||||
{
|
||||
LOCK_ACTIVE_MI;
|
||||
pthread_mutex_lock(&LOCK_active_mi);
|
||||
pthread_mutex_lock(&active_mi->rli.run_lock);
|
||||
/*
|
||||
The following test should normally never be true as we test this
|
||||
|
@ -1302,7 +1302,7 @@ bool sys_var_slave_skip_counter::update(THD *thd, set_var *var)
|
|||
pthread_mutex_unlock(&active_mi->rli.data_lock);
|
||||
}
|
||||
pthread_mutex_unlock(&active_mi->rli.run_lock);
|
||||
UNLOCK_ACTIVE_MI;
|
||||
pthread_mutex_unlock(&LOCK_active_mi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
28
sql/slave.cc
28
sql/slave.cc
|
@ -34,7 +34,6 @@ typedef bool (*CHECK_KILLED_FUNC)(THD*,void*);
|
|||
volatile bool slave_sql_running = 0, slave_io_running = 0;
|
||||
char* slave_load_tmpdir = 0;
|
||||
MASTER_INFO *active_mi;
|
||||
volatile int active_mi_in_use = 0;
|
||||
HASH replicate_do_table, replicate_ignore_table;
|
||||
DYNAMIC_ARRAY replicate_wild_do_table, replicate_wild_ignore_table;
|
||||
bool do_table_inited = 0, ignore_table_inited = 0;
|
||||
|
@ -114,8 +113,12 @@ int init_slave()
|
|||
{
|
||||
DBUG_ENTER("init_slave");
|
||||
|
||||
/* This is called when mysqld starts */
|
||||
|
||||
/*
|
||||
This is called when mysqld starts. Before client connections are
|
||||
accepted. However bootstrap may conflict with us if it does START SLAVE.
|
||||
So it's safer to take the lock.
|
||||
*/
|
||||
pthread_mutex_lock(&LOCK_active_mi);
|
||||
/*
|
||||
TODO: re-write this to interate through the list of files
|
||||
for multi-master
|
||||
|
@ -160,9 +163,11 @@ int init_slave()
|
|||
goto err;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&LOCK_active_mi);
|
||||
DBUG_RETURN(0);
|
||||
|
||||
err:
|
||||
pthread_mutex_unlock(&LOCK_active_mi);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
|
@ -806,7 +811,14 @@ static int end_slave_on_walk(MASTER_INFO* mi, gptr /*unused*/)
|
|||
|
||||
void end_slave()
|
||||
{
|
||||
/* This is called when the server terminates, in close_connections(). */
|
||||
/*
|
||||
This is called when the server terminates, in close_connections().
|
||||
It terminates slave threads. However, some CHANGE MASTER etc may still be
|
||||
running presently. If a START SLAVE was in progress, the mutex lock below
|
||||
will make us wait until slave threads have started, and START SLAVE
|
||||
returns, then we terminate them here.
|
||||
*/
|
||||
pthread_mutex_lock(&LOCK_active_mi);
|
||||
if (active_mi)
|
||||
{
|
||||
/*
|
||||
|
@ -827,6 +839,7 @@ void end_slave()
|
|||
delete active_mi;
|
||||
active_mi= 0;
|
||||
}
|
||||
pthread_mutex_unlock(&LOCK_active_mi);
|
||||
}
|
||||
|
||||
|
||||
|
@ -2237,13 +2250,6 @@ int check_expected_error(THD* thd, RELAY_LOG_INFO* rli, int expected_error)
|
|||
case ER_NET_ERROR_ON_WRITE:
|
||||
case ER_SERVER_SHUTDOWN:
|
||||
case ER_NEW_ABORTING_CONNECTION:
|
||||
slave_print_error(rli,expected_error,
|
||||
"query '%s' partially completed on the master \
|
||||
and was aborted. There is a chance that your master is inconsistent at this \
|
||||
point. If you are sure that your master is ok, run this query manually on the\
|
||||
slave and then restart the slave with SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1;\
|
||||
SLAVE START; .", thd->query);
|
||||
thd->query_error= 1;
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
|
|
36
sql/slave.h
36
sql/slave.h
|
@ -27,12 +27,19 @@
|
|||
/*
|
||||
MUTEXES in replication:
|
||||
|
||||
LOCK_active_mi: this is meant for multimaster, when we can switch from a
|
||||
master to another. It protects active_mi. We don't care of it for the moment,
|
||||
as active_mi never moves (it's created at startup and deleted at shutdown, and
|
||||
not changed: it always points to the same MASTER_INFO struct), because we
|
||||
don't have multimaster. So for the moment, mi does not move, and mi->rli does
|
||||
not either.
|
||||
LOCK_active_mi: [note: this was originally meant for multimaster, to switch
|
||||
from a master to another, to protect active_mi] It is used to SERIALIZE ALL
|
||||
administrative commands of replication: START SLAVE, STOP SLAVE, CHANGE
|
||||
MASTER, RESET SLAVE, end_slave() (when mysqld stops) [init_slave() does not
|
||||
need it it's called early]. Any of these commands holds the mutex from the
|
||||
start till the end. This thus protects us against a handful of deadlocks
|
||||
(consider start_slave_thread() which, when starting the I/O thread, releases
|
||||
mi->run_lock, keeps rli->run_lock, and tries to re-acquire mi->run_lock).
|
||||
|
||||
Currently active_mi never moves (it's created at startup and deleted at
|
||||
shutdown, and not changed: it always points to the same MASTER_INFO struct),
|
||||
because we don't have multimaster. So for the moment, mi does not move, and
|
||||
mi->rli does not either.
|
||||
|
||||
In MASTER_INFO: run_lock, data_lock
|
||||
run_lock protects all information about the run state: slave_running, and the
|
||||
|
@ -43,6 +50,9 @@
|
|||
In RELAY_LOG_INFO: run_lock, data_lock
|
||||
see MASTER_INFO
|
||||
|
||||
Order of acquisition: if you want to have LOCK_active_mi and a run_lock, you
|
||||
must acquire LOCK_active_mi first.
|
||||
|
||||
In MYSQL_LOG: LOCK_log, LOCK_index of the binlog and the relay log
|
||||
LOCK_log: when you write to it. LOCK_index: when you create/delete a binlog
|
||||
(so that you have to update the .index file).
|
||||
|
@ -64,19 +74,6 @@ enum enum_binlog_formats {
|
|||
BINLOG_FORMAT_323_LESS_57,
|
||||
BINLOG_FORMAT_323_GEQ_57 };
|
||||
|
||||
/*
|
||||
TODO: this needs to be redone, but for now it does not matter since
|
||||
we do not have multi-master yet.
|
||||
*/
|
||||
|
||||
#define LOCK_ACTIVE_MI { pthread_mutex_lock(&LOCK_active_mi); \
|
||||
++active_mi_in_use; \
|
||||
pthread_mutex_unlock(&LOCK_active_mi);}
|
||||
|
||||
#define UNLOCK_ACTIVE_MI { pthread_mutex_lock(&LOCK_active_mi); \
|
||||
--active_mi_in_use; \
|
||||
pthread_mutex_unlock(&LOCK_active_mi); }
|
||||
|
||||
/*
|
||||
st_relay_log_info contains information on the current relay log and
|
||||
relay log offset, and master log name and log sequence corresponding to the
|
||||
|
@ -441,7 +438,6 @@ extern "C" pthread_handler_decl(handle_slave_io,arg);
|
|||
extern "C" pthread_handler_decl(handle_slave_sql,arg);
|
||||
extern bool volatile abort_loop;
|
||||
extern MASTER_INFO main_mi, *active_mi; /* active_mi for multi-master */
|
||||
extern volatile int active_mi_in_use;
|
||||
extern LIST master_list;
|
||||
extern HASH replicate_do_table, replicate_ignore_table;
|
||||
extern DYNAMIC_ARRAY replicate_wild_do_table, replicate_wild_ignore_table;
|
||||
|
|
|
@ -65,6 +65,7 @@ static bool create_total_list(THD *thd, LEX *lex,
|
|||
TABLE_LIST **result, bool skip_first);
|
||||
static bool check_one_table_access(THD *thd, ulong want_access,
|
||||
TABLE_LIST *table, bool no_errors);
|
||||
static inline bool all_tables_not_ok(THD *thd, TABLE_LIST *tables);
|
||||
|
||||
const char *any_db="*any*"; // Special symbol for check_access
|
||||
|
||||
|
@ -1332,9 +1333,7 @@ mysql_execute_command(void)
|
|||
Skip if we are in the slave thread, some table rules have been
|
||||
given and the table list says the query should not be replicated
|
||||
*/
|
||||
if (table_rules_on && tables && !tables_ok(thd,tables) &&
|
||||
((lex->sql_command != SQLCOM_DELETE_MULTI) ||
|
||||
!tables_ok(thd,(TABLE_LIST *)thd->lex.auxilliary_table_list.first)))
|
||||
if (all_tables_not_ok(thd,tables))
|
||||
{
|
||||
/* we warn the slave SQL thread */
|
||||
my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
|
||||
|
@ -1519,9 +1518,9 @@ mysql_execute_command(void)
|
|||
{
|
||||
if (check_global_access(thd, SUPER_ACL))
|
||||
goto error;
|
||||
LOCK_ACTIVE_MI;
|
||||
pthread_mutex_lock(&LOCK_active_mi);
|
||||
res = change_master(thd,active_mi);
|
||||
UNLOCK_ACTIVE_MI;
|
||||
pthread_mutex_unlock(&LOCK_active_mi);
|
||||
break;
|
||||
}
|
||||
case SQLCOM_SHOW_SLAVE_STAT:
|
||||
|
@ -1529,9 +1528,9 @@ mysql_execute_command(void)
|
|||
/* Accept one of two privileges */
|
||||
if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
|
||||
goto error;
|
||||
LOCK_ACTIVE_MI;
|
||||
pthread_mutex_lock(&LOCK_active_mi);
|
||||
res = show_master_info(thd,active_mi);
|
||||
UNLOCK_ACTIVE_MI;
|
||||
pthread_mutex_unlock(&LOCK_active_mi);
|
||||
break;
|
||||
}
|
||||
case SQLCOM_SHOW_MASTER_STAT:
|
||||
|
@ -1581,7 +1580,7 @@ mysql_execute_command(void)
|
|||
if (error)
|
||||
goto error;
|
||||
}
|
||||
LOCK_ACTIVE_MI;
|
||||
pthread_mutex_lock(&LOCK_active_mi);
|
||||
/*
|
||||
fetch_master_table will send the error to the client on failure.
|
||||
Give error if the table already exists.
|
||||
|
@ -1591,7 +1590,7 @@ mysql_execute_command(void)
|
|||
{
|
||||
send_ok(&thd->net);
|
||||
}
|
||||
UNLOCK_ACTIVE_MI;
|
||||
pthread_mutex_unlock(&LOCK_active_mi);
|
||||
break;
|
||||
}
|
||||
#endif /* HAVE_REPLICATION */
|
||||
|
@ -1702,9 +1701,9 @@ mysql_execute_command(void)
|
|||
#ifdef HAVE_REPLICATION
|
||||
case SQLCOM_SLAVE_START:
|
||||
{
|
||||
LOCK_ACTIVE_MI;
|
||||
pthread_mutex_lock(&LOCK_active_mi);
|
||||
start_slave(thd,active_mi,1 /* net report*/);
|
||||
UNLOCK_ACTIVE_MI;
|
||||
pthread_mutex_unlock(&LOCK_active_mi);
|
||||
break;
|
||||
}
|
||||
case SQLCOM_SLAVE_STOP:
|
||||
|
@ -1727,9 +1726,9 @@ mysql_execute_command(void)
|
|||
break;
|
||||
}
|
||||
{
|
||||
LOCK_ACTIVE_MI;
|
||||
pthread_mutex_lock(&LOCK_active_mi);
|
||||
stop_slave(thd,active_mi,1/* net report*/);
|
||||
UNLOCK_ACTIVE_MI;
|
||||
pthread_mutex_unlock(&LOCK_active_mi);
|
||||
break;
|
||||
}
|
||||
#endif /* HAVE_REPLICATION */
|
||||
|
@ -2968,9 +2967,18 @@ void mysql_init_multi_delete(LEX *lex)
|
|||
lex->select->table_list.save_and_clear(&lex->auxilliary_table_list);
|
||||
}
|
||||
|
||||
static inline bool all_tables_not_ok(THD *thd, TABLE_LIST *tables)
|
||||
{
|
||||
return (table_rules_on && tables && !tables_ok(thd,tables) &&
|
||||
((thd->lex.sql_command != SQLCOM_DELETE_MULTI) ||
|
||||
!tables_ok(thd,(TABLE_LIST *)thd->lex.auxilliary_table_list.first)));
|
||||
}
|
||||
|
||||
void
|
||||
mysql_parse(THD *thd,char *inBuf,uint length)
|
||||
/*
|
||||
When you modify mysql_parse(), you may need to mofify
|
||||
mysql_test_parse_for_slave() in this same file.
|
||||
*/
|
||||
void mysql_parse(THD *thd, char *inBuf, uint length)
|
||||
{
|
||||
DBUG_ENTER("mysql_parse");
|
||||
|
||||
|
@ -3005,6 +3013,31 @@ mysql_parse(THD *thd,char *inBuf,uint length)
|
|||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
/*
|
||||
Usable by the replication SQL thread only: just parse a query to know if it
|
||||
can be ignored because of replicate-*-table rules.
|
||||
|
||||
RETURN VALUES
|
||||
0 cannot be ignored
|
||||
1 can be ignored
|
||||
*/
|
||||
|
||||
bool mysql_test_parse_for_slave(THD *thd, char *inBuf, uint length)
|
||||
{
|
||||
LEX *lex;
|
||||
bool error= 0;
|
||||
|
||||
mysql_init_query(thd);
|
||||
lex= lex_start(thd, (uchar*) inBuf, length);
|
||||
if (!yyparse() && ! thd->fatal_error &&
|
||||
all_tables_not_ok(thd,(TABLE_LIST*) lex->select_lex.table_list.first))
|
||||
error= 1; /* Ignore question */
|
||||
free_items(thd); /* Free strings used by items */
|
||||
lex_end(lex);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
** Store field definition for create
|
||||
|
@ -3638,9 +3671,9 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables)
|
|||
mysql_update_log.new_file(1);
|
||||
mysql_bin_log.new_file(1);
|
||||
mysql_slow_log.new_file(1);
|
||||
LOCK_ACTIVE_MI;
|
||||
pthread_mutex_lock(&LOCK_active_mi);
|
||||
rotate_relay_log(active_mi);
|
||||
UNLOCK_ACTIVE_MI;
|
||||
pthread_mutex_unlock(&LOCK_active_mi);
|
||||
|
||||
if (ha_flush_logs())
|
||||
result=1;
|
||||
|
@ -3685,7 +3718,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables)
|
|||
#endif
|
||||
if (options & REFRESH_SLAVE)
|
||||
{
|
||||
LOCK_ACTIVE_MI;
|
||||
pthread_mutex_lock(&LOCK_active_mi);
|
||||
if (reset_slave(thd, active_mi))
|
||||
{
|
||||
result=1;
|
||||
|
@ -3697,7 +3730,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables)
|
|||
*/
|
||||
error_already_sent=1;
|
||||
}
|
||||
UNLOCK_ACTIVE_MI;
|
||||
pthread_mutex_unlock(&LOCK_active_mi);
|
||||
}
|
||||
if (options & REFRESH_USER_RESOURCES)
|
||||
reset_mqh(thd,(LEX_USER *) NULL);
|
||||
|
|
|
@ -1270,11 +1270,11 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables,
|
|||
#ifdef HAVE_REPLICATION
|
||||
case SHOW_SLAVE_RUNNING:
|
||||
{
|
||||
LOCK_ACTIVE_MI;
|
||||
pthread_mutex_lock(&LOCK_active_mi);
|
||||
net_store_data(&packet2, (active_mi->slave_running &&
|
||||
active_mi->rli.slave_running)
|
||||
? "ON" : "OFF");
|
||||
UNLOCK_ACTIVE_MI;
|
||||
pthread_mutex_unlock(&LOCK_active_mi);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue