Commit 69f9ec28 authored by Magnus Svensson's avatar Magnus Svensson
Browse files

Merge

parents 36459fb6 32f40185
Loading
Loading
Loading
Loading
+31 −0
Original line number Diff line number Diff line
@@ -2101,6 +2101,37 @@ static bool add_line(String &buffer,char *line,char *in_string,
	continue;
      }
    }
    else if (!*ml_comment && !*in_string &&
             (end_of_line - pos) >= 10 &&
             !my_strnncoll(charset_info, (uchar*) pos, 10,
                           (const uchar*) "delimiter ", 10))
    {
      // Flush previously accepted characters
      if (out != line)
      {
        buffer.append(line, (uint32) (out - line));
        out= line;
      }

      // Flush possible comments in the buffer
      if (!buffer.is_empty())
      {
        if (com_go(&buffer, 0) > 0) // < 0 is not fatal
          DBUG_RETURN(1);
        buffer.length(0);
      }

      /*
        Delimiter wants the get rest of the given line as argument to
        allow one to change ';' to ';;' and back
      */
      buffer.append(pos);
      if (com_delimiter(&buffer, pos) > 0)
        DBUG_RETURN(1);

      buffer.length(0);
      break;
    }
    else if (!*ml_comment && !*in_string && is_prefix(pos, delimiter))
    {
      // Found a statement. Continue parsing after the delimiter
+258 −54
Original line number Diff line number Diff line
@@ -170,6 +170,8 @@ static void timer_output(void);
static ulonglong timer_now(void);


static ulong connection_retry_sleep= 100000; /* Microseconds */

/* Precompiled re's */
static my_regex_t ps_re;     /* the query can be run using PS protocol */
static my_regex_t sp_re;     /* the query can be run as a SP */
@@ -276,6 +278,7 @@ enum enum_commands {
  Q_WRITE_FILE, Q_COPY_FILE, Q_PERL, Q_DIE, Q_EXIT, Q_SKIP,
  Q_CHMOD_FILE, Q_APPEND_FILE, Q_CAT_FILE, Q_DIFF_FILES,
  Q_SEND_QUIT, Q_CHANGE_USER, Q_MKDIR, Q_RMDIR,
  Q_LIST_FILES, Q_LIST_FILES_WRITE_FILE, Q_LIST_FILES_APPEND_FILE,
  Q_SEND_SHUTDOWN, Q_SHUTDOWN_SERVER,

  Q_UNKNOWN,			       /* Unknown command.   */
@@ -368,6 +371,9 @@ const char *command_names[]=
  "change_user",
  "mkdir",
  "rmdir",
  "list_files",
  "list_files_write_file",
  "list_files_append_file",
  "send_shutdown",
  "shutdown_server",

@@ -654,6 +660,9 @@ void replace_dynstr_append(DYNAMIC_STRING *ds, const char *val);
void replace_dynstr_append_uint(DYNAMIC_STRING *ds, uint val);
void dynstr_append_sorted(DYNAMIC_STRING* ds, DYNAMIC_STRING* ds_input);

static int match_expected_error(struct st_command *command,
                                unsigned int err_errno,
                                const char *err_sqlstate);
void handle_error(struct st_command*,
                  unsigned int err_errno, const char *err_error,
                  const char *err_sqlstate, DYNAMIC_STRING *ds);
@@ -1010,30 +1019,26 @@ void check_command_args(struct st_command *command,
  DBUG_VOID_RETURN;
}


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

    if (command->abort_on_error)
      die("command \"%.*s\" failed with error %d",
          command->first_word_len, command->query, error);
    for (i= 0; i < command->expected_errors.count; i++)
    {
      DBUG_PRINT("info", ("expected error: %d",
                          command->expected_errors.err[i].code.errnum));
      if ((command->expected_errors.err[i].type == ERR_ERRNO) &&
          (command->expected_errors.err[i].code.errnum == error))

    i= match_expected_error(command, error, NULL);

    if (i >= 0)
    {
      DBUG_PRINT("info", ("command \"%.*s\" failed with expected error: %d",
                          command->first_word_len, command->query, error));
      DBUG_VOID_RETURN;
    }
    }
    die("command \"%.*s\" failed with wrong error: %d",
        command->first_word_len, command->query, error);
  }
@@ -2601,8 +2606,8 @@ void do_exec(struct st_command *command)
  error= pclose(res_file);
  if (error > 0)
  {
    uint status= WEXITSTATUS(error), i;
    my_bool ok= 0;
    uint status= WEXITSTATUS(error);
    int i;

    if (command->abort_on_error)
    {
@@ -2614,19 +2619,13 @@ void do_exec(struct st_command *command)

    DBUG_PRINT("info",
               ("error: %d, status: %d", error, status));
    for (i= 0; i < command->expected_errors.count; i++)
    {
      DBUG_PRINT("info", ("expected error: %d",
                          command->expected_errors.err[i].code.errnum));
      if ((command->expected_errors.err[i].type == ERR_ERRNO) &&
          (command->expected_errors.err[i].code.errnum == status))
      {
        ok= 1;

    i= match_expected_error(command, status, NULL);

    if (i >= 0)
      DBUG_PRINT("info", ("command \"%s\" failed with expected error: %d",
                          command->first_argument, status));
      }
    }
    if (!ok)
    else
    {
      dynstr_free(&ds_cmd);
      die("command \"%s\" failed with wrong error: %d",
@@ -2976,6 +2975,126 @@ void do_rmdir(struct st_command *command)
}


/*
  SYNOPSIS
  get_list_files
  ds          output
  ds_dirname  dir to list
  ds_wild     wild-card file pattern (can be empty)

  DESCRIPTION
  list all entries in directory (matching ds_wild if given)
*/

static int get_list_files(DYNAMIC_STRING *ds, const DYNAMIC_STRING *ds_dirname,
                          const DYNAMIC_STRING *ds_wild)
{
  uint i;
  MY_DIR *dir_info;
  FILEINFO *file;
  DBUG_ENTER("get_list_files");

  DBUG_PRINT("info", ("listing directory: %s", ds_dirname->str));
  /* Note that my_dir sorts the list if not given any flags */
  if (!(dir_info= my_dir(ds_dirname->str, MYF(0))))
    DBUG_RETURN(1);
  for (i= 0; i < (uint) dir_info->number_off_files; i++)
  {
    file= dir_info->dir_entry + i;
    if (file->name[0] == '.' &&
        (file->name[1] == '\0' ||
         (file->name[1] == '.' && file->name[2] == '\0')))
      continue;                               /* . or .. */
    if (ds_wild && ds_wild->length &&
        wild_compare(file->name, ds_wild->str, 0))
      continue;
    dynstr_append(ds, file->name);
    dynstr_append(ds, "\n");
  }
  my_dirend(dir_info);
  DBUG_RETURN(0);
}


/*
  SYNOPSIS
  do_list_files
  command	called command

  DESCRIPTION
  list_files <dir_name> [<file_name>]
  List files and directories in directory <dir_name> (like `ls`)
  [Matching <file_name>, where wild-cards are allowed]
*/

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");

  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);
  dynstr_free(&ds_dirname);
  dynstr_free(&ds_wild);
  DBUG_VOID_RETURN;
}


/*
  SYNOPSIS
  do_list_files_write_file_command
  command       called command
  append        append file, or create new

  DESCRIPTION
  list_files_{write|append}_file <filename> <dir_name> [<match_file>]
  List files and directories in directory <dir_name> (like `ls`)
  [Matching <match_file>, where wild-cards are allowed]

  Note: File will be truncated if exists and append is not true.
*/

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");

  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);
  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;
}


