Commit message: mysqltest: don't eat new lines in --exec

pass them through as is
CVE: CVE-2017-3600
CWE: NVD-CWE-noinfo
Vulnerability description: Vulnerability in the MySQL Server component of Oracle MySQL (subcomponent: Client mysqldump). Supported versions that are affected are 5.5.54 and earlier, 5.6.35 and earlier and 5.7.17 and earlier. Difficult to exploit vulnerability allows high privileged attacker with network access via multiple protocols to compromise MySQL Server. Successful attacks of this vulnerability can result in takeover of MySQL Server. Note: CVE-2017-3600 is equivalent to CVE-2016-5483. CVSS 3.0 Base Score 6.6 (Confidentiality, Integrity and Availability impacts). CVSS Vector: (CVSS:3.0/AV:N/AC:H/PR:H/UI:N/S:U/C:H/I:H/A:H).

Project: server

static void handle_no_active_connection(struct st_command *command, 
  struct st_connection *cn, DYNAMIC_STRING *ds)
{
  handle_error(command, 2006, "MySQL server has gone away", "000000", ds);
  cn->pending= FALSE;
  var_set_errno(2006);
}

Project: server

void do_exec(struct st_command *command)
{
  int error;
  char buf[512];
  FILE *res_file;
  char *cmd= command->first_argument;
  DYNAMIC_STRING ds_cmd;
  DYNAMIC_STRING ds_sorted, *ds_result;
  DBUG_ENTER("do_exec");
  DBUG_PRINT("enter", ("cmd: '%s'", cmd));

  /* Skip leading space */
  while (*cmd && my_isspace(charset_info, *cmd))
    cmd++;
  if (!*cmd)
  {
    report_or_die("Missing argument in exec");
    return;
  }
  command->last_argument= command->end;

  init_dynamic_string(&ds_cmd, 0, command->query_len+256, 256);
  /* Eval the command, thus replacing all environment variables */
  do_eval(&ds_cmd, cmd, command->end, !is_windows);

  /* Check if echo should be replaced with "builtin" echo */
  if (builtin_echo[0] && strncmp(cmd, "echo", 4) == 0)
  {
    /* Replace echo with our "builtin" echo */
    replace(&ds_cmd, "echo", 4, builtin_echo, strlen(builtin_echo));
  }

#ifdef __WIN__
#ifndef USE_CYGWIN
  /* Replace /dev/null with NUL */
  while(replace(&ds_cmd, "/dev/null", 9, "NUL", 3) == 0)
    ;
  /* Replace "closed stdout" with non existing output fd */
  while(replace(&ds_cmd, ">&-", 3, ">&4", 3) == 0)
    ;
#endif
#endif

  DBUG_PRINT("info", ("Executing '%s' as '%s'",
                      command->first_argument, ds_cmd.str));

  if (!(res_file= my_popen(&ds_cmd, "r")))
  {
    dynstr_free(&ds_cmd);
    if (command->abort_on_error)
      report_or_die("popen(\"%s\", \"r\") failed", command->first_argument);
    return;
  }

  ds_result= &ds_res;
  if (display_result_sorted)
  {
    init_dynamic_string(&ds_sorted, "", 1024, 1024);
    ds_result= &ds_sorted;
  }

  while (fgets(buf, sizeof(buf), res_file))
  {
    if (disable_result_log)
    {
      buf[strlen(buf)-1]=0;
      DBUG_PRINT("exec_result",("%s", buf));
    }
    else
    {
      replace_dynstr_append(ds_result, buf);
    }
  }
  error= pclose(res_file);

  if (display_result_sorted)
  {
    dynstr_append_sorted(&ds_res, &ds_sorted, 0);
    dynstr_free(&ds_sorted);
  }

  if (error > 0)
  {
    uint status= WEXITSTATUS(error);
    int i;

    if (command->abort_on_error)
    {
      report_or_die("exec of '%s' failed, error: %d, status: %d, errno: %d\n"
                    "Output from before failure:\n%s\n",
                    ds_cmd.str, error, status, errno,
                    ds_res.str);
      dynstr_free(&ds_cmd);
      return;
    }

    DBUG_PRINT("info",
               ("error: %d, status: %d", error, status));

    i= match_expected_error(command, status, NULL);

    if (i >= 0)
      DBUG_PRINT("info", ("command \"%s\" failed with expected error: %d",
                          command->first_argument, status));
    else
    {
      dynstr_free(&ds_cmd);
      if (command->expected_errors.count > 0)
        report_or_die("command \"%s\" failed with wrong error: %d",
                      command->first_argument, status);
    }
  }
  else if (command->expected_errors.err[0].type == ERR_ERRNO &&
           command->expected_errors.err[0].code.errnum != 0)
  {
    /* Error code we wanted was != 0, i.e. not an expected success */
    log_msg("exec of '%s failed, error: %d, errno: %d",
            ds_cmd.str, error, errno);
    dynstr_free(&ds_cmd);
    report_or_die("command \"%s\" succeeded - should have failed with "
                  "errno %d...",
                  command->first_argument,
                  command->expected_errors.err[0].code.errnum);
  }

  dynstr_free(&ds_cmd);
  DBUG_VOID_RETURN;
}

Project: server

void verbose_msg(const char *fmt, ...)
{
  va_list args;
  DBUG_ENTER("verbose_msg");
  DBUG_PRINT("enter", ("format: %s", fmt));

  if (!verbose)
    DBUG_VOID_RETURN;

  fflush(stdout);
  va_start(args, fmt);
  fprintf(stderr, "mysqltest: ");
  if (cur_file && cur_file != file_stack)
    fprintf(stderr, "In included file \"%s\": ",
            cur_file->file_name);
  if (start_lineno != 0)
    fprintf(stderr, "At line %u: ", start_lineno);
  vfprintf(stderr, fmt, args);
  fprintf(stderr, "\n");
  va_end(args);
  fflush(stderr);

  DBUG_VOID_RETURN;
}

Project: server

void close_connections()
{
  DBUG_ENTER("close_connections");
  for (--next_con; next_con >= connections; --next_con)
  {
#ifdef EMBEDDED_LIBRARY
    emb_close_connection(next_con);
#endif
    if (next_con->stmt)
      mysql_stmt_close(next_con->stmt);
    next_con->stmt= 0;
    mysql_close(next_con->mysql);
    next_con->mysql= 0;
    if (next_con->util_mysql)
      mysql_close(next_con->util_mysql);
    my_free(next_con->name);
  }
  my_free(connections);
  DBUG_VOID_RETURN;
}

Project: server

void do_mkdir(struct st_command *command)
{
  int error;
  static DYNAMIC_STRING ds_dirname;
  const struct command_arg mkdir_args[] = {
    {"dirname", ARG_STRING, TRUE, &ds_dirname, "Directory to create"}
  };
  DBUG_ENTER("do_mkdir");

  check_command_args(command, command->first_argument,
                     mkdir_args, sizeof(mkdir_args)/sizeof(struct command_arg),
                     ' ');

  DBUG_PRINT("info", ("creating directory: %s", ds_dirname.str));
  error= my_mkdir(ds_dirname.str, 0777, MYF(MY_WME)) != 0;
  handle_command_error(command, error, my_errno);
  dynstr_free(&ds_dirname);
  DBUG_VOID_RETURN;
}

Project: server

static int my_kill(int pid, int sig)
{
#ifdef __WIN__
  HANDLE proc;
  if ((proc= OpenProcess(SYNCHRONIZE|PROCESS_TERMINATE, FALSE, pid)) == NULL)
    return -1;
  if (sig == 0)
  {
    DWORD wait_result= WaitForSingleObject(proc, 0);
    CloseHandle(proc);
    return wait_result == WAIT_OBJECT_0?-1:0;
  }
  (void)TerminateProcess(proc, 201);
  CloseHandle(proc);
  return 1;
#else
  return kill(pid, sig);
#endif
}

Project: server

void do_close_connection(struct st_command *command)
{
  DBUG_ENTER("do_close_connection");

  struct st_connection *con;
  static DYNAMIC_STRING ds_connection;
  const struct command_arg close_connection_args[] = {
    { "connection_name", ARG_STRING, TRUE, &ds_connection,
      "Name of the connection to close." }
  };
  check_command_args(command, command->first_argument,
                     close_connection_args,
                     sizeof(close_connection_args)/sizeof(struct command_arg),
                     ' ');

  DBUG_PRINT("enter",("connection name: '%s'", ds_connection.str));

  if (!(con= find_connection_by_name(ds_connection.str)))
    die("connection '%s' not found in connection pool", ds_connection.str);

  DBUG_PRINT("info", ("Closing connection %s", con->name));
#ifndef EMBEDDED_LIBRARY
  if (command->type == Q_DIRTY_CLOSE)
  {
    if (con->mysql->net.vio)
    {
      vio_delete(con->mysql->net.vio);
      con->mysql->net.vio = 0;
    }
  }
#else
  /*
    As query could be still executed in a separate theread
    we need to check if the query's thread was finished and probably wait
    (embedded-server specific)
  */
  emb_close_connection(con);
#endif /*EMBEDDED_LIBRARY*/
  if (con->stmt)
    mysql_stmt_close(con->stmt);
  con->stmt= 0;

  mysql_close(con->mysql);
  con->mysql= 0;

  if (con->util_mysql)
    mysql_close(con->util_mysql);
  con->util_mysql= 0;
  con->pending= FALSE;
  
  my_free(con->name);

  /*
    When the connection is closed set name to "-closed_connection-"
    to make it possible to reuse the connection name.
  */
  if (!(con->name = my_strdup("-closed_connection-", MYF(MY_WME))))
    die("Out of memory");

  if (con == cur_con)
  {
    /* Current connection was closed */
    var_set_int("$mysql_get_server_version", 0xFFFFFFFF);
    var_set_string("$CURRENT_CONNECTION", con->name);
  }

  /* Connection logging if enabled */
  if (!disable_connect_log && !disable_query_log)
  {
    DYNAMIC_STRING *ds= &ds_res;

    dynstr_append_mem(ds, "disconnect ", 11);
    replace_dynstr_append(ds, ds_connection.str);
    dynstr_append_mem(ds, ";\n", 2);
  }

  dynstr_free(&ds_connection);
  DBUG_VOID_RETURN;
}

Project: server

static int diff_check(const char *diff_name)
{
  FILE *res_file;
  char buf[128];
  int have_diff= 0;

  my_snprintf(buf, sizeof(buf), "%s -v", diff_name);

  if (!(res_file= popen(buf, "r")))
    die("popen(\"%s\", \"r\") failed", buf);

  /*
    if diff is not present, nothing will be in stdout to increment
    have_diff
  */
  if (fgets(buf, sizeof(buf), res_file))
    have_diff= 1;

  pclose(res_file);

  return have_diff;
}

Project: server

void die(const char *fmt, ...)
{
  char buff[DIE_BUFF_SIZE];
  va_list args;
  va_start(args, fmt);
  make_error_message(buff, sizeof(buff), fmt, args);
  really_die(buff);
}

Project: server

void set_current_connection(struct st_connection *con)
{
  cur_con= con;
  /* Update $mysql_get_server_version to that of current connection */
  var_set_int("$mysql_get_server_version",
              mysql_get_server_version(con->mysql));
  /* Update $CURRENT_CONNECTION to the name of the current connection */
  var_set_string("$CURRENT_CONNECTION", con->name);
}

Project: server

void read_until_delimiter(DYNAMIC_STRING *ds,
                          DYNAMIC_STRING *ds_delimiter)
{
  char c;
  DBUG_ENTER("read_until_delimiter");
  DBUG_PRINT("enter", ("delimiter: %s, length: %u",
                       ds_delimiter->str, (uint) ds_delimiter->length));

  if (ds_delimiter->length > MAX_DELIMITER_LENGTH)
    die("Max delimiter length(%d) exceeded", MAX_DELIMITER_LENGTH);

  /* Read from file until delimiter is found */
  while (1)
  {
    c= my_getc(cur_file->file);

    if (c == '\n')
    {
      cur_file->lineno++;

      /* Skip newline from the same line as the command */
      if (start_lineno == (cur_file->lineno - 1))
        continue;
    }
    else if (start_lineno == cur_file->lineno)
    {
      /*
        No characters except \n are allowed on
        the same line as the command
      */
      report_or_die("Trailing characters found after command");
    }

    if (feof(cur_file->file))
      report_or_die("End of file encountered before '%s' delimiter was found",
                    ds_delimiter->str);

    if (match_delimiter(c, ds_delimiter->str, ds_delimiter->length))
    {
      DBUG_PRINT("exit", ("Found delimiter '%s'", ds_delimiter->str));
      break;
    }
    dynstr_append_mem(ds, (const char*)&c, 1);
  }
  DBUG_PRINT("exit", ("ds: %s", ds->str));
  DBUG_VOID_RETURN;
}

Project: server

void do_send_quit(struct st_command *command)
{
  char *p= command->first_argument, *name;
  struct st_connection *con;

  DBUG_ENTER("do_send_quit");
  DBUG_PRINT("enter",("name: '%s'",p));

  if (!*p)
    die("Missing connection name in send_quit");
  name= p;
  while (*p && !my_isspace(charset_info,*p))
    p++;

  if (*p)
    *p++= 0;
  command->last_argument= p;

  if (!(con= find_connection_by_name(name)))
    die("connection '%s' not found in connection pool", name);

  simple_command(con->mysql,COM_QUIT,0,0,1);

  DBUG_VOID_RETURN;
}

Project: server

void set_reconnect(MYSQL* mysql, my_bool val)
{
  my_bool reconnect= val;
  DBUG_ENTER("set_reconnect");
  DBUG_PRINT("info", ("val: %d", (int) val));
#if MYSQL_VERSION_ID < 50000
  mysql->reconnect= reconnect;
#else
  mysql_options(mysql, MYSQL_OPT_RECONNECT, (char *)&reconnect);
#endif
  DBUG_VOID_RETURN;
}

Project: server

static int run_command(char* cmd,
                       DYNAMIC_STRING *ds_res)
{
  char buf[512]= {0};
  FILE *res_file;
  int error;
  DBUG_ENTER("run_command");
  DBUG_PRINT("enter", ("cmd: %s", cmd));

  if (!(res_file= popen(cmd, "r")))
  {
    report_or_die("popen(\"%s\", \"r\") failed", cmd);
    return -1;
  }

  while (fgets(buf, sizeof(buf), res_file))
  {
    DBUG_PRINT("info", ("buf: %s", buf));
    if(ds_res)
    {
      /* Save the output of this command in the supplied string */
      dynstr_append(ds_res, buf);
    }
    else
    {
      /* Print it directly on screen */
      fprintf(stdout, "%s", buf);
    }
  }

  error= pclose(res_file);
  DBUG_RETURN(WEXITSTATUS(error));
}

Project: server

uint get_errcode_from_name(const char *error_name, const char *error_end,
                            st_error *e)
{
  DBUG_ENTER("get_errcode_from_name");
  DBUG_PRINT("enter", ("error_name: %s", error_name));

  /* Loop through the array of known error names */
  for (; e->name; e++)
  {
    /*
      If we get a match, we need to check the length of the name we
      matched against in case it was longer than what we are checking
      (as in ER_WRONG_VALUE vs. ER_WRONG_VALUE_COUNT).
    */
    if (!strncmp(error_name, e->name, (int) (error_end - error_name)) &&
        (uint) strlen(e->name) == (uint) (error_end - error_name))
    {
      DBUG_RETURN(e->code);
    }
  }
  DBUG_RETURN(0);
}

Project: server

void usage()
{
  print_version();
  puts(ORACLE_WELCOME_COPYRIGHT_NOTICE("2000"));
  printf("Runs a test against the mysql server and compares output with a results file.\n\n");
  printf("Usage: %s [OPTIONS] [database] < test_file\n", my_progname);
  print_defaults("my",load_default_groups);
  puts("");
  my_print_help(my_long_options);
  my_print_variables(my_long_options);
}

Project: server

static int match_expected_error(struct st_command *command,
                                unsigned int err_errno,
                                const char *err_sqlstate)
{
  uint i;

  for (i= 0 ; (uint) i < command->expected_errors.count ; i++)
  {
    if ((command->expected_errors.err[i].type == ERR_ERRNO) &&
        (command->expected_errors.err[i].code.errnum == err_errno))
      return i;

    if (command->expected_errors.err[i].type == ERR_SQLSTATE)
    {
      /*
        NULL is quite likely, but not in conjunction with a SQL-state expect!
      */
      if (unlikely(err_sqlstate == NULL))
        die("expecting a SQL-state (%s) from query '%s' which cannot "
            "produce one...",
            command->expected_errors.err[i].code.sqlstate, command->query);

      if (strncmp(command->expected_errors.err[i].code.sqlstate,
                  err_sqlstate, SQLSTATE_LENGTH) == 0)
        return i;
    }
  }
  return -1;
}

Project: server

static void dump_backtrace(void)
{
  struct st_connection *conn= cur_con;

  fprintf(stderr, "read_command_buf (%p): ", read_command_buf);
  my_safe_print_str(read_command_buf, sizeof(read_command_buf));
  fputc('\n', stderr);

  if (conn)
  {
    fprintf(stderr, "conn->name (%p): ", conn->name);
    my_safe_print_str(conn->name, conn->name_len);
    fputc('\n', stderr);
#ifdef EMBEDDED_LIBRARY
    fprintf(stderr, "conn->cur_query (%p): ", conn->cur_query);
    my_safe_print_str(conn->cur_query, conn->cur_query_len);
    fputc('\n', stderr);
#endif
  }
  fputs("Attempting backtrace...\n", stderr);
  my_print_stacktrace(NULL, my_thread_stack_size);
}

Project: server

