summaryrefslogtreecommitdiff
path: root/client/mysqltest.c
diff options
context:
space:
mode:
Diffstat (limited to 'client/mysqltest.c')
-rw-r--r--client/mysqltest.c414
1 files changed, 307 insertions, 107 deletions
diff --git a/client/mysqltest.c b/client/mysqltest.c
index 8ddcfb90cad..d62cf3c741a 100644
--- a/client/mysqltest.c
+++ b/client/mysqltest.c
@@ -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: