summaryrefslogtreecommitdiff
path: root/client/mysqltest.c
diff options
context:
space:
mode:
Diffstat (limited to 'client/mysqltest.c')
-rw-r--r--client/mysqltest.c1147
1 files changed, 539 insertions, 608 deletions
diff --git a/client/mysqltest.c b/client/mysqltest.c
index 6653d24e575..308bf6f9b79 100644
--- a/client/mysqltest.c
+++ b/client/mysqltest.c
@@ -248,8 +248,6 @@ typedef struct
int read_lines,current_line;
} PARSER;
-MYSQL_RES *last_result=0;
-
PARSER parser;
MASTER_POS master_pos;
/* if set, all results are concated and compared against this file */
@@ -437,7 +435,7 @@ static VAR* var_init(VAR* v, const char *name, int name_len, const char *val,
static void var_free(void* v);
int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname);
-void reject_dump(const char *record_file, char *buf, int size);
+void dump_result_to_reject_file(const char *record_file, char *buf, int size);
int close_connection(struct st_query*);
static void set_charset(struct st_query*);
@@ -464,9 +462,8 @@ void free_replace();
static int insert_pointer_name(reg1 POINTER_ARRAY *pa,my_string name);
void free_pointer_array(POINTER_ARRAY *pa);
static int initialize_replace_buffer(void);
-static void free_replace_buffer(void);
static void do_eval(DYNAMIC_STRING *query_eval, const char *query);
-void str_to_file(const char *fname, char *str, int size);
+static void str_to_file(const char *fname, char *str, int size);
int do_server_op(struct st_query *q,const char *op);
struct st_replace *glob_replace;
@@ -491,10 +488,10 @@ my_bool mysql_rpl_probe(MYSQL *mysql __attribute__((unused))) { return 1; }
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 handle_error(const char *query, struct st_query *q,
- unsigned int err_errno, const char *err_error,
- const char *err_sqlstate, DYNAMIC_STRING *ds);
-static int handle_no_error(struct st_query *q);
+static void handle_error(const char *query, struct st_query *q,
+ unsigned int err_errno, const char *err_error,
+ const char *err_sqlstate, DYNAMIC_STRING *ds);
+static void handle_no_error(struct st_query *q);
static void do_eval(DYNAMIC_STRING* query_eval, const char *query)
{
@@ -541,8 +538,6 @@ static void do_eval(DYNAMIC_STRING* query_eval, const char *query)
static void close_cons()
{
DBUG_ENTER("close_cons");
- if (last_result)
- mysql_free_result(last_result);
for (--next_con; next_con >= cons; --next_con)
{
mysql_close(&next_con->mysql);
@@ -734,7 +729,21 @@ err:
DBUG_RETURN(res);
}
-static int check_result(DYNAMIC_STRING* ds, const char *fname,
+/*
+ Check the content of ds against content of file fname
+
+ SYNOPSIS
+ check_result
+ ds - content to be checked
+ fname - name of file to check against
+ require_option - if set and check fails, the test will be aborted with the special
+ exit code "not supported test"
+
+ RETURN VALUES
+ error - the function will not return
+
+*/
+static void check_result(DYNAMIC_STRING* ds, const char *fname,
my_bool require_option)
{
int res= dyn_string_cmp(ds, fname);
@@ -746,17 +755,18 @@ static int check_result(DYNAMIC_STRING* ds, const char *fname,
case RESULT_OK:
break; /* ok */
case RESULT_LENGTH_MISMATCH:
- verbose_msg("Result length mismatch");
+ dump_result_to_reject_file(fname, ds->str, ds->length);
+ die("Result length mismatch");
break;
case RESULT_CONTENT_MISMATCH:
- verbose_msg("Result content mismatch");
+ dump_result_to_reject_file(fname, ds->str, ds->length);
+ die("Result content mismatch");
break;
default: /* impossible */
die("Unknown error code from dyn_string_cmp()");
}
- if (res != RESULT_OK)
- reject_dump(fname, ds->str, ds->length);
- DBUG_RETURN(res);
+
+ DBUG_VOID_RETURN;
}
@@ -1043,7 +1053,6 @@ static void do_exec(struct st_query *query)
{
int error;
DYNAMIC_STRING *ds= NULL;
- DYNAMIC_STRING ds_tmp;
char buf[1024];
FILE *res_file;
char *cmd= query->first_argument;
@@ -1070,14 +1079,7 @@ static void do_exec(struct st_query *query)
}
else
{
- if (query->record_file[0])
- {
- init_dynamic_string(&ds_tmp, "", 16384, 65536);
- ds= &ds_tmp;
- }
- else
- ds= &ds_res;
-
+ ds= &ds_res;
while (fgets(buf, sizeof(buf), res_file))
replace_dynstr_append(ds, buf);
}
@@ -1118,25 +1120,7 @@ static void do_exec(struct st_query *query)
cmd, query->expected_errno[0].code.errnum);
}
- if (!disable_result_log)
- {
- if (glob_replace)
- free_replace();
-
- if (record)
- {
- if (!query->record_file[0] && !result_file)
- die("Missing result file");
- if (!result_file)
- str_to_file(query->record_file, ds->str, ds->length);
- }
- else if (query->record_file[0])
- {
- error= check_result(ds, query->record_file, query->require_file);
- }
- if (ds == &ds_tmp)
- dynstr_free(&ds_tmp);
- }
+ free_replace();
}
@@ -1354,25 +1338,16 @@ int do_echo(struct st_query *q)
{
char *p= q->first_argument;
DYNAMIC_STRING *ds;
- DYNAMIC_STRING ds_tmp;
VAR v;
var_init(&v,0,0,0,0);
- if (q->record_file[0])
- {
- init_dynamic_string(&ds_tmp, "", 256, 512);
- ds= &ds_tmp;
- }
- else
- ds= &ds_res;
+ ds= &ds_res;
eval_expr(&v, p, 0); /* NULL terminated */
if (v.str_val_len)
dynstr_append_mem(ds, v.str_val, v.str_val_len);
dynstr_append_mem(ds, "\n", 1);
var_free(&v);
- if (ds == &ds_tmp)
- dynstr_free(&ds_tmp);
q->last_argument= q->end;
return 0;
}
@@ -1401,7 +1376,7 @@ wait_for_position:
die("failed in %s: %d: %s", query_buf, mysql_errno(mysql),
mysql_error(mysql));
- if (!(last_result= res= mysql_store_result(mysql)))
+ if (!(res= mysql_store_result(mysql)))
die("mysql_store_result() returned NULL for '%s'", query_buf);
if (!(row= mysql_fetch_row(res)))
die("empty result in %s", query_buf);
@@ -1418,7 +1393,6 @@ wait_for_position:
goto wait_for_position;
}
mysql_free_result(res);
- last_result=0;
if (rpl_parse)
mysql_enable_rpl_parse(mysql);
@@ -1457,13 +1431,13 @@ int do_save_master_pos()
die("failed in show master status: %d: %s",
mysql_errno(mysql), mysql_error(mysql));
- if (!(last_result =res = mysql_store_result(mysql)))
+ if (!(res = mysql_store_result(mysql)))
die("mysql_store_result() retuned NULL for '%s'", query);
if (!(row = mysql_fetch_row(res)))
die("empty result in show master status");
strnmov(master_pos.file, row[0], sizeof(master_pos.file)-1);
master_pos.pos = strtoul(row[1], (char**) 0, 10);
- mysql_free_result(res); last_result=0;
+ mysql_free_result(res);
if (rpl_parse)
mysql_enable_rpl_parse(mysql);
@@ -1832,7 +1806,7 @@ void free_replace()
{
my_free((char*) glob_replace,MYF(0));
glob_replace=0;
- free_replace_buffer();
+ my_free(out_buff,MYF(MY_WME));
}
DBUG_VOID_RETURN;
}
@@ -2029,21 +2003,11 @@ int connect_n_handle_errors(struct st_query *q, MYSQL* con, const char* host,
const char* db, int port, const char* sock,
int* create_conn)
{
- DYNAMIC_STRING ds_tmp, *ds;
+ DYNAMIC_STRING *ds;
my_bool reconnect= 1;
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;
+ ds= &ds_res;
if (!disable_query_log)
{
@@ -2076,13 +2040,15 @@ int connect_n_handle_errors(struct st_query *q, MYSQL* con, const char* host,
if (!mysql_real_connect(con, host, user, pass, db, port, sock ? sock: 0,
CLIENT_MULTI_STATEMENTS))
{
- error= handle_error("connect", q, mysql_errno(con), mysql_error(con),
- mysql_sqlstate(con), ds);
+ handle_error("connect", q, mysql_errno(con), mysql_error(con),
+ mysql_sqlstate(con), ds);
*create_conn= 0;
goto err;
}
- else if (handle_no_error(q))
+ else
{
+ 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.
@@ -2099,20 +2065,8 @@ int connect_n_handle_errors(struct st_query *q, MYSQL* con, const char* host,
*/
mysql_options(con, MYSQL_OPT_RECONNECT, (char *)&reconnect);
- if (record)
- {
- if (!q->record_file[0] && !result_file)
- die("Missing result file");
- 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;
}
@@ -2470,7 +2424,7 @@ int read_line(char *buf, int size)
state= R_Q;
}
else
- state= R_NORMAL;
+state= R_NORMAL;
break;
case R_Q:
@@ -2559,7 +2513,7 @@ static char read_query_buf[MAX_QUERY];
int read_query(struct st_query** q_ptr)
{
- char *p= read_query_buf, *p1;
+ char *p= read_query_buf;
struct st_query* q;
DBUG_ENTER("read_query");
@@ -2578,10 +2532,13 @@ int read_query(struct st_query** q_ptr)
q->type= Q_UNKNOWN;
q->query_buf= q->query= 0;
+ read_query_buf[0]= 0;
if (read_line(read_query_buf, sizeof(read_query_buf)))
{
+ check_eol_junk(read_query_buf);
DBUG_RETURN(1);
}
+
DBUG_PRINT("info", ("query: %s", read_query_buf));
if (*p == '#')
{
@@ -2606,15 +2563,6 @@ int read_query(struct st_query** q_ptr)
{
while (*p && my_isspace(charset_info, *p))
p++ ;
- if (*p == '@')
- {
- p++;
- p1 = q->record_file;
- while (!my_isspace(charset_info, *p) &&
- p1 < q->record_file + sizeof(q->record_file) - 1)
- *p1++ = *p++;
- *p1 = 0;
- }
}
end:
@@ -2862,7 +2810,17 @@ char* safe_str_append(char *buf, const char *str, int size)
return buf;
}
-void str_to_file(const char *fname, char *str, int size)
+
+/*
+ Write the content of str into file
+
+ SYNOPSIS
+ str_to_file
+ fname - name of file to truncate/create and write to
+ str - content to write to file
+ size - size of content witten to file
+*/
+static void str_to_file(const char *fname, char *str, int size)
{
int fd;
char buff[FN_REFLEN];
@@ -2881,7 +2839,7 @@ void str_to_file(const char *fname, char *str, int size)
my_close(fd, MYF(0));
}
-void reject_dump(const char *record_file, char *buf, int size)
+void dump_result_to_reject_file(const char *record_file, char *buf, int size)
{
char reject_file[FN_REFLEN];
str_to_file(fn_format(reject_file, record_file,"",".reject",2), buf, size);
@@ -2921,7 +2879,7 @@ static void append_result(DYNAMIC_STRING *ds, MYSQL_RES *res)
MYSQL_ROW row;
uint num_fields= mysql_num_fields(res);
MYSQL_FIELD *fields= !display_result_vertically ? 0 : mysql_fetch_fields(res);
- unsigned long *lengths;
+ ulong *lengths;
while ((row = mysql_fetch_row(res)))
{
uint i;
@@ -2963,100 +2921,305 @@ static void append_result(DYNAMIC_STRING *ds, MYSQL_RES *res)
/*
-* flags control the phased/stages of query execution to be performed
-* if QUERY_SEND bit is on, the query will be sent. If QUERY_REAP is on
-* the result will be read - for regular query, both bits must be on
+ Append all results from ps execution to the dynamic string separated
+ with '\t'. Values may be converted with 'replace_column'
*/
-static int run_query_normal(MYSQL *mysql, struct st_query *q, int flags);
-static int run_query_stmt (MYSQL *mysql, struct st_query *q, int flags);
-static void run_query_stmt_handle_warnings(MYSQL *mysql, DYNAMIC_STRING *ds);
-static void run_query_display_metadata(MYSQL_FIELD *field, uint num_fields,
- DYNAMIC_STRING *ds);
-
-static int run_query(MYSQL *mysql, struct st_query *q, int flags)
+static void append_stmt_result(DYNAMIC_STRING *ds, MYSQL_STMT* stmt,
+ MYSQL_FIELD* field, uint num_fields)
{
+ MYSQL_BIND *bind;
+ my_bool *is_null;
+ ulong *length;
+ ulonglong num_rows;
- /*
- Try to find out if we can run this statement using the prepared
- statement protocol.
+ /* FIXME we don't handle vertical display ..... */
+ uint col_idx, row_idx;
+
+ /* Allocate array with bind structs, lengths and NULL flags */
+ bind= (MYSQL_BIND*) my_malloc(num_fields * sizeof(MYSQL_BIND),
+ MYF(MY_WME | MY_FAE | MY_ZEROFILL));
+ length= (ulong*) my_malloc(num_fields * sizeof(ulong),
+ MYF(MY_WME | MY_FAE));
+ is_null= (my_bool*) my_malloc(num_fields * sizeof(my_bool),
+ MYF(MY_WME | MY_FAE));
+
+ for (col_idx= 0; col_idx < num_fields; col_idx++)
+ {
+ /* Allocate data for output */
+ /*
+ FIXME it may be a bug that for non string/blob types
+ 'max_length' is 0, should try out 'length' in that case
+ */
+ uint max_length= max(field[col_idx].max_length + 1, 1024);
+ char *str_data= (char *) my_malloc(max_length, MYF(MY_WME | MY_FAE));
+
+ bind[col_idx].buffer_type= MYSQL_TYPE_STRING;
+ bind[col_idx].buffer= (char *)str_data;
+ bind[col_idx].buffer_length= max_length;
+ bind[col_idx].is_null= &is_null[col_idx];
+ bind[col_idx].length= &length[col_idx];
+ }
+
+ /* Fill in the data into the structures created above */
+ if (mysql_stmt_bind_result(stmt, bind))
+ die("mysql_stmt_bind_result failed: %d: %s",
+ mysql_stmt_errno(stmt), mysql_stmt_error(stmt));
+
+ /* Read result from each row */
+ num_rows= mysql_stmt_num_rows(stmt);
+ for (row_idx= 0; row_idx < num_rows; row_idx++)
+ {
+ if (mysql_stmt_fetch(stmt))
+ die("mysql_stmt_fetch failed: %d %s",
+ mysql_stmt_errno(stmt), mysql_stmt_error(stmt));
+
+ /* Read result from each column */
+ for (col_idx= 0; col_idx < num_fields; col_idx++)
+ {
+ /* FIXME is string terminated? */
+ const char *val= (const char *)bind[col_idx].buffer;
+ ulonglong len= *bind[col_idx].length;
+ if (col_idx < max_replace_column && replace_column[col_idx])
+ {
+ val= replace_column[col_idx];
+ len= strlen(val);
+ }
+ if (*bind[col_idx].is_null)
+ {
+ val= "NULL";
+ len= 4;
+ }
+ if (!display_result_vertically)
+ {
+ if (col_idx) /* No tab before first col */
+ dynstr_append_mem(ds, "\t", 1);
+ replace_dynstr_append_mem(ds, val, (int)len);
+ }
+ else
+ {
+ dynstr_append(ds, field[col_idx].name);
+ dynstr_append_mem(ds, "\t", 1);
+ replace_dynstr_append_mem(ds, val, (int)len);
+ dynstr_append_mem(ds, "\n", 1);
+ }
+ }
+ if (!display_result_vertically)
+ dynstr_append_mem(ds, "\n", 1);
+ }
+
+ if (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
+ die("fetch didn't end with MYSQL_NO_DATA from statement: %d %s",
+ mysql_stmt_error(stmt), mysql_stmt_errno(stmt));
+
+ free_replace_column();
+
+ for (col_idx= 0; col_idx < num_fields; col_idx++)
+ {
+ /* Free data for output */
+ my_free((gptr)bind[col_idx].buffer, MYF(MY_WME | MY_FAE));
+ }
+ /* Free array with bind structs, lengths and NULL flags */
+ my_free((gptr)bind , MYF(MY_WME | MY_FAE));
+ my_free((gptr)length , MYF(MY_WME | MY_FAE));
+ my_free((gptr)is_null , MYF(MY_WME | MY_FAE));
+}
- We don't have a mysql_stmt_send_execute() so we only handle
- complete SEND+REAP.
- If it is a '?' in the query it may be a SQL level prepared
- statement already and we can't do it twice
- */
+/*
+ Append metadata for fields to output
+*/
+
+static void append_metadata(DYNAMIC_STRING *ds,
+ MYSQL_FIELD *field,
+ uint num_fields)
+{
+ MYSQL_FIELD *field_end;
+ dynstr_append(ds,"Catalog\tDatabase\tTable\tTable_alias\tColumn\t"
+ "Column_alias\tType\tLength\tMax length\tIs_null\t"
+ "Flags\tDecimals\tCharsetnr\n");
+
+ for (field_end= field+num_fields ;
+ field < field_end ;
+ field++)
+ {
+ char buff[22];
+ dynstr_append_mem(ds, field->catalog,
+ field->catalog_length);
+ dynstr_append_mem(ds, "\t", 1);
+ dynstr_append_mem(ds, field->db, field->db_length);
+ dynstr_append_mem(ds, "\t", 1);
+ dynstr_append_mem(ds, field->org_table,
+ field->org_table_length);
+ dynstr_append_mem(ds, "\t", 1);
+ dynstr_append_mem(ds, field->table,
+ field->table_length);
+ dynstr_append_mem(ds, "\t", 1);
+ dynstr_append_mem(ds, field->org_name,
+ field->org_name_length);
+ dynstr_append_mem(ds, "\t", 1);
+ dynstr_append_mem(ds, field->name, field->name_length);
+ dynstr_append_mem(ds, "\t", 1);
+ int10_to_str((int) field->type, buff, 10);
+ dynstr_append(ds, buff);
+ dynstr_append_mem(ds, "\t", 1);
+ longlong10_to_str((unsigned int) field->length, buff, 10);
+ dynstr_append(ds, buff);
+ dynstr_append_mem(ds, "\t", 1);
+ longlong10_to_str((unsigned int) field->max_length, buff, 10);
+ dynstr_append(ds, buff);
+ dynstr_append_mem(ds, "\t", 1);
+ dynstr_append_mem(ds, (char*) (IS_NOT_NULL(field->flags) ?
+ "N" : "Y"), 1);
+ dynstr_append_mem(ds, "\t", 1);
- if (ps_protocol_enabled && disable_info &&
- (flags & QUERY_SEND) && (flags & QUERY_REAP) && ps_match_re(q->query))
- return run_query_stmt(mysql, q, flags);
- return run_query_normal(mysql, q, flags);
+ int10_to_str((int) field->flags, buff, 10);
+ dynstr_append(ds, buff);
+ dynstr_append_mem(ds, "\t", 1);
+ int10_to_str((int) field->decimals, buff, 10);
+ dynstr_append(ds, buff);
+ dynstr_append_mem(ds, "\t", 1);
+ int10_to_str((int) field->charsetnr, buff, 10);
+ dynstr_append(ds, buff);
+ dynstr_append_mem(ds, "\n", 1);
+ }
}
+/*
+ Append affected row count and other info to output
+*/
-static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags)
+static void append_info(DYNAMIC_STRING* ds, ulong affected_rows,
+ const char* info)
{
- MYSQL_RES* res= 0;
- uint i;
- int error= 0, err= 0, counter= 0;
- DYNAMIC_STRING *ds;
- DYNAMIC_STRING ds_tmp;
- DYNAMIC_STRING eval_query;
- char* query;
- int query_len, got_error_on_send= 0;
- DBUG_ENTER("run_query_normal");
- DBUG_PRINT("enter",("flags: %d", flags));
-
- if (q->type != Q_EVAL)
- {
- query = q->query;
- query_len = strlen(query);
- }
- else
+ char buf[40];
+ sprintf(buf,"affected rows: %lu\n", affected_rows);
+ dynstr_append(ds, buf);
+ if (info)
{
- init_dynamic_string(&eval_query, "", 16384, 65536);
- do_eval(&eval_query, q->query);
- query = eval_query.str;
- query_len = eval_query.length;
+ dynstr_append(ds, "info: ");
+ dynstr_append(ds, info);
+ dynstr_append_mem(ds, "\n", 1);
}
- DBUG_PRINT("enter", ("query: '%-.60s'", query));
+}
+
- if (q->record_file[0])
+/*
+ Display the table headings with the names tab separated
+*/
+static void append_table_headings(DYNAMIC_STRING* ds,
+ MYSQL_FIELD* field,
+ uint num_fields)
+{
+ uint col_idx;
+ for (col_idx= 0; col_idx < num_fields; col_idx++)
{
- init_dynamic_string(&ds_tmp, "", 16384, 65536);
- ds = &ds_tmp;
+ if (col_idx)
+ dynstr_append_mem(ds, "\t", 1);
+ replace_dynstr_append(ds, field[col_idx].name);
}
- else
- ds= &ds_res;
+ dynstr_append_mem(ds, "\n", 1);
+}
+
+/*
+ Fetch warnings from server and append to output
+*/
+
+static void append_warnings(DYNAMIC_STRING *ds, MYSQL* mysql)
+{
+ uint count;
+ DBUG_ENTER("append_warnings");
+
+ if (!(count= mysql_warning_count(mysql)))
+ DBUG_VOID_RETURN;
+
+ /*
+ If one day we will support execution of multi-statements
+ through PS API we should not issue SHOW WARNINGS until
+ we have not read all results...
+ */
+ DBUG_ASSERT(!mysql_more_results(mysql));
+
+ if (mysql_real_query(mysql, "SHOW WARNINGS", 13))
+ die("Error running query \"SHOW WARNINGS\": %s", mysql_error(mysql));
+
+ MYSQL_RES *warn_res= mysql_store_result(mysql);
+ if (!warn_res)
+ die("Warning count is %u but didn't get any warnings",
+ count);
+
+
+ dynstr_append_mem(ds, "Warnings:\n", 10);
+ append_result(ds, warn_res);
+ mysql_free_result(warn_res);
+
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Run query using MySQL C API
+
+ SYNPOSIS
+ run_query_normal
+ mysql - mysql handle
+ command - currrent command pointer
+ query - query string to execute
+ query_len - length query string to execute
+ ds - output buffer wherte to store result form query
+
+ RETURN VALUE
+ error - function will not return
+*/
+
+static void run_query_normal(MYSQL *mysql, struct st_query *command,
+ int flags, char *query, int query_len,
+ DYNAMIC_STRING *ds)
+{
+ MYSQL_RES *res= 0;
+ int err= 0, counter= 0;
+ DBUG_ENTER("run_query_normal");
+ DBUG_PRINT("enter",("flags: %d", flags));
+ DBUG_PRINT("enter", ("query: '%-.60s'", query));
if (flags & QUERY_SEND)
{
- got_error_on_send= mysql_send_query(mysql, query, query_len);
- if (got_error_on_send && q->expected_errno[0].type == ERR_EMPTY)
- die("unable to send query '%s' (mysql_errno=%d , errno=%d)",
- query, mysql_errno(mysql), errno);
+ /*
+ Send the query, using the undocumented function mysql_send_query
+ */
+ if (mysql_send_query(mysql, query, query_len))
+ {
+ handle_error(query, command, mysql_errno(mysql), mysql_error(mysql),
+ mysql_sqlstate(mysql), ds);
+ goto end;
+ }
}
+ if (!(flags & QUERY_REAP))
+ DBUG_VOID_RETURN;
+
do
{
- if ((flags & QUERY_SEND) && !disable_query_log && !counter)
+ /*
+ When on first result set, call mysql_read_query_result to retrrieve
+ answer to the query sent earlier
+ */
+ if ((counter==0) && mysql_read_query_result(mysql))
{
- replace_dynstr_append_mem(ds,query, query_len);
- dynstr_append_mem(ds, delimiter, delimiter_length);
- dynstr_append_mem(ds, "\n", 1);
+ handle_error(query, command, mysql_errno(mysql), mysql_error(mysql),
+ mysql_sqlstate(mysql), ds);
+ goto end;
+
}
- if (!(flags & QUERY_REAP))
- DBUG_RETURN(0);
- if (got_error_on_send ||
- (!counter && (*mysql->methods->read_query_result)(mysql)) ||
- (!(last_result= res= mysql_store_result(mysql)) &&
- mysql_field_count(mysql)))
+ /*
+ Store the result. If res is NULL, use mysql_field_count to
+ determine if that was expected
+ */
+ if (!(res= mysql_store_result(mysql)) && mysql_field_count(mysql))
{
- if (handle_error(query, q, mysql_errno(mysql), mysql_error(mysql),
- mysql_sqlstate(mysql), ds))
- error= 1;
+ handle_error(query, command, mysql_errno(mysql), mysql_error(mysql),
+ mysql_sqlstate(mysql), ds);
goto end;
}
@@ -3067,27 +3230,20 @@ static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags)
if (res)
{
- MYSQL_FIELD *field= mysql_fetch_fields(res);
+ MYSQL_FIELD *fields= mysql_fetch_fields(res);
uint num_fields= mysql_num_fields(res);
if (display_metadata)
- run_query_display_metadata(field, num_fields, ds);
+ append_metadata(ds, fields, num_fields);
if (!display_result_vertically)
- {
- for (i = 0; i < num_fields; i++)
- {
- if (i)
- dynstr_append_mem(ds, "\t", 1);
- replace_dynstr_append(ds, field[i].name);
- }
- dynstr_append_mem(ds, "\n", 1);
- }
+ append_table_headings(ds, fields, num_fields);
+
append_result(ds, res);
}
/*
- Need to call mysql_affected_rows() before the new
+ Need to call mysql_affected_rows() before the "new"
query to find the warnings
*/
if (!disable_info)
@@ -3098,75 +3254,31 @@ static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags)
the middle of processing results from multi-statement, because
this will break protocol.
*/
- if (!disable_warnings && !mysql_more_results(mysql) &&
- mysql_warning_count(mysql))
- {
- MYSQL_RES *warn_res=0;
- uint count= mysql_warning_count(mysql);
- if (!mysql_real_query(mysql, "SHOW WARNINGS", 13))
- warn_res= mysql_store_result(mysql);
- if (!warn_res)
- die("Warning count is %u but didn't get any warnings", count);
- else
- {
- dynstr_append_mem(ds, "Warnings:\n", 10);
- append_result(ds, warn_res);
- mysql_free_result(warn_res);
- }
- }
+ if (!disable_warnings && !mysql_more_results(mysql))
+ append_warnings(ds, mysql);
+
if (!disable_info)
- {
- char buf[40];
- sprintf(buf,"affected rows: %lu\n", affected_rows);
- dynstr_append(ds, buf);
- if (mysql_info(mysql))
- {
- dynstr_append(ds, "info: ");
- dynstr_append(ds, mysql_info(mysql));
- dynstr_append_mem(ds, "\n", 1);
- }
- }
+ append_info(ds, affected_rows, mysql_info(mysql));
}
- if (record)
- {
- if (!q->record_file[0] && !result_file)
- die("Missing result file");
- 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);
- }
if (res)
mysql_free_result(res);
- last_result= 0;
counter++;
} while (!(err= mysql_next_result(mysql)));
if (err > 0)
{
- /* We got an error from mysql_next_result, maybe expected */
- if (handle_error(query, q, mysql_errno(mysql), mysql_error(mysql),
- mysql_sqlstate(mysql), ds))
- error= 1;
+ /* We got an error from mysql_next_result, maybe expected */
+ handle_error(query, command, mysql_errno(mysql), mysql_error(mysql),
+ mysql_sqlstate(mysql), ds);
goto end;
}
-
+ DBUG_ASSERT(err == -1); /* Successful and there are no more results */
+
/* If we come here the query is both executed and read successfully */
- if (handle_no_error(q))
- {
- error= 1;
- goto end;
- }
+ handle_no_error(command);
end:
free_replace();
- last_result=0;
- if (ds == &ds_tmp)
- dynstr_free(&ds_tmp);
- if (q->type == Q_EVAL)
- dynstr_free(&eval_query);
/*
We save the return code (mysql_errno(mysql)) from the last call sent
@@ -3174,12 +3286,12 @@ end:
variable then can be used from the test case itself.
*/
var_set_errno(mysql_errno(mysql));
- DBUG_RETURN(error);
+ DBUG_VOID_RETURN;
}
/*
- Handle errors which occurred after execution
+ Handle errors which occurred during execution
SYNOPSIS
handle_error()
@@ -3195,13 +3307,12 @@ end:
immediately.
RETURN VALUE
- 0 - OK
- 1 - Some other error was expected.
+ error - function will not return
*/
-static int handle_error(const char *query, struct st_query *q,
- unsigned int err_errno, const char *err_error,
- const char* err_sqlstate, DYNAMIC_STRING *ds)
+static void handle_error(const char *query, struct st_query *q,
+ unsigned int err_errno, const char *err_error,
+ const char *err_sqlstate, DYNAMIC_STRING *ds)
{
uint i;
@@ -3235,7 +3346,7 @@ static int handle_error(const char *query, struct st_query *q,
q->expected_errno[0].code.errnum != 0))
dynstr_append(ds,"Got one of the listed errors\n");
/* OK */
- DBUG_RETURN(0);
+ DBUG_VOID_RETURN;
}
}
@@ -3255,7 +3366,6 @@ static int handle_error(const char *query, struct st_query *q,
else
die("query '%s' failed with wrong sqlstate %s instead of %s...",
q->query, err_sqlstate, q->expected_errno[0].code.sqlstate);
- DBUG_RETURN(1);
}
/*
@@ -3264,7 +3374,7 @@ static int handle_error(const char *query, struct st_query *q,
*/
verbose_msg("query '%s' failed: %d: %s", q->query, err_errno,
err_error);
- DBUG_RETURN(0);
+ DBUG_VOID_RETURN;
}
@@ -3276,11 +3386,10 @@ static int handle_error(const char *query, struct st_query *q,
q - context of query
RETURN VALUE
- 0 - OK
- 1 - Some error was expected from this query.
+ error - function will not return
*/
-static int handle_no_error(struct st_query *q)
+static void handle_no_error(struct st_query *q)
{
DBUG_ENTER("handle_no_error");
@@ -3290,7 +3399,6 @@ static int handle_no_error(struct st_query *q)
/* Error code we wanted was != 0, i.e. not an expected success */
die("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)
@@ -3298,111 +3406,66 @@ static int handle_no_error(struct st_query *q)
/* SQLSTATE we wanted was != "00000", i.e. not an expected success */
die("query '%s' succeeded - should have failed with sqlstate %s...",
q->query, q->expected_errno[0].code.sqlstate);
- DBUG_RETURN(1);
}
- DBUG_RETURN(0);
+ DBUG_VOID_RETURN;
}
-/****************************************************************************\
- * If --ps-protocol run ordinary statements using prepared statemnt C API
-\****************************************************************************/
/*
- We don't have a mysql_stmt_send_execute() so we only handle
- complete SEND+REAP
+ Run query using prepared statement C API
+
+ SYNPOSIS
+ run_query_stmt
+ mysql - mysql handle
+ command - currrent command pointer
+ query - query string to execute
+ query_len - length query string to execute
+ ds - output buffer wherte to store result form query
+
+ RETURN VALUE
+ error - function will not return
*/
-static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags)
+static void run_query_stmt(MYSQL *mysql, struct st_query *command,
+ char *query, int query_len, DYNAMIC_STRING *ds)
{
- int error= 0; /* Function return code if "goto end;" */
- int err; /* Temporary storage of return code from calls */
- int query_len;
- ulonglong num_rows;
- char *query;
MYSQL_RES *res= NULL; /* Note that here 'res' is meta data result set */
- DYNAMIC_STRING *ds;
- DYNAMIC_STRING ds_tmp;
- DYNAMIC_STRING eval_query;
MYSQL_STMT *stmt;
DBUG_ENTER("run_query_stmt");
+ DBUG_PRINT("query", ("'%-.60s'", query));
/*
- We must allocate a new stmt for each query in this program becasue this
+ We must allocate a new stmt for each query in this program because this
may be a new connection.
+
+ Well, it could be stored togeter with mysql pointer in cur_con struct
*/
if (!(stmt= mysql_stmt_init(mysql)))
- die("unable init stmt structure");
-
- if (q->type != Q_EVAL)
- {
- query= q->query;
- query_len= strlen(query);
- }
- else
- {
- init_dynamic_string(&eval_query, "", 16384, 65536);
- do_eval(&eval_query, q->query);
- query= eval_query.str;
- query_len= eval_query.length;
- }
- DBUG_PRINT("query", ("'%-.60s'", query));
-
- if (q->record_file[0])
- {
- init_dynamic_string(&ds_tmp, "", 16384, 65536);
- ds= &ds_tmp;
- }
- else
- ds= &ds_res;
-
- /* Store the query into the output buffer if not disabled */
- if (!disable_query_log)
- {
- replace_dynstr_append_mem(ds,query, query_len);
- dynstr_append_mem(ds, delimiter, delimiter_length);
- dynstr_append_mem(ds, "\n", 1);
- }
+ die("unable to init stmt structure");
/*
- We use the prepared statement interface but there is actually no
- '?' in the query. If unpreparable we fall back to use normal
- C API.
+ Prepare the query
*/
- if ((err= mysql_stmt_prepare(stmt, query, query_len)) == CR_NO_PREPARE_STMT)
- return run_query_normal(mysql, q, flags);
-
- if (err != 0)
+ if (mysql_stmt_prepare(stmt, query, query_len))
{
- /*
- Preparing is part of normal execution and some errors may be expected
- */
- if (handle_error(query, q, mysql_stmt_errno(stmt),
- mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds))
- error= 1;
+ handle_error(query, command, mysql_stmt_errno(stmt),
+ mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds);
goto end;
}
- /* We may have got warnings already, collect them if any */
- if (!disable_ps_warnings)
- run_query_stmt_handle_warnings(mysql, ds);
-
/*
No need to call mysql_stmt_bind_param() because we have no
parameter markers.
-
- To optimize performance we use a global 'stmt' that is initiated
- once. A new prepare will implicitely close the old one. When we
- terminate we will lose the connection, this also closes the last
- prepared statement.
*/
- if (mysql_stmt_execute(stmt) != 0) /* 0 == Success */
+ /*
+ Execute the query
+ */
+ if (mysql_stmt_execute(stmt))
{
- /* We got an error, maybe expected */
- if (handle_error(query, q, mysql_stmt_errno(stmt),
- mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds))
- error= 1;
+ handle_error(query, command, mysql_stmt_errno(stmt),
+ mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds);
goto end;
}
@@ -3413,33 +3476,24 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags)
*/
{
my_bool one= 1;
- if ((err= mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH,
- (void*) &one)) != 0)
- die("unable to set stmt attribute "
- "'STMT_ATTR_UPDATE_MAX_LENGTH' err: %d", err);
+ if (mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (void*) &one))
+ die("mysql_stmt_attr_set failed': %d %s",
+ mysql_stmt_errno(stmt), mysql_stmt_error(stmt));
}
/*
If we got here the statement succeeded and was expected to do so,
get data. Note that this can still give errors found during execution!
*/
- if ((err= mysql_stmt_store_result(stmt)) != 0)
+ if (mysql_stmt_store_result(stmt))
{
- /* We got an error, maybe expected */
- if(handle_error(query, q, mysql_stmt_errno(stmt),
- mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds))
- error = 1;
+ handle_error(query, command, mysql_stmt_errno(stmt),
+ mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds);
goto end;
}
/* If we got here the statement was both executed and read succeesfully */
- if (handle_no_error(q))
- {
- error= 1;
- goto end;
- }
-
- num_rows= mysql_stmt_num_rows(stmt);
+ handle_no_error(command);
/*
Not all statements creates a result set. If there is one we can
@@ -3447,265 +3501,145 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags)
data. This set can be handled almost like any other non prepared
statement result set.
*/
- if (!disable_result_log && ((res= mysql_stmt_result_metadata(stmt)) != NULL))
+ if (!disable_result_log)
{
- /* Take the column count from meta info */
- MYSQL_FIELD *field= mysql_fetch_fields(res);
- uint num_fields= mysql_num_fields(res);
-
- if (display_metadata)
- run_query_display_metadata(field, num_fields, ds);
-
- if (!display_result_vertically)
- {
- /* Display the table heading with the names tab separated */
- uint col_idx;
- for (col_idx= 0; col_idx < num_fields; col_idx++)
- {
- if (col_idx)
- dynstr_append_mem(ds, "\t", 1);
- replace_dynstr_append(ds, field[col_idx].name);
- }
- dynstr_append_mem(ds, "\n", 1);
- }
-
- /* Now we are to put the real result into the output buffer */
- /* FIXME when it works, create function append_stmt_result() */
+ if ((res= mysql_stmt_result_metadata(stmt)) != NULL)
{
- MYSQL_BIND *bind;
- my_bool *is_null;
- unsigned long *length;
- /* FIXME we don't handle vertical display ..... */
- uint col_idx, row_idx;
-
- /* Allocate array with bind structs, lengths and NULL flags */
- bind= (MYSQL_BIND*) my_malloc(num_fields * sizeof(MYSQL_BIND),
- MYF(MY_WME | MY_FAE | MY_ZEROFILL));
- length= (unsigned long*) my_malloc(num_fields * sizeof(unsigned long),
- MYF(MY_WME | MY_FAE));
- is_null= (my_bool*) my_malloc(num_fields * sizeof(my_bool),
- MYF(MY_WME | MY_FAE));
-
- for (col_idx= 0; col_idx < num_fields; col_idx++)
- {
- /* Allocate data for output */
- /*
- FIXME it may be a bug that for non string/blob types
- 'max_length' is 0, should try out 'length' in that case
- */
- uint max_length= max(field[col_idx].max_length + 1, 1024);
- char *str_data= (char *) my_malloc(max_length, MYF(MY_WME | MY_FAE));
-
- bind[col_idx].buffer_type= MYSQL_TYPE_STRING;
- bind[col_idx].buffer= (char *)str_data;
- bind[col_idx].buffer_length= max_length;
- bind[col_idx].is_null= &is_null[col_idx];
- bind[col_idx].length= &length[col_idx];
- }
-
- /* Fill in the data into the structures created above */
- if ((err= mysql_stmt_bind_result(stmt, bind)) != 0)
- die("unable to bind result to statement '%s': "
- "%s (mysql_stmt_errno=%d returned=%d)",
- query,
- mysql_stmt_error(stmt), mysql_stmt_errno(stmt), err);
-
- /* Read result from each row */
- for (row_idx= 0; row_idx < num_rows; row_idx++)
- {
- if ((err= mysql_stmt_fetch(stmt)) != 0)
- die("unable to fetch all rows from statement '%s': "
- "%s (mysql_stmt_errno=%d returned=%d)",
- query,
- mysql_stmt_error(stmt), mysql_stmt_errno(stmt), err);
-
- /* Read result from each column */
- for (col_idx= 0; col_idx < num_fields; col_idx++)
- {
- /* FIXME is string terminated? */
- const char *val= (const char *)bind[col_idx].buffer;
- ulonglong len= *bind[col_idx].length;
- if (col_idx < max_replace_column && replace_column[col_idx])
- {
- val= replace_column[col_idx];
- len= strlen(val);
- }
- if (*bind[col_idx].is_null)
- {
- val= "NULL";
- len= 4;
- }
- if (!display_result_vertically)
- {
- if (col_idx) /* No tab before first col */
- dynstr_append_mem(ds, "\t", 1);
- replace_dynstr_append_mem(ds, val, (int)len);
- }
- else
- {
- dynstr_append(ds, field[col_idx].name);
- dynstr_append_mem(ds, "\t", 1);
- replace_dynstr_append_mem(ds, val, (int)len);
- dynstr_append_mem(ds, "\n", 1);
- }
- }
- if (!display_result_vertically)
- dynstr_append_mem(ds, "\n", 1);
- }
-
- if ((err= mysql_stmt_fetch(stmt)) != MYSQL_NO_DATA)
- die("fetch didn't end with MYSQL_NO_DATA from statement "
- "'%s': %s (mysql_stmt_errno=%d returned=%d)",
- query,
- mysql_stmt_error(stmt), mysql_stmt_errno(stmt), err);
-
- free_replace_column();
-
- for (col_idx= 0; col_idx < num_fields; col_idx++)
- {
- /* Free data for output */
- my_free((gptr)bind[col_idx].buffer, MYF(MY_WME | MY_FAE));
- }
- /* Free array with bind structs, lengths and NULL flags */
- my_free((gptr)bind , MYF(MY_WME | MY_FAE));
- my_free((gptr)length , MYF(MY_WME | MY_FAE));
- my_free((gptr)is_null , MYF(MY_WME | MY_FAE));
+ /* Take the column count from meta info */
+ MYSQL_FIELD *fields= mysql_fetch_fields(res);
+ uint num_fields= mysql_num_fields(res);
+
+ if (display_metadata)
+ append_metadata(ds, fields, num_fields);
+
+ if (!display_result_vertically)
+ append_table_headings(ds, fields, num_fields);
+
+ append_stmt_result(ds, stmt, fields, num_fields);
+
+ mysql_free_result(res); /* Free normal result set with meta data */
+
}
- /* Add all warnings to the result */
- run_query_stmt_handle_warnings(mysql, ds);
-
+ if (!disable_warnings)
+ append_warnings(ds, mysql);
+
if (!disable_info)
- {
- char buf[40];
- sprintf(buf,"affected rows: %lu\n",(ulong) mysql_affected_rows(mysql));
- dynstr_append(ds, buf);
- if (mysql_info(mysql))
- {
- dynstr_append(ds, "info: ");
- dynstr_append(ds, mysql_info(mysql));
- dynstr_append_mem(ds, "\n", 1);
- }
- }
+ append_info(ds, (ulong)mysql_affected_rows(mysql), mysql_info(mysql));
}
- run_query_stmt_handle_warnings(mysql, ds);
-
- if (record)
- {
- if (!q->record_file[0] && !result_file)
- die("Missing result file");
- 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);
- }
- if (res)
- mysql_free_result(res); /* Free normal result set with meta data */
- last_result= 0; /* FIXME have no idea what this is about... */
end:
free_replace();
- last_result=0;
- if (ds == &ds_tmp)
- dynstr_free(&ds_tmp);
- if (q->type == Q_EVAL)
- dynstr_free(&eval_query);
+ /*
+ We save the return code (mysql_stmt_errno(stmt)) from the last call sent
+ to the server into the mysqltest builtin variable $mysql_errno. This
+ variable then can be used from the test case itself.
+ */
var_set_errno(mysql_stmt_errno(stmt));
mysql_stmt_close(stmt);
- DBUG_RETURN(error);
+ DBUG_VOID_RETURN;
}
-/****************************************************************************\
- * Broken out sub functions to run_query_stmt()
-\****************************************************************************/
+/*
+
+ Run query
+
+ flags control the phased/stages of query execution to be performed
+ if QUERY_SEND bit is on, the query will be sent. If QUERY_REAP is on
+ the result will be read - for regular query, both bits must be on
+
+ SYNPOSIS
+ run_query
+ mysql - mysql handle
+ command - currrent command pointer
+
+*/
-static void run_query_display_metadata(MYSQL_FIELD *field, uint num_fields,
- DYNAMIC_STRING *ds)
+static void run_query(MYSQL *mysql, struct st_query *command, int flags)
{
- MYSQL_FIELD *field_end;
- dynstr_append(ds,"Catalog\tDatabase\tTable\tTable_alias\tColumn\t"
- "Column_alias\tType\tLength\tMax length\tIs_null\t"
- "Flags\tDecimals\tCharsetnr\n");
+ DYNAMIC_STRING *ds;
+ DYNAMIC_STRING ds_tmp;
+ DYNAMIC_STRING eval_query;
+ char *query;
+ int query_len;
- for (field_end= field+num_fields ;
- field < field_end ;
- field++)
+ /*
+ Evaluate query if this is an eval command
+ */
+ if (command->type == Q_EVAL)
{
- char buff[22];
- dynstr_append_mem(ds, field->catalog,
- field->catalog_length);
- dynstr_append_mem(ds, "\t", 1);
- dynstr_append_mem(ds, field->db, field->db_length);
- dynstr_append_mem(ds, "\t", 1);
- dynstr_append_mem(ds, field->org_table,
- field->org_table_length);
- dynstr_append_mem(ds, "\t", 1);
- dynstr_append_mem(ds, field->table,
- field->table_length);
- dynstr_append_mem(ds, "\t", 1);
- dynstr_append_mem(ds, field->org_name,
- field->org_name_length);
- dynstr_append_mem(ds, "\t", 1);
- dynstr_append_mem(ds, field->name, field->name_length);
- dynstr_append_mem(ds, "\t", 1);
- int10_to_str((int) field->type, buff, 10);
- dynstr_append(ds, buff);
- dynstr_append_mem(ds, "\t", 1);
- longlong10_to_str((unsigned int) field->length, buff, 10);
- dynstr_append(ds, buff);
- dynstr_append_mem(ds, "\t", 1);
- longlong10_to_str((unsigned int) field->max_length, buff, 10);
- dynstr_append(ds, buff);
- dynstr_append_mem(ds, "\t", 1);
- dynstr_append_mem(ds, (char*) (IS_NOT_NULL(field->flags) ?
- "N" : "Y"), 1);
- dynstr_append_mem(ds, "\t", 1);
+ init_dynamic_string(&eval_query, "", 16384, 65536);
+ do_eval(&eval_query, command->query);
+ query = eval_query.str;
+ query_len = eval_query.length;
+ }
+ else
+ {
+ query = command->query;
+ query_len = strlen(query);
+ }
- int10_to_str((int) field->flags, buff, 10);
- dynstr_append(ds, buff);
- dynstr_append_mem(ds, "\t", 1);
- int10_to_str((int) field->decimals, buff, 10);
- dynstr_append(ds, buff);
- dynstr_append_mem(ds, "\t", 1);
- int10_to_str((int) field->charsetnr, buff, 10);
- dynstr_append(ds, buff);
+ /*
+ When command->record_file is set the output of _this_ query
+ should be compared with an already existing file
+ Create a temporary dynamic string to contain the output from
+ this query.
+ */
+ if (command->record_file[0])
+ {
+ init_dynamic_string(&ds_tmp, "", 16384, 65536);
+ ds= &ds_tmp;
+ }
+ else
+ ds= &ds_res;
+
+ /* Store the query into the output buffer */
+ if (!disable_query_log && (flags & QUERY_SEND))
+ {
+ replace_dynstr_append_mem(ds,query, query_len);
+ dynstr_append_mem(ds, delimiter, delimiter_length);
dynstr_append_mem(ds, "\n", 1);
}
-}
+ /*
+ Find out how to run this query
-static void run_query_stmt_handle_warnings(MYSQL *mysql, DYNAMIC_STRING *ds)
-{
- uint count;
- DBUG_ENTER("run_query_stmt_handle_warnings");
+ We don't have a mysql_stmt_send_execute() so it must be a
+ complete SEND+REAP to use prepared statement
- if (!disable_warnings && (count= mysql_warning_count(mysql)))
+ If it is a '?' in the query it may be a SQL level prepared
+ statement already and we can't do it twice
+ */
+ if (ps_protocol_enabled &&
+ (flags & QUERY_SEND) && (flags & QUERY_REAP) &&
+ ps_match_re(query))
+ run_query_stmt(mysql, command, query, query_len, ds);
+ else
+ run_query_normal(mysql, command, flags, query, query_len, ds);
+
+ if (record)
{
- /*
- If one day we will support execution of multi-statements
- through PS API we should not issue SHOW WARNINGS until
- we have not read all results...
- */
- DBUG_ASSERT(!mysql_more_results(mysql));
+ /* Recording in progress */
+ if (!command->record_file[0])
+ die("Missing result file");
- if (mysql_real_query(mysql, "SHOW WARNINGS", 13) == 0)
- {
- MYSQL_RES *warn_res= mysql_store_result(mysql);
- if (!warn_res)
- die("Warning count is %u but didn't get any warnings",
- count);
- else
- {
- dynstr_append_mem(ds, "Warnings:\n", 10);
- append_result(ds, warn_res);
- mysql_free_result(warn_res);
- }
- }
+ /* Dump the output from _this_ query to the specified record_file */
+ str_to_file(command->record_file, ds->str, ds->length);
}
- DBUG_VOID_RETURN;
+ else if (command->record_file[0])
+ {
+ /*
+ The output from _this_ query should be checked against an already
+ existing file which has been specified using --require or --result
+ */
+ check_result(ds, command->record_file, command->require_file);
+ }
+
+ if (ds == &ds_tmp)
+ dynstr_free(&ds_tmp);
+ if (command->type == Q_EVAL)
+ dynstr_free(&eval_query);
}
@@ -3911,7 +3845,6 @@ static void init_var_hash(MYSQL *mysql)
int main(int argc, char **argv)
{
- int error = 0;
struct st_query *q;
my_bool require_file=0, q_send_flag=0, abort_flag= 0,
query_executed= 0;
@@ -4005,7 +3938,7 @@ int main(int argc, char **argv)
processed = 1;
switch (q->type) {
case Q_CONNECT:
- error|= do_connect(q);
+ do_connect(q);
break;
case Q_CONNECTION: select_connection(q); break;
case Q_DISCONNECT:
@@ -4039,7 +3972,7 @@ int main(int argc, char **argv)
#endif
case Q_INC: do_modify_var(q, "inc", DO_INC); break;
case Q_DEC: do_modify_var(q, "dec", DO_DEC); break;
- case Q_ECHO: do_echo(q); break;
+ case Q_ECHO: do_echo(q); query_executed= 1; break;
case Q_SYSTEM: do_system(q); break;
case Q_DELIMITER:
strmake(delimiter, q->first_argument, sizeof(delimiter) - 1);
@@ -4066,15 +3999,6 @@ int main(int argc, char **argv)
case Q_QUERY_HORIZONTAL:
{
my_bool old_display_result_vertically= display_result_vertically;
- if (!q->query[q->first_word_len])
- {
- /* This happens when we use 'query_..' on it's own line */
- q_send_flag=1;
- DBUG_PRINT("info",
- ("query: '%s' first_word_len: %d send_flag=1",
- q->query, q->first_word_len));
- break;
- }
/* fix up query pointer if this is * first iteration for this line */
if (q->query == q->query_buf)
q->query += q->first_word_len + 1;
@@ -4085,7 +4009,7 @@ int main(int argc, char **argv)
q->require_file=require_file;
save_file[0]=0;
}
- error|= run_query(&cur_con->mysql, q, QUERY_REAP|QUERY_SEND);
+ run_query(&cur_con->mysql, q, QUERY_REAP|QUERY_SEND);
display_result_vertically= old_display_result_vertically;
q->last_argument= q->end;
query_executed= 1;
@@ -4112,7 +4036,7 @@ int main(int argc, char **argv)
q->require_file=require_file;
save_file[0]=0;
}
- error |= run_query(&cur_con->mysql, q, flags);
+ run_query(&cur_con->mysql, q, flags);
query_executed= 1;
q->last_argument= q->end;
break;
@@ -4133,7 +4057,7 @@ int main(int argc, char **argv)
query and read the result some time later when reap instruction
is given on this connection.
*/
- error |= run_query(&cur_con->mysql, q, QUERY_SEND);
+ run_query(&cur_con->mysql, q, QUERY_SEND);
query_executed= 1;
q->last_argument= q->end;
break;
@@ -4255,6 +4179,12 @@ int main(int argc, char **argv)
parser.current_line += current_line_inc;
}
+ /*
+ The whole test has been executed sucessfully
+ Time to compare result or save it to record file
+ The entire output from test is now kept in ds_res
+ */
+
if (!query_executed && result_file && my_stat(result_file, &res_info, 0))
{
/*
@@ -4265,39 +4195,46 @@ int main(int argc, char **argv)
no query output from the test file, e.g. regarded as no error.
*/
if (res_info.st_size)
- error|= (RESULT_CONTENT_MISMATCH | RESULT_LENGTH_MISMATCH);
+ die("No queries executed but result file found!");
}
- if (ds_res.length && !error)
+
+ if (ds_res.length)
{
if (result_file)
{
- if (!record)
- error |= check_result(&ds_res, result_file, q->require_file);
+ if (record)
+ {
+ /* Dump the output from test to result file */
+ str_to_file(result_file, ds_res.str, ds_res.length);
+ }
else
- str_to_file(result_file, ds_res.str, ds_res.length);
+ {
+ /* Check that the output from test is equal to result file */
+ check_result(&ds_res, result_file, 0);
+ }
}
else
{
- /* Print the result to stdout */
+ /* No result_file to compare with, print the result to stdout */
printf("%s", ds_res.str);
}
- }
- dynstr_free(&ds_res);
-
- if (!silent)
+ }
+ else
{
- if (error)
- printf("not ok\n");
- else
- printf("ok\n");
+ /* The test didn't produce any output */
}
+ dynstr_free(&ds_res);
if (!got_end_timer)
timer_output(); /* No end_timer cmd, end it */
free_used_memory();
my_end(MY_CHECK_ERROR);
- exit(error ? 1 : 0);
- return error ? 1 : 0; /* Keep compiler happy */
+
+ /* Yes, if we got this far the test has suceeded! Sakila smiles */
+ if (!silent)
+ printf("ok\n");
+ exit(0);
+ return 0; /* Keep compiler happy */
}
@@ -5094,12 +5031,6 @@ static int initialize_replace_buffer(void)
return 0;
}
-static void free_replace_buffer(void)
-{
- my_free(out_buff,MYF(MY_WME));
-}
-
-
/****************************************************************************
Replace results for a column
*****************************************************************************/