Commit 569ac55c authored by sasha@mysql.sashanet.com's avatar sasha@mysql.sashanet.com
Browse files

client/mysqltest.c

    add --result-file option
mysql-test/mysql-test-run
    do a really good job to kill mysqld if it is stuck
parent ca5e1f6d
Loading
Loading
Loading
Loading
+151 −110
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@
#include "mysql.h"
#include "mysql_version.h"
#include "my_config.h"
#include "my_dir.h"
#include "mysqld_error.h"
#include <stdio.h>
#include <stdlib.h>
@@ -81,6 +82,8 @@ typedef
PARSER parser;
int block_ok = 1; /* set to 0 if the current block should not be executed */
int false_block_depth = 0;
const char* result_file = 0; /* if set, all results are concated and
				compared against this file*/

typedef struct 
{
@@ -113,9 +116,26 @@ struct query
	Q_UNKNOWN} type;
};

#define DS_CHUNK   16384

typedef struct dyn_string
{
  char* str;
  int len,max_len;
} DYN_STRING;

DYN_STRING ds_res;

void dyn_string_init(DYN_STRING* ds);
void dyn_string_append(DYN_STRING* ds, const char* str, int len);
int dyn_string_cmp(DYN_STRING* ds, const char* fname);
void reject_dump(const char* record_file, char* buf, int size);


static void die(const char* fmt, ...);
int close_connection(struct query* q);
VAR* var_get(char* var_name, char* var_name_end, int raw);
void verbose_msg(const char* fmt, ...);

void init_parser()
{
@@ -133,6 +153,83 @@ int hex_val(int c)
    return -1;
}

void dyn_string_init(DYN_STRING* ds)
{
  if(!(ds->str = (char*)my_malloc(DS_CHUNK, MYF(0))))
    die("Out of memory");
  ds->len = 0;
  ds->max_len = DS_CHUNK;
}
void dyn_string_append(DYN_STRING* ds, const char* str, int len)
{
  int new_len;
  if(!len)
    len = strlen(str);
  new_len = ds->len + len;
  if(new_len > ds->max_len)
    {
      int new_alloc_len = (new_len & ~(DS_CHUNK-1)) + DS_CHUNK;
      char* tmp = (char*) my_malloc(new_alloc_len, MYF(0));
      if(!tmp)
	die("Out of memory");
      memcpy(tmp, ds->str, ds->len);
      memcpy(tmp + ds->len, str, len);
      my_free((gptr)ds->str, MYF(0));
      ds->str = tmp;
      ds->len = new_len;
      ds->max_len = new_alloc_len;
    }
  else
    {
      memcpy(ds->str + ds->len, str, len);
      ds->len += len;
    }
}
int dyn_string_cmp(DYN_STRING* ds, const char* fname)
{
  MY_STAT stat_info;
  char *tmp;
  int res;
  int fd;
  if(!my_stat(fname, &stat_info, MYF(MY_WME)))
    die("Could not stat %s: errno =%d", fname, errno);
  if(stat_info.st_size != ds->len)
    return 2;
  if(!(tmp = (char*) my_malloc(ds->len, MYF(0))))
    die("Out of memory");
  if((fd = my_open(fname, O_RDONLY, MYF(MY_WME))) < 0)
    die("Could not open %s: errno = %d", fname, errno);
  if(my_read(fd, (byte*)tmp, stat_info.st_size, MYF(MY_WME|MY_NABP)))
    die("read failed");
  res = (memcmp(tmp, ds->str, stat_info.st_size)) ?  1 : 0;  
  my_free((gptr)tmp, MYF(0));
  my_close(fd, MYF(0));
  return res;
}

int check_result(DYN_STRING* ds, const char* fname)
{
  int error = 0;
  switch(dyn_string_cmp(ds, fname))
    {
    case 0:
      break; /* ok */
    case 2:
      verbose_msg("Result length mismatch");
      error = 1;
      break;
    case 1:
      verbose_msg("Result content mismatch");
      error = 1;
      break;
    default: /* impossible */
      die("Unknown error code from dyn_string_cmp()");
    }
  if(error)
    reject_dump(fname, ds->str, ds->len);
  return error;
}

