mysqltest.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:57k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 man page for more information.
  15.  *
  16.  * Written by:
  17.  *   Sasha Pachev <sasha@mysql.com>
  18.  *   Matt Wagner  <matt@mysql.com>
  19.  *   Monty
  20.  **/
  21. /**********************************************************************
  22.   TODO:
  23. - Print also the queries that returns a result to the log file;  This makes
  24.   it much easier to find out what's wrong.
  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 "1.7"
  36. #include <global.h>
  37. #include <my_sys.h>
  38. #include <m_string.h>
  39. #include <mysql.h>
  40. #include <mysql_version.h>
  41. #include <m_ctype.h>
  42. #include <my_config.h>
  43. #include <my_dir.h>
  44. #include <mysqld_error.h>
  45. #include <stdio.h>
  46. #include <stdlib.h>
  47. #include <getopt.h>
  48. #include <stdarg.h>
  49. #include <sys/stat.h>
  50. #include <unistd.h>
  51. #include <errno.h>
  52. #include <violite.h>
  53. #define MAX_QUERY  65536
  54. #define PAD_SIZE 128
  55. #define MAX_CONS   1024
  56. #define MAX_INCLUDE_DEPTH 16
  57. #define LAZY_GUESS_BUF_SIZE 8192
  58. #define INIT_Q_LINES   1024
  59. #define MIN_VAR_ALLOC   32
  60. #define BLOCK_STACK_DEPTH  32
  61. #define MAX_EXPECTED_ERRORS 10
  62. #define QUERY_SEND  1
  63. #define QUERY_REAP  2
  64. static int record = 0, verbose = 0, silent = 0, opt_sleep=0;
  65. static char *db = 0, *pass=0;
  66. const char* user = 0, *host = 0, *unix_sock = 0;
  67. static int port = 0;
  68. static uint start_lineno, *lineno;
  69. static char **default_argv;
  70. static const char *load_default_groups[]= { "mysqltest","client",0 };
  71. static FILE* file_stack[MAX_INCLUDE_DEPTH];
  72. static FILE** cur_file;
  73. static FILE** file_stack_end;
  74. static uint lineno_stack[MAX_INCLUDE_DEPTH];
  75. static char TMPDIR[FN_REFLEN];
  76. static int block_stack[BLOCK_STACK_DEPTH];
  77. static int *cur_block, *block_stack_end;
  78. static uint global_expected_errno[MAX_EXPECTED_ERRORS];
  79. DYNAMIC_ARRAY q_lines;
  80. typedef struct 
  81. {
  82.   char file[FN_REFLEN];
  83.   ulong pos;
  84. } MASTER_POS ;
  85. struct connection
  86. {
  87.   MYSQL mysql;
  88.   char *name;
  89. };
  90. typedef struct
  91. {
  92.   int read_lines,current_line;
  93. } PARSER;
  94. PARSER parser;
  95. MASTER_POS master_pos;
  96. int block_ok = 1; /* set to 0 if the current block should not be executed */
  97. int false_block_depth = 0;
  98. const char* result_file = 0; /* if set, all results are concated and
  99. compared against this file*/
  100. typedef struct
  101. {
  102.   char* name;
  103.   char* str_val;
  104.   int str_val_len;
  105.   int int_val;
  106.   int alloced_len;
  107.   int int_dirty; /* do not update string if int is updated until first read */
  108. } VAR;
  109. VAR var_reg[10];
  110. /*Perl/shell-like variable registers */
  111. struct connection cons[MAX_CONS];
  112. struct connection* cur_con, *next_con, *cons_end;
  113. /* this should really be called command */
  114. struct st_query
  115. {
  116.   char *query, *first_argument;
  117.   int first_word_len;
  118.   my_bool abort_on_error, require_file;
  119.   uint expected_errno[MAX_EXPECTED_ERRORS];
  120.   char record_file[FN_REFLEN];
  121.   /* Add new commands before Q_UNKNOWN */
  122.   enum { Q_CONNECTION=1,     Q_QUERY, 
  123.          Q_CONNECT,          Q_SLEEP, 
  124.          Q_INC,              Q_DEC,
  125.          Q_SOURCE,           Q_DISCONNECT,
  126.          Q_LET,              Q_ECHO, 
  127.          Q_WHILE,            Q_END_BLOCK,
  128.          Q_SYSTEM,           Q_RESULT, 
  129.          Q_REQUIRE,          Q_SAVE_MASTER_POS,
  130.          Q_SYNC_WITH_MASTER, Q_ERROR, 
  131.          Q_SEND,             Q_REAP, 
  132.          Q_DIRTY_CLOSE,      Q_REPLACE,
  133.  Q_PING,
  134.          Q_UNKNOWN,                             /* Unknown command.   */
  135.          Q_COMMENT,                             /* Comments, ignored. */
  136.          Q_COMMENT_WITH_COMMAND
  137.   } type;
  138. };
  139. const char *command_names[] = {
  140.   "connection",       "query",
  141.   "connect",          "sleep",
  142.   "inc",              "dec",
  143.   "source",           "disconnect",
  144.   "let",              "echo",
  145.   "while",            "end",
  146.   "system",           "result",
  147.   "require",          "save_master_pos",
  148.   "sync_with_master", "error",
  149.   "send",             "reap", 
  150.   "dirty_close",      "replace_result",
  151.   "ping",
  152.   0
  153. };
  154. TYPELIB command_typelib= {array_elements(command_names),"",
  155.   command_names};
  156. DYNAMIC_STRING ds_res;
  157. int dyn_string_cmp(DYNAMIC_STRING* ds, const char* fname);
  158. void reject_dump(const char* record_file, char* buf, int size);
  159. int close_connection(struct st_query* q);
  160. VAR* var_get(char* var_name, char* var_name_end, int raw);
  161. /* Definitions for replace */
  162. typedef struct st_pointer_array { /* when using array-strings */
  163.   TYPELIB typelib; /* Pointer to strings */
  164.   byte *str; /* Strings is here */
  165.   int7 *flag; /* Flag about each var. */
  166.   uint  array_allocs,max_count,length,max_length;
  167. } POINTER_ARRAY;
  168. struct st_replace;
  169. struct st_replace *init_replace(my_string *from, my_string *to, uint count,
  170. my_string word_end_chars);
  171. uint replace_strings(struct st_replace *rep, my_string *start,
  172.      uint *max_length, my_string from);
  173. static int insert_pointer_name(reg1 POINTER_ARRAY *pa,my_string name);
  174. void free_pointer_array(POINTER_ARRAY *pa);
  175. static int initialize_replace_buffer(void);
  176. static void free_replace_buffer(void);
  177. struct st_replace *glob_replace;
  178. static char *out_buff;
  179. static uint out_length;
  180. static void close_cons()
  181. {
  182.   DBUG_ENTER("close_cons");
  183.   for (--next_con; next_con >= cons; --next_con)
  184.   {
  185.     mysql_close(&next_con->mysql);
  186.     my_free(next_con->name, MYF(MY_ALLOW_ZERO_PTR));
  187.   }
  188.   DBUG_VOID_RETURN;
  189. }
  190. static void close_files()
  191. {
  192.   do
  193.   {
  194.     if (*cur_file != stdin)
  195.       my_fclose(*cur_file,MYF(0));
  196.   } while (cur_file-- != file_stack);
  197. }
  198. static void free_used_memory()
  199. {
  200.   uint i;
  201.   DBUG_ENTER("free_used_memory");
  202.   close_cons();
  203.   close_files();
  204.   for (i=0 ; i < q_lines.elements ; i++)
  205.   {
  206.     struct st_query **q= dynamic_element(&q_lines, i, struct st_query**);
  207.     my_free((gptr) (*q)->query,MYF(MY_ALLOW_ZERO_PTR));
  208.     my_free((gptr) (*q),MYF(0));
  209.   }
  210.   delete_dynamic(&q_lines);
  211.   dynstr_free(&ds_res);
  212.   my_free(pass,MYF(MY_ALLOW_ZERO_PTR));
  213.   free_defaults(default_argv);
  214.   my_end(MY_CHECK_ERROR);
  215.   DBUG_VOID_RETURN;
  216. }
  217. static void die(const char* fmt, ...)
  218. {
  219.   va_list args;
  220.   DBUG_ENTER("die");
  221.   va_start(args, fmt);
  222.   if (fmt)
  223.   {
  224.     fprintf(stderr, "%s: ", my_progname);
  225.     vfprintf(stderr, fmt, args);
  226.     fprintf(stderr, "n");
  227.   }
  228.   va_end(args);
  229.   free_used_memory();
  230.   exit(1);
  231. }
  232. static void abort_not_supported_test()
  233. {
  234.   DBUG_ENTER("abort_not_supported_test");
  235.   fprintf(stderr, "This test is not supported by this installationn");
  236.   if (!silent)
  237.     printf("skippedn");
  238.   free_used_memory();
  239.   exit(2);
  240. }
  241. static void verbose_msg(const char* fmt, ...)
  242. {
  243.   va_list args;
  244.   if (!verbose) return;
  245.   va_start(args, fmt);
  246.   fprintf(stderr, "%s: At line %u: ", my_progname, start_lineno);
  247.   vfprintf(stderr, fmt, args);
  248.   fprintf(stderr, "n");
  249.   va_end(args);
  250. }
  251. void init_parser()
  252. {
  253.   parser.current_line = parser.read_lines = 0;
  254.   memset(&var_reg,0, sizeof(var_reg));
  255. }
  256. int hex_val(int c)
  257. {
  258.   if (isdigit(c))
  259.     return c - '0';
  260.   else if ((c = tolower(c)) >= 'a' && c <= 'f')
  261.     return c - 'a' + 10;
  262.   else
  263.     return -1;
  264. }
  265. int dyn_string_cmp(DYNAMIC_STRING* ds, const char* fname)
  266. {
  267.   MY_STAT stat_info;
  268.   char *tmp;
  269.   int res;
  270.   int fd;
  271.   DBUG_ENTER("dyn_string_cmp");
  272.   if (!my_stat(fname, &stat_info, MYF(MY_WME)))
  273.     die(NullS);
  274.   if (stat_info.st_size != ds->length)
  275.     DBUG_RETURN(2);
  276.   if (!(tmp = (char*) my_malloc(ds->length, MYF(MY_WME))))
  277.     die(NullS);
  278.   if ((fd = my_open(fname, O_RDONLY, MYF(MY_WME))) < 0)
  279.     die(NullS);
  280.   if (my_read(fd, (byte*)tmp, stat_info.st_size, MYF(MY_WME|MY_NABP)))
  281.     die(NullS);
  282.   res = (memcmp(tmp, ds->str, stat_info.st_size)) ?  1 : 0;
  283.   my_free((gptr) tmp, MYF(0));
  284.   my_close(fd, MYF(MY_WME));
  285.   DBUG_RETURN(res);
  286. }
  287. static int check_result(DYNAMIC_STRING* ds, const char* fname,
  288. my_bool require_option)
  289. {
  290.   int error = 0;
  291.   int res=dyn_string_cmp(ds, fname);
  292.   if (res && require_option)
  293.     abort_not_supported_test();
  294.   switch (res)
  295.   {
  296.   case 0:
  297.     break; /* ok */
  298.   case 2:
  299.     verbose_msg("Result length mismatch");
  300.     error = 1;
  301.     break;
  302.   case 1:
  303.     verbose_msg("Result content mismatch");
  304.     error = 1;
  305.     break;
  306.   default: /* impossible */
  307.     die("Unknown error code from dyn_string_cmp()");
  308.   }
  309.   if (error)
  310.     reject_dump(fname, ds->str, ds->length);
  311.   return error;
  312. }
  313. VAR* var_get(char* var_name, char* var_name_end, int raw)
  314. {
  315.   int digit;
  316.   VAR* v;
  317.   if (*var_name++ != '$')
  318.   {
  319.     --var_name;
  320.     goto err;
  321.   }
  322.   digit = *var_name - '0';
  323.   if (!(digit < 10 && digit >= 0))
  324.   {
  325.     --var_name;
  326.     goto err;
  327.   }
  328.   v = var_reg + digit;
  329.   if (!raw && v->int_dirty)
  330.   {
  331.     sprintf(v->str_val, "%d", v->int_val);
  332.     v->int_dirty = 0;
  333.   }
  334.   return v;
  335. err:
  336.   if (var_name_end)
  337.     *var_name_end = 0;
  338.   die("Unsupported variable name: %s", var_name);
  339.   return 0;
  340. }
  341. int var_set(char* var_name, char* var_name_end, char* var_val,
  342.     char* var_val_end)
  343. {
  344.   int digit;
  345.   int val_len;
  346.   VAR* v;
  347.   if (*var_name++ != '$')
  348.     {
  349.       --var_name;
  350.       *var_name_end = 0;
  351.       die("Variable name in %s does not start with '$'", var_name);
  352.     }
  353.   digit = *var_name - '0';
  354.   if (!(digit < 10 && digit >= 0))
  355.     {
  356.       *var_name_end = 0;
  357.       die("Unsupported variable name: %s", var_name);
  358.     }
  359.   v = var_reg + digit;
  360.   if (v->alloced_len < (val_len = (int)(var_val_end - var_val)+1))
  361.     {
  362.       v->alloced_len = (val_len < MIN_VAR_ALLOC) ? MIN_VAR_ALLOC : val_len;
  363.      if (!(v->str_val =
  364.   v->str_val ? my_realloc(v->str_val, v->alloced_len,  MYF(MY_WME)) :
  365.    my_malloc(v->alloced_len, MYF(MY_WME))))
  366.  die("Out of memory");
  367.     }
  368.   memcpy(v->str_val, var_val, val_len-1);
  369.   v->str_val_len = val_len;
  370.   v->str_val[val_len] = 0;
  371.   v->int_val = atoi(v->str_val);
  372.   return 0;
  373. }
  374. int open_file(const char* name)
  375. {
  376.   if (*cur_file && cur_file == file_stack_end)
  377.     die("Source directives are nesting too deep");
  378.   if (!(*(cur_file+1) = my_fopen(name, O_RDONLY, MYF(MY_WME))))
  379.     die(NullS);
  380.   cur_file++;
  381.   *++lineno=1;
  382.   return 0;
  383. }
  384. int do_source(struct st_query* q)
  385. {
  386.   char* p=q->first_argument, *name;
  387.   if (!*p)
  388.     die("Missing file name in sourcen");
  389.   name = p;
  390.   while (*p && !isspace(*p))
  391.     p++;
  392.   *p = 0;
  393.   return open_file(name);
  394. }
  395. int eval_expr(VAR* v, char* p, char* p_end)
  396. {
  397.   VAR* vp;
  398.   if (*p == '$')
  399.     {
  400.       if ((vp = var_get(p,p_end,0)))
  401. {
  402.   memcpy(v, vp, sizeof(VAR));
  403.   return 0;
  404. }
  405.     }
  406.   else
  407.     {
  408.       v->str_val = p;
  409.       v->str_val_len = p_end ? p_end - p : strlen(p);
  410.       return 0;
  411.     }
  412.   if (p_end)
  413.     *p_end = 0;
  414.   die("Invalid expr: %s", p);
  415.   return 1;
  416. }
  417. int do_inc(struct st_query* q)
  418. {
  419.   char* p=q->first_argument;
  420.   VAR* v;
  421.   v = var_get(p, 0, 1);
  422.   v->int_val++;
  423.   v->int_dirty = 1;
  424.   return 0;
  425. }
  426. int do_dec(struct st_query* q)
  427. {
  428.   char* p=q->first_argument;
  429.   VAR* v;
  430.   v = var_get(p, 0, 1);
  431.   v->int_val--;
  432.   v->int_dirty = 1;
  433.   return 0;
  434. }
  435. int do_system(struct st_query* q)
  436. {
  437.   char* p=q->first_argument;
  438.   VAR v;
  439.   eval_expr(&v, p, 0); /* NULL terminated */
  440.   if (v.str_val_len > 1)
  441.     {
  442.       char expr_buf[512];
  443.       if ((uint)v.str_val_len > sizeof(expr_buf) - 1)
  444. v.str_val_len = sizeof(expr_buf) - 1;
  445.       memcpy(expr_buf, v.str_val, v.str_val_len);
  446.       expr_buf[v.str_val_len] = 0;
  447.       if (system(expr_buf) && q->abort_on_error)
  448. die("system command '%s' failed", expr_buf);
  449.     }
  450.   return 0;
  451. }
  452. int do_echo(struct st_query* q)
  453. {
  454.   char* p=q->first_argument;
  455.   VAR v;
  456.   eval_expr(&v, p, 0); /* NULL terminated */
  457.   if (v.str_val_len > 1)
  458.     {
  459.       fflush(stdout);
  460.       write(1, v.str_val, v.str_val_len - 1);
  461.     }
  462.   write(1, "n", 1);
  463.   return 0;
  464. }
  465. int do_sync_with_master(struct st_query* q)
  466. {
  467.   MYSQL_RES* res;
  468.   MYSQL_ROW row;
  469.   MYSQL* mysql = &cur_con->mysql;
  470.   char query_buf[FN_REFLEN+128];
  471.   int offset = 0;
  472.   char* p = q->first_argument;
  473.   if(*p)
  474.     offset = atoi(p);
  475.   
  476.   sprintf(query_buf, "select master_pos_wait('%s', %ld)", master_pos.file,
  477.   master_pos.pos + offset);
  478.   if(mysql_query(mysql, query_buf))
  479.     die("At line %u: failed in %s: %d: %s", start_lineno, query_buf,
  480. mysql_errno(mysql), mysql_error(mysql));
  481.   if(!(res = mysql_store_result(mysql)))
  482.     die("line %u: mysql_store_result() retuned NULL", start_lineno);
  483.   if(!(row = mysql_fetch_row(res)))
  484.     die("line %u: empty result in %s", start_lineno, query_buf);
  485.   if(!row[0])
  486.     die("Error on slave while syncing with master");
  487.   mysql_free_result(res);
  488.       
  489.   return 0;
  490. }
  491. int do_save_master_pos()
  492. {
  493.   MYSQL_RES* res;
  494.   MYSQL_ROW row;
  495.   MYSQL* mysql = &cur_con->mysql;
  496.   if(mysql_query(mysql, "show master status"))
  497.     die("At line %u: failed in show master status: %d: %s", start_lineno,
  498. mysql_errno(mysql), mysql_error(mysql));
  499.   if(!(res = mysql_store_result(mysql)))
  500.     die("line %u: mysql_store_result() retuned NULL", start_lineno);
  501.   if(!(row = mysql_fetch_row(res)))
  502.     die("line %u: empty result in show master status", start_lineno);
  503.   strncpy(master_pos.file, row[0], sizeof(master_pos.file));
  504.   master_pos.pos = strtoul(row[1], (char**) 0, 10); 
  505.   mysql_free_result(res);
  506.       
  507.   return 0;
  508. }
  509. int do_let(struct st_query* q)
  510. {
  511.   char* p=q->first_argument;
  512.   char *var_name, *var_name_end, *var_val_start;
  513.   if (!*p)
  514.     die("Missing variable name in letn");
  515.   var_name = p;
  516.   while(*p && (*p != '=' || isspace(*p)))
  517.     p++;
  518.   var_name_end = p;
  519.   if (*p == '=') p++;
  520.   while(*p && isspace(*p))
  521.     p++;
  522.   var_val_start = p;
  523.   while(*p && !isspace(*p))
  524.     p++;
  525.   return var_set(var_name, var_name_end, var_val_start, p);
  526. }
  527. int do_sleep(struct st_query* q)
  528. {
  529.   char* p=q->first_argument;
  530.   struct timeval t;
  531.   int dec_mul = 1000000;
  532.   while(*p && isspace(*p)) p++;
  533.   if (!*p)
  534.     die("Missing argument in sleepn");
  535.   t.tv_usec = 0;
  536.   if (opt_sleep)
  537.     t.tv_sec = opt_sleep;
  538.   else
  539.   {
  540.     t.tv_sec = atoi(p);
  541.     while(*p && *p != '.' && !isspace(*p))
  542.       p++;
  543.     if (*p == '.')
  544.     {
  545.       char c;
  546.       char *p_end;
  547.       p++;
  548.       p_end = p + 6;
  549.       for(;p <= p_end; ++p)
  550.       {
  551. c = *p - '0';
  552. if (c < 10 && c >= 0)
  553. {
  554.   t.tv_usec = t.tv_usec * 10 + c;
  555.   dec_mul /= 10;
  556. }
  557. else
  558.   break;
  559.       }
  560.     }
  561.   }
  562.   t.tv_usec *= dec_mul;
  563.   return select(0,0,0,0, &t);
  564. }
  565. static void get_file_name(char *filename, struct st_query* q)
  566. {
  567.   char* p=q->first_argument;
  568.   strnmov(filename, p, FN_REFLEN);
  569.   /* Remove end space */
  570.   while (p > filename && isspace(p[-1]))
  571.     p--;
  572.   p[0]=0;
  573. }
  574. static void get_ints(uint *to,struct st_query* q)
  575. {
  576.   char* p=q->first_argument;
  577.   long val;
  578.   DBUG_ENTER("get_ints");
  579.   if (!*p)
  580.     die("Missing argument in %sn", q->query);
  581.   for (; (p=str2int(p,10,(long) INT_MIN, (long) INT_MAX, &val)) ; p++)
  582.   {
  583.     *to++= (uint) val;
  584.     if (*p != ',')
  585.       break;
  586.   }
  587.   *to++=0; /* End of data */
  588.   DBUG_VOID_RETURN;
  589. }
  590. /*
  591.   Get a string;  Return ptr to end of string
  592.   Strings may be surrounded by " or '
  593. */
  594. static void get_string(char **to_ptr, char **from_ptr,
  595.        struct st_query* q)
  596. {
  597.   reg1 char c,sep;
  598.   char *to= *to_ptr, *from= *from_ptr;
  599.   DBUG_ENTER("get_string");
  600.   /* Find separator */
  601.   if (*from == '"' || *from == ''')
  602.     sep= *from++;
  603.   else
  604.     sep=' '; /* Separated with space */
  605.   for ( ; (c=*from) ; from++)
  606.   {
  607.     if (c == '\' && from[1])
  608.     { /* Escaped character */
  609.       /* We can't translate  -> ASCII 0 as replace can't handle ASCII 0 */
  610.       switch (*++from) {
  611.       case 'n':
  612. *to++= 'n';
  613. break;
  614.       case 't':
  615. *to++= 't';
  616. break;
  617.       case 'r':
  618. *to++ = 'r';
  619. break;
  620.       case 'b':
  621. *to++ = 'b';
  622. break;
  623.       case 'Z': /* ^Z must be escaped on Win32 */
  624. *to++='32';
  625. break;
  626.       default:
  627. *to++ = *from;
  628. break;
  629.       }
  630.     }
  631.     else if (c == sep)
  632.     {
  633.       if (c == ' ' || c != *++from)
  634. break; /* Found end of string */
  635.       *to++=c; /* Copy duplicated separator */
  636.     }
  637.     else
  638.       *to++=c;
  639.   }
  640.   if (*from != ' ' && *from)
  641.     die("Wrong string argument in %sn", q->query);
  642.   while (isspace(*from)) /* Point to next string */
  643.     from++;
  644.   *to++ =0; /* End of string marker */
  645.   *to_ptr= to;
  646.   *from_ptr= from;
  647. }
  648. /*
  649.   Get arguments for replace. The syntax is:
  650.   replace from to [from to ...]
  651.   Where each argument may be quoted with ' or "
  652. */
  653. static void get_replace(struct st_query *q)
  654. {
  655.   uint i;
  656.   char *from=q->first_argument;
  657.   char *buff,*start;
  658.   char word_end_chars[256],*pos;
  659.   POINTER_ARRAY to_array,from_array;
  660.   DBUG_ENTER("get_replace");
  661.   bzero((char*) &to_array,sizeof(to_array));
  662.   bzero((char*) &from_array,sizeof(from_array));
  663.   if (!*from)
  664.     die("Missing argument in %sn", q->query);
  665.   start=buff=my_malloc(strlen(from)+1,MYF(MY_WME | MY_FAE));
  666.   while (*from)
  667.   {
  668.     char *to=buff;
  669.     get_string(&buff, &from, q);
  670.     if (!*from)
  671.       die("Wrong number of arguments to replace in %sn", q->query);
  672.     insert_pointer_name(&from_array,to);
  673.     to=buff;
  674.     get_string(&buff, &from, q);
  675.     insert_pointer_name(&to_array,to);
  676.   }
  677.   for (i=1,pos=word_end_chars ; i < 256 ; i++)
  678.     if (isspace(i))
  679.       *pos++=i;
  680.   *pos=0; /* End pointer */
  681.   if (!(glob_replace=init_replace((char**) from_array.typelib.type_names,
  682.   (char**) to_array.typelib.type_names,
  683.   (uint) from_array.typelib.count,
  684.   word_end_chars)) ||
  685.       initialize_replace_buffer())
  686.     die("Can't initialize replace from %sn", q->query);
  687.   free_pointer_array(&from_array);
  688.   free_pointer_array(&to_array);
  689.   my_free(start, MYF(0));
  690. }
  691. void free_replace()
  692. {
  693.   DBUG_ENTER("free_replace");
  694.   my_free((char*) glob_replace,MYF(0));
  695.   glob_replace=0;
  696.   free_replace_buffer();
  697.   DBUG_VOID_RETURN;
  698. }
  699. int select_connection(struct st_query* q)
  700. {
  701.   char* p=q->first_argument, *name;
  702.   struct connection *con;
  703.   DBUG_ENTER("select_connection");
  704.   DBUG_PRINT("enter",("name: '%s'",p));
  705.   if (!*p)
  706.     die("Missing connection name in connectn");
  707.   name = p;
  708.   while(*p && !isspace(*p))
  709.     p++;
  710.   *p = 0;
  711.   for (con = cons; con < next_con; con++)
  712.   {
  713.     if (!strcmp(con->name, name))
  714.     {
  715.       cur_con = con;
  716.       DBUG_RETURN(0);
  717.     }
  718.   }
  719.   die("connection '%s' not found in connection pool", name);
  720.   DBUG_RETURN(1); /* Never reached */
  721. }
  722. int close_connection(struct st_query* q)
  723. {
  724.   char* p=q->first_argument, *name;
  725.   struct connection *con;
  726.   DBUG_ENTER("close_connection");
  727.   DBUG_PRINT("enter",("name: '%s'",p));
  728.   if (!*p)
  729.     die("Missing connection name in connectn");
  730.   name = p;
  731.   while(*p && !isspace(*p))
  732.     p++;
  733.   *p = 0;
  734.   for(con = cons; con < next_con; con++)
  735.   {
  736.     if (!strcmp(con->name, name))
  737.     {
  738.       if(q->type == Q_DIRTY_CLOSE)
  739. {
  740.   if(con->mysql.net.vio)
  741.     {
  742.       vio_delete(con->mysql.net.vio);
  743.       con->mysql.net.vio = 0;
  744.     }
  745. }
  746.       mysql_close(&con->mysql);
  747.       DBUG_RETURN(0);
  748.     }
  749.   }
  750.   die("connection '%s' not found in connection pool", name);
  751.   DBUG_RETURN(1); /* Never reached */
  752. }
  753. /* this one now is a hack - we may want to improve in in the
  754.    future to handle quotes. For now we assume that anything that is not
  755.    a comma, a space or ) belongs to the argument. space is a chopper, comma or
  756.    ) are delimiters/terminators
  757. */
  758. char* safe_get_param(char* str, char** arg, const char* msg)
  759. {
  760.   DBUG_ENTER("safe_get_param");
  761.   while(*str && isspace(*str)) str++;
  762.   *arg = str;
  763.   while(*str && *str != ',' && *str != ')')
  764.     {
  765.       if (isspace(*str)) *str = 0;
  766.       str++;
  767.     }
  768.   if (!*str)
  769.     die(msg);
  770.   *str++ = 0;
  771.   DBUG_RETURN(str);
  772. }
  773. int do_connect(struct st_query* q)
  774. {
  775.   char* con_name, *con_user,*con_pass, *con_host, *con_port_str,
  776.     *con_db, *con_sock;
  777.   char* p=q->first_argument;
  778.   char buff[FN_REFLEN];
  779.   DBUG_ENTER("do_connect");
  780.   DBUG_PRINT("enter",("connect: %s",p));
  781.   if (*p != '(')
  782.     die("Syntax error in connect - expected '(' found '%c'", *p);
  783.   p++;
  784.   p = safe_get_param(p, &con_name, "missing connection name");
  785.   p = safe_get_param(p, &con_host, "missing connection host");
  786.   p = safe_get_param(p, &con_user, "missing connection user");
  787.   p = safe_get_param(p, &con_pass, "missing connection password");
  788.   p = safe_get_param(p, &con_db, "missing connection db");
  789.   p = safe_get_param(p, &con_port_str, "missing connection port");
  790.   p = safe_get_param(p, &con_sock, "missing connection socket");
  791.   if (next_con == cons_end)
  792.     die("Connection limit exhausted - increase MAX_CONS in mysqltest.c");
  793.   if (!mysql_init(&next_con->mysql))
  794.     die("Failed on mysql_init()");
  795.   con_sock=fn_format(buff, con_sock, TMPDIR,"",0);
  796.   if (!mysql_real_connect(&next_con->mysql, con_host, con_user, con_pass,
  797.  con_db, atoi(con_port_str), con_sock, 0))
  798.     die("Could not open connection '%s': %s", con_name,
  799. mysql_error(&next_con->mysql));
  800.   if (!(next_con->name = my_strdup(con_name, MYF(MY_WME))))
  801.     die(NullS);
  802.   cur_con = next_con++;
  803.   DBUG_RETURN(0);
  804. }
  805. int do_done(struct st_query* q)
  806. {
  807.   q->type = Q_END_BLOCK;
  808.   if (cur_block == block_stack)
  809.     die("Stray '}' - end of block before beginning");
  810.   if (block_ok)
  811.     parser.current_line = *--cur_block;
  812.   else
  813.     {
  814.       if (!--false_block_depth)
  815. block_ok = 1;
  816.       ++parser.current_line;
  817.     }
  818.   return 0;
  819. }
  820. int do_while(struct st_query* q)
  821. {
  822.   char* p=q->first_argument;
  823.   char* expr_start, *expr_end;
  824.   VAR v;
  825.   if (cur_block == block_stack_end)
  826. die("Nesting too deeply");
  827.   if (!block_ok)
  828.     {
  829.       ++false_block_depth;
  830.       return 0;
  831.     }
  832.   expr_start = strchr(p, '(');
  833.   if (!expr_start)
  834.     die("missing '(' in while");
  835.   expr_end = strrchr(expr_start, ')');
  836.   if (!expr_end)
  837.     die("missing ')' in while");
  838.   eval_expr(&v, ++expr_start, --expr_end);
  839.   *cur_block++ = parser.current_line++;
  840.   if (!v.int_val)
  841.     {
  842.       block_ok = 0;
  843.       false_block_depth = 1;
  844.     }
  845.   return 0;
  846. }
  847. int safe_copy_unescape(char* dest, char* src, int size)
  848. {
  849.   register char* p_dest = dest, *p_src = src;
  850.   register int c, val;
  851.   enum { ST_NORMAL, ST_ESCAPED, ST_HEX2} state = ST_NORMAL ;
  852.   size--; /* just to make life easier */
  853.   for(; p_dest - size < dest && p_src - size < src
  854. && (c = *p_src) != 'n' && c; ++p_src )
  855.     {
  856.       switch(state)
  857. {
  858. case ST_NORMAL:
  859.   if (c == '\')
  860.     {
  861.       state = ST_ESCAPED;
  862.     }
  863.   else
  864.     *p_dest++ = c;
  865.   break;
  866. case ST_ESCAPED:
  867.   if ((val = hex_val(c)) > 0)
  868.     {
  869.       *p_dest = val;
  870.       state = ST_HEX2;
  871.     }
  872.   else
  873.     {
  874.       state = ST_NORMAL;
  875.       *p_dest++ = c;
  876.     }
  877.   break;
  878. case ST_HEX2:
  879.   if ((val = hex_val(c)) > 0)
  880.     {
  881.       *p_dest = (*p_dest << 4) + val;
  882.       p_dest++;
  883.     }
  884.   else
  885.     *p_dest++ = c;
  886.   state = ST_NORMAL;
  887.   break;
  888. }
  889.     }
  890.   *p_dest = 0;
  891.   return (p_dest - dest);
  892. }
  893. int read_line(char* buf, int size)
  894. {
  895.   int c;
  896.   char* p = buf, *buf_end = buf + size-1;
  897.   int no_save = 0;
  898.   enum {R_NORMAL, R_Q1, R_ESC_Q_Q1, R_ESC_Q_Q2,
  899. R_ESC_SLASH_Q1, R_ESC_SLASH_Q2,
  900. R_Q2, R_COMMENT, R_LINE_START} state = R_LINE_START;
  901.   start_lineno= *lineno;
  902.   for (; p < buf_end ;)
  903.   {
  904.     no_save = 0;
  905.     c = fgetc(*cur_file);
  906.     if (feof(*cur_file))
  907.     {
  908.       if ((*cur_file) != stdin)
  909. my_fclose(*cur_file,MYF(0));
  910.       if (cur_file == file_stack)
  911. return 1;
  912.       else
  913.       {
  914. cur_file--;
  915. lineno--;
  916. continue;
  917.       }
  918.     }
  919.     switch(state) {
  920.     case R_NORMAL:
  921.       /*  Only accept '{' in the beginning of a line */
  922.       if (c == ';')
  923.       {
  924. *p = 0;
  925. return 0;
  926.       }
  927.       else if (c == ''')
  928. state = R_Q1;
  929.       else if (c == '"')
  930. state = R_Q2;
  931.       else if (c == 'n')
  932.       {
  933. state = R_LINE_START;
  934. (*lineno)++;
  935.       }
  936.       break;
  937.     case R_COMMENT:
  938.       if (c == 'n')
  939.       {
  940. *p=0;
  941. (*lineno)++;
  942. return 0;
  943.       }
  944.       break;
  945.     case R_LINE_START:
  946.       if (c == '#' || c == '-')
  947.       {
  948. state = R_COMMENT;
  949.       }
  950.       else if (isspace(c))
  951.       {
  952. if (c == 'n')
  953.   start_lineno= ++*lineno; /* Query hasn't started yet */
  954. no_save = 1;
  955.       }
  956.       else if (c == '}')
  957.       {
  958. *buf++ = '}';
  959. *buf = 0;
  960. return 0;
  961.       }
  962.       else if (c == ';' || c == '{')
  963.       {
  964. *p = 0;
  965. return 0;
  966.       }
  967.       else
  968. state = R_NORMAL;
  969.       break;
  970.     case R_Q1:
  971.       if (c == ''')
  972. state = R_ESC_Q_Q1;
  973.       else if (c == '\')
  974. state = R_ESC_SLASH_Q1;
  975.       break;
  976.     case R_ESC_Q_Q1:
  977.       if (c == ';')
  978.       {
  979. *p = 0;
  980. return 0;
  981.       }
  982.       if (c != ''')
  983. state = R_NORMAL;
  984.       else
  985. state = R_Q1;
  986.       break;
  987.     case R_ESC_SLASH_Q1:
  988.       state = R_Q1;
  989.       break;
  990.     case R_Q2:
  991.       if (c == '"')
  992. state = R_ESC_Q_Q2;
  993.       else if (c == '\')
  994. state = R_ESC_SLASH_Q2;
  995.       break;
  996.     case R_ESC_Q_Q2:
  997.       if (c == ';')
  998.       {
  999. *p = 0;
  1000. return 0;
  1001.       }
  1002.       if (c != '"')
  1003. state = R_NORMAL;
  1004.       else
  1005. state = R_Q2;
  1006.       break;
  1007.     case R_ESC_SLASH_Q2:
  1008.       state = R_Q2;
  1009.       break;
  1010.     }
  1011.     if (!no_save)
  1012.       *p++ = c;
  1013.   }
  1014.   *p=0; /* Always end with  */
  1015.   return feof(*cur_file);
  1016. }
  1017. static char read_query_buf[MAX_QUERY];
  1018. int read_query(struct st_query** q_ptr)
  1019. {
  1020.   char *p = read_query_buf, * p1 ;
  1021.   int c, expected_errno;
  1022.   struct st_query* q;
  1023.   if (parser.current_line < parser.read_lines)
  1024.   {
  1025.     get_dynamic(&q_lines, (gptr) q_ptr, parser.current_line) ;
  1026.     return 0;
  1027.   }
  1028.   if (!(*q_ptr=q=(struct st_query*) my_malloc(sizeof(*q), MYF(MY_WME))) ||
  1029.       insert_dynamic(&q_lines, (gptr) &q))
  1030.     die(NullS);
  1031.   q->record_file[0] = 0;
  1032.   q->require_file=0;
  1033.   q->first_word_len = 0;
  1034.   memcpy((gptr) q->expected_errno, (gptr) global_expected_errno,
  1035.  sizeof(global_expected_errno));
  1036.   q->abort_on_error = global_expected_errno[0] == 0;
  1037.   bzero((gptr) global_expected_errno,sizeof(global_expected_errno));
  1038.   q->type = Q_UNKNOWN;
  1039.   q->query=0;
  1040.   if (read_line(read_query_buf, sizeof(read_query_buf)))
  1041.     return 1;
  1042.   if (*p == '#')
  1043.   {
  1044.     q->type = Q_COMMENT;
  1045.   }
  1046.   else if (p[0] == '-' && p[1] == '-')
  1047.   {
  1048.     q->type = Q_COMMENT_WITH_COMMAND;
  1049.     p+=2; /* To calculate first word */
  1050.   }
  1051.   else
  1052.   {
  1053.     if (*p == '!')
  1054.     {
  1055.       q->abort_on_error = 0;
  1056.       p++;
  1057.       if (*p == '$')
  1058.       {
  1059. expected_errno = 0;
  1060. p++;
  1061. for (;isdigit(*p);p++)
  1062.   expected_errno = expected_errno * 10 + *p - '0';
  1063. q->expected_errno[0] = expected_errno;
  1064. q->expected_errno[1] = 0;
  1065.       }
  1066.     }
  1067.     while(*p && isspace(*p)) p++ ;
  1068.     if (*p == '@')
  1069.     {
  1070.       p++;
  1071.       p1 = q->record_file;
  1072.       while(!isspace(c = *p) &&
  1073.     p1 < q->record_file + sizeof(q->record_file) - 1)
  1074. *p1++ = *p++;
  1075.       *p1 = 0;
  1076.     }
  1077.   }
  1078.   while (*p && isspace(*p)) p++;
  1079.   if (!(q->query=my_strdup(p,MYF(MY_WME))))
  1080.     die(NullS);
  1081.   /* Calculate first word and first argument */
  1082.   for (p=q->query; *p && !isspace(*p) ; p++) ;
  1083.   q->first_word_len = (uint) (p - q->query);
  1084.   while (*p && isspace(*p)) p++;
  1085.   q->first_argument=p;
  1086.   parser.read_lines++;
  1087.   return 0;
  1088. }
  1089. struct option long_options[] =
  1090. {
  1091.   {"debug",       optional_argument, 0, '#'},
  1092.   {"database",    required_argument, 0, 'D'},
  1093.   {"help",        no_argument,       0, '?'},
  1094.   {"host",        required_argument, 0, 'h'},
  1095.   {"password",    optional_argument, 0, 'p'},
  1096.   {"port",        required_argument, 0, 'P'},
  1097.   {"quiet",       no_argument,       0, 'q'},
  1098.   {"record",      no_argument,       0, 'r'},
  1099.   {"result-file", required_argument, 0, 'R'},
  1100.   {"silent",      no_argument,       0, 'q'},
  1101.   {"sleep",       required_argument, 0, 'T'},
  1102.   {"socket",      required_argument, 0, 'S'},
  1103.   {"tmpdir",      required_argument, 0, 't'},
  1104.   {"user",        required_argument, 0, 'u'},
  1105.   {"verbose",     no_argument,       0, 'v'},
  1106.   {"version",     no_argument,       0, 'V'},
  1107.   {0, 0, 0, 0}
  1108. };
  1109. static void print_version(void)
  1110. {
  1111.   printf("%s  Ver %s Distrib %s, for %s (%s)n",my_progname,MTEST_VERSION,
  1112.  MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
  1113. }
  1114. void usage()
  1115. {
  1116.   print_version();
  1117.   printf("MySQL AB, by Sasha, Matt & Montyn");
  1118.   printf("This software comes with ABSOLUTELY NO WARRANTYnn");
  1119.   printf("Runs a test against the mysql server and compares output with a results file.nn");
  1120.   printf("Usage: %s [OPTIONS] [database] < test_filen", my_progname);
  1121.   printf("n
  1122.   -?, --help               Display this help and exit.n");
  1123. #ifndef DBUG_OFF
  1124.   puts("
  1125.   -#, --debug=[...]        Output debug log. Often this is 'd:t:o,filename`");
  1126. #endif
  1127.   printf("
  1128.   -h, --host=...           Connect to host.n
  1129.   -u, --user=...           User for login.n
  1130.   -p[password], --password[=...]n
  1131.                            Password to use when connecting to server.n
  1132.   -D, --database=...       Database to use.n
  1133.   -P, --port=...           Port number to use for connection.n
  1134.   -S, --socket=...         Socket file to use for connection.n
  1135.   -t, --tmpdir=...    Temporary directory where sockets are putn
  1136.   -T, --sleep=#    Sleep always this many seconds on sleep commandsn
  1137.   -r, --record             Record output of test_file into result file.n
  1138.   -R, --result-file=...    Read/Store result from/in this file.n
  1139.   -v, --verbose            Write more.n
  1140.   -q, --quiet, --silent    Suppress all normal output.n
  1141.   -V, --version            Output version information and exit.n
  1142.   --no-defaults            Don't read default options from any options file.nn");
  1143. }
  1144. int parse_args(int argc, char **argv)
  1145. {
  1146.   int c, option_index = 0;
  1147.   my_bool tty_password=0;
  1148.   load_defaults("my",load_default_groups,&argc,&argv);
  1149.   default_argv= argv;
  1150.   while((c = getopt_long(argc, argv, "h:p::u:P:D:S:R:t:T:#:?rvVq",
  1151.  long_options, &option_index)) != EOF)
  1152.     {
  1153.       switch(c) {
  1154.       case '#':
  1155. DBUG_PUSH(optarg ? optarg : "d:t:O,/tmp/mysqltest.trace");
  1156. break;
  1157.       case 'v':
  1158. verbose = 1;
  1159. break;
  1160.       case 'r':
  1161. record = 1;
  1162. break;
  1163.       case 'u':
  1164. user = optarg;
  1165. break;
  1166.       case 'R':
  1167. result_file = optarg;
  1168. break;
  1169.       case 'p':
  1170. if (optarg)
  1171. {
  1172.   my_free(pass,MYF(MY_ALLOW_ZERO_PTR));
  1173.   pass=my_strdup(optarg,MYF(MY_FAE));
  1174.   while (*optarg) *optarg++= 'x'; /* Destroy argument */
  1175. }
  1176. else
  1177.   tty_password=1;
  1178. break;
  1179.       case 'P':
  1180. port = atoi(optarg);
  1181. break;
  1182.       case 'S':
  1183. unix_sock = optarg;
  1184. break;
  1185.       case 'D':
  1186. db = optarg;
  1187. break;
  1188.       case 'h':
  1189. host = optarg;
  1190. break;
  1191.       case 'q':
  1192. silent = 1;
  1193. break;
  1194.       case 't':
  1195. strnmov(TMPDIR,optarg,sizeof(TMPDIR));
  1196. break;
  1197.       case 'T':
  1198. opt_sleep=atoi(optarg);
  1199. break;
  1200.       case 'V':
  1201. print_version();
  1202. exit(0);
  1203.       case '?':
  1204. usage();
  1205. exit(1); /* Unknown option */
  1206.       default:
  1207. usage();
  1208. exit(1);
  1209.       }
  1210.     }
  1211.   argc-=optind;
  1212.   argv+=optind;
  1213.   if (argc > 1)
  1214.   {
  1215.     usage();
  1216.     exit(1);
  1217.   }
  1218.   if (argc == 1)
  1219.     db= *argv;
  1220.   if (tty_password)
  1221.     pass=get_tty_password(NullS);
  1222.   return 0;
  1223. }
  1224. char* safe_str_append(char* buf, const char* str, int size)
  1225. {
  1226.   int i,c ;
  1227.   for(i = 0; (c = *str++) &&  i < size - 1; i++)
  1228.     *buf++ = c;
  1229.   *buf = 0;
  1230.   return buf;
  1231. }
  1232. void str_to_file(const char* fname, char* str, int size)
  1233. {
  1234.   int fd;
  1235.   if ((fd = my_open(fname, O_WRONLY | O_CREAT | O_TRUNC,
  1236.     MYF(MY_WME | MY_FFNF))) < 0)
  1237.     die("Could not open %s: errno = %d", fname, errno);
  1238.   if (my_write(fd, (byte*)str, size, MYF(MY_WME|MY_FNABP)))
  1239.     die("write failed");
  1240.   my_close(fd, MYF(0));
  1241. }
  1242. void reject_dump(const char* record_file, char* buf, int size)
  1243. {
  1244.   char reject_file[FN_REFLEN];
  1245.   str_to_file(fn_format(reject_file, record_file,"",".reject",2), buf, size);
  1246. }
  1247. int run_query(MYSQL* mysql, struct st_query* q, int flags)
  1248. {
  1249.   MYSQL_RES* res = 0;
  1250.   MYSQL_FIELD* fields;
  1251.   MYSQL_ROW row;
  1252.   int num_fields,i, error = 0;
  1253.   unsigned long* lengths;
  1254.   char* val;
  1255.   int len;
  1256.   int q_error = 0 ;
  1257.   DYNAMIC_STRING *ds;
  1258.   DYNAMIC_STRING ds_tmp;
  1259.   DBUG_ENTER("run_query");
  1260.   if ( q->record_file[0])
  1261.   {
  1262.     init_dynamic_string(&ds_tmp, "", 16384, 65536);
  1263.     ds = &ds_tmp;
  1264.   }
  1265.   else
  1266.     ds= &ds_res;
  1267.   
  1268.   if ((flags & QUERY_SEND) &&
  1269.       (q_error = mysql_send_query(mysql, q->query, strlen(q->query))))
  1270.     die("At line %u: unable to send query '%s'", start_lineno, q->query);
  1271.   if(!(flags & QUERY_REAP))
  1272.     return 0;
  1273.   
  1274.   if (mysql_read_query_result(mysql))
  1275.   {
  1276.     if (q->require_file)
  1277.       abort_not_supported_test();
  1278.     if (q->abort_on_error)
  1279.       die("At line %u: query '%s' failed: %d: %s", start_lineno, q->query,
  1280.   mysql_errno(mysql), mysql_error(mysql));
  1281.     else
  1282.     {
  1283.       for (i=0 ; q->expected_errno[i] ; i++)
  1284.       {
  1285. if ((q->expected_errno[i] == mysql_errno(mysql)))
  1286.   goto end; /* Ok */
  1287.       }
  1288.       if (i)
  1289.       {
  1290. verbose_msg("query '%s' failed with wrong errno
  1291.  %d instead of %d...", q->query, mysql_errno(mysql), q->expected_errno[0]);
  1292. goto end;
  1293.       }
  1294.       verbose_msg("query '%s' failed: %d: %s", q->query, mysql_errno(mysql),
  1295.   mysql_error(mysql));
  1296.       /* if we do not abort on error, failure to run the query does
  1297.  not fail the whole test case
  1298.       */
  1299.       goto end;
  1300.     }
  1301.   }
  1302.   if (q->expected_errno[0])
  1303.   {
  1304.     error = 1;
  1305.     verbose_msg("query '%s' succeeded - should have failed with errno %d...",
  1306. q->query, q->expected_errno[0]);
  1307.     goto end;
  1308.   }
  1309.   if (!(res = mysql_store_result(mysql)) && mysql_field_count(mysql))
  1310.   {
  1311.     if (q->require_file)
  1312.       abort_not_supported_test();
  1313.     if (q->abort_on_error)
  1314.       die("At line %u: Failed in mysql_store_result for query '%s' (%d)",
  1315.   start_lineno, q->query, mysql_errno(mysql));
  1316.     else
  1317.     {
  1318.       verbose_msg("failed in mysql_store_result for query '%s' (%d)", q->query,
  1319.   mysql_errno(mysql));
  1320.       error = 1;
  1321.       goto end;
  1322.     }
  1323.   }
  1324.   if (!res) goto end;
  1325.   fields =  mysql_fetch_fields(res);
  1326.   num_fields = mysql_num_fields(res);
  1327.   for( i = 0; i < num_fields; i++)
  1328.   {
  1329.     if (i)
  1330.       dynstr_append_mem(ds, "t", 1);
  1331.     dynstr_append(ds, fields[i].name);
  1332.   }
  1333.   dynstr_append_mem(ds, "n", 1);
  1334.   while((row = mysql_fetch_row(res)))
  1335.   {
  1336.     lengths = mysql_fetch_lengths(res);
  1337.     for(i = 0; i < num_fields; i++)
  1338.     {
  1339.       val = (char*)row[i];
  1340.       len = lengths[i];
  1341.       if (!val)
  1342.       {
  1343. val = (char*)"NULL";
  1344. len = 4;
  1345.       }
  1346.       if (i)
  1347. dynstr_append_mem(ds, "t", 1);
  1348.       if (glob_replace)
  1349.       {
  1350. len=(int) replace_strings(glob_replace, &out_buff, &out_length, val);
  1351. if (len == -1)
  1352.   die("Out of memory in replacen");
  1353. val=out_buff;
  1354.       }
  1355.       dynstr_append_mem(ds, val, len);
  1356.     }
  1357.     dynstr_append_mem(ds, "n", 1);
  1358.   }
  1359.   if (glob_replace)
  1360.     free_replace();
  1361.   if (record)
  1362.   {
  1363.     if (!q->record_file[0] && !result_file)
  1364.       die("At line %u: Missing result file", start_lineno);
  1365.     if (!result_file)
  1366.       str_to_file(q->record_file, ds->str, ds->length);
  1367.   }
  1368.   else if (q->record_file[0])
  1369.   {
  1370.     error = check_result(ds, q->record_file, q->require_file);
  1371.   }
  1372. end:
  1373.   if (res) mysql_free_result(res);
  1374.   if (ds == &ds_tmp)
  1375.     dynstr_free(&ds_tmp);
  1376.   DBUG_RETURN(error);
  1377. }
  1378. void get_query_type(struct st_query* q)
  1379. {
  1380.   char save;
  1381.   uint type;
  1382.   if (*q->query == '}')
  1383.   {
  1384.     q->type = Q_END_BLOCK;
  1385.     return;
  1386.   }
  1387.   if (q->type != Q_COMMENT_WITH_COMMAND)
  1388.     q->type = Q_QUERY;
  1389.   save=q->query[q->first_word_len];
  1390.   q->query[q->first_word_len]=0;
  1391.   type=find_type(q->query, &command_typelib, 1+2);
  1392.   q->query[q->first_word_len]=save;
  1393.   if (type > 0)
  1394.     q->type=type; /* Found command */
  1395. }
  1396. int main(int argc, char** argv)
  1397. {
  1398.   int error = 0;
  1399.   struct st_query* q;
  1400.   my_bool require_file=0,q_send_flag=0;
  1401.   char save_file[FN_REFLEN];
  1402.   MY_INIT(argv[0]);
  1403.   save_file[0]=0;
  1404.   TMPDIR[0]=0;
  1405.   memset(cons, 0, sizeof(cons));
  1406.   cons_end = cons + MAX_CONS;
  1407.   next_con = cons + 1;
  1408.   cur_con = cons;
  1409.   memset(file_stack, 0, sizeof(file_stack));
  1410.   memset(&master_pos, 0, sizeof(master_pos));
  1411.   file_stack_end = file_stack + MAX_INCLUDE_DEPTH;
  1412.   cur_file = file_stack;
  1413.   lineno   = lineno_stack;
  1414.   init_dynamic_array(&q_lines, sizeof(struct st_query*), INIT_Q_LINES,
  1415.      INIT_Q_LINES);
  1416.   memset(block_stack, 0, sizeof(block_stack));
  1417.   block_stack_end = block_stack + BLOCK_STACK_DEPTH;
  1418.   cur_block = block_stack;
  1419.   init_dynamic_string(&ds_res, "", 0, 65536);
  1420.   parse_args(argc, argv);
  1421.   if (!*cur_file)
  1422.     *cur_file = stdin;
  1423.   *lineno=1;
  1424.   if (!( mysql_init(&cur_con->mysql)))
  1425.     die("Failed in mysql_init()");
  1426.   cur_con->name = my_strdup("default", MYF(MY_WME));
  1427.   if (!cur_con->name)
  1428.     die("Out of memory");
  1429.   if (!mysql_real_connect(&cur_con->mysql, host,
  1430.  user, pass, db, port, unix_sock,
  1431.      0))
  1432.     die("Failed in mysql_real_connect(): %s", mysql_error(&cur_con->mysql));
  1433.   while (!read_query(&q))
  1434.   {
  1435.     int current_line_inc = 1, processed = 0;
  1436.     if (q->type == Q_UNKNOWN || q->type == Q_COMMENT_WITH_COMMAND)
  1437.       get_query_type(q);
  1438.     if (block_ok)
  1439.     {
  1440.       processed = 1;
  1441.       switch (q->type) {
  1442.       case Q_CONNECT: do_connect(q); break;
  1443.       case Q_CONNECTION: select_connection(q); break;
  1444.       case Q_DISCONNECT:
  1445.       case Q_DIRTY_CLOSE:
  1446. close_connection(q); break;
  1447.       case Q_SOURCE: do_source(q); break;
  1448.       case Q_SLEEP: do_sleep(q); break;
  1449.       case Q_INC: do_inc(q); break;
  1450.       case Q_DEC: do_dec(q); break;
  1451.       case Q_ECHO: do_echo(q); break;
  1452.       case Q_SYSTEM: do_system(q); break;
  1453.       case Q_LET: do_let(q); break;
  1454.       case Q_QUERY:
  1455.       case Q_REAP:
  1456.       {
  1457. int flags = QUERY_REAP;
  1458. if (q->type == Q_QUERY)
  1459.   flags |= QUERY_SEND;
  1460. if (q_send_flag)
  1461. {
  1462.   flags=QUERY_SEND;
  1463.   q_send_flag=0;
  1464. }
  1465. if (save_file[0])
  1466. {
  1467.   strmov(q->record_file,save_file);
  1468.   q->require_file=require_file;
  1469.   save_file[0]=0;
  1470. }
  1471. error |= run_query(&cur_con->mysql, q, flags);
  1472. break;
  1473.       }
  1474.       case Q_SEND:
  1475. q_send_flag=1;
  1476. break;
  1477.       case Q_RESULT:
  1478. get_file_name(save_file,q);
  1479. require_file=0;
  1480. break;
  1481.       case Q_ERROR:
  1482. get_ints(global_expected_errno,q);
  1483. break;
  1484.       case Q_REQUIRE:
  1485. get_file_name(save_file,q);
  1486. require_file=1;
  1487. break;
  1488.       case Q_REPLACE:
  1489. get_replace(q);
  1490. break;
  1491.       case Q_SAVE_MASTER_POS: do_save_master_pos(q); break;
  1492.       case Q_SYNC_WITH_MASTER: do_sync_with_master(q); break;
  1493.       case Q_COMMENT: /* Ignore row */
  1494.       case Q_COMMENT_WITH_COMMAND:
  1495.       case Q_PING:
  1496. (void) mysql_ping(&cur_con->mysql);
  1497. break;
  1498.       default: processed = 0; break;
  1499.       }
  1500.     }
  1501.     if (!processed)
  1502.     {
  1503.       current_line_inc = 0;
  1504.       switch(q->type)
  1505.       {
  1506.       case Q_WHILE: do_while(q); break;
  1507.       case Q_END_BLOCK: do_done(q); break;
  1508.       default: current_line_inc = 1; break;
  1509.       }
  1510.     }
  1511.     parser.current_line += current_line_inc;
  1512.   }
  1513.   if (result_file && ds_res.length)
  1514.   {
  1515.     if (!record)
  1516.       error |= check_result(&ds_res, result_file, q->require_file);
  1517.     else
  1518.       str_to_file(result_file, ds_res.str, ds_res.length);
  1519.   }
  1520.   dynstr_free(&ds_res);
  1521.   if (!silent) {
  1522.     if(error)
  1523.       printf("not okn");
  1524.     else
  1525.       printf("okn");
  1526.   }
  1527.   free_used_memory();
  1528.   exit(error ? 1 : 0);
  1529.   return error ? 1 : 0; /* Keep compiler happy */
  1530. }
  1531. /****************************************************************************
  1532. * Handle replacement of strings
  1533. ****************************************************************************/
  1534. #define PC_MALLOC 256 /* Bytes for pointers */
  1535. #define PS_MALLOC 512 /* Bytes for data */
  1536. #define SPACE_CHAR 256
  1537. #define START_OF_LINE 257
  1538. #define END_OF_LINE 258
  1539. #define LAST_CHAR_CODE 259
  1540. typedef struct st_replace {
  1541.   bool   found;
  1542.   struct st_replace *next[256];
  1543. } REPLACE;
  1544. typedef struct st_replace_found {
  1545.   bool found;
  1546.   char *replace_string;
  1547.   uint to_offset;
  1548.   int from_offset;
  1549. } REPLACE_STRING;
  1550. #ifndef WORD_BIT
  1551. #define WORD_BIT (8*sizeof(uint))
  1552. #endif
  1553. static int insert_pointer_name(reg1 POINTER_ARRAY *pa,my_string name)
  1554. {
  1555.   uint i,length,old_count;
  1556.   byte *new_pos;
  1557.   const char **new_array;
  1558.   DBUG_ENTER("insert_pointer_name");
  1559.   if (! pa->typelib.count)
  1560.   {
  1561.     if (!(pa->typelib.type_names=(const char **)
  1562.   my_malloc(((PC_MALLOC-MALLOC_OVERHEAD)/
  1563.      (sizeof(my_string)+sizeof(*pa->flag))*
  1564.      (sizeof(my_string)+sizeof(*pa->flag))),MYF(MY_WME))))
  1565.       DBUG_RETURN(-1);
  1566.     if (!(pa->str= (byte*) my_malloc((uint) (PS_MALLOC-MALLOC_OVERHEAD),
  1567.      MYF(MY_WME))))
  1568.     {
  1569.       my_free((gptr) pa->typelib.type_names,MYF(0));
  1570.       DBUG_RETURN (-1);
  1571.     }
  1572.     pa->max_count=(PC_MALLOC-MALLOC_OVERHEAD)/(sizeof(byte*)+
  1573.        sizeof(*pa->flag));
  1574.     pa->flag= (int7*) (pa->typelib.type_names+pa->max_count);
  1575.     pa->length=0;
  1576.     pa->max_length=PS_MALLOC-MALLOC_OVERHEAD;
  1577.     pa->array_allocs=1;
  1578.   }
  1579.   length=(uint) strlen(name)+1;
  1580.   if (pa->length+length >= pa->max_length)
  1581.   {
  1582.     if (!(new_pos= (byte*) my_realloc((gptr) pa->str,
  1583.       (uint) (pa->max_length+PS_MALLOC),
  1584.       MYF(MY_WME))))
  1585.       DBUG_RETURN(1);
  1586.     if (new_pos != pa->str)
  1587.     {
  1588.       my_ptrdiff_t diff=PTR_BYTE_DIFF(new_pos,pa->str);
  1589.       for (i=0 ; i < pa->typelib.count ; i++)
  1590. pa->typelib.type_names[i]= ADD_TO_PTR(pa->typelib.type_names[i],diff,
  1591.       char*);
  1592.       pa->str=new_pos;
  1593.     }
  1594.     pa->max_length+=PS_MALLOC;
  1595.   }
  1596.   if (pa->typelib.count >= pa->max_count-1)
  1597.   {
  1598.     int len;
  1599.     pa->array_allocs++;
  1600.     len=(PC_MALLOC*pa->array_allocs - MALLOC_OVERHEAD);
  1601.     if (!(new_array=(const char **) my_realloc((gptr) pa->typelib.type_names,
  1602.        (uint) len/
  1603.  (sizeof(byte*)+sizeof(*pa->flag))*
  1604.  (sizeof(byte*)+sizeof(*pa->flag)),
  1605.  MYF(MY_WME))))
  1606.       DBUG_RETURN(1);
  1607.     pa->typelib.type_names=new_array;
  1608.     old_count=pa->max_count;
  1609.     pa->max_count=len/(sizeof(byte*) + sizeof(*pa->flag));
  1610.     pa->flag= (int7*) (pa->typelib.type_names+pa->max_count);
  1611.     memcpy((byte*) pa->flag,(my_string) (pa->typelib.type_names+old_count),
  1612.    old_count*sizeof(*pa->flag));
  1613.   }
  1614.   pa->flag[pa->typelib.count]=0; /* Reset flag */
  1615.   pa->typelib.type_names[pa->typelib.count++]= pa->str+pa->length;
  1616.   pa->typelib.type_names[pa->typelib.count]= NullS; /* Put end-mark */
  1617.   VOID(strmov(pa->str+pa->length,name));
  1618.   pa->length+=length;
  1619.   DBUG_RETURN(0);
  1620. } /* insert_pointer_name */
  1621. /* free pointer array */
  1622. void free_pointer_array(POINTER_ARRAY *pa)
  1623. {
  1624.   if (pa->typelib.count)
  1625.   {
  1626.     pa->typelib.count=0;
  1627.     my_free((gptr) pa->typelib.type_names,MYF(0));
  1628.     pa->typelib.type_names=0;
  1629.     my_free((gptr) pa->str,MYF(0));
  1630.   }
  1631. } /* free_pointer_array */
  1632. /* Code for replace rutines */
  1633. #define SET_MALLOC_HUNC 64
  1634. typedef struct st_rep_set {
  1635.   uint  *bits; /* Pointer to used sets */
  1636.   short next[LAST_CHAR_CODE]; /* Pointer to next sets */
  1637.   uint found_len; /* Best match to date */
  1638.   int found_offset;
  1639.   uint  table_offset;
  1640.   uint  size_of_bits; /* For convinience */
  1641. } REP_SET;
  1642. typedef struct st_rep_sets {
  1643.   uint count; /* Number of sets */
  1644.   uint extra; /* Extra sets in buffer */
  1645.   uint invisible; /* Sets not chown */
  1646.   uint size_of_bits;
  1647.   REP_SET *set,*set_buffer;
  1648.   uint *bit_buffer;
  1649. } REP_SETS;
  1650. typedef struct st_found_set {
  1651.   uint table_offset;
  1652.   int found_offset;
  1653. } FOUND_SET;
  1654. typedef struct st_follow {
  1655.   int chr;
  1656.   uint table_offset;
  1657.   uint len;
  1658. } FOLLOWS;
  1659. static int init_sets(REP_SETS *sets,uint states);
  1660. static REP_SET *make_new_set(REP_SETS *sets);
  1661. static void make_sets_invisible(REP_SETS *sets);
  1662. static void free_last_set(REP_SETS *sets);
  1663. static void free_sets(REP_SETS *sets);
  1664. static void set_bit(REP_SET *set, uint bit);
  1665. static void clear_bit(REP_SET *set, uint bit);
  1666. static void or_bits(REP_SET *to,REP_SET *from);
  1667. static void copy_bits(REP_SET *to,REP_SET *from);
  1668. static int cmp_bits(REP_SET *set1,REP_SET *set2);
  1669. static int get_next_bit(REP_SET *set,uint lastpos);
  1670. static int find_set(REP_SETS *sets,REP_SET *find);
  1671. static int find_found(FOUND_SET *found_set,uint table_offset,
  1672.   int found_offset);
  1673. static uint start_at_word(my_string pos);
  1674. static uint end_of_word(my_string pos);
  1675. static uint replace_len(my_string pos);
  1676. static uint found_sets=0;
  1677. /* Init a replace structure for further calls */
  1678. REPLACE *init_replace(my_string *from, my_string *to,uint count,
  1679.       my_string word_end_chars)
  1680. {
  1681.   uint i,j,states,set_nr,len,result_len,max_length,found_end,bits_set,bit_nr;
  1682.   int used_sets,chr,default_state;
  1683.   char used_chars[LAST_CHAR_CODE],is_word_end[256];
  1684.   my_string pos,to_pos,*to_array;
  1685.   REP_SETS sets;
  1686.   REP_SET *set,*start_states,*word_states,*new_set;
  1687.   FOLLOWS *follow,*follow_ptr;
  1688.   REPLACE *replace;
  1689.   FOUND_SET *found_set;
  1690.   REPLACE_STRING *rep_str;
  1691.   DBUG_ENTER("init_replace");
  1692.   /* Count number of states */
  1693.   for (i=result_len=max_length=0 , states=2 ; i < count ; i++)
  1694.   {
  1695.     len=replace_len(from[i]);
  1696.     if (!len)
  1697.     {
  1698.       errno=EINVAL;
  1699.       my_message(0,"No to-string for last from-string",MYF(ME_BELL));
  1700.       DBUG_RETURN(0);
  1701.     }
  1702.     states+=len+1;
  1703.     result_len+=(uint) strlen(to[i])+1;
  1704.     if (len > max_length)
  1705.       max_length=len;
  1706.   }
  1707.   bzero((char*) is_word_end,sizeof(is_word_end));
  1708.   for (i=0 ; word_end_chars[i] ; i++)
  1709.     is_word_end[(uchar) word_end_chars[i]]=1;
  1710.   if (init_sets(&sets,states))
  1711.     DBUG_RETURN(0);
  1712.   found_sets=0;
  1713.   if (!(found_set= (FOUND_SET*) my_malloc(sizeof(FOUND_SET)*max_length*count,
  1714.   MYF(MY_WME))))
  1715.   {
  1716.     free_sets(&sets);
  1717.     DBUG_RETURN(0);
  1718.   }
  1719.   VOID(make_new_set(&sets)); /* Set starting set */
  1720.   make_sets_invisible(&sets); /* Hide previus sets */
  1721.   used_sets=-1;
  1722.   word_states=make_new_set(&sets); /* Start of new word */
  1723.   start_states=make_new_set(&sets); /* This is first state */
  1724.   if (!(follow=(FOLLOWS*) my_malloc((states+2)*sizeof(FOLLOWS),MYF(MY_WME))))
  1725.   {
  1726.     free_sets(&sets);
  1727.     my_free((gptr) found_set,MYF(0));
  1728.     DBUG_RETURN(0);
  1729.   }
  1730. /* Init follow_ptr[] */
  1731.   for (i=0, states=1, follow_ptr=follow+1 ; i < count ; i++)
  1732.   {
  1733.     if (from[i][0] == '\' && from[i][1] == '^')
  1734.     {
  1735.       set_bit(start_states,states+1);
  1736.       if (!from[i][2])
  1737.       {
  1738. start_states->table_offset=i;
  1739. start_states->found_offset=1;
  1740.       }
  1741.     }
  1742.     else if (from[i][0] == '\' && from[i][1] == '$')
  1743.     {
  1744.       set_bit(start_states,states);
  1745.       set_bit(word_states,states);
  1746.       if (!from[i][2] && start_states->table_offset == (uint) ~0)
  1747.       {
  1748. start_states->table_offset=i;
  1749. start_states->found_offset=0;
  1750.       }
  1751.     }
  1752.     else
  1753.     {
  1754.       set_bit(word_states,states);
  1755.       if (from[i][0] == '\' && (from[i][1] == 'b' && from[i][2]))
  1756. set_bit(start_states,states+1);
  1757.       else
  1758. set_bit(start_states,states);
  1759.     }
  1760.     for (pos=from[i], len=0; *pos ; pos++)
  1761.     {
  1762.       if (*pos == '\' && *(pos+1))
  1763.       {
  1764. pos++;
  1765. switch (*pos) {
  1766. case 'b':
  1767.   follow_ptr->chr = SPACE_CHAR;
  1768.   break;
  1769. case '^':
  1770.   follow_ptr->chr = START_OF_LINE;
  1771.   break;
  1772. case '$':
  1773.   follow_ptr->chr = END_OF_LINE;
  1774.   break;
  1775. case 'r':
  1776.   follow_ptr->chr = 'r';
  1777.   break;
  1778. case 't':
  1779.   follow_ptr->chr = 't';
  1780.   break;
  1781. case 'v':
  1782.   follow_ptr->chr = 'v';
  1783.   break;
  1784. default:
  1785.   follow_ptr->chr = (uchar) *pos;
  1786.   break;
  1787. }
  1788.       }
  1789.       else
  1790. follow_ptr->chr= (uchar) *pos;
  1791.       follow_ptr->table_offset=i;
  1792.       follow_ptr->len= ++len;
  1793.       follow_ptr++;
  1794.     }
  1795.     follow_ptr->chr=0;
  1796.     follow_ptr->table_offset=i;
  1797.     follow_ptr->len=len;
  1798.     follow_ptr++;
  1799.     states+=(uint) len+1;
  1800.   }
  1801.   for (set_nr=0,pos=0 ; set_nr < sets.count ; set_nr++)
  1802.   {
  1803.     set=sets.set+set_nr;
  1804.     default_state= 0; /* Start from beginning */
  1805.     /* If end of found-string not found or start-set with current set */
  1806.     for (i= (uint) ~0; (i=get_next_bit(set,i)) ;)
  1807.     {
  1808.       if (!follow[i].chr)
  1809.       {
  1810. if (! default_state)
  1811.   default_state= find_found(found_set,set->table_offset,
  1812.     set->found_offset+1);
  1813.       }
  1814.     }
  1815.     copy_bits(sets.set+used_sets,set); /* Save set for changes */
  1816.     if (!default_state)
  1817.       or_bits(sets.set+used_sets,sets.set); /* Can restart from start */
  1818.     /* Find all chars that follows current sets */
  1819.     bzero((char*) used_chars,sizeof(used_chars));
  1820.     for (i= (uint) ~0; (i=get_next_bit(sets.set+used_sets,i)) ;)
  1821.     {
  1822.       used_chars[follow[i].chr]=1;
  1823.       if ((follow[i].chr == SPACE_CHAR && !follow[i+1].chr &&
  1824.    follow[i].len > 1) || follow[i].chr == END_OF_LINE)
  1825. used_chars[0]=1;
  1826.     }
  1827.     /* Mark word_chars used if b is in state */
  1828.     if (used_chars[SPACE_CHAR])
  1829.       for (pos= word_end_chars ; *pos ; pos++)
  1830. used_chars[(int) (uchar) *pos] = 1;
  1831.     /* Handle other used characters */
  1832.     for (chr= 0 ; chr < 256 ; chr++)
  1833.     {
  1834.       if (! used_chars[chr])
  1835. set->next[chr]= chr ? default_state : -1;
  1836.       else
  1837.       {
  1838. new_set=make_new_set(&sets);
  1839. set=sets.set+set_nr; /* if realloc */
  1840. new_set->table_offset=set->table_offset;
  1841. new_set->found_len=set->found_len;
  1842. new_set->found_offset=set->found_offset+1;
  1843. found_end=0;
  1844. for (i= (uint) ~0 ; (i=get_next_bit(sets.set+used_sets,i)) ; )
  1845. {
  1846.   if (!follow[i].chr || follow[i].chr == chr ||
  1847.       (follow[i].chr == SPACE_CHAR &&
  1848.        (is_word_end[chr] ||
  1849. (!chr && follow[i].len > 1 && ! follow[i+1].chr))) ||
  1850.       (follow[i].chr == END_OF_LINE && ! chr))
  1851.   {
  1852.     if ((! chr || (follow[i].chr && !follow[i+1].chr)) &&
  1853. follow[i].len > found_end)
  1854.       found_end=follow[i].len;
  1855.     if (chr && follow[i].chr)
  1856.       set_bit(new_set,i+1); /* To next set */
  1857.     else
  1858.       set_bit(new_set,i);
  1859.   }
  1860. }
  1861. if (found_end)
  1862. {
  1863.   new_set->found_len=0; /* Set for testing if first */
  1864.   bits_set=0;
  1865.   for (i= (uint) ~0; (i=get_next_bit(new_set,i)) ;)
  1866.   {
  1867.     if ((follow[i].chr == SPACE_CHAR ||
  1868.  follow[i].chr == END_OF_LINE) && ! chr)
  1869.       bit_nr=i+1;
  1870.     else
  1871.       bit_nr=i;
  1872.     if (follow[bit_nr-1].len < found_end ||
  1873. (new_set->found_len &&
  1874.  (chr == 0 || !follow[bit_nr].chr)))
  1875.       clear_bit(new_set,i);
  1876.     else
  1877.     {
  1878.       if (chr == 0 || !follow[bit_nr].chr)
  1879.       { /* best match  */
  1880. new_set->table_offset=follow[bit_nr].table_offset;
  1881. if (chr || (follow[i].chr == SPACE_CHAR ||
  1882.     follow[i].chr == END_OF_LINE))
  1883.   new_set->found_offset=found_end; /* New match */
  1884. new_set->found_len=found_end;
  1885.       }
  1886.       bits_set++;
  1887.     }
  1888.   }
  1889.   if (bits_set == 1)
  1890.   {
  1891.     set->next[chr] = find_found(found_set,
  1892. new_set->table_offset,
  1893. new_set->found_offset);
  1894.     free_last_set(&sets);
  1895.   }
  1896.   else
  1897.     set->next[chr] = find_set(&sets,new_set);
  1898. }
  1899. else
  1900.   set->next[chr] = find_set(&sets,new_set);
  1901.       }
  1902.     }
  1903.   }
  1904. /* Alloc replace structure for the replace-state-machine */
  1905.   if ((replace=(REPLACE*) my_malloc(sizeof(REPLACE)*(sets.count)+
  1906.     sizeof(REPLACE_STRING)*(found_sets+1)+
  1907.     sizeof(my_string)*count+result_len,
  1908.     MYF(MY_WME | MY_ZEROFILL))))
  1909.   {
  1910.     rep_str=(REPLACE_STRING*) (replace+sets.count);
  1911.     to_array=(my_string*) (rep_str+found_sets+1);
  1912.     to_pos=(my_string) (to_array+count);
  1913.     for (i=0 ; i < count ; i++)
  1914.     {
  1915.       to_array[i]=to_pos;
  1916.       to_pos=strmov(to_pos,to[i])+1;
  1917.     }
  1918.     rep_str[0].found=1;
  1919.     rep_str[0].replace_string=0;
  1920.     for (i=1 ; i <= found_sets ; i++)
  1921.     {
  1922.       pos=from[found_set[i-1].table_offset];
  1923.       rep_str[i].found= !bcmp(pos,"\^",3) ? 2 : 1;
  1924.       rep_str[i].replace_string=to_array[found_set[i-1].table_offset];
  1925.       rep_str[i].to_offset=found_set[i-1].found_offset-start_at_word(pos);
  1926.       rep_str[i].from_offset=found_set[i-1].found_offset-replace_len(pos)+
  1927. end_of_word(pos);
  1928.     }
  1929.     for (i=0 ; i < sets.count ; i++)
  1930.     {
  1931.       for (j=0 ; j < 256 ; j++)
  1932. if (sets.set[i].next[j] >= 0)
  1933.   replace[i].next[j]=replace+sets.set[i].next[j];
  1934. else
  1935.   replace[i].next[j]=(REPLACE*) (rep_str+(-sets.set[i].next[j]-1));
  1936.     }
  1937.   }
  1938.   my_free((gptr) follow,MYF(0));
  1939.   free_sets(&sets);
  1940.   my_free((gptr) found_set,MYF(0));
  1941.   DBUG_PRINT("exit",("Replace table has %d states",sets.count));
  1942.   DBUG_RETURN(replace);
  1943. }
  1944. static int init_sets(REP_SETS *sets,uint states)
  1945. {
  1946.   bzero((char*) sets,sizeof(*sets));
  1947.   sets->size_of_bits=((states+7)/8);
  1948.   if (!(sets->set_buffer=(REP_SET*) my_malloc(sizeof(REP_SET)*SET_MALLOC_HUNC,
  1949.       MYF(MY_WME))))
  1950.     return 1;
  1951.   if (!(sets->bit_buffer=(uint*) my_malloc(sizeof(uint)*sets->size_of_bits*
  1952.    SET_MALLOC_HUNC,MYF(MY_WME))))
  1953.   {
  1954.     my_free((gptr) sets->set,MYF(0));
  1955.     return 1;
  1956.   }
  1957.   return 0;
  1958. }
  1959. /* Make help sets invisible for nicer codeing */
  1960. static void make_sets_invisible(REP_SETS *sets)
  1961. {
  1962.   sets->invisible=sets->count;
  1963.   sets->set+=sets->count;
  1964.   sets->count=0;
  1965. }
  1966. static REP_SET *make_new_set(REP_SETS *sets)
  1967. {
  1968.   uint i,count,*bit_buffer;
  1969.   REP_SET *set;
  1970.   if (sets->extra)
  1971.   {
  1972.     sets->extra--;
  1973.     set=sets->set+ sets->count++;
  1974.     bzero((char*) set->bits,sizeof(uint)*sets->size_of_bits);
  1975.     bzero((char*) &set->next[0],sizeof(set->next[0])*LAST_CHAR_CODE);
  1976.     set->found_offset=0;
  1977.     set->found_len=0;
  1978.     set->table_offset= (uint) ~0;
  1979.     set->size_of_bits=sets->size_of_bits;
  1980.     return set;
  1981.   }
  1982.   count=sets->count+sets->invisible+SET_MALLOC_HUNC;
  1983.   if (!(set=(REP_SET*) my_realloc((gptr) sets->set_buffer,
  1984.    sizeof(REP_SET)*count,
  1985.   MYF(MY_WME))))
  1986.     return 0;
  1987.   sets->set_buffer=set;
  1988.   sets->set=set+sets->invisible;
  1989.   if (!(bit_buffer=(uint*) my_realloc((gptr) sets->bit_buffer,
  1990.       (sizeof(uint)*sets->size_of_bits)*count,
  1991.       MYF(MY_WME))))
  1992.     return 0;
  1993.   sets->bit_buffer=bit_buffer;
  1994.   for (i=0 ; i < count ; i++)
  1995.   {
  1996.     sets->set_buffer[i].bits=bit_buffer;
  1997.     bit_buffer+=sets->size_of_bits;
  1998.   }
  1999.   sets->extra=SET_MALLOC_HUNC;
  2000.   return make_new_set(sets);
  2001. }
  2002. static void free_last_set(REP_SETS *sets)
  2003. {
  2004.   sets->count--;
  2005.   sets->extra++;
  2006.   return;
  2007. }
  2008. static void free_sets(REP_SETS *sets)
  2009. {
  2010.   my_free((gptr)sets->set_buffer,MYF(0));
  2011.   my_free((gptr)sets->bit_buffer,MYF(0));
  2012.   return;
  2013. }
  2014. static void set_bit(REP_SET *set, uint bit)
  2015. {
  2016.   set->bits[bit / WORD_BIT] |= 1 << (bit % WORD_BIT);
  2017.   return;
  2018. }
  2019. static void clear_bit(REP_SET *set, uint bit)
  2020. {
  2021.   set->bits[bit / WORD_BIT] &= ~ (1 << (bit % WORD_BIT));
  2022.   return;
  2023. }
  2024. static void or_bits(REP_SET *to,REP_SET *from)
  2025. {
  2026.   reg1 uint i;
  2027.   for (i=0 ; i < to->size_of_bits ; i++)
  2028.     to->bits[i]|=from->bits[i];
  2029.   return;
  2030. }
  2031. static void copy_bits(REP_SET *to,REP_SET *from)
  2032. {
  2033.   memcpy((byte*) to->bits,(byte*) from->bits,
  2034.  (size_t) (sizeof(uint) * to->size_of_bits));
  2035. }
  2036. static int cmp_bits(REP_SET *set1,REP_SET *set2)
  2037. {
  2038.   return bcmp((byte*) set1->bits,(byte*) set2->bits,
  2039.       sizeof(uint) * set1->size_of_bits);
  2040. }
  2041. /* Get next set bit from set. */
  2042. static int get_next_bit(REP_SET *set,uint lastpos)
  2043. {
  2044.   uint pos,*start,*end,bits;
  2045.   start=set->bits+ ((lastpos+1) / WORD_BIT);
  2046.   end=set->bits + set->size_of_bits;
  2047.   bits=start[0] & ~((1 << ((lastpos+1) % WORD_BIT)) -1);
  2048.   while (! bits && ++start < end)
  2049.     bits=start[0];
  2050.   if (!bits)
  2051.     return 0;
  2052.   pos=(uint) (start-set->bits)*WORD_BIT;
  2053.   while (! (bits & 1))
  2054.   {
  2055.     bits>>=1;
  2056.     pos++;
  2057.   }
  2058.   return pos;
  2059. }
  2060. /* find if there is a same set in sets. If there is, use it and
  2061.    free given set, else put in given set in sets and return it's
  2062.    position */
  2063. static int find_set(REP_SETS *sets,REP_SET *find)
  2064. {
  2065.   uint i;
  2066.   for (i=0 ; i < sets->count-1 ; i++)
  2067.   {
  2068.     if (!cmp_bits(sets->set+i,find))
  2069.     {
  2070.       free_last_set(sets);
  2071.       return i;
  2072.     }
  2073.   }
  2074.   return i; /* return new postion */
  2075. }
  2076. /* find if there is a found_set with same table_offset & found_offset
  2077.    If there is return offset to it, else add new offset and return pos.
  2078.    Pos returned is -offset-2 in found_set_structure because it's is
  2079.    saved in set->next and set->next[] >= 0 points to next set and
  2080.    set->next[] == -1 is reserved for end without replaces.
  2081.    */
  2082. static int find_found(FOUND_SET *found_set,uint table_offset, int found_offset)
  2083. {
  2084.   int i;
  2085.   for (i=0 ; (uint) i < found_sets ; i++)
  2086.     if (found_set[i].table_offset == table_offset &&
  2087. found_set[i].found_offset == found_offset)
  2088.       return -i-2;
  2089.   found_set[i].table_offset=table_offset;
  2090.   found_set[i].found_offset=found_offset;
  2091.   found_sets++;
  2092.   return -i-2; /* return new postion */
  2093. }
  2094. /* Return 1 if regexp starts with b or ends with b*/
  2095. static uint start_at_word(my_string pos)
  2096. {
  2097.   return (((!bcmp(pos,"\b",2) && pos[2]) || !bcmp(pos,"\^",2)) ? 1 : 0);
  2098. }
  2099. static uint end_of_word(my_string pos)
  2100. {
  2101.   my_string end=strend(pos);
  2102.   return ((end > pos+2 && !bcmp(end-2,"\b",2)) ||
  2103.   (end >= pos+2 && !bcmp(end-2,"\$",2))) ?
  2104.     1 : 0;
  2105. }
  2106. static uint replace_len(my_string str)
  2107. {
  2108.   uint len=0;
  2109.   while (*str)
  2110.   {
  2111.     if (str[0] == '\' && str[1])
  2112.       str++;
  2113.     str++;
  2114.     len++;
  2115.   }
  2116.   return len;
  2117. }
  2118. /* Replace strings;  Return length of result string */
  2119. uint replace_strings(REPLACE *rep, my_string *start,uint *max_length, 
  2120.      my_string from)
  2121. {
  2122.   reg1 REPLACE *rep_pos;
  2123.   reg2 REPLACE_STRING *rep_str;
  2124.   my_string to,end,pos,new;
  2125.   end=(to= *start) + *max_length-1;
  2126.   rep_pos=rep+1;
  2127.   for(;;)
  2128.   {
  2129.     while (!rep_pos->found)
  2130.     {
  2131.       rep_pos= rep_pos->next[(uchar) *from];
  2132.       if (to == end)
  2133.       {
  2134. (*max_length)+=8192;
  2135. if (!(new=my_realloc(*start,*max_length,MYF(MY_WME))))
  2136.   return (uint) -1;
  2137. to=new+(to - *start);
  2138. end=(*start=new)+ *max_length-1;
  2139.       }
  2140.       *to++= *from++;
  2141.     }
  2142.     if (!(rep_str = ((REPLACE_STRING*) rep_pos))->replace_string)
  2143.       return (uint) (to - *start)-1;
  2144.     to-=rep_str->to_offset;
  2145.     for (pos=rep_str->replace_string; *pos ; pos++)
  2146.     {
  2147.       if (to == end)
  2148.       {
  2149. (*max_length)*=2;
  2150. if (!(new=my_realloc(*start,*max_length,MYF(MY_WME))))
  2151.   return (uint) -1;
  2152. to=new+(to - *start);
  2153. end=(*start=new)+ *max_length-1;
  2154.       }
  2155.       *to++= *pos;
  2156.     }
  2157.     if (!*(from-=rep_str->from_offset) && rep_pos->found != 2)
  2158.       return (uint) (to - *start);
  2159.     rep_pos=rep;
  2160.   }
  2161. }
  2162. static int initialize_replace_buffer(void)
  2163. {
  2164.   out_length=8192;
  2165.   if (!(out_buff=my_malloc(out_length,MYF(MY_WME))))
  2166.     return(1);
  2167.   return 0;
  2168. }
  2169. static void free_replace_buffer(void)
  2170. {
  2171.   my_free(out_buff,MYF(MY_WME));
  2172. }