diff options
author | unknown <bell@sanja.is.com.ua> | 2004-05-11 23:23:49 +0300 |
---|---|---|
committer | unknown <bell@sanja.is.com.ua> | 2004-05-11 23:23:49 +0300 |
commit | e66b74059812d5b7fc898fc370166c878fd635ed (patch) | |
tree | 4a14eff8f720b5252a8bce7d5b88155fd0dabffb | |
parent | d7938b9fef9e67145d6beeef65ae6e316fc01e07 (diff) | |
download | mariadb-git-e66b74059812d5b7fc898fc370166c878fd635ed.tar.gz |
file parser for new .frm
include/my_sys.h:
names for get_date format flags
include/mysqld_error.h:
error of parser
libmysqld/Makefile.am:
parser file added
mysys/mf_getdate.c:
function comment for get_date()
2 new flags added
names for get_date format flags
sql/Makefile.am:
parser file added
sql/mysql_priv.h:
parser file added
sql/share/czech/errmsg.txt:
file parser errors
sql/share/danish/errmsg.txt:
file parser errors
sql/share/dutch/errmsg.txt:
file parser errors
sql/share/english/errmsg.txt:
file parser errors
sql/share/estonian/errmsg.txt:
file parser errors
sql/share/french/errmsg.txt:
file parser errors
sql/share/german/errmsg.txt:
file parser errors
sql/share/greek/errmsg.txt:
file parser errors
sql/share/hungarian/errmsg.txt:
file parser errors
sql/share/italian/errmsg.txt:
file parser errors
sql/share/japanese/errmsg.txt:
file parser errors
sql/share/korean/errmsg.txt:
file parser errors
sql/share/norwegian-ny/errmsg.txt:
file parser errors
sql/share/norwegian/errmsg.txt:
file parser errors
sql/share/polish/errmsg.txt:
file parser errors
sql/share/portuguese/errmsg.txt:
file parser errors
sql/share/romanian/errmsg.txt:
file parser errors
sql/share/russian/errmsg.txt:
file parser errors
sql/share/serbian/errmsg.txt:
file parser errors
sql/share/slovak/errmsg.txt:
file parser errors
sql/share/spanish/errmsg.txt:
file parser errors
sql/share/swedish/errmsg.txt:
file parser errors
sql/share/ukrainian/errmsg.txt:
file parser errors
BitKeeper/etc/ignore:
Added libmysqld/parse_file.cc to the ignore list
32 files changed, 1018 insertions, 16 deletions
diff --git a/.bzrignore b/.bzrignore index 1126bd3e42b..ef0c655ffd6 100644 --- a/.bzrignore +++ b/.bzrignore @@ -655,3 +655,4 @@ vio/test-ssl vio/test-sslclient vio/test-sslserver vio/viotest-ssl +libmysqld/parse_file.cc diff --git a/include/my_sys.h b/include/my_sys.h index f08ac6a1fef..89dee5b713d 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -121,6 +121,13 @@ extern int NEAR my_errno; /* Last error in mysys */ #define MY_ERRNO_EDOM 33 #define MY_ERRNO_ERANGE 34 + /* Bits for get_date timeflag */ +#define GETDATE_DATE_TIME 1 +#define GETDATE_SHORT_DATE 2 +#define GETDATE_HHMMSSTIME 4 +#define GETDATE_GMT 8 +#define GETDATE_FIXEDLENGTH 16 + /* defines when allocating data */ #ifdef SAFEMALLOC #define my_malloc(SZ,FLAG) _mymalloc((SZ), __FILE__, __LINE__, FLAG ) diff --git a/include/mysqld_error.h b/include/mysqld_error.h index 3212104dcc6..e81986cdad3 100644 --- a/include/mysqld_error.h +++ b/include/mysqld_error.h @@ -348,4 +348,9 @@ #define ER_SP_VARCOND_AFTER_CURSHNDLR 1329 #define ER_SP_CURSOR_AFTER_HANDLER 1330 #define ER_SP_CASE_NOT_FOUND 1331 -#define ER_ERROR_MESSAGES 332 +#define ER_FPARSER_TOO_BIG_FILE 1332 +#define ER_FPARSER_BAD_HEADER 1333 +#define ER_FPARSER_EOF_IN_COMMENT 1334 +#define ER_FPARSER_ERROR_IN_PARAMETER 1335 +#define ER_FPARSER_EOF_IN_UNKNOWN_PARAMETER 1336 +#define ER_ERROR_MESSAGES 337 diff --git a/libmysqld/Makefile.am b/libmysqld/Makefile.am index ccdf724df68..c1f12659378 100644 --- a/libmysqld/Makefile.am +++ b/libmysqld/Makefile.am @@ -58,7 +58,8 @@ sqlsources = derror.cc field.cc field_conv.cc strfunc.cc filesort.cc \ sql_update.cc sql_yacc.cc table.cc thr_malloc.cc time.cc \ unireg.cc uniques.cc stacktrace.c sql_union.cc hash_filo.cc \ spatial.cc gstream.cc sql_help.cc protocol_cursor.cc \ - sp_head.cc sp_pcontext.cc sp.cc sp_cache.cc sp_rcontext.cc + sp_head.cc sp_pcontext.cc sp.cc sp_cache.cc sp_rcontext.cc \ + parse_file.cc libmysqld_int_a_SOURCES= $(libmysqld_sources) $(libmysqlsources) $(sqlsources) libmysqld_a_SOURCES= diff --git a/mysys/mf_getdate.c b/mysys/mf_getdate.c index 189d43e782a..b12e68cc1f9 100644 --- a/mysys/mf_getdate.c +++ b/mysys/mf_getdate.c @@ -19,11 +19,20 @@ #include "mysys_priv.h" #include <m_string.h> - /* - If flag & 1 Return date and time - If flag & 2 Return short date format YYMMDD - if flag & 4 Return time in HHMMDD format. - */ +/* + get date as string + + SYNOPSIS + get_date() + to - string where date will be written + flag - format of date: + If flag & GETDATE_TIME Return date and time + If flag & GETDATE_SHORT_DATE Return short date format YYMMDD + If flag & GETDATE_HHMMSSTIME Return time in HHMMDD format. + If flag & GETDATE_GMT Date/time in GMT + If flag & GETDATE_FIXEDLENGTH Return fixed length date/time + date - for conversion +*/ void get_date(register my_string to, int flag, time_t date) @@ -36,27 +45,36 @@ void get_date(register my_string to, int flag, time_t date) skr=date ? (time_t) date : time((time_t*) 0); #if defined(HAVE_LOCALTIME_R) && defined(_REENTRANT) - localtime_r(&skr,&tm_tmp); + if (flag & GETDATE_GMT) + localtime_r(&skr,&tm_tmp); + else + gmtime_r(&skr,&tm_tmp); start_time= &tm_tmp; #else - start_time=localtime(&skr); + if (flag & GETDATE_GMT) + start_time= localtime(&skr); + else + gmtime(&skr,&tm_tmp); #endif - if (flag & 2) + if (flag & GETDATE_SHORT_DATE) sprintf(to,"%02d%02d%02d", start_time->tm_year % 100, start_time->tm_mon+1, start_time->tm_mday); else - sprintf(to,"%d-%02d-%02d", + sprintf(to, ((flag & GETDATE_FIXEDLENGTH) ? + "%4d-%02d-%02d" : "%d-%02d-%02d"), start_time->tm_year+1900, start_time->tm_mon+1, start_time->tm_mday); - if (flag & 1) - sprintf(strend(to)," %2d:%02d:%02d", + if (flag & GETDATE_DATE_TIME) + sprintf(strend(to), + ((flag & GETDATE_FIXEDLENGTH) ? + " %02d:%02d:%02d" : " %2d:%02d:%02d"), start_time->tm_hour, start_time->tm_min, start_time->tm_sec); - else if (flag & 4) + else if (flag & GETDATE_HHMMSSTIME) sprintf(strend(to),"%02d%02d%02d", start_time->tm_hour, start_time->tm_min, diff --git a/sql/Makefile.am b/sql/Makefile.am index 045b3e64698..1f439a34f5e 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -58,7 +58,8 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \ log_event.h sql_repl.h slave.h \ stacktrace.h sql_sort.h sql_cache.h set_var.h \ spatial.h gstream.h client_settings.h \ - sp_head.h sp_pcontext.h sp_rcontext.h sp.h sp_cache.h + sp_head.h sp_pcontext.h sp_rcontext.h sp.h sp_cache.h \ + parse_file.h mysqld_SOURCES = sql_lex.cc sql_handler.cc \ item.cc item_sum.cc item_buff.cc item_func.cc \ item_cmpfunc.cc item_strfunc.cc item_timefunc.cc \ @@ -89,7 +90,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \ stacktrace.c repl_failsafe.h repl_failsafe.cc sql_olap.cc\ gstream.cc spatial.cc sql_help.cc protocol_cursor.cc \ sp_head.cc sp_pcontext.cc sp_rcontext.cc sp.cc \ - sp_cache.cc + sp_cache.cc parse_file.cc gen_lex_hash_SOURCES = gen_lex_hash.cc gen_lex_hash_LDADD = $(LDADD) $(CXXLDFLAGS) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 09a4fceb0a3..24d703d2827 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -375,6 +375,7 @@ inline THD *_current_thd(void) #include "sql_list.h" #include "sql_map.h" #include "handler.h" +#include "parse_file.h" #include "table.h" #include "field.h" /* Field definitions */ #include "protocol.h" diff --git a/sql/parse_file.cc b/sql/parse_file.cc new file mode 100644 index 00000000000..bdf8b6134ec --- /dev/null +++ b/sql/parse_file.cc @@ -0,0 +1,785 @@ +/* Copyright (C) 2004 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +// Text .frm files management routines + +#include "mysql_priv.h" +#include <errno.h> +#include <m_ctype.h> +#include <my_sys.h> +#include <my_dir.h> + + +/* + write string with escaping + + SYNOPSIS + write_escaped_string() + file - IO_CACHE for record + val_s - string for writing + + RETURN + FALSE - OK + TRUE - error +*/ + +static my_bool +write_escaped_string(IO_CACHE *file, LEX_STRING *val_s) +{ + char *eos= val_s->str + val_s->length; + char *ptr= val_s->str; + + for (; ptr < eos; ptr++) + { + /* + Should be in sync with read_escaped_string() and + parse_quated_escaped_string() + */ + switch(*ptr) { + case '\\': // escape character + if (my_b_write(file, "\\\\", 2)) + return TRUE; + break; + case '\n': // parameter value delimiter + if (my_b_write(file, "\\n", 2)) + return TRUE; + break; + case '\0': // problem for some string processing utilites + if (my_b_write(file, "\\0", 2)) + return TRUE; + break; + case 26: // problem for windows utilites (Ctrl-Z) + if (my_b_write(file, "\\z", 2)) + return TRUE; + break; + case '\'': // list of string delimiter + if (my_b_write(file, "\\\'", 2)) + return TRUE; + break; + default: + if (my_b_write(file, ptr, 1)) + return TRUE; + } + } + return FALSE; +} + + +/* + write parameter value to IO_CACHE + + SYNOPSIS + write_parameter() + file pointer to IO_CACHE structure for writing + base pointer to data structure + parameter pointer to parameter descriptor + old_version for returning back old version number value + + RETURN + FALSE - OK + TRUE - error +*/ + +static my_bool +write_parameter(IO_CACHE *file, gptr base, File_option *parameter, + ulonglong *old_version) +{ + char num_buf[20]; // buffer for numeric operations + // string for numeric operations + String num(num_buf, sizeof(num_buf), &my_charset_bin); + DBUG_ENTER("write_parameter"); + + switch (parameter->type) { + case FILE_OPTIONS_STRING: + { + LEX_STRING *val_s= (LEX_STRING *)(base + parameter->offset); + if (my_b_write(file, val_s->str, val_s->length)) + DBUG_RETURN(TRUE); + break; + } + case FILE_OPTIONS_ESTRING: + { + if (write_escaped_string(file, (LEX_STRING *)(base + parameter->offset))) + DBUG_RETURN(TRUE); + break; + } + case FILE_OPTIONS_ULONGLONG: + { + num.set(*((ulonglong *)(base + parameter->offset)), &my_charset_bin); + if (my_b_write(file, num.ptr(), num.length())) + DBUG_RETURN(TRUE); + break; + } + case FILE_OPTIONS_REV: + { + ulonglong *val_i= (ulonglong *)(base + parameter->offset); + *old_version= (*val_i)++; + num.set(*val_i, &my_charset_bin); + if (my_b_write(file, num.ptr(), num.length())) + DBUG_RETURN(TRUE); + break; + } + case FILE_OPTIONS_TIMESTAMP: + { + /* string have to be allocated already */ + LEX_STRING *val_s= (LEX_STRING *)(base + parameter->offset); + time_t tm= time(NULL); + + get_date(val_s->str, GETDATE_DATE_TIME|GETDATE_GMT|GETDATE_FIXEDLENGTH, + tm); + val_s->length= PARSE_FILE_TIMESTAMPLENGTH; + if (my_b_write(file, val_s->str, PARSE_FILE_TIMESTAMPLENGTH)) + DBUG_RETURN(TRUE); + break; + } + case FILE_OPTIONS_STRLIST: + { + List_iterator_fast<LEX_STRING> it(*((List<LEX_STRING>*) + (base + parameter->offset))); + bool first= 1; + LEX_STRING *str; + while ((str= it++)) + { + num.set((ulonglong)str->length, &my_charset_bin); + // ',' after string to detect list continuation + if ((!first && my_b_write(file, " ", 1)) || + my_b_write(file, "\'", 1) || + my_b_write(file, str->str, str->length) || + my_b_write(file, "\'", 1)) + { + DBUG_RETURN(TRUE); + } + first= 0; + } + break; + } + default: + DBUG_ASSERT(0); // never should happened + } + DBUG_RETURN(FALSE); +} + + +/* + write new .frm + + SYNOPSIS + sql_create_definition_file() + dir directory where put .frm + file .frm file name + type .frm type string (VIEW, TABLE) + base base address for parameter reading (structure like + TABLE) + parameters parameters description + max_versions number of versions to save + + RETURN + FALSE - OK + TRUE - error +*/ + +my_bool +sql_create_definition_file(const LEX_STRING *dir, const LEX_STRING *file_name, + const LEX_STRING *type, + gptr base, File_option *parameters, + uint max_versions) +{ + File handler; + IO_CACHE file; + char path[FN_REFLEN+1]; // +1 to put temporary file name for sure + ulonglong old_version= ULONGLONG_MAX; + int path_end; + DBUG_ENTER("sql_create_definition_file"); + DBUG_PRINT("enter", ("Dir: %s, file: %s, base 0x%lx", + dir->str, file_name->str, (ulong) base)); + + fn_format(path, file_name->str, dir->str, 0, MY_UNPACK_FILENAME); + path_end= strlen(path); + + // temporary file name + path[path_end]='~'; + path[path_end+1]= '\0'; + if ((handler= my_create(path, CREATE_MODE, O_RDWR | O_TRUNC, + MYF(MY_WME))) <= 0) + { + DBUG_RETURN(TRUE); + } + + if (init_io_cache(&file, handler, 0, SEQ_READ_APPEND, 0L, 0, MYF(MY_WME))) + goto err_w_file; + + // write header (file signature) + if (my_b_write(&file, "TYPE=", 5) || + my_b_write(&file, type->str, type->length) || + my_b_write(&file, "\n", 1)) + goto err_w_file; + + // write parameters to temporary file + for (File_option *param= parameters; param->name.str; param++) + { + if (my_b_write(&file, param->name.str, param->name.length) || + my_b_write(&file, "=", 1) || + write_parameter(&file, base, param, &old_version) || + my_b_write(&file, "\n", 1)) + goto err_w_cache; + } + + if (end_io_cache(&file)) + goto err_w_file; + + if (my_close(handler, MYF(MY_WME))) + { + DBUG_RETURN(TRUE); + } + + // archive copies management + path[path_end]='\0'; + if (!access(path, F_OK)) + { + if (old_version != ULONGLONG_MAX && max_versions != 0) + { + // save buckup + char path_arc[FN_REFLEN]; + // backup old version + char path_to[FN_REFLEN]; + + // check archive directory existence + fn_format(path_arc, "arc", dir->str, "", MY_UNPACK_FILENAME); + if (access(path_arc, F_OK)) + { + if (my_mkdir(path_arc, 0777, MYF(MY_WME))) + { + DBUG_RETURN(TRUE); + } + } + + my_snprintf(path_to, FN_REFLEN, "%s/%s-%04lld", + path_arc, file_name->str, old_version); + if (my_rename(path, path_to, MYF(MY_WME))) + { + DBUG_RETURN(TRUE); + } + + // remove very old version + if (old_version > max_versions) + { + my_snprintf(path_to, FN_REFLEN, "%s/%s-%04lld", + path_arc, file_name->str, + old_version - max_versions); + if (!access(path_arc, F_OK) && my_delete(path_to, MYF(MY_WME))) + { + DBUG_RETURN(TRUE); + } + } + } + else + { + if (my_delete(path, MYF(MY_WME))) // no backups + { + DBUG_RETURN(TRUE); + } + } + } + + { + // rename temporary file + char path_to[FN_REFLEN]; + memcpy(path_to, path, path_end+1); + path[path_end]='~'; + if (my_rename(path, path_to, MYF(MY_WME))) + { + DBUG_RETURN(TRUE); + } + } + DBUG_RETURN(FALSE); +err_w_cache: + end_io_cache(&file); +err_w_file: + my_close(handler, MYF(MY_WME)); + DBUG_RETURN(TRUE); +} + + +/* + Prepare frm to parse (read to memory) + + SYNOPSIS + sql_parse_prepare() + file_name - path & filename to .frm file + mem_root - MEM_ROOT for buffer allocation + bad_format_errors - send errors on bad content + + RETURN + 0 - error + parser object + + NOTE + returned pointer + 1 will be type of .frm +*/ + +File_parser * +sql_parse_prepare(const LEX_STRING *file_name, MEM_ROOT *mem_root, + bool bad_format_errors) +{ + MY_STAT stat_info; + uint len; + char *end, *sign; + File_parser *parser; + File file; + DBUG_ENTER("sql__parse_prepare"); + + if (!my_stat(file_name->str, &stat_info, MYF(MY_WME))) + { + DBUG_RETURN(0); + } + + if (stat_info.st_size > INT_MAX-1) + { + my_error(ER_FPARSER_TOO_BIG_FILE, MYF(0), file_name->str); + DBUG_RETURN(0); + } + + if (!(parser= new(mem_root) File_parser)) + { + DBUG_RETURN(0); + } + + if (!(parser->buff= alloc_root(mem_root, stat_info.st_size+1))) + { + DBUG_RETURN(0); + } + + if ((file= my_open(file_name->str, O_RDONLY | O_SHARE, MYF(MY_WME))) < 0) + { + DBUG_RETURN(0); + } + + if ((len= my_read(file, parser->buff, stat_info.st_size, MYF(MY_WME))) == + MY_FILE_ERROR) + { + my_close(file, MYF(MY_WME)); + DBUG_RETURN(0); + } + + if (my_close(file, MYF(MY_WME))) + { + DBUG_RETURN(0); + } + + end= parser->end= parser->buff + len; + *end= '\0'; // barriaer for more simple parsing + + // 7 = 5 (TYPE=) + 1 (leter at least of type name) + 1 ('\n') + if (len < 7 || + parser->buff[0] != 'T' || + parser->buff[1] != 'Y' || + parser->buff[2] != 'P' || + parser->buff[3] != 'E' || + parser->buff[4] != '=') + goto frm_error; + + // skip signature; + parser->file_type.str= sign= parser->buff + 5; + while (*sign >= 'A' && *sign <= 'Z' && sign < end) + sign++; + if (*sign != '\n') + goto frm_error; + parser->file_type.length= sign - parser->file_type.str; + // EOS for file signature just for safety + *sign= '\0'; + + parser->start= sign + 1; + parser->content_ok= 1; + + DBUG_RETURN(parser); + +frm_error: + if (bad_format_errors) + { + my_error(ER_FPARSER_BAD_HEADER, MYF(0), file_name->str); + DBUG_RETURN(0); + } + else + DBUG_RETURN(parser); // upper level have to check parser->ok() +} + + +/* + parse LEX_STRING + + SYNOPSIS + parse_string() + ptr - pointer on string beginning + end - pointer on symbol after parsed string end (still owned + by buffer and can be accessed + mem_root - MEM_ROOT for parameter allocation + str - pointer on string, where results should be stored + + RETURN + 0 - error + # - pointer on symbol after string +*/ + +static char * +parse_string(char *ptr, char *end, MEM_ROOT *mem_root, LEX_STRING *str) +{ + // get string length + char *eol= strchr(ptr, '\n'); + + if (eol >= end) + return 0; + + str->length= eol - ptr; + + if (!(str->str= alloc_root(mem_root, str->length+1))) + return 0; + + memcpy(str->str, ptr, str->length); + str->str[str->length]= '\0'; // just for safety + return eol+1; +} + + +/* + read escaped string from ptr to eol in already allocated str + + SYNOPSIS + parse_escaped_string() + ptr - pointer on string beginning + eol - pointer on character after end of string + str - target string + + RETURN + FALSE - OK + TRUE - error +*/ + +my_bool +read_escaped_string(char *ptr, char *eol, LEX_STRING *str) +{ + char *write_pos= str->str; + + for(; ptr < eol; ptr++, write_pos++) + { + char c= *ptr; + if (c == '\\') + { + ptr++; + if (ptr >= eol) + return TRUE; + /* + Should be in sync with write_escaped_string() and + parse_quated_escaped_string() + */ + switch(*ptr) { + case '\\': + *write_pos= '\\'; + break; + case 'n': + *write_pos= '\n'; + break; + case '0': + *write_pos= '\0'; + break; + case 'z': + *write_pos= 26; + break; + case '\'': + *write_pos= '\''; + default: + return TRUE; + } + } + else + *write_pos= c; + } + str->str[str->length= write_pos-str->str]= '\0'; // just for safety + return FALSE; +} + + +/* + parse \n delimited escaped string + + SYNOPSIS + parse_escaped_string() + ptr - pointer on string beginning + end - pointer on symbol after parsed string end (still owned + by buffer and can be accessed + mem_root - MEM_ROOT for parameter allocation + str - pointer on string, where results should be stored + + RETURN + 0 - error + # - pointer on symbol after string +*/ + +static char * +parse_escaped_string(char *ptr, char *end, MEM_ROOT *mem_root, LEX_STRING *str) +{ + char *eol= strchr(ptr, '\n'); + + if (eol == 0 || eol >= end || + !(str->str= alloc_root(mem_root, (eol - ptr) + 1)) || + read_escaped_string(ptr, eol, str)) + return 0; + + return eol+1; +} + + +/* + parse '' delimited escaped string + + SYNOPSIS + parse_escaped_string() + ptr - pointer on string beginning + end - pointer on symbol after parsed string end (still owned + by buffer and can be accessed + mem_root - MEM_ROOT for parameter allocation + str - pointer on string, where results should be stored + + RETURN + 0 - error + # - pointer on symbol after string +*/ + +static char * +parse_quated_escaped_string(char *ptr, char *end, + MEM_ROOT *mem_root, LEX_STRING *str) +{ + char *eol; + uint result_len= 0; + bool escaped= 0; + + // starting ' + if (*(ptr++) != '\'') + return 0; + + // find ending ' + for (eol= ptr; (*eol != '\'' || escaped) && eol < end; eol++) + { + if (!(escaped= (*eol == '\\' && !escaped))) + result_len++; + } + + // process string + if (eol >= end || + !(str->str= alloc_root(mem_root, result_len + 1)) || + read_escaped_string(ptr, eol, str)) + return 0; + + return eol+1; +} + + +/* + parse parameters + + SYNOPSIS + File_parser::parse() + base base address for parameter writing (structure like + TABLE) + mem_root MEM_ROOT for parameters allocation + parameters parameters description + required number of required parameters in above list + + RETURN + FALSE - OK + TRUE - error +*/ + +my_bool +File_parser::parse(gptr base, MEM_ROOT *mem_root, + struct File_option *parameters, uint required) +{ + uint first_param= 0, found= 0; + register char *ptr= start; + char *eol; + LEX_STRING *str; + MEM_ROOT *sql_mem; + List<LEX_STRING> *list; + bool change_mem; + DBUG_ENTER("File_parser::parse"); + + while (ptr < end && found < required) + { + char *line= ptr; + if (*ptr == '#') + { + // it is comment + if (!(ptr= strchr(ptr, '\n'))) + { + my_error(ER_FPARSER_EOF_IN_COMMENT, MYF(0), line); + DBUG_RETURN(TRUE); + } + ptr++; + } + else + { + File_option *parameter= parameters+first_param, + *parameters_end= parameters+required; + int len= 0; + for(; parameter < parameters_end; parameter++) + { + len= parameter->name.length; + // check length + if (len < (end-ptr) && ptr[len] != '=') + continue; + // check keyword + if (memcmp(parameter->name.str, ptr, len) == 0) + break; + } + + if (parameter < parameters_end) + { + found++; + /* + if we found first parameter, start search from next parameter + next time. + (this small optimisation should work, because they should be + written in same order) + */ + if (parameter == parameters+first_param) + first_param++; + + // get value + ptr+= (len+1); + switch (parameter->type) { + case FILE_OPTIONS_STRING: + { + if (!(ptr= parse_string(ptr, end, mem_root, + (LEX_STRING *)(base + + parameter->offset)))) + { + my_error(ER_FPARSER_ERROR_IN_PARAMETER, MYF(0), + parameter->name.str, line); + DBUG_RETURN(TRUE); + } + break; + } + case FILE_OPTIONS_ESTRING: + { + if (!(ptr= parse_escaped_string(ptr, end, mem_root, + (LEX_STRING *) + (base + parameter->offset)))) + { + my_error(ER_FPARSER_ERROR_IN_PARAMETER, MYF(0), + parameter->name.str, line); + DBUG_RETURN(TRUE); + DBUG_RETURN(TRUE); + } + break; + } + case FILE_OPTIONS_ULONGLONG: + case FILE_OPTIONS_REV: + if (!(eol= strchr(ptr, '\n'))) + { + my_error(ER_FPARSER_ERROR_IN_PARAMETER, MYF(0), + parameter->name.str, line); + DBUG_RETURN(TRUE); + } + *eol= '\0'; + *((ulonglong*)(base + parameter->offset))= atoll(ptr); + *eol= '\n'; + ptr= eol+1; + break; + case FILE_OPTIONS_TIMESTAMP: + { + /* string have to be allocated already */ + LEX_STRING *val= (LEX_STRING *)(base + parameter->offset); + /* yyyy-mm-dd HH:MM:SS = 19(PARSE_FILE_TIMESTAMPLENGTH) characters */ + if (ptr[PARSE_FILE_TIMESTAMPLENGTH] != '\n') + { + my_error(ER_FPARSER_ERROR_IN_PARAMETER, MYF(0), + parameter->name.str, line); + DBUG_RETURN(TRUE); + } + memcpy(val->str, ptr, PARSE_FILE_TIMESTAMPLENGTH); + val->str[val->length= PARSE_FILE_TIMESTAMPLENGTH]= '\0'; + ptr+= (PARSE_FILE_TIMESTAMPLENGTH+1); + break; + } + case FILE_OPTIONS_STRLIST: + { + /* + TODO: remove play with mem_root, when List will be able + to store MEM_ROOT* pointer for list elements allocation + */ + sql_mem= my_pthread_getspecific_ptr(MEM_ROOT*, THR_MALLOC); + list= (List<LEX_STRING>*)(base + parameter->offset); + if ((change_mem= (sql_mem != mem_root))) + { + change_mem= 1; + my_pthread_setspecific_ptr(THR_MALLOC, mem_root); + } + + list->empty(); + // list parsing + while (ptr < end) + { + if (!(str= (LEX_STRING*)alloc_root(mem_root, + sizeof(LEX_STRING))) || + list->push_back(str)) + goto list_err; + if(!(ptr= parse_quated_escaped_string(ptr, end, mem_root, str))) + goto list_err_w_message; + switch (*ptr) { + case '\n': + goto end_of_list; + case ' ': + // we cant go over buffer bounds, because we have \0 at the end + ptr++; + break; + default: + goto list_err_w_message; + } + } + end_of_list: + if (*(ptr++) != '\n') + goto list_err; + + if (change_mem) + my_pthread_setspecific_ptr(THR_MALLOC, sql_mem); + break; + + list_err_w_message: + my_error(ER_FPARSER_ERROR_IN_PARAMETER, MYF(0), + parameter->name.str, line); + list_err: + if (change_mem) + my_pthread_setspecific_ptr(THR_MALLOC, sql_mem); + DBUG_RETURN(TRUE); + } + default: + DBUG_ASSERT(0); // never should happened + } + } + else + { + // skip unknown parameter + if (!(ptr= strchr(ptr, '\n'))) + { + my_error(ER_FPARSER_EOF_IN_UNKNOWN_PARAMETER, MYF(0), + line); + DBUG_RETURN(TRUE); + } + ptr++; + } + } + } + DBUG_RETURN(FALSE); +} diff --git a/sql/parse_file.h b/sql/parse_file.h new file mode 100644 index 00000000000..537fd035f44 --- /dev/null +++ b/sql/parse_file.h @@ -0,0 +1,68 @@ +/* -*- C++ -*- */ +/* Copyright (C) 2004 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef _PARSE_FILE_H_ +#define _PARSE_FILE_H_ + +#define PARSE_FILE_TIMESTAMPLENGTH 19 + +typedef enum { + FILE_OPTIONS_STRING, /* String (LEX_STRING) */ + FILE_OPTIONS_ESTRING, /* Escaped string (LEX_STRING) */ + FILE_OPTIONS_ULONGLONG, /* ulonglong parapeter (ulonglong) */ + FILE_OPTIONS_REV, /* Revision version number (ulonglong) */ + FILE_OPTIONS_TIMESTAMP, /* timestamp (LEX_STRING have to be + allocated with length 20 (19+1) */ + FILE_OPTIONS_STRLIST /* list of strings (List<char*>) */ +} file_opt_type; + +struct File_option +{ + const LEX_STRING name; /* Name of the option */ + int offset; /* offset to base address of value */ + enum file_opt_type type; /* Option type */ +}; + +class File_parser; +File_parser *sql_parse_prepare(const LEX_STRING *file_name, + MEM_ROOT *mem_root); + +my_bool +sql_create_definition_file(const LEX_STRING *dir, const LEX_STRING *file_name, + const LEX_STRING *type, + gptr base, File_option *parameters, uint versions); + +class File_parser: public Sql_alloc +{ + char *buff, *start, *end; + LEX_STRING file_type; + my_bool content_ok; +public: + File_parser() :buff(0), start(0), end(0), content_ok(0) + { file_type.str= 0; file_type.length= 0; } + + my_bool ok() { return content_ok; } + LEX_STRING *type() { return &file_type; } + my_bool parse(gptr base, MEM_ROOT *mem_root, + struct File_option *parameters, uint required); + + friend File_parser *sql_parse_prepare(const LEX_STRING *file_name, + MEM_ROOT *mem_root, + bool bad_format_errors); +}; + +#endif /* _PARSE_FILE_H_ */ diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt index 423c3090b8a..332059edb73 100644 --- a/sql/share/czech/errmsg.txt +++ b/sql/share/czech/errmsg.txt @@ -344,3 +344,8 @@ character-set=latin2 "Variable or condition declaration after cursor or handler declaration" "Cursor declaration after handler declaration" "Case not found for CASE statement" +"Configuration file '%-.64s' is too big" +"Malformed file type header in file '%-.64s'" +"Unexpected end of file during parsing comment '%-.64s'" +"Error during parsing parameter '%-.64s' (line: '%-.64s')" +"Unexpected end of file during skipping unknown parameter '%-.64s'" diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt index ce444c8fad1..9290565a090 100644 --- a/sql/share/danish/errmsg.txt +++ b/sql/share/danish/errmsg.txt @@ -338,3 +338,8 @@ character-set=latin1 "Variable or condition declaration after cursor or handler declaration" "Cursor declaration after handler declaration" "Case not found for CASE statement" +"Configuration file '%-.64s' is too big" +"Malformed file type header in file '%-.64s'" +"Unexpected end of file during parsing comment '%-.64s'" +"Error during parsing parameter '%-.64s' (line: '%-.64s')" +"Unexpected end of file during skipping unknown parameter '%-.64s'" diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt index 5ae00ef6421..9cdcef22270 100644 --- a/sql/share/dutch/errmsg.txt +++ b/sql/share/dutch/errmsg.txt @@ -346,3 +346,8 @@ character-set=latin1 "Variable or condition declaration after cursor or handler declaration" "Cursor declaration after handler declaration" "Case not found for CASE statement" +"Configuration file '%-.64s' is too big" +"Malformed file type header in file '%-.64s'" +"Unexpected end of file during parsing comment '%-.64s'" +"Error during parsing parameter '%-.64s' (line: '%-.64s')" +"Unexpected end of file during skipping unknown parameter '%-.64s'" diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt index 234d9cf3916..49c65b66032 100644 --- a/sql/share/english/errmsg.txt +++ b/sql/share/english/errmsg.txt @@ -335,3 +335,8 @@ character-set=latin1 "Variable or condition declaration after cursor or handler declaration" "Cursor declaration after handler declaration" "Case not found for CASE statement" +"Configuration file '%-.64s' is too big" +"Malformed file type header in file '%-.64s'" +"Unexpected end of file during parsing comment '%-.64s'" +"Error during parsing parameter '%-.64s' (line: '%-.64s')" +"Unexpected end of file during skipping unknown parameter '%-.64s'" diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt index 275abf8690e..e053dc5a956 100644 --- a/sql/share/estonian/errmsg.txt +++ b/sql/share/estonian/errmsg.txt @@ -340,3 +340,8 @@ character-set=latin7 "Variable or condition declaration after cursor or handler declaration" "Cursor declaration after handler declaration" "Case not found for CASE statement" +"Configuration file '%-.64s' is too big" +"Malformed file type header in file '%-.64s'" +"Unexpected end of file during parsing comment '%-.64s'" +"Error during parsing parameter '%-.64s' (line: '%-.64s')" +"Unexpected end of file during skipping unknown parameter '%-.64s'" diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt index 2fb86fbf917..b178ea0503f 100644 --- a/sql/share/french/errmsg.txt +++ b/sql/share/french/errmsg.txt @@ -335,3 +335,8 @@ character-set=latin1 "Variable or condition declaration after cursor or handler declaration" "Cursor declaration after handler declaration" "Case not found for CASE statement" +"Configuration file '%-.64s' is too big" +"Malformed file type header in file '%-.64s'" +"Unexpected end of file during parsing comment '%-.64s'" +"Error during parsing parameter '%-.64s' (line: '%-.64s')" +"Unexpected end of file during skipping unknown parameter '%-.64s'" diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt index 3e4eaa445f8..8923e3f3aad 100644 --- a/sql/share/german/errmsg.txt +++ b/sql/share/german/errmsg.txt @@ -347,3 +347,8 @@ character-set=latin1 "Variable or condition declaration after cursor or handler declaration" "Cursor declaration after handler declaration" "Case not found for CASE statement" +"Configuration file '%-.64s' is too big" +"Malformed file type header in file '%-.64s'" +"Unexpected end of file during parsing comment '%-.64s'" +"Error during parsing parameter '%-.64s' (line: '%-.64s')" +"Unexpected end of file during skipping unknown parameter '%-.64s'" diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt index c287c5fdc9d..485d6ae7b5f 100644 --- a/sql/share/greek/errmsg.txt +++ b/sql/share/greek/errmsg.txt @@ -335,3 +335,8 @@ character-set=greek "Variable or condition declaration after cursor or handler declaration" "Cursor declaration after handler declaration" "Case not found for CASE statement" +"Configuration file '%-.64s' is too big" +"Malformed file type header in file '%-.64s'" +"Unexpected end of file during parsing comment '%-.64s'" +"Error during parsing parameter '%-.64s' (line: '%-.64s')" +"Unexpected end of file during skipping unknown parameter '%-.64s'" diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt index 80e84c2da72..f8bd3eb4d32 100644 --- a/sql/share/hungarian/errmsg.txt +++ b/sql/share/hungarian/errmsg.txt @@ -337,3 +337,8 @@ character-set=latin2 "Variable or condition declaration after cursor or handler declaration" "Cursor declaration after handler declaration" "Case not found for CASE statement" +"Configuration file '%-.64s' is too big" +"Malformed file type header in file '%-.64s'" +"Unexpected end of file during parsing comment '%-.64s'" +"Error during parsing parameter '%-.64s' (line: '%-.64s')" +"Unexpected end of file during skipping unknown parameter '%-.64s'" diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt index ef41c493622..beaf550177d 100644 --- a/sql/share/italian/errmsg.txt +++ b/sql/share/italian/errmsg.txt @@ -335,3 +335,8 @@ character-set=latin1 "Variable or condition declaration after cursor or handler declaration" "Cursor declaration after handler declaration" "Case not found for CASE statement" +"Configuration file '%-.64s' is too big" +"Malformed file type header in file '%-.64s'" +"Unexpected end of file during parsing comment '%-.64s'" +"Error during parsing parameter '%-.64s' (line: '%-.64s')" +"Unexpected end of file during skipping unknown parameter '%-.64s'" diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt index 60e390b02ff..d9a1fd15e7e 100644 --- a/sql/share/japanese/errmsg.txt +++ b/sql/share/japanese/errmsg.txt @@ -337,3 +337,8 @@ character-set=ujis "Variable or condition declaration after cursor or handler declaration" "Cursor declaration after handler declaration" "Case not found for CASE statement" +"Configuration file '%-.64s' is too big" +"Malformed file type header in file '%-.64s'" +"Unexpected end of file during parsing comment '%-.64s'" +"Error during parsing parameter '%-.64s' (line: '%-.64s')" +"Unexpected end of file during skipping unknown parameter '%-.64s'" diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt index 1797a7c8e2a..8d0f5043445 100644 --- a/sql/share/korean/errmsg.txt +++ b/sql/share/korean/errmsg.txt @@ -335,3 +335,8 @@ character-set=euckr "Variable or condition declaration after cursor or handler declaration" "Cursor declaration after handler declaration" "Case not found for CASE statement" +"Configuration file '%-.64s' is too big" +"Malformed file type header in file '%-.64s'" +"Unexpected end of file during parsing comment '%-.64s'" +"Error during parsing parameter '%-.64s' (line: '%-.64s')" +"Unexpected end of file during skipping unknown parameter '%-.64s'" diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt index 498b65715b8..f1fab840e52 100644 --- a/sql/share/norwegian-ny/errmsg.txt +++ b/sql/share/norwegian-ny/errmsg.txt @@ -337,3 +337,8 @@ character-set=latin1 "Variable or condition declaration after cursor or handler declaration" "Cursor declaration after handler declaration" "Case not found for CASE statement" +"Configuration file '%-.64s' is too big" +"Malformed file type header in file '%-.64s'" +"Unexpected end of file during parsing comment '%-.64s'" +"Error during parsing parameter '%-.64s' (line: '%-.64s')" +"Unexpected end of file during skipping unknown parameter '%-.64s'" diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt index 74f4acd43f0..d031a4385d3 100644 --- a/sql/share/norwegian/errmsg.txt +++ b/sql/share/norwegian/errmsg.txt @@ -337,3 +337,8 @@ character-set=latin1 "Variable or condition declaration after cursor or handler declaration" "Cursor declaration after handler declaration" "Case not found for CASE statement" +"Configuration file '%-.64s' is too big" +"Malformed file type header in file '%-.64s'" +"Unexpected end of file during parsing comment '%-.64s'" +"Error during parsing parameter '%-.64s' (line: '%-.64s')" +"Unexpected end of file during skipping unknown parameter '%-.64s'" diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt index e9f6e6a349e..604fbefeab4 100644 --- a/sql/share/polish/errmsg.txt +++ b/sql/share/polish/errmsg.txt @@ -339,3 +339,8 @@ character-set=latin2 "Variable or condition declaration after cursor or handler declaration" "Cursor declaration after handler declaration" "Case not found for CASE statement" +"Configuration file '%-.64s' is too big" +"Malformed file type header in file '%-.64s'" +"Unexpected end of file during parsing comment '%-.64s'" +"Error during parsing parameter '%-.64s' (line: '%-.64s')" +"Unexpected end of file during skipping unknown parameter '%-.64s'" diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt index 7056a5bb169..f43d592e49a 100644 --- a/sql/share/portuguese/errmsg.txt +++ b/sql/share/portuguese/errmsg.txt @@ -336,3 +336,8 @@ character-set=latin1 "Variable or condition declaration after cursor or handler declaration" "Cursor declaration after handler declaration" "Case not found for CASE statement" +"Configuration file '%-.64s' is too big" +"Malformed file type header in file '%-.64s'" +"Unexpected end of file during parsing comment '%-.64s'" +"Error during parsing parameter '%-.64s' (line: '%-.64s')" +"Unexpected end of file during skipping unknown parameter '%-.64s'" diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt index c1f7cbf9914..57302734a41 100644 --- a/sql/share/romanian/errmsg.txt +++ b/sql/share/romanian/errmsg.txt @@ -339,3 +339,8 @@ character-set=latin2 "Variable or condition declaration after cursor or handler declaration" "Cursor declaration after handler declaration" "Case not found for CASE statement" +"Configuration file '%-.64s' is too big" +"Malformed file type header in file '%-.64s'" +"Unexpected end of file during parsing comment '%-.64s'" +"Error during parsing parameter '%-.64s' (line: '%-.64s')" +"Unexpected end of file during skipping unknown parameter '%-.64s'" diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt index 86a4424b8f1..333869b9a1e 100644 --- a/sql/share/russian/errmsg.txt +++ b/sql/share/russian/errmsg.txt @@ -337,3 +337,8 @@ character-set=koi8r "Variable or condition declaration after cursor or handler declaration" "Cursor declaration after handler declaration" "Case not found for CASE statement" +"Слишком большой конфигурационный файл '%-.64s'" +"Неверный заголовок типа файла '%-.64s'" +"Неожиданный конец файла в коментарии '%-.64s'" +"Ошибка при распознавании параметра '%-.64s' (строка: '%-.64s')" +"Неожиданный конец файла при пропуске неизвестного параметра '%-.64s'" diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt index 957c7650a87..622cbb7e2aa 100644 --- a/sql/share/serbian/errmsg.txt +++ b/sql/share/serbian/errmsg.txt @@ -329,3 +329,8 @@ character-set=cp1250 "Variable or condition declaration after cursor or handler declaration" "Cursor declaration after handler declaration" "Case not found for CASE statement" +"Configuration file '%-.64s' is too big" +"Malformed file type header in file '%-.64s'" +"Unexpected end of file during parsing comment '%-.64s'" +"Error during parsing parameter '%-.64s' (line: '%-.64s')" +"Unexpected end of file during skipping unknown parameter '%-.64s'" diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt index feddd50b585..e8175d1e5fe 100644 --- a/sql/share/slovak/errmsg.txt +++ b/sql/share/slovak/errmsg.txt @@ -343,3 +343,8 @@ character-set=latin2 "Variable or condition declaration after cursor or handler declaration" "Cursor declaration after handler declaration" "Case not found for CASE statement" +"Configuration file '%-.64s' is too big" +"Malformed file type header in file '%-.64s'" +"Unexpected end of file during parsing comment '%-.64s'" +"Error during parsing parameter '%-.64s' (line: '%-.64s')" +"Unexpected end of file during skipping unknown parameter '%-.64s'" diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt index f309b8108bb..2d71c5f1abc 100644 --- a/sql/share/spanish/errmsg.txt +++ b/sql/share/spanish/errmsg.txt @@ -337,3 +337,8 @@ character-set=latin1 "Variable or condition declaration after cursor or handler declaration" "Cursor declaration after handler declaration" "Case not found for CASE statement" +"Configuration file '%-.64s' is too big" +"Malformed file type header in file '%-.64s'" +"Unexpected end of file during parsing comment '%-.64s'" +"Error during parsing parameter '%-.64s' (line: '%-.64s')" +"Unexpected end of file during skipping unknown parameter '%-.64s'" diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt index 4761a6c15c1..7e2cfe16265 100644 --- a/sql/share/swedish/errmsg.txt +++ b/sql/share/swedish/errmsg.txt @@ -335,3 +335,8 @@ character-set=latin1 "Variable or condition declaration after cursor or handler declaration" "Cursor declaration after handler declaration" "Case not found for CASE statement" +"Configuration file '%-.64s' is too big" +"Malformed file type header in file '%-.64s'" +"Unexpected end of file during parsing comment '%-.64s'" +"Error during parsing parameter '%-.64s' (line: '%-.64s')" +"Unexpected end of file during skipping unknown parameter '%-.64s'" diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt index 2495c2676be..a897cde70b4 100644 --- a/sql/share/ukrainian/errmsg.txt +++ b/sql/share/ukrainian/errmsg.txt @@ -340,3 +340,8 @@ character-set=koi8u "Variable or condition declaration after cursor or handler declaration" "Cursor declaration after handler declaration" "Case not found for CASE statement" +"Занадто великий конф╕гурац╕йний файл '%-.64s'" +"Нев╕рний заголовок типу у файл╕ '%-.64s'" +"Неспод╕ванний к╕нець файлу у коментар╕ '%-.64s'" +"Помилка в росп╕знаванн╕ параметру '%-.64s' (рядок: '%-.64s')" +"Неспод╕ванний к╕нець файлу у спроб╕ проминути нев╕домий параметр '%-.64s'" |