VAR* var_get(char* var_name, char* var_name_end, int raw)
{
  int digit;
@@ -491,7 +588,7 @@ void close_cons()
  for(--next_con; next_con >= cons; --next_con)
    {
      mysql_close(&next_con->mysql);
      my_free(next_con->name, MYF(0));
      my_free(next_con->name, MYF(MY_ALLOW_ZERO_PTR));
    }
}

@@ -734,6 +831,7 @@ struct option long_options[] =
  {"silent", no_argument, 0, 'q'},
  {"quiet", no_argument, 0, 'q'},
  {"record", no_argument, 0, 'r'},
  {"result-file", required_argument, 0, 'R'},
  {"help", no_argument, 0, '?'},
  {"user", required_argument, 0, 'u'},
  {"password", optional_argument, 0, 'p'},
@@ -752,6 +850,7 @@ void die(const char* fmt, ...)
  vfprintf(stderr, fmt, args);
  fprintf(stderr, "\n");
  va_end(args);
  close_cons();
  exit(1);
}

@@ -803,7 +902,7 @@ int parse_args(int argc, char **argv)
  my_bool tty_password=0;

  load_defaults("my",load_default_groups,&argc,&argv);
  while((c = getopt_long(argc, argv, "h:p::u:P:D:S:?rvVq",
  while((c = getopt_long(argc, argv, "h:p::u:P:D:S:R:?rvVq",
			 long_options, &option_index)) != EOF)
    {
      switch(c)
@@ -818,6 +917,9 @@ int parse_args(int argc, char **argv)
	case 'u':
	  user = optarg;
	  break;
	case 'R':
	  result_file = optarg;
	  break;
        case 'p':
	  if (optarg)
	    {
@@ -873,7 +975,7 @@ int parse_args(int argc, char **argv)
  return 0;
}

char* safe_str_append(char* buf, char* str, int size)
char* safe_str_append(char* buf, const char* str, int size)
{
  int i,c ;
  for(i = 0; (c = *str++) &&  i < size - 1; i++)
@@ -882,7 +984,17 @@ char* safe_str_append(char* buf, char* str, int size)
  return buf;
}

void reject_dump(char* record_file, char* buf, int size)
void str_to_file(const char* fname, char* str, int size)
{
  int fd;
  if((fd = my_open(fname, O_WRONLY|O_CREAT, MYF(MY_WME))) < 0)
    die("Could not open %s: errno = %d", fname, errno);
  if(my_write(fd, (byte*)str, size, MYF(MY_WME|MY_NABP)))
    die("write failed");
  my_close(fd, MYF(0));
}

void reject_dump(const char* record_file, char* buf, int size)
{
  char reject_file[MAX_RECORD_FILE+16];
  char* p;
@@ -892,11 +1004,7 @@ void reject_dump(char* record_file, char* buf, int size)
  p = safe_str_append(p, record_file, sizeof(reject_file));
  p = safe_str_append(p, (char*)".reject", reject_file - p +
		      sizeof(reject_file));

  if(!(freject = fopen(reject_file, "w")))
    die("Could not open reject file %s, error %d", reject_file, errno);
  fwrite(buf, size, 1, freject);
  fclose(freject);
  str_to_file(reject_file, buf, size);
}

int run_query(MYSQL* mysql, struct query* q)
@@ -905,46 +1013,14 @@ int run_query(MYSQL* mysql, struct query* q)
  MYSQL_FIELD* fields;
  MYSQL_ROW row;
  int num_fields,i, error = 0;
  FILE* frecord = 0;
  char* res_buf = 0, *p_res_buf = 0, *res_buf_end = 0, *record_buf = 0;
  struct stat info;
  unsigned long* lengths;
  char* val;
  int len;
  int guess_result_size;

  if(q->record_file[0])
    {
      if(!(frecord = fopen(q->record_file, record_mode)))
	die("Error %d opening record file '%s'", errno, q->record_file);
      if(!record)
  if(!result_file && q->record_file[0])
    {
	  if(stat(q->record_file, &info))
	    die("Error %d on stat of record file '%s'", errno, q->record_file);
	  /* let the developer be lazy and generate a .reject file
           * by touching the the result file and running the test
	   * in that case, we need a buffer large enough to hold the
	   * entire rejected result
	   */
	  guess_result_size = (info.st_size ? info.st_size :
			       LAZY_GUESS_BUF_SIZE) + PAD_SIZE;
	  /* if we guess wrong, the result will be truncated */
	  /* if the master result file is 0 length, the developer */
	  /* wants to generate reject file, edit it, and then move into
	   * the master result location - in this case we should just
	   * allocate a buffer that is large enough for the kind of result
	   * that a human would want to examine - hope 8 K is enough
	   * if this is a real test, the result should be exactly the length
	   * of the master file if it is correct. If it is wrong and is
	   * longer, we should be able to tell what is wrong by looking
	   * at the first "correct" number of bytes
	   */
	  if(!(p_res_buf = res_buf =
	       (char*)malloc(guess_result_size)))
	    die("malloc() failed trying to allocate %d bytes",
		guess_result_size);
	  res_buf_end = res_buf + guess_result_size;;
	}
      ds_res.len = 0;
    } 	


@@ -980,10 +1056,8 @@ int run_query(MYSQL* mysql, struct query* q)
      goto end;
    }
  
  if(!q->has_result_set)
    goto end;

  if(!(res = mysql_store_result(mysql)))
  if(!(res = mysql_store_result(mysql)) && mysql_field_count(mysql))
    {
     if(q->abort_on_error)
       die("failed in mysql_store_result for query '%s'", q->q);
@@ -995,27 +1069,18 @@ int run_query(MYSQL* mysql, struct query* q)
       }
    }

  if(!frecord)
      goto end;
  if(!res) goto end;
  
  fields =  mysql_fetch_fields(res);
  num_fields =  mysql_num_fields(res);
  for( i = 0; i < num_fields; i++)
    {
      if(record)
	fprintf(frecord, "%s\t", fields[i].name);
      else
	{
	  p_res_buf = safe_str_append(p_res_buf, fields[i].name,
				      res_buf_end - p_res_buf - 1);
	  *p_res_buf++ = '\t';
	}
      dyn_string_append(&ds_res, fields[i].name, 0);
      dyn_string_append(&ds_res, "\t", 1);
    }

  if(record)
    fputc('\n', frecord);
  else if(res_buf_end > p_res_buf) 
    *p_res_buf++ = '\n';
  dyn_string_append(&ds_res, "\n", 1);


  while((row = mysql_fetch_row(res)))
  {
@@ -1030,59 +1095,28 @@ int run_query(MYSQL* mysql, struct query* q)
	    val = (char*)"NULL";
	    len = 4;
	  }
	if(record)
	  {
	    fwrite(val, len, 1, frecord);
	    fputc('\t', frecord);
	  }
	else
	  {
	    if(p_res_buf + len + 1 < res_buf_end)
	      {
		 memcpy(p_res_buf, val, len);
		 p_res_buf += len;
		 *p_res_buf++ = '\t';
	      }
	
	dyn_string_append(&ds_res, val, len);
	dyn_string_append(&ds_res, "\t", 1);
      }
      }

    if(record)
      fputc('\n', frecord);
    else if(res_buf_end > p_res_buf) 
    *p_res_buf++ = '\n';
    
    dyn_string_append(&ds_res, "\n", 1);
  }

  if(!record && frecord) 
    {
      if( (len = p_res_buf - res_buf) != info.st_size)
  if(record)
    {
          verbose_msg("Result length mismatch: actual  %d, expected = %d ", len,
	      info.st_size);
          reject_dump(q->record_file, res_buf, len);
	  error = 1;
      if(!q->record_file[0] && !result_file)
	die("Missing result file");
      if(!result_file)
	str_to_file(q->record_file, ds_res.str, ds_res.len);
    }
      else
	{
	  if(!(record_buf = (char*)malloc(info.st_size)))
	    die("malloc() failed allocating %d bytes", info.st_size);
	  fread(record_buf, info.st_size, 1, frecord);
	  if(memcmp(record_buf, res_buf, len))
  else if(!result_file && q->record_file[0])
    {
	      verbose_msg("Result not the same as the record");
	      reject_dump(q->record_file, res_buf, len);
	      error = 1;
	    }
	}
      error = check_result(&ds_res, q->record_file);
    }
  
  
 end:
  if(res_buf) free(res_buf);
  if(record_buf) free(record_buf);
  if(res) mysql_free_result(res);
  if(frecord) fclose(frecord);
  return error;
}