*/
MYSQL_PLUGIN_EXPORT
char *mysql_authentication_dialog_ask(MYSQL *mysql, int type,
                                      const char *prompt,
                                      char *buf, int buf_len)
{
  char *s=buf;

  fputs(prompt, stdout);
  fputs(" ", stdout);

  if (!fgets(buf, buf_len-1, stdin))
    buf[0]= 0;
  else if (buf[0] && (s= strend(buf))[-1] == '\n')
    s[-1]= 0;

  for (s= buf; *s; s++)
    fputc(type == 2 ? '*' : *s, stdout);

  fputc('\n', stdout);

Project: server

void do_get_errcodes(struct st_command *command)
{
  struct st_match_err *to= saved_expected_errors.err;
  DBUG_ENTER("do_get_errcodes");

  if (!*command->first_argument)
    die("Missing argument(s) to 'error'");

  /* TODO: Potentially, there is a possibility of variables 
     being expanded twice, e.g.

     let $errcodes = 1,\$a;
     let $a = 1051;
     error $errcodes;
     DROP TABLE unknown_table;
     ...
     Got one of the listed errors

     But since it requires manual escaping, it does not seem 
     particularly dangerous or error-prone. 
  */
  DYNAMIC_STRING ds;
  init_dynamic_string(&ds, 0, command->query_len + 64, 256);
  do_eval(&ds, command->first_argument, command->end, !is_windows);
  char *p= ds.str;

  uint count= 0;
  char *next;

  do
  {
    char *end;

    /* Skip leading spaces */
    while (*p && *p == ' ')
      p++;

    /* Find end */
    end= p;
    while (*end && *end != ',' && *end != ' ')
      end++;

    next=end;

    /* code to handle variables passed to mysqltest */
     if( *p == '$')
     {
        const char* fin;
        VAR *var = var_get(p,&fin,0,0);
        p=var->str_val;
        end=p+var->str_val_len;
     }

    if (*p == 'S')
    {
      char *to_ptr= to->code.sqlstate;

      /*
        SQLSTATE string
        - Must be SQLSTATE_LENGTH long
        - May contain only digits[0-9] and _uppercase_ letters
      */
      p++; /* Step past the S */
      if ((end - p) != SQLSTATE_LENGTH)
        die("The sqlstate must be exactly %d chars long", SQLSTATE_LENGTH);

      /* Check sqlstate string validity */
      while (*p && p < end)
      {
        if (my_isdigit(charset_info, *p) || my_isupper(charset_info, *p))
          *to_ptr++= *p++;
        else
          die("The sqlstate may only consist of digits[0-9] " \
              "and _uppercase_ letters");
      }

      *to_ptr= 0;
      to->type= ERR_SQLSTATE;
      DBUG_PRINT("info", ("ERR_SQLSTATE: %s", to->code.sqlstate));
    }
    else if (*p == 's')
    {
      die("The sqlstate definition must start with an uppercase S");
    }
    else if (*p == 'E' || *p == 'H')
    {
      /* Error name string */

      DBUG_PRINT("info", ("Error name: %s", p));
      to->code.errnum= get_errcode_from_name(p, end);
      to->type= ERR_ERRNO;
      DBUG_PRINT("info", ("ERR_ERRNO: %d", to->code.errnum));
    }
    else if (*p == 'e' || *p == 'h')
    {
      die("The error name definition must start with an uppercase E or H");
    }
    else
    {
      long val;
      char *start= p;
      /* Check that the string passed to str2int only contain digits */
      while (*p && p != end)
      {
        if (!my_isdigit(charset_info, *p))
          die("Invalid argument to error: '%s' - "            \
              "the errno may only consist of digits[0-9]",
              command->first_argument);
        p++;
      }

      /* Convert the sting to int */
      if (!str2int(start, 10, (long) INT_MIN, (long) INT_MAX, &val))
	die("Invalid argument to error: '%s'", command->first_argument);

      to->code.errnum= (uint) val;
      to->type= ERR_ERRNO;
      DBUG_PRINT("info", ("ERR_ERRNO: %d", to->code.errnum));
    }
    to++;
    count++;

    if (count >= (sizeof(saved_expected_errors.err) /
                  sizeof(struct st_match_err)))
      die("Too many errorcodes specified");

    /* Set pointer to the end of the last error code */
    p= next;

    /* Find next ',' */
    while (*p && *p != ',')
      p++;

    if (*p)
      p++; /* Step past ',' */

  } while (*p);

  command->last_argument= command->first_argument;
  while (*command->last_argument)
    command->last_argument++;
  
  to->type= ERR_EMPTY;                        /* End of data */

  DBUG_PRINT("info", ("Expected errors: %d", count));
  saved_expected_errors.count= count;
  dynstr_free(&ds);
  DBUG_VOID_RETURN;
}

Project: server

void do_file_exist(struct st_command *command)
{
  int error;
  static DYNAMIC_STRING ds_filename;
  const struct command_arg file_exist_args[] = {
    { "filename", ARG_STRING, TRUE, &ds_filename, "File to check if it exist" }
  };
  DBUG_ENTER("do_file_exist");

  check_command_args(command, command->first_argument,
                     file_exist_args,
                     sizeof(file_exist_args)/sizeof(struct command_arg),
                     ' ');

  DBUG_PRINT("info", ("Checking for existence of file: %s", ds_filename.str));
  error= (access(ds_filename.str, F_OK) != 0);
  handle_command_error(command, error, errno);
  dynstr_free(&ds_filename);
  DBUG_VOID_RETURN;
}

Project: server

void handle_no_error(struct st_command *command)
{
  DBUG_ENTER("handle_no_error");

  if (command->expected_errors.err[0].type == ERR_ERRNO &&
      command->expected_errors.err[0].code.errnum != 0)
  {
    /* Error code we wanted was != 0, i.e. not an expected success */
    report_or_die("query '%s' succeeded - should have failed with errno %d...",
                  command->query, command->expected_errors.err[0].code.errnum);
  }
  else if (command->expected_errors.err[0].type == ERR_SQLSTATE &&
           strcmp(command->expected_errors.err[0].code.sqlstate,"00000") != 0)
  {
    /* SQLSTATE we wanted was != "00000", i.e. not an expected success */
    report_or_die("query '%s' succeeded - should have failed with "
                  "sqlstate %s...",
                  command->query,
                  command->expected_errors.err[0].code.sqlstate);
  }
  DBUG_VOID_RETURN;
}

Project: server

void free_used_memory()
{
  uint i;
  DBUG_ENTER("free_used_memory");

  if (connections)
    close_connections();
  close_files();
  my_hash_free(&var_hash);

  for (i= 0 ; i < q_lines.elements ; i++)
  {
    struct st_command **q= dynamic_element(&q_lines, i, struct st_command**);
    my_free((*q)->query_buf);
    if ((*q)->eval_query.str)
      dynstr_free(&(*q)->eval_query);
    if ((*q)->content.str)
      dynstr_free(&(*q)->content);
    my_free((*q));
  }
  for (i= 0; i < 10; i++)
  {
    if (var_reg[i].alloced_len)
      my_free(var_reg[i].str_val);
  }
  while (embedded_server_arg_count > 1)
    my_free(embedded_server_args[--embedded_server_arg_count]);
  delete_dynamic(&q_lines);
  dynstr_free(&ds_res);
  if (ds_warn)
    dynstr_free(ds_warn);
  free_all_replace();
  my_free(opt_pass);
  free_defaults(default_argv);
  free_root(&require_file_root, MYF(0));
  free_re();
#ifdef __WIN__
  free_tmp_sh_file();
  free_win_path_patterns();
#endif
  DBUG_VOID_RETURN;
}

Project: server

static int do_send_query(struct st_connection *cn, const char *q, int q_len)
{
  if (!cn->has_thread)
    return mysql_send_query(cn->mysql, q, q_len);
  cn->cur_query= q;
  cn->cur_query_len= q_len;
  signal_connection_thd(cn, EMB_SEND_QUERY);
  return 0;
}

Project: server

static void strip_parentheses(struct st_command *command)
{
  if (strip_surrounding(command->first_argument, '(', ')'))
    die("%.*s - argument list started with '%c' must be ended with '%c'",
        command->first_word_len, command->query, '(', ')');
}

Project: server

void run_query(struct st_connection *cn, struct st_command *command, int flags)
{
  MYSQL *mysql= cn->mysql;
  DYNAMIC_STRING *ds;
  DYNAMIC_STRING *save_ds= NULL;
  DYNAMIC_STRING ds_result;
  DYNAMIC_STRING ds_sorted;
  DYNAMIC_STRING ds_warnings;
  char *query;
  int query_len;
  my_bool view_created= 0, sp_created= 0;
  my_bool complete_query= ((flags & QUERY_SEND_FLAG) &&
                           (flags & QUERY_REAP_FLAG));
  DBUG_ENTER("run_query");

  if (cn->pending && (flags & QUERY_SEND_FLAG))
    die("Cannot run query on connection between send and reap");

  if (!(flags & QUERY_SEND_FLAG) && !cn->pending)
    die("Cannot reap on a connection without pending send");
  
  init_dynamic_string(&ds_warnings, NULL, 0, 256);
  ds_warn= &ds_warnings;
  
  /*
    Evaluate query if this is an eval command
  */
  if (command->type == Q_EVAL || command->type == Q_SEND_EVAL)
  {
    if (!command->eval_query.str)
      init_dynamic_string(&command->eval_query, "", command->query_len + 256,
                          1024);
    else
      dynstr_set(&command->eval_query, 0);
    do_eval(&command->eval_query, command->query, command->end, FALSE);
    query= command->eval_query.str;
    query_len= command->eval_query.length;
  }
  else
  {
    query = command->query;
    query_len = strlen(query);
  }

  /*
    When command->require_file is set the output of _this_ query
    should be compared with an already existing file
    Create a temporary dynamic string to contain the output from
    this query.
  */
  if (command->require_file)
  {
    init_dynamic_string(&ds_result, "", 1024, 1024);
    ds= &ds_result;
  }
  else
    ds= &ds_res;

  /*
    Log the query into the output buffer
  */
  if (!disable_query_log && (flags & QUERY_SEND_FLAG))
  {
    replace_dynstr_append_mem(ds, query, query_len);
    dynstr_append_mem(ds, delimiter, delimiter_length);
    dynstr_append_mem(ds, "\n", 1);
  }

  /*
    Write the command to the result file before we execute the query
    This is needed to be able to analyse the log if something goes
    wrong
  */
  log_file.write(&ds_res);
  log_file.flush();
  dynstr_set(&ds_res, 0);

  if (view_protocol_enabled &&
      complete_query &&
      match_re(&view_re, query))
  {
    /*
      Create the query as a view.
      Use replace since view can exist from a failed mysqltest run
    */
    DYNAMIC_STRING query_str;
    init_dynamic_string(&query_str,
			"CREATE OR REPLACE VIEW mysqltest_tmp_v AS ",
			query_len+64, 256);
    dynstr_append_mem(&query_str, query, query_len);
    if (util_query(mysql, query_str.str))
    {
      /*
	Failed to create the view, this is not fatal
	just run the query the normal way
      */
      DBUG_PRINT("view_create_error",
		 ("Failed to create view '%s': %d: %s", query_str.str,
		  mysql_errno(mysql), mysql_error(mysql)));

      /* Log error to create view */
      verbose_msg("Failed to create view '%s' %d: %s", query_str.str,
		  mysql_errno(mysql), mysql_error(mysql));
    }
    else
    {
      /*
	Yes, it was possible to create this query as a view
      */
      view_created= 1;
      query= (char*)"SELECT * FROM mysqltest_tmp_v";
      query_len = strlen(query);

      /*
        Collect warnings from create of the view that should otherwise
        have been produced when the SELECT was executed
      */
      append_warnings(&ds_warnings, cur_con->util_mysql);
    }

    dynstr_free(&query_str);
  }

  if (sp_protocol_enabled &&
      complete_query &&
      match_re(&sp_re, query))
  {
    /*
      Create the query as a stored procedure
      Drop first since sp can exist from a failed mysqltest run
    */
    DYNAMIC_STRING query_str;
    init_dynamic_string(&query_str,
			"DROP PROCEDURE IF EXISTS mysqltest_tmp_sp;",
			query_len+64, 256);
    util_query(mysql, query_str.str);
    dynstr_set(&query_str, "CREATE PROCEDURE mysqltest_tmp_sp()\n");
    dynstr_append_mem(&query_str, query, query_len);
    if (util_query(mysql, query_str.str))
    {
      /*
	Failed to create the stored procedure for this query,
	this is not fatal just run the query the normal way
      */
      DBUG_PRINT("sp_create_error",
		 ("Failed to create sp '%s': %d: %s", query_str.str,
		  mysql_errno(mysql), mysql_error(mysql)));

      /* Log error to create sp */
      verbose_msg("Failed to create sp '%s' %d: %s", query_str.str,
		  mysql_errno(mysql), mysql_error(mysql));

    }
    else
    {
      sp_created= 1;

      query= (char*)"CALL mysqltest_tmp_sp()";
      query_len = strlen(query);
    }
    dynstr_free(&query_str);
  }

  if (display_result_sorted)
  {
    /*
       Collect the query output in a separate string
       that can be sorted before it's added to the
       global result string
    */
    init_dynamic_string(&ds_sorted, "", 1024, 1024);
    save_ds= ds; /* Remember original ds */
    ds= &ds_sorted;
  }

  /*
    Find out how to run this query

    Always run with normal C API if it's not a complete
    SEND + REAP

    If it is a '?' in the query it may be a SQL level prepared
    statement already and we can't do it twice
  */
  if (ps_protocol_enabled &&
      complete_query &&
      match_re(&ps_re, query))
    run_query_stmt(cn, command, query, query_len, ds, &ds_warnings);
  else
    run_query_normal(cn, command, flags, query, query_len,
		     ds, &ds_warnings);

  dynstr_free(&ds_warnings);
  ds_warn= 0;

  if (display_result_sorted)
  {
    /* Sort the result set and append it to result */
    dynstr_append_sorted(save_ds, &ds_sorted, 1);
    ds= save_ds;
    dynstr_free(&ds_sorted);
  }

  if (sp_created)
  {
    if (util_query(mysql, "DROP PROCEDURE mysqltest_tmp_sp "))
      report_or_die("Failed to drop sp: %d: %s", mysql_errno(mysql),
                     mysql_error(mysql));
  }

  if (view_created)
  {
    if (util_query(mysql, "DROP VIEW mysqltest_tmp_v "))
      report_or_die("Failed to drop view: %d: %s",
	  mysql_errno(mysql), mysql_error(mysql));
  }

  if (command->require_file)
  {
    /* A result file was specified for _this_ query
       and the output should be checked against an already
       existing file which has been specified using --require or --result
    */
    check_require(ds, command->require_file);
  }

  if (ds == &ds_result)
    dynstr_free(&ds_result);
  DBUG_VOID_RETURN;
}

Project: server

static void init_signal_handling(void)
{
  struct sigaction sa;
  DBUG_ENTER("init_signal_handling");

#ifdef HAVE_STACKTRACE
  my_init_stacktrace();
#endif

  sa.sa_flags = SA_RESETHAND | SA_NODEFER;
  sigemptyset(&sa.sa_mask);
  sigprocmask(SIG_SETMASK, &sa.sa_mask, NULL);

  sa.sa_handler= signal_handler;

  sigaction(SIGSEGV, &sa, NULL);
  sigaction(SIGABRT, &sa, NULL);
#ifdef SIGBUS
  sigaction(SIGBUS, &sa, NULL);
#endif
  sigaction(SIGILL, &sa, NULL);
  sigaction(SIGFPE, &sa, NULL);
  DBUG_VOID_RETURN;
}

Project: server

pthread_handler_t connection_thread(void *arg)
{
  struct st_connection *cn= (struct st_connection*)arg;

  mysql_thread_init();
  while (cn->command != EMB_END_CONNECTION)
  {
    if (!cn->command)
    {
      pthread_mutex_lock(&cn->query_mutex);
      while (!cn->command)
        pthread_cond_wait(&cn->query_cond, &cn->query_mutex);
      pthread_mutex_unlock(&cn->query_mutex);
    }
    switch (cn->command)
    {
      case EMB_END_CONNECTION:
        goto end_thread;
      case EMB_SEND_QUERY:
        cn->result= mysql_send_query(cn->mysql,
                                     cn->cur_query, cn->cur_query_len);
        break;
      case EMB_READ_QUERY_RESULT:
        cn->result= mysql_read_query_result(cn->mysql);
        break;
      case EMB_PREPARE_STMT:
        cn->result= mysql_stmt_prepare(cn->stmt,
                                       cn->cur_query, cn->cur_query_len);
        break;
      case EMB_EXECUTE_STMT:
        cn->result= mysql_stmt_execute(cn->stmt);
        break;
      default:
        DBUG_ASSERT(0);
    }
    cn->command= 0;
    pthread_mutex_lock(&cn->result_mutex);
    cn->query_done= 1;
    pthread_cond_signal(&cn->result_cond);
    pthread_mutex_unlock(&cn->result_mutex);
  }

end_thread:
  cn->query_done= 1;
  mysql_thread_end();
  pthread_exit(0);
  return 0;
}

Project: server

int cat_file(DYNAMIC_STRING* ds, const char* filename)
{
  int fd;
  size_t len;
  char buff[16384];

  if ((fd= my_open(filename, O_RDONLY, MYF(0))) < 0)
    return 1;
  while((len= my_read(fd, (uchar*)&buff,
                      sizeof(buff)-1, MYF(0))) > 0)
  {
    char *p= buff, *start= buff;
    while (p < buff+len)
    {
      /* Convert cr/lf to lf */
      if (*p == '\r' && *(p+1) && *(p+1)== '\n')
      {
        /* Add fake newline instead of cr and output the line */
        *p= '\n';
        p++; /* Step past the "fake" newline */
        *p= 0;
        replace_dynstr_append_mem(ds, start, p-start);
        p++; /* Step past the "fake" newline */
        start= p;
      }
      else
        p++;
    }
    /* Output any chars that migh be left */
    *p= 0;
    replace_dynstr_append_mem(ds, start, p-start);
  }
  my_close(fd, MYF(0));
  return 0;
}

Project: server

void do_remove_file(struct st_command *command)
{
  int error;
  static DYNAMIC_STRING ds_filename;
  const struct command_arg rm_args[] = {
    { "filename", ARG_STRING, TRUE, &ds_filename, "File to delete" }
  };
  DBUG_ENTER("do_remove_file");

  check_command_args(command, command->first_argument,
                     rm_args, sizeof(rm_args)/sizeof(struct command_arg),
                     ' ');

  DBUG_PRINT("info", ("removing file: %s", ds_filename.str));
  error= my_delete(ds_filename.str, MYF(disable_warnings ? 0 : MY_WME)) != 0;
  handle_command_error(command, error, my_errno);
  dynstr_free(&ds_filename);
  DBUG_VOID_RETURN;
}

Project: server

void do_remove_files_wildcard(struct st_command *command)
{
  int error= 0, sys_errno= 0;
  uint i;
  size_t directory_length;
  MY_DIR *dir_info;
  FILEINFO *file;
  char dir_separator[2];
  static DYNAMIC_STRING ds_directory;
  static DYNAMIC_STRING ds_wild;
  static DYNAMIC_STRING ds_file_to_remove;
  char dirname[FN_REFLEN];
  
  const struct command_arg rm_args[] = {
    { "directory", ARG_STRING, TRUE, &ds_directory,
      "Directory containing files to delete" },
    { "filename", ARG_STRING, FALSE, &ds_wild, "File pattern to delete" }
  };
  DBUG_ENTER("do_remove_files_wildcard");

  check_command_args(command, command->first_argument,
                     rm_args, sizeof(rm_args)/sizeof(struct command_arg),
                     ' ');
  fn_format(dirname, ds_directory.str, "", "", MY_UNPACK_FILENAME);

  DBUG_PRINT("info", ("listing directory: %s", dirname));
  /* Note that my_dir sorts the list if not given any flags */
  if (!(dir_info= my_dir(dirname, MYF(MY_DONT_SORT | MY_WANT_STAT | MY_WME))))
  {
    error= 1;
    sys_errno= my_errno;
    goto end;
  }
  init_dynamic_string(&ds_file_to_remove, dirname, 1024, 1024);
  dir_separator[0]= FN_LIBCHAR;
  dynstr_append_mem(&ds_file_to_remove, dir_separator, 1);
  directory_length= ds_file_to_remove.length;
  
  /* Set default wild chars for wild_compare, is changed in embedded mode */
  set_wild_chars(1);
  
  for (i= 0; i < (uint) dir_info->number_off_files; i++)
  {
    file= dir_info->dir_entry + i;
    /* Remove only regular files, i.e. no directories etc. */
    /* if (!MY_S_ISREG(file->mystat->st_mode)) */
    /* MY_S_ISREG does not work here on Windows, just skip directories */
    if (MY_S_ISDIR(file->mystat->st_mode))
      continue;
    if (ds_wild.length &&
        wild_compare(file->name, ds_wild.str, 0))
      continue;
    ds_file_to_remove.length= directory_length;
    dynstr_append(&ds_file_to_remove, file->name);
    DBUG_PRINT("info", ("removing file: %s", ds_file_to_remove.str));
    if ((error= (my_delete(ds_file_to_remove.str, MYF(MY_WME)) != 0)))
      sys_errno= my_errno;
    if (error)
      break;
  }
  set_wild_chars(0);
  my_dirend(dir_info);

end:
  handle_command_error(command, error, sys_errno);
  dynstr_free(&ds_directory);
  dynstr_free(&ds_wild);
  dynstr_free(&ds_file_to_remove);
  DBUG_VOID_RETURN;
}

Project: server

int do_save_master_pos()
{
  MYSQL_RES *res;
  MYSQL_ROW row;
  MYSQL *mysql = cur_con->mysql;
  const char *query;
  DBUG_ENTER("do_save_master_pos");

#ifdef HAVE_NDB_BINLOG
  /*
    Wait for ndb binlog to be up-to-date with all changes
    done on the local mysql server
  */
  {
    ulong have_ndbcluster;
    if (mysql_query(mysql, query= "show variables like 'have_ndbcluster'"))
      die("'%s' failed: %d %s", query,
          mysql_errno(mysql), mysql_error(mysql));
    if (!(res= mysql_store_result(mysql)))
      die("mysql_store_result() returned NULL for '%s'", query);
    if (!(row= mysql_fetch_row(res)))
      die("Query '%s' returned empty result", query);

    have_ndbcluster= strcmp("YES", row[1]) == 0;
    mysql_free_result(res);

    if (have_ndbcluster)
    {
      ulonglong start_epoch= 0, handled_epoch= 0,
	latest_epoch=0, latest_trans_epoch=0,
	latest_handled_binlog_epoch= 0, latest_received_binlog_epoch= 0,
	latest_applied_binlog_epoch= 0;
      int count= 0;
      int do_continue= 1;
      while (do_continue)
      {
        const char binlog[]= "binlog";
	const char latest_epoch_str[]=
          "latest_epoch=";
        const char latest_trans_epoch_str[]=
          "latest_trans_epoch=";
	const char latest_received_binlog_epoch_str[]=
	  "latest_received_binlog_epoch";
        const char latest_handled_binlog_epoch_str[]=
          "latest_handled_binlog_epoch=";
        const char latest_applied_binlog_epoch_str[]=
          "latest_applied_binlog_epoch=";
        if (count)
          my_sleep(100*1000); /* 100ms */
        if (mysql_query(mysql, query= "show engine ndb status"))
          die("failed in '%s': %d %s", query,
              mysql_errno(mysql), mysql_error(mysql));
        if (!(res= mysql_store_result(mysql)))
          die("mysql_store_result() returned NULL for '%s'", query);
        while ((row= mysql_fetch_row(res)))
        {
          if (strcmp(row[1], binlog) == 0)
          {
            const char *status= row[2];

	    /* latest_epoch */
	    while (*status && strncmp(status, latest_epoch_str,
				      sizeof(latest_epoch_str)-1))
	      status++;
	    if (*status)
            {
	      status+= sizeof(latest_epoch_str)-1;
	      latest_epoch= strtoull(status, (char**) 0, 10);
	    }
	    else
	      die("result does not contain '%s' in '%s'",
		  latest_epoch_str, query);
	    /* latest_trans_epoch */
	    while (*status && strncmp(status, latest_trans_epoch_str,
				      sizeof(latest_trans_epoch_str)-1))
	      status++;
	    if (*status)
	    {
	      status+= sizeof(latest_trans_epoch_str)-1;
	      latest_trans_epoch= strtoull(status, (char**) 0, 10);
	    }
	    else
	      die("result does not contain '%s' in '%s'",
		  latest_trans_epoch_str, query);
	    /* latest_received_binlog_epoch */
	    while (*status &&
		   strncmp(status, latest_received_binlog_epoch_str,
			   sizeof(latest_received_binlog_epoch_str)-1))
	      status++;
	    if (*status)
	    {
	      status+= sizeof(latest_received_binlog_epoch_str)-1;
	      latest_received_binlog_epoch= strtoull(status, (char**) 0, 10);
	    }
	    else
	      die("result does not contain '%s' in '%s'",
		  latest_received_binlog_epoch_str, query);
	    /* latest_handled_binlog */
	    while (*status &&
		   strncmp(status, latest_handled_binlog_epoch_str,
			   sizeof(latest_handled_binlog_epoch_str)-1))
	      status++;
	    if (*status)
	    {
	      status+= sizeof(latest_handled_binlog_epoch_str)-1;
	      latest_handled_binlog_epoch= strtoull(status, (char**) 0, 10);
	    }
	    else
	      die("result does not contain '%s' in '%s'",
		  latest_handled_binlog_epoch_str, query);
	    /* latest_applied_binlog_epoch */
	    while (*status &&
		   strncmp(status, latest_applied_binlog_epoch_str,
			   sizeof(latest_applied_binlog_epoch_str)-1))
	      status++;
	    if (*status)
	    {
	      status+= sizeof(latest_applied_binlog_epoch_str)-1;
	      latest_applied_binlog_epoch= strtoull(status, (char**) 0, 10);
	    }
	    else
	      die("result does not contain '%s' in '%s'",
		  latest_applied_binlog_epoch_str, query);
	    if (count == 0)
	      start_epoch= latest_trans_epoch;
	    break;
	  }
	}
	if (!row)
	  die("result does not contain '%s' in '%s'",
	      binlog, query);
	if (latest_handled_binlog_epoch > handled_epoch)
	  count= 0;
	handled_epoch= latest_handled_binlog_epoch;
	count++;
	if (latest_handled_binlog_epoch >= start_epoch)
          do_continue= 0;
        else if (count > 300) /* 30s */
	{
	  break;
        }
        mysql_free_result(res);
      }
    }
  }
#endif
  if (mysql_query(mysql, query= "show master status"))
    die("failed in 'show master status': %d %s",
	mysql_errno(mysql), mysql_error(mysql));

  if (!(res = mysql_store_result(mysql)))
    die("mysql_store_result() retuned NULL for '%s'", query);
  if (!(row = mysql_fetch_row(res)))
    die("empty result in show master status");
  strnmov(master_pos.file, row[0], sizeof(master_pos.file)-1);
  master_pos.pos = strtoul(row[1], (char**) 0, 10);
  mysql_free_result(res);
  DBUG_RETURN(0);
}

Project: server

const char *get_errname_from_code(uint error_code)
{
  const char *name;
  if ((name= get_errname_from_code(error_code, global_error_names)) !=
      unknown_error)
    return name;
  return get_errname_from_code(error_code, handler_error_names);
}

Project: server

int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname)
{
  int error;
  File fd;
  char temp_file_path[FN_REFLEN];

  DBUG_ENTER("dyn_string_cmp");
  DBUG_PRINT("enter", ("fname: %s", fname));

  if ((fd= create_temp_file(temp_file_path, TMPDIR,
                            "tmp", O_CREAT | O_SHARE | O_RDWR,
                            MYF(MY_WME))) < 0)
    die("Failed to create temporary file for ds");

  /* Write ds to temporary file and set file pos to beginning*/
  if (my_write(fd, (uchar *) ds->str, ds->length,
               MYF(MY_FNABP | MY_WME)) ||
      my_seek(fd, 0, SEEK_SET, MYF(0)) == MY_FILEPOS_ERROR)
  {
    my_close(fd, MYF(0));
    /* Remove the temporary file */
    my_delete(temp_file_path, MYF(MY_WME));
    die("Failed to write file '%s'", temp_file_path);
  }

  error= compare_files2(fd, fname);

  my_close(fd, MYF(0));
  /* Remove the temporary file */
  my_delete(temp_file_path, MYF(MY_WME));

  DBUG_RETURN(error);
}

