mysqltest.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:133k
- #include <help_end.h>
- static my_bool
- get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
- char *argument)
- {
- switch(optid) {
- case '#':
- #ifndef DBUG_OFF
- DBUG_PUSH(argument ? argument : "d:t:S:i:O,/tmp/mysqltest.trace");
- #endif
- break;
- case 'r':
- record = 1;
- break;
- case (int)OPT_MANAGER_PASSWD:
- my_free(manager_pass,MYF(MY_ALLOW_ZERO_PTR));
- manager_pass=my_strdup(argument, MYF(MY_FAE));
- while (*argument) *argument++= 'x'; /* Destroy argument */
- break;
- case 'x':
- {
- char buff[FN_REFLEN];
- if (!test_if_hard_path(argument))
- {
- strxmov(buff, opt_basedir, argument, NullS);
- argument= buff;
- }
- fn_format(buff, argument, "", "", 4);
- DBUG_ASSERT(cur_file == file_stack && cur_file->file == 0);
- if (!(cur_file->file=
- my_fopen(buff, O_RDONLY | FILE_BINARY, MYF(0))))
- die("Could not open %s: errno = %d", buff, errno);
- cur_file->file_name= my_strdup(buff, MYF(MY_FAE));
- break;
- }
- case 'm':
- {
- static char buff[FN_REFLEN];
- if (!test_if_hard_path(argument))
- {
- strxmov(buff, opt_basedir, argument, NullS);
- argument= buff;
- }
- fn_format(buff, argument, "", "", 4);
- timer_file= buff;
- unlink(timer_file); /* Ignore error, may not exist */
- break;
- }
- case 'p':
- if (argument)
- {
- my_free(pass, MYF(MY_ALLOW_ZERO_PTR));
- pass= my_strdup(argument, MYF(MY_FAE));
- while (*argument) *argument++= 'x'; /* Destroy argument */
- tty_password= 0;
- }
- else
- tty_password= 1;
- break;
- #include <sslopt-case.h>
- case 't':
- strnmov(TMPDIR, argument, sizeof(TMPDIR));
- break;
- case 'A':
- if (!embedded_server_arg_count)
- {
- embedded_server_arg_count=1;
- embedded_server_args[0]= (char*) "";
- }
- if (embedded_server_arg_count == MAX_SERVER_ARGS-1 ||
- !(embedded_server_args[embedded_server_arg_count++]=
- my_strdup(argument, MYF(MY_FAE))))
- {
- die("Can't use server argument");
- }
- break;
- case 'F':
- if (read_server_arguments(argument))
- die(NullS);
- break;
- case OPT_SKIP_SAFEMALLOC:
- #ifdef SAFEMALLOC
- sf_malloc_quick=1;
- #endif
- break;
- case 'V':
- print_version();
- exit(0);
- case '?':
- usage();
- exit(1);
- }
- return 0;
- }
- int parse_args(int argc, char **argv)
- {
- load_defaults("my",load_default_groups,&argc,&argv);
- default_argv= argv;
- if ((handle_options(&argc, &argv, my_long_options, get_one_option)))
- exit(1);
- if (argc > 1)
- {
- usage();
- exit(1);
- }
- if (argc == 1)
- db= *argv;
- if (tty_password)
- pass=get_tty_password(NullS);
- return 0;
- }
- char* safe_str_append(char *buf, const char *str, int size)
- {
- int i,c ;
- for (i = 0; (c = *str++) && i < size - 1; i++)
- *buf++ = c;
- *buf = 0;
- return buf;
- }
- void str_to_file(const char *fname, char *str, int size)
- {
- int fd;
- char buff[FN_REFLEN];
- if (!test_if_hard_path(fname))
- {
- strxmov(buff, opt_basedir, fname, NullS);
- fname=buff;
- }
- fn_format(buff,fname,"","",4);
-
- if ((fd = my_open(buff, O_WRONLY | O_CREAT | O_TRUNC,
- MYF(MY_WME | MY_FFNF))) < 0)
- die("Could not open %s: errno = %d", buff, errno);
- if (my_write(fd, (byte*)str, size, MYF(MY_WME|MY_FNABP)))
- die("write failed");
- my_close(fd, MYF(0));
- }
- void reject_dump(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);
- }
- /* Append the string to ds, with optional replace */
- static void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val,
- int len)
- {
- if (glob_replace)
- {
- len=(int) replace_strings(glob_replace, &out_buff, &out_length, val);
- if (len == -1)
- die("Out of memory in replace");
- val=out_buff;
- }
- dynstr_append_mem(ds, val, len);
- }
- /*
- Append all results to the dynamic string separated with 't'
- Values may be converted with 'replace_column'
- */
- 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;
- while ((row = mysql_fetch_row(res)))
- {
- uint i;
- lengths = mysql_fetch_lengths(res);
- for (i = 0; i < num_fields; i++)
- {
- const char *val= row[i];
- ulonglong len= lengths[i];
- if (i < max_replace_column && replace_column[i])
- {
- val= replace_column[i];
- len= strlen(val);
- }
- if (!val)
- {
- val= "NULL";
- len= 4;
- }
- if (!display_result_vertically)
- {
- if (i)
- dynstr_append_mem(ds, "t", 1);
- replace_dynstr_append_mem(ds, val, len);
- }
- else
- {
- dynstr_append(ds, fields[i].name);
- dynstr_append_mem(ds, "t", 1);
- replace_dynstr_append_mem(ds, val, len);
- dynstr_append_mem(ds, "n", 1);
- }
- }
- if (!display_result_vertically)
- dynstr_append_mem(ds, "n", 1);
- }
- free_replace_column();
- }
- /*
- * 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
- */
- 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 int run_query_stmt_handle_error(char *query, struct st_query *q,
- MYSQL_STMT *stmt, 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)
- {
- /*
- Try to find out if we can run this statement using the prepared
- statement protocol.
- 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
- */
- 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);
- }
- static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags)
- {
- 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
- {
- init_dynamic_string(&eval_query, "", 16384, 65536);
- do_eval(&eval_query, q->query);
- query = eval_query.str;
- query_len = eval_query.length;
- }
- DBUG_PRINT("enter", ("query: '%-.60s'", query));
- if (q->record_file[0])
- {
- init_dynamic_string(&ds_tmp, "", 16384, 65536);
- ds = &ds_tmp;
- }
- else
- ds= &ds_res;
- 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);
- }
- do
- {
- if ((flags & QUERY_SEND) && !disable_query_log && !counter)
- {
- replace_dynstr_append_mem(ds,query, query_len);
- dynstr_append_mem(ds, delimiter, delimiter_length);
- dynstr_append_mem(ds, "n", 1);
- }
- 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)))
- {
- if (q->require_file)
- {
- abort_not_supported_test();
- }
- if (q->abort_on_error)
- die("query '%s' failed: %d: %s", query,
- mysql_errno(mysql), mysql_error(mysql));
- 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 errorsn");
- 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;
- }
- if (handle_no_error(q))
- {
- error= 1;
- goto end;
- }
- if (!disable_result_log)
- {
- ulong affected_rows; /* Ok to be undef if 'disable_info' is set */
- LINT_INIT(affected_rows);
- if (res)
- {
- 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)
- {
- for (i = 0; i < num_fields; i++)
- {
- if (i)
- dynstr_append_mem(ds, "t", 1);
- replace_dynstr_append_mem(ds, field[i].name,
- strlen(field[i].name));
- }
- dynstr_append_mem(ds, "n", 1);
- }
- append_result(ds, res);
- }
- /*
- Need to call mysql_affected_rows() before the new
- query to find the warnings
- */
- if (!disable_info)
- affected_rows= (ulong)mysql_affected_rows(mysql);
- /* Add all warnings to the result */
- if (!disable_warnings && 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)
- verbose_msg("Warning count is %u but didn't get any warningsn",
- count);
- else
- {
- dynstr_append_mem(ds, "Warnings:n", 10);
- append_result(ds, warn_res);
- mysql_free_result(warn_res);
- }
- }
- if (!disable_info)
- {
- char buf[40];
- sprintf(buf,"affected rows: %lun", 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);
- }
- }
- }
- 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 >= 1)
- mysql_error(mysql);
- 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
- 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_errno(mysql));
- DBUG_RETURN(error);
- }
- /****************************************************************************
- * 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
- */
- static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags)
- {
- int error= 0; /* Function return code if "goto end;" */
- int err; /* Temporary storage of return code from calls */
- int query_len, got_error_on_execute;
- uint 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");
- /*
- We must allocate a new stmt for each query in this program becasue this
- may be a new connection.
- */
- 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);
- }
- /*
- We use the prepared statement interface but there is actually no
- '?' in the query. If unpreparable we fall back to use normal
- C API.
- */
- if ((err= mysql_stmt_prepare(stmt, query, query_len)) == CR_NO_PREPARE_STMT)
- return run_query_normal(mysql, q, flags);
- if (err != 0)
- {
- if (q->abort_on_error)
- {
- die("query '%s' failed: %d: %s", query,
- mysql_stmt_errno(stmt), mysql_stmt_error(stmt));
- }
- else
- {
- /*
- Preparing is part of normal execution and some errors may be expected
- */
- error= run_query_stmt_handle_error(query, q, stmt, ds);
- goto end;
- }
- }
- /* We may have got warnings already, collect them if any */
- /* FIXME we only want this if the statement succeeds I think */
- 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 ((got_error_on_execute= mysql_stmt_execute(stmt)) != 0) /* 0 == Success */
- {
- if (q->abort_on_error)
- {
- /* We got an error, unexpected */
- die("unable to execute statement '%s': "
- "%s (mysql_stmt_errno=%d returned=%d)",
- query, mysql_stmt_error(stmt),
- mysql_stmt_errno(stmt), got_error_on_execute);
- }
- else
- {
- /* We got an error, maybe expected */
- error= run_query_stmt_handle_error(query, q, stmt, ds);
- goto end;
- }
- }
- /*
- We instruct that we want to update the "max_length" field in
- mysql_stmt_store_result(), this is our only way to know how much
- buffer to allocate for result data
- */
- {
- my_bool one= 1;
- if (mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH,
- (void*) &one) != 0)
- die("unable to set stmt attribute "
- "'STMT_ATTR_UPDATE_MAX_LENGTH': %s (returned=%d)",
- query, err);
- }
- /*
- 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 (q->abort_on_error)
- {
- /* We got an error, unexpected */
- die("unable to execute statement '%s': "
- "%s (mysql_stmt_errno=%d returned=%d)",
- query, mysql_stmt_error(stmt),
- mysql_stmt_errno(stmt), got_error_on_execute);
- }
- else
- {
- /* We got an error, maybe expected */
- error= run_query_stmt_handle_error(query, q, 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);
- /*
- Not all statements creates a result set. If there is one we can
- now create another normal result set that contains the meta
- 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))
- {
- /* Take the column count from meta info */
- MYSQL_FIELD *field= mysql_fetch_fields(res);
- uint num_fields= mysql_num_fields(res);
- /* FIXME check error from the above? */
- 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_mem(ds, field[col_idx].name,
- strlen(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() */
- {
- 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));
- 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++)
- {
- const char *val;
- ulonglong len;
- if (col_idx < max_replace_column && replace_column[col_idx])
- {
- val= replace_column[col_idx];
- len= strlen(val);
- }
- else if (*bind[col_idx].is_null)
- {
- val= "NULL";
- len= 4;
- }
- else
- {
- /* FIXME is string terminated? */
- val= (const char *) bind[col_idx].buffer;
- len= *bind[col_idx].length;
- }
- if (!display_result_vertically)
- {
- if (col_idx) /* No tab before first col */
- dynstr_append_mem(ds, "t", 1);
- replace_dynstr_append_mem(ds, val, len);
- }
- else
- {
- dynstr_append(ds, field[col_idx].name);
- dynstr_append_mem(ds, "t", 1);
- replace_dynstr_append_mem(ds, val, 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));
- }
- /* Add all warnings to the result */
- run_query_stmt_handle_warnings(mysql, ds);
- if (!disable_info)
- {
- char buf[40];
- sprintf(buf,"affected rows: %lun",(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);
- }
- }
- }
- 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... */
- if (err >= 1)
- mysql_error(mysql); /* FIXME strange, has no effect... */
- end:
- free_replace();
- last_result=0;
- if (ds == &ds_tmp)
- dynstr_free(&ds_tmp);
- if (q->type == Q_EVAL)
- dynstr_free(&eval_query);
- var_set_errno(mysql_stmt_errno(stmt));
- mysql_stmt_close(stmt);
- DBUG_RETURN(error);
- }
- /****************************************************************************
- * Broken out sub functions to run_query_stmt()
- ****************************************************************************/
- static void run_query_display_metadata(MYSQL_FIELD *field, uint num_fields,
- DYNAMIC_STRING *ds)
- {
- MYSQL_FIELD *field_end;
- dynstr_append(ds,"CatalogtDatabasetTabletTable_aliastColumnt"
- "Column_aliastTypetLengthtMax lengthtIs_nullt"
- "FlagstDecimalstCharsetnrn");
- 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);
- 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);
- }
- }
- static void run_query_stmt_handle_warnings(MYSQL *mysql, DYNAMIC_STRING *ds)
- {
- uint count;
- DBUG_ENTER("run_query_stmt_handle_warnings");
- if (!disable_warnings && (count= mysql_warning_count(mysql)))
- {
- if (mysql_real_query(mysql, "SHOW WARNINGS", 13) == 0)
- {
- MYSQL_RES *warn_res= mysql_store_result(mysql);
- if (!warn_res)
- verbose_msg("Warning count is %u but didn't get any warningsn",
- count);
- else
- {
- dynstr_append_mem(ds, "Warnings:n", 10);
- append_result(ds, warn_res);
- mysql_free_result(warn_res);
- }
- }
- }
- DBUG_VOID_RETURN;
- }
- static int run_query_stmt_handle_error(char *query, struct st_query *q,
- MYSQL_STMT *stmt, DYNAMIC_STRING *ds)
- {
- if (q->require_file) /* FIXME don't understand this one */
- {
- abort_not_supported_test();
- }
- if (q->abort_on_error)
- die("query '%s' failed: %d: %s", query,
- mysql_stmt_errno(stmt), mysql_stmt_error(stmt));
- else
- {
- int i;
- for (i=0 ; (uint) i < q->expected_errors ; i++)
- {
- if (((q->expected_errno[i].type == ERR_ERRNO) &&
- (q->expected_errno[i].code.errnum == mysql_stmt_errno(stmt))) ||
- ((q->expected_errno[i].type == ERR_SQLSTATE) &&
- (strcmp(q->expected_errno[i].code.sqlstate,
- mysql_stmt_sqlstate(stmt)) == 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_stmt_sqlstate(stmt),
- strlen(mysql_stmt_sqlstate(stmt)));
- dynstr_append_mem(ds, ": ", 2);
- replace_dynstr_append_mem(ds,mysql_stmt_error(stmt),
- strlen(mysql_stmt_error(stmt)));
- 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 errorsn");
- return 0; /* 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_stmt_sqlstate(stmt),
- strlen(mysql_stmt_sqlstate(stmt)));
- dynstr_append_mem(ds,": ",2);
- replace_dynstr_append_mem(ds, mysql_stmt_error(stmt),
- strlen(mysql_stmt_error(stmt)));
- 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_stmt_errno(stmt),
- q->expected_errno[0].code.errnum);
- else
- verbose_msg("query '%s' failed with wrong sqlstate %s instead of %s...",
- q->query, mysql_stmt_sqlstate(stmt),
- q->expected_errno[0].code.sqlstate);
- return 1; /* Error */
- }
- verbose_msg("query '%s' failed: %d: %s", q->query, mysql_stmt_errno(stmt),
- mysql_stmt_error(stmt));
- /*
- if we do not abort on error, failure to run the query does
- not fail the whole test case
- */
- return 0;
- }
- return 0;
- }
- /*
- Handle absence of errors after execution
- SYNOPSIS
- handle_no_error()
- q - context of query
- RETURN VALUE
- 0 - OK
- 1 - Some error was expected from this query.
- */
- static int handle_no_error(struct st_query *q)
- {
- DBUG_ENTER("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);
- }
- /****************************************************************************
- * Functions to match SQL statements that can be prepared
- ****************************************************************************/
- static void ps_init_re(void)
- {
- const char *ps_re_str =
- "^("
- "[[:space:]]*REPLACE[[:space:]]|"
- "[[:space:]]*INSERT[[:space:]]|"
- "[[:space:]]*UPDATE[[:space:]]|"
- "[[:space:]]*DELETE[[:space:]]|"
- "[[:space:]]*SELECT[[:space:]]|"
- "[[:space:]]*CREATE[[:space:]]+TABLE[[:space:]]|"
- "[[:space:]]*DO[[:space:]]|"
- "[[:space:]]*SET[[:space:]]+OPTION[[:space:]]|"
- "[[:space:]]*DELETE[[:space:]]+MULTI[[:space:]]|"
- "[[:space:]]*UPDATE[[:space:]]+MULTI[[:space:]]|"
- "[[:space:]]*INSERT[[:space:]]+SELECT[[:space:]])";
- int err= my_regcomp(&ps_re, ps_re_str,
- (REG_EXTENDED | REG_ICASE | REG_NOSUB),
- &my_charset_latin1);
- if (err)
- {
- char erbuf[100];
- int len= my_regerror(err, &ps_re, erbuf, sizeof(erbuf));
- fprintf(stderr, "error %s, %d/%d `%s'n",
- ps_eprint(err), len, (int)sizeof(erbuf), erbuf);
- exit(1);
- }
- }
- static int ps_match_re(char *stmt_str)
- {
- int err= my_regexec(&ps_re, stmt_str, (size_t)0, NULL, 0);
- if (err == 0)
- return 1;
- else if (err == REG_NOMATCH)
- return 0;
- else
- {
- char erbuf[100];
- int len= my_regerror(err, &ps_re, erbuf, sizeof(erbuf));
- fprintf(stderr, "error %s, %d/%d `%s'n",
- ps_eprint(err), len, (int)sizeof(erbuf), erbuf);
- exit(1);
- }
- }
- static char *ps_eprint(int err)
- {
- static char epbuf[100];
- size_t len= my_regerror(REG_ITOA|err, (my_regex_t *)NULL, epbuf, sizeof(epbuf));
- assert(len <= sizeof(epbuf));
- return(epbuf);
- }
- static void ps_free_reg(void)
- {
- my_regfree(&ps_re);
- }
- /****************************************************************************/
- void get_query_type(struct st_query* q)
- {
- char save;
- uint type;
- DBUG_ENTER("get_query_type");
- if (*q->query == '}')
- {
- q->type = Q_END_BLOCK;
- DBUG_VOID_RETURN;
- }
- if (q->type != Q_COMMENT_WITH_COMMAND)
- q->type = Q_QUERY;
- save=q->query[q->first_word_len];
- q->query[q->first_word_len]=0;
- type=find_type(q->query, &command_typelib, 1+2);
- q->query[q->first_word_len]=save;
- if (type > 0)
- q->type=(enum enum_commands) type; /* Found command */
- DBUG_VOID_RETURN;
- }
- static byte *get_var_key(const byte* var, uint* len,
- my_bool __attribute__((unused)) t)
- {
- register char* key;
- key = ((VAR*)var)->name;
- *len = ((VAR*)var)->name_len;
- return (byte*)key;
- }
- static VAR *var_init(VAR *v, const char *name, int name_len, const char *val,
- int val_len)
- {
- int val_alloc_len;
- VAR *tmp_var;
- if (!name_len && name)
- name_len = strlen(name);
- if (!val_len && val)
- val_len = strlen(val) ;
- val_alloc_len = val_len + 16; /* room to grow */
- if (!(tmp_var=v) && !(tmp_var = (VAR*)my_malloc(sizeof(*tmp_var)
- + name_len, MYF(MY_WME))))
- die("Out of memory");
- tmp_var->name = (name) ? (char*) tmp_var + sizeof(*tmp_var) : 0;
- tmp_var->alloced = (v == 0);
- if (!(tmp_var->str_val = my_malloc(val_alloc_len+1, MYF(MY_WME))))
- die("Out of memory");
- memcpy(tmp_var->name, name, name_len);
- if (val)
- {
- memcpy(tmp_var->str_val, val, val_len);
- tmp_var->str_val[val_len]=0;
- }
- tmp_var->name_len = name_len;
- tmp_var->str_val_len = val_len;
- tmp_var->alloced_len = val_alloc_len;
- tmp_var->int_val = (val) ? atoi(val) : 0;
- tmp_var->int_dirty = 0;
- return tmp_var;
- }
- static void var_free(void *v)
- {
- my_free(((VAR*) v)->str_val, MYF(MY_WME));
- if (((VAR*)v)->alloced)
- my_free((char*) v, MYF(MY_WME));
- }
- static VAR* var_from_env(const char *name, const char *def_val)
- {
- const char *tmp;
- VAR *v;
- if (!(tmp = getenv(name)))
- tmp = def_val;
- v = var_init(0, name, strlen(name), tmp, strlen(tmp));
- my_hash_insert(&var_hash, (byte*)v);
- return v;
- }
- static void init_var_hash(MYSQL *mysql)
- {
- VAR *v;
- DBUG_ENTER("init_var_hash");
- if (hash_init(&var_hash, charset_info,
- 1024, 0, 0, get_var_key, var_free, MYF(0)))
- die("Variable hash initialization failed");
- if (opt_big_test)
- my_hash_insert(&var_hash, (byte*) var_init(0,"BIG_TEST", 0, "1",0));
- v= var_init(0,"MAX_TABLES", 0, (sizeof(ulong) == 4) ? "31" : "62",0);
- my_hash_insert(&var_hash, (byte*) v);
- v= var_init(0,"SERVER_VERSION", 0, mysql_get_server_info(mysql), 0);
- my_hash_insert(&var_hash, (byte*) v);
- v= var_init(0,"DB", 2, db, 0);
- my_hash_insert(&var_hash, (byte*) v);
- DBUG_VOID_RETURN;
- }
- int main(int argc, char **argv)
- {
- int error = 0;
- struct st_query *q;
- my_bool require_file=0, q_send_flag=0, query_executed= 0, abort_flag= 0;
- char save_file[FN_REFLEN];
- MY_STAT res_info;
- MY_INIT(argv[0]);
- {
- DBUG_ENTER("main");
- DBUG_PROCESS(argv[0]);
- /* Use all time until exit if no explicit 'start_timer' */
- timer_start= timer_now();
- save_file[0]=0;
- TMPDIR[0]=0;
- memset(cons, 0, sizeof(cons));
- cons_end = cons + MAX_CONS;
- next_con = cons + 1;
- cur_con = cons;
- memset(file_stack, 0, sizeof(file_stack));
- memset(&master_pos, 0, sizeof(master_pos));
- file_stack_end= file_stack + MAX_INCLUDE_DEPTH - 1;
- cur_file= file_stack;
- lineno = lineno_stack;
- my_init_dynamic_array(&q_lines, sizeof(struct st_query*), INIT_Q_LINES,
- INIT_Q_LINES);
- memset(block_stack, 0, sizeof(block_stack));
- block_stack_end= block_stack + BLOCK_STACK_DEPTH - 1;
- cur_block= block_stack;
- cur_block->ok= TRUE; /* Outer block should always be executed */
- cur_block->cmd= Q_UNKNOWN;
- init_dynamic_string(&ds_res, "", 0, 65536);
- parse_args(argc, argv);
- if (mysql_server_init(embedded_server_arg_count,
- embedded_server_args,
- (char**) embedded_server_groups))
- die("Can't initialize MySQL server");
- if (cur_file == file_stack && cur_file->file == 0)
- {
- cur_file->file= stdin;
- cur_file->file_name= my_strdup("<stdin>", MYF(MY_WME));
- }
- *lineno=1;
- #ifndef EMBEDDED_LIBRARY
- if (manager_host)
- init_manager();
- #endif
- if (ps_protocol)
- {
- ps_protocol_enabled= 1;
- ps_init_re();
- }
- if (!( mysql_init(&cur_con->mysql)))
- die("Failed in mysql_init()");
- if (opt_compress)
- mysql_options(&cur_con->mysql,MYSQL_OPT_COMPRESS,NullS);
- mysql_options(&cur_con->mysql, MYSQL_OPT_LOCAL_INFILE, 0);
- mysql_options(&cur_con->mysql, MYSQL_SET_CHARSET_NAME, charset_name);
- #ifdef HAVE_OPENSSL
- if (opt_use_ssl)
- mysql_ssl_set(&cur_con->mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
- opt_ssl_capath, opt_ssl_cipher);
- #endif
- if (!(cur_con->name = my_strdup("default", MYF(MY_WME))))
- die("Out of memory");
- if (safe_connect(&cur_con->mysql, host, user, pass, db, port, unix_sock))
- die("Failed in mysql_real_connect(): %s", mysql_error(&cur_con->mysql));
- init_var_hash(&cur_con->mysql);
- /*
- Initialize $mysql_errno with -1, so we can
- - distinguish it from valid values ( >= 0 ) and
- - detect if there was never a command sent to the server
- */
- var_set_errno(-1);
- while (!abort_flag && !read_query(&q))
- {
- int current_line_inc = 1, processed = 0;
- if (q->type == Q_UNKNOWN || q->type == Q_COMMENT_WITH_COMMAND)
- get_query_type(q);
- if (cur_block->ok)
- {
- q->last_argument= q->first_argument;
- processed = 1;
- switch (q->type) {
- case Q_CONNECT: do_connect(q); break;
- case Q_CONNECTION: select_connection(q); break;
- case Q_DISCONNECT:
- case Q_DIRTY_CLOSE:
- close_connection(q); break;
- case Q_RPL_PROBE: do_rpl_probe(q); break;
- case Q_ENABLE_RPL_PARSE: do_enable_rpl_parse(q); break;
- case Q_DISABLE_RPL_PARSE: do_disable_rpl_parse(q); break;
- case Q_ENABLE_QUERY_LOG: disable_query_log=0; break;
- case Q_DISABLE_QUERY_LOG: disable_query_log=1; break;
- case Q_ENABLE_ABORT_ON_ERROR: abort_on_error=1; break;
- case Q_DISABLE_ABORT_ON_ERROR: abort_on_error=0; break;
- case Q_ENABLE_RESULT_LOG: disable_result_log=0; break;
- case Q_DISABLE_RESULT_LOG: disable_result_log=1; break;
- case Q_ENABLE_WARNINGS: disable_warnings=0; break;
- case Q_DISABLE_WARNINGS: disable_warnings=1; break;
- case Q_ENABLE_INFO: disable_info=0; break;
- case Q_DISABLE_INFO: disable_info=1; break;
- case Q_ENABLE_METADATA: display_metadata=1; break;
- case Q_DISABLE_METADATA: display_metadata=0; break;
- case Q_SOURCE: do_source(q); break;
- case Q_SLEEP: do_sleep(q, 0); break;
- case Q_REAL_SLEEP: do_sleep(q, 1); break;
- case Q_WAIT_FOR_SLAVE_TO_STOP: do_wait_for_slave_to_stop(q); break;
- case Q_REQUIRE_MANAGER: do_require_manager(q); break;
- #ifndef EMBEDDED_LIBRARY
- case Q_SERVER_START: do_server_start(q); break;
- case Q_SERVER_STOP: do_server_stop(q); break;
- #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_SYSTEM: do_system(q); break;
- case Q_DELIMITER:
- strmake(delimiter, q->first_argument, sizeof(delimiter) - 1);
- delimiter_length= strlen(delimiter);
- q->last_argument= q->first_argument+delimiter_length;
- break;
- case Q_DISPLAY_VERTICAL_RESULTS:
- display_result_vertically= TRUE;
- break;
- case Q_DISPLAY_HORIZONTAL_RESULTS:
- display_result_vertically= FALSE;
- break;
- case Q_LET: do_let(q); break;
- case Q_EVAL_RESULT:
- eval_result = 1; break;
- case Q_EVAL:
- if (q->query == q->query_buf)
- {
- q->query= q->first_argument;
- q->first_word_len= 0;
- }
- /* fall through */
- case Q_QUERY_VERTICAL:
- 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;
- display_result_vertically= (q->type==Q_QUERY_VERTICAL);
- if (save_file[0])
- {
- strmov(q->record_file,save_file);
- q->require_file=require_file;
- save_file[0]=0;
- }
- error|= 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;
- break;
- }
- case Q_QUERY:
- case Q_REAP:
- {
- /*
- We read the result always regardless of the mode for both full
- query and read-result only (reap)
- */
- int flags = QUERY_REAP;
- if (q->type != Q_REAP) /* for a full query, enable the send stage */
- flags |= QUERY_SEND;
- if (q_send_flag)
- {
- flags= QUERY_SEND;
- q_send_flag=0;
- }
- if (save_file[0])
- {
- strmov(q->record_file,save_file);
- q->require_file=require_file;
- save_file[0]=0;
- }
- error |= run_query(&cur_con->mysql, q, flags);
- query_executed= 1;
- q->last_argument= q->end;
- break;
- }
- case Q_SEND:
- if (!q->query[q->first_word_len])
- {
- /* This happens when we use 'send' on it's own line */
- q_send_flag=1;
- 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;
- /*
- run_query() can execute a query partially, depending on the flags
- QUERY_SEND flag without QUERY_REAP tells it to just send the
- 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);
- query_executed= 1;
- q->last_argument= q->end;
- break;
- case Q_RESULT:
- get_file_name(save_file,q);
- require_file=0;
- break;
- case Q_ERROR:
- global_expected_errors=get_errcodes(global_expected_errno,q);
- break;
- case Q_REQUIRE:
- get_file_name(save_file,q);
- require_file=1;
- break;
- case Q_REPLACE:
- get_replace(q);
- break;
- case Q_REPLACE_COLUMN:
- get_replace_column(q);
- break;
- case Q_SAVE_MASTER_POS: do_save_master_pos(); break;
- case Q_SYNC_WITH_MASTER: do_sync_with_master(q); break;
- case Q_SYNC_SLAVE_WITH_MASTER:
- {
- do_save_master_pos();
- if (*q->first_argument)
- select_connection(q);
- else
- select_connection_name("slave");
- do_sync_with_master2(0);
- break;
- }
- case Q_COMMENT: /* Ignore row */
- case Q_COMMENT_WITH_COMMAND:
- q->last_argument= q->end;
- break;
- case Q_PING:
- (void) mysql_ping(&cur_con->mysql);
- break;
- case Q_EXEC:
- do_exec(q);
- query_executed= 1;
- break;
- case Q_START_TIMER:
- /* Overwrite possible earlier start of timer */
- timer_start= timer_now();
- break;
- case Q_END_TIMER:
- /* End timer before ending mysqltest */
- timer_output();
- got_end_timer= TRUE;
- break;
- case Q_CHARACTER_SET:
- set_charset(q);
- break;
- case Q_DISABLE_PS_PROTOCOL:
- ps_protocol_enabled= 0;
- break;
- case Q_ENABLE_PS_PROTOCOL:
- ps_protocol_enabled= ps_protocol;
- break;
- case Q_DISABLE_RECONNECT:
- cur_con->mysql.reconnect= 0;
- break;
- case Q_ENABLE_RECONNECT:
- cur_con->mysql.reconnect= 1;
- break;
- case Q_EXIT:
- abort_flag= 1;
- break;
- default: processed = 0; break;
- }
- }
- if (!processed)
- {
- current_line_inc = 0;
- switch (q->type) {
- case Q_WHILE: do_block(Q_WHILE, q); break;
- case Q_IF: do_block(Q_IF, q); break;
- case Q_END_BLOCK: do_done(q); break;
- default: current_line_inc = 1; break;
- }
- }
- else
- check_eol_junk(q->last_argument);
- if (q->type != Q_ERROR)
- {
- /*
- As soon as any non "error" command has been executed,
- the array with expected errors should be cleared
- */
- global_expected_errors= 0;
- bzero((gptr) global_expected_errno, sizeof(global_expected_errno));
- }
- parser.current_line += current_line_inc;
- }
- if (!query_executed && result_file && my_stat(result_file, &res_info, 0))
- {
- /*
- my_stat() successful on result file. Check if we have not run a
- single query, but we do have a result file that contains data.
- Note that we don't care, if my_stat() fails. For example for
- non-existing or non-readable file we assume it's fine to have
- 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);
- }
- if (ds_res.length && !error)
- {
- if (result_file)
- {
- if (!record)
- error |= check_result(&ds_res, result_file, q->require_file);
- else
- str_to_file(result_file, ds_res.str, ds_res.length);
- }
- else
- {
- /* Print the result to stdout */
- printf("%s", ds_res.str);
- }
- }
- dynstr_free(&ds_res);
- if (!silent)
- {
- if (error)
- printf("not okn");
- else
- printf("okn");
- }
- 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 */
- }
- }
- /*
- Read arguments for embedded server and put them into
- embedded_server_args_count and embedded_server_args[]
- */
- static int read_server_arguments(const char *name)
- {
- char argument[1024],buff[FN_REFLEN], *str=0;
- FILE *file;
- if (!test_if_hard_path(name))
- {
- strxmov(buff, opt_basedir, name, NullS);
- name=buff;
- }
- fn_format(buff,name,"","",4);
- if (!embedded_server_arg_count)
- {
- embedded_server_arg_count=1;
- embedded_server_args[0]= (char*) ""; /* Progname */
- }
- if (!(file=my_fopen(buff, O_RDONLY | FILE_BINARY, MYF(MY_WME))))
- return 1;
- while (embedded_server_arg_count < MAX_SERVER_ARGS &&
- (str=fgets(argument,sizeof(argument), file)))
- {
- *(strend(str)-1)=0; /* Remove end newline */
- if (!(embedded_server_args[embedded_server_arg_count]=
- (char*) my_strdup(str,MYF(MY_WME))))
- {
- my_fclose(file,MYF(0));
- return 1;
- }
- embedded_server_arg_count++;
- }
- my_fclose(file,MYF(0));
- if (str)
- {
- fprintf(stderr,"Too many arguments in option file: %sn",name);
- return 1;
- }
- return 0;
- }
- /****************************************************************************
- *
- * A primitive timer that give results in milliseconds if the
- * --timer-file=<filename> is given. The timer result is written
- * to that file when the result is available. To not confuse
- * mysql-test-run with an old obsolete result, we remove the file
- * before executing any commands. The time we measure is
- *
- * - If no explicit 'start_timer' or 'end_timer' is given in the
- * test case, the timer measure how long we execute in mysqltest.
- *
- * - If only 'start_timer' is given we measure how long we execute
- * from that point until we terminate mysqltest.
- *
- * - If only 'end_timer' is given we measure how long we execute
- * from that we enter mysqltest to the 'end_timer' is command is
- * executed.
- *
- * - If both 'start_timer' and 'end_timer' are given we measure
- * the time between executing the two commands.
- *
- ****************************************************************************/
- static void timer_output(void)
- {
- if (timer_file)
- {
- char buf[32], *end;
- ulonglong timer= timer_now() - timer_start;
- end= longlong2str(timer, buf, 10);
- str_to_file(timer_file,buf, (int) (end-buf));
- }
- }
- static ulonglong timer_now(void)
- {
- return my_getsystime() / 10000;
- }
- /****************************************************************************
- * Handle replacement of strings
- ****************************************************************************/
- #define PC_MALLOC 256 /* Bytes for pointers */
- #define PS_MALLOC 512 /* Bytes for data */
- #define SPACE_CHAR 256
- #define START_OF_LINE 257
- #define END_OF_LINE 258
- #define LAST_CHAR_CODE 259
- typedef struct st_replace {
- bool found;
- struct st_replace *next[256];
- } REPLACE;
- typedef struct st_replace_found {
- bool found;
- char *replace_string;
- uint to_offset;
- int from_offset;
- } REPLACE_STRING;
- #ifndef WORD_BIT
- #define WORD_BIT (8*sizeof(uint))
- #endif
- static int insert_pointer_name(reg1 POINTER_ARRAY *pa,my_string name)
- {
- uint i,length,old_count;
- byte *new_pos;
- const char **new_array;
- DBUG_ENTER("insert_pointer_name");
- if (! pa->typelib.count)
- {
- if (!(pa->typelib.type_names=(const char **)
- my_malloc(((PC_MALLOC-MALLOC_OVERHEAD)/
- (sizeof(my_string)+sizeof(*pa->flag))*
- (sizeof(my_string)+sizeof(*pa->flag))),MYF(MY_WME))))
- DBUG_RETURN(-1);
- if (!(pa->str= (byte*) my_malloc((uint) (PS_MALLOC-MALLOC_OVERHEAD),
- MYF(MY_WME))))
- {
- my_free((gptr) pa->typelib.type_names,MYF(0));
- DBUG_RETURN (-1);
- }
- pa->max_count=(PC_MALLOC-MALLOC_OVERHEAD)/(sizeof(byte*)+
- sizeof(*pa->flag));
- pa->flag= (int7*) (pa->typelib.type_names+pa->max_count);
- pa->length=0;
- pa->max_length=PS_MALLOC-MALLOC_OVERHEAD;
- pa->array_allocs=1;
- }
- length=(uint) strlen(name)+1;
- if (pa->length+length >= pa->max_length)
- {
- if (!(new_pos= (byte*) my_realloc((gptr) pa->str,
- (uint) (pa->max_length+PS_MALLOC),
- MYF(MY_WME))))
- DBUG_RETURN(1);
- if (new_pos != pa->str)
- {
- my_ptrdiff_t diff=PTR_BYTE_DIFF(new_pos,pa->str);
- for (i=0 ; i < pa->typelib.count ; i++)
- pa->typelib.type_names[i]= ADD_TO_PTR(pa->typelib.type_names[i],diff,
- char*);
- pa->str=new_pos;
- }
- pa->max_length+=PS_MALLOC;
- }
- if (pa->typelib.count >= pa->max_count-1)
- {
- int len;
- pa->array_allocs++;
- len=(PC_MALLOC*pa->array_allocs - MALLOC_OVERHEAD);
- if (!(new_array=(const char **) my_realloc((gptr) pa->typelib.type_names,
- (uint) len/
- (sizeof(byte*)+sizeof(*pa->flag))*
- (sizeof(byte*)+sizeof(*pa->flag)),
- MYF(MY_WME))))
- DBUG_RETURN(1);
- pa->typelib.type_names=new_array;
- old_count=pa->max_count;
- pa->max_count=len/(sizeof(byte*) + sizeof(*pa->flag));
- pa->flag= (int7*) (pa->typelib.type_names+pa->max_count);
- memcpy((byte*) pa->flag,(my_string) (pa->typelib.type_names+old_count),
- old_count*sizeof(*pa->flag));
- }
- pa->flag[pa->typelib.count]=0; /* Reset flag */
- pa->typelib.type_names[pa->typelib.count++]= pa->str+pa->length;
- pa->typelib.type_names[pa->typelib.count]= NullS; /* Put end-mark */
- VOID(strmov(pa->str+pa->length,name));
- pa->length+=length;
- DBUG_RETURN(0);
- } /* insert_pointer_name */
- /* free pointer array */
- void free_pointer_array(POINTER_ARRAY *pa)
- {
- if (pa->typelib.count)
- {
- pa->typelib.count=0;
- my_free((gptr) pa->typelib.type_names,MYF(0));
- pa->typelib.type_names=0;
- my_free((gptr) pa->str,MYF(0));
- }
- } /* free_pointer_array */
- /* Code for replace rutines */
- #define SET_MALLOC_HUNC 64
- typedef struct st_rep_set {
- uint *bits; /* Pointer to used sets */
- short next[LAST_CHAR_CODE]; /* Pointer to next sets */
- uint found_len; /* Best match to date */
- int found_offset;
- uint table_offset;
- uint size_of_bits; /* For convinience */
- } REP_SET;
- typedef struct st_rep_sets {
- uint count; /* Number of sets */
- uint extra; /* Extra sets in buffer */
- uint invisible; /* Sets not chown */
- uint size_of_bits;
- REP_SET *set,*set_buffer;
- uint *bit_buffer;
- } REP_SETS;
- typedef struct st_found_set {
- uint table_offset;
- int found_offset;
- } FOUND_SET;
- typedef struct st_follow {
- int chr;
- uint table_offset;
- uint len;
- } FOLLOWS;
- static int init_sets(REP_SETS *sets,uint states);
- static REP_SET *make_new_set(REP_SETS *sets);
- static void make_sets_invisible(REP_SETS *sets);
- static void free_last_set(REP_SETS *sets);
- static void free_sets(REP_SETS *sets);
- static void internal_set_bit(REP_SET *set, uint bit);
- static void internal_clear_bit(REP_SET *set, uint bit);
- static void or_bits(REP_SET *to,REP_SET *from);
- static void copy_bits(REP_SET *to,REP_SET *from);
- static int cmp_bits(REP_SET *set1,REP_SET *set2);
- static int get_next_bit(REP_SET *set,uint lastpos);
- static int find_set(REP_SETS *sets,REP_SET *find);
- static int find_found(FOUND_SET *found_set,uint table_offset,
- int found_offset);
- static uint start_at_word(my_string pos);
- static uint end_of_word(my_string pos);
- static uint replace_len(my_string pos);
- static uint found_sets=0;
- /* Init a replace structure for further calls */
- REPLACE *init_replace(my_string *from, my_string *to,uint count,
- my_string word_end_chars)
- {
- uint i,j,states,set_nr,len,result_len,max_length,found_end,bits_set,bit_nr;
- int used_sets,chr,default_state;
- char used_chars[LAST_CHAR_CODE],is_word_end[256];
- my_string pos,to_pos,*to_array;
- REP_SETS sets;
- REP_SET *set,*start_states,*word_states,*new_set;
- FOLLOWS *follow,*follow_ptr;
- REPLACE *replace;
- FOUND_SET *found_set;
- REPLACE_STRING *rep_str;
- DBUG_ENTER("init_replace");
- /* Count number of states */
- for (i=result_len=max_length=0 , states=2 ; i < count ; i++)
- {
- len=replace_len(from[i]);
- if (!len)
- {
- errno=EINVAL;
- my_message(0,"No to-string for last from-string",MYF(ME_BELL));
- DBUG_RETURN(0);
- }
- states+=len+1;
- result_len+=(uint) strlen(to[i])+1;
- if (len > max_length)
- max_length=len;
- }
- bzero((char*) is_word_end,sizeof(is_word_end));
- for (i=0 ; word_end_chars[i] ; i++)
- is_word_end[(uchar) word_end_chars[i]]=1;
- if (init_sets(&sets,states))
- DBUG_RETURN(0);
- found_sets=0;
- if (!(found_set= (FOUND_SET*) my_malloc(sizeof(FOUND_SET)*max_length*count,
- MYF(MY_WME))))
- {
- free_sets(&sets);
- DBUG_RETURN(0);
- }
- VOID(make_new_set(&sets)); /* Set starting set */
- make_sets_invisible(&sets); /* Hide previus sets */
- used_sets=-1;
- word_states=make_new_set(&sets); /* Start of new word */
- start_states=make_new_set(&sets); /* This is first state */
- if (!(follow=(FOLLOWS*) my_malloc((states+2)*sizeof(FOLLOWS),MYF(MY_WME))))
- {
- free_sets(&sets);
- my_free((gptr) found_set,MYF(0));
- DBUG_RETURN(0);
- }
- /* Init follow_ptr[] */
- for (i=0, states=1, follow_ptr=follow+1 ; i < count ; i++)
- {
- if (from[i][0] == '\' && from[i][1] == '^')
- {
- internal_set_bit(start_states,states+1);
- if (!from[i][2])
- {
- start_states->table_offset=i;
- start_states->found_offset=1;
- }
- }
- else if (from[i][0] == '\' && from[i][1] == '$')
- {
- internal_set_bit(start_states,states);
- internal_set_bit(word_states,states);
- if (!from[i][2] && start_states->table_offset == (uint) ~0)
- {
- start_states->table_offset=i;
- start_states->found_offset=0;
- }
- }
- else
- {
- internal_set_bit(word_states,states);
- if (from[i][0] == '\' && (from[i][1] == 'b' && from[i][2]))
- internal_set_bit(start_states,states+1);
- else
- internal_set_bit(start_states,states);
- }
- for (pos=from[i], len=0; *pos ; pos++)
- {
- if (*pos == '\' && *(pos+1))
- {
- pos++;
- switch (*pos) {
- case 'b':
- follow_ptr->chr = SPACE_CHAR;
- break;
- case '^':
- follow_ptr->chr = START_OF_LINE;
- break;
- case '$':
- follow_ptr->chr = END_OF_LINE;
- break;
- case 'r':
- follow_ptr->chr = 'r';
- break;
- case 't':
- follow_ptr->chr = 't';
- break;
- case 'v':
- follow_ptr->chr = 'v';
- break;
- default:
- follow_ptr->chr = (uchar) *pos;
- break;
- }
- }
- else
- follow_ptr->chr= (uchar) *pos;
- follow_ptr->table_offset=i;
- follow_ptr->len= ++len;
- follow_ptr++;
- }
- follow_ptr->chr=0;
- follow_ptr->table_offset=i;
- follow_ptr->len=len;
- follow_ptr++;
- states+=(uint) len+1;
- }
- for (set_nr=0,pos=0 ; set_nr < sets.count ; set_nr++)
- {
- set=sets.set+set_nr;
- default_state= 0; /* Start from beginning */
- /* If end of found-string not found or start-set with current set */
- for (i= (uint) ~0; (i=get_next_bit(set,i)) ;)
- {
- if (!follow[i].chr)
- {
- if (! default_state)
- default_state= find_found(found_set,set->table_offset,
- set->found_offset+1);
- }
- }
- copy_bits(sets.set+used_sets,set); /* Save set for changes */
- if (!default_state)
- or_bits(sets.set+used_sets,sets.set); /* Can restart from start */
- /* Find all chars that follows current sets */
- bzero((char*) used_chars,sizeof(used_chars));
- for (i= (uint) ~0; (i=get_next_bit(sets.set+used_sets,i)) ;)
- {
- used_chars[follow[i].chr]=1;
- if ((follow[i].chr == SPACE_CHAR && !follow[i+1].chr &&
- follow[i].len > 1) || follow[i].chr == END_OF_LINE)
- used_chars[0]=1;
- }
- /* Mark word_chars used if b is in state */
- if (used_chars[SPACE_CHAR])
- for (pos= word_end_chars ; *pos ; pos++)
- used_chars[(int) (uchar) *pos] = 1;
- /* Handle other used characters */
- for (chr= 0 ; chr < 256 ; chr++)
- {
- if (! used_chars[chr])
- set->next[chr]= chr ? default_state : -1;
- else
- {
- new_set=make_new_set(&sets);
- set=sets.set+set_nr; /* if realloc */
- new_set->table_offset=set->table_offset;
- new_set->found_len=set->found_len;
- new_set->found_offset=set->found_offset+1;
- found_end=0;
- for (i= (uint) ~0 ; (i=get_next_bit(sets.set+used_sets,i)) ; )
- {
- if (!follow[i].chr || follow[i].chr == chr ||
- (follow[i].chr == SPACE_CHAR &&
- (is_word_end[chr] ||
- (!chr && follow[i].len > 1 && ! follow[i+1].chr))) ||
- (follow[i].chr == END_OF_LINE && ! chr))
- {
- if ((! chr || (follow[i].chr && !follow[i+1].chr)) &&
- follow[i].len > found_end)
- found_end=follow[i].len;
- if (chr && follow[i].chr)
- internal_set_bit(new_set,i+1); /* To next set */
- else
- internal_set_bit(new_set,i);
- }
- }
- if (found_end)
- {
- new_set->found_len=0; /* Set for testing if first */
- bits_set=0;
- for (i= (uint) ~0; (i=get_next_bit(new_set,i)) ;)
- {
- if ((follow[i].chr == SPACE_CHAR ||
- follow[i].chr == END_OF_LINE) && ! chr)
- bit_nr=i+1;
- else
- bit_nr=i;
- if (follow[bit_nr-1].len < found_end ||
- (new_set->found_len &&
- (chr == 0 || !follow[bit_nr].chr)))
- internal_clear_bit(new_set,i);
- else
- {
- if (chr == 0 || !follow[bit_nr].chr)
- { /* best match */
- new_set->table_offset=follow[bit_nr].table_offset;
- if (chr || (follow[i].chr == SPACE_CHAR ||
- follow[i].chr == END_OF_LINE))
- new_set->found_offset=found_end; /* New match */
- new_set->found_len=found_end;
- }
- bits_set++;
- }
- }
- if (bits_set == 1)
- {
- set->next[chr] = find_found(found_set,
- new_set->table_offset,
- new_set->found_offset);
- free_last_set(&sets);
- }
- else
- set->next[chr] = find_set(&sets,new_set);
- }
- else
- set->next[chr] = find_set(&sets,new_set);
- }
- }
- }
- /* Alloc replace structure for the replace-state-machine */
- if ((replace=(REPLACE*) my_malloc(sizeof(REPLACE)*(sets.count)+
- sizeof(REPLACE_STRING)*(found_sets+1)+
- sizeof(my_string)*count+result_len,
- MYF(MY_WME | MY_ZEROFILL))))
- {
- rep_str=(REPLACE_STRING*) (replace+sets.count);
- to_array=(my_string*) (rep_str+found_sets+1);
- to_pos=(my_string) (to_array+count);
- for (i=0 ; i < count ; i++)
- {
- to_array[i]=to_pos;
- to_pos=strmov(to_pos,to[i])+1;
- }
- rep_str[0].found=1;
- rep_str[0].replace_string=0;
- for (i=1 ; i <= found_sets ; i++)
- {
- pos=from[found_set[i-1].table_offset];
- rep_str[i].found= !bcmp(pos,"\^",3) ? 2 : 1;
- rep_str[i].replace_string=to_array[found_set[i-1].table_offset];
- rep_str[i].to_offset=found_set[i-1].found_offset-start_at_word(pos);
- rep_str[i].from_offset=found_set[i-1].found_offset-replace_len(pos)+
- end_of_word(pos);
- }
- for (i=0 ; i < sets.count ; i++)
- {
- for (j=0 ; j < 256 ; j++)
- if (sets.set[i].next[j] >= 0)
- replace[i].next[j]=replace+sets.set[i].next[j];
- else
- replace[i].next[j]=(REPLACE*) (rep_str+(-sets.set[i].next[j]-1));
- }
- }
- my_free((gptr) follow,MYF(0));
- free_sets(&sets);
- my_free((gptr) found_set,MYF(0));
- DBUG_PRINT("exit",("Replace table has %d states",sets.count));
- DBUG_RETURN(replace);
- }
- static int init_sets(REP_SETS *sets,uint states)
- {
- bzero((char*) sets,sizeof(*sets));
- sets->size_of_bits=((states+7)/8);
- if (!(sets->set_buffer=(REP_SET*) my_malloc(sizeof(REP_SET)*SET_MALLOC_HUNC,
- MYF(MY_WME))))
- return 1;
- if (!(sets->bit_buffer=(uint*) my_malloc(sizeof(uint)*sets->size_of_bits*
- SET_MALLOC_HUNC,MYF(MY_WME))))
- {
- my_free((gptr) sets->set,MYF(0));
- return 1;
- }
- return 0;
- }
- /* Make help sets invisible for nicer codeing */
- static void make_sets_invisible(REP_SETS *sets)
- {
- sets->invisible=sets->count;
- sets->set+=sets->count;
- sets->count=0;
- }
- static REP_SET *make_new_set(REP_SETS *sets)
- {
- uint i,count,*bit_buffer;
- REP_SET *set;
- if (sets->extra)
- {
- sets->extra--;
- set=sets->set+ sets->count++;
- bzero((char*) set->bits,sizeof(uint)*sets->size_of_bits);
- bzero((char*) &set->next[0],sizeof(set->next[0])*LAST_CHAR_CODE);
- set->found_offset=0;
- set->found_len=0;
- set->table_offset= (uint) ~0;
- set->size_of_bits=sets->size_of_bits;
- return set;
- }
- count=sets->count+sets->invisible+SET_MALLOC_HUNC;
- if (!(set=(REP_SET*) my_realloc((gptr) sets->set_buffer,
- sizeof(REP_SET)*count,
- MYF(MY_WME))))
- return 0;
- sets->set_buffer=set;
- sets->set=set+sets->invisible;
- if (!(bit_buffer=(uint*) my_realloc((gptr) sets->bit_buffer,
- (sizeof(uint)*sets->size_of_bits)*count,
- MYF(MY_WME))))
- return 0;
- sets->bit_buffer=bit_buffer;
- for (i=0 ; i < count ; i++)
- {
- sets->set_buffer[i].bits=bit_buffer;
- bit_buffer+=sets->size_of_bits;
- }
- sets->extra=SET_MALLOC_HUNC;
- return make_new_set(sets);
- }
- static void free_last_set(REP_SETS *sets)
- {
- sets->count--;
- sets->extra++;
- return;
- }
- static void free_sets(REP_SETS *sets)
- {
- my_free((gptr)sets->set_buffer,MYF(0));
- my_free((gptr)sets->bit_buffer,MYF(0));
- return;
- }
- static void internal_set_bit(REP_SET *set, uint bit)
- {
- set->bits[bit / WORD_BIT] |= 1 << (bit % WORD_BIT);
- return;
- }
- static void internal_clear_bit(REP_SET *set, uint bit)
- {
- set->bits[bit / WORD_BIT] &= ~ (1 << (bit % WORD_BIT));
- return;
- }
- static void or_bits(REP_SET *to,REP_SET *from)
- {
- reg1 uint i;
- for (i=0 ; i < to->size_of_bits ; i++)
- to->bits[i]|=from->bits[i];
- return;
- }
- static void copy_bits(REP_SET *to,REP_SET *from)
- {
- memcpy((byte*) to->bits,(byte*) from->bits,
- (size_t) (sizeof(uint) * to->size_of_bits));
- }
- static int cmp_bits(REP_SET *set1,REP_SET *set2)
- {
- return bcmp((byte*) set1->bits,(byte*) set2->bits,
- sizeof(uint) * set1->size_of_bits);
- }
- /* Get next set bit from set. */
- static int get_next_bit(REP_SET *set,uint lastpos)
- {
- uint pos,*start,*end,bits;
- start=set->bits+ ((lastpos+1) / WORD_BIT);
- end=set->bits + set->size_of_bits;
- bits=start[0] & ~((1 << ((lastpos+1) % WORD_BIT)) -1);
- while (! bits && ++start < end)
- bits=start[0];
- if (!bits)
- return 0;
- pos=(uint) (start-set->bits)*WORD_BIT;
- while (! (bits & 1))
- {
- bits>>=1;
- pos++;
- }
- return pos;
- }
- /* find if there is a same set in sets. If there is, use it and
- free given set, else put in given set in sets and return it's
- position */
- static int find_set(REP_SETS *sets,REP_SET *find)
- {
- uint i;
- for (i=0 ; i < sets->count-1 ; i++)
- {
- if (!cmp_bits(sets->set+i,find))
- {
- free_last_set(sets);
- return i;
- }
- }
- return i; /* return new postion */
- }
- /* find if there is a found_set with same table_offset & found_offset
- If there is return offset to it, else add new offset and return pos.
- Pos returned is -offset-2 in found_set_structure because it's is
- saved in set->next and set->next[] >= 0 points to next set and
- set->next[] == -1 is reserved for end without replaces.
- */
- static int find_found(FOUND_SET *found_set,uint table_offset, int found_offset)
- {
- int i;
- for (i=0 ; (uint) i < found_sets ; i++)
- if (found_set[i].table_offset == table_offset &&
- found_set[i].found_offset == found_offset)
- return -i-2;
- found_set[i].table_offset=table_offset;
- found_set[i].found_offset=found_offset;
- found_sets++;
- return -i-2; /* return new postion */
- }
- /* Return 1 if regexp starts with b or ends with b*/
- static uint start_at_word(my_string pos)
- {
- return (((!bcmp(pos,"\b",2) && pos[2]) || !bcmp(pos,"\^",2)) ? 1 : 0);
- }
- static uint end_of_word(my_string pos)
- {
- my_string end=strend(pos);
- return ((end > pos+2 && !bcmp(end-2,"\b",2)) ||
- (end >= pos+2 && !bcmp(end-2,"\$",2))) ?
- 1 : 0;
- }
- static uint replace_len(my_string str)
- {
- uint len=0;
- while (*str)
- {
- if (str[0] == '\' && str[1])
- str++;
- str++;
- len++;
- }
- return len;
- }
- /* Replace strings; Return length of result string */
- uint replace_strings(REPLACE *rep, my_string *start,uint *max_length,
- const char *from)
- {
- reg1 REPLACE *rep_pos;
- reg2 REPLACE_STRING *rep_str;
- my_string to,end,pos,new_str;
- end=(to= *start) + *max_length-1;
- rep_pos=rep+1;
- for (;;)
- {
- while (!rep_pos->found)
- {
- rep_pos= rep_pos->next[(uchar) *from];
- if (to == end)
- {
- (*max_length)+=8192;
- if (!(new_str=my_realloc(*start,*max_length,MYF(MY_WME))))
- return (uint) -1;
- to=new_str+(to - *start);
- end=(*start=new_str)+ *max_length-1;
- }
- *to++= *from++;
- }
- if (!(rep_str = ((REPLACE_STRING*) rep_pos))->replace_string)
- return (uint) (to - *start)-1;
- to-=rep_str->to_offset;
- for (pos=rep_str->replace_string; *pos ; pos++)
- {
- if (to == end)
- {
- (*max_length)*=2;
- if (!(new_str=my_realloc(*start,*max_length,MYF(MY_WME))))
- return (uint) -1;
- to=new_str+(to - *start);
- end=(*start=new_str)+ *max_length-1;
- }
- *to++= *pos;
- }
- if (!*(from-=rep_str->from_offset) && rep_pos->found != 2)
- return (uint) (to - *start);
- rep_pos=rep;
- }
- }
- static int initialize_replace_buffer(void)
- {
- out_length=8192;
- if (!(out_buff=my_malloc(out_length,MYF(MY_WME))))
- return(1);
- return 0;
- }
- static void free_replace_buffer(void)
- {
- my_free(out_buff,MYF(MY_WME));
- }
- /****************************************************************************
- Replace results for a column
- *****************************************************************************/
- static void free_replace_column()
- {
- uint i;
- for (i=0 ; i < max_replace_column ; i++)
- {
- if (replace_column[i])
- {
- my_free(replace_column[i], 0);
- replace_column[i]= 0;
- }
- }
- max_replace_column= 0;
- }
- /*
- Get arguments for replace_columns. The syntax is:
- replace-column column_number to_string [column_number to_string ...]
- Where each argument may be quoted with ' or "
- A argument may also be a variable, in which case the value of the
- variable is replaced.
- */
- static void get_replace_column(struct st_query *q)
- {
- char *from=q->first_argument;
- char *buff,*start;
- DBUG_ENTER("get_replace_columns");
- free_replace_column();
- if (!*from)
- die("Missing argument in %s", q->query);
- /* Allocate a buffer for results */
- start=buff=my_malloc(strlen(from)+1,MYF(MY_WME | MY_FAE));
- while (*from)
- {
- char *to;
- uint column_number;
- to= get_string(&buff, &from, q);
- if (!(column_number= atoi(to)) || column_number > MAX_COLUMNS)
- die("Wrong column number to replace_column in '%s'", q->query);
- if (!*from)
- die("Wrong number of arguments to replace_column in '%s'", q->query);
- to= get_string(&buff, &from, q);
- my_free(replace_column[column_number-1], MY_ALLOW_ZERO_PTR);
- replace_column[column_number-1]= my_strdup(to, MYF(MY_WME | MY_FAE));
- set_if_bigger(max_replace_column, column_number);
- }
- my_free(start, MYF(0));
- q->last_argument= q->end;
- }
- #if defined(__NETWARE__) || defined(__WIN__)
- /*
- Substitute environment variables with text.
- SYNOPSIS
- subst_env_var()
- arg String that should be substitute
- DESCRIPTION
- This function takes a string as an input and replaces the
- environment variables, that starts with '$' character, with it value.
- NOTES
- Return string must be freed with my_free()
- RETURN
- String with environment variables replaced.
- */
- static char *subst_env_var(const char *str)
- {
- char *result;
- char *pos;
- result= pos= my_malloc(MAX_QUERY, MYF(MY_FAE));
- while (*str)
- {
- /*
- need this only when we want to provide the functionality of
- escaping through 'backslash'
- if ((result == pos && *str=='$') ||
- (result != pos && *str=='$' && str[-1] !='\'))
- */
- if (*str == '$')
- {
- char env_var[256], *env_pos= env_var, *subst;
- /* Search for end of environment variable */
- for (str++;
- *str && !isspace(*str) && *str != '\' && *str != '/' &&
- *str != '$';
- str++)
- *env_pos++= *str;
- *env_pos= 0;
- if (!(subst= getenv(env_var)))
- {
- my_free(result, MYF(0));
- die("MYSQLTEST.NLM: Environment variable %s is not defined",
- env_var);
- }
- /* get the string to be substitued for env_var */
- pos= strmov(pos, subst);
- /* Process delimiter in *str again */
- }
- else
- *pos++= *str++;
- }
- *pos= 0;
- return result;
- }
- /*
- popen replacement for Netware
- SYNPOSIS
- my_popen()
- name Command to execute (with possible env variables)
- mode Mode for popen.
- NOTES
- Environment variable expansion does not take place for popen function
- on NetWare, so we use this function to wrap around popen to do this.
- For the moment we ignore 'mode' and always use 'r0'
- RETURN
- # >= 0 File handle
- -1 Error
- */
- #undef popen /* Remove wrapper */
- #ifdef __WIN__
- #define popen _popen /* redefine for windows */
- #endif
- FILE *my_popen(const char *cmd, const char *mode __attribute__((unused)))
- {
- char *subst_cmd;
- FILE *res_file;
- subst_cmd= subst_env_var(cmd);
- res_file= popen(subst_cmd, "r0");
- my_free(subst_cmd, MYF(0));
- return res_file;
- }
- #endif /* __NETWARE__ or __WIN__*/