From 2b7f8f29171f97f18c478b8190c21c1ec409fd6c Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Mon, 27 Feb 2017 06:03:59 -0500 Subject: [PATCH 01/16] MDEV-12192: Shell-style alias/unalias commands for MariaDB client --- client/mysql.cc | 561 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 558 insertions(+), 3 deletions(-) diff --git a/client/mysql.cc b/client/mysql.cc index 5beff40d982e6..3b2438487c04e 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -214,6 +214,7 @@ static void my_vidattr(chtype attrs) #include "completion_hash.h" #include // ORACLE_WELCOME_COPYRIGHT_NOTICE +#include "hash.h" #define PROMPT_CHAR '\\' #define DEFAULT_DELIMITER ";" @@ -302,6 +303,8 @@ unsigned short terminal_width= 80; static uint opt_protocol=0; static const char *opt_protocol_type= ""; +static HASH aliases; /* Aliases. */ + #include "sslopt-vars.h" const char *default_dbug_option="d:t:o,/tmp/mariadb.trace"; @@ -324,8 +327,11 @@ static int com_quit(String *str,char*), com_rehash(String *str, char*), com_tee(String *str, char*), com_notee(String *str, char*), com_charset(String *str,char*), com_prompt(String *str, char*), com_delimiter(String *str, char*), - com_warnings(String *str, char*), com_nowarnings(String *str, char*); + com_warnings(String *str, char*), com_nowarnings(String *str, char*), + com_alias(String *str, char*), com_unalias(String *str, char*); static int com_query_cost(String *str, char*); +static int init_alias(); +static int deinit_alias(); #ifdef USE_POPEN static int com_nopager(String *str, char*), com_pager(String *str, char*), @@ -373,6 +379,7 @@ typedef struct { static COMMANDS commands[] = { { "?", '?', com_help, 1, "Synonym for `help'." }, + { "alias", 'a', com_alias, 1, "Print or add aliases." }, { "clear", 'c', com_clear, 0, "Clear the current input statement."}, { "connect",'r', com_connect,1, "Reconnect to the server. Optional arguments are db and host." }, @@ -408,6 +415,7 @@ static COMMANDS commands[] = { #endif { "tee", 'T', com_tee, 1, "Set outfile [to_outfile]. Append everything into given outfile." }, + { "unalias",'A', com_unalias,1, "Remove aliases." }, { "use", 'u', com_use, 1, "Use another database. Takes database name as argument." }, { "charset", 'C', com_charset, 1, @@ -1285,6 +1293,10 @@ int main(int argc,char *argv[]) my_end(0); exit(1); } + + /* Init alias hash. */ + init_alias(); + if (mysql_server_init(embedded_server_arg_count, embedded_server_args, (char**) embedded_server_groups)) { @@ -1392,6 +1404,10 @@ int main(int argc,char *argv[]) "Type 'help;' or '\\h' for help. Type '\\c' to clear the current input statement.\n"); put_info(buff,INFO_INFO); status.exit_status= read_and_execute(!status.batch); + + /* Free alias hash. */ + deinit_alias(); + if (opt_outfile) end_tee(); mysql_end(0); @@ -3460,6 +3476,14 @@ com_charset(String *buffer __attribute__((unused)), char *line) return 0; } + +typedef struct { + char *name; + int name_len; + char *value; +} ALIAS; + + /* Execute command Returns: 0 if ok @@ -3478,6 +3502,8 @@ com_go(String *buffer,char *line __attribute__((unused))) ulong warnings= 0; uint error= 0; int err= 0; + char *alias_end= 0; + int alias_len; interrupted_query= 0; if (!status.batch) @@ -3502,11 +3528,32 @@ com_go(String *buffer,char *line __attribute__((unused))) buffer->length(0); // Remove query on error return opt_reconnect ? -1 : 1; // Fatal error } + + if ((alias_end= strchr((char *)(buffer->ptr()), ' '))) + { + alias_len= alias_end - buffer->ptr(); + } + else + { + alias_len= buffer->length(); + } + if (verbose) (void) com_print(buffer,0); + ALIAS *alias_element= (ALIAS *) my_hash_search(&aliases, (const uchar*) + buffer->ptr(), alias_len); + String aliased_buffer; + if (alias_element) + { + aliased_buffer.copy(alias_element->value, strlen(alias_element->value), + charset_info); + } + + aliased_buffer.append(alias_end, buffer->length() - alias_len); + if (skip_updates && - (buffer->length() < 4 || charset_info->strnncoll((const uchar*)buffer->ptr(),4, + (buffer->length() < 4 || charset_info->strnncoll((const uchar*)aliased_buffer->ptr(),4, (const uchar*)"SET ",4))) { (void) put_info("Ignoring query to other database",INFO_INFO); @@ -3515,7 +3562,8 @@ com_go(String *buffer,char *line __attribute__((unused))) timer= microsecond_interval_timer(); executing_query= 1; - error= mysql_real_query_for_lazy(buffer->ptr(),buffer->length()); + error= mysql_real_query_for_lazy(aliased_buffer.ptr(), + aliased_buffer.length()); report_progress_end(); #ifdef HAVE_READLINE @@ -3529,6 +3577,7 @@ com_go(String *buffer,char *line __attribute__((unused))) #endif buffer->length(0); + aliased_buffer.length(0); if (error) goto end; @@ -5718,6 +5767,512 @@ static int com_prompt(String *buffer __attribute__((unused)), return 0; } +static uchar *get_alias_key(const uchar *var, size_t *len, + my_bool __attribute__((unused)) t) +{ + register char *key; + key= ((ALIAS *)var)->name; + *len= ((ALIAS *)var)->name_len; + return (uchar *) key; +} + +static void alias_free(void *v) +{ + ALIAS *alias= (ALIAS *) v; + my_free(alias->name); + my_free(alias->value); + my_free(alias); +} + +static char *parse_alias_name(char *line, char **out, bool *is_valid) +{ + char *beg, *end, *pos, *name; + bool single_quoted= false, double_quoted= false, quoted= false; + size_t len; + + *is_valid= false; + beg= pos= line; + + if (*pos == '\'') + { + quoted= single_quoted= true; + pos ++; + beg= pos; + } + else if (*pos == '\"') + { + quoted= double_quoted= true; + pos ++; + beg= pos; + } + + while ((my_isalpha(charset_info, *pos)) || + (quoted && my_isspace(charset_info, *pos)) || + *pos == '-' || + *pos == '_') + { + pos ++; + } + + if (*pos) + { + /* Terminal characters. */ + switch (*pos) { + case '=': /* fallthrough */ + case ' ': /* fallthrough */ + case '\t': + if (!quoted) *is_valid= true; + end= pos; + break; + case '\'': + if (single_quoted && (my_isspace(charset_info, *(pos + 1)) || + (*(pos + 1) == '=') || + (*(pos + 1) == 0))) + { + *is_valid= true; + end= pos; + pos ++; + break; + } + while (!my_isspace(charset_info, *pos)) pos ++; + end= pos; + break; + case '\"': + if (double_quoted && (my_isspace(charset_info, *(pos + 1)) || + (*(pos + 1) == '=') || + (*(pos + 1) == 0))) + { + *is_valid= true; + end= pos; + pos ++; + break; + } + *is_valid= false; + while (!my_isspace(charset_info, *pos)) pos ++; + end= pos; + break; + default: + /* Its an invalid entry. Lets move until we find a space. */ + *is_valid= false; + while (!my_isspace(charset_info, *pos)) pos ++; + end= pos; + } + } + else + { + /* We have reached the end. */ + if (!quoted) *is_valid= true; + end= pos; + } + + len= end - beg; assert(len > 0); + name= (char *) my_malloc(len + 1, MYF(MY_WME)); + memcpy(name, beg, len); + name[len]= 0; + *out= name; + return pos; +} + +static char *parse_alias_value(char *line, char **out, bool *is_valid) +{ + char *beg, *end, *pos, *value; + bool single_quoted= false, double_quoted= false, quoted= false; + size_t len; + + *is_valid= false; + beg= pos= line; + + if (*pos == '\'') + { + quoted= single_quoted= true; + pos ++; + beg= pos; + } + else if (*pos == '\"') + { + quoted= double_quoted= true; + pos ++; + beg= pos; + } + + while (*pos && my_isprint(charset_info, *pos)) + { + if (!quoted && (*pos == ' ' || *pos == '\t')) + { + break; + } + else if (single_quoted && *pos == '\'' && *(pos - 1) != '\\') + { + quoted= false; + break; + } + else if (double_quoted && *pos == '\"' && *(pos - 1) != '\\') + { + quoted= false; + break; + } + pos ++; + } + + if (*pos) + { + switch (*pos) { + case ' ': + /* fallthrough */ + case '\t': + if (!quoted) *is_valid= true; + end= pos; + break; + case '\'': + if (single_quoted && (my_isspace(charset_info, *(pos + 1)) || + *(pos + 1) == 0)) + { + *is_valid= true; + end= pos; + pos ++; + break; + } + while (!my_isspace(charset_info, *pos)) pos ++; + end= pos; + break; + case '\"': + if (double_quoted && (my_isspace(charset_info, *(pos + 1)) || + *(pos + 1) == 0)) + { + *is_valid= true; + end= pos; + pos ++; + break; + } + while (!my_isspace(charset_info, *pos)) pos ++; + end= pos; + break; + default: + /* Its an invalid entry. Lets move until we find a space. */ + while (!my_isspace(charset_info, *pos)) pos ++; + end= pos; + } + } + else + { + /* We have reached the end. */ + if (!quoted) *is_valid= true; + end= pos; + } + + len= end - beg; + value= (char *) my_malloc(len + 1, MYF(MY_WME)); + memcpy(value, beg, len); + value[len]= 0; + *out= value; + return pos; +} + +static char *handle_next_alias(char *line, bool *error) +{ + ALIAS *alias; + char *name, *value, *pos; + bool is_valid; + size_t name_len; + uchar *record; + + /* Parse the alias name. */ + pos= parse_alias_name(line, &name, &is_valid); + + if (!is_valid) + { + tee_fprintf(stdout, "alias: '%s': invalid alias name\n", name); + *error= true; + } + else + { + /* TODO: A non-alphanumeric alias name is invalid. */ + + /* + We have a valid alias name. Lets check if there is a value being + assigned to it. (Note: there mustn't be spaces around '='.) + */ + name_len= strlen(name); + + if (*pos == '=') + { + pos ++; + pos= parse_alias_value(pos, &value, &is_valid); + + if (!is_valid) + { + tee_fprintf(stdout, "alias: '%s': invalid alias name\n", name); + } + else + { + /* + We now have a valid name and value, let add/update the + aliases hash. + */ + + if ((record= my_hash_search(&aliases, (const uchar *) name, name_len))) + { + my_hash_delete(&aliases, record); + } + alias= (ALIAS *) my_malloc(sizeof(ALIAS), MYF(MY_WME)); + alias->name= name; + alias->name_len= name_len; + alias->value= value; + my_hash_insert(&aliases, (uchar *) alias); + } + } + else + { + /* Only alias name specified, lookup, print its value and return. */ + alias= (ALIAS *) my_hash_search(&aliases, (const uchar*) name, + name_len); + if (alias) + { + tee_fprintf(stdout, "alias %s = '%s'\n", alias->name, alias->value); + } + else + { + tee_fprintf(stdout, "alias: '%s': not found\n", name); + } + } + *error= false; + } + return pos; +} + +static char *handle_next_unalias(char *line, bool *error) +{ + char *name, *pos; + uchar *record; + bool is_valid; + + /* Parse the alias name. */ + pos= parse_alias_name(line, &name, &is_valid); + + if (!is_valid) + { + tee_fprintf(stdout, "unalias: '%s': invalid alias name\n", name); + *error= true; + } + else + { + if ((record= my_hash_search(&aliases, (const uchar *) name, strlen(name)))) + { + my_hash_delete(&aliases, record); + } + else + { + tee_fprintf(stdout, "unalias: '%s': not found\n", name); + } + *error= false; + } + return pos; +} +static int init_alias() +{ + FILE *file= 0; + char *mariadbrc_file; + char *line= 0; + char *ptr; + size_t len= 0; + ssize_t read; + MY_STAT stat_arg; + bool error; + int pos; + + /* Initialize the hash structure to store aliases. */ + if (my_hash_init2(&aliases, 64, charset_info, + 64, 0, 0, get_alias_key, 0, + alias_free, MYF(0))) + { + put_info("Couldn't initialize hash to store aliases.", INFO_ERROR); + exit(1); + } + + /* + Read alias commands from mariadbrc file. + */ + if (getenv("MARIADBRC_FILE")) + { + mariadbrc_file= my_strdup(getenv("MARIADBRC_FILE"), MYF(MY_WME)); + } + else if (getenv("HOME")) + { + mariadbrc_file= (char*) my_malloc((uint) strlen(getenv("HOME")) + + (uint) strlen("/.mariadbrc") + + 2, MYF(MY_WME)); + if (mariadbrc_file) + sprintf(mariadbrc_file, "%s/.mariadbrc", getenv("HOME")); + } + + if (mariadbrc_file == 0) + { + put_info("out-of-memory!", INFO_ERROR); + exit(1); + } + + /* Check if mariadbrc file exists. */ + if (!my_stat(mariadbrc_file, &stat_arg, MYF(MY_WME))) + goto cleanup; /* Do nothing */ + + if (!(file= my_fopen(mariadbrc_file, O_RDONLY, MYF(MY_WME)))) + { + put_info("Failed to open .mariadbrc file: ", INFO_ERROR); + put_info(strerror(errno), INFO_ERROR, errno); + exit(1); + } + + while ((read= getline(&line, &len, file))) + { + if (read == -1) /* EOF/Error */ + { + if (errno == 0) + break; + + put_info("Failed to read from .mariadbrc file: ", INFO_ERROR); + put_info(strerror(errno), INFO_ERROR, errno); + exit(1); + } + + /* Remove trailing newline character. */ + pos= read; + while (--pos && pos > 0 && my_iscntrl(charset_info, line[pos])) + line[pos]= 0; + + ptr= line; + + /* Remove leading whitespaces. */ + while (*ptr && my_isspace(charset_info, *ptr)) + ptr ++; + + if (strncasecmp(ptr, "alias", 5) == 0) + { + + /* Move past "alias" */ + ptr += 5; + while (*ptr && my_isspace(charset_info, *ptr)) + ptr ++; + + /* There are more arguments to handle. */ + while (*ptr) + { + ptr= handle_next_alias(ptr, &error); + + if (error) + exit(1); + + /* Bypass the spaces. */ + while (*ptr && my_isspace(charset_info, *ptr)) ptr ++; + } + + } + else if (strncasecmp(ptr, "unalias", 7) == 0) + { + /* Move past "unalias" */ + ptr += 7; + while (*ptr && my_isspace(charset_info, *ptr)) + ptr ++; + + /* There are more arguments to handle. */ + while (*ptr) + { + ptr= handle_next_unalias(ptr, &error); + + if (error) + exit(1); + + /* Bypass the spaces. */ + while (*ptr && my_isspace(charset_info, *ptr)) ptr ++; + } + } + } + + if (line) + free(line); + + if (file) + my_fclose(file, MYF(0)); + +cleanup: + if (mariadbrc_file) + my_free(mariadbrc_file); + + return 0; +} + +static int deinit_alias() +{ + my_hash_free(&aliases); + return 0; +} + +static int com_alias(String *buffer __attribute__((unused)), + char *line) +{ + char *ptr= line; + bool unused; + + /* Move past "alias" and spaces. */ + if ((ptr= strchr(line, ' '))) + { + while (*ptr && my_isspace(charset_info, *ptr)) + ptr ++; + } + + if ((!ptr) || (*ptr == 0)) + { + /* Only alias command specified, print all aliases and return. */ + ALIAS *alias; + ulong i= 0; + + while ((alias= (ALIAS *) my_hash_element(&aliases, i++))) + { + tee_fprintf(stdout, "alias %s = '%s'\n", alias->name, alias->value); + } + return 0; + } + + /* There are more arguments to handle. */ + while (*ptr) + { + ptr= handle_next_alias(ptr, &unused); + + /* Bypass the spaces. */ + while (*ptr && my_isspace(charset_info, *ptr)) ptr ++; + } + return 0; +} + +static int com_unalias(String *buffer __attribute__((unused)), + char *line) +{ + char *ptr= line; + bool unused; + + /* Move past "unalias" and spaces. */ + if ((ptr= strchr(line, ' '))) + { + while (*ptr && my_isspace(charset_info, *ptr)) + ptr ++; + } + + if ((!ptr) || (*ptr == 0)) + { + tee_fprintf(stdout, "unalias: no alias specified\n"); + return 0; + } + + /* There are more arguments to handle. */ + while (*ptr) + { + ptr= handle_next_unalias(ptr, &unused); + + /* Bypass the spaces. */ + while (*ptr && my_isspace(charset_info, *ptr)) ptr ++; + } + return 0; +} + #ifndef EMBEDDED_LIBRARY static void report_progress(const MYSQL *mysql, uint stage, uint max_stage, double progress, const char *proc_info, From fb4b3ae2ed357bf5f3c586bf49ac7e0e3116063d Mon Sep 17 00:00:00 2001 From: Anel Husakovic Date: Tue, 27 Sep 2022 11:08:52 +0200 Subject: [PATCH 02/16] MDEV-12912: Update per PR review and update of error messages - Apply svoj review of PR #301 - Update error message --- client/mysql.cc | 65 ++++++++++++++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 25 deletions(-) diff --git a/client/mysql.cc b/client/mysql.cc index 3b2438487c04e..af26762da9b34 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -1405,9 +1405,6 @@ int main(int argc,char *argv[]) put_info(buff,INFO_INFO); status.exit_status= read_and_execute(!status.batch); - /* Free alias hash. */ - deinit_alias(); - if (opt_outfile) end_tee(); mysql_end(0); @@ -1463,6 +1460,7 @@ sig_handler mysql_end(int sig) my_free(current_prompt); while (embedded_server_arg_count > 1) my_free(embedded_server_args[--embedded_server_arg_count]); + deinit_alias(); mysql_server_end(); free_defaults(defaults_argv); my_end(my_end_arg); @@ -3488,7 +3486,7 @@ typedef struct { Execute command Returns: 0 if ok -1 if not fatal error - 1 if fatal error + 1 if fatal error */ @@ -3577,7 +3575,6 @@ com_go(String *buffer,char *line __attribute__((unused))) #endif buffer->length(0); - aliased_buffer.length(0); if (error) goto end; @@ -5796,13 +5793,13 @@ static char *parse_alias_name(char *line, char **out, bool *is_valid) if (*pos == '\'') { quoted= single_quoted= true; - pos ++; + pos++; beg= pos; } else if (*pos == '\"') { quoted= double_quoted= true; - pos ++; + pos++; beg= pos; } @@ -5810,9 +5807,7 @@ static char *parse_alias_name(char *line, char **out, bool *is_valid) (quoted && my_isspace(charset_info, *pos)) || *pos == '-' || *pos == '_') - { - pos ++; - } + pos++; if (*pos) { @@ -5831,10 +5826,10 @@ static char *parse_alias_name(char *line, char **out, bool *is_valid) { *is_valid= true; end= pos; - pos ++; + pos++; break; } - while (!my_isspace(charset_info, *pos)) pos ++; + while (!my_isspace(charset_info, *pos)) pos++; end= pos; break; case '\"': @@ -5844,11 +5839,11 @@ static char *parse_alias_name(char *line, char **out, bool *is_valid) { *is_valid= true; end= pos; - pos ++; + pos++; break; } *is_valid= false; - while (!my_isspace(charset_info, *pos)) pos ++; + while (!my_isspace(charset_info, *pos)) pos++; end= pos; break; default: @@ -5976,12 +5971,15 @@ static char *handle_next_alias(char *line, bool *error) size_t name_len; uchar *record; + *error= false; + /* Parse the alias name. */ pos= parse_alias_name(line, &name, &is_valid); if (!is_valid) { tee_fprintf(stdout, "alias: '%s': invalid alias name\n", name); + my_free(name); *error= true; } else @@ -6001,7 +5999,8 @@ static char *handle_next_alias(char *line, bool *error) if (!is_valid) { - tee_fprintf(stdout, "alias: '%s': invalid alias name\n", name); + tee_fprintf(stdout, "alias: '%s': invalid alias value\n", value); + my_free(value); } else { @@ -6035,7 +6034,6 @@ static char *handle_next_alias(char *line, bool *error) tee_fprintf(stdout, "alias: '%s': not found\n", name); } } - *error= false; } return pos; } @@ -6086,6 +6084,8 @@ static int init_alias() alias_free, MYF(0))) { put_info("Couldn't initialize hash to store aliases.", INFO_ERROR); + free_defaults(defaults_argv); + my_end(0); exit(1); } @@ -6108,17 +6108,21 @@ static int init_alias() if (mariadbrc_file == 0) { put_info("out-of-memory!", INFO_ERROR); + free_defaults(defaults_argv); + my_end(0); exit(1); } /* Check if mariadbrc file exists. */ - if (!my_stat(mariadbrc_file, &stat_arg, MYF(MY_WME))) + if (!my_stat(mariadbrc_file, &stat_arg, MYF(ME_JUST_WARNING))) goto cleanup; /* Do nothing */ if (!(file= my_fopen(mariadbrc_file, O_RDONLY, MYF(MY_WME)))) { put_info("Failed to open .mariadbrc file: ", INFO_ERROR); put_info(strerror(errno), INFO_ERROR, errno); + free_defaults(defaults_argv); + my_end(0); exit(1); } @@ -6131,6 +6135,8 @@ static int init_alias() put_info("Failed to read from .mariadbrc file: ", INFO_ERROR); put_info(strerror(errno), INFO_ERROR, errno); + free_defaults(defaults_argv); + my_end(0); exit(1); } @@ -6159,7 +6165,11 @@ static int init_alias() ptr= handle_next_alias(ptr, &error); if (error) + { + free_defaults(defaults_argv); + my_end(0); exit(1); + } /* Bypass the spaces. */ while (*ptr && my_isspace(charset_info, *ptr)) ptr ++; @@ -6179,7 +6189,11 @@ static int init_alias() ptr= handle_next_unalias(ptr, &error); if (error) + { + free_defaults(defaults_argv); + my_end(0); exit(1); + } /* Bypass the spaces. */ while (*ptr && my_isspace(charset_info, *ptr)) ptr ++; @@ -6209,26 +6223,26 @@ static int deinit_alias() static int com_alias(String *buffer __attribute__((unused)), char *line) { - char *ptr= line; + char *ptr; bool unused; /* Move past "alias" and spaces. */ - if ((ptr= strchr(line, ' '))) + if (!(ptr= strstr(line, "alias"))) { - while (*ptr && my_isspace(charset_info, *ptr)) - ptr ++; + // Bad syntax, missing "alias" keyword + return 1; } + ptr+= 5; + while (*ptr && my_isspace(charset_info, *ptr)) ptr++; if ((!ptr) || (*ptr == 0)) { /* Only alias command specified, print all aliases and return. */ ALIAS *alias; - ulong i= 0; + size_t i= 0; while ((alias= (ALIAS *) my_hash_element(&aliases, i++))) - { tee_fprintf(stdout, "alias %s = '%s'\n", alias->name, alias->value); - } return 0; } @@ -6238,8 +6252,9 @@ static int com_alias(String *buffer __attribute__((unused)), ptr= handle_next_alias(ptr, &unused); /* Bypass the spaces. */ - while (*ptr && my_isspace(charset_info, *ptr)) ptr ++; + while (*ptr && my_isspace(charset_info, *ptr)) ptr++; } + return 0; } From b855cd97dc9204cf36dace671ff9da16150a5f49 Mon Sep 17 00:00:00 2001 From: Anel Husakovic Date: Mon, 21 Nov 2022 14:37:03 +0100 Subject: [PATCH 03/16] MDEV-12192: Further update - Alias buffer in `com_go()` should be used if an alias exist, otherwise all other queries will break. The same should happen with collations. - Check memory allocations for alias name/value - Style fixes - Add test case and result --- client/mysql.cc | 80 +++++++++++++++++--------- mysql-test/main/mariadb-aliases.result | 43 ++++++++++++++ mysql-test/main/mariadb-aliases.test | 50 ++++++++++++++++ 3 files changed, 146 insertions(+), 27 deletions(-) create mode 100644 mysql-test/main/mariadb-aliases.result create mode 100644 mysql-test/main/mariadb-aliases.test diff --git a/client/mysql.cc b/client/mysql.cc index af26762da9b34..7e3ba3e6391aa 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -3528,13 +3528,9 @@ com_go(String *buffer,char *line __attribute__((unused))) } if ((alias_end= strchr((char *)(buffer->ptr()), ' '))) - { alias_len= alias_end - buffer->ptr(); - } else - { alias_len= buffer->length(); - } if (verbose) (void) com_print(buffer,0); @@ -3546,13 +3542,15 @@ com_go(String *buffer,char *line __attribute__((unused))) { aliased_buffer.copy(alias_element->value, strlen(alias_element->value), charset_info); + aliased_buffer.append(alias_end, buffer->length() - alias_len); } - aliased_buffer.append(alias_end, buffer->length() - alias_len); - if (skip_updates && - (buffer->length() < 4 || charset_info->strnncoll((const uchar*)aliased_buffer->ptr(),4, - (const uchar*)"SET ",4))) + (buffer->length() < 4 || + charset_info->strnncoll(alias_element ? + (const uchar*) aliased_buffer->ptr() : + (const uchar*) buffer->ptr(), 4, + (const uchar*) "SET ",4))) { (void) put_info("Ignoring query to other database",INFO_INFO); return 0; @@ -3560,9 +3558,12 @@ com_go(String *buffer,char *line __attribute__((unused))) timer= microsecond_interval_timer(); executing_query= 1; - error= mysql_real_query_for_lazy(aliased_buffer.ptr(), - aliased_buffer.length()); - report_progress_end(); + if(aliased_buffer.ptr()) + error= mysql_real_query_for_lazy(aliased_buffer.ptr(), + aliased_buffer.length()); + else + error= mysql_real_query_for_lazy(buffer->ptr(),buffer->length()); +report_progress_end(); #ifdef HAVE_READLINE if (status.add_to_history) @@ -3606,9 +3607,9 @@ com_go(String *buffer,char *line __attribute__((unused))) /* Every branch must truncate buff. */ if (result) { - if (!mysql_num_rows(result) && ! quick && !column_types_flag) + if (!mysql_num_rows(result) && !quick && !column_types_flag) { - strmov(buff, "Empty set"); + strmov(buff, "Empty set"); if (opt_xml) { /* @@ -5849,7 +5850,7 @@ static char *parse_alias_name(char *line, char **out, bool *is_valid) default: /* Its an invalid entry. Lets move until we find a space. */ *is_valid= false; - while (!my_isspace(charset_info, *pos)) pos ++; + while (!my_isspace(charset_info, *pos)) pos++; end= pos; } } @@ -5860,8 +5861,19 @@ static char *parse_alias_name(char *line, char **out, bool *is_valid) end= pos; } - len= end - beg; assert(len > 0); + len= end - beg; + if (len == 0) + { + *is_valid= false; + *out= NULL; + return pos; + } name= (char *) my_malloc(len + 1, MYF(MY_WME)); + if (!name) + { + fprintf(stderr, "Couldn't allocate memory for alias name!\n"); + exit(1); + } memcpy(name, beg, len); name[len]= 0; *out= name; @@ -5880,22 +5892,20 @@ static char *parse_alias_value(char *line, char **out, bool *is_valid) if (*pos == '\'') { quoted= single_quoted= true; - pos ++; + pos++; beg= pos; } else if (*pos == '\"') { quoted= double_quoted= true; - pos ++; + pos++; beg= pos; } while (*pos && my_isprint(charset_info, *pos)) { if (!quoted && (*pos == ' ' || *pos == '\t')) - { break; - } else if (single_quoted && *pos == '\'' && *(pos - 1) != '\\') { quoted= false; @@ -5906,7 +5916,7 @@ static char *parse_alias_value(char *line, char **out, bool *is_valid) quoted= false; break; } - pos ++; + pos++; } if (*pos) @@ -5924,10 +5934,10 @@ static char *parse_alias_value(char *line, char **out, bool *is_valid) { *is_valid= true; end= pos; - pos ++; + pos++; break; } - while (!my_isspace(charset_info, *pos)) pos ++; + while (!my_isspace(charset_info, *pos)) pos++; end= pos; break; case '\"': @@ -5936,15 +5946,15 @@ static char *parse_alias_value(char *line, char **out, bool *is_valid) { *is_valid= true; end= pos; - pos ++; + pos++; break; } - while (!my_isspace(charset_info, *pos)) pos ++; + while (!my_isspace(charset_info, *pos)) pos++; end= pos; break; default: /* Its an invalid entry. Lets move until we find a space. */ - while (!my_isspace(charset_info, *pos)) pos ++; + while (!my_isspace(charset_info, *pos)) pos++; end= pos; } } @@ -5957,6 +5967,11 @@ static char *parse_alias_value(char *line, char **out, bool *is_valid) len= end - beg; value= (char *) my_malloc(len + 1, MYF(MY_WME)); + if (!value) + { + fprintf(stderr, "Couldn't allocate memory for alias value!\n"); + exit(1); + } memcpy(value, beg, len); value[len]= 0; *out= value; @@ -5978,8 +5993,14 @@ static char *handle_next_alias(char *line, bool *error) if (!is_valid) { - tee_fprintf(stdout, "alias: '%s': invalid alias name\n", name); - my_free(name); + if (!name) + tee_fprintf(stdout, "alias: '%s': not found\n", pos); + else + { + tee_fprintf(stdout, "alias: '%s': invalid alias name\n", name); + my_free(name); + } + *error= true; } else @@ -6246,6 +6267,11 @@ static int com_alias(String *buffer __attribute__((unused)), return 0; } + if (*ptr == '=') + { + tee_fprintf(stdout, "alias: '%s': not found\n", ptr); + return 0; + } /* There are more arguments to handle. */ while (*ptr) { diff --git a/mysql-test/main/mariadb-aliases.result b/mysql-test/main/mariadb-aliases.result new file mode 100644 index 0000000000000..0370911bdc6e9 --- /dev/null +++ b/mysql-test/main/mariadb-aliases.result @@ -0,0 +1,43 @@ +# +# MDEV-12192: Shell-style alias/unalias commands for MariaDB client +# +alias: '=': not found +alias: '= =': not found +alias: '=a': not found +alias: '=a=b': not found +alias a = '' +alias a = '' +alias: '=x=y z='select 1'': not found +alias x = 'select 1' +alias y = 'select 2' +alias x = 'select 1' +# Handle non existing alias +alias: 'abc': not found +alias: 'xyz': not found +alias: 'zxy': not found +# Handle alias NAME=VALUE +alias sx = 'select 1 as sx' +sx +1 +alias sx = 'select 1 as sx' +alias sy = 'select 2 as sy' +sy +2 +# Handle unalias NAME=VALUE +alias sx = 'select 1 as sx' +alias sy = 'select 2 as sy' +alias sy = 'select 2 as sy' +# Handle chaining of valid alias +alias c = 'select 1' +alias c = 'select 1' +alias c = 'select 1' +alias c = 'select 1' +alias c = 'select 1' +alias c = 'select 1' +alias c = 'select 1' +alias x = 'select 1' +alias: 'unknown': not found +alias x = 'select 1' +alias y = 'select 1' +alias y = 'select 1' +alias: 'unknown': not found diff --git a/mysql-test/main/mariadb-aliases.test b/mysql-test/main/mariadb-aliases.test new file mode 100644 index 0000000000000..8cf681805ac11 --- /dev/null +++ b/mysql-test/main/mariadb-aliases.test @@ -0,0 +1,50 @@ +--echo # +--echo # MDEV-12192: Shell-style alias/unalias commands for MariaDB client +--echo # + +# Empty alias name, return not found +--exec $MYSQL -e "alias =;" +# multiple occurence of not found +--exec $MYSQL -e "alias = =;" +--exec $MYSQL -e "alias =a;" +--exec $MYSQL -e "alias =a=b;" + +# no numeric allowed in names -> wip +# --exec $MYSQL -e "alias s1;" +# --exec $MYSQL -e "alias s1='select 2''" + +# Handle empty name and alias chaining +--error 1 # ER_EMPTY_QUERY +--exec $MYSQL -e "alias a=''; alias; a;" +--error 1 # ER_EMPTY_QUERY +--exec $MYSQL -e "alias a=; alias; a;" + +# Wrong query +--error 1 # ER_PARSE_ERROR +--exec $MYSQL -e "alias a='select '; a;" + +# Chaining with valid alias, +# Wrong alias +--exec $MYSQL -e "alias =x=y z='select 1'; alias;" +# Alias substituion +--exec $MYSQL -e "alias x='select 1' y='select 2' x; alias;" + +--echo # Handle non existing alias +# Should return not found +--exec $MYSQL -e "alias abc"; +--exec $MYSQL -e "alias xyz zxy"; + +--echo # Handle alias NAME=VALUE +--exec $MYSQL -e "alias sx='select 1 as sx'; alias; sx; alias sy='select 2 as sy'; alias; sy;" + +--echo # Handle unalias NAME=VALUE +--exec $MYSQL -e "alias sx='select 1 as sx'; alias sy='select 2 as sy'; alias; unalias sx; alias; unalias sy; alias;" + +--echo # Handle chaining of valid alias +# Handle chaining of names +--exec $MYSQL -e "alias c='select 1'; alias; alias c; alias c c; alias c c c;" +# Handle chaining of names with wrong name +--exec $MYSQL -e "alias x='select 1'; alias x; alias unknown x;" +--exec $MYSQL -e "alias y='select 1'; alias y; alias y unknown;" + +# end of 10.3 (should be 10.11 after review) From 1cccfe981d16cf7d4a45c5e46a88437b7d5cfa7c Mon Sep 17 00:00:00 2001 From: Anel Husakovic Date: Mon, 21 Nov 2022 14:51:59 +0100 Subject: [PATCH 04/16] MDEV-12912: Remove mariadbrc file - Remove initialization of mariadbrc file from `init_alias()` - Further style fixes --- client/mysql.cc | 139 +----------------------------------------------- 1 file changed, 1 insertion(+), 138 deletions(-) diff --git a/client/mysql.cc b/client/mysql.cc index 7e3ba3e6391aa..6129dde84752d 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -6076,29 +6076,15 @@ static char *handle_next_unalias(char *line, bool *error) else { if ((record= my_hash_search(&aliases, (const uchar *) name, strlen(name)))) - { my_hash_delete(&aliases, record); - } else - { tee_fprintf(stdout, "unalias: '%s': not found\n", name); - } *error= false; } return pos; } static int init_alias() { - FILE *file= 0; - char *mariadbrc_file; - char *line= 0; - char *ptr; - size_t len= 0; - ssize_t read; - MY_STAT stat_arg; - bool error; - int pos; - /* Initialize the hash structure to store aliases. */ if (my_hash_init2(&aliases, 64, charset_info, 64, 0, 0, get_alias_key, 0, @@ -6110,128 +6096,6 @@ static int init_alias() exit(1); } - /* - Read alias commands from mariadbrc file. - */ - if (getenv("MARIADBRC_FILE")) - { - mariadbrc_file= my_strdup(getenv("MARIADBRC_FILE"), MYF(MY_WME)); - } - else if (getenv("HOME")) - { - mariadbrc_file= (char*) my_malloc((uint) strlen(getenv("HOME")) - + (uint) strlen("/.mariadbrc") - + 2, MYF(MY_WME)); - if (mariadbrc_file) - sprintf(mariadbrc_file, "%s/.mariadbrc", getenv("HOME")); - } - - if (mariadbrc_file == 0) - { - put_info("out-of-memory!", INFO_ERROR); - free_defaults(defaults_argv); - my_end(0); - exit(1); - } - - /* Check if mariadbrc file exists. */ - if (!my_stat(mariadbrc_file, &stat_arg, MYF(ME_JUST_WARNING))) - goto cleanup; /* Do nothing */ - - if (!(file= my_fopen(mariadbrc_file, O_RDONLY, MYF(MY_WME)))) - { - put_info("Failed to open .mariadbrc file: ", INFO_ERROR); - put_info(strerror(errno), INFO_ERROR, errno); - free_defaults(defaults_argv); - my_end(0); - exit(1); - } - - while ((read= getline(&line, &len, file))) - { - if (read == -1) /* EOF/Error */ - { - if (errno == 0) - break; - - put_info("Failed to read from .mariadbrc file: ", INFO_ERROR); - put_info(strerror(errno), INFO_ERROR, errno); - free_defaults(defaults_argv); - my_end(0); - exit(1); - } - - /* Remove trailing newline character. */ - pos= read; - while (--pos && pos > 0 && my_iscntrl(charset_info, line[pos])) - line[pos]= 0; - - ptr= line; - - /* Remove leading whitespaces. */ - while (*ptr && my_isspace(charset_info, *ptr)) - ptr ++; - - if (strncasecmp(ptr, "alias", 5) == 0) - { - - /* Move past "alias" */ - ptr += 5; - while (*ptr && my_isspace(charset_info, *ptr)) - ptr ++; - - /* There are more arguments to handle. */ - while (*ptr) - { - ptr= handle_next_alias(ptr, &error); - - if (error) - { - free_defaults(defaults_argv); - my_end(0); - exit(1); - } - - /* Bypass the spaces. */ - while (*ptr && my_isspace(charset_info, *ptr)) ptr ++; - } - - } - else if (strncasecmp(ptr, "unalias", 7) == 0) - { - /* Move past "unalias" */ - ptr += 7; - while (*ptr && my_isspace(charset_info, *ptr)) - ptr ++; - - /* There are more arguments to handle. */ - while (*ptr) - { - ptr= handle_next_unalias(ptr, &error); - - if (error) - { - free_defaults(defaults_argv); - my_end(0); - exit(1); - } - - /* Bypass the spaces. */ - while (*ptr && my_isspace(charset_info, *ptr)) ptr ++; - } - } - } - - if (line) - free(line); - - if (file) - my_fclose(file, MYF(0)); - -cleanup: - if (mariadbrc_file) - my_free(mariadbrc_file); - return 0; } @@ -6249,10 +6113,9 @@ static int com_alias(String *buffer __attribute__((unused)), /* Move past "alias" and spaces. */ if (!(ptr= strstr(line, "alias"))) - { // Bad syntax, missing "alias" keyword return 1; - } + ptr+= 5; while (*ptr && my_isspace(charset_info, *ptr)) ptr++; From 9262d9f33786bda8fd4bf2f7505d296d37794561 Mon Sep 17 00:00:00 2001 From: Anel Husakovic Date: Mon, 21 Nov 2022 17:02:03 +0100 Subject: [PATCH 05/16] MDEV-30062 Remove unnecessary delimiter from query for mariadb-client shortcut command - Check which buffer to use as an argument for the call to the function pointer of command. Buffer shouldn't have delimiter. - By default check if command processed is `go` which doesn't take any parameter (`takes_params`) or if a server side comment (`/*! \C latin1 */ select 1`) is applied. If so use `pos` buffer, otherwise create buffer without delimiter. - Order of call of function pointer matters. --- client/mysql.cc | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/client/mysql.cc b/client/mysql.cc index 6129dde84752d..0491b947b45b9 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -2605,9 +2605,16 @@ static bool add_line(String &buffer, char *line, size_t line_length, buffer.append(line, (uint) (out-line)); out= line; } - - if ((*com->func)(&buffer,pos-1) > 0) - DBUG_RETURN(1); // Quit + /* Check which buffer to use as an argument for the call + to the function pointer of command. Buffer shouldn't have delimiter. + By default check if command processed is `go` which doesn't take any + parameter (`takes_params`) or if server side comment is applied. + If so use `pos` buffer, otherwise create buffer without delimiter. + */ + if (*pos == 'g' || *pos == 'G' || (com->takes_params && ss_comment)) + if ((*com->func)(&buffer, pos-1) > 0) + DBUG_RETURN(1); // Quit + if (com->takes_params) { if (ss_comment) @@ -2623,14 +2630,22 @@ static bool add_line(String &buffer, char *line, size_t line_length, } else { - for (pos++ ; + for (pos++; *pos && (*pos != *delimiter || - !is_prefix(pos + 1, delimiter + 1)) ; pos++) + !is_prefix(pos + 1, delimiter + 1)); pos++) ; // Remove parameters if (!*pos) pos--; else pos+= delimiter_length - 1; // Point at last delim char + + if (*pos == *delimiter) + buffer.append(line, (uint32) (pos-line)); + else + buffer.append(line, strlen(line)); + if ((*com->func)(&buffer, buffer.c_ptr()) > 0) + DBUG_RETURN(1); // Quit + buffer.length(0); } } } From 6457e1d4f5f8457634a24b7f56d24cd15910c6a8 Mon Sep 17 00:00:00 2001 From: Anel Husakovic Date: Tue, 22 Nov 2022 17:06:08 +0100 Subject: [PATCH 06/16] add test case --- mysql-test/main/mariadb-aliases.test | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mysql-test/main/mariadb-aliases.test b/mysql-test/main/mariadb-aliases.test index 8cf681805ac11..5bfca4160eaeb 100644 --- a/mysql-test/main/mariadb-aliases.test +++ b/mysql-test/main/mariadb-aliases.test @@ -47,4 +47,8 @@ --exec $MYSQL -e "alias x='select 1'; alias x; alias unknown x;" --exec $MYSQL -e "alias y='select 1'; alias y; alias y unknown;" +--echo # Use alias shortcut command +--exec $MYSQL -e "\a xy= 'select 3'; \a; " +--echo # Use unalias shortcut command +--exec $MYSQL -e "\a xy= 'select 3'; \a; \A; \a; \a xy;" # end of 10.3 (should be 10.11 after review) From 676b8c56a76415613cbd2847b9c868fa429f3281 Mon Sep 17 00:00:00 2001 From: Anel Husakovic Date: Mon, 21 Nov 2022 17:03:18 +0100 Subject: [PATCH 07/16] shell alias: allow shortcuts --- client/mysql.cc | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/client/mysql.cc b/client/mysql.cc index 0491b947b45b9..7164c36e7123c 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -6123,16 +6123,12 @@ static int deinit_alias() static int com_alias(String *buffer __attribute__((unused)), char *line) { - char *ptr; + char *ptr= strchr(line,' '); bool unused; /* Move past "alias" and spaces. */ - if (!(ptr= strstr(line, "alias"))) - // Bad syntax, missing "alias" keyword - return 1; - - ptr+= 5; - while (*ptr && my_isspace(charset_info, *ptr)) ptr++; + if (ptr) + while (my_isspace(charset_info, *ptr)) ptr++; if ((!ptr) || (*ptr == 0)) { @@ -6145,11 +6141,12 @@ static int com_alias(String *buffer __attribute__((unused)), return 0; } - if (*ptr == '=') - { - tee_fprintf(stdout, "alias: '%s': not found\n", ptr); - return 0; - } + if (*ptr == '=') + { + tee_fprintf(stdout, "alias: '%s': not found\n", ptr); + return 0; + } + /* There are more arguments to handle. */ while (*ptr) { From 6e50d7c9862e351e061db5066d443b2a30faf7f6 Mon Sep 17 00:00:00 2001 From: Anel Husakovic Date: Tue, 22 Nov 2022 18:04:17 +0100 Subject: [PATCH 08/16] Single line multi command delimiter parsing --- client/mysql.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/client/mysql.cc b/client/mysql.cc index 7164c36e7123c..95380b09e7259 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -2630,6 +2630,7 @@ static bool add_line(String &buffer, char *line, size_t line_length, } else { + char *tmp_buffer= pos; for (pos++; *pos && (*pos != *delimiter || !is_prefix(pos + 1, delimiter + 1)); pos++) @@ -2640,9 +2641,9 @@ static bool add_line(String &buffer, char *line, size_t line_length, pos+= delimiter_length - 1; // Point at last delim char if (*pos == *delimiter) - buffer.append(line, (uint32) (pos-line)); + buffer.append(tmp_buffer, (uint32) (pos-tmp_buffer)); else - buffer.append(line, strlen(line)); + buffer.append(tmp_buffer, strlen(tmp_buffer)); if ((*com->func)(&buffer, buffer.c_ptr()) > 0) DBUG_RETURN(1); // Quit buffer.length(0); From 62c9a205b4a1adbf229950aed9b0f0f1cab0b9b7 Mon Sep 17 00:00:00 2001 From: Anel Husakovic Date: Tue, 22 Nov 2022 18:05:03 +0100 Subject: [PATCH 09/16] Remove spaces at beginning of line --- client/mysql.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client/mysql.cc b/client/mysql.cc index 95380b09e7259..1fdde448e569e 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -6124,6 +6124,9 @@ static int deinit_alias() static int com_alias(String *buffer __attribute__((unused)), char *line) { + while (my_isspace(charset_info,*line)) + line++; + char *ptr= strchr(line,' '); bool unused; From 918aab5cc7c5ade8d14943b571b36a6df6a04008 Mon Sep 17 00:00:00 2001 From: Anel Husakovic Date: Tue, 22 Nov 2022 18:05:47 +0100 Subject: [PATCH 10/16] Update test/result with shortcut commands for alias/unalias --- mysql-test/main/mariadb-aliases.result | 27 ++++++++++++++++++++++++++ mysql-test/main/mariadb-aliases.test | 8 ++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/mysql-test/main/mariadb-aliases.result b/mysql-test/main/mariadb-aliases.result index 0370911bdc6e9..6ffb275dfb8b4 100644 --- a/mysql-test/main/mariadb-aliases.result +++ b/mysql-test/main/mariadb-aliases.result @@ -16,6 +16,15 @@ alias: 'abc': not found alias: 'xyz': not found alias: 'zxy': not found # Handle alias NAME=VALUE +invalid value, space in select value +alias: 'select 1': invalid alias name +alias: 'as': not found +alias: 'sx'': invalid alias name +alias: 'in': not found +alias: 'select': not found +alias: 'value'': invalid alias name +alias: 'q)V': invalid alias name +alias: 'Wp)V': invalid alias name alias sx = 'select 1 as sx' sx 1 @@ -41,3 +50,21 @@ alias x = 'select 1' alias y = 'select 1' alias y = 'select 1' alias: 'unknown': not found +# Use alias shortcut command +test command without spaces +test command with spaces +create alias +show alias +alias xy = 'select 3' +# Use unalias shortcut command +unalias empty argument +unalias: no alias specified +create alias +alias: 'select 3'': invalid alias name +show alias +alias xy = '' +unalias alias +unalias: no alias specified +show alias again +alias xy = '' +alias xy = '' diff --git a/mysql-test/main/mariadb-aliases.test b/mysql-test/main/mariadb-aliases.test index 5bfca4160eaeb..e7d31b0b03955 100644 --- a/mysql-test/main/mariadb-aliases.test +++ b/mysql-test/main/mariadb-aliases.test @@ -35,6 +35,7 @@ --exec $MYSQL -e "alias xyz zxy"; --echo # Handle alias NAME=VALUE +--exec $MYSQL -Ne "select 'invalid value, space in select value';alias sx= 'select 1 as sx';" # Do we want to prevent this or allow ? Vicentiu --exec $MYSQL -e "alias sx='select 1 as sx'; alias; sx; alias sy='select 2 as sy'; alias; sy;" --echo # Handle unalias NAME=VALUE @@ -48,7 +49,10 @@ --exec $MYSQL -e "alias y='select 1'; alias y; alias y unknown;" --echo # Use alias shortcut command ---exec $MYSQL -e "\a xy= 'select 3'; \a; " +--exec $MYSQL -Ne "select 'test command without spaces';\a; select 'test command with spaces'; \a ;" +--exec $MYSQL -Ne "select 'create alias';\a xy='select 3'; select 'show alias'; \a; " + --echo # Use unalias shortcut command ---exec $MYSQL -e "\a xy= 'select 3'; \a; \A; \a; \a xy;" +--exec $MYSQL -Ne "select 'unalias empty argument'; \A;"; +--exec $MYSQL -Ne "select 'create alias'; \a xy= 'select 3'; select 'show alias'; \a; select 'unalias alias'; \A; select 'show alias again'; \a; \a xy;" # end of 10.3 (should be 10.11 after review) From 8abc904b6e314b88a09ff35d45be92e08f259a90 Mon Sep 17 00:00:00 2001 From: Anel Husakovic Date: Tue, 22 Nov 2022 18:22:30 +0100 Subject: [PATCH 11/16] Remove spaces from value and update test/result case --- client/mysql.cc | 3 ++- mysql-test/main/mariadb-aliases.result | 23 ++++++++--------------- mysql-test/main/mariadb-aliases.test | 4 ++-- 3 files changed, 12 insertions(+), 18 deletions(-) diff --git a/client/mysql.cc b/client/mysql.cc index 1fdde448e569e..966be4f5438ca 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -6031,7 +6031,8 @@ static char *handle_next_alias(char *line, bool *error) if (*pos == '=') { - pos ++; + pos++; + while (my_isspace(charset_info,*pos)) pos++; pos= parse_alias_value(pos, &value, &is_valid); if (!is_valid) diff --git a/mysql-test/main/mariadb-aliases.result b/mysql-test/main/mariadb-aliases.result index 6ffb275dfb8b4..5f5d93642ed5c 100644 --- a/mysql-test/main/mariadb-aliases.result +++ b/mysql-test/main/mariadb-aliases.result @@ -16,21 +16,15 @@ alias: 'abc': not found alias: 'xyz': not found alias: 'zxy': not found # Handle alias NAME=VALUE -invalid value, space in select value -alias: 'select 1': invalid alias name -alias: 'as': not found -alias: 'sx'': invalid alias name -alias: 'in': not found -alias: 'select': not found -alias: 'value'': invalid alias name -alias: 'q)V': invalid alias name -alias: 'Wp)V': invalid alias name +space in value - ok +show value +alias sx = 'select 1 as sx' +no space in value - ok +show value alias sx = 'select 1 as sx' -sx 1 alias sx = 'select 1 as sx' alias sy = 'select 2 as sy' -sy 2 # Handle unalias NAME=VALUE alias sx = 'select 1 as sx' @@ -60,11 +54,10 @@ alias xy = 'select 3' unalias empty argument unalias: no alias specified create alias -alias: 'select 3'': invalid alias name show alias -alias xy = '' +alias xy = 'select 3' unalias alias unalias: no alias specified show alias again -alias xy = '' -alias xy = '' +alias xy = 'select 3' +alias xy = 'select 3' diff --git a/mysql-test/main/mariadb-aliases.test b/mysql-test/main/mariadb-aliases.test index e7d31b0b03955..5460dcc55ddc8 100644 --- a/mysql-test/main/mariadb-aliases.test +++ b/mysql-test/main/mariadb-aliases.test @@ -35,8 +35,8 @@ --exec $MYSQL -e "alias xyz zxy"; --echo # Handle alias NAME=VALUE ---exec $MYSQL -Ne "select 'invalid value, space in select value';alias sx= 'select 1 as sx';" # Do we want to prevent this or allow ? Vicentiu ---exec $MYSQL -e "alias sx='select 1 as sx'; alias; sx; alias sy='select 2 as sy'; alias; sy;" +--exec $MYSQL -Ne "select 'space in value - ok'; alias sx= 'select 1 as sx'; select 'show value'; alias;" +--exec $MYSQL -Ne "select 'no space in value - ok'; alias sx='select 1 as sx'; select 'show value'; alias; sx; alias sy='select 2 as sy'; alias; sy;" --echo # Handle unalias NAME=VALUE --exec $MYSQL -e "alias sx='select 1 as sx'; alias sy='select 2 as sy'; alias; unalias sx; alias; unalias sy; alias;" From 461e5786e340d67415637ba0b8ead5b919fb1977 Mon Sep 17 00:00:00 2001 From: Anel Husakovic Date: Tue, 22 Nov 2022 18:25:51 +0100 Subject: [PATCH 12/16] Add alpha-numer handling of alias names and update test/result --- client/mysql.cc | 2 +- mysql-test/main/mariadb-aliases.result | 2 ++ mysql-test/main/mariadb-aliases.test | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/client/mysql.cc b/client/mysql.cc index 966be4f5438ca..bde22aa78a6bd 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -5820,7 +5820,7 @@ static char *parse_alias_name(char *line, char **out, bool *is_valid) beg= pos; } - while ((my_isalpha(charset_info, *pos)) || + while ((my_isalnum(charset_info, *pos)) || (quoted && my_isspace(charset_info, *pos)) || *pos == '-' || *pos == '_') diff --git a/mysql-test/main/mariadb-aliases.result b/mysql-test/main/mariadb-aliases.result index 5f5d93642ed5c..f779591a7b035 100644 --- a/mysql-test/main/mariadb-aliases.result +++ b/mysql-test/main/mariadb-aliases.result @@ -5,6 +5,8 @@ alias: '=': not found alias: '= =': not found alias: '=a': not found alias: '=a=b': not found +alias: 's1': not found +alias s1 = 'select 2' alias a = '' alias a = '' alias: '=x=y z='select 1'': not found diff --git a/mysql-test/main/mariadb-aliases.test b/mysql-test/main/mariadb-aliases.test index 5460dcc55ddc8..76694ed1965fe 100644 --- a/mysql-test/main/mariadb-aliases.test +++ b/mysql-test/main/mariadb-aliases.test @@ -10,8 +10,8 @@ --exec $MYSQL -e "alias =a=b;" # no numeric allowed in names -> wip -# --exec $MYSQL -e "alias s1;" -# --exec $MYSQL -e "alias s1='select 2''" +--exec $MYSQL -e "alias s1; alias;" +--exec $MYSQL -e "alias s1='select 2'; alias;" # Handle empty name and alias chaining --error 1 # ER_EMPTY_QUERY From 12313674fb40e84886189b5f21ef74ff51dbd96e Mon Sep 17 00:00:00 2001 From: Anel Husakovic Date: Tue, 22 Nov 2022 18:45:25 +0100 Subject: [PATCH 13/16] Update for parsing multicommand statement --- client/mysql.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/mysql.cc b/client/mysql.cc index bde22aa78a6bd..9db8798f975a0 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -2643,7 +2643,7 @@ static bool add_line(String &buffer, char *line, size_t line_length, if (*pos == *delimiter) buffer.append(tmp_buffer, (uint32) (pos-tmp_buffer)); else - buffer.append(tmp_buffer, strlen(tmp_buffer)); + buffer.append(line, strlen(line)); if ((*com->func)(&buffer, buffer.c_ptr()) > 0) DBUG_RETURN(1); // Quit buffer.length(0); From 6f4d94f3fcb950676cda215cdc68dfb05ba4ecf6 Mon Sep 17 00:00:00 2001 From: Anel Husakovic Date: Mon, 28 Nov 2022 14:38:43 +0100 Subject: [PATCH 14/16] Add not embedded --- mysql-test/main/mariadb-aliases.test | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mysql-test/main/mariadb-aliases.test b/mysql-test/main/mariadb-aliases.test index 76694ed1965fe..3953b5c4aaf45 100644 --- a/mysql-test/main/mariadb-aliases.test +++ b/mysql-test/main/mariadb-aliases.test @@ -1,3 +1,5 @@ +-- source include/not_embedded.inc + --echo # --echo # MDEV-12192: Shell-style alias/unalias commands for MariaDB client --echo # From 37d6284d1fafb2e6eb53b05d9879b2b2598f3ee3 Mon Sep 17 00:00:00 2001 From: Anel Husakovic Date: Mon, 28 Nov 2022 17:10:52 +0100 Subject: [PATCH 15/16] Make bb :) --- client/mysql.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/client/mysql.cc b/client/mysql.cc index 9db8798f975a0..40d4a1c181003 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -3493,7 +3493,7 @@ com_charset(String *buffer __attribute__((unused)), char *line) typedef struct { char *name; - int name_len; + size_t name_len; char *value; } ALIAS; @@ -3517,7 +3517,7 @@ com_go(String *buffer,char *line __attribute__((unused))) uint error= 0; int err= 0; char *alias_end= 0; - int alias_len; + intptr_t alias_len; interrupted_query= 0; if (!status.batch) @@ -3544,9 +3544,9 @@ com_go(String *buffer,char *line __attribute__((unused))) } if ((alias_end= strchr((char *)(buffer->ptr()), ' '))) - alias_len= alias_end - buffer->ptr(); + alias_len= (intptr_t)alias_end - (intptr_t)buffer->ptr(); else - alias_len= buffer->length(); + alias_len= (intptr_t)buffer->length(); if (verbose) (void) com_print(buffer,0); @@ -5784,7 +5784,7 @@ static int com_prompt(String *buffer __attribute__((unused)), static uchar *get_alias_key(const uchar *var, size_t *len, my_bool __attribute__((unused)) t) { - register char *key; + char *key; key= ((ALIAS *)var)->name; *len= ((ALIAS *)var)->name_len; return (uchar *) key; From 66c18e416db541648bc5d611e00a97a1cee8e3a3 Mon Sep 17 00:00:00 2001 From: Anel Husakovic Date: Wed, 13 Mar 2024 09:59:18 +0100 Subject: [PATCH 16/16] Fix for 11.0 --- client/mysql.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/client/mysql.cc b/client/mysql.cc index 40d4a1c181003..a2a8a6c11c8f1 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -3564,7 +3564,7 @@ com_go(String *buffer,char *line __attribute__((unused))) if (skip_updates && (buffer->length() < 4 || charset_info->strnncoll(alias_element ? - (const uchar*) aliased_buffer->ptr() : + (const uchar*) aliased_buffer.ptr() : (const uchar*) buffer->ptr(), 4, (const uchar*) "SET ",4))) { @@ -5884,7 +5884,7 @@ static char *parse_alias_name(char *line, char **out, bool *is_valid) *out= NULL; return pos; } - name= (char *) my_malloc(len + 1, MYF(MY_WME)); + name= (char *) my_malloc(PSI_NOT_INSTRUMENTED, len + 1, MYF(MY_WME)); if (!name) { fprintf(stderr, "Couldn't allocate memory for alias name!\n"); @@ -5982,7 +5982,7 @@ static char *parse_alias_value(char *line, char **out, bool *is_valid) } len= end - beg; - value= (char *) my_malloc(len + 1, MYF(MY_WME)); + value= (char *) my_malloc(PSI_NOT_INSTRUMENTED, len + 1, MYF(MY_WME)); if (!value) { fprintf(stderr, "Couldn't allocate memory for alias value!\n"); @@ -6051,7 +6051,7 @@ static char *handle_next_alias(char *line, bool *error) { my_hash_delete(&aliases, record); } - alias= (ALIAS *) my_malloc(sizeof(ALIAS), MYF(MY_WME)); + alias= (ALIAS *) my_malloc(PSI_NOT_INSTRUMENTED, sizeof(ALIAS), MYF(MY_WME)); alias->name= name; alias->name_len= name_len; alias->value= value; @@ -6103,7 +6103,7 @@ static char *handle_next_unalias(char *line, bool *error) static int init_alias() { /* Initialize the hash structure to store aliases. */ - if (my_hash_init2(&aliases, 64, charset_info, + if (my_hash_init2(PSI_NOT_INSTRUMENTED, &aliases, 64, charset_info, 64, 0, 0, get_alias_key, 0, alias_free, MYF(0))) {