Project: server

void do_chmod_file(struct st_command *command)
{
  long mode= 0;
  int err_code;
  static DYNAMIC_STRING ds_mode;
  static DYNAMIC_STRING ds_file;
  const struct command_arg chmod_file_args[] = {
    { "mode", ARG_STRING, TRUE, &ds_mode, "Mode of file(octal) ex. 0660"}, 
    { "filename", ARG_STRING, TRUE, &ds_file, "Filename of file to modify" }
  };
  DBUG_ENTER("do_chmod_file");

  check_command_args(command, command->first_argument,
                     chmod_file_args,
                     sizeof(chmod_file_args)/sizeof(struct command_arg),
                     ' ');

  /* Parse what mode to set */
  if (ds_mode.length != 4 ||
      str2int(ds_mode.str, 8, 0, INT_MAX, &mode) == NullS)
    die("You must write a 4 digit octal number for mode");

  DBUG_PRINT("info", ("chmod %o %s", (uint)mode, ds_file.str));
  err_code= chmod(ds_file.str, mode);
  if (err_code < 0)
    err_code= 1;
  handle_command_error(command, err_code, errno);
  dynstr_free(&ds_mode);
  dynstr_free(&ds_file);
  DBUG_VOID_RETURN;
}

Project: server

void do_sync_with_master2(struct st_command *command, long offset)
{
  MYSQL_RES *res;
  MYSQL_ROW row;
  MYSQL *mysql= cur_con->mysql;
  char query_buf[FN_REFLEN+128];
  int timeout= 300; /* seconds */

  if (!master_pos.file[0])
    die("Calling 'sync_with_master' without calling 'save_master_pos'");

  sprintf(query_buf, "select master_pos_wait('%s', %ld, %d)",
          master_pos.file, master_pos.pos + offset, timeout);

  if (mysql_query(mysql, query_buf))
    die("failed in '%s': %d: %s", query_buf, mysql_errno(mysql),
        mysql_error(mysql));

  if (!(res= mysql_store_result(mysql)))
    die("mysql_store_result() returned NULL for '%s'", query_buf);
  if (!(row= mysql_fetch_row(res)))
  {
    mysql_free_result(res);
    die("empty result in %s", query_buf);
  }

  int result= -99;
  const char* result_str= row[0];
  if (result_str)
    result= atoi(result_str);

  mysql_free_result(res);

  if (!result_str || result < 0)
  {
    /* master_pos_wait returned NULL or < 0 */
    show_query(mysql, "SHOW MASTER STATUS");
    show_query(mysql, "SHOW SLAVE STATUS");
    show_query(mysql, "SHOW PROCESSLIST");
    fprintf(stderr, "analyze: sync_with_master\n");

    if (!result_str)
    {
      /*
        master_pos_wait returned NULL. This indicates that
        slave SQL thread is not started, the slave's master
        information is not initialized, the arguments are
        incorrect, or an error has occured
      */
      die("%.*s failed: '%s' returned NULL "          \
          "indicating slave SQL thread failure",
          command->first_word_len, command->query, query_buf);

    }

    if (result == -1)
      die("%.*s failed: '%s' returned -1 "            \
          "indicating timeout after %d seconds",
          command->first_word_len, command->query, query_buf, timeout);
    else
      die("%.*s failed: '%s' returned unknown result :%d",
          command->first_word_len, command->query, query_buf, result);
  }

  return;
}

Project: server

get_one_option(int optid, const struct my_option *opt, char *argument)
{
  switch(optid) {
  case '#':
#ifndef DBUG_OFF
    DBUG_PUSH(argument ? argument : "d:t:S:i:O,/tmp/mysqltest.trace");
    debug_check_flag= 1;
    debug_info_flag= 1;
#endif
    break;
  case 'r':
    record = 1;
    break;
  case 'x':
  {
    char buff[FN_REFLEN];
    if (!test_if_hard_path(argument))
    {
      strxmov(buff, opt_basedir, argument, NullS);
      argument= buff;
    }
    fn_format(buff, argument, "", "", MY_UNPACK_FILENAME);
    DBUG_ASSERT(cur_file == file_stack && cur_file->file == 0);
    if (!(cur_file->file=
          fopen(buff, "rb")))
      die("Could not open '%s' for reading, errno: %d", buff, errno);
    cur_file->file_name= my_strdup(buff, MYF(MY_FAE));
    cur_file->lineno= 1;
    break;
  }
  case 'm':
  {
    static char buff[FN_REFLEN];
    if (!test_if_hard_path(argument))
    {
      strxmov(buff, opt_basedir, argument, NullS);
      argument= buff;
    }
    fn_format(buff, argument, "", "", MY_UNPACK_FILENAME);
    timer_file= buff;
    unlink(timer_file);	     /* Ignore error, may not exist */
    break;
  }
  case 'p':
    if (argument == disabled_my_option)
      argument= (char*) "";			// Don't require password
    if (argument)
    {
      my_free(opt_pass);
      opt_pass= my_strdup(argument, MYF(MY_FAE));
      while (*argument) *argument++= 'x';		/* Destroy argument */
      tty_password= 0;
    }
    else
      tty_password= 1;
    break;
#include <sslopt-case.h>
  case 't':
    strnmov(TMPDIR, argument, sizeof(TMPDIR));
    break;
  case 'A':
    if (!embedded_server_arg_count)
    {
      embedded_server_arg_count=1;
      embedded_server_args[0]= (char*) "";
    }
    if (embedded_server_arg_count == MAX_EMBEDDED_SERVER_ARGS-1 ||
        !(embedded_server_args[embedded_server_arg_count++]=
          my_strdup(argument, MYF(MY_FAE))))
    {
      die("Can't use server argument");
    }
    break;
  case OPT_LOG_DIR:
    /* Check that the file exists */
    if (access(opt_logdir, F_OK) != 0)
      die("The specified log directory does not exist: '%s'", opt_logdir);
    break;
  case 'F':
    read_embedded_server_arguments(argument);
    break;
  case OPT_RESULT_FORMAT_VERSION:
    set_result_format_version(opt_result_format_version);
    break;
  case 'V':
    print_version();
    exit(0);
  case OPT_MYSQL_PROTOCOL:
#ifndef EMBEDDED_LIBRARY
    opt_protocol= find_type_or_exit(argument, &sql_protocol_typelib,
                                    opt->name);
#endif
    break;
  case '?':
    usage();
    exit(0);
  }
  return 0;
}

Project: server

void run_query_stmt(struct st_connection *cn, struct st_command *command,
                    char *query, int query_len, DYNAMIC_STRING *ds,
                    DYNAMIC_STRING *ds_warnings)
{
  MYSQL_RES *res= NULL;     /* Note that here 'res' is meta data result set */
  MYSQL *mysql= cn->mysql;
  MYSQL_STMT *stmt;
  DYNAMIC_STRING ds_prepare_warnings;
  DYNAMIC_STRING ds_execute_warnings;
  DBUG_ENTER("run_query_stmt");
  DBUG_PRINT("query", ("'%-.60s'", query));

  /*
    Init a new stmt if it's not already one created for this connection
  */
  if(!(stmt= cn->stmt))
  {
    if (!(stmt= mysql_stmt_init(mysql)))
      die("unable to init stmt structure");
    cn->stmt= stmt;
  }

  /* Init dynamic strings for warnings */
  if (!disable_warnings)
  {
    init_dynamic_string(&ds_prepare_warnings, NULL, 0, 256);
    init_dynamic_string(&ds_execute_warnings, NULL, 0, 256);
  }

  /*
    Prepare the query
  */
  if (do_stmt_prepare(cn, query, query_len))
  {
    handle_error(command,  mysql_stmt_errno(stmt),
                 mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds);
    goto end;
  }

  /*
    Get the warnings from mysql_stmt_prepare and keep them in a
    separate string
  */
  if (!disable_warnings)
    append_warnings(&ds_prepare_warnings, mysql);

  /*
    No need to call mysql_stmt_bind_param() because we have no
    parameter markers.
  */

#if MYSQL_VERSION_ID >= 50000
  if (cursor_protocol_enabled)
  {
    /*
      Use cursor when retrieving result
    */
    ulong type= CURSOR_TYPE_READ_ONLY;
    if (mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type))
      die("mysql_stmt_attr_set(STMT_ATTR_CURSOR_TYPE) failed': %d %s",
          mysql_stmt_errno(stmt), mysql_stmt_error(stmt));
  }
#endif

  /*
    Execute the query
  */
  if (do_stmt_execute(cn))
  {
    handle_error(command, mysql_stmt_errno(stmt),
                 mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds);
    goto end;
  }

  /*
    When running in cursor_protocol get the warnings from execute here
    and keep them in a separate string for later.
  */
  if (cursor_protocol_enabled && !disable_warnings)
    append_warnings(&ds_execute_warnings, mysql);

  /*
    We instruct that we want to update the "max_length" field in
    mysql_stmt_store_result(), this is our only way to know how much
    buffer to allocate for result data
  */
  {
    my_bool one= 1;
    if (mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (void*) &one))
      die("mysql_stmt_attr_set(STMT_ATTR_UPDATE_MAX_LENGTH) failed': %d %s",
          mysql_stmt_errno(stmt), mysql_stmt_error(stmt));
  }

  /*
    If we got here the statement succeeded and was expected to do so,
    get data. Note that this can still give errors found during execution!
    Store the result of the query if if will return any fields
  */
  if (mysql_stmt_field_count(stmt) && mysql_stmt_store_result(stmt))
  {
    handle_error(command, mysql_stmt_errno(stmt),
                 mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds);
    goto end;
  }

  /* If we got here the statement was both executed and read successfully */
  handle_no_error(command);
  if (!disable_result_log)
  {
    /*
      Not all statements creates a result set. If there is one we can
      now create another normal result set that contains the meta
      data. This set can be handled almost like any other non prepared
      statement result set.
    */
    if ((res= mysql_stmt_result_metadata(stmt)) != NULL)
    {
      /* Take the column count from meta info */
      MYSQL_FIELD *fields= mysql_fetch_fields(res);
      uint num_fields= mysql_num_fields(res);

      if (display_metadata)
        append_metadata(ds, fields, num_fields);

      if (!display_result_vertically)
        append_table_headings(ds, fields, num_fields);

      append_stmt_result(ds, stmt, fields, num_fields);

      mysql_free_result(res);     /* Free normal result set with meta data */

      /*
        Normally, if there is a result set, we do not show warnings from the
        prepare phase. This is because some warnings are generated both during
        prepare and execute; this would generate different warning output
        between normal and ps-protocol test runs.

        The --enable_prepare_warnings command can be used to change this so
        that warnings from both the prepare and execute phase are shown.
      */
      if (!disable_warnings && !prepare_warnings_enabled)
        dynstr_set(&ds_prepare_warnings, NULL);
    }
    else
    {
      /*
	This is a query without resultset
      */
    }

    /*
      Fetch info before fetching warnings, since it will be reset
      otherwise.
    */
    if (!disable_info)
      append_info(ds, mysql_stmt_affected_rows(stmt), mysql_info(mysql));

    if (!disable_warnings)
    {
      /* Get the warnings from execute */

      /* Append warnings to ds - if there are any */
      if (append_warnings(&ds_execute_warnings, mysql) ||
          ds_execute_warnings.length ||
          ds_prepare_warnings.length ||
          ds_warnings->length)
      {
        dynstr_append_mem(ds, "Warnings:\n", 10);
        if (ds_warnings->length)
          dynstr_append_mem(ds, ds_warnings->str,
                            ds_warnings->length);
        if (ds_prepare_warnings.length)
          dynstr_append_mem(ds, ds_prepare_warnings.str,
                            ds_prepare_warnings.length);
        if (ds_execute_warnings.length)
          dynstr_append_mem(ds, ds_execute_warnings.str,
                            ds_execute_warnings.length);
      }
    }
  }

end:
  if (!disable_warnings)
  {
    dynstr_free(&ds_prepare_warnings);
    dynstr_free(&ds_execute_warnings);
  }

  /*
    We save the return code (mysql_stmt_errno(stmt)) from the last call sent
    to the server into the mysqltest builtin variable $mysql_errno. This
    variable then can be used from the test case itself.
  */

  var_set_errno(mysql_stmt_errno(stmt));

  revert_properties();

  /* Close the statement if reconnect, need new prepare */
  if (mysql->reconnect)
  {
    mysql_stmt_close(stmt);
    cn->stmt= NULL;
  }

  DBUG_VOID_RETURN;
}

Project: server

int query_get_string(MYSQL* mysql, const char* query,
                     int column, DYNAMIC_STRING* ds)
{
  MYSQL_RES *res= NULL;
  MYSQL_ROW row;

  if (mysql_query(mysql, query))
  {
    report_or_die("'%s' failed: %d %s", query,
                  mysql_errno(mysql), mysql_error(mysql));
    return 1;
  }
  if ((res= mysql_store_result(mysql)) == NULL)
  {
    report_or_die("Failed to store result: %d %s",
                  mysql_errno(mysql), mysql_error(mysql));
    return 1;
  }

  if ((row= mysql_fetch_row(res)) == NULL)
  {
    mysql_free_result(res);
    return 1;
  }
  init_dynamic_string(ds, (row[column] ? row[column] : "NULL"), ~0, 32);
  mysql_free_result(res);
  return 0;
}

Project: server

void do_system(struct st_command *command)
{
  DYNAMIC_STRING ds_cmd;
  DBUG_ENTER("do_system");

  if (strlen(command->first_argument) == 0)
  {
    report_or_die("Missing arguments to system, nothing to do!");
    return;
  }

  init_dynamic_string(&ds_cmd, 0, command->query_len + 64, 256);

  /* Eval the system command, thus replacing all environment variables */
  do_eval(&ds_cmd, command->first_argument, command->end, !is_windows);

#ifdef __WIN__
#ifndef USE_CYGWIN
   /* Replace /dev/null with NUL */
   while(replace(&ds_cmd, "/dev/null", 9, "NUL", 3) == 0)
     ;
#endif
#endif


  DBUG_PRINT("info", ("running system command '%s' as '%s'",
                      command->first_argument, ds_cmd.str));
  if (my_system(&ds_cmd))
  {
    if (command->abort_on_error)
      report_or_die("system command '%s' failed", command->first_argument);
    else
    {
      /* If ! abort_on_error, log message and continue */
      dynstr_append(&ds_res, "system command '");
      replace_dynstr_append(&ds_res, command->first_argument);
      dynstr_append(&ds_res, "' failed\n");
    }
  }

  command->last_argument= command->end;
  dynstr_free(&ds_cmd);
  DBUG_VOID_RETURN;
}

Project: server

void really_die(const char *msg)
{
  static int dying= 0;
  fflush(stdout);
  fprintf(stderr, "%s", msg);
  fflush(stderr);

  /*
    Protect against dying twice
    first time 'die' is called, try to write log files
    second time, just exit
  */
  if (dying)
    cleanup_and_exit(1);
  dying= 1;

  log_file.show_tail(opt_tail_lines);

  /*
    Help debugging by displaying any warnings that might have
    been produced prior to the error
  */
  if (cur_con && !cur_con->pending)
    show_warnings_before_error(cur_con->mysql);

  cleanup_and_exit(1);
}

Project: server

  void show_tail(uint lines) {
    DBUG_ENTER("LogFile::show_tail");

    if (!m_file || m_file == stdout)
      DBUG_VOID_RETURN;

    if (lines == 0)
      DBUG_VOID_RETURN;
    lines++;

    int show_offset= 0;
    char buf[256+1];                   /* + zero termination for DBUG_PRINT */
    size_t bytes;
    bool found_bof= false;

    /* Search backward in file until "lines" newline has been found */
    while (lines && !found_bof)
    {
      show_offset-= sizeof(buf)-1;
      while(fseek(m_file, show_offset, SEEK_END) != 0 && show_offset < 0)
      {
        found_bof= true;
        // Seeking before start of file
        show_offset++;
      }

      if ((bytes= fread(buf, 1, sizeof(buf)-1, m_file)) <= 0)
      {
	// ferror=0 will happen here if no queries executed yet
	if (ferror(m_file))
	  fprintf(stderr,
	          "Failed to read from '%s', errno: %d, feof:%d, ferror:%d\n",
	          m_file_name, errno, feof(m_file), ferror(m_file));
        DBUG_VOID_RETURN;
      }

      DBUG_PRINT("info", ("Read %zu bytes from file, buf: %.*s",
                          bytes, (int)bytes, buf));

      char* show_from= buf + bytes;
      while(show_from > buf && lines > 0 )
      {
        show_from--;
        if (*show_from == '\n')
          lines--;
      }
      if (show_from != buf)
      {
        // The last new line was found in this buf, adjust offset
        show_offset+= (show_from - buf) + 1;
        DBUG_PRINT("info", ("adjusted offset to %d", show_offset));
      }
      DBUG_PRINT("info", ("show_offset: %d", show_offset));
    }

    fprintf(stderr, "\nThe result from queries just before the failure was:\n");

    DBUG_PRINT("info", ("show_offset: %d", show_offset));
    if (!lines)
    {
      fprintf(stderr, "< snip >\n");

      if (fseek(m_file, show_offset, SEEK_END) != 0)
      {
        fprintf(stderr, "Failed to seek to position %d in '%s', errno: %d",
                show_offset, m_file_name, errno);
        DBUG_VOID_RETURN;
      }

    }
    else {
      DBUG_PRINT("info", ("Showing the whole file"));
      if (fseek(m_file, 0L, SEEK_SET) != 0)
      {
        fprintf(stderr, "Failed to seek to pos 0 in '%s', errno: %d",
                m_file_name, errno);
        DBUG_VOID_RETURN;
      }
    }

    while ((bytes= fread(buf, 1, sizeof(buf)-1, m_file)) > 0)
      if (bytes != fwrite(buf, 1, bytes, stderr))
        die("Failed to write to '%s', errno: %d",
            m_file_name, errno);

    if (!lines)
    {
      fprintf(stderr,
              "\nMore results from queries before failure can be found in %s\n",
              m_file_name);
    }
    fflush(stderr);

    DBUG_VOID_RETURN;
  }

Project: server