/*
  Read characters from line buffer or file. This is needed to allow
  my_ungetc() to buffer MAX_DELIMITER_LENGTH characters for a file
@@ -4458,7 +4577,6 @@ void safe_connect(MYSQL* mysql, const char *name, const char *host,
                  int port, const char *sock)
{
  int failed_attempts= 0;
  static ulong connection_retry_sleep= 100000; /* Microseconds */

  DBUG_ENTER("safe_connect");
  while(!mysql_real_connect(mysql, host,user, pass, db, port, sock,
@@ -4525,6 +4643,7 @@ int connect_n_handle_errors(struct st_command *command,
                            const char* db, int port, const char* sock)
{
  DYNAMIC_STRING *ds;
  int failed_attempts= 0;

  ds= &ds_res;

@@ -4553,9 +4672,41 @@ int connect_n_handle_errors(struct st_command *command,
    dynstr_append_mem(ds, delimiter, delimiter_length);
    dynstr_append_mem(ds, "\n", 1);
  }
  if (!mysql_real_connect(con, host, user, pass, db, port, sock ? sock: 0,
  while (!mysql_real_connect(con, host, user, pass, db, port, sock ? sock: 0,
                          CLIENT_MULTI_STATEMENTS))
  {
    /*
      If we have used up all our connections check whether this
      is expected (by --error). If so, handle the error right away.
      Otherwise, give it some extra time to rule out race-conditions.
      If extra-time doesn't help, we have an unexpected error and
      must abort -- just proceeding to handle_error() when second
      and third chances are used up will handle that for us.

      There are various user-limits of which only max_user_connections
      and max_connections_per_hour apply at connect time. For the
      the second to create a race in our logic, we'd need a limits
      test that runs without a FLUSH for longer than an hour, so we'll
      stay clear of trying to work out which exact user-limit was
      exceeded.
    */

    if (((mysql_errno(con) == ER_TOO_MANY_USER_CONNECTIONS) ||
         (mysql_errno(con) == ER_USER_LIMIT_REACHED)) &&
        (failed_attempts++ < opt_max_connect_retries))
    {
      int i;

      i= match_expected_error(command, mysql_errno(con), mysql_sqlstate(con));

      if (i >= 0)
        goto do_handle_error;                 /* expected error, handle */

      my_sleep(connection_retry_sleep);       /* unexpected error, wait */
      continue;                               /* and give it 1 more chance */
    }

do_handle_error:
    var_set_errno(mysql_errno(con));
    handle_error(command, mysql_errno(con), mysql_error(con),
		 mysql_sqlstate(con), ds);
@@ -6265,6 +6416,56 @@ void run_query_normal(struct st_connection *cn, struct st_command *command,
}


/*
  Check whether given error is in list of expected errors

  SYNOPSIS
    match_expected_error()

  PARAMETERS
    command        the current command (and its expect-list)
    err_errno      error number of the error that actually occurred
    err_sqlstate   SQL-state that was thrown, or NULL for impossible
                   (file-ops, diff, etc.)

  RETURNS
    -1 for not in list, index in list of expected errors otherwise

  NOTE
    If caller needs to know whether the list was empty, they should
    check command->expected_errors.count.
*/

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;
}


/*
  Handle errors which occurred during execution

@@ -6285,7 +6486,7 @@ void handle_error(struct st_command *command,
                  unsigned int err_errno, const char *err_error,
                  const char *err_sqlstate, DYNAMIC_STRING *ds)
{
  uint i;
  int i;

  DBUG_ENTER("handle_error");

@@ -6311,13 +6512,10 @@ void handle_error(struct st_command *command,

  DBUG_PRINT("info", ("expected_errors.count: %d",
                      command->expected_errors.count));
  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)) ||
        ((command->expected_errors.err[i].type == ERR_SQLSTATE) &&
         (strncmp(command->expected_errors.err[i].code.sqlstate,
                  err_sqlstate, SQLSTATE_LENGTH) == 0)))

  i= match_expected_error(command, err_errno, err_sqlstate);

  if (i >= 0)
  {
    if (!disable_result_log)
    {
@@ -6339,7 +6537,6 @@ void handle_error(struct st_command *command,
    /* OK */
    DBUG_VOID_RETURN;
  }
  }

  DBUG_PRINT("info",("i: %d  expected_errors: %d", i,
                     command->expected_errors.count));
@@ -6353,7 +6550,7 @@ void handle_error(struct st_command *command,
    dynstr_append_mem(ds, "\n", 1);
  }

  if (i)
  if (command->expected_errors.count > 0)
  {
    if (command->expected_errors.err[0].type == ERR_ERRNO)
      die("query '%s' failed with wrong errno %d: '%s', instead of %d...",
@@ -7375,6 +7572,13 @@ int main(int argc, char **argv)
      case Q_REMOVE_FILE: do_remove_file(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;
+5 −5
Original line number Diff line number Diff line
@@ -617,19 +617,19 @@ fi
AC_MSG_CHECKING(whether features provided by the user community should be included.)
AC_ARG_ENABLE(community-features,
    AC_HELP_STRING(
        [--enable-community-features], 
        [Enable additional features provided by the user community.]),
        [--disable-community-features], 
        [Disable additional features provided by the user community.]),
    [ ENABLE_COMMUNITY_FEATURES=$enableval ],
    [ ENABLE_COMMUNITY_FEATURES=no ]
    [ ENABLE_COMMUNITY_FEATURES=yes ]
    )

if test "$ENABLE_COMMUNITY_FEATURES" = "yes"
then
  AC_DEFINE([COMMUNITY_SERVER], [1],
            [Whether features provided by the user community should be included])
  AC_MSG_RESULT([yes, community server])
  AC_MSG_RESULT([yes])
else
  AC_MSG_RESULT([no, enterprise server])
  AC_MSG_RESULT([no])
fi

AC_ARG_WITH(server-suffix,
+1 −0
Original line number Diff line number Diff line
@@ -693,6 +693,7 @@ extern char * fn_format(char * to,const char *name,const char *dir,
			   const char *form, uint flag);
extern size_t strlength(const char *str);
extern void pack_dirname(char * to,const char *from);
extern size_t normalize_dirname(char * to, const char *from);
extern size_t unpack_dirname(char * to,const char *from);
extern size_t cleanup_dirname(char * to,const char *from);
extern size_t system_filename(char * to,const char *from);
+2 −1
Original line number Diff line number Diff line
@@ -447,7 +447,8 @@ int emb_load_querycache_result(THD *thd, Querycache_stream *src)
  if (thd->protocol == &thd->protocol_binary)
  {
    uint length;
    row= (MYSQL_ROWS *)alloc_root(&data->alloc, rows * sizeof(MYSQL_ROWS));
    row= (MYSQL_ROWS *)alloc_root(&data->alloc,
                                  (size_t) (rows * sizeof(MYSQL_ROWS)));
    end_row= row + rows;
    data->data= row;

Loading