mysqltest.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:133k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 2000 MySQL AB
  2.    This program is free software; you can redistribute it and/or modify
  3.    it under the terms of the GNU General Public License as published by
  4.    the Free Software Foundation; either version 2 of the License, or
  5.    (at your option) any later version.
  6.    This program is distributed in the hope that it will be useful,
  7.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  8.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  9.    GNU General Public License for more details.
  10.    You should have received a copy of the GNU General Public License
  11.    along with this program; if not, write to the Free Software
  12.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  13. /* mysqltest test tool
  14.  * See the manual for more information
  15.  * TODO: document better how mysqltest works
  16.  *
  17.  * Written by:
  18.  *   Sasha Pachev <sasha@mysql.com>
  19.  *   Matt Wagner  <matt@mysql.com>
  20.  *   Monty
  21.  *   Jani
  22.  **/
  23. /**********************************************************************
  24.   TODO:
  25. - Do comparison line by line, instead of doing a full comparison of
  26.   the text file.  This will save space as we don't need to keep many
  27.   results in memory.  It will also make it possible to do simple
  28.   'comparison' fixes like accepting the result even if a float differed
  29.   in the last decimals.
  30. - Don't buffer lines from the test that you don't expect to need
  31.   again.
  32. - Change 'read_line' to be faster by using the readline.cc code;
  33.   We can do better than calling feof() for each character!
  34. **********************************************************************/
  35. #define MTEST_VERSION "2.5"
  36. #include <my_global.h>
  37. #include <mysql_embed.h>
  38. #include <my_sys.h>
  39. #include <m_string.h>
  40. #include <mysql.h>
  41. #include <mysql_version.h>
  42. #include <mysqld_error.h>
  43. #include <m_ctype.h>
  44. #include <my_dir.h>
  45. #include <errmsg.h>                       /* Error codes */
  46. #include <hash.h>
  47. #include <my_getopt.h>
  48. #include <stdarg.h>
  49. #include <sys/stat.h>
  50. #include <violite.h>
  51. #include "my_regex.h"                     /* Our own version of lib */
  52. #ifdef HAVE_SYS_WAIT_H
  53. #include <sys/wait.h>
  54. #endif
  55. #ifndef WEXITSTATUS
  56. # ifdef __WIN__
  57. #  define WEXITSTATUS(stat_val) (stat_val)
  58. # else
  59. #  define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
  60. # endif
  61. #endif
  62. #define MAX_QUERY     131072
  63. #define MAX_VAR_NAME 256
  64. #define MAX_COLUMNS 256
  65. #define PAD_SIZE 128
  66. #define MAX_CONS 128
  67. #define MAX_INCLUDE_DEPTH 16
  68. #define LAZY_GUESS_BUF_SIZE 8192
  69. #define INIT_Q_LINES   1024
  70. #define MIN_VAR_ALLOC   32
  71. #define BLOCK_STACK_DEPTH  32
  72. #define MAX_EXPECTED_ERRORS 10
  73. #define QUERY_SEND  1
  74. #define QUERY_REAP  2
  75. #ifndef MYSQL_MANAGER_PORT
  76. #define MYSQL_MANAGER_PORT 23546
  77. #endif
  78. #define MAX_SERVER_ARGS 64
  79. /*
  80.   Sometimes in a test the client starts before
  81.   the server - to solve the problem, we try again
  82.   after some sleep if connection fails the first
  83.   time
  84. */
  85. #define CON_RETRY_SLEEP 2
  86. #define MAX_CON_TRIES 5
  87. #define SLAVE_POLL_INTERVAL 300000 /* 0.3 of a sec */
  88. #define DEFAULT_DELIMITER ";"
  89. #define MAX_DELIMITER 16
  90. #define RESULT_OK 0
  91. #define RESULT_CONTENT_MISMATCH 1
  92. #define RESULT_LENGTH_MISMATCH 2
  93. enum {OPT_MANAGER_USER=256,OPT_MANAGER_HOST,OPT_MANAGER_PASSWD,
  94.       OPT_MANAGER_PORT,OPT_MANAGER_WAIT_TIMEOUT, OPT_SKIP_SAFEMALLOC,
  95.       OPT_SSL_SSL, OPT_SSL_KEY, OPT_SSL_CERT, OPT_SSL_CA, OPT_SSL_CAPATH,
  96.       OPT_SSL_CIPHER,OPT_PS_PROTOCOL};
  97. /* ************************************************************************ */
  98. /*
  99.   The list of error codes to --error are stored in an internal array of
  100.   structs. This struct can hold numeric SQL error codes or SQLSTATE codes
  101.   as strings. The element next to the last active element in the list is
  102.   set to type ERR_EMPTY. When an SQL statement return an error we use
  103.   this list to check if this  is an expected error.
  104. */
  105.  
  106. enum match_err_type
  107. {
  108.   ERR_EMPTY= 0,
  109.   ERR_ERRNO,
  110.   ERR_SQLSTATE
  111. };
  112. typedef struct
  113. {
  114.   enum match_err_type type;
  115.   union
  116.   {
  117.     uint errnum;
  118.     char sqlstate[SQLSTATE_LENGTH+1];  /*  terminated string */
  119.   } code;
  120. } match_err;
  121. static match_err global_expected_errno[MAX_EXPECTED_ERRORS];
  122. static uint global_expected_errors;
  123. /* ************************************************************************ */
  124. static int record = 0, opt_sleep=0;
  125. static char *db = 0, *pass=0;
  126. const char *user = 0, *host = 0, *unix_sock = 0, *opt_basedir="./";
  127. static int port = 0;
  128. static my_bool opt_big_test= 0, opt_compress= 0, silent= 0, verbose = 0;
  129. static my_bool tty_password= 0, ps_protocol= 0, ps_protocol_enabled= 0;
  130. static uint start_lineno, *lineno;
  131. const char *manager_user="root",*manager_host=0;
  132. char *manager_pass=0;
  133. int manager_port=MYSQL_MANAGER_PORT;
  134. int manager_wait_timeout=3;
  135. MYSQL_MANAGER* manager=0;
  136. static char **default_argv;
  137. static const char *load_default_groups[]= { "mysqltest","client",0 };
  138. static char line_buffer[MAX_DELIMITER], *line_buffer_pos= line_buffer;
  139. typedef struct
  140. {
  141.   FILE* file;
  142.   const char *file_name;
  143. } test_file;
  144. static test_file file_stack[MAX_INCLUDE_DEPTH];
  145. static test_file* cur_file;
  146. static test_file* file_stack_end;
  147. static uint lineno_stack[MAX_INCLUDE_DEPTH];
  148. static char TMPDIR[FN_REFLEN];
  149. static char delimiter[MAX_DELIMITER]= DEFAULT_DELIMITER;
  150. static uint delimiter_length= 1;
  151. static CHARSET_INFO *charset_info= &my_charset_latin1; /* Default charset */
  152. static const char *charset_name= "latin1"; /* Default character set name */
  153. static int embedded_server_arg_count=0;
  154. static char *embedded_server_args[MAX_SERVER_ARGS];
  155. static my_bool display_result_vertically= FALSE, display_metadata= FALSE;
  156. /* See the timer_output() definition for details */
  157. static char *timer_file = NULL;
  158. static ulonglong timer_start;
  159. static int got_end_timer= FALSE;
  160. static void timer_output(void);
  161. static ulonglong timer_now(void);
  162. static my_regex_t ps_re; /* Holds precompiled re for valid PS statements */
  163. static void ps_init_re(void);
  164. static int ps_match_re(char *);
  165. static char *ps_eprint(int);
  166. static void ps_free_reg(void);
  167. static const char *embedded_server_groups[] = {
  168.   "server",
  169.   "embedded",
  170.   "mysqltest_SERVER",
  171.   NullS
  172. };
  173. DYNAMIC_ARRAY q_lines;
  174. #include "sslopt-vars.h"
  175. typedef struct
  176. {
  177.   char file[FN_REFLEN];
  178.   ulong pos;
  179. } MASTER_POS ;
  180. struct connection
  181. {
  182.   MYSQL mysql;
  183.   char *name;
  184. };
  185. typedef struct
  186. {
  187.   int read_lines,current_line;
  188. } PARSER;
  189. MYSQL_RES *last_result=0;
  190. PARSER parser;
  191. MASTER_POS master_pos;
  192. /* if set, all results are concated and compared against this file */
  193. const char *result_file = 0;
  194. typedef struct
  195. {
  196.   char *name;
  197.   int name_len;
  198.   char *str_val;
  199.   int str_val_len;
  200.   int int_val;
  201.   int alloced_len;
  202.   int int_dirty; /* do not update string if int is updated until first read */
  203.   int alloced;
  204. } VAR;
  205. #if defined(__NETWARE__) || defined(__WIN__)
  206. /*
  207.   Netware doesn't proved environment variable substitution that is done
  208.   by the shell in unix environments. We do this in the following function:
  209. */
  210. static char *subst_env_var(const char *cmd);
  211. static FILE *my_popen(const char *cmd, const char *mode);
  212. #define popen(A,B) my_popen((A),(B))
  213. #endif /* __NETWARE__ */
  214. VAR var_reg[10];
  215. /*Perl/shell-like variable registers */
  216. HASH var_hash;
  217. my_bool disable_query_log=0, disable_result_log=0, disable_warnings=0;
  218. my_bool disable_info= 1; /* By default off */
  219. my_bool abort_on_error= 1;
  220. struct connection cons[MAX_CONS];
  221. struct connection* cur_con, *next_con, *cons_end;
  222.   /* Add new commands before Q_UNKNOWN !*/
  223. enum enum_commands {
  224. Q_CONNECTION=1,     Q_QUERY,
  225. Q_CONNECT,     Q_SLEEP, Q_REAL_SLEEP, 
  226. Q_INC,     Q_DEC,
  227. Q_SOURCE,     Q_DISCONNECT,
  228. Q_LET,     Q_ECHO,
  229. Q_WHILE,     Q_END_BLOCK,
  230. Q_SYSTEM,     Q_RESULT,
  231. Q_REQUIRE,     Q_SAVE_MASTER_POS,
  232. Q_SYNC_WITH_MASTER,
  233. Q_SYNC_SLAVE_WITH_MASTER,
  234. Q_ERROR,
  235. Q_SEND,     Q_REAP,
  236. Q_DIRTY_CLOSE,     Q_REPLACE, Q_REPLACE_COLUMN,
  237. Q_PING,     Q_EVAL,
  238. Q_RPL_PROBE,     Q_ENABLE_RPL_PARSE,
  239. Q_DISABLE_RPL_PARSE, Q_EVAL_RESULT,
  240. Q_ENABLE_QUERY_LOG, Q_DISABLE_QUERY_LOG,
  241. Q_ENABLE_RESULT_LOG, Q_DISABLE_RESULT_LOG,
  242. Q_SERVER_START, Q_SERVER_STOP,Q_REQUIRE_MANAGER,
  243. Q_WAIT_FOR_SLAVE_TO_STOP,
  244. Q_ENABLE_WARNINGS, Q_DISABLE_WARNINGS,
  245. Q_ENABLE_INFO, Q_DISABLE_INFO,
  246. Q_ENABLE_METADATA, Q_DISABLE_METADATA,
  247. Q_EXEC, Q_DELIMITER,
  248. Q_DISABLE_ABORT_ON_ERROR, Q_ENABLE_ABORT_ON_ERROR,
  249. Q_DISPLAY_VERTICAL_RESULTS, Q_DISPLAY_HORIZONTAL_RESULTS,
  250. Q_QUERY_VERTICAL, Q_QUERY_HORIZONTAL,
  251. Q_START_TIMER, Q_END_TIMER,
  252. Q_CHARACTER_SET, Q_DISABLE_PS_PROTOCOL, Q_ENABLE_PS_PROTOCOL,
  253. Q_EXIT,
  254. Q_DISABLE_RECONNECT, Q_ENABLE_RECONNECT,
  255. Q_IF,
  256. Q_UNKNOWN,        /* Unknown command.   */
  257. Q_COMMENT,        /* Comments, ignored. */
  258. Q_COMMENT_WITH_COMMAND
  259. };
  260. /* this should really be called command */
  261. struct st_query
  262. {
  263.   char *query, *query_buf,*first_argument,*last_argument,*end;
  264.   int first_word_len;
  265.   my_bool abort_on_error, require_file;
  266.   match_err expected_errno[MAX_EXPECTED_ERRORS];
  267.   uint expected_errors;
  268.   char record_file[FN_REFLEN];
  269.   enum enum_commands type;
  270. };
  271. const char *command_names[]=
  272. {
  273.   "connection",
  274.   "query",
  275.   "connect",
  276.   /* the difference between sleep and real_sleep is that sleep will use
  277.      the delay from command line (--sleep) if there is one.
  278.      real_sleep always uses delay from mysqltest's command line argument.
  279.      the logic is that sometimes delays are cpu-dependent (and --sleep
  280.      can be used to set this delay. real_sleep is used for cpu-independent
  281.      delays
  282.    */
  283.   "sleep",
  284.   "real_sleep",
  285.   "inc",
  286.   "dec",
  287.   "source",
  288.   "disconnect",
  289.   "let",
  290.   "echo",
  291.   "while",
  292.   "end",
  293.   "system",
  294.   "result",
  295.   "require",
  296.   "save_master_pos",
  297.   "sync_with_master",
  298.   "sync_slave_with_master",
  299.   "error",
  300.   "send",
  301.   "reap",
  302.   "dirty_close",
  303.   "replace_result",
  304.   "replace_column",
  305.   "ping",
  306.   "eval",
  307.   "rpl_probe",
  308.   "enable_rpl_parse",
  309.   "disable_rpl_parse",
  310.   "eval_result",
  311.   "enable_query_log",
  312.   "disable_query_log",
  313.   "enable_result_log",
  314.   "disable_result_log",
  315.   "server_start",
  316.   "server_stop",
  317.   "require_manager",
  318.   "wait_for_slave_to_stop",
  319.   "enable_warnings",
  320.   "disable_warnings",
  321.   "enable_info",
  322.   "disable_info",
  323.   "enable_metadata",
  324.   "disable_metadata",
  325.   "exec",
  326.   "delimiter",
  327.   "disable_abort_on_error",
  328.   "enable_abort_on_error",
  329.   "vertical_results",
  330.   "horizontal_results",
  331.   "query_vertical",
  332.   "query_horizontal",
  333.   "start_timer",
  334.   "end_timer",
  335.   "character_set",
  336.   "disable_ps_protocol",
  337.   "enable_ps_protocol",
  338.   "exit",
  339.   "disable_reconnect",
  340.   "enable_reconnect",
  341.   "if",
  342.   0
  343. };
  344. /* Block stack */
  345. typedef struct
  346. {
  347.   int                 line; /* Start line of block */
  348.   my_bool             ok;   /* Should block be executed */
  349.   enum enum_commands  cmd;  /* Command owning the block */
  350. } BLOCK;
  351. static BLOCK block_stack[BLOCK_STACK_DEPTH];
  352. static BLOCK *cur_block, *block_stack_end;
  353. TYPELIB command_typelib= {array_elements(command_names),"",
  354.   command_names, 0};
  355. DYNAMIC_STRING ds_res;
  356. static void die(const char *fmt, ...);
  357. static void init_var_hash();
  358. static VAR* var_from_env(const char *, const char *);
  359. static byte* get_var_key(const byte* rec, uint* len, my_bool t);
  360. static VAR* var_init(VAR* v, const char *name, int name_len, const char *val,
  361.      int val_len);
  362. static void var_free(void* v);
  363. int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname);
  364. void reject_dump(const char *record_file, char *buf, int size);
  365. int close_connection(struct st_query*);
  366. static void set_charset(struct st_query*);
  367. VAR* var_get(const char *var_name, const char** var_name_end, my_bool raw,
  368.      my_bool ignore_not_existing);
  369. int eval_expr(VAR* v, const char *p, const char** p_end);
  370. static int read_server_arguments(const char *name);
  371. /* Definitions for replace result */
  372. typedef struct st_pointer_array { /* when using array-strings */
  373.   TYPELIB typelib; /* Pointer to strings */
  374.   byte *str; /* Strings is here */
  375.   int7 *flag; /* Flag about each var. */
  376.   uint array_allocs,max_count,length,max_length;
  377. } POINTER_ARRAY;
  378. struct st_replace;
  379. struct st_replace *init_replace(my_string *from, my_string *to, uint count,
  380. my_string word_end_chars);
  381. uint replace_strings(struct st_replace *rep, my_string *start,
  382.      uint *max_length, const char *from);
  383. void free_replace();
  384. static int insert_pointer_name(reg1 POINTER_ARRAY *pa,my_string name);
  385. void free_pointer_array(POINTER_ARRAY *pa);
  386. static int initialize_replace_buffer(void);
  387. static void free_replace_buffer(void);
  388. static void do_eval(DYNAMIC_STRING *query_eval, const char *query);
  389. void str_to_file(const char *fname, char *str, int size);
  390. int do_server_op(struct st_query *q,const char *op);
  391. struct st_replace *glob_replace;
  392. static char *out_buff;
  393. static uint out_length;
  394. static int eval_result = 0;
  395. /* For column replace */
  396. char *replace_column[MAX_COLUMNS];
  397. uint max_replace_column= 0;
  398. static void get_replace_column(struct st_query *q);
  399. static void free_replace_column();
  400. /* Disable functions that only exist in MySQL 4.0 */
  401. #if MYSQL_VERSION_ID < 40000
  402. void mysql_enable_rpl_parse(MYSQL* mysql __attribute__((unused))) {}
  403. void mysql_disable_rpl_parse(MYSQL* mysql __attribute__((unused))) {}
  404. int mysql_rpl_parse_enabled(MYSQL* mysql __attribute__((unused))) { return 1; }
  405. my_bool mysql_rpl_probe(MYSQL *mysql __attribute__((unused))) { return 1; }
  406. #endif
  407. static void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val,
  408.       int len);
  409. static int handle_no_error(struct st_query *q);
  410. static void do_eval(DYNAMIC_STRING* query_eval, const char *query)
  411. {
  412.   const char *p;
  413.   register char c;
  414.   register int escaped = 0;
  415.   VAR* v;
  416.   DBUG_ENTER("do_eval");
  417.   for (p= query; (c = *p); ++p)
  418.   {
  419.     switch(c) {
  420.     case '$':
  421.       if (escaped)
  422.       {
  423. escaped = 0;
  424. dynstr_append_mem(query_eval, p, 1);
  425.       }
  426.       else
  427.       {
  428. if (!(v = var_get(p, &p, 0, 0)))
  429.   die("Bad variable in eval");
  430. dynstr_append_mem(query_eval, v->str_val, v->str_val_len);
  431.       }
  432.       break;
  433.     case '\':
  434.       if (escaped)
  435.       {
  436. escaped = 0;
  437. dynstr_append_mem(query_eval, p, 1);
  438.       }
  439.       else
  440. escaped = 1;
  441.       break;
  442.     default:
  443.       dynstr_append_mem(query_eval, p, 1);
  444.       break;
  445.     }
  446.   }
  447.   DBUG_VOID_RETURN;
  448. }
  449. static void close_cons()
  450. {
  451.   DBUG_ENTER("close_cons");
  452.   if (last_result)
  453.     mysql_free_result(last_result);
  454.   for (--next_con; next_con >= cons; --next_con)
  455.   {
  456.     mysql_close(&next_con->mysql);
  457.     my_free(next_con->name, MYF(MY_ALLOW_ZERO_PTR));
  458.   }
  459.   DBUG_VOID_RETURN;
  460. }
  461. static void close_files()
  462. {
  463.   DBUG_ENTER("close_files");
  464.   for (; cur_file != (file_stack-1) ; cur_file--)
  465.   {
  466.     DBUG_PRINT("info", ("file_name: %s", cur_file->file_name));
  467.     if (cur_file->file && cur_file->file != stdin)
  468.       my_fclose(cur_file->file, MYF(0));
  469.     my_free((gptr)cur_file->file_name, MYF(MY_ALLOW_ZERO_PTR));
  470.     cur_file->file_name= 0;
  471.   }
  472.   DBUG_VOID_RETURN;
  473. }
  474. static void free_used_memory()
  475. {
  476.   uint i;
  477.   DBUG_ENTER("free_used_memory");
  478. #ifndef EMBEDDED_LIBRARY
  479.   if (manager)
  480.     mysql_manager_close(manager);
  481. #endif
  482.   close_cons();
  483.   close_files();
  484.   hash_free(&var_hash);
  485.   for (i=0 ; i < q_lines.elements ; i++)
  486.   {
  487.     struct st_query **q= dynamic_element(&q_lines, i, struct st_query**);
  488.     my_free((gptr) (*q)->query_buf,MYF(MY_ALLOW_ZERO_PTR));
  489.     my_free((gptr) (*q),MYF(0));
  490.   }
  491.   for (i=0; i < 10; i++)
  492.   {
  493.     if (var_reg[i].alloced_len)
  494.       my_free(var_reg[i].str_val, MYF(MY_WME));
  495.   }
  496.   while (embedded_server_arg_count > 1)
  497.     my_free(embedded_server_args[--embedded_server_arg_count],MYF(0));
  498.   delete_dynamic(&q_lines);
  499.   dynstr_free(&ds_res);
  500.   free_replace();
  501.   free_replace_column();
  502.   my_free(pass,MYF(MY_ALLOW_ZERO_PTR));
  503.   free_defaults(default_argv);
  504.   mysql_server_end();
  505.   if (ps_protocol)
  506.     ps_free_reg();
  507.   DBUG_VOID_RETURN;
  508. }
  509. static void die(const char *fmt, ...)
  510. {
  511.   va_list args;
  512.   DBUG_ENTER("die");
  513.   va_start(args, fmt);
  514.   if (fmt)
  515.   {
  516.     fprintf(stderr, "mysqltest: ");
  517.     if (cur_file && cur_file != file_stack)
  518.       fprintf(stderr, "In included file "%s": ",
  519.               cur_file->file_name);
  520.     if (start_lineno != 0)
  521.       fprintf(stderr, "At line %u: ", start_lineno);
  522.     vfprintf(stderr, fmt, args);
  523.     fprintf(stderr, "n");
  524.     fflush(stderr);
  525.   }
  526.   va_end(args);
  527.   free_used_memory();
  528.   my_end(MY_CHECK_ERROR);
  529.   exit(1);
  530. }
  531. /* Note that we will get some memory leaks when calling this! */
  532. static void abort_not_supported_test()
  533. {
  534.   DBUG_ENTER("abort_not_supported_test");
  535.   fprintf(stderr, "This test is not supported by this installationn");
  536.   if (!silent)
  537.     printf("skippedn");
  538.   free_used_memory();
  539.   my_end(MY_CHECK_ERROR);
  540.   exit(62);
  541. }
  542. static void verbose_msg(const char *fmt, ...)
  543. {
  544.   va_list args;
  545.   DBUG_ENTER("verbose_msg");
  546.   if (!verbose)
  547.     DBUG_VOID_RETURN;
  548.   va_start(args, fmt);
  549.   fprintf(stderr, "mysqltest: ");
  550.   if (start_lineno > 0)
  551.     fprintf(stderr, "At line %u: ", start_lineno);
  552.   vfprintf(stderr, fmt, args);
  553.   fprintf(stderr, "n");
  554.   va_end(args);
  555.   DBUG_VOID_RETURN;
  556. }
  557. void init_parser()
  558. {
  559.   parser.current_line= parser.read_lines= 0;
  560.   memset(&var_reg, 0, sizeof(var_reg));
  561. }
  562. int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname)
  563. {
  564.   MY_STAT stat_info;
  565.   char *tmp, *res_ptr;
  566.   char eval_file[FN_REFLEN];
  567.   int res;
  568.   uint res_len;
  569.   int fd;
  570.   DYNAMIC_STRING res_ds;
  571.   DBUG_ENTER("dyn_string_cmp");
  572.   if (!test_if_hard_path(fname))
  573.   {
  574.     strxmov(eval_file, opt_basedir, fname, NullS);
  575.     fn_format(eval_file, eval_file,"","",4);
  576.   }
  577.   else
  578.     fn_format(eval_file, fname,"","",4);
  579.   if (!my_stat(eval_file, &stat_info, MYF(MY_WME)))
  580.     die(NullS);
  581.   if (!eval_result && (uint) stat_info.st_size != ds->length)
  582.   {
  583.     DBUG_PRINT("info",("Size differs:  result size: %u  file size: %u",
  584.        ds->length, stat_info.st_size));
  585.     DBUG_RETURN(RESULT_LENGTH_MISMATCH);
  586.   }
  587.   if (!(tmp = (char*) my_malloc(stat_info.st_size + 1, MYF(MY_WME))))
  588.     die(NullS);
  589.   if ((fd = my_open(eval_file, O_RDONLY, MYF(MY_WME))) < 0)
  590.     die(NullS);
  591.   if (my_read(fd, (byte*)tmp, stat_info.st_size, MYF(MY_WME|MY_NABP)))
  592.     die(NullS);
  593.   tmp[stat_info.st_size] = 0;
  594.   init_dynamic_string(&res_ds, "", 0, 65536);
  595.   if (eval_result)
  596.   {
  597.     do_eval(&res_ds, tmp);
  598.     res_ptr = res_ds.str;
  599.     if ((res_len = res_ds.length) != ds->length)
  600.     {
  601.       res= RESULT_LENGTH_MISMATCH;
  602.       goto err;
  603.     }
  604.   }
  605.   else
  606.   {
  607.     res_ptr = tmp;
  608.     res_len = stat_info.st_size;
  609.   }
  610.   res= (memcmp(res_ptr, ds->str, res_len)) ?
  611.     RESULT_CONTENT_MISMATCH : RESULT_OK;
  612. err:
  613.   if (res && eval_result)
  614.     str_to_file(fn_format(eval_file, fname, "", ".eval",2), res_ptr,
  615. res_len);
  616.   my_free((gptr) tmp, MYF(0));
  617.   my_close(fd, MYF(MY_WME));
  618.   dynstr_free(&res_ds);
  619.   DBUG_RETURN(res);
  620. }
  621. static int check_result(DYNAMIC_STRING* ds, const char *fname,
  622. my_bool require_option)
  623. {
  624.   int error= RESULT_OK;
  625.   int res= dyn_string_cmp(ds, fname);
  626.   if (res && require_option)
  627.     abort_not_supported_test();
  628.   switch (res) {
  629.   case RESULT_OK:
  630.     break; /* ok */
  631.   case RESULT_LENGTH_MISMATCH:
  632.     verbose_msg("Result length mismatch");
  633.     error= RESULT_LENGTH_MISMATCH;
  634.     break;
  635.   case RESULT_CONTENT_MISMATCH:
  636.     verbose_msg("Result content mismatch");
  637.     error= RESULT_CONTENT_MISMATCH;
  638.     break;
  639.   default: /* impossible */
  640.     die("Unknown error code from dyn_string_cmp()");
  641.   }
  642.   if (error)
  643.     reject_dump(fname, ds->str, ds->length);
  644.   return error;
  645. }
  646. VAR* var_get(const char *var_name, const char** var_name_end, my_bool raw,
  647.      my_bool ignore_not_existing)
  648. {
  649.   int digit;
  650.   VAR* v;
  651.   DBUG_ENTER("var_get");
  652.   DBUG_PRINT("enter",("var_name: %s",var_name));
  653.   if (*var_name != '$')
  654.     goto err;
  655.   digit = *++var_name - '0';
  656.   if (digit < 0 || digit >= 10)
  657.   {
  658.     const char *save_var_name = var_name, *end;
  659.     uint length;
  660.     end = (var_name_end) ? *var_name_end : 0;
  661.     while (my_isvar(charset_info,*var_name) && var_name != end)
  662.       var_name++;
  663.     if (var_name == save_var_name)
  664.     {
  665.       if (ignore_not_existing)
  666. DBUG_RETURN(0);
  667.       die("Empty variable");
  668.     }
  669.     length= (uint) (var_name - save_var_name);
  670.     if (length >= MAX_VAR_NAME)
  671.       die("Too long variable name: %s", save_var_name);
  672.     if (!(v = (VAR*) hash_search(&var_hash, save_var_name, length)))
  673.     {
  674.       char buff[MAX_VAR_NAME+1];
  675.       strmake(buff, save_var_name, length);
  676.       v= var_from_env(buff, "");
  677.     }
  678.     var_name--; /* Point at last character */
  679.   }
  680.   else
  681.     v = var_reg + digit;
  682.   if (!raw && v->int_dirty)
  683.   {
  684.     sprintf(v->str_val, "%d", v->int_val);
  685.     v->int_dirty = 0;
  686.     v->str_val_len = strlen(v->str_val);
  687.   }
  688.   if (var_name_end)
  689.     *var_name_end = var_name  ;
  690.   DBUG_RETURN(v);
  691. err:
  692.   if (var_name_end)
  693.     *var_name_end = 0;
  694.   die("Unsupported variable name: %s", var_name);
  695.   DBUG_RETURN(0);
  696. }
  697. static VAR *var_obtain(const char *name, int len)
  698. {
  699.   VAR* v;
  700.   if ((v = (VAR*)hash_search(&var_hash, name, len)))
  701.     return v;
  702.   v = var_init(0, name, len, "", 0);
  703.   my_hash_insert(&var_hash, (byte*)v);
  704.   return v;
  705. }
  706. int var_set(const char *var_name, const char *var_name_end,
  707.             const char *var_val, const char *var_val_end)
  708. {
  709.   int digit;
  710.   VAR* v;
  711.   DBUG_ENTER("var_set");
  712.   DBUG_PRINT("enter", ("var_name: '%.*s' = '%.*s' (length: %d)",
  713.                        (int) (var_name_end - var_name), var_name,
  714.                        (int) (var_val_end - var_val), var_val,
  715.                        (int) (var_val_end - var_val)));
  716.   if (*var_name++ != '$')
  717.   {
  718.     var_name--;
  719.     die("Variable name in %s does not start with '$'", var_name);
  720.   }
  721.   digit = *var_name - '0';
  722.   if (!(digit < 10 && digit >= 0))
  723.   {
  724.     v = var_obtain(var_name, (uint) (var_name_end - var_name));
  725.   }
  726.   else
  727.     v = var_reg + digit;
  728.   DBUG_RETURN(eval_expr(v, var_val, (const char**)&var_val_end));
  729. }
  730. int open_file(const char *name)
  731. {
  732.   char buff[FN_REFLEN];
  733.   DBUG_ENTER("open_file");
  734.   DBUG_PRINT("enter", ("name: %s", name));
  735.   if (!test_if_hard_path(name))
  736.   {
  737.     strxmov(buff, opt_basedir, name, NullS);
  738.     name=buff;
  739.   }
  740.   fn_format(buff,name,"","",4);
  741.   if (cur_file == file_stack_end)
  742.     die("Source directives are nesting too deep");
  743.   cur_file++;
  744.   if (!(cur_file->file = my_fopen(buff, O_RDONLY | FILE_BINARY, MYF(0))))
  745.   {
  746.     cur_file--;
  747.     die("Could not open file %s", buff);
  748.   }
  749.   cur_file->file_name= my_strdup(buff, MYF(MY_FAE));
  750.   *++lineno=1;
  751.   DBUG_RETURN(0);
  752. }
  753. /*
  754.   Check for unexpected "junk" after the end of query
  755.   This is normally caused by missing delimiters
  756. */
  757. int check_eol_junk(const char *eol)
  758. {
  759.   const char *p= eol;
  760.   DBUG_ENTER("check_eol_junk");
  761.   DBUG_PRINT("enter", ("eol: %s", eol));
  762.   /* Remove all spacing chars except new line */
  763.   while (*p && my_isspace(charset_info, *p) && (*p != 'n'))
  764.     p++;
  765.   /* Check for extra delimiter */
  766.   if (*p && !strncmp(p, delimiter, delimiter_length))
  767.     die("Extra delimiter "%s" found", delimiter);
  768.   /* Allow trailing # comment */
  769.   if (*p && *p != '#')
  770.   {
  771.     if (*p == 'n')
  772.       die("Missing delimiter");
  773.     die("End of line junk detected: "%s"", p);
  774.   }
  775.   DBUG_RETURN(0);
  776. }
  777. /* ugly long name, but we are following the convention */
  778. int do_wait_for_slave_to_stop(struct st_query *q __attribute__((unused)))
  779. {
  780.   MYSQL* mysql = &cur_con->mysql;
  781.   for (;;)
  782.   {
  783.     MYSQL_RES *res;
  784.     MYSQL_ROW row;
  785.     int done;
  786.     LINT_INIT(res);
  787.     if (mysql_query(mysql,"show status like 'Slave_running'") ||
  788. !(res=mysql_store_result(mysql)))
  789.       die("Query failed while probing slave for stop: %s",
  790.   mysql_error(mysql));
  791.     if (!(row=mysql_fetch_row(res)) || !row[1])
  792.     {
  793.       mysql_free_result(res);
  794.       die("Strange result from query while probing slave for stop");
  795.     }
  796.     done = !strcmp(row[1],"OFF");
  797.     mysql_free_result(res);
  798.     if (done)
  799.       break;
  800.     my_sleep(SLAVE_POLL_INTERVAL);
  801.   }
  802.   return 0;
  803. }
  804. int do_require_manager(struct st_query *query __attribute__((unused)) )
  805. {
  806.   if (!manager)
  807.     abort_not_supported_test();
  808.   return 0;
  809. }
  810. #ifndef EMBEDDED_LIBRARY
  811. int do_server_start(struct st_query *q)
  812. {
  813.   return do_server_op(q, "start");
  814. }
  815. int do_server_stop(struct st_query *q)
  816. {
  817.   return do_server_op(q, "stop");
  818. }
  819. int do_server_op(struct st_query *q, const char *op)
  820. {
  821.   char *p= q->first_argument;
  822.   char com_buf[256], *com_p;
  823.   if (!manager)
  824.   {
  825.     die("Manager is not initialized, manager commands are not possible");
  826.   }
  827.   com_p= strmov(com_buf,op);
  828.   com_p= strmov(com_p,"_exec ");
  829.   if (!*p)
  830.     die("Missing server name in server_%s", op);
  831.   while (*p && !my_isspace(charset_info, *p))
  832.    *com_p++= *p++;
  833.   *com_p++= ' ';
  834.   com_p= int10_to_str(manager_wait_timeout, com_p, 10);
  835.   *com_p++= 'n';
  836.   *com_p= 0;
  837.   if (mysql_manager_command(manager, com_buf, (int)(com_p-com_buf)))
  838.     die("Error in command: %s(%d)", manager->last_error, manager->last_errno);
  839.   while (!manager->eof)
  840.   {
  841.     if (mysql_manager_fetch_line(manager, com_buf, sizeof(com_buf)))
  842.       die("Error fetching result line: %s(%d)", manager->last_error,
  843.   manager->last_errno);
  844.   }
  845.   q->last_argument= p;
  846.   return 0;
  847. }
  848. #endif
  849. /*
  850.   Source and execute the given file
  851.   SYNOPSIS
  852.     do_source()
  853.     query called command
  854.   DESCRIPTION
  855.     source <file_name>
  856.     Open the file <file_name> and execute it
  857. */
  858. int do_source(struct st_query *query)
  859. {
  860.   char *p= query->first_argument, *name;
  861.   if (!*p)
  862.     die("Missing file name in source");
  863.   name= p;
  864.   while (*p && !my_isspace(charset_info,*p))
  865.     p++;
  866.   if (*p)
  867.     *p++= 0;
  868.   query->last_argument= p;
  869.   /*
  870.      If this file has already been sourced, dont source it again.
  871.      It's already available in the q_lines cache
  872.   */
  873.   if (parser.current_line < (parser.read_lines - 1))
  874.     return 0;
  875.   return open_file(name);
  876. }
  877. /*
  878.   Execute given command.
  879.   SYNOPSIS
  880.     do_exec()
  881.     query called command
  882.   DESCRIPTION
  883.     exec <command>
  884.     Execute the text between exec and end of line in a subprocess.
  885.     The error code returned from the subprocess is checked against the
  886.     expected error array, previously set with the --error command.
  887.     It can thus be used to execute a command that shall fail.
  888. */
  889. static void do_exec(struct st_query *query)
  890. {
  891.   int error;
  892.   DYNAMIC_STRING *ds= NULL;
  893.   DYNAMIC_STRING ds_tmp;
  894.   char buf[1024];
  895.   FILE *res_file;
  896.   char *cmd= query->first_argument;
  897.   DBUG_ENTER("do_exec");
  898.   while (*cmd && my_isspace(charset_info, *cmd))
  899.     cmd++;
  900.   if (!*cmd)
  901.     die("Missing argument in exec");
  902.   query->last_argument= query->end;
  903.   DBUG_PRINT("info", ("Executing '%s'", cmd));
  904.   if (!(res_file= popen(cmd, "r")) && query->abort_on_error)
  905.     die("popen("%s", "r") failed", cmd);
  906.   if (disable_result_log)
  907.   {
  908.     while (fgets(buf, sizeof(buf), res_file))
  909.     {
  910.       buf[strlen(buf)-1]=0;
  911.       DBUG_PRINT("exec_result",("%s", buf));
  912.     }
  913.   }
  914.   else
  915.   {
  916.     if (query->record_file[0])
  917.     {
  918.       init_dynamic_string(&ds_tmp, "", 16384, 65536);
  919.       ds= &ds_tmp;
  920.     }
  921.     else
  922.       ds= &ds_res;
  923.     while (fgets(buf, sizeof(buf), res_file))
  924.       replace_dynstr_append_mem(ds, buf, strlen(buf));
  925.   }
  926.   error= pclose(res_file);
  927.   if (error != 0)
  928.   {
  929.     uint status= WEXITSTATUS(error), i;
  930.     my_bool ok= 0;
  931.     if (query->abort_on_error)
  932.       die("command "%s" failed", cmd);
  933.     DBUG_PRINT("info",
  934.                ("error: %d, status: %d", error, status));
  935.     for (i= 0; i < query->expected_errors; i++)
  936.     {
  937.       DBUG_PRINT("info", ("expected error: %d",
  938.                           query->expected_errno[i].code.errnum));
  939.       if ((query->expected_errno[i].type == ERR_ERRNO) &&
  940.           (query->expected_errno[i].code.errnum == status))
  941.       {
  942.         ok= 1;
  943.         DBUG_PRINT("info", ("command "%s" failed with expected error: %d",
  944.                             cmd, status));
  945.       }
  946.     }
  947.     if (!ok)
  948.       die("command "%s" failed with wrong error: %d",
  949.           cmd, status);
  950.   }
  951.   else if (query->expected_errno[0].type == ERR_ERRNO &&
  952.            query->expected_errno[0].code.errnum != 0)
  953.   {
  954.     /* Error code we wanted was != 0, i.e. not an expected success */
  955.     die("command "%s" succeeded - should have failed with errno %d...",
  956.         cmd, query->expected_errno[0].code.errnum);
  957.   }
  958.   if (!disable_result_log)
  959.   {
  960.     if (glob_replace)
  961.       free_replace();
  962.     if (record)
  963.     {
  964.       if (!query->record_file[0] && !result_file)
  965.         die("Missing result file");
  966.       if (!result_file)
  967.         str_to_file(query->record_file, ds->str, ds->length);
  968.     }
  969.     else if (query->record_file[0])
  970.     {
  971.       error= check_result(ds, query->record_file, query->require_file);
  972.     }
  973.     if (ds == &ds_tmp)
  974.       dynstr_free(&ds_tmp);
  975.   }
  976. }
  977. int var_query_set(VAR* v, const char *p, const char** p_end)
  978. {
  979.   char* end = (char*)((p_end && *p_end) ? *p_end : p + strlen(p));
  980.   MYSQL_RES *res;
  981.   MYSQL_ROW row;
  982.   MYSQL* mysql = &cur_con->mysql;
  983.   LINT_INIT(res);
  984.   while (end > p && *end != '`')
  985.     --end;
  986.   if (p == end)
  987.     die("Syntax error in query, missing '`'");
  988.   ++p;
  989.   if (mysql_real_query(mysql, p, (int)(end - p)) ||
  990.       !(res = mysql_store_result(mysql)))
  991.   {
  992.     *end = 0;
  993.     die("Error running query '%s': %s", p, mysql_error(mysql));
  994.   }
  995.   if ((row = mysql_fetch_row(res)) && row[0])
  996.   {
  997.     /*
  998.       Concatenate all row results with tab in between to allow us to work
  999.       with results from many columns (for example from SHOW VARIABLES)
  1000.     */
  1001.     DYNAMIC_STRING result;
  1002.     uint i;
  1003.     ulong *lengths;
  1004.     char *end;
  1005.     init_dynamic_string(&result, "", 16384, 65536);
  1006.     lengths= mysql_fetch_lengths(res);
  1007.     for (i=0; i < mysql_num_fields(res); i++)
  1008.     {
  1009.       if (row[0])
  1010. dynstr_append_mem(&result, row[i], lengths[i]);
  1011.       dynstr_append_mem(&result, "t", 1);
  1012.     }
  1013.     end= result.str + result.length-1;
  1014.     eval_expr(v, result.str, (const char**) &end);
  1015.     dynstr_free(&result);
  1016.   }
  1017.   else
  1018.     eval_expr(v, "", 0);
  1019.   mysql_free_result(res);
  1020.   return 0;
  1021. }
  1022. void var_copy(VAR *dest, VAR *src)
  1023. {
  1024.   dest->int_val= src->int_val;
  1025.   dest->int_dirty= src->int_dirty;
  1026.   /* Alloc/realloc data for str_val in dest */
  1027.   if (dest->alloced_len < src->alloced_len &&
  1028.       !(dest->str_val= dest->str_val
  1029.         ? my_realloc(dest->str_val, src->alloced_len, MYF(MY_WME))
  1030.         : my_malloc(src->alloced_len, MYF(MY_WME))))
  1031.     die("Out of memory");
  1032.   else
  1033.     dest->alloced_len= src->alloced_len;
  1034.   /* Copy str_val data to dest */
  1035.   dest->str_val_len= src->str_val_len;
  1036.   if (src->str_val_len)
  1037.     memcpy(dest->str_val, src->str_val, src->str_val_len);
  1038. }
  1039. int eval_expr(VAR* v, const char *p, const char** p_end)
  1040. {
  1041.   VAR* vp;
  1042.   if (*p == '$')
  1043.   {
  1044.     if ((vp = var_get(p,p_end,0,0)))
  1045.     {
  1046.       var_copy(v, vp);
  1047.       return 0;
  1048.     }
  1049.   }
  1050.   else if (*p == '`')
  1051.   {
  1052.     return var_query_set(v, p, p_end);
  1053.   }
  1054.   else
  1055.     {
  1056.       int new_val_len = (p_end && *p_end) ?
  1057.  (int) (*p_end - p) : (int) strlen(p);
  1058.       if (new_val_len + 1 >= v->alloced_len)
  1059.       {
  1060. v->alloced_len = (new_val_len < MIN_VAR_ALLOC - 1) ?
  1061.   MIN_VAR_ALLOC : new_val_len + 1;
  1062. if (!(v->str_val =
  1063.       v->str_val ? my_realloc(v->str_val, v->alloced_len+1,
  1064.       MYF(MY_WME)) :
  1065.       my_malloc(v->alloced_len+1, MYF(MY_WME))))
  1066.   die("Out of memory");
  1067.       }
  1068.       v->str_val_len = new_val_len;
  1069.       memcpy(v->str_val, p, new_val_len);
  1070.       v->str_val[new_val_len] = 0;
  1071.       v->int_val=atoi(p);
  1072.       v->int_dirty=0;
  1073.       return 0;
  1074.     }
  1075.   die("Invalid expr: %s", p);
  1076.   return 1;
  1077. }
  1078. enum enum_operator
  1079. {
  1080.   DO_DEC,
  1081.   DO_INC
  1082. };
  1083. /*
  1084.   Decrease or increase the value of a variable
  1085.   SYNOPSIS
  1086.     do_modify_var()
  1087.     query called command
  1088.     name        human readable name of operator
  1089.     operator    operation to perform on the var
  1090.   DESCRIPTION
  1091.     dec $var_name
  1092.     inc $var_name
  1093. */
  1094. int do_modify_var(struct st_query *query, const char *name,
  1095.                   enum enum_operator operator)
  1096. {
  1097.   const char *p= query->first_argument;
  1098.   VAR* v;
  1099.   if (!*p)
  1100.     die("Missing arguments to %s", name);
  1101.   if (*p != '$')
  1102.     die("First argument to %s must be a variable (start with $)", name);
  1103.   v= var_get(p, &p, 1, 0);
  1104.   switch (operator){
  1105.   case DO_DEC:
  1106.     v->int_val--;
  1107.     break;
  1108.   case DO_INC:
  1109.     v->int_val++;
  1110.     break;
  1111.   default:
  1112.     die("Invalid operator to do_operator");
  1113.     break;
  1114.   }
  1115.   v->int_dirty= 1;
  1116.   query->last_argument= (char*)++p;
  1117.   return 0;
  1118. }
  1119. int do_system(struct st_query *q)
  1120. {
  1121.   char *p=q->first_argument;
  1122.   VAR v;
  1123.   var_init(&v, 0, 0, 0, 0);
  1124.   eval_expr(&v, p, 0); /* NULL terminated */
  1125.   if (v.str_val_len)
  1126.   {
  1127.     char expr_buf[1024];
  1128.     if ((uint)v.str_val_len > sizeof(expr_buf) - 1)
  1129.       v.str_val_len = sizeof(expr_buf) - 1;
  1130.     memcpy(expr_buf, v.str_val, v.str_val_len);
  1131.     expr_buf[v.str_val_len] = 0;
  1132.     DBUG_PRINT("info", ("running system command '%s'", expr_buf));
  1133.     if (system(expr_buf))
  1134.     {
  1135.       if (q->abort_on_error)
  1136.         die("system command '%s' failed", expr_buf);
  1137.       /* If ! abort_on_error, display message and continue */
  1138.       verbose_msg("system command '%s' failed", expr_buf);
  1139.     }
  1140.   }
  1141.   else
  1142.     die("Missing arguments to system, nothing to do!");
  1143.   var_free(&v);
  1144.   q->last_argument= q->end;
  1145.   return 0;
  1146. }
  1147. /*
  1148.   Print the content between echo and <delimiter> to result file.
  1149.   If content is a variable, the variable value will be retrieved
  1150.   SYNOPSIS
  1151.     do_echo()
  1152.     q  called command
  1153.   DESCRIPTION
  1154.     Usage 1:
  1155.     echo text
  1156.     Print the text after echo until end of command to result file
  1157.     Usage 2:
  1158.     echo $<var_name>
  1159.     Print the content of the variable <var_name> to result file
  1160. */
  1161. int do_echo(struct st_query *q)
  1162. {
  1163.   char *p= q->first_argument;
  1164.   DYNAMIC_STRING *ds;
  1165.   DYNAMIC_STRING ds_tmp;
  1166.   VAR v;
  1167.   var_init(&v,0,0,0,0);
  1168.   if (q->record_file[0])
  1169.   {
  1170.     init_dynamic_string(&ds_tmp, "", 256, 512);
  1171.     ds= &ds_tmp;
  1172.   }
  1173.   else
  1174.     ds= &ds_res;
  1175.   eval_expr(&v, p, 0); /* NULL terminated */
  1176.   if (v.str_val_len)
  1177.     dynstr_append_mem(ds, v.str_val, v.str_val_len);
  1178.   dynstr_append_mem(ds, "n", 1);
  1179.   var_free(&v);
  1180.   if (ds == &ds_tmp)
  1181.     dynstr_free(&ds_tmp);
  1182.   q->last_argument= q->end;
  1183.   return 0;
  1184. }
  1185. int do_sync_with_master2(long offset)
  1186. {
  1187.   MYSQL_RES* res;
  1188.   MYSQL_ROW row;
  1189.   MYSQL* mysql= &cur_con->mysql;
  1190.   char query_buf[FN_REFLEN+128];
  1191.   int tries= 0;
  1192.   int rpl_parse;
  1193.   if (!master_pos.file[0])
  1194.     die("Calling 'sync_with_master' without calling 'save_master_pos'");
  1195.   rpl_parse= mysql_rpl_parse_enabled(mysql);
  1196.   mysql_disable_rpl_parse(mysql);
  1197.   sprintf(query_buf, "select master_pos_wait('%s', %ld)", master_pos.file,
  1198.   master_pos.pos + offset);
  1199. wait_for_position:
  1200.   if (mysql_query(mysql, query_buf))
  1201.     die("failed in %s: %d: %s", query_buf, mysql_errno(mysql),
  1202.         mysql_error(mysql));
  1203.   if (!(last_result= res= mysql_store_result(mysql)))
  1204.     die("mysql_store_result() returned NULL for '%s'", query_buf);
  1205.   if (!(row= mysql_fetch_row(res)))
  1206.     die("empty result in %s", query_buf);
  1207.   if (!row[0])
  1208.   {
  1209.     /*
  1210.       It may be that the slave SQL thread has not started yet, though START
  1211.       SLAVE has been issued ?
  1212.     */
  1213.     if (tries++ == 3)
  1214.       die("could not sync with master ('%s' returned NULL)", query_buf);
  1215.     sleep(1); /* So at most we will wait 3 seconds and make 4 tries */
  1216.     mysql_free_result(res);
  1217.     goto wait_for_position;
  1218.   }
  1219.   mysql_free_result(res);
  1220.   last_result=0;
  1221.   if (rpl_parse)
  1222.     mysql_enable_rpl_parse(mysql);
  1223.   return 0;
  1224. }
  1225. int do_sync_with_master(struct st_query *query)
  1226. {
  1227.   long offset= 0;
  1228.   char *p= query->first_argument;
  1229.   const char *offset_start= p;
  1230.   if (*offset_start)
  1231.   {
  1232.     for (; my_isdigit(charset_info, *p); p++)
  1233.       offset = offset * 10 + *p - '0';
  1234.     if(*p && !my_isspace(charset_info, *p))
  1235.       die("Invalid integer argument "%s"", offset_start);
  1236.     query->last_argument= p;
  1237.   }
  1238.   return do_sync_with_master2(offset);
  1239. }
  1240. int do_save_master_pos()
  1241. {
  1242.   MYSQL_RES* res;
  1243.   MYSQL_ROW row;
  1244.   MYSQL* mysql = &cur_con->mysql;
  1245.   const char *query;
  1246.   int rpl_parse;
  1247.   rpl_parse = mysql_rpl_parse_enabled(mysql);
  1248.   mysql_disable_rpl_parse(mysql);
  1249.   if (mysql_query(mysql, query= "show master status"))
  1250.     die("failed in show master status: %d: %s",
  1251. mysql_errno(mysql), mysql_error(mysql));
  1252.   if (!(last_result =res = mysql_store_result(mysql)))
  1253.     die("mysql_store_result() retuned NULL for '%s'", query);
  1254.   if (!(row = mysql_fetch_row(res)))
  1255.     die("empty result in show master status");
  1256.   strnmov(master_pos.file, row[0], sizeof(master_pos.file)-1);
  1257.   master_pos.pos = strtoul(row[1], (char**) 0, 10);
  1258.   mysql_free_result(res); last_result=0;
  1259.   if (rpl_parse)
  1260.     mysql_enable_rpl_parse(mysql);
  1261.   return 0;
  1262. }
  1263. /*
  1264.   Assign the variable <var_name> with <var_val>
  1265.   SYNOPSIS
  1266.    do_let()
  1267.     query called command
  1268.   DESCRIPTION
  1269.     let $<var_name>=<var_val><delimiter>
  1270.     <var_name>  - is the string string found between the $ and =
  1271.     <var_val>   - is the content between the = and <delimiter>, it may span
  1272.                   multiple line and contain any characters except <delimiter>
  1273.     <delimiter> - is a string containing of one or more chars, default is ;
  1274.   RETURN VALUES
  1275.    Program will die if error detected
  1276. */
  1277. int do_let(struct st_query *query)
  1278. {
  1279.   char *p= query->first_argument;
  1280.   char *var_name, *var_name_end, *var_val_start;
  1281.   /* Find <var_name> */
  1282.   if (!*p)
  1283.     die("Missing arguments to let");
  1284.   var_name= p;
  1285.   while (*p && (*p != '=') && !my_isspace(charset_info,*p))
  1286.     p++;
  1287.   var_name_end= p;
  1288.   if (var_name+1 == var_name_end)
  1289.     die("Missing variable name in let");
  1290.   while (my_isspace(charset_info,*p))
  1291.     p++;
  1292.   if (*p++ != '=')
  1293.     die("Missing assignment operator in let");
  1294.   /* Find start of <var_val> */
  1295.   while (*p && my_isspace(charset_info,*p))
  1296.     p++;
  1297.   var_val_start= p;
  1298.   query->last_argument= query->end;
  1299.   /* Assign var_val to var_name */
  1300.   return var_set(var_name, var_name_end, var_val_start, query->end);
  1301. }
  1302. /*
  1303.   Store an integer (typically the returncode of the last SQL)
  1304.   statement in the mysqltest builtin variable $mysql_errno, by
  1305.   simulating of a user statement "let $mysql_errno= <integer>"
  1306. */
  1307. int var_set_errno(int sql_errno)
  1308. {
  1309.   const char *var_name= "$mysql_errno";
  1310.   char var_val[21];
  1311.   uint length= my_sprintf(var_val, (var_val, "%d", sql_errno));
  1312.   return var_set(var_name, var_name + 12, var_val, var_val + length);
  1313. }
  1314. int do_rpl_probe(struct st_query *query __attribute__((unused)))
  1315. {
  1316.   DBUG_ENTER("do_rpl_probe");
  1317.   if (mysql_rpl_probe(&cur_con->mysql))
  1318.     die("Failed in mysql_rpl_probe(): '%s'", mysql_error(&cur_con->mysql));
  1319.   DBUG_RETURN(0);
  1320. }
  1321. int do_enable_rpl_parse(struct st_query *query __attribute__((unused)))
  1322. {
  1323.   mysql_enable_rpl_parse(&cur_con->mysql);
  1324.   return 0;
  1325. }
  1326. int do_disable_rpl_parse(struct st_query *query __attribute__((unused)))
  1327. {
  1328.   mysql_disable_rpl_parse(&cur_con->mysql);
  1329.   return 0;
  1330. }
  1331. /*
  1332.   Sleep the number of specifed seconds
  1333.   SYNOPSIS
  1334.    do_sleep()
  1335.     q        called command
  1336.     real_sleep  use the value from opt_sleep as number of seconds to sleep
  1337.   DESCRIPTION
  1338.     sleep <seconds>
  1339.     real_sleep
  1340. */
  1341. int do_sleep(struct st_query *query, my_bool real_sleep)
  1342. {
  1343.   int error= 0;
  1344.   char *p= query->first_argument;
  1345.   char *sleep_start, *sleep_end= query->end;
  1346.   double sleep_val;
  1347.   while (my_isspace(charset_info, *p))
  1348.     p++;
  1349.   if (!*p)
  1350.     die("Missing argument to sleep");
  1351.   sleep_start= p;
  1352.   /* Check that arg starts with a digit, not handled by my_strtod */
  1353.   if (!my_isdigit(charset_info, *sleep_start))
  1354.     die("Invalid argument to sleep "%s"", query->first_argument);
  1355.   sleep_val= my_strtod(sleep_start, &sleep_end, &error);
  1356.   if (error)
  1357.     die("Invalid argument to sleep "%s"", query->first_argument);
  1358.   /* Fixed sleep time selected by --sleep option */
  1359.   if (opt_sleep && !real_sleep)
  1360.     sleep_val= opt_sleep;
  1361.   my_sleep((ulong) (sleep_val * 1000000L));
  1362.   query->last_argument= sleep_end;
  1363.   return 0;
  1364. }
  1365. static void get_file_name(char *filename, struct st_query *q)
  1366. {
  1367.   char *p= q->first_argument, *name;
  1368.   if (!*p)
  1369.     die("Missing file name argument");
  1370.   name= p;
  1371.   while (*p && !my_isspace(charset_info,*p))
  1372.     p++;
  1373.   if (*p)
  1374.     *p++= 0;
  1375.   q->last_argument= p;
  1376.   strmake(filename, name, FN_REFLEN);
  1377. }
  1378. static void set_charset(struct st_query *q)
  1379. {
  1380.   char *charset_name= q->first_argument;
  1381.   char *p;
  1382.   if (!charset_name || !*charset_name)
  1383.     die("Missing charset name in 'character_set'");
  1384.   /* Remove end space */
  1385.   p= charset_name;
  1386.   while (*p && !my_isspace(charset_info,*p))
  1387.     p++;
  1388.   if(*p)
  1389.     *p++= 0;
  1390.   q->last_argument= p;
  1391.   charset_info= get_charset_by_csname(charset_name,MY_CS_PRIMARY,MYF(MY_WME));
  1392.   if (!charset_info)
  1393.     abort_not_supported_test();
  1394. }
  1395. static uint get_errcodes(match_err *to,struct st_query *q)
  1396. {
  1397.   char *p= q->first_argument;
  1398.   uint count= 0;
  1399.   DBUG_ENTER("get_errcodes");
  1400.   if (!*p)
  1401.     die("Missing argument in %s", q->query);
  1402.   do
  1403.   {
  1404.     if (*p == 'S')
  1405.     {
  1406.       /* SQLSTATE string */
  1407.       int i;
  1408.       p++;
  1409.       for (i = 0; my_isalnum(charset_info, *p) && i < SQLSTATE_LENGTH; p++, i++)
  1410.         to[count].code.sqlstate[i]= *p;
  1411.       to[count].code.sqlstate[i]= '';
  1412.       to[count].type= ERR_SQLSTATE;
  1413.     }
  1414.     else
  1415.     {
  1416.       long val;
  1417.       p=str2int(p,10,(long) INT_MIN, (long) INT_MAX, &val);
  1418.       if (p == NULL)
  1419.         die("Invalid argument in %s", q->query);
  1420.       to[count].code.errnum= (uint) val;
  1421.       to[count].type= ERR_ERRNO;
  1422.     }
  1423.     count++;
  1424.   } while (*(p++) == ',');
  1425.   q->last_argument= (p - 1);
  1426.   to[count].type= ERR_EMPTY;                        /* End of data */
  1427.   DBUG_RETURN(count);
  1428. }
  1429. /*
  1430.   Get a string;  Return ptr to end of string
  1431.   Strings may be surrounded by " or '
  1432.   If string is a '$variable', return the value of the variable.
  1433. */
  1434. static char *get_string(char **to_ptr, char **from_ptr,
  1435. struct st_query *q)
  1436. {
  1437.   reg1 char c,sep;
  1438.   char *to= *to_ptr, *from= *from_ptr, *start=to;
  1439.   DBUG_ENTER("get_string");
  1440.   /* Find separator */
  1441.   if (*from == '"' || *from == ''')
  1442.     sep= *from++;
  1443.   else
  1444.     sep=' '; /* Separated with space */
  1445.   for ( ; (c=*from) ; from++)
  1446.   {
  1447.     if (c == '\' && from[1])
  1448.     { /* Escaped character */
  1449.       /* We can't translate  -> ASCII 0 as replace can't handle ASCII 0 */
  1450.       switch (*++from) {
  1451.       case 'n':
  1452. *to++= 'n';
  1453. break;
  1454.       case 't':
  1455. *to++= 't';
  1456. break;
  1457.       case 'r':
  1458. *to++ = 'r';
  1459. break;
  1460.       case 'b':
  1461. *to++ = 'b';
  1462. break;
  1463.       case 'Z': /* ^Z must be escaped on Win32 */
  1464. *to++='32';
  1465. break;
  1466.       default:
  1467. *to++ = *from;
  1468. break;
  1469.       }
  1470.     }
  1471.     else if (c == sep)
  1472.     {
  1473.       if (c == ' ' || c != *++from)
  1474. break; /* Found end of string */
  1475.       *to++=c; /* Copy duplicated separator */
  1476.     }
  1477.     else
  1478.       *to++=c;
  1479.   }
  1480.   if (*from != ' ' && *from)
  1481.     die("Wrong string argument in %s", q->query);
  1482.   while (my_isspace(charset_info,*from)) /* Point to next string */
  1483.     from++;
  1484.   *to =0; /* End of string marker */
  1485.   *to_ptr= to+1; /* Store pointer to end */
  1486.   *from_ptr= from;
  1487.   /* Check if this was a variable */
  1488.   if (*start == '$')
  1489.   {
  1490.     const char *end= to;
  1491.     VAR *var=var_get(start, &end, 0, 1);
  1492.     if (var && to == (char*) end+1)
  1493.     {
  1494.       DBUG_PRINT("info",("var: '%s' -> '%s'", start, var->str_val));
  1495.       DBUG_RETURN(var->str_val); /* return found variable value */
  1496.     }
  1497.   }
  1498.   DBUG_RETURN(start);
  1499. }
  1500. /*
  1501.   Get arguments for replace. The syntax is:
  1502.   replace from to [from to ...]
  1503.   Where each argument may be quoted with ' or "
  1504.   A argument may also be a variable, in which case the value of the
  1505.   variable is replaced.
  1506. */
  1507. static void get_replace(struct st_query *q)
  1508. {
  1509.   uint i;
  1510.   char *from= q->first_argument;
  1511.   char *buff,*start;
  1512.   char word_end_chars[256],*pos;
  1513.   POINTER_ARRAY to_array,from_array;
  1514.   DBUG_ENTER("get_replace");
  1515.   free_replace();
  1516.   bzero((char*) &to_array,sizeof(to_array));
  1517.   bzero((char*) &from_array,sizeof(from_array));
  1518.   if (!*from)
  1519.     die("Missing argument in %s", q->query);
  1520.   start=buff=my_malloc(strlen(from)+1,MYF(MY_WME | MY_FAE));
  1521.   while (*from)
  1522.   {
  1523.     char *to=buff;
  1524.     to=get_string(&buff, &from, q);
  1525.     if (!*from)
  1526.       die("Wrong number of arguments to replace_result in '%s'", q->query);
  1527.     insert_pointer_name(&from_array,to);
  1528.     to=get_string(&buff, &from, q);
  1529.     insert_pointer_name(&to_array,to);
  1530.   }
  1531.   for (i=1,pos=word_end_chars ; i < 256 ; i++)
  1532.     if (my_isspace(charset_info,i))
  1533.       *pos++= i;
  1534.   *pos=0; /* End pointer */
  1535.   if (!(glob_replace=init_replace((char**) from_array.typelib.type_names,
  1536.   (char**) to_array.typelib.type_names,
  1537.   (uint) from_array.typelib.count,
  1538.   word_end_chars)) ||
  1539.       initialize_replace_buffer())
  1540.     die("Can't initialize replace from '%s'", q->query);
  1541.   free_pointer_array(&from_array);
  1542.   free_pointer_array(&to_array);
  1543.   my_free(start, MYF(0));
  1544.   q->last_argument= q->end;
  1545.   DBUG_VOID_RETURN;
  1546. }
  1547. void free_replace()
  1548. {
  1549.   DBUG_ENTER("free_replace");
  1550.   if (glob_replace)
  1551.   {
  1552.     my_free((char*) glob_replace,MYF(0));
  1553.     glob_replace=0;
  1554.     free_replace_buffer();
  1555.   }
  1556.   DBUG_VOID_RETURN;
  1557. }
  1558. int select_connection_name(const char *name)
  1559. {
  1560.   struct connection *con;
  1561.   DBUG_ENTER("select_connection2");
  1562.   DBUG_PRINT("enter",("name: '%s'", name));
  1563.   for (con= cons; con < next_con; con++)
  1564.   {
  1565.     if (!strcmp(con->name, name))
  1566.     {
  1567.       cur_con= con;
  1568.       DBUG_RETURN(0);
  1569.     }
  1570.   }
  1571.   die("connection '%s' not found in connection pool", name);
  1572.   DBUG_RETURN(1); /* Never reached */
  1573. }
  1574. int select_connection(struct st_query *query)
  1575. {
  1576.   char *name;
  1577.   char *p= query->first_argument;
  1578.   DBUG_ENTER("select_connection");
  1579.   if (!*p)
  1580.     die("Missing connection name in connect");
  1581.   name= p;
  1582.   while (*p && !my_isspace(charset_info,*p))
  1583.     p++;
  1584.   if (*p)
  1585.     *p++= 0;
  1586.   query->last_argument= p;
  1587.   return select_connection_name(name);
  1588. }
  1589. int close_connection(struct st_query *q)
  1590. {
  1591.   char *p= q->first_argument, *name;
  1592.   struct connection *con;
  1593.   DBUG_ENTER("close_connection");
  1594.   DBUG_PRINT("enter",("name: '%s'",p));
  1595.   if (!*p)
  1596.     die("Missing connection name in connect");
  1597.   name= p;
  1598.   while (*p && !my_isspace(charset_info,*p))
  1599.     p++;
  1600.   if (*p)
  1601.     *p++= 0;
  1602.   q->last_argument= p;
  1603.   for (con= cons; con < next_con; con++)
  1604.   {
  1605.     if (!strcmp(con->name, name))
  1606.     {
  1607. #ifndef EMBEDDED_LIBRARY
  1608.       if (q->type == Q_DIRTY_CLOSE)
  1609.       {
  1610. if (con->mysql.net.vio)
  1611. {
  1612.   vio_delete(con->mysql.net.vio);
  1613.   con->mysql.net.vio = 0;
  1614. }
  1615.       }
  1616. #endif
  1617.       mysql_close(&con->mysql);
  1618.       DBUG_RETURN(0);
  1619.     }
  1620.   }
  1621.   die("connection '%s' not found in connection pool", name);
  1622.   DBUG_RETURN(1); /* Never reached */
  1623. }
  1624. /*
  1625.    This one now is a hack - we may want to improve in in the
  1626.    future to handle quotes. For now we assume that anything that is not
  1627.    a comma, a space or ) belongs to the argument. space is a chopper, comma or
  1628.    ) are delimiters/terminators
  1629. */
  1630. char* safe_get_param(char *str, char** arg, const char *msg)
  1631. {
  1632.   DBUG_ENTER("safe_get_param");
  1633.   while (*str && my_isspace(charset_info,*str))
  1634.     str++;
  1635.   *arg= str;
  1636.   for (; *str && *str != ',' && *str != ')' ; str++)
  1637.   {
  1638.     if (my_isspace(charset_info,*str))
  1639.       *str= 0;
  1640.   }
  1641.   if (!*str)
  1642.     die(msg);
  1643.   *str++= 0;
  1644.   DBUG_RETURN(str);
  1645. }
  1646. #ifndef EMBEDDED_LIBRARY
  1647. void init_manager()
  1648. {
  1649.   if (!(manager=mysql_manager_init(0)))
  1650.     die("Failed in mysql_manager_init()");
  1651.   if (!mysql_manager_connect(manager,manager_host,manager_user,
  1652.      manager_pass,manager_port))
  1653.     die("Could not connect to MySQL manager: %s(%d)",manager->last_error,
  1654. manager->last_errno);
  1655. }
  1656. #endif
  1657. int safe_connect(MYSQL* con, const char *host, const char *user,
  1658.  const char *pass,
  1659.  const char *db, int port, const char *sock)
  1660. {
  1661.   int con_error = 1;
  1662.   int i;
  1663.   for (i = 0; i < MAX_CON_TRIES; ++i)
  1664.   {
  1665.     if (mysql_real_connect(con, host,user, pass, db, port, sock,
  1666.    CLIENT_MULTI_STATEMENTS))
  1667.     {
  1668.       con_error = 0;
  1669.       break;
  1670.     }
  1671.     sleep(CON_RETRY_SLEEP);
  1672.   }
  1673.   return con_error;
  1674. }
  1675. int do_connect(struct st_query *q)
  1676. {
  1677.   char *con_name, *con_user,*con_pass, *con_host, *con_port_str,
  1678.     *con_db, *con_sock;
  1679.   char *p= q->first_argument;
  1680.   char buff[FN_REFLEN];
  1681.   int con_port;
  1682.   int free_con_sock= 0;
  1683.   DBUG_ENTER("do_connect");
  1684.   DBUG_PRINT("enter",("connect: %s",p));
  1685.   if (*p != '(')
  1686.     die("Syntax error in connect - expected '(' found '%c'", *p);
  1687.   p++;
  1688.   p= safe_get_param(p, &con_name, "missing connection name");
  1689.   p= safe_get_param(p, &con_host, "missing connection host");
  1690.   p= safe_get_param(p, &con_user, "missing connection user");
  1691.   p= safe_get_param(p, &con_pass, "missing connection password");
  1692.   p= safe_get_param(p, &con_db, "missing connection db");
  1693.   if (!*p || *p == ';') /* Default port and sock */
  1694.   {
  1695.     con_port= port;
  1696.     con_sock= (char*) unix_sock;
  1697.   }
  1698.   else
  1699.   {
  1700.     VAR* var_port, *var_sock;
  1701.     p= safe_get_param(p, &con_port_str, "missing connection port");
  1702.     if (*con_port_str == '$')
  1703.     {
  1704.       if (!(var_port= var_get(con_port_str, 0, 0, 0)))
  1705. die("Unknown variable '%s'", con_port_str+1);
  1706.       con_port= var_port->int_val;
  1707.     }
  1708.     else
  1709.       con_port= atoi(con_port_str);
  1710.     p= safe_get_param(p, &con_sock, "missing connection socket");
  1711.     if (*con_sock == '$')
  1712.     {
  1713.       if (!(var_sock= var_get(con_sock, 0, 0, 0)))
  1714. die("Unknown variable '%s'", con_sock+1);
  1715.       if (!(con_sock= (char*)my_malloc(var_sock->str_val_len+1, MYF(0))))
  1716. die("Out of memory");
  1717.       free_con_sock= 1;
  1718.       memcpy(con_sock, var_sock->str_val, var_sock->str_val_len);
  1719.       con_sock[var_sock->str_val_len]= 0;
  1720.     }
  1721.   }
  1722.   q->last_argument= p;
  1723.   if (next_con == cons_end)
  1724.     die("Connection limit exhausted - increase MAX_CONS in mysqltest.c");
  1725.   if (!mysql_init(&next_con->mysql))
  1726.     die("Failed on mysql_init()");
  1727.   if (opt_compress)
  1728.     mysql_options(&next_con->mysql,MYSQL_OPT_COMPRESS,NullS);
  1729.   mysql_options(&next_con->mysql, MYSQL_OPT_LOCAL_INFILE, 0);
  1730.   mysql_options(&next_con->mysql, MYSQL_SET_CHARSET_NAME, charset_name);
  1731. #ifdef HAVE_OPENSSL
  1732.   if (opt_use_ssl)
  1733.     mysql_ssl_set(&next_con->mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
  1734.   opt_ssl_capath, opt_ssl_cipher);
  1735. #endif
  1736.   if (con_sock && !free_con_sock && *con_sock && *con_sock != FN_LIBCHAR)
  1737.     con_sock=fn_format(buff, con_sock, TMPDIR, "",0);
  1738.   if (!con_db[0])
  1739.     con_db= db;
  1740.   /* Special database to allow one to connect without a database name */
  1741.   if (con_db && !strcmp(con_db,"*NO-ONE*"))
  1742.     con_db= 0;
  1743.   if ((safe_connect(&next_con->mysql, con_host,
  1744.     con_user, con_pass,
  1745.     con_db, con_port, con_sock ? con_sock: 0)))
  1746.     die("Could not open connection '%s': %s", con_name,
  1747. mysql_error(&next_con->mysql));
  1748.   if (!(next_con->name= my_strdup(con_name, MYF(MY_WME))))
  1749.     die(NullS);
  1750.   cur_con= next_con++;
  1751.   if (free_con_sock)
  1752.     my_free(con_sock, MYF(MY_WME));
  1753.   DBUG_RETURN(0);
  1754. }
  1755. int do_done(struct st_query *q)
  1756. {
  1757.   /* Check if empty block stack */
  1758.   if (cur_block == block_stack)
  1759.   {
  1760.     if (*q->query != '}')
  1761.       die("Stray 'end' command - end of block before beginning");
  1762.     die("Stray '}' - end of block before beginning");
  1763.   }
  1764.   /* Test if inner block has been executed */
  1765.   if (cur_block->ok && cur_block->cmd == Q_WHILE)
  1766.   {
  1767.     /* Pop block from stack, re-execute outer block */
  1768.     cur_block--;
  1769.     parser.current_line = cur_block->line;
  1770.   }
  1771.   else
  1772.   {
  1773.     /* Pop block from stack, goto next line */
  1774.     cur_block--;
  1775.     parser.current_line++;
  1776.   }
  1777.   return 0;
  1778. }
  1779. int do_block(enum enum_commands cmd, struct st_query *q)
  1780. {
  1781.   char *p= q->first_argument;
  1782.   const char *expr_start, *expr_end;
  1783.   VAR v;
  1784.   const char *cmd_name= (cmd == Q_WHILE ? "while" : "if");
  1785.   /* Check stack overflow */
  1786.   if (cur_block == block_stack_end)
  1787.     die("Nesting too deeply");
  1788.   /* Set way to find outer block again, increase line counter */
  1789.   cur_block->line= parser.current_line++;
  1790.   /* If this block is ignored */
  1791.   if (!cur_block->ok)
  1792.   {
  1793.     /* Inner block should be ignored too */
  1794.     cur_block++;
  1795.     cur_block->cmd= cmd;
  1796.     cur_block->ok= FALSE;
  1797.     return 0;
  1798.   }
  1799.   /* Parse and evaluate test expression */
  1800.   expr_start= strchr(p, '(');
  1801.   if (!expr_start)
  1802.     die("missing '(' in %s", cmd_name);
  1803.   expr_end= strrchr(expr_start, ')');
  1804.   if (!expr_end)
  1805.     die("missing ')' in %s", cmd_name);
  1806.   p= (char*)expr_end+1;
  1807.   while (*p && my_isspace(charset_info, *p))
  1808.     p++;
  1809.   if (*p == '{')
  1810.     die("Missing newline between %s and '{'", cmd_name);
  1811.   if (*p)
  1812.     die("Missing '{' after %s. Found "%s"", cmd_name, p);
  1813.   var_init(&v,0,0,0,0);
  1814.   eval_expr(&v, ++expr_start, &expr_end);
  1815.   /* Define inner block */
  1816.   cur_block++;
  1817.   cur_block->cmd= cmd;
  1818.   cur_block->ok= (v.int_val ? TRUE : FALSE);
  1819.   var_free(&v);
  1820.   return 0;
  1821. }
  1822. /*
  1823.   Read characters from line buffer or file. This is needed to allow
  1824.   my_ungetc() to buffer MAX_DELIMITER characters for a file
  1825.   NOTE:
  1826.     This works as long as one doesn't change files (with 'source file_name')
  1827.     when there is things pushed into the buffer.  This should however not
  1828.     happen for any tests in the test suite.
  1829. */
  1830. int my_getc(FILE *file)
  1831. {
  1832.   if (line_buffer_pos == line_buffer)
  1833.     return fgetc(file);
  1834.   return *--line_buffer_pos;
  1835. }
  1836. void my_ungetc(int c)
  1837. {
  1838.   *line_buffer_pos++= (char) c;
  1839. }
  1840. my_bool end_of_query(int c)
  1841. {
  1842.   uint i;
  1843.   char tmp[MAX_DELIMITER];
  1844.   if (c != *delimiter)
  1845.     return 0;
  1846.   for (i= 1; i < delimiter_length &&
  1847.  (c= my_getc(cur_file->file)) == *(delimiter + i);
  1848.        i++)
  1849.     tmp[i]= c;
  1850.   if (i == delimiter_length)
  1851.     return 1; /* Found delimiter */
  1852.   /* didn't find delimiter, push back things that we read */
  1853.   my_ungetc(c);
  1854.   while (i > 1)
  1855.     my_ungetc(tmp[--i]);
  1856.   return 0;
  1857. }
  1858. /*
  1859.   Read one "line" from the file
  1860.   SYNOPSIS
  1861.     read_line
  1862.     buf     buffer for the read line
  1863.     size    size of the buffer i.e max size to read
  1864.   DESCRIPTION
  1865.     This function actually reads several lines an adds them to the
  1866.     buffer buf. It will continue to read until it finds what it believes
  1867.     is a complete query.
  1868.     Normally that means it will read lines until it reaches the
  1869.     "delimiter" that marks end of query. Default delimiter is ';'
  1870.     The function should be smart enough not to detect delimiter's
  1871.     found inside strings sorrounded with '"' and ''' escaped strings.
  1872.     If the first line in a query starts with '#' or '-' this line is treated
  1873.     as a comment. A comment is always terminated when end of line 'n' is
  1874.     reached.
  1875. */
  1876. int read_line(char *buf, int size)
  1877. {
  1878.   int c;
  1879.   char *p= buf, *buf_end= buf + size - 1;
  1880.   int no_save= 0;
  1881.   enum {R_NORMAL, R_Q1, R_ESC_Q_Q1, R_ESC_Q_Q2,
  1882. R_ESC_SLASH_Q1, R_ESC_SLASH_Q2,
  1883. R_Q2, R_COMMENT, R_LINE_START} state= R_LINE_START;
  1884.   DBUG_ENTER("read_line");
  1885.   start_lineno= *lineno;
  1886.   for (; p < buf_end ;)
  1887.   {
  1888.     no_save= 0;
  1889.     c= my_getc(cur_file->file);
  1890.     if (feof(cur_file->file))
  1891.     {
  1892.   found_eof:
  1893.       if (cur_file->file != stdin)
  1894.       {
  1895. my_fclose(cur_file->file, MYF(0));
  1896.         cur_file->file= 0;
  1897.       }
  1898.       my_free((gptr)cur_file->file_name, MYF(MY_ALLOW_ZERO_PTR));
  1899.       cur_file->file_name= 0;
  1900.       lineno--;
  1901.       start_lineno= *lineno;
  1902.       if (cur_file == file_stack)
  1903.       {
  1904.         /* We're back at the first file, check if
  1905.            all { have matching }
  1906.          */
  1907.         if (cur_block != block_stack)
  1908.         {
  1909.           start_lineno= *(lineno+1);
  1910.           die("Missing end of block");
  1911.         }
  1912. DBUG_RETURN(1);
  1913.       }
  1914.       cur_file--;
  1915.       continue;
  1916.     }
  1917.     /* Line counting is independent of state */
  1918.     if (c == 'n')
  1919.       (*lineno)++;
  1920.     switch(state) {
  1921.     case R_NORMAL:
  1922.       /*  Only accept '{' in the beginning of a line */
  1923.       if (end_of_query(c))
  1924.       {
  1925. *p= 0;
  1926. DBUG_RETURN(0);
  1927.       }
  1928.       else if (c == ''')
  1929. state = R_Q1;
  1930.       else if (c == '"')
  1931. state = R_Q2;
  1932.       else if (c == 'n')
  1933.       {
  1934. state = R_LINE_START;
  1935.       }
  1936.       break;
  1937.     case R_COMMENT:
  1938.       if (c == 'n')
  1939.       {
  1940. *p= 0;
  1941. DBUG_RETURN(0);
  1942.       }
  1943.       break;
  1944.     case R_LINE_START:
  1945.       /* Only accept start of comment if this is the first line in query */
  1946.       if ((*lineno == start_lineno) && (c == '#' || c == '-'))
  1947.       {
  1948. state = R_COMMENT;
  1949.       }
  1950.       else if (my_isspace(charset_info, c))
  1951.       {
  1952. if (c == 'n')
  1953.   start_lineno= *lineno; /* Query hasn't started yet */
  1954. no_save= 1;
  1955.       }
  1956.       else if (c == '}')
  1957.       {
  1958. *buf++= '}';
  1959. *buf= 0;
  1960. DBUG_RETURN(0);
  1961.       }
  1962.       else if (end_of_query(c) || c == '{')
  1963.       {
  1964. *p= 0;
  1965. DBUG_RETURN(0);
  1966.       }
  1967.       else if (c == ''')
  1968. state= R_Q1;
  1969.       else if (c == '"')
  1970. state= R_Q2;
  1971.       else
  1972. state= R_NORMAL;
  1973.       break;
  1974.     case R_Q1:
  1975.       if (c == ''')
  1976. state= R_ESC_Q_Q1;
  1977.       else if (c == '\')
  1978. state= R_ESC_SLASH_Q1;
  1979.       break;
  1980.     case R_ESC_Q_Q1:
  1981.       if (end_of_query(c))
  1982.       {
  1983. *p= 0;
  1984. DBUG_RETURN(0);
  1985.       }
  1986.       if (c != ''')
  1987. state= R_NORMAL;
  1988.       else
  1989. state= R_Q1;
  1990.       break;
  1991.     case R_ESC_SLASH_Q1:
  1992.       state= R_Q1;
  1993.       break;
  1994.     case R_Q2:
  1995.       if (c == '"')
  1996. state= R_ESC_Q_Q2;
  1997.       else if (c == '\')
  1998. state= R_ESC_SLASH_Q2;
  1999.       break;
  2000.     case R_ESC_Q_Q2:
  2001.       if (end_of_query(c))
  2002.       {
  2003. *p= 0;
  2004. DBUG_RETURN(0);
  2005.       }
  2006.       if (c != '"')
  2007. state= R_NORMAL;
  2008.       else
  2009. state= R_Q2;
  2010.       break;
  2011.     case R_ESC_SLASH_Q2:
  2012.       state= R_Q2;
  2013.       break;
  2014.     }
  2015.     if (!no_save)
  2016.     {
  2017.       /* Could be a multibyte character */
  2018.       /* This code is based on the code in "sql_load.cc" */
  2019. #ifdef USE_MB
  2020.       int charlen = my_mbcharlen(charset_info, c);
  2021.       /* We give up if multibyte character is started but not */
  2022.       /* completed before we pass buf_end */
  2023.       if ((charlen > 1) && (p + charlen) <= buf_end)
  2024.       {
  2025. int i;
  2026. char* mb_start = p;
  2027. *p++ = c;
  2028. for (i= 1; i < charlen; i++)
  2029. {
  2030.   if (feof(cur_file->file))
  2031.     goto found_eof; /* FIXME: could we just break here?! */
  2032.   c= my_getc(cur_file->file);
  2033.   *p++ = c;
  2034. }
  2035. if (! my_ismbchar(charset_info, mb_start, p))
  2036. {
  2037.   /* It was not a multiline char, push back the characters */
  2038.   /* We leave first 'c', i.e. pretend it was a normal char */
  2039.   while (p > mb_start)
  2040.     my_ungetc(*--p);
  2041. }
  2042.       }
  2043.       else
  2044. #endif
  2045. *p++= c;
  2046.     }
  2047.   }
  2048.   *p= 0; /* Always end with  */
  2049.   DBUG_RETURN(feof(cur_file->file));
  2050. }
  2051. /*
  2052.   Create a query from a set of lines
  2053.   SYNOPSIS
  2054.     read_query()
  2055.     q_ptr pointer where to return the new query
  2056.   DESCRIPTION
  2057.     Converts lines returned by read_line into a query, this involves
  2058.     parsing the first word in the read line to find the query type.
  2059.     A -- comment may contain a valid query as the first word after the
  2060.     comment start. Thus it's always checked to see if that is the case.
  2061.     The advantage with this approach is to be able to execute commands
  2062.     terminated by new line 'n' regardless how many "delimiter" it contain.
  2063.     If query starts with @<file_name> this will specify a file to ....
  2064. */
  2065. static char read_query_buf[MAX_QUERY];
  2066. int read_query(struct st_query** q_ptr)
  2067. {
  2068.   char *p= read_query_buf, *p1;
  2069.   struct st_query* q;
  2070.   DBUG_ENTER("read_query");
  2071.   if (parser.current_line < parser.read_lines)
  2072.   {
  2073.     get_dynamic(&q_lines, (gptr) q_ptr, parser.current_line) ;
  2074.     DBUG_RETURN(0);
  2075.   }
  2076.   if (!(*q_ptr= q= (struct st_query*) my_malloc(sizeof(*q), MYF(MY_WME))) ||
  2077.       insert_dynamic(&q_lines, (gptr) &q))
  2078.     die(NullS);
  2079.   q->record_file[0]= 0;
  2080.   q->require_file= 0;
  2081.   q->first_word_len= 0;
  2082.   q->type= Q_UNKNOWN;
  2083.   q->query_buf= q->query= 0;
  2084.   if (read_line(read_query_buf, sizeof(read_query_buf)))
  2085.   {
  2086.     DBUG_PRINT("warning",("too long query"));
  2087.     DBUG_RETURN(1);
  2088.   }
  2089.   DBUG_PRINT("info", ("query: %s", read_query_buf));
  2090.   if (*p == '#')
  2091.   {
  2092.     q->type= Q_COMMENT;
  2093.     /* This goto is to avoid losing the "expected error" info. */
  2094.     goto end;
  2095.   }
  2096.   memcpy((gptr) q->expected_errno, (gptr) global_expected_errno,
  2097.  sizeof(global_expected_errno));
  2098.   q->expected_errors= global_expected_errors;
  2099.   q->abort_on_error= (global_expected_errors == 0 && abort_on_error);
  2100.   if (p[0] == '-' && p[1] == '-')
  2101.   {
  2102.     q->type= Q_COMMENT_WITH_COMMAND;
  2103.     p+= 2; /* To calculate first word */
  2104.   }
  2105.   else
  2106.   {
  2107.     while (*p && my_isspace(charset_info, *p))
  2108.       p++ ;
  2109.     if (*p == '@')
  2110.     {
  2111.       p++;
  2112.       p1 = q->record_file;
  2113.       while (!my_isspace(charset_info, *p) &&
  2114.      p1 < q->record_file + sizeof(q->record_file) - 1)
  2115. *p1++ = *p++;
  2116.       *p1 = 0;
  2117.     }
  2118.   }
  2119. end:
  2120.   while (*p && my_isspace(charset_info, *p))
  2121.     p++;
  2122.   if (!(q->query_buf= q->query= my_strdup(p, MYF(MY_WME))))
  2123.     die(NullS);
  2124.   /* Calculate first word and first argument */
  2125.   for (p= q->query; *p && !my_isspace(charset_info, *p) ; p++) ;
  2126.   q->first_word_len= (uint) (p - q->query);
  2127.   while (*p && my_isspace(charset_info, *p))
  2128.     p++;
  2129.   q->first_argument= p;
  2130.   q->end= strend(q->query);
  2131.   parser.read_lines++;
  2132.   DBUG_RETURN(0);
  2133. }
  2134. static struct my_option my_long_options[] =
  2135. {
  2136.   {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.",
  2137.    0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
  2138.   {"database", 'D', "Database to use.", (gptr*) &db, (gptr*) &db, 0,
  2139.    GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
  2140.   {"basedir", 'b', "Basedir for tests.", (gptr*) &opt_basedir,
  2141.    (gptr*) &opt_basedir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
  2142.   {"big-test", 'B', "Define BIG_TEST to 1.", (gptr*) &opt_big_test,
  2143.    (gptr*) &opt_big_test, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
  2144.   {"compress", 'C', "Use the compressed server/client protocol.",
  2145.    (gptr*) &opt_compress, (gptr*) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
  2146.    0, 0, 0},
  2147.   {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG,
  2148.    0, 0, 0, 0, 0, 0},
  2149.   {"host", 'h', "Connect to host.", (gptr*) &host, (gptr*) &host, 0,
  2150.    GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
  2151.   {"manager-user", OPT_MANAGER_USER, "Undocumented: Used for debugging.",
  2152.    (gptr*) &manager_user, (gptr*) &manager_user, 0, GET_STR, REQUIRED_ARG, 0,
  2153.    0, 0, 0, 0, 0},
  2154.   {"manager-host", OPT_MANAGER_HOST, "Undocumented: Used for debugging.",
  2155.    (gptr*) &manager_host, (gptr*) &manager_host, 0, GET_STR, REQUIRED_ARG,
  2156.    0, 0, 0, 0, 0, 0},
  2157.   {"manager-password", OPT_MANAGER_PASSWD, "Undocumented: Used for debugging.",
  2158.    0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
  2159.   {"manager-port", OPT_MANAGER_PORT, "Undocumented: Used for debugging.",
  2160.    (gptr*) &manager_port, (gptr*) &manager_port, 0, GET_INT, REQUIRED_ARG,
  2161.    MYSQL_MANAGER_PORT, 0, 0, 0, 0, 0},
  2162.   {"manager-wait-timeout", OPT_MANAGER_WAIT_TIMEOUT,
  2163.    "Undocumented: Used for debugging.", (gptr*) &manager_wait_timeout,
  2164.    (gptr*) &manager_wait_timeout, 0, GET_INT, REQUIRED_ARG, 3, 0, 0, 0, 0, 0},
  2165.   {"password", 'p', "Password to use when connecting to server.",
  2166.    0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
  2167.   {"port", 'P', "Port number to use for connection.", (gptr*) &port,
  2168.    (gptr*) &port, 0, GET_INT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0, 0},
  2169.   {"ps-protocol", OPT_PS_PROTOCOL, "Use prepared statements protocol for communication",
  2170.    (gptr*) &ps_protocol, (gptr*) &ps_protocol, 0,
  2171.    GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
  2172.   {"quiet", 's', "Suppress all normal output.", (gptr*) &silent,
  2173.    (gptr*) &silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
  2174.   {"record", 'r', "Record output of test_file into result file.",
  2175.    0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
  2176.   {"result-file", 'R', "Read/Store result from/in this file.",
  2177.    (gptr*) &result_file, (gptr*) &result_file, 0, GET_STR, REQUIRED_ARG,
  2178.    0, 0, 0, 0, 0, 0},
  2179.   {"server-arg", 'A', "Send enbedded server this as a paramenter.",
  2180.    0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
  2181.   {"server-file", 'F', "Read embedded server arguments from file.",
  2182.    0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
  2183.   {"silent", 's', "Suppress all normal output. Synonym for --quiet.",
  2184.    (gptr*) &silent, (gptr*) &silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
  2185.   {"skip-safemalloc", OPT_SKIP_SAFEMALLOC,
  2186.    "Don't use the memory allocation checking.", 0, 0, 0, GET_NO_ARG, NO_ARG,
  2187.    0, 0, 0, 0, 0, 0},
  2188.   {"sleep", 'T', "Sleep always this many seconds on sleep commands.",
  2189.    (gptr*) &opt_sleep, (gptr*) &opt_sleep, 0, GET_INT, REQUIRED_ARG, 0, 0, 0,
  2190.    0, 0, 0},
  2191.   {"socket", 'S', "Socket file to use for connection.",
  2192.    (gptr*) &unix_sock, (gptr*) &unix_sock, 0, GET_STR, REQUIRED_ARG, 0, 0, 0,
  2193.    0, 0, 0},
  2194. #include "sslopt-longopts.h"
  2195.   {"test-file", 'x', "Read test from/in this file (default stdin).",
  2196.    0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
  2197.   {"timer-file", 'm', "File where the timing in micro seconds is stored.",
  2198.    0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
  2199.   {"tmpdir", 't', "Temporary directory where sockets are put.",
  2200.    0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
  2201.   {"user", 'u', "User for login.", (gptr*) &user, (gptr*) &user, 0, GET_STR,
  2202.    REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
  2203.   {"verbose", 'v', "Write more.", (gptr*) &verbose, (gptr*) &verbose, 0,
  2204.    GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
  2205.   {"version", 'V', "Output version information and exit.",
  2206.    0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
  2207.   { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
  2208. };
  2209. #include <help_start.h>
  2210. static void print_version(void)
  2211. {
  2212.   printf("%s  Ver %s Distrib %s, for %s (%s)n",my_progname,MTEST_VERSION,
  2213.  MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
  2214. }
  2215. void usage()
  2216. {
  2217.   print_version();
  2218.   printf("MySQL AB, by Sasha, Matt, Monty & Janin");
  2219.   printf("This software comes with ABSOLUTELY NO WARRANTYnn");
  2220.   printf("Runs a test against the mysql server and compares output with a results file.nn");
  2221.   printf("Usage: %s [OPTIONS] [database] < test_filen", my_progname);
  2222.   my_print_help(my_long_options);
  2223.   printf("  --no-defaults       Don't read default options from any options file.n");
  2224.   my_print_variables(my_long_options);
  2225. }