void do_wait_for_slave_to_stop(struct st_command *c __attribute__((unused)))
{
  static int SLAVE_POLL_INTERVAL= 300000;
  MYSQL* mysql = cur_con->mysql;
  for (;;)
  {
    MYSQL_RES *UNINIT_VAR(res);
    MYSQL_ROW row;
    int done;

    if (mysql_query(mysql,"show status like 'Slave_running'") ||
	!(res=mysql_store_result(mysql)))
      die("Query failed while probing slave for stop: %s",
	  mysql_error(mysql));
    if (!(row=mysql_fetch_row(res)) || !row[1])
    {
      mysql_free_result(res);
      die("Strange result from query while probing slave for stop");
    }
    done = !strcmp(row[1],"OFF");
    mysql_free_result(res);
    if (done)
      break;
    my_sleep(SLAVE_POLL_INTERVAL);
  }
  return;
}

Project: server

void var_set_query_get_value(struct st_command *command, VAR *var)
{
  long row_no;
  int col_no= -1;
  MYSQL_RES* res;
  MYSQL* mysql= cur_con->mysql;

  static DYNAMIC_STRING ds_query;
  static DYNAMIC_STRING ds_col;
  static DYNAMIC_STRING ds_row;
  const struct command_arg query_get_value_args[] = {
    {"query", ARG_STRING, TRUE, &ds_query, "Query to run"},
    {"column name", ARG_STRING, TRUE, &ds_col, "Name of column"},
    {"row number", ARG_STRING, TRUE, &ds_row, "Number for row"}
  };

  DBUG_ENTER("var_set_query_get_value");
  LINT_INIT(res);

  if (!mysql)
  {
    handle_no_active_connection(command, cur_con, &ds_res);
    DBUG_VOID_RETURN;
  }

  strip_parentheses(command);
  DBUG_PRINT("info", ("query: %s", command->query));
  check_command_args(command, command->first_argument, query_get_value_args,
                     sizeof(query_get_value_args)/sizeof(struct command_arg),
                     ',');

  DBUG_PRINT("info", ("query: %s", ds_query.str));
  DBUG_PRINT("info", ("col: %s", ds_col.str));

  /* Convert row number to int */
  if (!str2int(ds_row.str, 10, (long) 0, (long) INT_MAX, &row_no))
    die("Invalid row number: '%s'", ds_row.str);
  DBUG_PRINT("info", ("row: %s, row_no: %ld", ds_row.str, row_no));
  dynstr_free(&ds_row);

  /* Remove any surrounding "'s from the query - if there is any */
  if (strip_surrounding(ds_query.str, '"', '"'))
    die("Mismatched \"'s around query '%s'", ds_query.str);

  /* Run the query */
  if (mysql_real_query(mysql, ds_query.str, ds_query.length))
  {
    handle_error(curr_command, mysql_errno(mysql), mysql_error(mysql),
                 mysql_sqlstate(mysql), &ds_res);
    /* If error was acceptable, return empty string */
    dynstr_free(&ds_query);
    dynstr_free(&ds_col);
    eval_expr(var, "", 0);
    DBUG_VOID_RETURN;
  }

  if (!(res= mysql_store_result(mysql)))
  {
    report_or_die("Query '%s' didn't return a result set", ds_query.str);
    dynstr_free(&ds_query);
    dynstr_free(&ds_col);
    eval_expr(var, "", 0);
    return;
  }

  {
    /* Find column number from the given column name */
    uint i;
    uint num_fields= mysql_num_fields(res);
    MYSQL_FIELD *fields= mysql_fetch_fields(res);

    for (i= 0; i < num_fields; i++)
    {
      if (strcmp(fields[i].name, ds_col.str) == 0 &&
          strlen(fields[i].name) == ds_col.length)
      {
        col_no= i;
        break;
      }
    }
    if (col_no == -1)
    {
      mysql_free_result(res);
      report_or_die("Could not find column '%s' in the result of '%s'",
                    ds_col.str, ds_query.str);
      dynstr_free(&ds_query);
      dynstr_free(&ds_col);
      return;
    }
    DBUG_PRINT("info", ("Found column %d with name '%s'",
                        i, fields[i].name));
  }
  dynstr_free(&ds_col);

  {
    /* Get the value */
    MYSQL_ROW row;
    long rows= 0;
    const char* value= "No such row";

    while ((row= mysql_fetch_row(res)))
    {
      if (++rows == row_no)
      {

        DBUG_PRINT("info", ("At row %ld, column %d is '%s'",
                            row_no, col_no, row[col_no]));
        /* Found the row to get */
        if (row[col_no])
          value= row[col_no];
        else
          value= "NULL";

        break;
      }
    }
    eval_expr(var, value, 0, false, false);
  }
  dynstr_free(&ds_query);
  mysql_free_result(res);

  DBUG_VOID_RETURN;
}

Project: server

void timer_output(void)
{
  if (timer_file)
  {
    char buf[32], *end;
    ulonglong timer= timer_now() - timer_start;
    end= longlong10_to_str(timer, buf, 10);
    str_to_file(timer_file,buf, (int) (end-buf));
    /* Timer has been written to the file, don't use it anymore */
    timer_file= 0;
  }
}

Project: server

void do_perl(struct st_command *command)
{
  int error;
  File fd;
  FILE *res_file;
  char buf[FN_REFLEN];
  char temp_file_path[FN_REFLEN];
  static DYNAMIC_STRING ds_script;
  static DYNAMIC_STRING ds_delimiter;
  const struct command_arg perl_args[] = {
    { "delimiter", ARG_STRING, FALSE, &ds_delimiter, "Delimiter to read until" }
  };
  DBUG_ENTER("do_perl");

  check_command_args(command,
                     command->first_argument,
                     perl_args,
                     sizeof(perl_args)/sizeof(struct command_arg),
                     ' ');

  ds_script= command->content;
  /* If it hasn't been done already by a loop iteration, fill it in */
  if (! ds_script.str)
  {
    /* If no delimiter was provided, use EOF */
    if (ds_delimiter.length == 0)
      dynstr_set(&ds_delimiter, "EOF");

    init_dynamic_string(&ds_script, "", 1024, 1024);
    read_until_delimiter(&ds_script, &ds_delimiter);
    command->content= ds_script;
  }

  /* This function could be called even if "false", so check before doing */
  if (cur_block->ok)
  {
    DBUG_PRINT("info", ("Executing perl: %s", ds_script.str));

    /* Create temporary file name */
    if ((fd= create_temp_file(temp_file_path, getenv("MYSQLTEST_VARDIR"),
                              "tmp", O_CREAT | O_SHARE | O_RDWR,
                              MYF(MY_WME))) < 0)
      die("Failed to create temporary file for perl command");
    my_close(fd, MYF(0));

    str_to_file(temp_file_path, ds_script.str, ds_script.length);

    /* Format the "perl <filename>" command */
    my_snprintf(buf, sizeof(buf), "perl %s", temp_file_path);

    if (!(res_file= popen(buf, "r")))
    {
      if (command->abort_on_error)
        die("popen(\"%s\", \"r\") failed", buf);
      dynstr_free(&ds_delimiter);
      return;
    }

    while (fgets(buf, sizeof(buf), res_file))
    {
      if (disable_result_log)
      {
	buf[strlen(buf)-1]=0;
	DBUG_PRINT("exec_result",("%s", buf));
      }
      else
      {
	replace_dynstr_append(&ds_res, buf);
      }
    }
    error= pclose(res_file);

    /* Remove the temporary file, but keep it if perl failed */
    if (!error)
      my_delete(temp_file_path, MYF(MY_WME));

    /* Check for error code that indicates perl could not be started */
    int exstat= WEXITSTATUS(error);
#ifdef __WIN__
    if (exstat == 1)
      /* Text must begin 'perl not found' as mtr looks for it */
      abort_not_supported_test("perl not found in path or did not start");
#else
    if (exstat == 127)
      abort_not_supported_test("perl not found in path");
#endif
    else
      handle_command_error(command, exstat, my_errno);
  }
  dynstr_free(&ds_delimiter);
  DBUG_VOID_RETURN;
}

Project: server

void check_result()
{
  const char *mess= 0;

  DBUG_ENTER("check_result");
  DBUG_ASSERT(result_file_name);
  DBUG_PRINT("enter", ("result_file_name: %s", result_file_name));

  switch (compare_files(log_file.file_name(), result_file_name)) {
  case RESULT_OK:
    if (!error_count)
      break; /* ok */
    mess= "Got errors while running test";
    /* Fallthrough */
  case RESULT_LENGTH_MISMATCH:
    if (!mess)
      mess= "Result length mismatch\n";
    /* Fallthrough */
  case RESULT_CONTENT_MISMATCH:
  {
    /*
      Result mismatched, dump results to .reject file
      and then show the diff
    */
    char reject_file[FN_REFLEN];
    size_t reject_length;

    if (!mess)
      mess= "Result content mismatch\n";

    dirname_part(reject_file, result_file_name, &reject_length);

    if (access(reject_file, W_OK) == 0)
    {
      /* Result file directory is writable, save reject file there */
      fn_format(reject_file, result_file_name, "",
                ".reject", MY_REPLACE_EXT);
    }
    else
    {
      /* Put reject file in opt_logdir */
      fn_format(reject_file, result_file_name, opt_logdir,
                ".reject", MY_REPLACE_DIR | MY_REPLACE_EXT);
    }

    if (my_copy(log_file.file_name(), reject_file, MYF(0)) != 0)
      die("Failed to copy '%s' to '%s', errno: %d",
          log_file.file_name(), reject_file, errno);

    show_diff(NULL, result_file_name, reject_file);
    die("%s", mess);
    break;
  }
  default: /* impossible */
    die("Unknown error code from dyn_string_cmp()");
  }

  DBUG_VOID_RETURN;
}

Project: server

static void do_list_files(struct st_command *command)
{
  int error;
  static DYNAMIC_STRING ds_dirname;
  static DYNAMIC_STRING ds_wild;
  const struct command_arg list_files_args[] = {
    {"dirname", ARG_STRING, TRUE, &ds_dirname, "Directory to list"},
    {"file", ARG_STRING, FALSE, &ds_wild, "Filename (incl. wildcard)"}
  };
  DBUG_ENTER("do_list_files");
  command->used_replace= 1;

  check_command_args(command, command->first_argument,
                     list_files_args,
                     sizeof(list_files_args)/sizeof(struct command_arg), ' ');

  error= get_list_files(&ds_res, &ds_dirname, &ds_wild);
  handle_command_error(command, error, my_errno);
  dynstr_free(&ds_dirname);
  dynstr_free(&ds_wild);
  DBUG_VOID_RETURN;
}

Project: server

void run_query_normal(struct st_connection *cn, struct st_command *command,
                      int flags, char *query, int query_len,
                      DYNAMIC_STRING *ds, DYNAMIC_STRING *ds_warnings)
{
  MYSQL_RES *res= 0;
  MYSQL *mysql= cn->mysql;
  int err= 0, counter= 0;
  DBUG_ENTER("run_query_normal");
  DBUG_PRINT("enter",("flags: %d", flags));
  DBUG_PRINT("enter", ("query: '%-.60s'", query));

  if (!mysql)
  {
    handle_no_active_connection(command, cn, ds);
    DBUG_VOID_RETURN;
  }

  if (flags & QUERY_SEND_FLAG)
  {
    /*
      Send the query
    */
    if (do_send_query(cn, query, query_len))
    {
      handle_error(command, mysql_errno(mysql), mysql_error(mysql),
		   mysql_sqlstate(mysql), ds);
      goto end;
    }
  }
  if (!(flags & QUERY_REAP_FLAG))
  {
    cn->pending= TRUE;
    DBUG_VOID_RETURN;
  }
  
  do
  {
    /*
      When  on first result set, call mysql_read_query_result to retrieve
      answer to the query sent earlier
    */
    if ((counter==0) && do_read_query_result(cn))
    {
      /* we've failed to collect the result set */
      cn->pending= TRUE;
      handle_error(command, mysql_errno(mysql), mysql_error(mysql),
		   mysql_sqlstate(mysql), ds);
      goto end;

    }

    /*
      Store the result of the query if it will return any fields
    */
    if (mysql_field_count(mysql) && ((res= mysql_store_result(mysql)) == 0))
    {
      handle_error(command, mysql_errno(mysql), mysql_error(mysql),
		   mysql_sqlstate(mysql), ds);
      goto end;
    }

    if (!disable_result_log)
    {
      if (res)
      {
	MYSQL_FIELD *fields= mysql_fetch_fields(res);
	uint num_fields= mysql_num_fields(res);

	if (display_metadata)
          append_metadata(ds, fields, num_fields);

	if (!display_result_vertically)
	  append_table_headings(ds, fields, num_fields);

	append_result(ds, res);
      }

      /*
        Need to call mysql_affected_rows() before the "new"
        query to find the warnings.
      */
      if (!disable_info)
	append_info(ds, mysql_affected_rows(mysql), mysql_info(mysql));

      /*
        Add all warnings to the result. We can't do this if we are in
        the middle of processing results from multi-statement, because
        this will break protocol.
      */
      if (!disable_warnings && !mysql_more_results(mysql))
      {
	if (append_warnings(ds_warnings, mysql) || ds_warnings->length)
	{
	  dynstr_append_mem(ds, "Warnings:\n", 10);
	  dynstr_append_mem(ds, ds_warnings->str, ds_warnings->length);
	}
      }
    }

    if (res)
    {
      mysql_free_result(res);
      res= 0;
    }
    counter++;
  } while (!(err= mysql_next_result(mysql)));
  if (err > 0)
  {
    /* We got an error from mysql_next_result, maybe expected */
    handle_error(command, mysql_errno(mysql), mysql_error(mysql),
		 mysql_sqlstate(mysql), ds);
    goto end;
  }
  DBUG_ASSERT(err == -1); /* Successful and there are no more results */

  /* If we come here the query is both executed and read successfully */
  handle_no_error(command);
  revert_properties();

end:

  cn->pending= FALSE;
  /*
    We save the return code (mysql_errno(mysql)) from the last call sent
    to the server into the mysqltest builtin variable $mysql_errno. This
    variable then can be used from the test case itself.
  */
  var_set_errno(mysql_errno(mysql));
  DBUG_VOID_RETURN;
}

Project: server

int do_sleep(struct st_command *command, my_bool real_sleep)
{
  int error= 0;
  char *sleep_start, *sleep_end;
  double sleep_val;
  char *p;
  static DYNAMIC_STRING ds_sleep;
  const struct command_arg sleep_args[] = {
    { "sleep_delay", ARG_STRING, TRUE, &ds_sleep, "Number of seconds to sleep." }
  };
  check_command_args(command, command->first_argument, sleep_args,
                     sizeof(sleep_args)/sizeof(struct command_arg),
                     ' ');

  p= ds_sleep.str;
  sleep_end= ds_sleep.str + ds_sleep.length;
  while (my_isspace(charset_info, *p))
    p++;
  if (!*p)
    die("Missing argument to %.*s", command->first_word_len,
        command->query);
  sleep_start= p;
  /* Check that arg starts with a digit, not handled by my_strtod */
  if (!my_isdigit(charset_info, *sleep_start))
    die("Invalid argument to %.*s \"%s\"", command->first_word_len,
        command->query, sleep_start);
  sleep_val= my_strtod(sleep_start, &sleep_end, &error);
  check_eol_junk_line(sleep_end);
  if (error)
    die("Invalid argument to %.*s \"%s\"", command->first_word_len,
        command->query, command->first_argument);
  dynstr_free(&ds_sleep);

  /* Fixed sleep time selected by --sleep option */
  if (opt_sleep >= 0 && !real_sleep)
    sleep_val= opt_sleep;

  DBUG_PRINT("info", ("sleep_val: %f", sleep_val));
  if (sleep_val)
    my_sleep((ulong) (sleep_val * 1000000L));
  return 0;
}

Project: server

static int do_stmt_execute(struct st_connection *cn)
{
  /* The cn->stmt is already set. */
  if (!cn->has_thread)
    return mysql_stmt_execute(cn->stmt);
  signal_connection_thd(cn, EMB_EXECUTE_STMT);
  wait_query_thread_done(cn);
  return cn->result;
}

Project: server

static void make_error_message(char *buf, size_t len, const char *fmt, va_list args)
{
  char *s= buf, *end= buf + len;
  s+= my_snprintf(s, end - s, "mysqltest: ");
  if (cur_file && cur_file != file_stack)
  {
    s+= my_snprintf(s, end - s, "In included file \"%s\": \n",
                    cur_file->file_name);
    s+= print_file_stack(s, end);
  }
  
  if (start_lineno > 0)
    s+= my_snprintf(s, end -s, "At line %u: ", start_lineno);
  if (!fmt)
    fmt= "unknown error";

  s+= my_vsnprintf(s, end - s, fmt, args);
  s+= my_snprintf(s, end -s, "\n", start_lineno);
}

Project: server

int util_query(MYSQL* org_mysql, const char* query){

  MYSQL* mysql;
  DBUG_ENTER("util_query");

  if(!(mysql= cur_con->util_mysql))
  {
    DBUG_PRINT("info", ("Creating util_mysql"));
    if (!(mysql= mysql_init(mysql)))
      die("Failed in mysql_init()");

    if (opt_connect_timeout)
      mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT,
                    (void *) &opt_connect_timeout);

    /* enable local infile, in non-binary builds often disabled by default */
    mysql_options(mysql, MYSQL_OPT_LOCAL_INFILE, 0);
    mysql_options(mysql, MYSQL_OPT_NONBLOCK, 0);
    safe_connect(mysql, "util", org_mysql->host, org_mysql->user,
                 org_mysql->passwd, org_mysql->db, org_mysql->port,
                 org_mysql->unix_socket);

    cur_con->util_mysql= mysql;
  }

  int ret= mysql_query(mysql, query);
  DBUG_RETURN(ret);
}

Project: server

}

