mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
Manual merge of patch implementing WL#1339 with main tree.
This commit is contained in:
@ -437,6 +437,10 @@ my_bool mysql_rpl_probe(MYSQL *mysql __attribute__((unused))) { return 1; }
|
||||
#endif
|
||||
static void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val,
|
||||
int len);
|
||||
static void replace_dynstr_append(DYNAMIC_STRING *ds, const char *val);
|
||||
static int normal_handle_error(const char *query, struct st_query *q,
|
||||
MYSQL *mysql, DYNAMIC_STRING *ds);
|
||||
static int normal_handle_no_error(struct st_query *q);
|
||||
|
||||
static void do_eval(DYNAMIC_STRING* query_eval, const char* query)
|
||||
{
|
||||
@ -951,7 +955,7 @@ static void do_exec(struct st_query* q)
|
||||
ds= &ds_res;
|
||||
|
||||
while (fgets(buf, sizeof(buf), res_file))
|
||||
replace_dynstr_append_mem(ds, buf, strlen(buf));
|
||||
replace_dynstr_append(ds, buf);
|
||||
}
|
||||
error= pclose(res_file);
|
||||
|
||||
@ -1613,6 +1617,29 @@ void init_manager()
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
Connect to a server doing several retries if needed.
|
||||
|
||||
SYNOPSIS
|
||||
safe_connect()
|
||||
con - connection structure to be used
|
||||
host, user, pass, - connection parameters
|
||||
db, port, sock
|
||||
|
||||
NOTE
|
||||
This function will try to connect to the given server MAX_CON_TRIES
|
||||
times and sleep CON_RETRY_SLEEP seconds between attempts before
|
||||
finally giving up. This helps in situation when the client starts
|
||||
before the server (which happens sometimes).
|
||||
It will ignore any errors during these retries. One should use
|
||||
connect_n_handle_errors() if he expects a connection error and wants
|
||||
handle as if it was an error from a usual statement.
|
||||
|
||||
RETURN VALUE
|
||||
0 - success, non-0 - failure
|
||||
*/
|
||||
|
||||
int safe_connect(MYSQL* con, const char* host, const char* user,
|
||||
const char* pass,
|
||||
const char* db, int port, const char* sock)
|
||||
@ -1634,6 +1661,114 @@ int safe_connect(MYSQL* con, const char* host, const char* user,
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Connect to a server and handle connection errors in case when they occur.
|
||||
|
||||
SYNOPSIS
|
||||
connect_n_handle_errors()
|
||||
q - context of connect "query" (command)
|
||||
con - connection structure to be used
|
||||
host, user, pass, - connection parameters
|
||||
db, port, sock
|
||||
create_conn - out parameter, set to zero if connection was
|
||||
not established and is not touched otherwise
|
||||
|
||||
DESCRIPTION
|
||||
This function will try to establish a connection to server and handle
|
||||
possible errors in the same manner as if "connect" was usual SQL-statement
|
||||
(If error is expected it will ignore it once it occurs and log the
|
||||
"statement" to the query log).
|
||||
Unlike safe_connect() it won't do several attempts.
|
||||
|
||||
RETURN VALUE
|
||||
0 - success, non-0 - failure
|
||||
*/
|
||||
|
||||
int connect_n_handle_errors(struct st_query *q, MYSQL* con, const char* host,
|
||||
const char* user, const char* pass,
|
||||
const char* db, int port, const char* sock,
|
||||
int* create_conn)
|
||||
{
|
||||
DYNAMIC_STRING ds_tmp, *ds;
|
||||
int error= 0;
|
||||
|
||||
/*
|
||||
Altough we ignore --require or --result before connect() command we still
|
||||
need to handle record_file because of "@result_file sql-command" syntax.
|
||||
*/
|
||||
if (q->record_file[0])
|
||||
{
|
||||
init_dynamic_string(&ds_tmp, "", 16384, 65536);
|
||||
ds= &ds_tmp;
|
||||
}
|
||||
else
|
||||
ds= &ds_res;
|
||||
|
||||
if (!disable_query_log)
|
||||
{
|
||||
/*
|
||||
It is nice to have connect() statement logged in result file
|
||||
in this case.
|
||||
QQ: Should we do this only if we are expecting an error ?
|
||||
*/
|
||||
char port_buff[22]; /* This should be enough for any int */
|
||||
char *port_end;
|
||||
dynstr_append_mem(ds, "connect(", 8);
|
||||
replace_dynstr_append(ds, host);
|
||||
dynstr_append_mem(ds, ",", 1);
|
||||
replace_dynstr_append(ds, user);
|
||||
dynstr_append_mem(ds, ",", 1);
|
||||
replace_dynstr_append(ds, pass);
|
||||
dynstr_append_mem(ds, ",", 1);
|
||||
if (db)
|
||||
replace_dynstr_append(ds, db);
|
||||
dynstr_append_mem(ds, ",", 1);
|
||||
port_end= int10_to_str(port, port_buff, 10);
|
||||
replace_dynstr_append_mem(ds, port_buff, port_end - port_buff);
|
||||
dynstr_append_mem(ds, ",", 1);
|
||||
if (sock)
|
||||
replace_dynstr_append(ds, sock);
|
||||
dynstr_append_mem(ds, ")", 1);
|
||||
dynstr_append_mem(ds, delimiter, delimiter_length);
|
||||
dynstr_append_mem(ds, "\n", 1);
|
||||
}
|
||||
if (!mysql_real_connect(con, host, user, pass, db, port, sock ? sock: 0,
|
||||
CLIENT_MULTI_STATEMENTS))
|
||||
{
|
||||
error= normal_handle_error("connect", q, con, ds);
|
||||
*create_conn= 0;
|
||||
goto err;
|
||||
}
|
||||
else if (normal_handle_no_error(q))
|
||||
{
|
||||
/*
|
||||
Fail if there was no error but we expected it.
|
||||
We also don't want to have connection in this case.
|
||||
*/
|
||||
mysql_close(con);
|
||||
*create_conn= 0;
|
||||
error= 1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (record)
|
||||
{
|
||||
if (!q->record_file[0] && !result_file)
|
||||
die("At line %u: Missing result file", start_lineno);
|
||||
if (!result_file)
|
||||
str_to_file(q->record_file, ds->str, ds->length);
|
||||
}
|
||||
else if (q->record_file[0])
|
||||
error|= check_result(ds, q->record_file, q->require_file);
|
||||
|
||||
err:
|
||||
free_replace();
|
||||
if (ds == &ds_tmp)
|
||||
dynstr_free(&ds_tmp);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
int do_connect(struct st_query* q)
|
||||
{
|
||||
char* con_name, *con_user,*con_pass, *con_host, *con_port_str,
|
||||
@ -1642,6 +1777,8 @@ int do_connect(struct st_query* q)
|
||||
char buff[FN_REFLEN];
|
||||
int con_port;
|
||||
int free_con_sock = 0;
|
||||
int error= 0;
|
||||
int create_conn= 1;
|
||||
|
||||
DBUG_ENTER("do_connect");
|
||||
DBUG_PRINT("enter",("connect: %s",p));
|
||||
@ -1706,18 +1843,28 @@ int do_connect(struct st_query* q)
|
||||
/* Special database to allow one to connect without a database name */
|
||||
if (con_db && !strcmp(con_db,"*NO-ONE*"))
|
||||
con_db=0;
|
||||
if ((safe_connect(&next_con->mysql, con_host,
|
||||
con_user, con_pass,
|
||||
con_db, con_port, con_sock ? con_sock: 0)))
|
||||
die("Could not open connection '%s': %s", con_name,
|
||||
mysql_error(&next_con->mysql));
|
||||
|
||||
if (!(next_con->name = my_strdup(con_name, MYF(MY_WME))))
|
||||
die(NullS);
|
||||
cur_con = next_con++;
|
||||
if (q->abort_on_error)
|
||||
{
|
||||
if ((safe_connect(&next_con->mysql, con_host, con_user, con_pass,
|
||||
con_db, con_port, con_sock ? con_sock: 0)))
|
||||
die("Could not open connection '%s': %s", con_name,
|
||||
mysql_error(&next_con->mysql));
|
||||
}
|
||||
else
|
||||
error= connect_n_handle_errors(q, &next_con->mysql, con_host, con_user,
|
||||
con_pass, con_db, con_port, con_sock,
|
||||
&create_conn);
|
||||
|
||||
if (create_conn)
|
||||
{
|
||||
if (!(next_con->name= my_strdup(con_name, MYF(MY_WME))))
|
||||
die(NullS);
|
||||
cur_con= next_con++;
|
||||
}
|
||||
if (free_con_sock)
|
||||
my_free(con_sock, MYF(MY_WME));
|
||||
DBUG_RETURN(0);
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
||||
|
||||
@ -2356,6 +2503,13 @@ static void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val,
|
||||
dynstr_append_mem(ds, val, len);
|
||||
}
|
||||
|
||||
/* Append zero-terminated string to ds, with optional replace */
|
||||
|
||||
static void replace_dynstr_append(DYNAMIC_STRING *ds, const char *val)
|
||||
{
|
||||
replace_dynstr_append_mem(ds, val, strlen(val));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Append all results to the dynamic string separated with '\t'
|
||||
@ -2502,93 +2656,14 @@ static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags)
|
||||
(!(last_result= res= mysql_store_result(mysql)) &&
|
||||
mysql_field_count(mysql)))
|
||||
{
|
||||
if (q->require_file)
|
||||
{
|
||||
abort_not_supported_test();
|
||||
}
|
||||
if (q->abort_on_error)
|
||||
die("At line %u: query '%s' failed: %d: %s", start_lineno, query,
|
||||
mysql_errno(mysql), mysql_error(mysql));
|
||||
else
|
||||
{
|
||||
for (i=0 ; (uint) i < q->expected_errors ; i++)
|
||||
{
|
||||
if (((q->expected_errno[i].type == ERR_ERRNO) &&
|
||||
(q->expected_errno[i].code.errnum == mysql_errno(mysql))) ||
|
||||
((q->expected_errno[i].type == ERR_SQLSTATE) &&
|
||||
(strcmp(q->expected_errno[i].code.sqlstate,mysql_sqlstate(mysql)) == 0)))
|
||||
{
|
||||
if (i == 0 && q->expected_errors == 1)
|
||||
{
|
||||
/* Only log error if there is one possible error */
|
||||
dynstr_append_mem(ds,"ERROR ",6);
|
||||
replace_dynstr_append_mem(ds, mysql_sqlstate(mysql),
|
||||
strlen(mysql_sqlstate(mysql)));
|
||||
dynstr_append_mem(ds, ": ", 2);
|
||||
replace_dynstr_append_mem(ds,mysql_error(mysql),
|
||||
strlen(mysql_error(mysql)));
|
||||
dynstr_append_mem(ds,"\n",1);
|
||||
}
|
||||
/* Don't log error if we may not get an error */
|
||||
else if (q->expected_errno[0].type == ERR_SQLSTATE ||
|
||||
(q->expected_errno[0].type == ERR_ERRNO &&
|
||||
q->expected_errno[0].code.errnum != 0))
|
||||
dynstr_append(ds,"Got one of the listed errors\n");
|
||||
goto end; /* Ok */
|
||||
}
|
||||
}
|
||||
DBUG_PRINT("info",("i: %d expected_errors: %d", i,
|
||||
q->expected_errors));
|
||||
dynstr_append_mem(ds, "ERROR ",6);
|
||||
replace_dynstr_append_mem(ds, mysql_sqlstate(mysql),
|
||||
strlen(mysql_sqlstate(mysql)));
|
||||
dynstr_append_mem(ds,": ",2);
|
||||
replace_dynstr_append_mem(ds, mysql_error(mysql),
|
||||
strlen(mysql_error(mysql)));
|
||||
dynstr_append_mem(ds,"\n",1);
|
||||
if (i)
|
||||
{
|
||||
if (q->expected_errno[0].type == ERR_ERRNO)
|
||||
verbose_msg("query '%s' failed with wrong errno %d instead of %d...",
|
||||
q->query, mysql_errno(mysql), q->expected_errno[0].code.errnum);
|
||||
else
|
||||
verbose_msg("query '%s' failed with wrong sqlstate %s instead of %s...",
|
||||
q->query, mysql_sqlstate(mysql), q->expected_errno[0].code.sqlstate);
|
||||
error= 1;
|
||||
goto end;
|
||||
}
|
||||
verbose_msg("query '%s' failed: %d: %s", q->query, mysql_errno(mysql),
|
||||
mysql_error(mysql));
|
||||
/*
|
||||
if we do not abort on error, failure to run the query does
|
||||
not fail the whole test case
|
||||
*/
|
||||
goto end;
|
||||
}
|
||||
/*{
|
||||
verbose_msg("failed in mysql_store_result for query '%s' (%d)", query,
|
||||
mysql_errno(mysql));
|
||||
error = 1;
|
||||
goto end;
|
||||
}*/
|
||||
}
|
||||
|
||||
if (q->expected_errno[0].type == ERR_ERRNO &&
|
||||
q->expected_errno[0].code.errnum != 0)
|
||||
{
|
||||
/* Error code we wanted was != 0, i.e. not an expected success */
|
||||
verbose_msg("query '%s' succeeded - should have failed with errno %d...",
|
||||
q->query, q->expected_errno[0].code.errnum);
|
||||
error = 1;
|
||||
if (normal_handle_error(query, q, mysql, ds))
|
||||
error= 1;
|
||||
goto end;
|
||||
}
|
||||
else if (q->expected_errno[0].type == ERR_SQLSTATE &&
|
||||
strcmp(q->expected_errno[0].code.sqlstate,"00000") != 0)
|
||||
|
||||
if (normal_handle_no_error(q))
|
||||
{
|
||||
/* SQLSTATE we wanted was != "00000", i.e. not an expected success */
|
||||
verbose_msg("query '%s' succeeded - should have failed with sqlstate %s...",
|
||||
q->query, q->expected_errno[0].code.sqlstate);
|
||||
error = 1;
|
||||
error= 1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
@ -2608,8 +2683,7 @@ static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags)
|
||||
{
|
||||
if (i)
|
||||
dynstr_append_mem(ds, "\t", 1);
|
||||
replace_dynstr_append_mem(ds, field[i].name,
|
||||
strlen(field[i].name));
|
||||
replace_dynstr_append(ds, field[i].name);
|
||||
}
|
||||
dynstr_append_mem(ds, "\n", 1);
|
||||
}
|
||||
@ -2686,6 +2760,135 @@ end:
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Handle errors which occurred after execution of conventional (non-prepared)
|
||||
statement.
|
||||
|
||||
SYNOPSIS
|
||||
normal_handle_error()
|
||||
query - query string
|
||||
q - query context
|
||||
mysql - connection through which query was sent to server
|
||||
ds - dynamic string which is used for output buffer
|
||||
|
||||
NOTE
|
||||
If there is an unexpected error this function will abort mysqltest
|
||||
immediately.
|
||||
|
||||
RETURN VALUE
|
||||
0 - OK
|
||||
1 - Some other error was expected.
|
||||
*/
|
||||
|
||||
static int normal_handle_error(const char *query, struct st_query *q,
|
||||
MYSQL *mysql, DYNAMIC_STRING *ds)
|
||||
{
|
||||
uint i;
|
||||
|
||||
DBUG_ENTER("normal_handle_error");
|
||||
|
||||
if (q->require_file)
|
||||
abort_not_supported_test();
|
||||
|
||||
if (q->abort_on_error)
|
||||
die("At line %u: query '%s' failed: %d: %s", start_lineno, query,
|
||||
mysql_errno(mysql), mysql_error(mysql));
|
||||
else
|
||||
{
|
||||
for (i= 0 ; (uint) i < q->expected_errors ; i++)
|
||||
{
|
||||
if (((q->expected_errno[i].type == ERR_ERRNO) &&
|
||||
(q->expected_errno[i].code.errnum == mysql_errno(mysql))) ||
|
||||
((q->expected_errno[i].type == ERR_SQLSTATE) &&
|
||||
(strcmp(q->expected_errno[i].code.sqlstate, mysql_sqlstate(mysql)) == 0)))
|
||||
{
|
||||
if (q->expected_errors == 1)
|
||||
{
|
||||
/* Only log error if there is one possible error */
|
||||
dynstr_append_mem(ds, "ERROR ", 6);
|
||||
replace_dynstr_append(ds, mysql_sqlstate(mysql));
|
||||
dynstr_append_mem(ds, ": ", 2);
|
||||
replace_dynstr_append(ds, mysql_error(mysql));
|
||||
dynstr_append_mem(ds,"\n",1);
|
||||
}
|
||||
/* Don't log error if we may not get an error */
|
||||
else if (q->expected_errno[0].type == ERR_SQLSTATE ||
|
||||
(q->expected_errno[0].type == ERR_ERRNO &&
|
||||
q->expected_errno[0].code.errnum != 0))
|
||||
dynstr_append(ds,"Got one of the listed errors\n");
|
||||
/* OK */
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
}
|
||||
|
||||
DBUG_PRINT("info",("i: %d expected_errors: %d", i, q->expected_errors));
|
||||
|
||||
dynstr_append_mem(ds, "ERROR ",6);
|
||||
replace_dynstr_append(ds, mysql_sqlstate(mysql));
|
||||
dynstr_append_mem(ds, ": ", 2);
|
||||
replace_dynstr_append(ds, mysql_error(mysql));
|
||||
dynstr_append_mem(ds, "\n", 1);
|
||||
|
||||
if (i)
|
||||
{
|
||||
if (q->expected_errno[0].type == ERR_ERRNO)
|
||||
verbose_msg("query '%s' failed with wrong errno %d instead of %d...",
|
||||
q->query, mysql_errno(mysql),
|
||||
q->expected_errno[0].code.errnum);
|
||||
else
|
||||
verbose_msg("query '%s' failed with wrong sqlstate %s instead of %s...",
|
||||
q->query, mysql_sqlstate(mysql),
|
||||
q->expected_errno[0].code.sqlstate);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
/*
|
||||
If we do not abort on error, failure to run the query does not fail the
|
||||
whole test case.
|
||||
*/
|
||||
verbose_msg("query '%s' failed: %d: %s", q->query, mysql_errno(mysql),
|
||||
mysql_error(mysql));
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Handle absence of errors after execution of convetional statement.
|
||||
|
||||
SYNOPSIS
|
||||
normal_handle_error()
|
||||
q - context of query
|
||||
|
||||
RETURN VALUE
|
||||
0 - OK
|
||||
1 - Some error was expected from this query.
|
||||
*/
|
||||
|
||||
static int normal_handle_no_error(struct st_query *q)
|
||||
{
|
||||
DBUG_ENTER("normal_handle_no_error");
|
||||
|
||||
if (q->expected_errno[0].type == ERR_ERRNO &&
|
||||
q->expected_errno[0].code.errnum != 0)
|
||||
{
|
||||
/* Error code we wanted was != 0, i.e. not an expected success */
|
||||
verbose_msg("query '%s' succeeded - should have failed with errno %d...",
|
||||
q->query, q->expected_errno[0].code.errnum);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
else if (q->expected_errno[0].type == ERR_SQLSTATE &&
|
||||
strcmp(q->expected_errno[0].code.sqlstate,"00000") != 0)
|
||||
{
|
||||
/* SQLSTATE we wanted was != "00000", i.e. not an expected success */
|
||||
verbose_msg("query '%s' succeeded - should have failed with sqlstate %s...",
|
||||
q->query, q->expected_errno[0].code.sqlstate);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
/****************************************************************************\
|
||||
* If --ps-protocol run ordinary statements using prepared statemnt C API
|
||||
\****************************************************************************/
|
||||
@ -2879,8 +3082,7 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags)
|
||||
{
|
||||
if (col_idx)
|
||||
dynstr_append_mem(ds, "\t", 1);
|
||||
replace_dynstr_append_mem(ds, field[col_idx].name,
|
||||
strlen(field[col_idx].name));
|
||||
replace_dynstr_append(ds, field[col_idx].name);
|
||||
}
|
||||
dynstr_append_mem(ds, "\n", 1);
|
||||
}
|
||||
@ -3148,11 +3350,9 @@ static int run_query_stmt_handle_error(char *query, struct st_query *q,
|
||||
{
|
||||
/* Only log error if there is one possible error */
|
||||
dynstr_append_mem(ds,"ERROR ",6);
|
||||
replace_dynstr_append_mem(ds, mysql_stmt_sqlstate(stmt),
|
||||
strlen(mysql_stmt_sqlstate(stmt)));
|
||||
replace_dynstr_append(ds, mysql_stmt_sqlstate(stmt));
|
||||
dynstr_append_mem(ds, ": ", 2);
|
||||
replace_dynstr_append_mem(ds,mysql_stmt_error(stmt),
|
||||
strlen(mysql_stmt_error(stmt)));
|
||||
replace_dynstr_append(ds,mysql_stmt_error(stmt));
|
||||
dynstr_append_mem(ds,"\n",1);
|
||||
}
|
||||
/* Don't log error if we may not get an error */
|
||||
@ -3166,11 +3366,9 @@ static int run_query_stmt_handle_error(char *query, struct st_query *q,
|
||||
DBUG_PRINT("info",("i: %d expected_errors: %d", i,
|
||||
q->expected_errors));
|
||||
dynstr_append_mem(ds, "ERROR ",6);
|
||||
replace_dynstr_append_mem(ds, mysql_stmt_sqlstate(stmt),
|
||||
strlen(mysql_stmt_sqlstate(stmt)));
|
||||
replace_dynstr_append(ds, mysql_stmt_sqlstate(stmt));
|
||||
dynstr_append_mem(ds,": ",2);
|
||||
replace_dynstr_append_mem(ds, mysql_stmt_error(stmt),
|
||||
strlen(mysql_stmt_error(stmt)));
|
||||
replace_dynstr_append(ds, mysql_stmt_error(stmt));
|
||||
dynstr_append_mem(ds,"\n",1);
|
||||
if (i)
|
||||
{
|
||||
@ -3452,7 +3650,9 @@ int main(int argc, char **argv)
|
||||
{
|
||||
processed = 1;
|
||||
switch (q->type) {
|
||||
case Q_CONNECT: do_connect(q); break;
|
||||
case Q_CONNECT:
|
||||
error|= do_connect(q);
|
||||
break;
|
||||
case Q_CONNECTION: select_connection(q->first_argument); break;
|
||||
case Q_DISCONNECT:
|
||||
case Q_DIRTY_CLOSE:
|
||||
|
Reference in New Issue
Block a user