@@ -1170,7 +1204,7 @@ int main(int argc, char** argv)
  memset(block_stack, 0, sizeof(block_stack));
  block_stack_end = block_stack + BLOCK_STACK_DEPTH;
  cur_block = block_stack;
  
  dyn_string_init(&ds_res);
  parse_args(argc, argv);
  if(!*cur_file)
    *cur_file = stdin;
@@ -1182,13 +1216,14 @@ int main(int argc, char** argv)

  mysql_options(&cur_con->mysql, MYSQL_READ_DEFAULT_GROUP, "mysql");
  
  cur_con->name = my_strdup("default", MYF(MY_WME));
  if(!cur_con->name)
    die("Out of memory");
  
  if(!mysql_real_connect(&cur_con->mysql, host,
			 user, pass, db, port, unix_sock,
     0))
    die("Failed in mysql_real_connect(): %s", mysql_error(&cur_con->mysql));
  cur_con->name = my_strdup("default", MYF(MY_WME));
  if(!cur_con->name)
    die("Out of memory");

  for(;!read_query(&q);)
    {
@@ -1230,6 +1265,12 @@ int main(int argc, char** argv)

  close_cons();

  if(result_file)
    if(!record)
      error |= check_result(&ds_res, result_file);
    else
      str_to_file(result_file, ds_res.str, ds_res.len);
  
  if (!silent) {
    if(error)
      printf("not ok\n");
+24 −0
Original line number Diff line number Diff line
@@ -361,6 +361,18 @@ stop_slave ()
  if [ x$SLAVE_RUNNING = x1 ]
  then
    $MYSQLADMIN --no-defaults --socket=$SLAVE_MYSOCK -u root shutdown
    if [ $? != 0 ] ; then # try harder!
     echo "slave not cooperating with mysqladmin, will try manual kill"
     kill `cat $SLAVE_MYPID`
     sleep 2
     if [ -f $SLAVE_MYPID ] ; then
       echo "slave refused to die, resorting to SIGKILL murder"
       kill -9 `cat $SLAVE_MYPID`
       rm -f $SLAVE_MYPID
     else
      echo "slave responded to SIGTERM " 
     fi
    fi
    SLAVE_RUNNING=0
  fi  
}
@@ -370,6 +382,18 @@ stop_master ()
  if [ x$MASTER_RUNNING = x1 ]
  then
    $MYSQLADMIN --no-defaults --socket=$MASTER_MYSOCK -u root shutdown
    if [ $? != 0 ] ; then # try harder!
     echo "master not cooperating with mysqladmin, will try manual kill"
     kill `cat $MASTER_MYPID`
     sleep 2
     if [ -f $MASTER_MYPID ] ; then
       echo "master refused to die, resorting to SIGKILL murder"
       kill -9 `cat $MASTER_MYPID`
       rm -f $MASTER_MYPID
     else
      echo "master responded to SIGTERM " 
     fi
    fi
    MASTER_RUNNING=0
  fi
}