void dynstr_append_sorted(DYNAMIC_STRING* ds, DYNAMIC_STRING *ds_input,
                          bool keep_header)
{
  unsigned i;
  char *start= ds_input->str;
  DYNAMIC_ARRAY lines;
  DBUG_ENTER("dynstr_append_sorted");

  if (!*start)
    DBUG_VOID_RETURN;  /* No input */

  my_init_dynamic_array(&lines, sizeof(const char*), 32, 32);

  if (keep_header)
  {
    /* First line is result header, skip past it */
    while (*start && *start != '\n')
      start++;
    start++; /* Skip past \n */
    dynstr_append_mem(ds, ds_input->str, start - ds_input->str);
  }

  /* Insert line(s) in array */
  while (*start)
  {
    char* line_end= (char*)start;

    /* Find end of line */
    while (*line_end && *line_end != '\n')
      line_end++;
    *line_end= 0;

    /* Insert pointer to the line in array */
    if (insert_dynamic(&lines, (uchar*) &start))
      die("Out of memory inserting lines to sort");

    start= line_end+1;
  }

  /* Sort array */
  qsort(lines.buffer, lines.elements,
        sizeof(char**), (qsort_cmp)comp_lines);

  /* Create new result */
  for (i= 0; i < lines.elements ; i++)
  {
    const char **line= dynamic_element(&lines, i, const char**);
    dynstr_append(ds, *line);
    dynstr_append(ds, "\n");
  }

  delete_dynamic(&lines);

Project: server

int read_line(char *buf, int size)
{
  char c, UNINIT_VAR(last_quote), last_char= 0;
  char *p= buf, *buf_end= buf + size - 1;
  int skip_char= 0;
  my_bool have_slash= FALSE;
  
  enum {R_NORMAL, R_Q, R_SLASH_IN_Q,
        R_COMMENT, R_LINE_START} state= R_LINE_START;
  DBUG_ENTER("read_line");

  start_lineno= cur_file->lineno;
  DBUG_PRINT("info", ("Starting to read at lineno: %d", start_lineno));
  for (; p < buf_end ;)
  {
    skip_char= 0;
    c= my_getc(cur_file->file);
    if (feof(cur_file->file))
    {
  found_eof:
      if (cur_file->file != stdin)
      {
	fclose(cur_file->file);
        cur_file->file= 0;
      }
      my_free(cur_file->file_name);
      cur_file->file_name= 0;
      if (cur_file == file_stack)
      {
        /* We're back at the first file, check if
           all { have matching }
        */
        if (cur_block != block_stack)
          die("Missing end of block");

        *p= 0;
        DBUG_PRINT("info", ("end of file at line %d", cur_file->lineno));
        DBUG_RETURN(1);
      }
      cur_file--;
      start_lineno= cur_file->lineno;
      continue;
    }

    if (c == '\n')
    {
      /* Line counting is independent of state */
      cur_file->lineno++;

      /* Convert cr/lf to lf */
      if (p != buf && *(p-1) == '\r')
        p--;
    }

    switch(state) {
    case R_NORMAL:
      if (end_of_query(c))
      {
	*p= 0;
        DBUG_PRINT("exit", ("Found delimiter '%s' at line %d",
                            delimiter, cur_file->lineno));
	DBUG_RETURN(0);
      }
      else if ((c == '{' &&
                (!my_strnncoll_simple(charset_info, (const uchar*) "while", 5,
                                      (uchar*) buf, min(5, p - buf), 0) ||
                 !my_strnncoll_simple(charset_info, (const uchar*) "if", 2,
                                      (uchar*) buf, min(2, p - buf), 0))))
      {
        /* Only if and while commands can be terminated by { */
        *p++= c;
	*p= 0;
        DBUG_PRINT("exit", ("Found '{' indicating start of block at line %d",
                            cur_file->lineno));
	DBUG_RETURN(0);
      }
      else if (c == '\'' || c == '"' || c == '`')
      {
        if (! have_slash) 
        {
	  last_quote= c;
	  state= R_Q;
	}
      }
      have_slash= (c == '\\');
      break;

    case R_COMMENT:
      if (c == '\n')
      {
        /* Comments are terminated by newline */
	*p= 0;
        DBUG_PRINT("exit", ("Found newline in comment at line: %d",
                            cur_file->lineno));
	DBUG_RETURN(0);
      }
      break;

    case R_LINE_START:
      if (c == '#' || c == '-')
      {
        /* A # or - in the first position of the line - this is a comment */
	state = R_COMMENT;
      }
      else if (my_isspace(charset_info, c))
      {
	if (c == '\n')
        {
          if (last_char == '\n')
          {
            /* Two new lines in a row, return empty line */
            DBUG_PRINT("info", ("Found two new lines in a row"));
            *p++= c;
            *p= 0;
            DBUG_RETURN(0);
          }

          /* Query hasn't started yet */
	  start_lineno= cur_file->lineno;
          DBUG_PRINT("info", ("Query hasn't started yet, start_lineno: %d",
                              start_lineno));
        }

        /* Skip all space at begining of line */
	skip_char= 1;
      }
      else if (end_of_query(c))
      {
	*p= 0;
        DBUG_PRINT("exit", ("Found delimiter '%s' at line: %d",
                            delimiter, cur_file->lineno));
	DBUG_RETURN(0);
      }
      else if (c == '}')
      {
        /* A "}" need to be by itself in the begining of a line to terminate */
        *p++= c;
	*p= 0;
        DBUG_PRINT("exit", ("Found '}' in begining of a line at line: %d",
                            cur_file->lineno));
	DBUG_RETURN(0);
      }
      else if (c == '\'' || c == '"' || c == '`')
      {
        last_quote= c;
	state= R_Q;
      }
      else
	state= R_NORMAL;
      break;

    case R_Q:
      if (c == last_quote)
	state= R_NORMAL;
      else if (c == '\\')
	state= R_SLASH_IN_Q;
      break;

    case R_SLASH_IN_Q:
      state= R_Q;
      break;

    }

    last_char= c;

    if (!skip_char)
    {
      /* Could be a multibyte character */
      /* This code is based on the code in "sql_load.cc" */
#ifdef USE_MB
      int charlen = my_mbcharlen(charset_info, (unsigned char) c);
      /* We give up if multibyte character is started but not */
      /* completed before we pass buf_end */
      if ((charlen > 1) && (p + charlen) <= buf_end)
      {
	int i;
	char* mb_start = p;

	*p++ = c;

	for (i= 1; i < charlen; i++)
	{
	  c= my_getc(cur_file->file);
	  if (feof(cur_file->file))
	    goto found_eof;
	  *p++ = c;
	}
	if (! my_ismbchar(charset_info, mb_start, p))
	{
	  /* It was not a multiline char, push back the characters */
	  /* We leave first 'c', i.e. pretend it was a normal char */
	  while (p-1 > mb_start)
	    my_ungetc(*--p);
	}
      }
      else
#endif
	*p++= c;
    }
  }
  die("The input buffer is too small for this query.x\n"      \
      "check your query or increase MAX_QUERY and recompile");
  DBUG_RETURN(0);
}

Project: server

const char *get_errname_from_code (uint error_code, st_error *e)
{
   DBUG_ENTER("get_errname_from_code");
   DBUG_PRINT("enter", ("error_code: %d", error_code));

   if (! error_code)
   {
     DBUG_RETURN("");
   }
   for (; e->name; e++)
   {
     if (e->code == error_code)
     {
       DBUG_RETURN(e->name);
     }
   }
   /* Apparently, errors without known names may occur */
   DBUG_RETURN(unknown_error);
}

Project: server

void do_copy_file(struct st_command *command)
{
  int error;
  static DYNAMIC_STRING ds_from_file;
  static DYNAMIC_STRING ds_to_file;
  const struct command_arg copy_file_args[] = {
    { "from_file", ARG_STRING, TRUE, &ds_from_file, "Filename to copy from" },
    { "to_file", ARG_STRING, TRUE, &ds_to_file, "Filename to copy to" }
  };
  DBUG_ENTER("do_copy_file");

  check_command_args(command, command->first_argument,
                     copy_file_args,
                     sizeof(copy_file_args)/sizeof(struct command_arg),
                     ' ');

  DBUG_PRINT("info", ("Copy %s to %s", ds_from_file.str, ds_to_file.str));
  /* MY_HOLD_ORIGINAL_MODES prevents attempts to chown the file */
  error= (my_copy(ds_from_file.str, ds_to_file.str,
                  MYF(MY_DONT_OVERWRITE_FILE | MY_WME | MY_HOLD_ORIGINAL_MODES)) != 0);
  handle_command_error(command, error, my_errno);
  dynstr_free(&ds_from_file);
  dynstr_free(&ds_to_file);
  DBUG_VOID_RETURN;
}

Project: server

void append_stmt_result(DYNAMIC_STRING *ds, MYSQL_STMT *stmt,
                        MYSQL_FIELD *fields, uint num_fields)
{
  MYSQL_BIND *my_bind;
  my_bool *is_null;
  ulong *length;
  uint i;
  int error;

  /* Allocate array with bind structs, lengths and NULL flags */
  my_bind= (MYSQL_BIND*) my_malloc(num_fields * sizeof(MYSQL_BIND),
				MYF(MY_WME | MY_FAE | MY_ZEROFILL));
  length= (ulong*) my_malloc(num_fields * sizeof(ulong),
			     MYF(MY_WME | MY_FAE));
  is_null= (my_bool*) my_malloc(num_fields * sizeof(my_bool),
				MYF(MY_WME | MY_FAE));

  /* Allocate data for the result of each field */
  for (i= 0; i < num_fields; i++)
  {
    uint max_length= fields[i].max_length + 1;
    my_bind[i].buffer_type= MYSQL_TYPE_STRING;
    my_bind[i].buffer= my_malloc(max_length, MYF(MY_WME | MY_FAE));
    my_bind[i].buffer_length= max_length;
    my_bind[i].is_null= &is_null[i];
    my_bind[i].length= &length[i];

    DBUG_PRINT("bind", ("col[%d]: buffer_type: %d, buffer_length: %lu",
			i, my_bind[i].buffer_type, my_bind[i].buffer_length));
  }

  if (mysql_stmt_bind_result(stmt, my_bind))
    die("mysql_stmt_bind_result failed: %d: %s",
	mysql_stmt_errno(stmt), mysql_stmt_error(stmt));

  while ((error=mysql_stmt_fetch(stmt)) == 0)
  {
    for (i= 0; i < num_fields; i++)
      append_field(ds, i, &fields[i], (char*)my_bind[i].buffer,
                   *my_bind[i].length, *my_bind[i].is_null);
    if (!display_result_vertically)
      dynstr_append_mem(ds, "\n", 1);
  }

  if (error != MYSQL_NO_DATA)
    die("mysql_fetch didn't end with MYSQL_NO_DATA from statement: "
        "error: %d", error);
  if (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
    die("mysql_fetch didn't end with MYSQL_NO_DATA from statement: %d %s",
	mysql_stmt_errno(stmt), mysql_stmt_error(stmt));

  for (i= 0; i < num_fields; i++)
  {
    /* Free data for output */
    my_free(my_bind[i].buffer);
  }
  /* Free array with bind structs, lengths and NULL flags */
  my_free(my_bind);
  my_free(length);
  my_free(is_null);
}

Project: server

void do_block(enum block_cmd cmd, struct st_command* command)
{
  char *p= command->first_argument;
  const char *expr_start, *expr_end;
  VAR v;
  const char *cmd_name= (cmd == cmd_while ? "while" : "if");
  my_bool not_expr= FALSE;
  DBUG_ENTER("do_block");
  DBUG_PRINT("enter", ("%s", cmd_name));

  /* Check stack overflow */
  if (cur_block == block_stack_end)
    die("Nesting too deeply");

  /* Set way to find outer block again, increase line counter */
  cur_block->line= parser.current_line++;

  /* If this block is ignored */
  if (!cur_block->ok)
  {
    /* Inner block should be ignored too */
    cur_block++;
    cur_block->cmd= cmd;
    cur_block->ok= FALSE;
    cur_block->delim[0]= '\0';
    DBUG_VOID_RETURN;
  }

  /* Parse and evaluate test expression */
  expr_start= strchr(p, '(');
  if (!expr_start++)
    die("missing '(' in %s", cmd_name);

  while (my_isspace(charset_info, *expr_start))
    expr_start++;
  
  /* Check for !<expr> */
  if (*expr_start == '!')
  {
    not_expr= TRUE;
    expr_start++; /* Step past the '!', then any whitespace */
    while (*expr_start && my_isspace(charset_info, *expr_start))
      expr_start++;
  }
  /* Find ending ')' */
  expr_end= strrchr(expr_start, ')');
  if (!expr_end)
    die("missing ')' in %s", cmd_name);
  p= (char*)expr_end+1;

  while (*p && my_isspace(charset_info, *p))
    p++;
  if (*p && *p != '{')
    die("Missing '{' after %s. Found \"%s\"", cmd_name, p);

  var_init(&v,0,0,0,0);

  /* If expression starts with a variable, it may be a compare condition */

  if (*expr_start == '$')
  {
    const char *curr_ptr= expr_end;
    eval_expr(&v, expr_start, &curr_ptr, true);
    while (my_isspace(charset_info, *++curr_ptr))
    {}
    /* If there was nothing past the variable, skip condition part */
    if (curr_ptr == expr_end)
      goto NO_COMPARE;

    enum block_op operand= find_operand(curr_ptr);
    if (operand == ILLEG_OP)
      die("Found junk '%.*s' after $variable in condition",
          (int)(expr_end - curr_ptr), curr_ptr);

    /* We could silently allow this, but may be confusing */
    if (not_expr)
      die("Negation and comparison should not be combined, please rewrite");
    
    /* Skip the 1 or 2 chars of the operand, then white space */
    if (operand == LT_OP || operand == GT_OP)
    {
      curr_ptr++;
    }
    else
    {
      curr_ptr+= 2;
    }
    while (my_isspace(charset_info, *curr_ptr))
      curr_ptr++;
    if (curr_ptr == expr_end)
      die("Missing right operand in comparison");

    /* Strip off trailing white space */
    while (my_isspace(charset_info, expr_end[-1]))
      expr_end--;
    /* strip off ' or " around the string */
    if (*curr_ptr == '\'' || *curr_ptr == '"')
    {
      if (expr_end[-1] != *curr_ptr)
        die("Unterminated string value");
      curr_ptr++;
      expr_end--;
    }
    VAR v2;
    var_init(&v2,0,0,0,0);
    eval_expr(&v2, curr_ptr, &expr_end);

    if ((operand!=EQ_OP && operand!=NE_OP) && ! (v.is_int && v2.is_int))
      die("Only == and != are supported for string values");

    /* Now we overwrite the first variable with 0 or 1 (for false or true) */

    switch (operand)
    {
    case EQ_OP:
      if (v.is_int)
        v.int_val= (v2.is_int && v2.int_val == v.int_val);
      else
        v.int_val= !strcmp (v.str_val, v2.str_val);
      break;
      
    case NE_OP:
      if (v.is_int)
        v.int_val= ! (v2.is_int && v2.int_val == v.int_val);
      else
        v.int_val= (strcmp (v.str_val, v2.str_val) != 0);
      break;

    case LT_OP:
      v.int_val= (v.int_val < v2.int_val);
      break;
    case LE_OP:
      v.int_val= (v.int_val <= v2.int_val);
      break;
    case GT_OP:
      v.int_val= (v.int_val > v2.int_val);
      break;
    case GE_OP:
      v.int_val= (v.int_val >= v2.int_val);
      break;
    case ILLEG_OP:
      die("Impossible operator, this cannot happen");
    }

    v.is_int= TRUE;
    var_free(&v2);
  } else
  {
    if (*expr_start != '`' && ! my_isdigit(charset_info, *expr_start))
      die("Expression in if/while must beging with $, ` or a number");
    eval_expr(&v, expr_start, &expr_end);
  }

 NO_COMPARE:
  /* Define inner block */
  cur_block++;
  cur_block->cmd= cmd;
  if (v.is_int)
  {
    cur_block->ok= (v.int_val != 0);
  } else
  /* Any non-empty string which does not begin with 0 is also TRUE */
  {
    p= v.str_val;
    /* First skip any leading white space or unary -+ */
    while (*p && ((my_isspace(charset_info, *p) || *p == '-' || *p == '+')))
      p++;

    cur_block->ok= (*p && *p != '0') ? TRUE : FALSE;
  }
  
  if (not_expr)
    cur_block->ok = !cur_block->ok;

  if (cur_block->ok) 
  {
    cur_block->delim[0]= '\0';
  } else
  {
    /* Remember "old" delimiter if entering a false if block */
    strcpy (cur_block->delim, delimiter);
  }
  
  DBUG_PRINT("info", ("OK: %d", cur_block->ok));

  var_free(&v);
  DBUG_VOID_RETURN;
}

Project: server

  void write(DYNAMIC_STRING* ds)
  {
    DBUG_ENTER("LogFile::write");
    DBUG_ASSERT(m_file);

    if (ds->length == 0)
      DBUG_VOID_RETURN;
    DBUG_ASSERT(ds->str);

#ifdef EXTRA_DEBUG
    DBUG_PRINT("QQ", ("str: %*s", (int) ds->length, ds->str));
#endif

    if (fwrite(ds->str, 1, ds->length, m_file) != ds->length)
      die("Failed to write %lu bytes to '%s', errno: %d",
          (unsigned long)ds->length, m_file_name, errno);
    m_bytes_written+= ds->length;
    DBUG_VOID_RETURN;
  }

Project: server

static void cleanup_and_exit(int exit_code)
{
  free_used_memory();

  /* Only call mysql_server_end if mysql_server_init has been called */
  if (server_initialized)
    mysql_server_end();

  /*
    mysqltest is fundamentally written in a way that makes impossible
    to free all memory before exit (consider memory allocated
    for frame local DYNAMIC_STRING's and die() invoked down the stack.

    We close stderr here to stop unavoidable safemalloc reports
    from polluting the output.
  */
  fclose(stderr);

  my_end(my_end_arg);

  if (!silent) {
    switch (exit_code) {
    case 1:
      printf("not ok\n");
      break;
    case 0:
      printf("ok\n");
      break;
    case 62:
      printf("skipped\n");
    break;
    default:
      printf("unknown exit code: %d\n", exit_code);
      DBUG_ASSERT(0);
    }
  }

  sf_leaking_memory= 0; /* all memory should be freed by now */
  exit(exit_code);
}

Project: server

void abort_not_supported_test(const char *fmt, ...)
{
  va_list args;
  DBUG_ENTER("abort_not_supported_test");

  /* Print include filestack */
  fflush(stdout);
  fprintf(stderr, "The test '%s' is not supported by this installation\n",
          file_stack->file_name);
  fprintf(stderr, "Detected in file %s at line %d\n",
          cur_file->file_name, cur_file->lineno);

  char buff[DIE_BUFF_SIZE];
  print_file_stack(buff, buff + sizeof(buff));
  fprintf(stderr, "%s", buff);

  /* Print error message */
  va_start(args, fmt);
  if (fmt)
  {
    fprintf(stderr, "reason: ");
    vfprintf(stderr, fmt, args);
    fprintf(stderr, "\n");
    fflush(stderr);
  }
  va_end(args);

  cleanup_and_exit(62);
}

Project: server

void mark_progress(struct st_command* command __attribute__((unused)),
                   int line)
{
  static ulonglong progress_start= 0; // < Beware
  DYNAMIC_STRING ds_progress;

  char buf[32], *end;
  ulonglong timer= timer_now();
  if (!progress_start)
    progress_start= timer;
  timer-= progress_start;

  if (init_dynamic_string(&ds_progress, "", 256, 256))
    die("Out of memory");

  /* Milliseconds since start */
  end= longlong10_to_str(timer, buf, 10);
  dynstr_append_mem(&ds_progress, buf, (int)(end-buf));
  dynstr_append_mem(&ds_progress, "\t", 1);

  /* Parser line number */
  end= int10_to_str(line, buf, 10);
  dynstr_append_mem(&ds_progress, buf, (int)(end-buf));
  dynstr_append_mem(&ds_progress, "\t", 1);

  /* Filename */
  dynstr_append(&ds_progress, cur_file->file_name);
  dynstr_append_mem(&ds_progress, ":", 1);

  /* Line in file */
  end= int10_to_str(cur_file->lineno, buf, 10);
  dynstr_append_mem(&ds_progress, buf, (int)(end-buf));


  dynstr_append_mem(&ds_progress, "\n", 1);

  progress_file.write(&ds_progress);

  dynstr_free(&ds_progress);

}

Project: server

static int do_read_query_result(struct st_connection *cn)
{
  DBUG_ASSERT(cn->has_thread);
  wait_query_thread_done(cn);
  if (cn->result)
    goto exit_func;

  signal_connection_thd(cn, EMB_READ_QUERY_RESULT);
  wait_query_thread_done(cn);

exit_func:
  return cn->result;
}

Project: server

int compare_files2(File fd1, const char* filename2)
{
  int error= RESULT_OK;
  File fd2;
  size_t fd1_length, fd2_length;
  DYNAMIC_STRING fd1_result, fd2_result;

  if ((fd2= my_open(filename2, O_RDONLY, MYF(0))) < 0)
  {
    my_close(fd1, MYF(0));
    die("Failed to open second file: '%s'", filename2);
  }

  fd1_length= (size_t) my_seek(fd1, 0, SEEK_END, MYF(0));
  fd2_length= (size_t) my_seek(fd2, 0, SEEK_END, MYF(0));

  if (init_dynamic_string(&fd1_result, 0, fd1_length, 0) ||
      init_dynamic_string(&fd2_result, 0, fd2_length, 0))
    die("Out of memory when allocating data for result");

  fd1_result.length= fd1_length;
  fd2_result.length= fd2_length;

  (void) my_seek(fd1, 0, SEEK_SET, MYF(0));
  (void) my_seek(fd2, 0, SEEK_SET, MYF(0));
  if (my_read(fd1, (uchar*) fd1_result.str, fd1_length, MYF(MY_WME | MY_NABP)))
    die("Error when reading data from result file");
  if (my_read(fd2, (uchar*) fd2_result.str, fd2_length, MYF(MY_WME | MY_NABP)))
    die("Error when reading data from result file");

  if (global_subst &&
      (fd1_length != fd2_length ||
       memcmp(fd1_result.str, fd2_result.str, fd1_length)))
  {
    /**
       @todo MARIA_HACK
       This serves for when a test is run with --default-storage-engine=X
       where X is not MyISAM: tests using SHOW CREATE TABLE will always fail
       because SHOW CREATE TABLE prints X instead of MyISAM. With
       --global-subst=X,MyISAM , such trivial differences are eliminated and
       test may be reported as passing.
       --global-subst is only a quick way to run a lot of existing tests
       with Maria and find bugs; it is not good enough for reaching the main
       trees when Maria is merged into them.
         --global-subst should be removed.
    */
    uint global_subst_from_len= strlen(global_subst_from);
    uint global_subst_to_len=   strlen(global_subst_to);
    while (replace(&fd1_result,
                   global_subst_from, global_subst_from_len,
                   global_subst_to,   global_subst_to_len) == 0)
      /* do nothing */ ;
    /* let's compare again to see if it is ok now */
  }

  if (fd1_result.length != fd2_result.length)
    error= RESULT_LENGTH_MISMATCH;
  else if ((memcmp(fd1_result.str, fd2_result.str, fd1_result.length)))
    error= RESULT_CONTENT_MISMATCH;

  my_close(fd2, MYF(0));
  dynstr_free(&fd1_result);
  dynstr_free(&fd2_result);

  return error;
}

Project: server

int main(int argc, char **argv)
{
  struct st_command *command;
  my_bool q_send_flag= 0, abort_flag= 0;
  uint command_executed= 0, last_command_executed= 0;
  char save_file[FN_REFLEN];
  bool empty_result= FALSE;
  MY_INIT(argv[0]);
  DBUG_ENTER("main");

  /* mysqltest has no way to free all its memory correctly */
  sf_leaking_memory= 1;

  save_file[0]= 0;
  TMPDIR[0]= 0;

  init_signal_handling();

  /* Init expected errors */
  memset(&saved_expected_errors, 0, sizeof(saved_expected_errors));

#ifdef EMBEDDED_LIBRARY
  /* set appropriate stack for the 'query' threads */
  (void) pthread_attr_init(&cn_thd_attrib);
  pthread_attr_setstacksize(&cn_thd_attrib, DEFAULT_THREAD_STACK);
#endif /*EMBEDDED_LIBRARY*/

  /* Init file stack */
  memset(file_stack, 0, sizeof(file_stack));
  file_stack_end=
    file_stack + (sizeof(file_stack)/sizeof(struct st_test_file)) - 1;
  cur_file= file_stack;

  /* Init block stack */
  memset(block_stack, 0, sizeof(block_stack));
  block_stack_end=
    block_stack + (sizeof(block_stack)/sizeof(struct st_block)) - 1;
  cur_block= block_stack;
  cur_block->ok= TRUE; /* Outer block should always be executed */
  cur_block->cmd= cmd_none;

  my_init_dynamic_array(&q_lines, sizeof(struct st_command*), 1024, 1024);

  if (my_hash_init2(&var_hash, 64, charset_info,
                 128, 0, 0, get_var_key, var_free, MYF(0)))
    die("Variable hash initialization failed");

  var_set_string("MYSQL_SERVER_VERSION", MYSQL_SERVER_VERSION);
  var_set_string("MYSQL_SYSTEM_TYPE", SYSTEM_TYPE);
  var_set_string("MYSQL_MACHINE_TYPE", MACHINE_TYPE);
  if (sizeof(void *) == 8) {
    var_set_string("MYSQL_SYSTEM_ARCHITECTURE", "64");
  } else {
    var_set_string("MYSQL_SYSTEM_ARCHITECTURE", "32");
  }

  memset(&master_pos, 0, sizeof(master_pos));

  parser.current_line= parser.read_lines= 0;
  memset(&var_reg, 0, sizeof(var_reg));

  init_builtin_echo();
#ifdef __WIN__
#ifndef USE_CYGWIN
  is_windows= 1;
#endif
  init_tmp_sh_file();
  init_win_path_patterns();
#endif

  init_dynamic_string(&ds_res, "", 2048, 2048);
  init_alloc_root(&require_file_root, 1024, 1024);

  parse_args(argc, argv);

  log_file.open(opt_logdir, result_file_name, ".log");
  verbose_msg("Logging to '%s'.", log_file.file_name());
  if (opt_mark_progress)
  {
    progress_file.open(opt_logdir, result_file_name, ".progress");
    verbose_msg("Tracing progress in '%s'.", progress_file.file_name());
  }

  /* Init connections, allocate 1 extra as buffer + 1 for default */
  connections= (struct st_connection*)
    my_malloc((opt_max_connections+2) * sizeof(struct st_connection),
              MYF(MY_WME | MY_ZEROFILL));
  connections_end= connections + opt_max_connections +1;
  next_con= connections + 1;
  
  var_set_int("$PS_PROTOCOL", ps_protocol);
  var_set_int("$NON_BLOCKING_API", non_blocking_api_enabled);
  var_set_int("$SP_PROTOCOL", sp_protocol);
  var_set_int("$VIEW_PROTOCOL", view_protocol);
  var_set_int("$CURSOR_PROTOCOL", cursor_protocol);

  var_set_int("$ENABLED_QUERY_LOG", 1);
  var_set_int("$ENABLED_ABORT_ON_ERROR", 1);
  var_set_int("$ENABLED_RESULT_LOG", 1);
  var_set_int("$ENABLED_CONNECT_LOG", 0);
  var_set_int("$ENABLED_WARNINGS", 1);
  var_set_int("$ENABLED_INFO", 0);
  var_set_int("$ENABLED_METADATA", 0);

  DBUG_PRINT("info",("result_file: '%s'",
                     result_file_name ? result_file_name : ""));
  verbose_msg("Results saved in '%s'.", 
              result_file_name ? result_file_name : "");
  if (mysql_server_init(embedded_server_arg_count,
			embedded_server_args,
			(char**) embedded_server_groups))
    die("Can't initialize MySQL server");
  server_initialized= 1;
  if (cur_file == file_stack && cur_file->file == 0)
  {
    cur_file->file= stdin;
    cur_file->file_name= my_strdup("<stdin>", MYF(MY_WME));
    cur_file->lineno= 1;
  }
  var_set_string("MYSQLTEST_FILE", cur_file->file_name);
  init_re();

  /* Cursor protcol implies ps protocol */
  if (cursor_protocol)
    ps_protocol= 1;

  ps_protocol_enabled= ps_protocol;
  sp_protocol_enabled= sp_protocol;
  view_protocol_enabled= view_protocol;
  cursor_protocol_enabled= cursor_protocol;

  st_connection *con= connections;
  init_connection_thd(con);
  if (! (con->mysql= mysql_init(0)))
    die("Failed in mysql_init()");
  if (opt_connect_timeout)
    mysql_options(con->mysql, MYSQL_OPT_CONNECT_TIMEOUT,
                  (void *) &opt_connect_timeout);
  if (opt_compress)
    mysql_options(con->mysql,MYSQL_OPT_COMPRESS,NullS);
  mysql_options(con->mysql, MYSQL_OPT_LOCAL_INFILE, 0);
  mysql_options(con->mysql, MYSQL_SET_CHARSET_NAME,
                charset_info->csname);
  if (opt_charsets_dir)
    mysql_options(con->mysql, MYSQL_SET_CHARSET_DIR,
                  opt_charsets_dir);

  if (opt_protocol)
    mysql_options(con->mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);

  if (opt_plugin_dir && *opt_plugin_dir)
    mysql_options(con->mysql, MYSQL_PLUGIN_DIR, opt_plugin_dir);

#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)

  if (opt_use_ssl)
  {
    mysql_ssl_set(con->mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
		  opt_ssl_capath, opt_ssl_cipher);
#if MYSQL_VERSION_ID >= 50000
    /* Turn on ssl_verify_server_cert only if host is "localhost" */
    opt_ssl_verify_server_cert= opt_host && !strcmp(opt_host, "localhost");
    mysql_options(con->mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
                  &opt_ssl_verify_server_cert);
#endif
  }
#endif

#ifdef HAVE_SMEM
  if (shared_memory_base_name)
    mysql_options(con->mysql,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name);
#endif

  if (!(con->name = my_strdup("default", MYF(MY_WME))))
    die("Out of memory");
  mysql_options(con->mysql, MYSQL_OPT_NONBLOCK, 0);

  safe_connect(con->mysql, con->name, opt_host, opt_user, opt_pass,
               opt_db, opt_port, unix_sock);

  /* Use all time until exit if no explicit 'start_timer' */
  timer_start= timer_now();

  /*
    Initialize $mysql_errno with -1, so we can
    - distinguish it from valid values ( >= 0 ) and
    - detect if there was never a command sent to the server
  */
  var_set_errno(-1);

  set_current_connection(con);

  if (opt_prologue)
  {
    open_file(opt_prologue);
  }

  verbose_msg("Start processing test commands from '%s' ...", cur_file->file_name);
  while (!read_command(&command) && !abort_flag)
  {
    my_bool ok_to_do;
    int current_line_inc = 1, processed = 0;
    if (command->type == Q_UNKNOWN || command->type == Q_COMMENT_WITH_COMMAND)
      get_command_type(command);

    if (parsing_disabled &&
        command->type != Q_ENABLE_PARSING &&
        command->type != Q_DISABLE_PARSING)
    {
      /* Parsing is disabled, silently convert this line to a comment */
      command->type= Q_COMMENT;
    }

    /* (Re-)set abort_on_error for this command */
    command->abort_on_error= (command->expected_errors.count == 0 &&
                              abort_on_error);
    
    /*
      some commmands need to be executed or at least parsed unconditionally,
      because they change the grammar.
    */
    ok_to_do= cur_block->ok || command->type == Q_DELIMITER
                            || command->type == Q_PERL;
    /*
      Some commands need to be "done" the first time if they may get
      re-iterated over in a true context. This can only happen if there's 
      a while loop at some level above the current block.
    */
    if (!ok_to_do)
    {
      if (command->type == Q_SOURCE ||
          command->type == Q_ERROR ||
          command->type == Q_WRITE_FILE ||
          command->type == Q_APPEND_FILE)
      {
	for (struct st_block *stb= cur_block-1; stb >= block_stack; stb--)
	{
	  if (stb->cmd == cmd_while)
	  {
	    ok_to_do= 1;
	    break;
	  }
	}
      }
    }

    if (ok_to_do)
    {
      command->last_argument= command->first_argument;
      processed = 1;
      /* Need to remember this for handle_error() */
      curr_command= command;
      switch (command->type) {
      case Q_CONNECT:
        do_connect(command);
        break;
      case Q_CONNECTION: select_connection(command); break;
      case Q_DISCONNECT:
      case Q_DIRTY_CLOSE:
	do_close_connection(command); break;
      case Q_ENABLE_PREPARE_WARNINGS:  prepare_warnings_enabled=1; break;
      case Q_DISABLE_PREPARE_WARNINGS: prepare_warnings_enabled=0; break;
      case Q_ENABLE_QUERY_LOG:
        set_property(command, P_QUERY, 0);
        break;
      case Q_DISABLE_QUERY_LOG:
        set_property(command, P_QUERY, 1);
        break;
      case Q_ENABLE_ABORT_ON_ERROR:
        set_property(command, P_ABORT, 1);
        break;
      case Q_DISABLE_ABORT_ON_ERROR:
        set_property(command, P_ABORT, 0);
        break;
      case Q_ENABLE_RESULT_LOG:
        set_property(command, P_RESULT, 0);
        break;
      case Q_DISABLE_RESULT_LOG:
        set_property(command, P_RESULT, 1);
        break;
      case Q_ENABLE_CONNECT_LOG:
        set_property(command, P_CONNECT, 0);
        break;
      case Q_DISABLE_CONNECT_LOG:
        set_property(command, P_CONNECT, 1);
        break;
      case Q_ENABLE_WARNINGS:
        set_property(command, P_WARN, 0);
        break;
      case Q_DISABLE_WARNINGS:
        set_property(command, P_WARN, 1);
        break;
      case Q_ENABLE_INFO:
        set_property(command, P_INFO, 0);
        break;
      case Q_DISABLE_INFO:
        set_property(command, P_INFO, 1);
        break;
      case Q_ENABLE_METADATA:
        set_property(command, P_META, 1);
        break;
      case Q_DISABLE_METADATA:
        set_property(command, P_META, 0);
        break;
      case Q_ENABLE_COLUMN_NAMES:
        disable_column_names= 0;
        var_set_int("$ENABLED_COLUMN_NAMES", 0);
        break;
      case Q_DISABLE_COLUMN_NAMES:
        disable_column_names= 1;
        var_set_int("$ENABLED_COLUMN_NAMES", 1);
        break;
      case Q_SOURCE: do_source(command); break;
      case Q_SLEEP: do_sleep(command, 0); break;
      case Q_REAL_SLEEP: do_sleep(command, 1); break;
      case Q_WAIT_FOR_SLAVE_TO_STOP: do_wait_for_slave_to_stop(command); break;
      case Q_INC: do_modify_var(command, DO_INC); break;
      case Q_DEC: do_modify_var(command, DO_DEC); break;
      case Q_ECHO: do_echo(command); command_executed++; break;
      case Q_SYSTEM: do_system(command); break;
      case Q_REMOVE_FILE: do_remove_file(command); break;
      case Q_REMOVE_FILES_WILDCARD: do_remove_files_wildcard(command); break;
      case Q_MKDIR: do_mkdir(command); break;
      case Q_RMDIR: do_rmdir(command); break;
      case Q_LIST_FILES: do_list_files(command); break;
      case Q_LIST_FILES_WRITE_FILE:
        do_list_files_write_file_command(command, FALSE);
        break;
      case Q_LIST_FILES_APPEND_FILE:
        do_list_files_write_file_command(command, TRUE);
        break;
      case Q_FILE_EXIST: do_file_exist(command); break;
      case Q_WRITE_FILE: do_write_file(command); break;
      case Q_APPEND_FILE: do_append_file(command); break;
      case Q_DIFF_FILES: do_diff_files(command); break;
      case Q_SEND_QUIT: do_send_quit(command); break;
      case Q_CHANGE_USER: do_change_user(command); break;
      case Q_CAT_FILE: do_cat_file(command); break;
      case Q_COPY_FILE: do_copy_file(command); break;
      case Q_MOVE_FILE: do_move_file(command); break;
      case Q_CHMOD_FILE: do_chmod_file(command); break;
      case Q_PERL: do_perl(command); break;
      case Q_RESULT_FORMAT_VERSION: do_result_format_version(command); break;
      case Q_DELIMITER:
        do_delimiter(command);
	break;
      case Q_DISPLAY_VERTICAL_RESULTS:
        display_result_vertically= TRUE;
        break;
      case Q_DISPLAY_HORIZONTAL_RESULTS:
	display_result_vertically= FALSE;
        break;
      case Q_SORTED_RESULT:
        /*
          Turn on sorting of result set, will be reset after next
          command
        */
	display_result_sorted= TRUE;
        break;
      case Q_LOWERCASE:
        /*
          Turn on lowercasing of result, will be reset after next
          command
        */
        display_result_lower= TRUE;
        break;
      case Q_LET: do_let(command); break;
      case Q_EVAL_RESULT:
        die("'eval_result' command  is deprecated");
      case Q_EVAL:
      case Q_QUERY_VERTICAL:
      case Q_QUERY_HORIZONTAL:
	if (command->query == command->query_buf)
        {
          /* Skip the first part of command, i.e query_xxx */
	  command->query= command->first_argument;
          command->first_word_len= 0;
        }
	/* fall through */
      case Q_QUERY:
      case Q_REAP:
      {
	my_bool old_display_result_vertically= display_result_vertically;
        /* Default is full query, both reap and send  */
        int flags= QUERY_REAP_FLAG | QUERY_SEND_FLAG;

        if (q_send_flag)
        {
          /* Last command was an empty 'send' */
          flags= QUERY_SEND_FLAG;
          q_send_flag= 0;
        }
        else if (command->type == Q_REAP)
        {
          flags= QUERY_REAP_FLAG;
        }

        /* Check for special property for this query */
        display_result_vertically|= (command->type == Q_QUERY_VERTICAL);

	if (save_file[0])
	{
          if (!(command->require_file= strdup_root(&require_file_root,
                                                   save_file)))
            die("out of memory for require_file");
	  save_file[0]= 0;
	}
	run_query(cur_con, command, flags);
	command_executed++;
        command->last_argument= command->end;

        /* Restore settings */
	display_result_vertically= old_display_result_vertically;

	break;
      }
      case Q_SEND:
      case Q_SEND_EVAL:
        if (!*command->first_argument)
        {
          /*
            This is a send without arguments, it indicates that _next_ query
            should be send only
          */
          q_send_flag= 1;
          break;
        }

        /* Remove "send" if this is first iteration */
	if (command->query == command->query_buf)
	  command->query= command->first_argument;

	/*
	  run_query() can execute a query partially, depending on the flags.
	  QUERY_SEND_FLAG flag without QUERY_REAP_FLAG tells it to just send
          the query and read the result some time later when reap instruction
	  is given on this connection.
        */
	run_query(cur_con, command, QUERY_SEND_FLAG);
	command_executed++;
        command->last_argument= command->end;
	break;
      case Q_REQUIRE:
	do_get_file_name(command, save_file, sizeof(save_file));
	break;
      case Q_ERROR:
        do_get_errcodes(command);
	break;
      case Q_REPLACE:
	do_get_replace(command);
	break;
      case Q_REPLACE_REGEX:
        do_get_replace_regex(command);
        break;
      case Q_REPLACE_COLUMN:
	do_get_replace_column(command);
	break;
      case Q_SAVE_MASTER_POS: do_save_master_pos(); break;
      case Q_SYNC_WITH_MASTER: do_sync_with_master(command); break;
      case Q_SYNC_SLAVE_WITH_MASTER:
      {
	do_save_master_pos();
	if (*command->first_argument)
	  select_connection(command);
	else
	  select_connection_name("slave");
	do_sync_with_master2(command, 0);
	break;
      }
      case Q_COMMENT:
      {
        command->last_argument= command->end;

        /* Don't output comments in v1 */
        if (opt_result_format_version == 1)
          break;

        /* Don't output comments if query logging is off */
        if (disable_query_log)
          break;

        /* Write comment's with two starting #'s to result file */
        const char* p= command->query;
        if (p && *p == '#' && *(p+1) == '#')
        {
          dynstr_append_mem(&ds_res, command->query, command->query_len);
          dynstr_append(&ds_res, "\n");
        }
	break;
      }
      case Q_EMPTY_LINE:
        /* Don't output newline in v1 */
        if (opt_result_format_version == 1)
          break;

        /* Don't output newline if query logging is off */
        if (disable_query_log)
          break;

        dynstr_append(&ds_res, "\n");
        break;
      case Q_PING:
        handle_command_error(command, mysql_ping(cur_con->mysql), -1);
        break;
      case Q_SEND_SHUTDOWN:
        handle_command_error(command,
                             mysql_shutdown(cur_con->mysql,
                                            SHUTDOWN_DEFAULT), -1);
        break;
      case Q_SHUTDOWN_SERVER:
        do_shutdown_server(command);
        break;
      case Q_EXEC:
	do_exec(command);
	command_executed++;
	break;
      case Q_START_TIMER:
	/* Overwrite possible earlier start of timer */
	timer_start= timer_now();
	break;
      case Q_END_TIMER:
	/* End timer before ending mysqltest */
	timer_output();
	break;
      case Q_CHARACTER_SET:
	do_set_charset(command);
	break;
      case Q_DISABLE_PS_PROTOCOL:
        set_property(command, P_PS, 0);
        /* Close any open statements */
        close_statements();
        break;
      case Q_ENABLE_PS_PROTOCOL:
        set_property(command, P_PS, ps_protocol);
        break;
      case Q_DISABLE_NON_BLOCKING_API:
        non_blocking_api_enabled= 0;
        break;
      case Q_ENABLE_NON_BLOCKING_API:
        non_blocking_api_enabled= 1;
        break;
      case Q_DISABLE_RECONNECT:
        set_reconnect(cur_con->mysql, 0);
        break;
      case Q_ENABLE_RECONNECT:
        set_reconnect(cur_con->mysql, 1);
        /* Close any open statements - no reconnect, need new prepare */
        close_statements();
        break;
      case Q_DISABLE_PARSING:
        if (parsing_disabled == 0)
          parsing_disabled= 1;
        else
          report_or_die("Parsing is already disabled");
        break;
      case Q_ENABLE_PARSING:
        /*
          Ensure we don't get parsing_disabled < 0 as this would accidentally
          disable code we don't want to have disabled
        */
        if (parsing_disabled == 1)
          parsing_disabled= 0;
        else
          report_or_die("Parsing is already enabled");
        break;
      case Q_DIE:
        /* Abort test with error code and error message */
        die("%s", command->first_argument);
        break;
      case Q_EXIT:
        /* Stop processing any more commands */
        abort_flag= 1;
        break;
      case Q_SKIP:
        /* Eval the query, thus replacing all environment variables */
        dynstr_set(&ds_res, 0);
        do_eval(&ds_res, command->first_argument, command->end, FALSE);
        abort_not_supported_test("%s",ds_res.str);
        break;

      case Q_RESULT:
        die("result, deprecated command");
        break;

      default:
        processed= 0;
        break;
      }
    }

    if (!processed)
    {
      current_line_inc= 0;
      switch (command->type) {
      case Q_WHILE: do_block(cmd_while, command); break;
      case Q_IF: do_block(cmd_if, command); break;
      case Q_END_BLOCK: do_done(command); break;
      default: current_line_inc = 1; break;
      }
    }
    else
      check_eol_junk(command->last_argument);

    if (command->type != Q_ERROR &&
        command->type != Q_COMMENT)
    {
      /*
        As soon as any non "error" command or comment has been executed,
        the array with expected errors should be cleared
      */
      memset(&saved_expected_errors, 0, sizeof(saved_expected_errors));
    }

    if (command_executed != last_command_executed || command->used_replace)
    {
      /*
        As soon as any command has been executed,
        the replace structures should be cleared
      */
      free_all_replace();

      /* Also reset "sorted_result" and "lowercase"*/
      display_result_sorted= FALSE;
      display_result_lower= FALSE;
    }
    last_command_executed= command_executed;

    parser.current_line += current_line_inc;
    if ( opt_mark_progress )
      mark_progress(command, parser.current_line);

    /* Write result from command to log file immediately */
    log_file.write(&ds_res);
    log_file.flush();
    dynstr_set(&ds_res, 0);
  }

  log_file.close();

  start_lineno= 0;
  verbose_msg("... Done processing test commands.");

  if (parsing_disabled)
    die("Test ended with parsing disabled");

  /*
    The whole test has been executed _sucessfully_.
    Time to compare result or save it to record file.
    The entire output from test is in the log file
  */
  if (log_file.bytes_written())
  {
    if (result_file_name)
    {
      /* A result file has been specified */

      if (record)
      {
	/* Recording */

        /* save a copy of the log to result file */
        if (my_copy(log_file.file_name(), result_file_name, MYF(0)) != 0)
          die("Failed to copy '%s' to '%s', errno: %d",
              log_file.file_name(), result_file_name, errno);

      }
      else
      {
	/* Check that the output from test is equal to result file */
	check_result();
      }
    }
  }
  else
  {
    /* Empty output is an error *unless* we also have an empty result file */
    if (! result_file_name || record ||
        compare_files (log_file.file_name(), result_file_name))
    {
      die("The test didn't produce any output");
    }
    else 
    {
      empty_result= TRUE;  /* Meaning empty was expected */
    }
  }

  if (!command_executed && result_file_name && !empty_result)
    die("No queries executed but non-empty result file found!");

  verbose_msg("Test has succeeded!");
  timer_output();
  /* Yes, if we got this far the test has suceeded! Sakila smiles */
  cleanup_and_exit(0);
  return 0; /* Keep compiler happy too */
}

Project: server

void do_rmdir(struct st_command *command)
{
  int error;
  static DYNAMIC_STRING ds_dirname;
  const struct command_arg rmdir_args[] = {
    { "dirname", ARG_STRING, TRUE, &ds_dirname, "Directory to remove" }
  };
  DBUG_ENTER("do_rmdir");

  check_command_args(command, command->first_argument,
                     rmdir_args, sizeof(rmdir_args)/sizeof(struct command_arg),
                     ' ');

  DBUG_PRINT("info", ("removing directory: %s", ds_dirname.str));
  error= rmdir(ds_dirname.str) != 0;
  handle_command_error(command, error, errno);
  dynstr_free(&ds_dirname);
  DBUG_VOID_RETURN;
}

Project: server

void do_shutdown_server(struct st_command *command)
{
  long timeout=60;
  int pid;
  DYNAMIC_STRING ds_pidfile_name;
  MYSQL* mysql = cur_con->mysql;
  static DYNAMIC_STRING ds_timeout;
  const struct command_arg shutdown_args[] = {
    {"timeout", ARG_STRING, FALSE, &ds_timeout, "Timeout before killing server"}
  };
  DBUG_ENTER("do_shutdown_server");

  check_command_args(command, command->first_argument, shutdown_args,
                     sizeof(shutdown_args)/sizeof(struct command_arg),
                     ' ');

  if (ds_timeout.length)
  {
    char* endptr;
    timeout= strtol(ds_timeout.str, &endptr, 10);
    if (*endptr != '\0')
      die("Illegal argument for timeout: '%s'", ds_timeout.str);
  }
  dynstr_free(&ds_timeout);

  /* Get the servers pid_file name and use it to read pid */
  if (query_get_string(mysql, "SHOW VARIABLES LIKE 'pid_file'", 1,
                       &ds_pidfile_name))
    die("Failed to get pid_file from server");

  /* Read the pid from the file */
  {
    int fd;
    char buff[32];

    if ((fd= my_open(ds_pidfile_name.str, O_RDONLY, MYF(0))) < 0)
      die("Failed to open file '%s'", ds_pidfile_name.str);
    dynstr_free(&ds_pidfile_name);

    if (my_read(fd, (uchar*)&buff,
                sizeof(buff), MYF(0)) <= 0){
      my_close(fd, MYF(0));
      die("pid file was empty");
    }
    my_close(fd, MYF(0));

    pid= atoi(buff);
    if (pid == 0)
      die("Pidfile didn't contain a valid number");
  }
  DBUG_PRINT("info", ("Got pid %d", pid));

  /* Tell server to shutdown if timeout > 0*/
  if (timeout && mysql_shutdown(mysql, SHUTDOWN_DEFAULT))
    die("mysql_shutdown failed");

  /* Check that server dies */
  while(timeout--){
    if (my_kill(pid, 0) < 0){
      DBUG_PRINT("info", ("Process %d does not exist anymore", pid));
      DBUG_VOID_RETURN;
    }
    DBUG_PRINT("info", ("Sleeping, timeout: %ld", timeout));
    my_sleep(1000000L);
  }

  /* Kill the server */
  DBUG_PRINT("info", ("Killing server, pid: %d", pid));
  (void)my_kill(pid, 9);

  DBUG_VOID_RETURN;

}

Project: server

void do_connect(struct st_command *command)
{
  int con_port= opt_port;
  char *con_options;
  char *ssl_cipher __attribute__((unused))= 0;
  my_bool con_ssl= 0, con_compress= 0;
  my_bool con_pipe= 0;
  my_bool con_shm __attribute__ ((unused))= 0;
  struct st_connection* con_slot;

  static DYNAMIC_STRING ds_connection_name;
  static DYNAMIC_STRING ds_host;
  static DYNAMIC_STRING ds_user;
  static DYNAMIC_STRING ds_password;
  static DYNAMIC_STRING ds_database;
  static DYNAMIC_STRING ds_port;
  static DYNAMIC_STRING ds_sock;
  static DYNAMIC_STRING ds_options;
  static DYNAMIC_STRING ds_default_auth;
#ifdef HAVE_SMEM
  static DYNAMIC_STRING ds_shm;
#endif
  const struct command_arg connect_args[] = {
    { "connection name", ARG_STRING, TRUE, &ds_connection_name, "Name of the connection" },
    { "host", ARG_STRING, TRUE, &ds_host, "Host to connect to" },
    { "user", ARG_STRING, FALSE, &ds_user, "User to connect as" },
    { "passsword", ARG_STRING, FALSE, &ds_password, "Password used when connecting" },
    { "database", ARG_STRING, FALSE, &ds_database, "Database to select after connect" },
    { "port", ARG_STRING, FALSE, &ds_port, "Port to connect to" },
    { "socket", ARG_STRING, FALSE, &ds_sock, "Socket to connect with" },
    { "options", ARG_STRING, FALSE, &ds_options, "Options to use while connecting" },
    { "default_auth", ARG_STRING, FALSE, &ds_default_auth, "Default authentication to use" }
  };

  DBUG_ENTER("do_connect");
  DBUG_PRINT("enter",("connect: %s", command->first_argument));

  strip_parentheses(command);
  check_command_args(command, command->first_argument, connect_args,
                     sizeof(connect_args)/sizeof(struct command_arg),
                     ',');

  /* Port */
  if (ds_port.length)
  {
    con_port= atoi(ds_port.str);
    if (con_port == 0)
      die("Illegal argument for port: '%s'", ds_port.str);
  }

#ifdef HAVE_SMEM
  /* Shared memory */
  init_dynamic_string(&ds_shm, ds_sock.str, 0, 0);
#endif

  /* Sock */
  if (ds_sock.length)
  {
    /*
      If the socket is specified just as a name without path
      append tmpdir in front
    */
    if (*ds_sock.str != FN_LIBCHAR)
    {
      char buff[FN_REFLEN];
      fn_format(buff, ds_sock.str, TMPDIR, "", 0);
      dynstr_set(&ds_sock, buff);
    }
  }
  else
  {
    /* No socket specified, use default */
    dynstr_set(&ds_sock, unix_sock);
  }
  DBUG_PRINT("info", ("socket: %s", ds_sock.str));


  /* Options */
  con_options= ds_options.str;
  while (*con_options)
  {
    size_t length;
    char *end;
    /* Step past any spaces in beginning of option*/
    while (*con_options && my_isspace(charset_info, *con_options))
     con_options++;
    /* Find end of this option */
    end= con_options;
    while (*end && !my_isspace(charset_info, *end))
      end++;
    length= (size_t) (end - con_options);
    if (length == 3 && !strncmp(con_options, "SSL", 3))
      con_ssl= 1;
    else if (!strncmp(con_options, "SSL-CIPHER=", 11))
    {
      con_ssl= 1;
      ssl_cipher=con_options + 11;
    }
    else if (length == 8 && !strncmp(con_options, "COMPRESS", 8))
      con_compress= 1;
    else if (length == 4 && !strncmp(con_options, "PIPE", 4))
      con_pipe= 1;
    else if (length == 3 && !strncmp(con_options, "SHM", 3))
      con_shm= 1;
    else
      die("Illegal option to connect: %.*s", 
          (int) (end - con_options), con_options);
    /* Process next option */
    con_options= end;
  }

  if (find_connection_by_name(ds_connection_name.str))
    die("Connection %s already exists", ds_connection_name.str);
    
  if (next_con != connections_end)
    con_slot= next_con;
  else
  {
    if (!(con_slot= find_connection_by_name("-closed_connection-")))
      die("Connection limit exhausted, you can have max %d connections",
          opt_max_connections);
    my_free(con_slot->name);
    con_slot->name= 0;
  }

  init_connection_thd(con_slot);

  if (!(con_slot->mysql= mysql_init(0)))
    die("Failed on mysql_init()");

  if (opt_connect_timeout)
    mysql_options(con_slot->mysql, MYSQL_OPT_CONNECT_TIMEOUT,
                  (void *) &opt_connect_timeout);
#ifndef MY_CONTEXT_DISABLE
  if (mysql_options(con_slot->mysql, MYSQL_OPT_NONBLOCK, 0))
    die("Failed to initialise non-blocking API");
#endif
  if (opt_compress || con_compress)
    mysql_options(con_slot->mysql, MYSQL_OPT_COMPRESS, NullS);
  mysql_options(con_slot->mysql, MYSQL_OPT_LOCAL_INFILE, 0);
  mysql_options(con_slot->mysql, MYSQL_SET_CHARSET_NAME,
                charset_info->csname);
  if (opt_charsets_dir)
    mysql_options(con_slot->mysql, MYSQL_SET_CHARSET_DIR,
                  opt_charsets_dir);
#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
  if (opt_use_ssl)
    con_ssl= 1;
#endif

  if (con_ssl)
  {
#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
    mysql_ssl_set(con_slot->mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
		  opt_ssl_capath, ssl_cipher ? ssl_cipher : opt_ssl_cipher);
#if MYSQL_VERSION_ID >= 50000
    /* Turn on ssl_verify_server_cert only if host is "localhost" */
    opt_ssl_verify_server_cert= !strcmp(ds_host.str, "localhost");
    mysql_options(con_slot->mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
                  &opt_ssl_verify_server_cert);
#endif
#endif
  }

  if (con_pipe)
  {
#ifdef __WIN__
    opt_protocol= MYSQL_PROTOCOL_PIPE;
#endif
  }

  if (opt_protocol)
    mysql_options(con_slot->mysql, MYSQL_OPT_PROTOCOL, (char*) &opt_protocol);

#ifdef HAVE_SMEM
  if (con_shm)
  {
    uint protocol= MYSQL_PROTOCOL_MEMORY;
    if (!ds_shm.length)
      die("Missing shared memory base name");
    mysql_options(con_slot->mysql, MYSQL_SHARED_MEMORY_BASE_NAME, ds_shm.str);
    mysql_options(con_slot->mysql, MYSQL_OPT_PROTOCOL, &protocol);
  }
  else if (shared_memory_base_name)
  {
    mysql_options(con_slot->mysql, MYSQL_SHARED_MEMORY_BASE_NAME,
                  shared_memory_base_name);
  }
#endif

  /* Use default db name */
  if (ds_database.length == 0)
    dynstr_set(&ds_database, opt_db);

  if (opt_plugin_dir && *opt_plugin_dir)
    mysql_options(con_slot->mysql, MYSQL_PLUGIN_DIR, opt_plugin_dir);

  if (ds_default_auth.length)
    mysql_options(con_slot->mysql, MYSQL_DEFAULT_AUTH, ds_default_auth.str);

  /* Special database to allow one to connect without a database name */
  if (ds_database.length && !strcmp(ds_database.str,"*NO-ONE*"))
    dynstr_set(&ds_database, "");

  if (connect_n_handle_errors(command, con_slot->mysql,
                              ds_host.str,ds_user.str,
                              ds_password.str, ds_database.str,
                              con_port, ds_sock.str))
  {
    DBUG_PRINT("info", ("Inserting connection %s in connection pool",
                        ds_connection_name.str));
    if (!(con_slot->name= my_strdup(ds_connection_name.str, MYF(MY_WME))))
      die("Out of memory");
    con_slot->name_len= strlen(con_slot->name);
    set_current_connection(con_slot);

    if (con_slot == next_con)
      next_con++; /* if we used the next_con slot, advance the pointer */
  }

  dynstr_free(&ds_connection_name);
  dynstr_free(&ds_host);
  dynstr_free(&ds_user);
  dynstr_free(&ds_password);
  dynstr_free(&ds_database);
  dynstr_free(&ds_port);
  dynstr_free(&ds_sock);
  dynstr_free(&ds_options);
  dynstr_free(&ds_default_auth);
#ifdef HAVE_SMEM
  dynstr_free(&ds_shm);
#endif
  DBUG_VOID_RETURN;
}

Project: server

static void do_list_files_write_file_command(struct st_command *command,
                                             my_bool append)
{
  int error;
  static DYNAMIC_STRING ds_content;
  static DYNAMIC_STRING ds_filename;
  static DYNAMIC_STRING ds_dirname;
  static DYNAMIC_STRING ds_wild;
  const struct command_arg list_files_args[] = {
    {"filename", ARG_STRING, TRUE, &ds_filename, "Filename for write"},
    {"dirname", ARG_STRING, TRUE, &ds_dirname, "Directory to list"},
    {"file", ARG_STRING, FALSE, &ds_wild, "Filename (incl. wildcard)"}
  };
  DBUG_ENTER("do_list_files_write_file");
  command->used_replace= 1;

  check_command_args(command, command->first_argument,
                     list_files_args,
                     sizeof(list_files_args)/sizeof(struct command_arg), ' ');

  init_dynamic_string(&ds_content, "", 1024, 1024);
  error= get_list_files(&ds_content, &ds_dirname, &ds_wild);
  handle_command_error(command, error, my_errno);
  str_to_file2(ds_filename.str, ds_content.str, ds_content.length, append);
  dynstr_free(&ds_content);
  dynstr_free(&ds_filename);
  dynstr_free(&ds_dirname);
  dynstr_free(&ds_wild);
  DBUG_VOID_RETURN;
}

Project: server

void do_move_file(struct st_command *command)
{
  int error;
  static DYNAMIC_STRING ds_from_file;
  static DYNAMIC_STRING ds_to_file;
  const struct command_arg move_file_args[] = {
    { "from_file", ARG_STRING, TRUE, &ds_from_file, "Filename to move from" },
    { "to_file", ARG_STRING, TRUE, &ds_to_file, "Filename to move to" }
  };
  DBUG_ENTER("do_move_file");

  check_command_args(command, command->first_argument,
                     move_file_args,
                     sizeof(move_file_args)/sizeof(struct command_arg),
                     ' ');

  DBUG_PRINT("info", ("Move %s to %s", ds_from_file.str, ds_to_file.str));
  error= (my_rename(ds_from_file.str, ds_to_file.str,
                    MYF(disable_warnings ? 0 : MY_WME)) != 0);
  handle_command_error(command, error, my_errno);
  dynstr_free(&ds_from_file);
  dynstr_free(&ds_to_file);
  DBUG_VOID_RETURN;
}

Project: server

char *re_eprint(int err)
{
  static char epbuf[100];
  size_t len __attribute__((unused))=
          my_regerror(REG_ITOA|err, (my_regex_t *)NULL, epbuf, sizeof(epbuf));
  assert(len <= sizeof(epbuf));
  return(epbuf);
}

Project: server

void do_eval(DYNAMIC_STRING *query_eval, const char *query,
             const char *query_end, my_bool pass_through_escape_chars)
{
  const char *p;
  register char c, next_c;
  register int escaped = 0;
  VAR *v;
  DBUG_ENTER("do_eval");

  for (p= query; (c= *p) && p < query_end; ++p)
  {
    switch(c) {
    case '$':
      if (escaped)
      {
	escaped= 0;
	dynstr_append_mem(query_eval, p, 1);
      }
      else
      {
	if (!(v= var_get(p, &p, 0, 0)))
        {
          report_or_die( "Bad variable in eval");
          return;
        }
	dynstr_append_mem(query_eval, v->str_val, v->str_val_len);
      }
      break;
    case '\\':
      next_c= *(p+1);
      if (escaped)
      {
	escaped= 0;
	dynstr_append_mem(query_eval, p, 1);
      }
      else if (next_c == '\\' || next_c == '$' || next_c == '"')
      {
        /* Set escaped only if next char is \, " or $ */
	escaped= 1;

        if (pass_through_escape_chars)
        {
          /* The escape char should be added to the output string. */
          dynstr_append_mem(query_eval, p, 1);
        }
      }
      else
	dynstr_append_mem(query_eval, p, 1);
      break;
    default:
      escaped= 0;
      dynstr_append_mem(query_eval, p, 1);
      break;
    }
  }
#ifdef __WIN__
    fix_win_paths(query_eval->str, query_eval->length);
#endif
  DBUG_VOID_RETURN;
}

Project: server

static int do_stmt_prepare(struct st_connection *cn, const char *q, int q_len)
{
  /* The cn->stmt is already set. */
  if (!cn->has_thread)
    return mysql_stmt_prepare(cn->stmt, q, q_len);
  cn->cur_query= q;
  cn->cur_query_len= q_len;
  signal_connection_thd(cn, EMB_PREPARE_STMT);
  wait_query_thread_done(cn);
  return cn->result;
}

Project: server

void append_table_headings(DYNAMIC_STRING *ds,
                           MYSQL_FIELD *field,
                           uint num_fields)
{
  uint col_idx;
  if (disable_column_names)
    return;
  for (col_idx= 0; col_idx < num_fields; col_idx++)
  {
    if (col_idx)
      dynstr_append_mem(ds, "\t", 1);
    replace_dynstr_append(ds, field[col_idx].name);
  }
  dynstr_append_mem(ds, "\n", 1);
}

Project: server

void handle_error(struct st_command *command,
                  unsigned int err_errno, const char *err_error,
                  const char *err_sqlstate, DYNAMIC_STRING *ds)
{
  int i;

  DBUG_ENTER("handle_error");

  command->used_replace= 1;
  if (command->require_file)
  {
    /*
      The query after a "--require" failed. This is fine as long the server
      returned a valid reponse. Don't allow 2013 or 2006 to trigger an
      abort_not_supported_test
    */
    if (err_errno == CR_SERVER_LOST ||
        err_errno == CR_SERVER_GONE_ERROR)
      die("require query '%s' failed: %d: %s", command->query,
          err_errno, err_error);

    /* Abort the run of this test, pass the failed query as reason */
    abort_not_supported_test("Query '%s' failed, required functionality " \
                             "not supported", command->query);
  }

  if (command->abort_on_error)
  {
    report_or_die("query '%s' failed: %d: %s", command->query, err_errno,
                  err_error);
    DBUG_VOID_RETURN;
  }

  DBUG_PRINT("info", ("expected_errors.count: %d",
                      command->expected_errors.count));

  i= match_expected_error(command, err_errno, err_sqlstate);

  if (i >= 0)
  {
    if (!disable_result_log)
    {
      if (command->expected_errors.count == 1)
      {
        /* Only log error if there is one possible error */
        dynstr_append_mem(ds, "ERROR ", 6);
        replace_dynstr_append(ds, err_sqlstate);
        dynstr_append_mem(ds, ": ", 2);
        replace_dynstr_append(ds, err_error);
        dynstr_append_mem(ds,"\n",1);
      }
      /* Don't log error if we may not get an error */
      else if (command->expected_errors.err[0].type == ERR_SQLSTATE ||
               (command->expected_errors.err[0].type == ERR_ERRNO &&
                command->expected_errors.err[0].code.errnum != 0))
        dynstr_append(ds,"Got one of the listed errors\n");
    }
    /* OK */
    revert_properties();
    DBUG_VOID_RETURN;
  }

  DBUG_PRINT("info",("i: %d  expected_errors: %d", i,
                     command->expected_errors.count));

  if (!disable_result_log)
  {
    dynstr_append_mem(ds, "ERROR ",6);
    replace_dynstr_append(ds, err_sqlstate);
    dynstr_append_mem(ds, ": ", 2);
    replace_dynstr_append(ds, err_error);
    dynstr_append_mem(ds, "\n", 1);
  }

  if (command->expected_errors.count > 0)
  {
    if (command->expected_errors.err[0].type == ERR_ERRNO)
      report_or_die("query '%s' failed with wrong errno %d: '%s', instead of "
                    "%d...",
                    command->query, err_errno, err_error,
                    command->expected_errors.err[0].code.errnum);
    else
      report_or_die("query '%s' failed with wrong sqlstate %s: '%s', "
                    "instead of %s...",
                    command->query, err_sqlstate, err_error,
                    command->expected_errors.err[0].code.sqlstate);
  }

  revert_properties();
  DBUG_VOID_RETURN;
}

Project: server

void var_query_set(VAR *var, const char *query, const char** query_end)
{
  char *end = (char*)((query_end && *query_end) ?
		      *query_end : query + strlen(query));
  MYSQL_RES *res;
  MYSQL_ROW row;
  MYSQL* mysql = cur_con->mysql;
  DYNAMIC_STRING ds_query;
  DBUG_ENTER("var_query_set");
  LINT_INIT(res);

  if (!mysql)
  {
    struct st_command command;
    memset(&command, 0, sizeof(command));
    command.query= (char*)query;
    command.first_word_len= (*query_end - query);
    command.first_argument= command.query + command.first_word_len;
    command.end= (char*)*query_end;
    command.abort_on_error= 1; /* avoid uninitialized variables */
    handle_no_active_connection(&command, cur_con, &ds_res);
    DBUG_VOID_RETURN;
  }

  /* Only white space or ) allowed past ending ` */
  while (end > query && *end != '`')
  {
    if (*end && (*end != ' ' && *end != '\t' && *end != '\n' && *end != ')'))
      die("Spurious text after `query` expression");
    --end;
  }

  if (query == end)
    die("Syntax error in query, missing '`'");
  ++query;

  /* Eval the query, thus replacing all environment variables */
  init_dynamic_string(&ds_query, 0, (end - query) + 32, 256);
  do_eval(&ds_query, query, end, FALSE);

  if (mysql_real_query(mysql, ds_query.str, ds_query.length)) 
  {
    handle_error(curr_command, mysql_errno(mysql), mysql_error(mysql),
                 mysql_sqlstate(mysql), &ds_res);
    /* If error was acceptable, return empty string */
    dynstr_free(&ds_query);
    eval_expr(var, "", 0);
    DBUG_VOID_RETURN;
  }
  
  if (!(res= mysql_store_result(mysql)))
  {
    report_or_die("Query '%s' didn't return a result set", ds_query.str);
    dynstr_free(&ds_query);
    eval_expr(var, "", 0);
    return;
  }
  dynstr_free(&ds_query);

  if ((row= mysql_fetch_row(res)) && row[0])
  {
    /*
      Concatenate all fields in the first row with tab in between
      and assign that string to the $variable
    */
    DYNAMIC_STRING result;
    uint i;
    ulong *lengths;

    init_dynamic_string(&result, "", 512, 512);
    lengths= mysql_fetch_lengths(res);
    for (i= 0; i < mysql_num_fields(res); i++)
    {
      if (row[i])
      {
        /* Add column to tab separated string */
	char *val= row[i];
	int len= lengths[i];
	
	if (glob_replace_regex)
	{
	  /* Regex replace */
	  if (!multi_reg_replace(glob_replace_regex, (char*)val))
	  {
	    val= glob_replace_regex->buf;
	    len= strlen(val);
	  }
	}
	
	if (glob_replace)
	  replace_strings_append(glob_replace, &result, val, len);
	else
	  dynstr_append_mem(&result, val, len);
      }
      dynstr_append_mem(&result, "\t", 1);
    }
    end= result.str + result.length-1;
    /* Evaluation should not recurse via backtick */
    eval_expr(var, result.str, (const char**) &end, false, false);
    dynstr_free(&result);
  }
  else
    eval_expr(var, "", 0);

  mysql_free_result(res);
  DBUG_VOID_RETURN;
}

Project: server

void do_delimiter(struct st_command* command)
{
  char* p= command->first_argument;
  DBUG_ENTER("do_delimiter");
  DBUG_PRINT("enter", ("first_argument: %s", command->first_argument));

  while (*p && my_isspace(charset_info, *p))
    p++;

  if (!(*p))
    die("Can't set empty delimiter");

  delimiter_length= strmake_buf(delimiter, p) - delimiter;

  DBUG_PRINT("exit", ("delimiter: %s", delimiter));
  command->last_argument= p + delimiter_length;
  DBUG_VOID_RETURN;
}

Project: server

void report_or_die(const char *fmt, ...)
{
  va_list args;
  DBUG_ENTER("report_or_die");

  char buff[DIE_BUFF_SIZE];

  va_start(args, fmt);
  make_error_message(buff, sizeof(buff), fmt, args);
  va_end(args);

  if (opt_continue_on_error)
  {
    /* Just log the error and continue */
    replace_dynstr_append(&ds_res, buff);
    error_count++;
    DBUG_VOID_RETURN;
  }

  really_die(buff);
}

Project: server

void do_get_replace_column(struct st_command *command)
{
  char *from= command->first_argument;
  char *buff, *start;
  DBUG_ENTER("get_replace_columns");

  free_replace_column();
  if (!*from)
    die("Missing argument in %s", command->query);

  /* Allocate a buffer for results */
  start= buff= (char*)my_malloc(strlen(from)+1,MYF(MY_WME | MY_FAE));
  while (*from)
  {
    char *to;
    uint column_number;
    to= get_string(&buff, &from, command);
    if (!(column_number= atoi(to)) || column_number > MAX_COLUMNS)
      die("Wrong column number to replace_column in '%s'", command->query);
    if (!*from)
      die("Wrong number of arguments to replace_column in '%s'",
          command->query);
    to= get_string(&buff, &from, command);
    my_free(replace_column[column_number-1]);
    replace_column[column_number-1]= my_strdup(to, MYF(MY_WME | MY_FAE));
    set_if_bigger(max_replace_column, column_number);
  }
  my_free(start);
  command->last_argument= command->end;

  DBUG_VOID_RETURN;
}

Project: server

void eval_expr(VAR *v, const char *p, const char **p_end,
               bool open_end, bool do_eval)
{

  DBUG_ENTER("eval_expr");
  DBUG_PRINT("enter", ("p: '%s'", p));

  /* Skip to treat as pure string if no evaluation */
  if (! do_eval)
    goto NO_EVAL;
  
  if (*p == '$')
  {
    VAR *vp;
    const char* expected_end= *p_end; // Remember var end
    if ((vp= var_get(p, p_end, 0, 0)))
      var_copy(v, vp);

    /* Apparently it is not safe to assume null-terminated string */
    v->str_val[v->str_val_len]= 0;

    /* Make sure there was just a $variable and nothing else */
    const char* end= *p_end + 1;
    if (end < expected_end && !open_end)
      die("Found junk '%.*s' after $variable in expression",
          (int)(expected_end - end - 1), end);

    DBUG_VOID_RETURN;
  }

  if (*p == '`')
  {
    var_query_set(v, p, p_end);
    DBUG_VOID_RETURN;
  }

  {
    /* Check if this is a "let $var= query_get_value()" */
    const char* get_value_str= "query_get_value";
    const size_t len= strlen(get_value_str);
    if (strncmp(p, get_value_str, len)==0)
    {
      struct st_command command;
      memset(&command, 0, sizeof(command));
      command.query= (char*)p;
      command.first_word_len= len;
      command.first_argument= command.query + len;
      command.end= (char*)*p_end;
      command.abort_on_error= 1; /* avoid uninitialized variables */
      var_set_query_get_value(&command, v);
      DBUG_VOID_RETURN;
    }
  }

 NO_EVAL:
  {
    int new_val_len = (p_end && *p_end) ?
      (int) (*p_end - p) : (int) strlen(p);
    if (new_val_len + 1 >= v->alloced_len)
    {
      static int MIN_VAR_ALLOC= 32;
      v->alloced_len = (new_val_len < MIN_VAR_ALLOC - 1) ?
        MIN_VAR_ALLOC : new_val_len + 1;
      if (!(v->str_val =
            v->str_val ?
            (char*)my_realloc(v->str_val, v->alloced_len+1, MYF(MY_WME)) :
            (char*)my_malloc(v->alloced_len+1, MYF(MY_WME))))
        die("Out of memory");
    }
    v->str_val_len = new_val_len;
    memcpy(v->str_val, p, new_val_len);
    v->str_val[new_val_len] = 0;
    var_check_int(v);
  }
  DBUG_VOID_RETURN;
}

Project: server

void do_cat_file(struct st_command *command)
{
  int error;
  static DYNAMIC_STRING ds_filename;
  const struct command_arg cat_file_args[] = {
    { "filename", ARG_STRING, TRUE, &ds_filename, "File to read from" }
  };
  DBUG_ENTER("do_cat_file");

  check_command_args(command,
                     command->first_argument,
                     cat_file_args,
                     sizeof(cat_file_args)/sizeof(struct command_arg),
                     ' ');

  DBUG_PRINT("info", ("Reading from, file: %s", ds_filename.str));

  error= cat_file(&ds_res, ds_filename.str);
  handle_command_error(command, error, my_errno);
  dynstr_free(&ds_filename);
  DBUG_VOID_RETURN;
}

Project: server

void do_diff_files(struct st_command *command)
{
  int error= 0;
  static DYNAMIC_STRING ds_filename;
  static DYNAMIC_STRING ds_filename2;
  const struct command_arg diff_file_args[] = {
    { "file1", ARG_STRING, TRUE, &ds_filename, "First file to diff" },
    { "file2", ARG_STRING, TRUE, &ds_filename2, "Second file to diff" }
  };
  DBUG_ENTER("do_diff_files");

  check_command_args(command,
                     command->first_argument,
                     diff_file_args,
                     sizeof(diff_file_args)/sizeof(struct command_arg),
                     ' ');

  if (access(ds_filename.str, F_OK) != 0)
    die("command \"diff_files\" failed, file '%s' does not exist",
        ds_filename.str);

  if (access(ds_filename2.str, F_OK) != 0)
    die("command \"diff_files\" failed, file '%s' does not exist",
        ds_filename2.str);

  if ((error= compare_files(ds_filename.str, ds_filename2.str)) &&
      match_expected_error(command, error, NULL) < 0)
  {
    /*
      Compare of the two files failed, append them to output
      so the failure can be analyzed, but only if it was not
      expected to fail.
    */
    show_diff(&ds_res, ds_filename.str, ds_filename2.str);
    log_file.write(&ds_res);
    log_file.flush();
    dynstr_set(&ds_res, 0);
  }

  dynstr_free(&ds_filename);
  dynstr_free(&ds_filename2);
  handle_command_error(command, error, -1);
  DBUG_VOID_RETURN;
}

Project: server

void do_change_user(struct st_command *command)
{
  MYSQL *mysql = cur_con->mysql;
  /* static keyword to make the NetWare compiler happy. */
  static DYNAMIC_STRING ds_user, ds_passwd, ds_db;
  const struct command_arg change_user_args[] = {
    { "user", ARG_STRING, FALSE, &ds_user, "User to connect as" },
    { "password", ARG_STRING, FALSE, &ds_passwd, "Password used when connecting" },
    { "database", ARG_STRING, FALSE, &ds_db, "Database to select after connect" },
  };

  DBUG_ENTER("do_change_user");

  check_command_args(command, command->first_argument,
                     change_user_args,
                     sizeof(change_user_args)/sizeof(struct command_arg),
                     ',');

  if (cur_con->stmt)
  {
    mysql_stmt_close(cur_con->stmt);
    cur_con->stmt= NULL;
  }

  if (!ds_user.length)
  {
    dynstr_set(&ds_user, mysql->user);

    if (!ds_passwd.length)
      dynstr_set(&ds_passwd, mysql->passwd);

    if (!ds_db.length)
      dynstr_set(&ds_db, mysql->db);
  }

  DBUG_PRINT("info",("connection: '%s' user: '%s' password: '%s' database: '%s'",
                      cur_con->name, ds_user.str, ds_passwd.str, ds_db.str));

  if (mysql_change_user(mysql, ds_user.str, ds_passwd.str, ds_db.str))
    handle_error(command, mysql_errno(mysql), mysql_error(mysql),
		 mysql_sqlstate(mysql), &ds_res);
  else
    handle_no_error(command);

  dynstr_free(&ds_user);
  dynstr_free(&ds_passwd);
  dynstr_free(&ds_db);

  DBUG_VOID_RETURN;
}

Project: server

ulonglong timer_now(void)
{
  return my_interval_timer() / 1000000;
}

Project: server

  void open(const char* dir, const char* name, const char* ext)
  {
    DBUG_ENTER("LogFile::open");
    DBUG_PRINT("enter", ("dir: '%s', name: '%s'", dir, name));
    if (!name)
    {
      m_file= stdout;
      DBUG_VOID_RETURN;
    }

    fn_format(m_file_name, name, dir, ext,
              *dir ? MY_REPLACE_DIR | MY_REPLACE_EXT :
              MY_REPLACE_EXT);

    DBUG_PRINT("info", ("file_name: %s", m_file_name));

    if ((m_file= fopen(m_file_name, "wb+")) == NULL)
      die("Failed to open log file %s, errno: %d", m_file_name, errno);

    DBUG_VOID_RETURN;
  }

Project: server

void open_file(const char *name)
{
  char buff[FN_REFLEN];
  size_t length;
  const char *curname= cur_file->file_name;
  DBUG_ENTER("open_file");
  DBUG_PRINT("enter", ("name: %s", name));

  if (cur_file == file_stack_end)
    die("Source directives are nesting too deep");

  if (test_if_hard_path(name))
  {
    if (open_and_set_current(name))
      DBUG_VOID_RETURN;
  }
  else
  {
    /*
      if overlay-dir is specified, and the file is located somewhere
      under overlay-dir or under suite-dir, the search works as follows:

      0.let suffix be current file dirname relative to siute-dir or overlay-dir
      1.try in overlay-dir/suffix
      2.try in suite-dir/suffix
      3.try in overlay-dir
      4.try in suite-dir
      5.try in basedir

        consider an example: 'rty' overlay of the 'qwe' suite,
        file qwe/include/some.inc contains the line
          --source thing.inc
        we look for it in this order:
        0.suffix is "include/"
        1.try in rty/include/thing.inc
        2.try in qwe/include/thing.inc
        3.try in try/thing.inc             | this is useful when t/a.test has
        4.try in qwe/thing.inc             | source include/b.inc;
        5.try in mysql-test/include/thing.inc

      otherwise the search is as follows
      1.try in current file dirname
      3.try in overlay-dir (if any)
      4.try in suite-dir
      5.try in basedir
    */

#ifdef __WIN__
    fix_win_paths(curname, sizeof(curname));
#endif

    bool in_overlay= opt_overlay_dir &&
                     !strncmp(curname, opt_overlay_dir, overlay_dir_len);
    bool in_suiteir= opt_overlay_dir && !in_overlay &&
                     !strncmp(curname, opt_suite_dir, suite_dir_len);
    if (in_overlay || in_suiteir)
    {
      size_t prefix_len = in_overlay ? overlay_dir_len : suite_dir_len;
      char buf2[FN_REFLEN], *suffix= buf2 + prefix_len;
      dirname_part(buf2, curname, &length);

      /* 1. first we look in the overlay dir */
      strxnmov(buff, sizeof(buff), opt_overlay_dir, suffix, name, NullS);

      /*
        Overlayed rty/include/thing.inc can contain the line
        --source thing.inc
        which would mean to include qwe/include/thing.inc.
        But it looks like including "itself", so don't try to open the file,
        if buff contains the same file name as curname.
      */
      if (strcmp(buff, curname) && open_and_set_current(buff))
        DBUG_VOID_RETURN;

      /* 2. if that failed, we look in the suite dir */
      strxnmov(buff, sizeof(buff), opt_suite_dir, suffix, name, NullS);

      /* buff can not be equal to curname, as a file can never include itself */
      if (open_and_set_current(buff))
        DBUG_VOID_RETURN;
    }
    else
    {
      /* 1. try in current file dirname */
      dirname_part(buff, curname, &length);
      strxnmov(buff, sizeof(buff), buff, name, NullS);
      if (open_and_set_current(buff))
        DBUG_VOID_RETURN;
    }

    /* 3. now, look in the overlay dir */
    if (opt_overlay_dir)
    {
      strxmov(buff, opt_overlay_dir, name, NullS);
      if (open_and_set_current(buff))
        DBUG_VOID_RETURN;
    }

    /* 4. if that failed - look in the suite dir */
    strxmov(buff, opt_suite_dir, name, NullS);
    if (open_and_set_current(buff))
      DBUG_VOID_RETURN;
    
    /* 5. the last resort - look in the base dir */
    strxnmov(buff, sizeof(buff), opt_basedir, name, NullS);
    if (open_and_set_current(buff))
      DBUG_VOID_RETURN;
  }

  die("Could not open '%s' for reading, errno: %d", name, errno);
  DBUG_VOID_RETURN;
}

Project: server

void get_command_type(struct st_command* command)
{
  char save;
  uint type;
  DBUG_ENTER("get_command_type");

  if (*command->query == '}')
  {
    command->type = Q_END_BLOCK;
    DBUG_VOID_RETURN;
  }

  save= command->query[command->first_word_len];
  command->query[command->first_word_len]= 0;
  type= find_type(command->query, &command_typelib, FIND_TYPE_NO_PREFIX);
  command->query[command->first_word_len]= save;
  if (type > 0)
  {
    command->type=(enum enum_commands) type;		/* Found command */

    /*
      Look for case where "query" was explicitly specified to
      force command being sent to server
    */
    if (type == Q_QUERY)
    {
      /* Skip the "query" part */
      command->query= command->first_argument;
    }
  }
  else
  {
    /* No mysqltest command matched */

    if (command->type != Q_COMMENT_WITH_COMMAND)
    {
      /* A query that will sent to mysqld */
      command->type= Q_QUERY;
    }
    else
    {
      /* -- "comment" that didn't contain a mysqltest command */
      report_or_die("Found line beginning with --  that didn't contain " \
          "a valid mysqltest command, check your syntax or "            \
          "use # if you intended to write a comment");
      command->type= Q_COMMENT;
    }
  }

  /* Set expected error on command */
  memcpy(&command->expected_errors, &saved_expected_errors,
         sizeof(saved_expected_errors));
  DBUG_PRINT("info", ("There are %d expected errors",
                      command->expected_errors.count));
  DBUG_VOID_RETURN;
}

Project: server

int parse_args(int argc, char **argv)
{
  if (load_defaults("my",load_default_groups,&argc,&argv))
    exit(1);

  default_argv= argv;

  if ((handle_options(&argc, &argv, my_long_options, get_one_option)))
    exit(1);

  if (argc > 1)
  {
    usage();
    exit(1);
  }
  if (argc == 1)
    opt_db= *argv;
  if (tty_password)
    opt_pass= get_tty_password(NullS);          /* purify tested */
  if (debug_info_flag)
    my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO;
  if (debug_check_flag)
    my_end_arg|= MY_CHECK_ERROR;

  if (global_subst != NULL)
  {
    char *comma= strstr(global_subst, ",");
    if (comma == NULL)
      die("wrong --global-subst, must be X,Y");
    memcpy(global_subst_from, global_subst, (comma-global_subst));
    global_subst_from[comma-global_subst]= 0;
    memcpy(global_subst_to, comma+1, strlen(comma));
  }

  if (!opt_suite_dir)
    opt_suite_dir= "./";
  suite_dir_len= strlen(opt_suite_dir);
  overlay_dir_len= opt_overlay_dir ? strlen(opt_overlay_dir) : 0;

  if (!record)
  {
    /* Check that the result file exists */
    if (result_file_name && access(result_file_name, F_OK) != 0)
      die("The specified result file '%s' does not exist",
          result_file_name);
  }

  return 0;
}

Project: server

uint get_errcode_from_name(const char *error_name, const char *error_end)
{
  uint tmp;
  if ((tmp= get_errcode_from_name(error_name, error_end,
                                     global_error_names)))
    return tmp;
  if ((tmp= get_errcode_from_name(error_name, error_end,
                                     handler_error_names)))
    return tmp;
  die("Unknown SQL error name '%s'", error_name);
}

Project: server

int do_modify_var(struct st_command *command,
                  enum enum_operator op)
{
  const char *p= command->first_argument;
  VAR* v;
  if (!*p)
    die("Missing argument to %.*s", command->first_word_len,
        command->query);
  if (*p != '$')
    die("The argument to %.*s must be a variable (start with $)",
        command->first_word_len, command->query);
  v= var_get(p, &p, 1, 0);
  if (! v->is_int)
    die("Cannot perform inc/dec on a non-numeric value");
  switch (op) {
  case DO_DEC:
    v->int_val--;
    break;
  case DO_INC:
    v->int_val++;
    break;
  default:
    die("Invalid operator to do_modify_var");
    break;
  }
  v->int_dirty= true;
  command->last_argument= (char*)++p;
  return 0;
}

Project: server

void replace_strings_append(REPLACE *rep, DYNAMIC_STRING* ds,
                            const char *str,
                            int len __attribute__((unused)))
{
  reg1 REPLACE *rep_pos;
  reg2 REPLACE_STRING *rep_str;
  const char *start, *from;
  DBUG_ENTER("replace_strings_append");

  start= from= str;
  rep_pos=rep+1;
  for (;;)
  {
    /* Loop through states */
    DBUG_PRINT("info", ("Looping through states"));
    while (!rep_pos->found)
      rep_pos= rep_pos->next[(uchar) *from++];

    /* Does this state contain a string to be replaced */
    if (!(rep_str = ((REPLACE_STRING*) rep_pos))->replace_string)
    {
      /* No match found */
      dynstr_append_mem(ds, start, from - start - 1);
      DBUG_PRINT("exit", ("Found no more string to replace, appended: %s", start));
      DBUG_VOID_RETURN;
    }

    /* Found a string that needs to be replaced */
    DBUG_PRINT("info", ("found: %d, to_offset: %u, from_offset: %d, string: %s",
                        rep_str->found, rep_str->to_offset,
                        rep_str->from_offset, rep_str->replace_string));

    /* Append part of original string before replace string */
    dynstr_append_mem(ds, start, (from - rep_str->to_offset) - start);

    /* Append replace string */
    dynstr_append_mem(ds, rep_str->replace_string,
                      strlen(rep_str->replace_string));

    if (!*(from-=rep_str->from_offset) && rep_pos->found != 2)
    {
      /* End of from string */
      DBUG_PRINT("exit", ("Found end of from string"));
      DBUG_VOID_RETURN;
    }
    DBUG_ASSERT(from <= str+len);
    start= from;
    rep_pos=rep;
  }
}

Project: server

bool open_and_set_current(const char *name)
{
  FILE *opened= fopen(name, "rb");

  if (!opened)
    return false;

  cur_file++;
  cur_file->file= opened;
  cur_file->file_name= my_strdup(name, MYF(MY_FAE));
  cur_file->lineno=1;
  return true;
}

Project: server

size_t print_file_stack(char *s, const char *end)
{
  char *start= s;
  struct st_test_file* err_file= cur_file;
  if (err_file == file_stack)
    return 0;

  for (;;)
  {
    err_file--;
    s+= my_snprintf(s, end - s, "included from %s at line %d:\n",
                     err_file->file_name, err_file->lineno);
    if (err_file == file_stack)
      break;
  }
  return s - start;
}

Project: server

void handle_command_error(struct st_command *command, uint error,
                          int sys_errno)
{
  DBUG_ENTER("handle_command_error");
  DBUG_PRINT("enter", ("error: %d", error));
  var_set_int("$sys_errno",sys_errno);
  var_set_int("$errno",error);
  if (error != 0)
  {
    int i;

    if (command->abort_on_error)
    {
      report_or_die("command \"%.*s\" failed with error: %u  my_errno: %d  "
                    "errno: %d",
          command->first_word_len, command->query, error, my_errno,
          sys_errno);
      DBUG_VOID_RETURN;
    }

    i= match_expected_error(command, error, NULL);

    if (i >= 0)
    {
      DBUG_PRINT("info", ("command \"%.*s\" failed with expected error: %u, errno: %d",
                          command->first_word_len, command->query, error,
                          sys_errno));
      revert_properties();
      DBUG_VOID_RETURN;
    }
    if (command->expected_errors.count > 0)
      report_or_die("command \"%.*s\" failed with wrong error: %u  "
                    "my_errno: %d  errno: %d",
                    command->first_word_len, command->query, error, my_errno,
                    sys_errno);
  }
  else if (command->expected_errors.err[0].type == ERR_ERRNO &&
           command->expected_errors.err[0].code.errnum != 0)
  {
    /* Error code we wanted was != 0, i.e. not an expected success */
    report_or_die("command \"%.*s\" succeeded - should have failed with "
                  "errno %d...",
        command->first_word_len, command->query,
        command->expected_errors.err[0].code.errnum);
  }
  revert_properties();
  DBUG_VOID_RETURN;
}