00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040 #define MTEST_VERSION "3.3"
00041
00042 #include <config.h>
00043 #include <client/get_password.h>
00044 #include <libdrizzle-2.0/libdrizzle.hpp>
00045
00046 #include <queue>
00047 #include <map>
00048 #include <string>
00049 #include <sstream>
00050 #include <fstream>
00051 #include <iostream>
00052 #include <vector>
00053 #include <algorithm>
00054 #ifdef HAVE_SYS_WAIT_H
00055 #include <sys/wait.h>
00056 #endif
00057 #include <cassert>
00058 #include <sys/stat.h>
00059 #include <sys/types.h>
00060 #include <fcntl.h>
00061 #include <boost/array.hpp>
00062 #include <boost/foreach.hpp>
00063 #include <boost/program_options.hpp>
00064 #include <boost/smart_ptr.hpp>
00065
00066 #include PCRE_HEADER
00067
00068 #include <stdarg.h>
00069 #include <boost/unordered_map.hpp>
00070
00071
00072 #include <drizzled/gettext.h>
00073
00074 #include <drizzled/definitions.h>
00075 #include <drizzled/internal/my_sys.h>
00076 #include <drizzled/type/time.h>
00077 #include <drizzled/charset.h>
00078 #include <drizzled/typelib.h>
00079 #include <drizzled/configmake.h>
00080 #include <drizzled/util/find_ptr.h>
00081
00082 #define PTR_BYTE_DIFF(A,B) (ptrdiff_t) (reinterpret_cast<const unsigned char*>(A) - reinterpret_cast<const unsigned char*>(B))
00083
00084 namespace po= boost::program_options;
00085 using namespace std;
00086 using namespace drizzled;
00087
00088 unsigned char *get_var_key(const unsigned char* var, size_t *len, bool);
00089
00090 int get_one_option(int optid, const struct option *, char *argument);
00091
00092 #define MAX_VAR_NAME_LENGTH 256
00093 #define MAX_COLUMNS 256
00094 #define MAX_DELIMITER_LENGTH 16
00095
00096 #define QUERY_SEND_FLAG 1
00097 #define QUERY_REAP_FLAG 2
00098
00099 typedef boost::unordered_map<std::string, uint32_t> ErrorCodes;
00100 ErrorCodes global_error_names;
00101
00102 enum {
00103 OPT_PS_PROTOCOL, OPT_SP_PROTOCOL, OPT_CURSOR_PROTOCOL, OPT_VIEW_PROTOCOL,
00104 OPT_MAX_CONNECT_RETRIES, OPT_MARK_PROGRESS, OPT_LOG_DIR, OPT_TAIL_LINES,
00105 OPT_TESTDIR
00106 };
00107
00108 static int record= 0, opt_sleep= -1;
00109 static char *opt_pass= NULL;
00110 const char *unix_sock= NULL;
00111 static uint32_t opt_port= 0;
00112 static uint32_t opt_max_connect_retries;
00113 static bool silent= false, verbose= false;
00114 static bool opt_mark_progress= false;
00115 static bool parsing_disabled= false;
00116 static bool display_result_vertically= false,
00117 display_metadata= false, display_result_sorted= false;
00118 static bool disable_query_log= false, disable_result_log= false;
00119 static bool disable_warnings= false;
00120 static bool disable_info= true;
00121 static bool abort_on_error= true;
00122 static bool server_initialized= false;
00123 static bool is_windows= false;
00124 static bool use_drizzle_protocol= false;
00125 static char line_buffer[MAX_DELIMITER_LENGTH], *line_buffer_pos= line_buffer;
00126 static void free_all_replace();
00127
00128 std::string opt_basedir,
00129 opt_charsets_dir,
00130 opt_db,
00131 opt_host,
00132 opt_include,
00133 opt_testdir,
00134 opt_logdir,
00135 password,
00136 opt_password,
00137 result_file_name,
00138 opt_user,
00139 opt_protocol;
00140
00141 static uint32_t start_lineno= 0;
00142
00143
00144 static uint32_t opt_tail_lines= 0;
00145
00146 static char delimiter[MAX_DELIMITER_LENGTH]= ";";
00147 static uint32_t delimiter_length= 1;
00148
00149 static char TMPDIR[FN_REFLEN];
00150
00151
00152 enum block_cmd {
00153 cmd_none,
00154 cmd_if,
00155 cmd_while
00156 };
00157
00158 struct st_block
00159 {
00160 int line;
00161 bool ok;
00162 enum block_cmd cmd;
00163 };
00164
00165 static struct st_block block_stack[32];
00166 static struct st_block *cur_block, *block_stack_end;
00167
00168
00169 struct st_test_file
00170 {
00171 FILE* file;
00172 const char *file_name;
00173 uint32_t lineno;
00174 };
00175
00176 static boost::array<st_test_file, 16> file_stack;
00177 static st_test_file* cur_file;
00178
00179 static const charset_info_st *charset_info= &my_charset_utf8_general_ci;
00180
00181
00182
00183
00184
00185 static char *timer_file = NULL;
00186 static uint64_t timer_start;
00187 static void timer_output();
00188 static uint64_t timer_now();
00189
00190 static uint64_t progress_start= 0;
00191
00192 vector<struct st_command*> q_lines;
00193
00194 struct parser_st
00195 {
00196 int read_lines;
00197 int current_line;
00198 } parser;
00199
00200 struct master_pos_st
00201 {
00202 char file[FN_REFLEN];
00203 uint32_t pos;
00204 };
00205
00206 master_pos_st master_pos;
00207
00208
00209
00210 class VAR
00211 {
00212 public:
00213 char *name;
00214 int name_len;
00215 char *str_val;
00216 int str_val_len;
00217 int int_val;
00218 int alloced_len;
00219 int int_dirty;
00220 int alloced;
00221 char *env_s;
00222 };
00223
00224
00225 boost::array<VAR, 10> var_reg;
00226
00227 typedef boost::unordered_map<string, VAR *> var_hash_t;
00228 var_hash_t var_hash;
00229
00230 class st_connection
00231 {
00232 public:
00233 st_connection() : con(drizzle)
00234 {
00235 drizzle_con_add_options(*this, use_drizzle_protocol ? DRIZZLE_CON_EXPERIMENTAL : DRIZZLE_CON_MYSQL);
00236 }
00237
00238 operator drizzle::connection_c&()
00239 {
00240 return con;
00241 }
00242
00243 operator drizzle_con_st*()
00244 {
00245 return con;
00246 }
00247
00248 drizzle::drizzle_c drizzle;
00249 drizzle::connection_c con;
00250 };
00251
00252 typedef map<string, st_connection*> connections_t;
00253 connections_t g_connections;
00254 st_connection* cur_con= NULL;
00255
00256
00257
00258
00259
00260
00261 enum enum_commands
00262 {
00263 Q_CONNECTION=1, Q_QUERY,
00264 Q_CONNECT, Q_SLEEP, Q_REAL_SLEEP,
00265 Q_INC, Q_DEC,
00266 Q_SOURCE, Q_DISCONNECT,
00267 Q_LET, Q_ECHO,
00268 Q_WHILE, Q_END_BLOCK,
00269 Q_SYSTEM, Q_RESULT,
00270 Q_REQUIRE, Q_SAVE_MASTER_POS,
00271 Q_SYNC_WITH_MASTER,
00272 Q_SYNC_SLAVE_WITH_MASTER,
00273 Q_ERROR,
00274 Q_SEND, Q_REAP,
00275 Q_DIRTY_CLOSE, Q_REPLACE, Q_REPLACE_COLUMN,
00276 Q_PING, Q_EVAL,
00277 Q_EVAL_RESULT,
00278 Q_ENABLE_QUERY_LOG, Q_DISABLE_QUERY_LOG,
00279 Q_ENABLE_RESULT_LOG, Q_DISABLE_RESULT_LOG,
00280 Q_WAIT_FOR_SLAVE_TO_STOP,
00281 Q_ENABLE_WARNINGS, Q_DISABLE_WARNINGS,
00282 Q_ENABLE_INFO, Q_DISABLE_INFO,
00283 Q_ENABLE_METADATA, Q_DISABLE_METADATA,
00284 Q_EXEC, Q_DELIMITER,
00285 Q_DISABLE_ABORT_ON_ERROR, Q_ENABLE_ABORT_ON_ERROR,
00286 Q_DISPLAY_VERTICAL_RESULTS, Q_DISPLAY_HORIZONTAL_RESULTS,
00287 Q_QUERY_VERTICAL, Q_QUERY_HORIZONTAL, Q_SORTED_RESULT,
00288 Q_START_TIMER, Q_END_TIMER,
00289 Q_CHARACTER_SET,
00290 Q_DISABLE_RECONNECT, Q_ENABLE_RECONNECT,
00291 Q_IF,
00292 Q_DISABLE_PARSING, Q_ENABLE_PARSING,
00293 Q_REPLACE_REGEX, Q_REMOVE_FILE, Q_FILE_EXIST,
00294 Q_WRITE_FILE, Q_COPY_FILE, Q_PERL, Q_DIE, Q_EXIT, Q_SKIP,
00295 Q_CHMOD_FILE, Q_APPEND_FILE, Q_CAT_FILE, Q_DIFF_FILES,
00296 Q_SEND_QUIT, Q_CHANGE_USER, Q_MKDIR, Q_RMDIR,
00297
00298 Q_UNKNOWN,
00299 Q_COMMENT,
00300 Q_COMMENT_WITH_COMMAND
00301 };
00302
00303
00304 const char *command_names[]=
00305 {
00306 "connection",
00307 "query",
00308 "connect",
00309 "sleep",
00310 "real_sleep",
00311 "inc",
00312 "dec",
00313 "source",
00314 "disconnect",
00315 "let",
00316 "echo",
00317 "while",
00318 "end",
00319 "system",
00320 "result",
00321 "require",
00322 "save_master_pos",
00323 "sync_with_master",
00324 "sync_slave_with_master",
00325 "error",
00326 "send",
00327 "reap",
00328 "dirty_close",
00329 "replace_result",
00330 "replace_column",
00331 "ping",
00332 "eval",
00333 "eval_result",
00334
00335 "enable_query_log",
00336 "disable_query_log",
00337
00338 "enable_result_log",
00339 "disable_result_log",
00340 "wait_for_slave_to_stop",
00341 "enable_warnings",
00342 "disable_warnings",
00343 "enable_info",
00344 "disable_info",
00345 "enable_metadata",
00346 "disable_metadata",
00347 "exec",
00348 "delimiter",
00349 "disable_abort_on_error",
00350 "enable_abort_on_error",
00351 "vertical_results",
00352 "horizontal_results",
00353 "query_vertical",
00354 "query_horizontal",
00355 "sorted_result",
00356 "start_timer",
00357 "end_timer",
00358 "character_set",
00359 "disable_reconnect",
00360 "enable_reconnect",
00361 "if",
00362 "disable_parsing",
00363 "enable_parsing",
00364 "replace_regex",
00365 "remove_file",
00366 "file_exists",
00367 "write_file",
00368 "copy_file",
00369 "perl",
00370 "die",
00371
00372
00373 "exit",
00374 "skip",
00375 "chmod",
00376 "append_file",
00377 "cat_file",
00378 "diff_files",
00379 "send_quit",
00380 "change_user",
00381 "mkdir",
00382 "rmdir",
00383
00384 0
00385 };
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395 enum match_err_type
00396 {
00397 ERR_EMPTY= 0,
00398 ERR_ERRNO,
00399 ERR_SQLSTATE
00400 };
00401
00402 struct st_match_err
00403 {
00404 enum match_err_type type;
00405 union
00406 {
00407 uint32_t errnum;
00408 char sqlstate[DRIZZLE_MAX_SQLSTATE_SIZE+1];
00409 } code;
00410 };
00411
00412 struct st_expected_errors
00413 {
00414 struct st_match_err err[10];
00415 uint32_t count;
00416 };
00417
00418 static st_expected_errors saved_expected_errors;
00419
00420 class st_command
00421 {
00422 public:
00423 char *query, *query_buf,*first_argument,*last_argument,*end;
00424 int first_word_len, query_len;
00425 bool abort_on_error;
00426 st_expected_errors expected_errors;
00427 string require_file;
00428 enum_commands type;
00429
00430 st_command()
00431 : query(NULL), query_buf(NULL), first_argument(NULL), last_argument(NULL),
00432 end(NULL), first_word_len(0), query_len(0), abort_on_error(false),
00433 require_file(""), type(Q_CONNECTION)
00434 {
00435 memset(&expected_errors, 0, sizeof(st_expected_errors));
00436 }
00437
00438 ~st_command()
00439 {
00440 free(query_buf);
00441 }
00442 };
00443
00444 TYPELIB command_typelib= {array_elements(command_names),"",
00445 command_names, 0};
00446
00447 string ds_res, ds_progress, ds_warning_messages;
00448
00449 char builtin_echo[FN_REFLEN];
00450
00451 void die(const char *fmt, ...)
00452 __attribute__((format(printf, 1, 2)));
00453 void abort_not_supported_test(const char *fmt, ...)
00454 __attribute__((format(printf, 1, 2)));
00455 void verbose_msg(const char *fmt, ...)
00456 __attribute__((format(printf, 1, 2)));
00457 void warning_msg(const char *fmt, ...)
00458 __attribute__((format(printf, 1, 2)));
00459 void log_msg(const char *fmt, ...)
00460 __attribute__((format(printf, 1, 2)));
00461
00462 VAR* var_from_env(const char *, const char *);
00463 VAR* var_init(VAR* v, const char *name, int name_len, const char *val,
00464 int val_len);
00465 VAR* var_get(const char *var_name, const char** var_name_end,
00466 bool raw, bool ignore_not_existing);
00467 void eval_expr(VAR* v, const char *p, const char** p_end);
00468 bool match_delimiter(int c, const char *delim, uint32_t length);
00469 void dump_result_to_reject_file(char *buf, int size);
00470 void dump_result_to_log_file(const char *buf, int size);
00471 void dump_warning_messages();
00472 void dump_progress();
00473
00474 void do_eval(string *query_eval, const char *query,
00475 const char *query_end, bool pass_through_escape_chars);
00476 void str_to_file(const char *fname, const char *str, int size);
00477 void str_to_file2(const char *fname, const char *str, int size, bool append);
00478
00479
00480 static char *replace_column[MAX_COLUMNS];
00481 static uint32_t max_replace_column= 0;
00482 void do_get_replace_column(st_command*);
00483 void free_replace_column();
00484
00485
00486 void do_get_replace(st_command* command);
00487 void free_replace();
00488
00489
00490 void do_get_replace_regex(st_command* command);
00491
00492 void replace_append_mem(string& ds, const char *val, int len);
00493 void replace_append(string *ds, const char *val);
00494 void replace_append_uint(string& ds, uint32_t val);
00495 void append_sorted(string& ds, const string& ds_input);
00496
00497 void handle_error(st_command*,
00498 unsigned int err_errno, const char *err_error,
00499 const char *err_sqlstate, string *ds);
00500 void handle_no_error(st_command*);
00501
00502
00503 void do_eval(string *query_eval, const char *query,
00504 const char *query_end, bool pass_through_escape_chars)
00505 {
00506 char c, next_c;
00507 int escaped = 0;
00508
00509 for (const char *p= query; (c= *p) && p < query_end; ++p)
00510 {
00511 switch(c)
00512 {
00513 case '$':
00514 if (escaped)
00515 {
00516 escaped= 0;
00517 query_eval->append(p, 1);
00518 }
00519 else
00520 {
00521 VAR* v= var_get(p, &p, 0, 0);
00522 if (not v)
00523 die("Bad variable in eval");
00524 query_eval->append(v->str_val, v->str_val_len);
00525 }
00526 break;
00527 case '\\':
00528 next_c= *(p+1);
00529 if (escaped)
00530 {
00531 escaped= 0;
00532 query_eval->append(p, 1);
00533 }
00534 else if (next_c == '\\' || next_c == '$' || next_c == '"')
00535 {
00536
00537 escaped= 1;
00538
00539 if (pass_through_escape_chars)
00540 {
00541
00542 query_eval->append(p, 1);
00543 }
00544 }
00545 else
00546 query_eval->append(p, 1);
00547 break;
00548 default:
00549 escaped= 0;
00550 query_eval->append(p, 1);
00551 }
00552 }
00553 }
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570 static void append_os_quoted(string *str, const char *append, ...)
00571 {
00572 const char *quote_str= "\'";
00573 const uint32_t quote_len= 1;
00574
00575 va_list dirty_text;
00576
00577 str->append(quote_str, quote_len);
00578 va_start(dirty_text, append);
00579 while (append != NULL)
00580 {
00581 const char *cur_pos= append;
00582 const char *next_pos= cur_pos;
00583
00584
00585 while ((next_pos= strrchr(cur_pos, quote_str[0])) != NULL)
00586 {
00587 str->append(cur_pos, next_pos - cur_pos);
00588 str->append("\\", 1);
00589 str->append(quote_str, quote_len);
00590 cur_pos= next_pos + 1;
00591 }
00592 str->append(cur_pos);
00593 append= va_arg(dirty_text, char *);
00594 }
00595 va_end(dirty_text);
00596 str->append(quote_str, quote_len);
00597 }
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613 static int dt_query_log(drizzle::connection_c& con, drizzle::result_c& res, const std::string& query)
00614 {
00615 if (drizzle_return_t ret= con.query(res, query))
00616 {
00617 if (ret == DRIZZLE_RETURN_ERROR_CODE)
00618 {
00619 log_msg("Error running query '%s': %d %s", query.c_str(), res.error_code(), res.error());
00620 }
00621 else
00622 {
00623 log_msg("Error running query '%s': %d %s", query.c_str(), ret, con.error());
00624 }
00625 return 1;
00626 }
00627 return res.column_count() == 0;
00628 }
00629
00630 static void show_query(drizzle::connection_c& con, const char* query)
00631 {
00632 drizzle::result_c res;
00633 if (dt_query_log(con, res, query))
00634 return;
00635
00636 unsigned int row_num= 0;
00637 unsigned int num_fields= res.column_count();
00638
00639 fprintf(stderr, "=== %s ===\n", query);
00640 while (drizzle_row_t row= res.row_next())
00641 {
00642 size_t *lengths= res.row_field_sizes();
00643 row_num++;
00644
00645 fprintf(stderr, "---- %d. ----\n", row_num);
00646 res.column_seek(0);
00647 for (unsigned int i= 0; i < num_fields; i++)
00648 {
00649 drizzle_column_st* column= res.column_next();
00650 fprintf(stderr, "%s\t%.*s\n", drizzle_column_name(column), (int)lengths[i], row[i] ? row[i] : "NULL");
00651 }
00652 }
00653 for (size_t i= 0; i < strlen(query)+8; i++)
00654 fprintf(stderr, "=");
00655 fprintf(stderr, "\n\n");
00656 }
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672 static void show_warnings_before_error(drizzle::connection_c& con)
00673 {
00674 drizzle::result_c res;
00675 if (dt_query_log(con, res, "show warnings"))
00676 return;
00677
00678 if (res.row_count() >= 2)
00679 {
00680 unsigned int row_num= 0;
00681 unsigned int num_fields= res.column_count();
00682
00683 fprintf(stderr, "\nWarnings from just before the error:\n");
00684 while (drizzle_row_t row= res.row_next())
00685 {
00686 size_t *lengths= res.row_field_sizes();
00687
00688 if (++row_num >= res.row_count())
00689 {
00690
00691 break;
00692 }
00693
00694 for (uint32_t i= 0; i < num_fields; i++)
00695 {
00696 fprintf(stderr, "%.*s ", (int)lengths[i], row[i] ? row[i] : "NULL");
00697 }
00698 fprintf(stderr, "\n");
00699 }
00700 }
00701 }
00702
00703 enum arg_type
00704 {
00705 ARG_STRING,
00706 ARG_REST
00707 };
00708
00709 struct command_arg
00710 {
00711 const char *argname;
00712 enum arg_type type;
00713 bool required;
00714 string *ds;
00715 const char *description;
00716 };
00717
00718
00719 static void check_command_args(st_command* command,
00720 const char *arguments,
00721 const struct command_arg *args,
00722 int num_args, const char delimiter_arg)
00723 {
00724 const char *ptr= arguments;
00725 const char *start;
00726
00727 for (int i= 0; i < num_args; i++)
00728 {
00729 const struct command_arg *arg= &args[i];
00730 arg->ds->clear();
00731
00732 bool known_arg_type= true;
00733 switch (arg->type) {
00734
00735 case ARG_STRING:
00736
00737 while (*ptr && *ptr == ' ')
00738 ptr++;
00739 start= ptr;
00740
00741 while (*ptr && *ptr != delimiter_arg)
00742 ptr++;
00743 if (ptr > start)
00744 {
00745 do_eval(arg->ds, start, ptr, false);
00746 }
00747 else
00748 {
00749
00750 arg->ds->erase();
00751 }
00752 command->last_argument= (char*)ptr;
00753
00754
00755 if (*ptr && *ptr == delimiter_arg)
00756 ptr++;
00757 break;
00758
00759
00760 case ARG_REST:
00761 start= ptr;
00762 do_eval(arg->ds, start, command->end, false);
00763 command->last_argument= command->end;
00764 break;
00765
00766 default:
00767 known_arg_type= false;
00768 break;
00769 }
00770 assert(known_arg_type);
00771
00772
00773 if (arg->ds->length() == 0 && arg->required)
00774 die("Missing required argument '%s' to command '%.*s'", arg->argname,
00775 command->first_word_len, command->query);
00776
00777 }
00778
00779 ptr= command->last_argument;
00780 while (ptr <= command->end)
00781 {
00782 if (*ptr && *ptr != ' ')
00783 die("Extra argument '%s' passed to '%.*s'",
00784 ptr, command->first_word_len, command->query);
00785 ptr++;
00786 }
00787 return;
00788 }
00789
00790
00791 static void handle_command_error(st_command* command, uint32_t error)
00792 {
00793 if (error != 0)
00794 {
00795 if (command->abort_on_error)
00796 die("command \"%.*s\" failed with error %d", command->first_word_len, command->query, error);
00797 for (uint32_t i= 0; i < command->expected_errors.count; i++)
00798 {
00799 if (command->expected_errors.err[i].type == ERR_ERRNO &&
00800 command->expected_errors.err[i].code.errnum == error)
00801 {
00802 return;
00803 }
00804 }
00805 die("command \"%.*s\" failed with wrong error: %d",
00806 command->first_word_len, command->query, error);
00807 }
00808 else if (command->expected_errors.err[0].type == ERR_ERRNO &&
00809 command->expected_errors.err[0].code.errnum != 0)
00810 {
00811
00812 die("command \"%.*s\" succeeded - should have failed with errno %d...",
00813 command->first_word_len, command->query,
00814 command->expected_errors.err[0].code.errnum);
00815 }
00816 }
00817
00818 static void cleanup_and_exit(int exit_code)
00819 {
00820 if (!silent)
00821 {
00822 switch (exit_code)
00823 {
00824 case 1:
00825 printf("not ok\n");
00826 break;
00827 case 0:
00828 printf("ok\n");
00829 break;
00830 case 62:
00831 printf("skipped\n");
00832 break;
00833 default:
00834 printf("unknown exit code: %d\n", exit_code);
00835 assert(false);
00836 }
00837 }
00838 exit(exit_code);
00839 }
00840
00841 void die(const char *fmt, ...)
00842 {
00843
00844
00845
00846
00847
00848 static bool dying= false;
00849 if (dying)
00850 cleanup_and_exit(1);
00851 dying= true;
00852
00853
00854 fprintf(stderr, "drizzletest: ");
00855 if (cur_file && cur_file != file_stack.data())
00856 fprintf(stderr, "In included file \"%s\": ", cur_file->file_name);
00857 if (start_lineno > 0)
00858 fprintf(stderr, "At line %u: ", start_lineno);
00859 if (fmt)
00860 {
00861 va_list args;
00862 va_start(args, fmt);
00863 vfprintf(stderr, fmt, args);
00864 va_end(args);
00865 }
00866 else
00867 fprintf(stderr, "unknown error");
00868 fprintf(stderr, "\n");
00869 fflush(stderr);
00870
00871
00872 if (ds_res.length() && opt_tail_lines)
00873 {
00874 int tail_lines= opt_tail_lines;
00875 const char* show_from= ds_res.c_str() + ds_res.length() - 1;
00876 while (show_from > ds_res.c_str() && tail_lines > 0 )
00877 {
00878 show_from--;
00879 if (*show_from == '\n')
00880 tail_lines--;
00881 }
00882 fprintf(stderr, "\nThe result from queries just before the failure was:\n");
00883 if (show_from > ds_res.c_str())
00884 fprintf(stderr, "< snip >");
00885 fprintf(stderr, "%s", show_from);
00886 fflush(stderr);
00887 }
00888
00889
00890 if (! result_file_name.empty() && ds_res.length())
00891 dump_result_to_log_file(ds_res.c_str(), ds_res.length());
00892
00893
00894 if (! result_file_name.empty() && ds_warning_messages.length())
00895 dump_warning_messages();
00896
00897
00898
00899
00900
00901 if (cur_con)
00902 {
00903 show_warnings_before_error(*cur_con);
00904 }
00905
00906 cleanup_and_exit(1);
00907 }
00908
00909
00910 void abort_not_supported_test(const char *fmt, ...)
00911 {
00912 va_list args;
00913 st_test_file* err_file= cur_file;
00914
00915
00916
00917 fprintf(stderr, "The test '%s' is not supported by this installation\n",
00918 file_stack[0].file_name);
00919 fprintf(stderr, "Detected in file %s at line %d\n",
00920 err_file->file_name, err_file->lineno);
00921 while (err_file != file_stack.data())
00922 {
00923 err_file--;
00924 fprintf(stderr, "included from %s at line %d\n",
00925 err_file->file_name, err_file->lineno);
00926 }
00927
00928
00929 va_start(args, fmt);
00930 if (fmt)
00931 {
00932 fprintf(stderr, "reason: ");
00933 vfprintf(stderr, fmt, args);
00934 fprintf(stderr, "\n");
00935 fflush(stderr);
00936 }
00937 va_end(args);
00938
00939 cleanup_and_exit(62);
00940 }
00941
00942
00943 void verbose_msg(const char *fmt, ...)
00944 {
00945 if (!verbose)
00946 return;
00947 va_list args;
00948 va_start(args, fmt);
00949 fprintf(stderr, "drizzletest: ");
00950 if (cur_file && cur_file != file_stack.data())
00951 fprintf(stderr, "In included file \"%s\": ", cur_file->file_name);
00952 if (start_lineno != 0)
00953 fprintf(stderr, "At line %u: ", start_lineno);
00954 vfprintf(stderr, fmt, args);
00955 fprintf(stderr, "\n");
00956 va_end(args);
00957 }
00958
00959
00960 void warning_msg(const char *fmt, ...)
00961 {
00962 va_list args;
00963 char buff[512];
00964 size_t len;
00965
00966 va_start(args, fmt);
00967 ds_warning_messages += "drizzletest: ";
00968 if (start_lineno != 0)
00969 {
00970 ds_warning_messages += "Warning detected ";
00971 if (cur_file && cur_file != file_stack.data())
00972 {
00973 len= snprintf(buff, sizeof(buff), "in included file %s ", cur_file->file_name);
00974 ds_warning_messages.append(buff, len);
00975 }
00976 len= snprintf(buff, sizeof(buff), "at line %d: ", start_lineno);
00977 ds_warning_messages.append(buff, len);
00978 }
00979
00980 len= vsnprintf(buff, sizeof(buff), fmt, args);
00981 ds_warning_messages.append(buff, len);
00982
00983 ds_warning_messages += "\n";
00984 va_end(args);
00985
00986 return;
00987 }
00988
00989
00990 void log_msg(const char *fmt, ...)
00991 {
00992 va_list args;
00993 char buff[1024];
00994
00995 va_start(args, fmt);
00996 size_t len= vsnprintf(buff, sizeof(buff)-1, fmt, args);
00997 va_end(args);
00998
00999 ds_res.append(buff, len);
01000 ds_res += "\n";
01001 }
01002
01003
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013
01014 static void cat_file(string& ds, const char* filename)
01015 {
01016 int fd= internal::my_open(filename, O_RDONLY, MYF(0));
01017 if (fd < 0)
01018 die("Failed to open file '%s'", filename);
01019 char buff[512];
01020 while (uint32_t len= internal::my_read(fd, (unsigned char*)&buff, sizeof(buff), MYF(0)))
01021 {
01022 char *p= buff, *start= buff;
01023 while (p < buff+len)
01024 {
01025
01026 if (*p == '\r' && *(p+1) && *(p+1)== '\n')
01027 {
01028
01029 *p= '\n';
01030 p++;
01031 ds.append(start, p - start);
01032 p++;
01033 start= p;
01034 }
01035 else
01036 p++;
01037 }
01038
01039 ds.append(start, p - start);
01040 }
01041 internal::my_close(fd, MYF(0));
01042 }
01043
01044
01045
01046
01047
01048
01049
01050
01051
01052
01053
01054
01055 static int run_command(const char* cmd, string& result)
01056 {
01057 FILE* res_file= popen(cmd, "r");
01058 if (not res_file)
01059 die("popen(\"%s\", \"r\") failed", cmd);
01060
01061 char buf[512]= {0};
01062 while (fgets(buf, sizeof(buf), res_file))
01063 {
01064
01065 result.append(buf);
01066 }
01067 int error= pclose(res_file);
01068 return WEXITSTATUS(error);
01069 }
01070
01071
01072
01073
01074
01075
01076
01077
01078
01079
01080
01081
01082
01083
01084 static int run_tool(const char *tool_path, string& result, ...)
01085 {
01086 string ds_cmdline;
01087 append_os_quoted(&ds_cmdline, tool_path, NULL);
01088 ds_cmdline += " ";
01089
01090 va_list args;
01091 va_start(args, result);
01092 while (const char* arg= va_arg(args, char *))
01093 {
01094
01095 if (strncmp(arg, "--", 2) == 0)
01096 append_os_quoted(&ds_cmdline, arg, NULL);
01097 else
01098 ds_cmdline += arg;
01099 ds_cmdline += " ";
01100 }
01101
01102 va_end(args);
01103
01104 return run_command(ds_cmdline.c_str(), result);
01105 }
01106
01107
01108
01109
01110
01111
01112
01113
01114
01115
01116
01117
01118
01119
01120
01121 static void show_diff(string* ds, const char* filename1, const char* filename2)
01122 {
01123 string ds_tmp;
01124
01125
01126 if (run_tool("diff",
01127 ds_tmp,
01128 "-u",
01129 filename1,
01130 filename2,
01131 "2>&1",
01132 NULL) > 1)
01133 {
01134
01135
01136 if (run_tool("diff",
01137 ds_tmp,
01138 "-c",
01139 filename1,
01140 filename2,
01141 "2>&1",
01142 NULL) > 1)
01143 {
01144
01145
01146
01147
01148 ds_tmp=
01149 "\n"
01150 "The two files differ but it was not possible to execute 'diff' in\n"
01151 "order to show only the difference, tried both 'diff -u' or 'diff -c'.\n"
01152 "Instead the whole content of the two files was shown for you to diff manually. ;)\n"
01153 "\n"
01154 "To get a better report you should install 'diff' on your system, which you\n"
01155 "for example can get from http://www.gnu.org/software/diffutils/diffutils.html\n"
01156 "\n";
01157
01158 ds_tmp += " --- ";
01159 ds_tmp += filename1;
01160 ds_tmp += " >>>\n";
01161 cat_file(ds_tmp, filename1);
01162 ds_tmp += "<<<\n --- ";
01163 ds_tmp += filename1;
01164 ds_tmp += " >>>\n";
01165 cat_file(ds_tmp, filename2);
01166 ds_tmp += "<<<<\n";
01167 }
01168 }
01169
01170 if (ds)
01171 {
01172
01173 *ds += ds_tmp;
01174 }
01175 else
01176 {
01177
01178 fprintf(stderr, "%s\n", ds_tmp.c_str());
01179 }
01180
01181 }
01182
01183 enum compare_files_result_enum
01184 {
01185 RESULT_OK= 0,
01186 RESULT_CONTENT_MISMATCH= 1,
01187 RESULT_LENGTH_MISMATCH= 2
01188 };
01189
01190
01191
01192
01193
01194
01195
01196
01197
01198
01199
01200
01201
01202
01203
01204 static int compare_files2(int fd, const char* filename2)
01205 {
01206 int error= RESULT_OK;
01207 uint32_t len, len2;
01208 char buff[512], buff2[512];
01209 const char *fname= filename2;
01210 string tmpfile;
01211
01212 int fd2= internal::my_open(fname, O_RDONLY, MYF(0));
01213 if (fd2 < 0)
01214 {
01215 internal::my_close(fd, MYF(0));
01216 if (! opt_testdir.empty())
01217 {
01218 tmpfile= opt_testdir;
01219 if (tmpfile[tmpfile.length()] != '/')
01220 tmpfile += "/";
01221 tmpfile += filename2;
01222 fname= tmpfile.c_str();
01223 }
01224 if ((fd2= internal::my_open(fname, O_RDONLY, MYF(0))) < 0)
01225 {
01226 internal::my_close(fd, MYF(0));
01227
01228 die("Failed to open second file: '%s'", fname);
01229 }
01230 }
01231 while ((len= internal::my_read(fd, (unsigned char*)&buff,
01232 sizeof(buff), MYF(0))) > 0)
01233 {
01234 if ((len2= internal::my_read(fd2, (unsigned char*)&buff2,
01235 sizeof(buff2), MYF(0))) < len)
01236 {
01237
01238 error= RESULT_LENGTH_MISMATCH;
01239 break;
01240 }
01241 if (len2 > len)
01242 {
01243
01244 error= RESULT_LENGTH_MISMATCH;
01245 break;
01246 }
01247 if ((memcmp(buff, buff2, len)))
01248 {
01249
01250 error= RESULT_CONTENT_MISMATCH;
01251 break;
01252 }
01253 }
01254 if (!error && internal::my_read(fd2, (unsigned char*)&buff2,
01255 sizeof(buff2), MYF(0)) > 0)
01256 {
01257
01258 error= RESULT_LENGTH_MISMATCH;
01259 }
01260
01261 internal::my_close(fd2, MYF(0));
01262
01263 return error;
01264 }
01265
01266
01267
01268
01269
01270
01271
01272
01273
01274
01275
01276
01277
01278
01279
01280 static int compare_files(const char* filename1, const char* filename2)
01281 {
01282 int fd= internal::my_open(filename1, O_RDONLY, MYF(0));
01283 if (fd < 0)
01284 die("Failed to open first file: '%s'", filename1);
01285 int error= compare_files2(fd, filename2);
01286 internal::my_close(fd, MYF(0));
01287 return error;
01288 }
01289
01290
01291
01292
01293
01294
01295
01296
01297
01298
01299
01300
01301
01302
01303 static int string_cmp(const string& ds, const char *fname)
01304 {
01305 char temp_file_path[FN_REFLEN];
01306
01307 int fd= internal::create_temp_file(temp_file_path, TMPDIR, "tmp", MYF(MY_WME));
01308 if (fd < 0)
01309 die("Failed to create temporary file for ds");
01310
01311
01312 if (internal::my_write(fd, (unsigned char *) ds.data(), ds.length(), MYF(MY_FNABP | MY_WME)) ||
01313 lseek(fd, 0, SEEK_SET) == MY_FILEPOS_ERROR)
01314 {
01315 internal::my_close(fd, MYF(0));
01316
01317 internal::my_delete(temp_file_path, MYF(0));
01318 die("Failed to write file '%s'", temp_file_path);
01319 }
01320
01321 int error= compare_files2(fd, fname);
01322
01323 internal::my_close(fd, MYF(0));
01324
01325 internal::my_delete(temp_file_path, MYF(0));
01326
01327 return error;
01328 }
01329
01330
01331
01332
01333
01334
01335
01336
01337
01338
01339
01340
01341
01342
01343 static void check_result(string& ds)
01344 {
01345 const char* mess= "Result content mismatch\n";
01346
01347 if (access(result_file_name.c_str(), F_OK) != 0)
01348 die("The specified result file does not exist: '%s'", result_file_name.c_str());
01349
01350 switch (string_cmp(ds, result_file_name.c_str()))
01351 {
01352 case RESULT_OK:
01353 break;
01354 case RESULT_LENGTH_MISMATCH:
01355 mess= "Result length mismatch\n";
01356
01357 case RESULT_CONTENT_MISMATCH:
01358 {
01359
01360
01361
01362
01363 char reject_file[FN_REFLEN];
01364 size_t reject_length;
01365 internal::dirname_part(reject_file, result_file_name.c_str(), &reject_length);
01366
01367 if (access(reject_file, W_OK) == 0)
01368 {
01369
01370 internal::fn_format(reject_file, result_file_name.c_str(), NULL, ".reject", MY_REPLACE_EXT);
01371 }
01372 else
01373 {
01374
01375 internal::fn_format(reject_file, result_file_name.c_str(), opt_logdir.c_str(), ".reject", MY_REPLACE_DIR | MY_REPLACE_EXT);
01376 }
01377 str_to_file(reject_file, ds.data(), ds.length());
01378
01379 ds.erase();
01380
01381 show_diff(NULL, result_file_name.c_str(), reject_file);
01382 die("%s",mess);
01383 break;
01384 }
01385 default:
01386 die("Unknown error code from dyn_string_cmp()");
01387 }
01388 }
01389
01390
01391
01392
01393
01394
01395
01396
01397
01398
01399
01400
01401
01402
01403
01404
01405
01406 static void check_require(const string& ds, const string& fname)
01407 {
01408 if (string_cmp(ds, fname.c_str()))
01409 {
01410 char reason[FN_REFLEN];
01411 internal::fn_format(reason, fname.c_str(), "", "", MY_REPLACE_EXT | MY_REPLACE_DIR);
01412 abort_not_supported_test("Test requires: '%s'", reason);
01413 }
01414 }
01415
01416
01417
01418
01419
01420
01421
01422 static int strip_surrounding(char* str, char c1, char c2)
01423 {
01424 char* ptr= str;
01425
01426
01427 while (*ptr && charset_info->isspace(*ptr))
01428 ptr++;
01429 if (*ptr == c1)
01430 {
01431
01432 *ptr= ' ';
01433
01434
01435 ptr= strchr(str, '\0')-1;
01436 while (*ptr && charset_info->isspace(*ptr))
01437 ptr--;
01438 if (*ptr == c2)
01439 {
01440
01441 *ptr= 0;
01442 }
01443 else
01444 {
01445
01446 return 1;
01447 }
01448 }
01449 return 0;
01450 }
01451
01452
01453 static void strip_parentheses(st_command* command)
01454 {
01455 if (strip_surrounding(command->first_argument, '(', ')'))
01456 die("%.*s - argument list started with '%c' must be ended with '%c'",
01457 command->first_word_len, command->query, '(', ')');
01458 }
01459
01460
01461
01462 VAR *var_init(VAR *v, const char *name, int name_len, const char *val,
01463 int val_len)
01464 {
01465 if (!name_len && name)
01466 name_len = strlen(name);
01467 if (!val_len && val)
01468 val_len = strlen(val) ;
01469 VAR *tmp_var = v ? v : (VAR*)malloc(sizeof(*tmp_var) + name_len+1);
01470
01471 tmp_var->name = name ? (char*)&tmp_var[1] : 0;
01472 tmp_var->alloced = (v == 0);
01473
01474 int val_alloc_len = val_len + 16;
01475 tmp_var->str_val = (char*)malloc(val_alloc_len+1);
01476
01477 memcpy(tmp_var->name, name, name_len);
01478 if (val)
01479 {
01480 memcpy(tmp_var->str_val, val, val_len);
01481 tmp_var->str_val[val_len]= 0;
01482 }
01483 tmp_var->name_len = name_len;
01484 tmp_var->str_val_len = val_len;
01485 tmp_var->alloced_len = val_alloc_len;
01486 tmp_var->int_val = val ? atoi(val) : 0;
01487 tmp_var->int_dirty = false;
01488 tmp_var->env_s = 0;
01489 return tmp_var;
01490 }
01491
01492 VAR* var_from_env(const char *name, const char *def_val)
01493 {
01494 const char *tmp= getenv(name);
01495 if (!tmp)
01496 tmp = def_val;
01497 return var_hash[name] = var_init(0, name, strlen(name), tmp, strlen(tmp));
01498 }
01499
01500 VAR* var_get(const char *var_name, const char **var_name_end, bool raw,
01501 bool ignore_not_existing)
01502 {
01503 int digit;
01504 VAR *v;
01505 if (*var_name != '$')
01506 goto err;
01507 digit = *++var_name - '0';
01508 if (digit < 0 || digit >= 10)
01509 {
01510 const char *save_var_name = var_name, *end;
01511 uint32_t length;
01512 end = (var_name_end) ? *var_name_end : 0;
01513 while (charset_info->isvar(*var_name) && var_name != end)
01514 var_name++;
01515 if (var_name == save_var_name)
01516 {
01517 if (ignore_not_existing)
01518 return(0);
01519 die("Empty variable");
01520 }
01521 length= (uint32_t) (var_name - save_var_name);
01522 if (length >= MAX_VAR_NAME_LENGTH)
01523 die("Too long variable name: %s", save_var_name);
01524
01525 string save_var_name_str(save_var_name, length);
01526 if (var_hash_t::mapped_type* ptr= find_ptr(var_hash, save_var_name_str))
01527 v= *ptr;
01528 else
01529 {
01530 char buff[MAX_VAR_NAME_LENGTH+1];
01531 strncpy(buff, save_var_name, length);
01532 buff[length]= '\0';
01533 v= var_from_env(buff, "");
01534 }
01535 var_name--;
01536 }
01537 else
01538 v = &var_reg[digit];
01539
01540 if (!raw && v->int_dirty)
01541 {
01542 sprintf(v->str_val, "%d", v->int_val);
01543 v->int_dirty = 0;
01544 v->str_val_len = strlen(v->str_val);
01545 }
01546 if (var_name_end)
01547 *var_name_end = var_name ;
01548 return(v);
01549 err:
01550 if (var_name_end)
01551 *var_name_end = 0;
01552 die("Unsupported variable name: %s", var_name);
01553 return(0);
01554 }
01555
01556
01557 static VAR *var_obtain(const char *name, int len)
01558 {
01559 string var_name(name, len);
01560 if (var_hash_t::mapped_type* ptr= find_ptr(var_hash, var_name))
01561 return *ptr;
01562 return var_hash[var_name] = var_init(0, name, len, "", 0);
01563 }
01564
01565
01566
01567
01568
01569
01570
01571
01572 static void var_set(const char *var_name, const char *var_name_end,
01573 const char *var_val, const char *var_val_end)
01574 {
01575 int digit, env_var= 0;
01576 VAR *v;
01577
01578 if (*var_name != '$')
01579 env_var= 1;
01580 else
01581 var_name++;
01582
01583 digit= *var_name - '0';
01584 if (!(digit < 10 && digit >= 0))
01585 {
01586 v= var_obtain(var_name, (uint32_t) (var_name_end - var_name));
01587 }
01588 else
01589 v= &var_reg[digit];
01590
01591 eval_expr(v, var_val, (const char**) &var_val_end);
01592
01593 if (env_var)
01594 {
01595 char buf[1024], *old_env_s= v->env_s;
01596 if (v->int_dirty)
01597 {
01598 sprintf(v->str_val, "%d", v->int_val);
01599 v->int_dirty= 0;
01600 v->str_val_len= strlen(v->str_val);
01601 }
01602 snprintf(buf, sizeof(buf), "%.*s=%.*s",
01603 v->name_len, v->name,
01604 v->str_val_len, v->str_val);
01605 v->env_s= strdup(buf);
01606 putenv(v->env_s);
01607 free(old_env_s);
01608 }
01609 return;
01610 }
01611
01612
01613 static void var_set_string(const char* name, const char* value)
01614 {
01615 var_set(name, name + strlen(name), value, value + strlen(value));
01616 }
01617
01618
01619 static void var_set_int(const char* name, int value)
01620 {
01621 char buf[21];
01622 snprintf(buf, sizeof(buf), "%d", value);
01623 var_set_string(name, buf);
01624 }
01625
01626
01627
01628
01629
01630
01631
01632 static void var_set_errno(int sql_errno)
01633 {
01634 var_set_int("$drizzleclient_errno", sql_errno);
01635 }
01636
01637
01638
01639
01640
01641
01642
01643 static void var_set_drizzleclient_get_server_version(drizzle_con_st *con)
01644 {
01645 var_set_int("$drizzle_con_server_version", drizzle_con_server_version_number(con));
01646 }
01647
01648
01649
01650
01651
01652
01653
01654
01655
01656
01657
01658
01659
01660
01661
01662
01663
01664
01665
01666
01667
01668
01669
01670
01671
01672 static void dt_query(drizzle::connection_c& con, drizzle::result_c& res, const std::string& query)
01673 {
01674 if (drizzle_return_t ret= con.query(res, query))
01675 {
01676 if (ret == DRIZZLE_RETURN_ERROR_CODE)
01677 {
01678 die("Error running query '%s': %d %s", query.c_str(), res.error_code(), res.error());
01679 }
01680 else
01681 {
01682 die("Error running query '%s': %d %s", query.c_str(), ret, con.error());
01683 }
01684 }
01685
01686 if (res.column_count() == 0)
01687 {
01688 die("Query '%s' didn't return a result set", query.c_str());
01689 }
01690 }
01691
01692 static void var_query_set(VAR *var, const char *query, const char** query_end)
01693 {
01694 const char *end = ((query_end && *query_end) ? *query_end : query + strlen(query));
01695 drizzle::connection_c& con= *cur_con;
01696
01697 while (end > query && *end != '`')
01698 --end;
01699 if (query == end)
01700 die("Syntax error in query, missing '`'");
01701 ++query;
01702
01703 string ds_query;
01704
01705 do_eval(&ds_query, query, end, false);
01706
01707 drizzle::result_c res;
01708 dt_query(con, res, ds_query);
01709
01710 drizzle_row_t row= res.row_next();
01711 if (row && row[0])
01712 {
01713
01714
01715
01716
01717 string result;
01718 size_t* lengths= res.row_field_sizes();
01719 for (uint32_t i= 0; i < res.column_count(); i++)
01720 {
01721 if (row[i])
01722 {
01723
01724 result.append(row[i], lengths[i]);
01725 }
01726 result += "\t";
01727 }
01728 end= result.c_str() + result.length() - 1;
01729 eval_expr(var, result.c_str(), (const char**) &end);
01730 }
01731 else
01732 eval_expr(var, "", 0);
01733 }
01734
01735
01736
01737
01738
01739
01740
01741
01742
01743
01744
01745
01746
01747
01748
01749
01750
01751
01752
01753
01754
01755
01756
01757
01758 static void var_set_query_get_value(st_command* command, VAR *var)
01759 {
01760 int col_no= -1;
01761 drizzle::connection_c& con= *cur_con;
01762
01763 string ds_query;
01764 string ds_col;
01765 string ds_row;
01766 const struct command_arg query_get_value_args[] = {
01767 {"query", ARG_STRING, true, &ds_query, "Query to run"},
01768 {"column name", ARG_STRING, true, &ds_col, "Name of column"},
01769 {"row number", ARG_STRING, true, &ds_row, "Number for row"}
01770 };
01771
01772
01773
01774 strip_parentheses(command);
01775 check_command_args(command, command->first_argument, query_get_value_args,
01776 sizeof(query_get_value_args)/sizeof(struct command_arg),
01777 ',');
01778
01779
01780 long row_no= atoi(ds_row.c_str());
01781
01782 istringstream buff(ds_row);
01783 if ((buff >> row_no).fail())
01784 die("Invalid row number: '%s'", ds_row.c_str());
01785
01786
01787
01788 char* unstripped_query= strdup(ds_query.c_str());
01789 if (strip_surrounding(unstripped_query, '"', '"'))
01790 die("Mismatched \"'s around query '%s'", ds_query.c_str());
01791 ds_query= unstripped_query;
01792
01793 drizzle::result_c res;
01794 dt_query(con, res, ds_query);
01795
01796 {
01797
01798 uint32_t num_fields= res.column_count();
01799 for (uint32_t i= 0; i < num_fields; i++)
01800 {
01801 drizzle_column_st* column= res.column_next();
01802 if (strcmp(drizzle_column_name(column), ds_col.c_str()) == 0 &&
01803 strlen(drizzle_column_name(column)) == ds_col.length())
01804 {
01805 col_no= i;
01806 break;
01807 }
01808 }
01809 if (col_no == -1)
01810 {
01811 die("Could not find column '%s' in the result of '%s'", ds_col.c_str(), ds_query.c_str());
01812 }
01813 }
01814
01815 {
01816
01817 long rows= 0;
01818 const char* value= "No such row";
01819
01820 while (drizzle_row_t row= res.row_next())
01821 {
01822 if (++rows == row_no)
01823 {
01824
01825 value= row[col_no] ? row[col_no] : "NULL";
01826 break;
01827 }
01828 }
01829 eval_expr(var, value, 0);
01830 }
01831 }
01832
01833
01834 static void var_copy(VAR *dest, VAR *src)
01835 {
01836 dest->int_val= src->int_val;
01837 dest->int_dirty= src->int_dirty;
01838
01839
01840 if (dest->alloced_len < src->alloced_len)
01841 {
01842 char *tmpptr= (char *)realloc(dest->str_val, src->alloced_len);
01843 dest->str_val= tmpptr;
01844 }
01845 else
01846 dest->alloced_len= src->alloced_len;
01847
01848
01849 dest->str_val_len= src->str_val_len;
01850 if (src->str_val_len)
01851 memcpy(dest->str_val, src->str_val, src->str_val_len);
01852 }
01853
01854
01855 void eval_expr(VAR *v, const char *p, const char **p_end)
01856 {
01857 if (*p == '$')
01858 {
01859 VAR *vp= var_get(p, p_end, 0, 0);
01860 if (vp)
01861 var_copy(v, vp);
01862 return;
01863 }
01864
01865 if (*p == '`')
01866 {
01867 var_query_set(v, p, p_end);
01868 return;
01869 }
01870
01871 {
01872
01873 const char* get_value_str= "query_get_value";
01874 const size_t len= strlen(get_value_str);
01875 if (strncmp(p, get_value_str, len)==0)
01876 {
01877 st_command command;
01878 command.query= (char*)p;
01879 command.first_word_len= len;
01880 command.first_argument= command.query + len;
01881 command.end= (char*)*p_end;
01882 var_set_query_get_value(&command, v);
01883 return;
01884 }
01885 }
01886
01887 {
01888 int new_val_len = (p_end && *p_end) ?
01889 (int) (*p_end - p) : (int) strlen(p);
01890 if (new_val_len + 1 >= v->alloced_len)
01891 {
01892 static int MIN_VAR_ALLOC= 32;
01893 v->alloced_len = (new_val_len < MIN_VAR_ALLOC - 1) ?
01894 MIN_VAR_ALLOC : new_val_len + 1;
01895 char *tmpptr= (char *)realloc(v->str_val, v->alloced_len+1);
01896 v->str_val= tmpptr;
01897 }
01898 v->str_val_len = new_val_len;
01899 memcpy(v->str_val, p, new_val_len);
01900 v->str_val[new_val_len] = 0;
01901 v->int_val=atoi(p);
01902 v->int_dirty=0;
01903 }
01904 return;
01905 }
01906
01907
01908 static void open_file(const char *name)
01909 {
01910 char buff[FN_REFLEN];
01911
01912 if (!internal::test_if_hard_path(name))
01913 {
01914 snprintf(buff, sizeof(buff), "%s%s",opt_basedir.c_str(),name);
01915 name=buff;
01916 }
01917 internal::fn_format(buff, name, "", "", MY_UNPACK_FILENAME);
01918
01919 cur_file++;
01920 if (cur_file == &*file_stack.end())
01921 die("Source directives are nesting too deep");
01922 if (!(cur_file->file= fopen(buff, "r")))
01923 {
01924 cur_file--;
01925 die("Could not open '%s' for reading", buff);
01926 }
01927 cur_file->file_name= strdup(buff);
01928 cur_file->lineno=1;
01929 }
01930
01931
01932
01933
01934
01935
01936
01937
01938
01939
01940
01941
01942
01943
01944
01945
01946 static void do_source(st_command* command)
01947 {
01948 string ds_filename;
01949 const struct command_arg source_args[] = {
01950 { "filename", ARG_STRING, true, &ds_filename, "File to source" }
01951 };
01952
01953
01954 check_command_args(command, command->first_argument, source_args,
01955 sizeof(source_args)/sizeof(struct command_arg),
01956 ' ');
01957
01958
01959
01960
01961
01962 if (parser.current_line < (parser.read_lines - 1))
01963 ;
01964 else
01965 {
01966 if (! opt_testdir.empty())
01967 {
01968 string testdir(opt_testdir);
01969 if (testdir[testdir.length()] != '/')
01970 testdir += "/";
01971 testdir += ds_filename;
01972 ds_filename.swap(testdir);
01973 }
01974 open_file(ds_filename.c_str());
01975 }
01976 }
01977
01978
01979 static void init_builtin_echo()
01980 {
01981 builtin_echo[0]= 0;
01982 }
01983
01984
01985
01986
01987
01988
01989
01990
01991
01992
01993
01994
01995
01996
01997
01998
01999
02000
02001 static int replace(string *ds_str,
02002 const char *search_str, uint32_t search_len,
02003 const char *replace_str, uint32_t replace_len)
02004 {
02005 string ds_tmp;
02006 const char *start= strstr(ds_str->c_str(), search_str);
02007 if (!start)
02008 return 1;
02009 ds_tmp.append(ds_str->c_str(), start - ds_str->c_str());
02010 ds_tmp.append(replace_str, replace_len);
02011 ds_tmp.append(start + search_len);
02012 *ds_str= ds_tmp;
02013 return 0;
02014 }
02015
02016
02017
02018
02019
02020
02021
02022
02023
02024
02025
02026
02027
02028
02029
02030
02031
02032
02033
02034
02035
02036
02037
02038 static void do_exec(st_command* command)
02039 {
02040 int error;
02041 char buf[512];
02042 FILE *res_file;
02043 char *cmd= command->first_argument;
02044 string ds_cmd;
02045
02046
02047 while (*cmd && charset_info->isspace(*cmd))
02048 cmd++;
02049 if (!*cmd)
02050 die("Missing argument in exec");
02051 command->last_argument= command->end;
02052
02053
02054 do_eval(&ds_cmd, cmd, command->end, !is_windows);
02055
02056
02057 if (builtin_echo[0] && strncmp(cmd, "echo", 4) == 0)
02058 {
02059
02060 replace(&ds_cmd, "echo", 4, builtin_echo, strlen(builtin_echo));
02061 }
02062
02063 if (!(res_file= popen(ds_cmd.c_str(), "r")) && command->abort_on_error)
02064 {
02065 die("popen(\"%s\", \"r\") failed", command->first_argument);
02066 }
02067
02068 while (fgets(buf, sizeof(buf), res_file))
02069 {
02070 if (disable_result_log)
02071 {
02072 buf[strlen(buf)-1]=0;
02073 }
02074 else
02075 {
02076 replace_append(&ds_res, buf);
02077 }
02078 }
02079 error= pclose(res_file);
02080 if (error > 0)
02081 {
02082 uint32_t status= WEXITSTATUS(error), i;
02083 bool ok= 0;
02084
02085 if (command->abort_on_error)
02086 {
02087 log_msg("exec of '%s' failed, error: %d, status: %d, errno: %d", ds_cmd.c_str(), error, status, errno);
02088 die("command \"%s\" failed", command->first_argument);
02089 }
02090
02091 for (i= 0; i < command->expected_errors.count; i++)
02092 {
02093 if ((command->expected_errors.err[i].type == ERR_ERRNO) &&
02094 (command->expected_errors.err[i].code.errnum == status))
02095 {
02096 ok= 1;
02097 }
02098 }
02099 if (!ok)
02100 {
02101 die("command \"%s\" failed with wrong error: %d",
02102 command->first_argument, status);
02103 }
02104 }
02105 else if (command->expected_errors.err[0].type == ERR_ERRNO &&
02106 command->expected_errors.err[0].code.errnum != 0)
02107 {
02108
02109 log_msg("exec of '%s failed, error: %d, errno: %d", ds_cmd.c_str(), error, errno);
02110 die("command \"%s\" succeeded - should have failed with errno %d...",
02111 command->first_argument, command->expected_errors.err[0].code.errnum);
02112 }
02113
02114 return;
02115 }
02116
02117 enum enum_operator
02118 {
02119 DO_DEC,
02120 DO_INC
02121 };
02122
02123
02124
02125
02126
02127
02128
02129
02130
02131
02132
02133
02134
02135
02136
02137
02138 static int do_modify_var(st_command* command,
02139 enum enum_operator op)
02140 {
02141 const char *p= command->first_argument;
02142 VAR* v;
02143 if (!*p)
02144 die("Missing argument to %.*s", command->first_word_len, command->query);
02145 if (*p != '$')
02146 die("The argument to %.*s must be a variable (start with $)",
02147 command->first_word_len, command->query);
02148 v= var_get(p, &p, 1, 0);
02149 switch (op) {
02150 case DO_DEC:
02151 v->int_val--;
02152 break;
02153 case DO_INC:
02154 v->int_val++;
02155 break;
02156 default:
02157 die("Invalid operator to do_modify_var");
02158 break;
02159 }
02160 v->int_dirty= 1;
02161 command->last_argument= (char*)++p;
02162 return 0;
02163 }
02164
02165
02166
02167
02168
02169
02170
02171
02172
02173
02174
02175
02176
02177
02178
02179 static void do_system(st_command* command)
02180 {
02181 string ds_cmd;
02182
02183
02184 if (strlen(command->first_argument) == 0)
02185 die("Missing arguments to system, nothing to do!");
02186
02187
02188 do_eval(&ds_cmd, command->first_argument, command->end, !is_windows);
02189
02190 if (system(ds_cmd.c_str()))
02191 {
02192 if (command->abort_on_error)
02193 die("system command '%s' failed", command->first_argument);
02194
02195
02196 ds_res += "system command '";
02197 replace_append(&ds_res, command->first_argument);
02198 ds_res += "' failed\n";
02199 }
02200
02201 command->last_argument= command->end;
02202 return;
02203 }
02204
02205
02206
02207
02208
02209
02210
02211
02212
02213
02214
02215
02216 static void do_remove_file(st_command* command)
02217 {
02218 string ds_filename;
02219 const struct command_arg rm_args[] = {
02220 { "filename", ARG_STRING, true, &ds_filename, "File to delete" }
02221 };
02222
02223
02224 check_command_args(command, command->first_argument,
02225 rm_args, sizeof(rm_args)/sizeof(struct command_arg),
02226 ' ');
02227
02228 int error= internal::my_delete(ds_filename.c_str(), MYF(0)) != 0;
02229 handle_command_error(command, error);
02230 }
02231
02232
02233
02234
02235
02236
02237
02238
02239
02240
02241
02242
02243
02244
02245 static void do_copy_file(st_command* command)
02246 {
02247 string ds_from_file;
02248 string ds_to_file;
02249 const struct command_arg copy_file_args[] = {
02250 { "from_file", ARG_STRING, true, &ds_from_file, "Filename to copy from" },
02251 { "to_file", ARG_STRING, true, &ds_to_file, "Filename to copy to" }
02252 };
02253
02254
02255 check_command_args(command, command->first_argument,
02256 copy_file_args,
02257 sizeof(copy_file_args)/sizeof(struct command_arg),
02258 ' ');
02259
02260 int error= (internal::my_copy(ds_from_file.c_str(), ds_to_file.c_str(),
02261 MYF(MY_DONT_OVERWRITE_FILE)) != 0);
02262 handle_command_error(command, error);
02263 }
02264
02265
02266
02267
02268
02269
02270
02271
02272
02273
02274
02275
02276
02277 static void do_chmod_file(st_command* command)
02278 {
02279 long mode= 0;
02280 string ds_mode;
02281 string ds_file;
02282 const struct command_arg chmod_file_args[] = {
02283 { "mode", ARG_STRING, true, &ds_mode, "Mode of file(octal) ex. 0660"},
02284 { "filename", ARG_STRING, true, &ds_file, "Filename of file to modify" }
02285 };
02286
02287
02288 check_command_args(command, command->first_argument,
02289 chmod_file_args,
02290 sizeof(chmod_file_args)/sizeof(struct command_arg),
02291 ' ');
02292
02293
02294 istringstream buff(ds_mode);
02295 if (ds_mode.length() != 4 ||
02296 (buff >> oct >> mode).fail())
02297 die("You must write a 4 digit octal number for mode");
02298
02299 handle_command_error(command, chmod(ds_file.c_str(), mode));
02300 }
02301
02302
02303
02304
02305
02306
02307
02308
02309
02310
02311
02312
02313 static void do_file_exist(st_command* command)
02314 {
02315 string ds_filename;
02316 const struct command_arg file_exist_args[] = {
02317 { "filename", ARG_STRING, true, &ds_filename, "File to check if it exist" }
02318 };
02319
02320
02321 check_command_args(command, command->first_argument,
02322 file_exist_args,
02323 sizeof(file_exist_args)/sizeof(struct command_arg),
02324 ' ');
02325
02326 int error= access(ds_filename.c_str(), F_OK) != 0;
02327 handle_command_error(command, error);
02328 }
02329
02330
02331
02332
02333
02334
02335
02336
02337
02338
02339
02340
02341 static void do_mkdir(st_command* command)
02342 {
02343 string ds_dirname;
02344 const struct command_arg mkdir_args[] = {
02345 {"dirname", ARG_STRING, true, &ds_dirname, "Directory to create"}
02346 };
02347
02348
02349 check_command_args(command, command->first_argument,
02350 mkdir_args, sizeof(mkdir_args)/sizeof(struct command_arg),
02351 ' ');
02352
02353 int error= mkdir(ds_dirname.c_str(), (0777 & internal::my_umask_dir)) != 0;
02354 handle_command_error(command, error);
02355 }
02356
02357
02358
02359
02360
02361
02362
02363
02364
02365
02366
02367 static void do_rmdir(st_command* command)
02368 {
02369 string ds_dirname;
02370 const struct command_arg rmdir_args[] = {
02371 {"dirname", ARG_STRING, true, &ds_dirname, "Directory to remove"}
02372 };
02373
02374
02375 check_command_args(command, command->first_argument,
02376 rmdir_args, sizeof(rmdir_args)/sizeof(struct command_arg),
02377 ' ');
02378
02379 int error= rmdir(ds_dirname.c_str()) != 0;
02380 handle_command_error(command, error);
02381 }
02382
02383
02384
02385
02386
02387
02388
02389
02390
02391
02392
02393
02394 static int my_getc(FILE *file)
02395 {
02396 if (line_buffer_pos == line_buffer)
02397 return fgetc(file);
02398 return *--line_buffer_pos;
02399 }
02400
02401
02402 static void my_ungetc(int c)
02403 {
02404 *line_buffer_pos++= (char) c;
02405 }
02406
02407
02408 static void read_until_delimiter(string *ds,
02409 string *ds_delimiter)
02410 {
02411 if (ds_delimiter->length() > MAX_DELIMITER_LENGTH)
02412 die("Max delimiter length(%d) exceeded", MAX_DELIMITER_LENGTH);
02413
02414
02415 while (1)
02416 {
02417 char c= my_getc(cur_file->file);
02418
02419 if (c == '\n')
02420 {
02421 cur_file->lineno++;
02422
02423
02424 if (start_lineno == (cur_file->lineno - 1))
02425 continue;
02426 }
02427 else if (start_lineno == cur_file->lineno)
02428 {
02429
02430
02431
02432
02433 die("Trailing characters found after command");
02434 }
02435
02436 if (feof(cur_file->file))
02437 die("End of file encountered before '%s' delimiter was found",
02438 ds_delimiter->c_str());
02439
02440 if (match_delimiter(c, ds_delimiter->c_str(), ds_delimiter->length()))
02441 break;
02442
02443 ds->push_back(c);
02444 }
02445 }
02446
02447
02448 static void do_write_file_command(st_command* command, bool append)
02449 {
02450 string ds_content;
02451 string ds_filename;
02452 string ds_delimiter;
02453 const struct command_arg write_file_args[] = {
02454 { "filename", ARG_STRING, true, &ds_filename, "File to write to" },
02455 { "delimiter", ARG_STRING, false, &ds_delimiter, "Delimiter to read until" }
02456 };
02457
02458
02459 check_command_args(command,
02460 command->first_argument,
02461 write_file_args,
02462 sizeof(write_file_args)/sizeof(struct command_arg),
02463 ' ');
02464
02465
02466 if (ds_delimiter.length() == 0)
02467 ds_delimiter += "EOF";
02468
02469 if (!append && access(ds_filename.c_str(), F_OK) == 0)
02470 {
02471
02472 die("File already exist: '%s'", ds_filename.c_str());
02473 }
02474
02475 read_until_delimiter(&ds_content, &ds_delimiter);
02476 str_to_file2(ds_filename.c_str(), ds_content.c_str(), ds_content.length(), append);
02477 }
02478
02479
02480
02481
02482
02483
02484
02485
02486
02487
02488
02489
02490
02491
02492
02493
02494
02495
02496
02497
02498
02499
02500
02501
02502
02503
02504
02505
02506
02507 static void do_write_file(st_command* command)
02508 {
02509 do_write_file_command(command, false);
02510 }
02511
02512
02513
02514
02515
02516
02517
02518
02519
02520
02521
02522
02523
02524
02525
02526
02527
02528
02529
02530
02531
02532
02533
02534
02535
02536
02537
02538 static void do_append_file(st_command* command)
02539 {
02540 do_write_file_command(command, true);
02541 }
02542
02543
02544
02545
02546
02547
02548
02549
02550
02551
02552
02553
02554
02555
02556 static void do_cat_file(st_command* command)
02557 {
02558 static string ds_filename;
02559 const struct command_arg cat_file_args[] = {
02560 { "filename", ARG_STRING, true, &ds_filename, "File to read from" }
02561 };
02562
02563
02564 check_command_args(command,
02565 command->first_argument,
02566 cat_file_args,
02567 sizeof(cat_file_args)/sizeof(struct command_arg),
02568 ' ');
02569
02570 cat_file(ds_res, ds_filename.c_str());
02571 }
02572
02573
02574
02575
02576
02577
02578
02579
02580
02581
02582
02583
02584
02585
02586 static void do_diff_files(st_command* command)
02587 {
02588 string ds_filename;
02589 string ds_filename2;
02590 const struct command_arg diff_file_args[] = {
02591 { "file1", ARG_STRING, true, &ds_filename, "First file to diff" },
02592 { "file2", ARG_STRING, true, &ds_filename2, "Second file to diff" }
02593 };
02594
02595
02596 check_command_args(command,
02597 command->first_argument,
02598 diff_file_args,
02599 sizeof(diff_file_args)/sizeof(struct command_arg),
02600 ' ');
02601
02602 int error= compare_files(ds_filename.c_str(), ds_filename2.c_str());
02603 if (error)
02604 {
02605
02606
02607
02608 show_diff(&ds_res, ds_filename.c_str(), ds_filename2.c_str());
02609 }
02610
02611 handle_command_error(command, error);
02612 }
02613
02614
02615
02616
02617
02618
02619
02620
02621
02622
02623
02624 static void do_send_quit(st_command* command)
02625 {
02626 char* p= command->first_argument;
02627
02628 if (not *p)
02629 die("Missing connection name in send_quit");
02630 char* name= p;
02631 while (*p && !charset_info->isspace(*p))
02632 p++;
02633
02634 if (*p)
02635 *p++= 0;
02636 command->last_argument= p;
02637
02638 st_connection* con= find_ptr2(g_connections, name);
02639 if (not con)
02640 die("connection '%s' not found in connection pool", name);
02641
02642 drizzle::result_c result;
02643 drizzle_return_t ret;
02644 drizzle_quit(*con, result, &ret);
02645 }
02646
02647
02648
02649
02650
02651
02652
02653
02654
02655
02656
02657
02658
02659
02660
02661
02662
02663
02664 static void do_change_user(st_command *)
02665 {
02666 assert(0);
02667 }
02668
02669
02670
02671
02672
02673
02674
02675
02676
02677
02678
02679
02680
02681
02682
02683
02684
02685
02686
02687
02688 static void do_perl(st_command* command)
02689 {
02690 char buf[FN_REFLEN];
02691 char temp_file_path[FN_REFLEN];
02692 string ds_script;
02693 string ds_delimiter;
02694 const command_arg perl_args[] = {
02695 { "delimiter", ARG_STRING, false, &ds_delimiter, "Delimiter to read until" }
02696 };
02697
02698
02699 check_command_args(command,
02700 command->first_argument,
02701 perl_args,
02702 sizeof(perl_args)/sizeof(struct command_arg),
02703 ' ');
02704
02705
02706 if (ds_delimiter.length() == 0)
02707 ds_delimiter += "EOF";
02708
02709 read_until_delimiter(&ds_script, &ds_delimiter);
02710
02711
02712 int fd= internal::create_temp_file(temp_file_path, getenv("MYSQLTEST_VARDIR"), "tmp", MYF(MY_WME));
02713 if (fd < 0)
02714 die("Failed to create temporary file for perl command");
02715 internal::my_close(fd, MYF(0));
02716
02717 str_to_file(temp_file_path, ds_script.c_str(), ds_script.length());
02718
02719
02720 snprintf(buf, sizeof(buf), "perl %s", temp_file_path);
02721
02722 FILE* res_file= popen(buf, "r");
02723 if (not res_file && command->abort_on_error)
02724 die("popen(\"%s\", \"r\") failed", buf);
02725
02726 while (fgets(buf, sizeof(buf), res_file))
02727 {
02728 if (disable_result_log)
02729 buf[strlen(buf)-1]=0;
02730 else
02731 replace_append(&ds_res, buf);
02732 }
02733 int error= pclose(res_file);
02734
02735
02736 internal::my_delete(temp_file_path, MYF(0));
02737
02738 handle_command_error(command, WEXITSTATUS(error));
02739 }
02740
02741
02742
02743
02744
02745
02746
02747
02748
02749
02750
02751
02752
02753
02754
02755
02756
02757
02758
02759
02760
02761
02762
02763
02764
02765
02766 static void do_echo(st_command* command)
02767 {
02768 string ds_echo;
02769 do_eval(&ds_echo, command->first_argument, command->end, false);
02770 ds_res += ds_echo;
02771 ds_res += "\n";
02772 command->last_argument= command->end;
02773 }
02774
02775 static void do_wait_for_slave_to_stop()
02776 {
02777 static int SLAVE_POLL_INTERVAL= 300000;
02778 drizzle::connection_c& con= *cur_con;
02779 for (;;)
02780 {
02781 drizzle::result_c res;
02782 dt_query(con, res, "show status like 'Slave_running'");
02783 drizzle_row_t row= res.row_next();
02784 if (!row || !row[1])
02785 {
02786 die("Strange result from query while probing slave for stop");
02787 }
02788 if (!strcmp(row[1], "OFF"))
02789 break;
02790 usleep(SLAVE_POLL_INTERVAL);
02791 }
02792 }
02793
02794 static void do_sync_with_master2(long offset)
02795 {
02796 drizzle::connection_c& con= *cur_con;
02797
02798 if (!master_pos.file[0])
02799 die("Calling 'sync_with_master' without calling 'save_master_pos'");
02800
02801 char query_buf[FN_REFLEN+128];
02802 snprintf(query_buf, sizeof(query_buf), "select master_pos_wait('%s', %ld)", master_pos.file, master_pos.pos + offset);
02803 for (int tries= 0; tries < 30; tries++)
02804 {
02805 drizzle::result_c res;
02806 dt_query(con, res, query_buf);
02807
02808 drizzle_row_t row= res.row_next();
02809 if (not row)
02810 die("empty result in %s", query_buf);
02811 if (row[0])
02812 return;
02813
02814
02815
02816
02817 sleep(1);
02818 }
02819 show_query(con, "SHOW MASTER STATUS");
02820 show_query(con, "SHOW SLAVE STATUS");
02821 die("could not sync with master ('%s' returned NULL)", query_buf);
02822 }
02823
02824 static void do_sync_with_master(st_command* command)
02825 {
02826 long offset= 0;
02827 char *p= command->first_argument;
02828 const char *offset_start= p;
02829 if (*offset_start)
02830 {
02831 for (; charset_info->isdigit(*p); p++)
02832 offset = offset * 10 + *p - '0';
02833
02834 if(*p && !charset_info->isspace(*p))
02835 die("Invalid integer argument \"%s\"", offset_start);
02836 command->last_argument= p;
02837 }
02838 do_sync_with_master2(offset);
02839 return;
02840 }
02841
02842
02843
02844
02845
02846
02847 static void do_save_master_pos()
02848 {
02849 drizzle::result_c res;
02850 dt_query(*cur_con, res, "show master status");
02851 drizzle_row_t row= res.row_next();
02852 if (!row)
02853 die("empty result in show master status");
02854 strncpy(master_pos.file, row[0], sizeof(master_pos.file)-1);
02855 master_pos.pos = strtoul(row[1], (char**) 0, 10);
02856 }
02857
02858
02859
02860
02861
02862
02863
02864
02865
02866
02867
02868
02869
02870
02871
02872
02873
02874
02875
02876
02877
02878 static void do_let(st_command* command)
02879 {
02880 char *p= command->first_argument;
02881 char *var_name, *var_name_end;
02882 string let_rhs_expr;
02883
02884
02885
02886 if (!*p)
02887 die("Missing arguments to let");
02888 var_name= p;
02889 while (*p && (*p != '=') && !charset_info->isspace(*p))
02890 p++;
02891 var_name_end= p;
02892 if (var_name == var_name_end ||
02893 (var_name+1 == var_name_end && *var_name == '$'))
02894 die("Missing variable name in let");
02895 while (charset_info->isspace(*p))
02896 p++;
02897 if (*p++ != '=')
02898 die("Missing assignment operator in let");
02899
02900
02901 while (*p && charset_info->isspace(*p))
02902 p++;
02903
02904 do_eval(&let_rhs_expr, p, command->end, false);
02905
02906 command->last_argument= command->end;
02907
02908 var_set(var_name, var_name_end, let_rhs_expr.c_str(),
02909 (let_rhs_expr.c_str() + let_rhs_expr.length()));
02910 return;
02911 }
02912
02913
02914
02915
02916
02917
02918
02919
02920
02921
02922
02923
02924
02925
02926
02927
02928
02929
02930
02931
02932
02933
02934
02935
02936 static void do_sleep(st_command* command, bool real_sleep)
02937 {
02938 char *p= command->first_argument;
02939 char *sleep_start, *sleep_end= command->end;
02940 double sleep_val= 0;
02941
02942 while (charset_info->isspace(*p))
02943 p++;
02944 if (!*p)
02945 die("Missing argument to %.*s", command->first_word_len, command->query);
02946 sleep_start= p;
02947
02948 if (!charset_info->isdigit(*sleep_start))
02949 die("Invalid argument to %.*s \"%s\"", command->first_word_len,
02950 command->query,command->first_argument);
02951 string buff_str(sleep_start, sleep_end-sleep_start);
02952 istringstream buff(buff_str);
02953 buff >> sleep_val;
02954 if (buff.fail())
02955 die("Invalid argument to %.*s \"%s\"", command->first_word_len, command->query, command->first_argument);
02956
02957
02958 if (opt_sleep >= 0 && !real_sleep)
02959 sleep_val= opt_sleep;
02960
02961 if (sleep_val)
02962 usleep(sleep_val * 1000000);
02963 command->last_argument= sleep_end;
02964 }
02965
02966
02967 static void do_get_file_name(st_command* command, string &dest)
02968 {
02969 char *p= command->first_argument;
02970 if (!*p)
02971 die("Missing file name argument");
02972 char *name= p;
02973 while (*p && !charset_info->isspace(*p))
02974 p++;
02975 if (*p)
02976 *p++= 0;
02977 command->last_argument= p;
02978 if (! opt_testdir.empty())
02979 {
02980 dest= opt_testdir;
02981 if (dest[dest.length()] != '/')
02982 dest += "/";
02983 }
02984 dest.append(name);
02985 }
02986
02987
02988 static void do_set_charset(st_command* command)
02989 {
02990 char *charset_name= command->first_argument;
02991 char *p;
02992
02993 if (!charset_name || !*charset_name)
02994 die("Missing charset name in 'character_set'");
02995
02996 p= charset_name;
02997 while (*p && !charset_info->isspace(*p))
02998 p++;
02999 if(*p)
03000 *p++= 0;
03001 command->last_argument= p;
03002 charset_info= get_charset_by_csname(charset_name, MY_CS_PRIMARY);
03003 if (!charset_info)
03004 abort_not_supported_test("Test requires charset '%s'", charset_name);
03005 }
03006
03007 static void fill_global_error_names()
03008 {
03009 drizzle::connection_c& con= *cur_con;
03010
03011 global_error_names.clear();
03012
03013 drizzle::result_c res;
03014 dt_query(con, res, "select error_name, error_code from data_dictionary.errors");
03015 while (drizzle_row_t row= res.row_next())
03016 {
03017 if (not row[0])
03018 break;
03019
03020
03021
03022
03023 size_t *lengths= res.row_field_sizes();
03024 try
03025 {
03026 global_error_names[string(row[0], lengths[0])] = boost::lexical_cast<uint32_t>(string(row[1], lengths[1]));
03027 }
03028 catch (boost::bad_lexical_cast &ex)
03029 {
03030 die("Invalid error_code from Drizzle: %s", ex.what());
03031 }
03032 }
03033 }
03034
03035 static uint32_t get_errcode_from_name(const char *error_name, const char *error_end)
03036 {
03037 string error_name_s(error_name, error_end);
03038
03039 if (ErrorCodes::mapped_type* ptr= find_ptr(global_error_names, error_name_s))
03040 return *ptr;
03041
03042 die("Unknown SQL error name '%s'", error_name_s.c_str());
03043 return 0;
03044 }
03045
03046 static void do_get_errcodes(st_command* command)
03047 {
03048 struct st_match_err *to= saved_expected_errors.err;
03049 char *p= command->first_argument;
03050 uint32_t count= 0;
03051
03052
03053
03054 if (!*p)
03055 die("Missing argument(s) to 'error'");
03056
03057 do
03058 {
03059 char *end;
03060
03061
03062 while (*p && *p == ' ')
03063 p++;
03064
03065
03066 end= p;
03067 while (*end && *end != ',' && *end != ' ')
03068 end++;
03069
03070 if (*p == 'S')
03071 {
03072 char *to_ptr= to->code.sqlstate;
03073
03074
03075
03076
03077
03078
03079 p++;
03080 if ((end - p) != DRIZZLE_MAX_SQLSTATE_SIZE)
03081 die("The sqlstate must be exactly %d chars long", DRIZZLE_MAX_SQLSTATE_SIZE);
03082
03083
03084 while (*p && p < end)
03085 {
03086 if (charset_info->isdigit(*p) || charset_info->isupper(*p))
03087 *to_ptr++= *p++;
03088 else
03089 die("The sqlstate may only consist of digits[0-9] and _uppercase_ letters");
03090 }
03091
03092 *to_ptr= 0;
03093 to->type= ERR_SQLSTATE;
03094 }
03095 else if (*p == 's')
03096 {
03097 die("The sqlstate definition must start with an uppercase S");
03098 }
03099 else if (*p == 'E')
03100 {
03101
03102
03103 to->code.errnum= get_errcode_from_name(p, end);
03104 to->type= ERR_ERRNO;
03105 }
03106 else if (*p == 'e')
03107 {
03108 die("The error name definition must start with an uppercase E");
03109 }
03110 else if (*p == 'H')
03111 {
03112
03113
03114 to->code.errnum= get_errcode_from_name(p, end);
03115 to->type= ERR_ERRNO;
03116 }
03117 else
03118 {
03119 die ("You must either use the SQLSTATE or built in drizzle error label, numbers are not accepted");
03120 }
03121 to++;
03122 count++;
03123
03124 if (count >= (sizeof(saved_expected_errors.err) /
03125 sizeof(struct st_match_err)))
03126 die("Too many errorcodes specified");
03127
03128
03129 p= end;
03130
03131
03132 while (*p && *p != ',')
03133 p++;
03134
03135 if (*p)
03136 p++;
03137
03138 } while (*p);
03139
03140 command->last_argument= p;
03141 to->type= ERR_EMPTY;
03142
03143 saved_expected_errors.count= count;
03144 return;
03145 }
03146
03147
03148
03149
03150
03151
03152
03153
03154
03155 static char *get_string(char **to_ptr, char **from_ptr,
03156 st_command* command)
03157 {
03158 char c, sep;
03159 char *to= *to_ptr, *from= *from_ptr, *start=to;
03160
03161
03162
03163 if (*from == '"' || *from == '\'')
03164 sep= *from++;
03165 else
03166 sep=' ';
03167
03168 for ( ; (c=*from) ; from++)
03169 {
03170 if (c == '\\' && from[1])
03171 {
03172
03173 switch (*++from) {
03174 case 'n':
03175 *to++= '\n';
03176 break;
03177 case 't':
03178 *to++= '\t';
03179 break;
03180 case 'r':
03181 *to++ = '\r';
03182 break;
03183 case 'b':
03184 *to++ = '\b';
03185 break;
03186 case 'Z':
03187 *to++='\032';
03188 break;
03189 default:
03190 *to++ = *from;
03191 break;
03192 }
03193 }
03194 else if (c == sep)
03195 {
03196 if (c == ' ' || c != *++from)
03197 break;
03198 *to++=c;
03199 }
03200 else
03201 *to++=c;
03202 }
03203 if (*from != ' ' && *from)
03204 die("Wrong string argument in %s", command->query);
03205
03206 while (charset_info->isspace(*from))
03207 from++;
03208
03209 *to =0;
03210 *to_ptr= to+1;
03211 *from_ptr= from;
03212
03213
03214 if (*start == '$')
03215 {
03216 const char *end= to;
03217 VAR *var=var_get(start, &end, 0, 1);
03218 if (var && to == (char*) end+1)
03219 return(var->str_val);
03220 }
03221 return(start);
03222 }
03223
03224
03225 static void set_reconnect(drizzle_con_st *con, int val)
03226 {
03227 (void) con;
03228 (void) val;
03229
03230
03231
03232
03233
03234 }
03235
03236
03237 static void select_connection_name(const char *name)
03238 {
03239 if (!(cur_con= find_ptr2(g_connections, name)))
03240 die("connection '%s' not found in connection pool", name);
03241
03242
03243 var_set_drizzleclient_get_server_version(*cur_con);
03244 }
03245
03246
03247 static void select_connection(st_command* command)
03248 {
03249 char *p= command->first_argument;
03250 if (!*p)
03251 die("Missing connection name in connect");
03252 char* name= p;
03253 while (*p && !charset_info->isspace(*p))
03254 p++;
03255 if (*p)
03256 *p++= 0;
03257 command->last_argument= p;
03258 select_connection_name(name);
03259 }
03260
03261
03262 static void do_close_connection(st_command* command)
03263 {
03264 char* p= command->first_argument;
03265 if (!*p)
03266 die("Missing connection name in disconnect");
03267 char* name= p;
03268 while (*p && !charset_info->isspace(*p))
03269 p++;
03270
03271 if (*p)
03272 *p++= 0;
03273 command->last_argument= p;
03274
03275 st_connection* con= find_ptr2(g_connections, name);
03276 if (!con)
03277 die("connection '%s' not found in connection pool", name);
03278 g_connections.erase(name);
03279 delete con;
03280 }
03281
03282
03283
03284
03285
03286
03287
03288
03289
03290
03291
03292
03293
03294
03295
03296
03297
03298
03299
03300
03301
03302
03303
03304
03305
03306
03307
03308 static st_connection* safe_connect(const char *name, const string host, const string user, const char *pass, const string db, uint32_t port)
03309 {
03310 uint32_t failed_attempts= 0;
03311 st_connection* con0= new st_connection;
03312 drizzle_con_st* con= *con0;
03313 drizzle_con_set_tcp(con, host.c_str(), port);
03314 drizzle_con_set_auth(con, user.c_str(), pass);
03315 while (drizzle_return_t ret= drizzle_con_connect(con))
03316 {
03317
03318
03319
03320
03321
03322
03323
03324
03325 if ((ret == DRIZZLE_RETURN_GETADDRINFO ||
03326 ret == DRIZZLE_RETURN_COULD_NOT_CONNECT) &&
03327 failed_attempts < opt_max_connect_retries)
03328 {
03329 verbose_msg("Connect attempt %d/%d failed: %d: %s", failed_attempts, opt_max_connect_retries, ret, drizzle_con_error(con));
03330 usleep(100000);
03331 }
03332 else
03333 {
03334 if (failed_attempts > 0)
03335 die("Could not open connection '%s' after %d attempts: %d %s", name, failed_attempts, ret, drizzle_con_error(con));
03336 else
03337 die("Could not open connection '%s': %d %s", name, ret, drizzle_con_error(con));
03338 }
03339 failed_attempts++;
03340 }
03341
03342 {
03343 std::string sql_string("CREATE SCHEMA IF NOT EXISTS mysql");
03344 drizzle_return_t ret;
03345 drizzle_result_st *result= drizzle_query(con, NULL, sql_string.c_str(), sql_string.size(), &ret);
03346 if (ret != DRIZZLE_RETURN_OK)
03347 {
03348 die("Failed to create schema '%s': %d %s", db.c_str(), ret, drizzle_con_error(con));
03349 }
03350
03351 if (result)
03352 {
03353 drizzle_result_free(result);
03354 }
03355 }
03356
03357 {
03358 std::string sql_string("CREATE SCHEMA IF NOT EXISTS ");
03359 sql_string+= db;
03360 drizzle_return_t ret;
03361 drizzle_result_st *result= drizzle_query(con, NULL, sql_string.c_str(), sql_string.size(), &ret);
03362 if (ret != DRIZZLE_RETURN_OK)
03363 {
03364 die("Failed to create schema '%s': %d %s", db.c_str(), ret, drizzle_con_error(con));
03365 }
03366
03367 if (result)
03368 {
03369 drizzle_result_free(result);
03370 }
03371 }
03372
03373 {
03374 std::string sql_string("USE ");
03375 sql_string+= db;
03376 drizzle_return_t ret;
03377 drizzle_result_st *result= drizzle_query(con, NULL, sql_string.c_str(), sql_string.size(), &ret);
03378 if (ret != DRIZZLE_RETURN_OK)
03379 {
03380 die("Failed to use schema '%s': %d %s", db.c_str(), ret, drizzle_con_error(con));
03381 }
03382
03383 if (result)
03384 {
03385 drizzle_result_free(result);
03386 }
03387 }
03388
03389 return con0;
03390 }
03391
03392
03393
03394
03395
03396
03397
03398
03399
03400
03401
03402
03403
03404
03405
03406
03407
03408
03409
03410
03411
03412
03413
03414
03415
03416 static int connect_n_handle_errors(st_command* command,
03417 drizzle_con_st *con, const char* host,
03418 const char* user, const char* pass,
03419 const char* db, int port, const char* sock)
03420 {
03421
03422 if (!command->abort_on_error &&
03423 !disable_query_log)
03424 {
03425
03426
03427
03428 ds_res += "connect(";
03429 replace_append(&ds_res, host);
03430 ds_res += ",";
03431 replace_append(&ds_res, user);
03432 ds_res += ",";
03433 replace_append(&ds_res, pass);
03434 ds_res += ",";
03435 if (db)
03436 replace_append(&ds_res, db);
03437 ds_res += ",";
03438 replace_append_uint(ds_res, port);
03439 ds_res += ",";
03440 if (sock)
03441 replace_append(&ds_res, sock);
03442 ds_res += ")";
03443 ds_res += delimiter;
03444 ds_res += "\n";
03445 }
03446 drizzle_con_set_tcp(con, host, port);
03447 drizzle_con_set_auth(con, user, pass);
03448 drizzle_con_set_db(con, db);
03449 if (drizzle_return_t ret= drizzle_con_connect(con))
03450 {
03451 if (ret == DRIZZLE_RETURN_HANDSHAKE_FAILED)
03452 {
03453 var_set_errno(drizzle_con_error_code(con));
03454 handle_error(command, drizzle_con_error_code(con), drizzle_con_error(con), drizzle_con_sqlstate(con), &ds_res);
03455 }
03456 else
03457 {
03458 var_set_errno(ret);
03459 handle_error(command, ret, drizzle_con_error(con), "", &ds_res);
03460 }
03461 return 0;
03462 }
03463 var_set_errno(0);
03464 handle_no_error(command);
03465 return 1;
03466 }
03467
03468
03469
03470
03471
03472
03473
03474
03475
03476
03477
03478
03479
03480
03481
03482
03483
03484
03485
03486
03487
03488
03489
03490
03491
03492
03493
03494 static void do_connect(st_command* command)
03495 {
03496 uint32_t con_port= opt_port;
03497
03498 string ds_connection_name;
03499 string ds_host;
03500 string ds_user;
03501 string ds_password;
03502 string ds_database;
03503 string ds_port;
03504 string ds_sock;
03505 string ds_options;
03506 const struct command_arg connect_args[] = {
03507 { "connection name", ARG_STRING, true, &ds_connection_name, "Name of the connection" },
03508 { "host", ARG_STRING, true, &ds_host, "Host to connect to" },
03509 { "user", ARG_STRING, false, &ds_user, "User to connect as" },
03510 { "passsword", ARG_STRING, false, &ds_password, "Password used when connecting" },
03511 { "database", ARG_STRING, false, &ds_database, "Database to select after connect" },
03512 { "port", ARG_STRING, false, &ds_port, "Port to connect to" },
03513 { "socket", ARG_STRING, false, &ds_sock, "Socket to connect with" },
03514 { "options", ARG_STRING, false, &ds_options, "Options to use while connecting" }
03515 };
03516
03517 strip_parentheses(command);
03518 check_command_args(command, command->first_argument, connect_args,
03519 sizeof(connect_args)/sizeof(struct command_arg),
03520 ',');
03521
03522
03523 if (ds_port.length())
03524 {
03525 con_port= atoi(ds_port.c_str());
03526 if (con_port == 0)
03527 die("Illegal argument for port: '%s'", ds_port.c_str());
03528 }
03529
03530
03531 if (!ds_sock.empty())
03532 {
03533
03534
03535
03536
03537 if (*ds_sock.c_str() != FN_LIBCHAR)
03538 {
03539 char buff[FN_REFLEN];
03540 internal::fn_format(buff, ds_sock.c_str(), TMPDIR, "", 0);
03541 ds_sock= buff;
03542 }
03543 }
03544
03545
03546 const char* con_options= ds_options.c_str();
03547 while (*con_options)
03548 {
03549
03550 while (*con_options && charset_info->isspace(*con_options))
03551 con_options++;
03552
03553 const char* end= con_options;
03554 while (*end && !charset_info->isspace(*end))
03555 end++;
03556 die("Illegal option to connect: %.*s", (int) (end - con_options), con_options);
03557
03558 con_options= end;
03559 }
03560
03561 if (find_ptr2(g_connections, ds_connection_name))
03562 die("Connection %s already exists", ds_connection_name.c_str());
03563
03564 st_connection* con_slot= new st_connection;
03565
03566
03567 if (ds_database.empty())
03568 {
03569 ds_database= opt_db;
03570 }
03571
03572
03573 if (ds_database == "*NO-ONE*")
03574 {
03575 ds_database.clear();
03576 }
03577
03578 if (connect_n_handle_errors(command, *con_slot, ds_host.c_str(), ds_user.c_str(),
03579 ds_password.c_str(), ds_database.c_str(), con_port, ds_sock.c_str()))
03580 {
03581 g_connections[ds_connection_name]= con_slot;
03582 cur_con= con_slot;
03583 }
03584
03585
03586 var_set_drizzleclient_get_server_version(*cur_con);
03587 }
03588
03589
03590 static void do_done(st_command* command)
03591 {
03592
03593 if (cur_block == block_stack)
03594 {
03595 if (*command->query != '}')
03596 die("Stray 'end' command - end of block before beginning");
03597 die("Stray '}' - end of block before beginning");
03598 }
03599
03600
03601 if (cur_block->ok && cur_block->cmd == cmd_while)
03602 {
03603
03604 cur_block--;
03605 parser.current_line = cur_block->line;
03606 }
03607 else
03608 {
03609
03610 cur_block--;
03611 parser.current_line++;
03612 }
03613 }
03614
03615
03616
03617
03618
03619
03620
03621
03622
03623
03624
03625
03626
03627
03628
03629
03630
03631
03632
03633
03634
03635
03636
03637
03638
03639
03640
03641
03642 static void do_block(enum block_cmd cmd, st_command* command)
03643 {
03644 char *p= command->first_argument;
03645 const char *expr_start, *expr_end;
03646 const char *cmd_name= (cmd == cmd_while ? "while" : "if");
03647 bool not_expr= false;
03648
03649
03650 if (cur_block == block_stack_end)
03651 die("Nesting too deeply");
03652
03653
03654 cur_block->line= parser.current_line++;
03655
03656
03657 if (!cur_block->ok)
03658 {
03659
03660 cur_block++;
03661 cur_block->cmd= cmd;
03662 cur_block->ok= false;
03663 return;
03664 }
03665
03666
03667 expr_start= strchr(p, '(');
03668 if (!expr_start++)
03669 die("missing '(' in %s", cmd_name);
03670
03671
03672 if (*expr_start == '!')
03673 {
03674 not_expr= true;
03675 expr_start++;
03676 }
03677
03678 expr_end= strrchr(expr_start, ')');
03679 if (!expr_end)
03680 die("missing ')' in %s", cmd_name);
03681 p= (char*)expr_end+1;
03682
03683 while (*p && charset_info->isspace(*p))
03684 p++;
03685 if (*p && *p != '{')
03686 die("Missing '{' after %s. Found \"%s\"", cmd_name, p);
03687
03688 VAR v;
03689 var_init(&v,0,0,0,0);
03690 eval_expr(&v, expr_start, &expr_end);
03691
03692
03693 cur_block++;
03694 cur_block->cmd= cmd;
03695 cur_block->ok= (v.int_val ? true : false);
03696
03697 if (not_expr)
03698 cur_block->ok = !cur_block->ok;
03699
03700 free(v.str_val);
03701 free(v.env_s);
03702 }
03703
03704
03705 static void do_delimiter(st_command* command)
03706 {
03707 char* p= command->first_argument;
03708
03709 while (*p && charset_info->isspace(*p))
03710 p++;
03711
03712 if (!(*p))
03713 {
03714 die("Can't set empty delimiter");
03715 }
03716
03717 strncpy(delimiter, p, sizeof(delimiter) - 1);
03718 delimiter_length= strlen(delimiter);
03719
03720 command->last_argument= p + delimiter_length;
03721 }
03722
03723
03724 bool match_delimiter(int c, const char *delim, uint32_t length)
03725 {
03726 uint32_t i;
03727 char tmp[MAX_DELIMITER_LENGTH];
03728
03729 if (c != *delim)
03730 return 0;
03731
03732 for (i= 1; i < length &&
03733 (c= my_getc(cur_file->file)) == *(delim + i);
03734 i++)
03735 tmp[i]= c;
03736
03737 if (i == length)
03738 return 1;
03739
03740
03741 my_ungetc(c);
03742 while (i > 1)
03743 my_ungetc(tmp[--i]);
03744 return 0;
03745 }
03746
03747
03748 static bool end_of_query(int c)
03749 {
03750 return match_delimiter(c, delimiter, delimiter_length);
03751 }
03752
03753
03754
03755
03756
03757
03758
03759
03760
03761
03762
03763
03764
03765
03766
03767
03768
03769
03770
03771
03772
03773
03774
03775
03776
03777
03778
03779 static int my_strnncoll_simple(const charset_info_st * const cs, const unsigned char *s, size_t slen,
03780 const unsigned char *t, size_t tlen,
03781 bool t_is_prefix)
03782 {
03783 size_t len = ( slen > tlen ) ? tlen : slen;
03784 unsigned char *map= cs->sort_order;
03785 if (t_is_prefix && slen > tlen)
03786 slen=tlen;
03787 while (len--)
03788 {
03789 if (map[*s++] != map[*t++])
03790 return ((int) map[s[-1]] - (int) map[t[-1]]);
03791 }
03792
03793
03794
03795
03796 return slen > tlen ? 1 : slen < tlen ? -1 : 0 ;
03797 }
03798
03799 static int read_line(char *buf, int size)
03800 {
03801 char c, last_quote= 0;
03802 char *p= buf, *buf_end= buf + size - 1;
03803 int skip_char= 0;
03804 enum {R_NORMAL, R_Q, R_SLASH_IN_Q,
03805 R_COMMENT, R_LINE_START} state= R_LINE_START;
03806
03807
03808 start_lineno= cur_file->lineno;
03809 for (; p < buf_end ;)
03810 {
03811 skip_char= 0;
03812 c= my_getc(cur_file->file);
03813 if (feof(cur_file->file))
03814 {
03815 found_eof:
03816 if (cur_file->file != stdin)
03817 {
03818 fclose(cur_file->file);
03819 cur_file->file= 0;
03820 }
03821 free((unsigned char*) cur_file->file_name);
03822 cur_file->file_name= 0;
03823 if (cur_file == file_stack.data())
03824 {
03825
03826
03827
03828 if (cur_block != block_stack)
03829 die("Missing end of block");
03830
03831 *p= 0;
03832 return(1);
03833 }
03834 cur_file--;
03835 start_lineno= cur_file->lineno;
03836 continue;
03837 }
03838
03839 if (c == '\n')
03840 {
03841
03842 cur_file->lineno++;
03843
03844
03845 if (p != buf && *(p-1) == '\r')
03846 p--;
03847 }
03848
03849 switch(state) {
03850 case R_NORMAL:
03851 if (end_of_query(c))
03852 {
03853 *p= 0;
03854 return(0);
03855 }
03856 else if ((c == '{' &&
03857 (!my_strnncoll_simple(charset_info, (const unsigned char*) "while", 5,
03858 (unsigned char*) buf, min((ptrdiff_t)5, p - buf), 0) ||
03859 !my_strnncoll_simple(charset_info, (const unsigned char*) "if", 2,
03860 (unsigned char*) buf, min((ptrdiff_t)2, p - buf), 0))))
03861 {
03862
03863 *p++= c;
03864 *p= 0;
03865 return(0);
03866 }
03867 else if (c == '\'' || c == '"' || c == '`')
03868 {
03869 last_quote= c;
03870 state= R_Q;
03871 }
03872 break;
03873
03874 case R_COMMENT:
03875 if (c == '\n')
03876 {
03877
03878 *p= 0;
03879 return(0);
03880 }
03881 break;
03882
03883 case R_LINE_START:
03884 if (c == '#' || c == '-')
03885 {
03886
03887 state = R_COMMENT;
03888 }
03889 else if (charset_info->isspace(c))
03890 {
03891
03892 if (c == '\n')
03893 {
03894
03895 start_lineno= cur_file->lineno;
03896 }
03897 skip_char= 1;
03898 }
03899 else if (end_of_query(c))
03900 {
03901 *p= 0;
03902 return(0);
03903 }
03904 else if (c == '}')
03905 {
03906
03907 *p++= c;
03908 *p= 0;
03909 return(0);
03910 }
03911 else if (c == '\'' || c == '"' || c == '`')
03912 {
03913 last_quote= c;
03914 state= R_Q;
03915 }
03916 else
03917 state= R_NORMAL;
03918 break;
03919
03920 case R_Q:
03921 if (c == last_quote)
03922 state= R_NORMAL;
03923 else if (c == '\\')
03924 state= R_SLASH_IN_Q;
03925 break;
03926
03927 case R_SLASH_IN_Q:
03928 state= R_Q;
03929 break;
03930
03931 }
03932
03933 if (!skip_char)
03934 {
03935
03936
03937 int charlen = my_mbcharlen(charset_info, c);
03938
03939
03940 if ((charlen > 1) && (p + charlen) <= buf_end)
03941 {
03942 int i;
03943 char* mb_start = p;
03944
03945 *p++ = c;
03946
03947 for (i= 1; i < charlen; i++)
03948 {
03949 if (feof(cur_file->file))
03950 goto found_eof;
03951 c= my_getc(cur_file->file);
03952 *p++ = c;
03953 }
03954 if (! my_ismbchar(charset_info, mb_start, p))
03955 {
03956
03957
03958 while (p > mb_start)
03959 my_ungetc(*--p);
03960 }
03961 }
03962 else
03963 *p++= c;
03964 }
03965 }
03966 die("The input buffer is too small for this query.x\n" \
03967 "check your query or increase MAX_QUERY and recompile");
03968 return(0);
03969 }
03970
03971
03972
03973
03974
03975
03976
03977
03978
03979
03980
03981
03982
03983 static void convert_to_format_v1(char* query)
03984 {
03985 int last_c_was_quote= 0;
03986 char *p= query, *to= query;
03987 char *end= strchr(query, '\0');
03988 char last_c;
03989
03990 while (p <= end)
03991 {
03992 if (*p == '\n' && !last_c_was_quote)
03993 {
03994 *to++ = *p++;
03995
03996
03997 while (*p && charset_info->isspace(*p))
03998 p++;
03999
04000 last_c_was_quote= 0;
04001 }
04002 else if (*p == '\'' || *p == '"' || *p == '`')
04003 {
04004 last_c= *p;
04005 *to++ = *p++;
04006
04007
04008 while (*p && *p != last_c)
04009 *to++ = *p++;
04010
04011 *to++ = *p++;
04012
04013 last_c_was_quote= 1;
04014 }
04015 else
04016 {
04017 *to++ = *p++;
04018 last_c_was_quote= 0;
04019 }
04020 }
04021 }
04022
04023
04024
04025
04026
04027
04028
04029
04030 static void scan_command_for_warnings(st_command* command)
04031 {
04032 const char *ptr= command->query;
04033
04034 while (*ptr)
04035 {
04036
04037
04038
04039
04040 if (ptr[0] == '\n' &&
04041 ptr[1] && ptr[1] == '-' &&
04042 ptr[2] && ptr[2] == '-' &&
04043 ptr[3])
04044 {
04045 uint32_t type;
04046 char save;
04047 char *end, *start= (char*)ptr+3;
04048
04049 while (*start && charset_info->isspace(*start))
04050 start++;
04051 end= start;
04052
04053 while (*end && !charset_info->isspace(*end))
04054 end++;
04055 save= *end;
04056 *end= 0;
04057 type= command_typelib.find_type(start, TYPELIB::e_default);
04058 if (type)
04059 warning_msg("Embedded drizzletest command '--%s' detected in query '%s' was this intentional? ", start, command->query);
04060 *end= save;
04061 }
04062 ptr++;
04063 }
04064 }
04065
04066
04067
04068
04069
04070
04071
04072 static void check_eol_junk_line(const char *line)
04073 {
04074 const char *p= line;
04075
04076
04077 if (*p && !strncmp(p, delimiter, delimiter_length))
04078 die("Extra delimiter \"%s\" found", delimiter);
04079
04080
04081 if (*p && *p != '#')
04082 {
04083 if (*p == '\n')
04084 die("Missing delimiter");
04085 die("End of line junk detected: \"%s\"", p);
04086 }
04087 return;
04088 }
04089
04090 static void check_eol_junk(const char *eol)
04091 {
04092 const char *p= eol;
04093
04094
04095 while (*p && (charset_info->isspace(*p) || *p == '#' || *p == '\n'))
04096 {
04097
04098 if (*p && *p == '#')
04099 {
04100 p++;
04101 while (*p && *p != '\n')
04102 p++;
04103 }
04104
04105
04106 if (*p && *p == '\n')
04107 check_eol_junk_line(p);
04108
04109 if (*p)
04110 p++;
04111 }
04112
04113 check_eol_junk_line(p);
04114
04115 return;
04116 }
04117
04118
04119
04120
04121
04122
04123
04124
04125
04126
04127
04128
04129
04130
04131
04132
04133
04134
04135 #define MAX_QUERY (768*1024*2)
04136 static char read_command_buf[MAX_QUERY];
04137
04138 static int read_command(st_command** command_ptr)
04139 {
04140 char *p= read_command_buf;
04141 st_command* command;
04142
04143
04144 if (parser.current_line < parser.read_lines)
04145 {
04146 *command_ptr= q_lines[parser.current_line];
04147 return(0);
04148 }
04149 *command_ptr= command= new st_command;
04150 q_lines.push_back(command);
04151 command->type= Q_UNKNOWN;
04152
04153 read_command_buf[0]= 0;
04154 if (read_line(read_command_buf, sizeof(read_command_buf)))
04155 {
04156 check_eol_junk(read_command_buf);
04157 return(1);
04158 }
04159
04160 convert_to_format_v1(read_command_buf);
04161
04162 if (*p == '#')
04163 {
04164 command->type= Q_COMMENT;
04165 }
04166 else if (p[0] == '-' && p[1] == '-')
04167 {
04168 command->type= Q_COMMENT_WITH_COMMAND;
04169 p+= 2;
04170 }
04171
04172
04173 while (*p && charset_info->isspace(*p))
04174 p++;
04175
04176 command->query_buf= command->query= strdup(p);
04177
04178
04179 p= command->query;
04180 while (*p && !charset_info->isspace(*p) && *p != '(')
04181 p++;
04182 command->first_word_len= (uint32_t) (p - command->query);
04183
04184
04185 while (*p && charset_info->isspace(*p))
04186 p++;
04187 command->first_argument= p;
04188
04189 command->end= strchr(command->query, '\0');
04190 command->query_len= (command->end - command->query);
04191 parser.read_lines++;
04192
04193 return(0);
04194 }
04195
04196
04197
04198
04199
04200
04201
04202
04203
04204
04205
04206
04207 void str_to_file2(const char *fname, const char *str, int size, bool append)
04208 {
04209 char buff[FN_REFLEN];
04210 if (!internal::test_if_hard_path(fname))
04211 {
04212 snprintf(buff, sizeof(buff), "%s%s",opt_basedir.c_str(),fname);
04213 fname= buff;
04214 }
04215 internal::fn_format(buff, fname, "", "", MY_UNPACK_FILENAME);
04216
04217 int flags= O_WRONLY | O_CREAT;
04218 if (!append)
04219 flags|= O_TRUNC;
04220 int fd= internal::my_open(buff, flags, MYF(MY_WME | MY_FFNF));
04221 if (fd < 0)
04222 die("Could not open '%s' for writing: errno = %d", buff, errno);
04223 if (append && lseek(fd, 0, SEEK_END) == MY_FILEPOS_ERROR)
04224 die("Could not find end of file '%s': errno = %d", buff, errno);
04225 if (internal::my_write(fd, (unsigned char*)str, size, MYF(MY_WME|MY_FNABP)))
04226 die("write failed");
04227 internal::my_close(fd, MYF(0));
04228 }
04229
04230
04231
04232
04233
04234
04235
04236
04237
04238
04239
04240 void str_to_file(const char *fname, const char *str, int size)
04241 {
04242 str_to_file2(fname, str, size, false);
04243 }
04244
04245
04246 void dump_result_to_log_file(const char *buf, int size)
04247 {
04248 char log_file[FN_REFLEN];
04249 str_to_file(internal::fn_format(log_file, result_file_name.c_str(), opt_logdir.c_str(), ".log",
04250 ! opt_logdir.empty() ? MY_REPLACE_DIR | MY_REPLACE_EXT :
04251 MY_REPLACE_EXT),
04252 buf, size);
04253 fprintf(stderr, "\nMore results from queries before failure can be found in %s\n", log_file);
04254 }
04255
04256 void dump_progress()
04257 {
04258 char progress_file[FN_REFLEN];
04259 str_to_file(internal::fn_format(progress_file, result_file_name.c_str(),
04260 opt_logdir.c_str(), ".progress",
04261 ! opt_logdir.empty() ? MY_REPLACE_DIR | MY_REPLACE_EXT :
04262 MY_REPLACE_EXT),
04263 ds_progress.c_str(), ds_progress.length());
04264 }
04265
04266 void dump_warning_messages()
04267 {
04268 char warn_file[FN_REFLEN];
04269
04270 str_to_file(internal::fn_format(warn_file, result_file_name.c_str(), opt_logdir.c_str(), ".warnings",
04271 ! opt_logdir.empty() ? MY_REPLACE_DIR | MY_REPLACE_EXT :
04272 MY_REPLACE_EXT),
04273 ds_warning_messages.c_str(), ds_warning_messages.length());
04274 }
04275
04276
04277
04278
04279
04280
04281 static void append_field(string *ds, uint32_t col_idx, drizzle_column_st *column,
04282 const char* val, uint64_t len, bool is_null)
04283 {
04284 if (col_idx < max_replace_column && replace_column[col_idx])
04285 {
04286 val= replace_column[col_idx];
04287 len= strlen(val);
04288 }
04289 else if (is_null)
04290 {
04291 val= "NULL";
04292 len= 4;
04293 }
04294
04295 if (!display_result_vertically)
04296 {
04297 if (col_idx)
04298 ds->append("\t");
04299 replace_append_mem(*ds, val, (int)len);
04300 }
04301 else
04302 {
04303 ds->append(drizzle_column_name(column));
04304 ds->append("\t");
04305 replace_append_mem(*ds, val, (int)len);
04306 ds->append("\n");
04307 }
04308 }
04309
04310
04311
04312
04313
04314
04315
04316 static void append_result(string *ds, drizzle::result_c& res)
04317 {
04318 uint32_t num_fields= res.column_count();
04319 while (drizzle_row_t row = res.row_next())
04320 {
04321 size_t* lengths = res.row_field_sizes();
04322 res.column_seek(0);
04323 for (uint32_t i = 0; i < num_fields; i++)
04324 {
04325 drizzle_column_st* column= res.column_next();
04326 if (row[i] && drizzle_column_type(column) == DRIZZLE_COLUMN_TYPE_TINY)
04327 {
04328 if (boost::lexical_cast<uint32_t>(row[i]))
04329 {
04330 if (drizzle_column_flags(column) & DRIZZLE_COLUMN_FLAGS_UNSIGNED)
04331 {
04332 append_field(ds, i, column, "YES", 3, false);
04333 }
04334 else
04335 {
04336 append_field(ds, i, column, "TRUE", 4, false);
04337 }
04338 }
04339 else
04340 {
04341 if (drizzle_column_flags(column) & DRIZZLE_COLUMN_FLAGS_UNSIGNED)
04342 {
04343 append_field(ds, i, column, "NO", 2, false);
04344 }
04345 else
04346 {
04347 append_field(ds, i, column, "FALSE", 5, false);
04348 }
04349 }
04350 }
04351 else
04352 {
04353 append_field(ds, i, column, (const char*)row[i], lengths[i], !row[i]);
04354 }
04355 }
04356 if (!display_result_vertically)
04357 ds->append("\n");
04358 }
04359 }
04360
04361
04362
04363
04364
04365
04366 static void append_metadata(string& ds, drizzle::result_c& res)
04367 {
04368 ds += "Catalog\tDatabase\tTable\tTable_alias\tColumn\tColumn_alias\tType\tLength\tMax length\tIs_null\tFlags\tDecimals\tCharsetnr\n";
04369 res.column_seek(0);
04370 while (drizzle_column_st* column= res.column_next())
04371 {
04372 ds += drizzle_column_catalog(column);
04373 ds += "\t";
04374 ds += drizzle_column_db(column);
04375 ds += "\t";
04376 ds += drizzle_column_orig_table(column);
04377 ds += "\t";
04378 ds += drizzle_column_table(column);
04379 ds += "\t";
04380 ds += drizzle_column_orig_name(column);
04381 ds += "\t";
04382 ds += drizzle_column_name(column);
04383 ds += "\t";
04384 replace_append_uint(ds, drizzle_column_type_drizzle(column));
04385 ds += "\t";
04386 replace_append_uint(ds, drizzle_column_size(column));
04387 ds += "\t";
04388 replace_append_uint(ds, drizzle_column_type(column) == DRIZZLE_COLUMN_TYPE_TINY ? 1 : drizzle_column_max_size(column));
04389 ds += "\t";
04390 ds += drizzle_column_flags(column) & DRIZZLE_COLUMN_FLAGS_NOT_NULL ? "N" : "Y";
04391 ds += "\t";
04392 replace_append_uint(ds, drizzle_column_flags(column));
04393 ds += "\t";
04394 replace_append_uint(ds, drizzle_column_decimals(column));
04395 ds += "\t";
04396 replace_append_uint(ds, drizzle_column_charset(column));
04397 ds += "\n";
04398 }
04399 }
04400
04401
04402
04403
04404
04405
04406 static void append_info(string *ds, uint64_t affected_rows,
04407 const char *info)
04408 {
04409 ostringstream buf;
04410 buf << "affected rows: " << affected_rows << endl;
04411 ds->append(buf.str());
04412 if (info && strcmp(info, ""))
04413 {
04414 ds->append("info: ");
04415 ds->append(info);
04416 ds->append("\n", 1);
04417 }
04418 }
04419
04420
04421
04422
04423
04424
04425 static void append_table_headings(string& ds, drizzle::result_c& res)
04426 {
04427 uint32_t col_idx= 0;
04428 res.column_seek(0);
04429 while (drizzle_column_st* column= res.column_next())
04430 {
04431 if (col_idx)
04432 ds += "\t";
04433 replace_append(&ds, drizzle_column_name(column));
04434 col_idx++;
04435 }
04436 ds += "\n";
04437 }
04438
04439
04440
04441
04442
04443
04444
04445
04446 static int append_warnings(string& ds, drizzle::connection_c& con, drizzle::result_c& res)
04447 {
04448 uint32_t count= drizzle_result_warning_count(res);
04449 if (!count)
04450 return 0;
04451
04452 drizzle::result_c warn_res;
04453 dt_query(con, warn_res, "show warnings");
04454 append_result(&ds, warn_res);
04455 return count;
04456 }
04457
04458
04459
04460
04461
04462
04463
04464
04465
04466
04467
04468
04469
04470
04471
04472 static void run_query_normal(st_connection& cn,
04473 st_command* command,
04474 int flags, char *query, int query_len,
04475 string *ds, string& ds_warnings)
04476 {
04477 drizzle_return_t ret;
04478 drizzle_con_st *con= cn;
04479 int err= 0;
04480
04481 drizzle_con_add_options(con, DRIZZLE_CON_NO_RESULT_READ);
04482
04483 drizzle::result_c res;
04484 if (flags & QUERY_SEND_FLAG)
04485 {
04486
04487
04488
04489
04490 (void) drizzle_query(con, res, query, query_len, &ret);
04491 if (ret != DRIZZLE_RETURN_OK)
04492 {
04493 if (ret == DRIZZLE_RETURN_ERROR_CODE ||
04494 ret == DRIZZLE_RETURN_HANDSHAKE_FAILED)
04495 {
04496 err= res.error_code();
04497 handle_error(command, err, res.error(), drizzle_result_sqlstate(res), ds);
04498 }
04499 else
04500 {
04501 handle_error(command, ret, drizzle_con_error(con), "", ds);
04502 err= ret;
04503 }
04504 goto end;
04505 }
04506 }
04507 if (!(flags & QUERY_REAP_FLAG))
04508 return;
04509
04510 {
04511
04512
04513
04514 if (drizzle_result_read(con, res, &ret) == NULL ||
04515 ret != DRIZZLE_RETURN_OK)
04516 {
04517 if (ret == DRIZZLE_RETURN_ERROR_CODE)
04518 {
04519 handle_error(command, res.error_code(), res.error(), drizzle_result_sqlstate(res), ds);
04520 }
04521 else
04522 handle_error(command, ret, drizzle_con_error(con), "", ds);
04523 err= ret;
04524 goto end;
04525 }
04526
04527
04528
04529
04530 if (res.column_count() && (ret= drizzle_result_buffer(res)) != DRIZZLE_RETURN_OK)
04531 {
04532 if (ret == DRIZZLE_RETURN_ERROR_CODE)
04533 {
04534 handle_error(command, res.error_code(), res.error(), drizzle_result_sqlstate(res), ds);
04535 }
04536 else
04537 handle_error(command, ret, drizzle_con_error(con), "", ds);
04538 err= ret;
04539 goto end;
04540 }
04541
04542 if (!disable_result_log)
04543 {
04544 uint64_t affected_rows= 0;
04545
04546 if (res.column_count())
04547 {
04548 if (display_metadata)
04549 append_metadata(*ds, res);
04550
04551 if (!display_result_vertically)
04552 append_table_headings(*ds, res);
04553
04554 append_result(ds, res);
04555 }
04556
04557
04558
04559
04560
04561 if (!disable_info)
04562 affected_rows= drizzle_result_affected_rows(res);
04563
04564
04565
04566
04567
04568
04569 if (!disable_warnings)
04570 {
04571 drizzle_con_remove_options(con, DRIZZLE_CON_NO_RESULT_READ);
04572 if (append_warnings(ds_warnings, cn, res) || not ds_warnings.empty())
04573 {
04574 ds->append("Warnings:\n", 10);
04575 *ds += ds_warnings;
04576 }
04577 }
04578
04579 if (!disable_info)
04580 append_info(ds, affected_rows, drizzle_result_info(res));
04581 }
04582
04583 }
04584
04585
04586 handle_no_error(command);
04587
04588 end:
04589
04590
04591
04592
04593
04594
04595 drizzle_con_remove_options(con, DRIZZLE_CON_NO_RESULT_READ);
04596 var_set_errno(err);
04597 }
04598
04599
04600
04601
04602
04603
04604
04605
04606
04607
04608
04609
04610
04611
04612
04613
04614
04615
04616 void handle_error(st_command* command,
04617 unsigned int err_errno, const char *err_error,
04618 const char *err_sqlstate, string *ds)
04619 {
04620 if (! command->require_file.empty())
04621 {
04622
04623
04624
04625
04626
04627 if (err_errno == DRIZZLE_RETURN_LOST_CONNECTION)
04628 die("require query '%s' failed: %d: %s", command->query, err_errno, err_error);
04629
04630
04631 abort_not_supported_test("Query '%s' failed, required functionality not supported", command->query);
04632 }
04633
04634 if (command->abort_on_error)
04635 die("query '%s' failed: %d: %s", command->query, err_errno, err_error);
04636
04637 uint32_t i= 0;
04638 for (; i < command->expected_errors.count; i++)
04639 {
04640 if (((command->expected_errors.err[i].type == ERR_ERRNO) &&
04641 (command->expected_errors.err[i].code.errnum == err_errno)) ||
04642 ((command->expected_errors.err[i].type == ERR_SQLSTATE) &&
04643 (strncmp(command->expected_errors.err[i].code.sqlstate,
04644 err_sqlstate, DRIZZLE_MAX_SQLSTATE_SIZE) == 0)))
04645 {
04646 if (!disable_result_log)
04647 {
04648 if (command->expected_errors.count == 1)
04649 {
04650
04651 ds->append("ERROR ", 6);
04652 replace_append(ds, err_sqlstate);
04653 ds->append(": ", 2);
04654 replace_append(ds, err_error);
04655 ds->append("\n",1);
04656 }
04657
04658 else if (command->expected_errors.err[0].type == ERR_SQLSTATE ||
04659 (command->expected_errors.err[0].type == ERR_ERRNO &&
04660 command->expected_errors.err[0].code.errnum != 0))
04661 ds->append("Got one of the listed errors\n");
04662 }
04663
04664 return;
04665 }
04666 }
04667
04668 if (!disable_result_log)
04669 {
04670 ds->append("ERROR ",6);
04671 replace_append(ds, err_sqlstate);
04672 ds->append(": ", 2);
04673 replace_append(ds, err_error);
04674 ds->append("\n", 1);
04675 }
04676
04677 if (i)
04678 {
04679 if (command->expected_errors.err[0].type == ERR_ERRNO)
04680 die("query '%s' failed with wrong errno %d: '%s', instead of %d...",
04681 command->query, err_errno, err_error,
04682 command->expected_errors.err[0].code.errnum);
04683 else
04684 die("query '%s' failed with wrong sqlstate %s: '%s', instead of %s...",
04685 command->query, err_sqlstate, err_error,
04686 command->expected_errors.err[0].code.sqlstate);
04687 }
04688 }
04689
04690
04691
04692
04693
04694
04695
04696
04697
04698
04699
04700
04701
04702 void handle_no_error(st_command* command)
04703 {
04704 if (command->expected_errors.err[0].type == ERR_ERRNO &&
04705 command->expected_errors.err[0].code.errnum != 0)
04706 {
04707
04708 die("query '%s' succeeded - should have failed with errno %d...", command->query, command->expected_errors.err[0].code.errnum);
04709 }
04710 else if (command->expected_errors.err[0].type == ERR_SQLSTATE &&
04711 strcmp(command->expected_errors.err[0].code.sqlstate,"00000") != 0)
04712 {
04713
04714 die("query '%s' succeeded - should have failed with sqlstate %s...", command->query, command->expected_errors.err[0].code.sqlstate);
04715 }
04716 }
04717
04718
04719
04720
04721
04722
04723
04724
04725
04726
04727
04728
04729
04730
04731
04732 static void run_query(st_connection& cn,
04733 st_command* command,
04734 int flags)
04735 {
04736 string eval_query;
04737 char *query;
04738 int query_len;
04739
04740
04741
04742 scan_command_for_warnings(command);
04743
04744
04745
04746
04747 if (command->type == Q_EVAL)
04748 {
04749 do_eval(&eval_query, command->query, command->end, false);
04750 query = strdup(eval_query.c_str());
04751 query_len = eval_query.length();
04752 }
04753 else
04754 {
04755 query = command->query;
04756 query_len = strlen(query);
04757 }
04758
04759
04760
04761
04762
04763
04764
04765 string ds_result;
04766 string* ds= command->require_file.empty() ? &ds_res : &ds_result;
04767
04768
04769
04770 if (!disable_query_log && (flags & QUERY_SEND_FLAG))
04771 {
04772 replace_append_mem(*ds, query, query_len);
04773 ds->append(delimiter, delimiter_length);
04774 ds->append("\n");
04775 }
04776
04777 string* save_ds= NULL;
04778 string ds_sorted;
04779 if (display_result_sorted)
04780 {
04781
04782
04783
04784
04785
04786 save_ds= ds;
04787 ds= &ds_sorted;
04788 }
04789
04790
04791
04792
04793
04794 string ds_warnings;
04795 run_query_normal(cn, command, flags, query, query_len, ds, ds_warnings);
04796
04797 if (display_result_sorted)
04798 {
04799
04800 append_sorted(*save_ds, ds_sorted);
04801 ds= save_ds;
04802 }
04803
04804 if (! command->require_file.empty())
04805 {
04806
04807
04808
04809
04810 check_require(*ds, command->require_file);
04811 }
04812 }
04813
04814
04815
04816
04817 static void get_command_type(st_command* command)
04818 {
04819 if (*command->query == '}')
04820 {
04821 command->type = Q_END_BLOCK;
04822 return;
04823 }
04824
04825 char save= command->query[command->first_word_len];
04826 command->query[command->first_word_len]= 0;
04827 uint32_t type= command_typelib.find_type(command->query, TYPELIB::e_default);
04828 command->query[command->first_word_len]= save;
04829 if (type > 0)
04830 {
04831 command->type=(enum enum_commands) type;
04832
04833
04834
04835
04836
04837 if (type == Q_QUERY)
04838 {
04839
04840 command->query= command->first_argument;
04841 }
04842 }
04843 else
04844 {
04845
04846
04847 if (command->type != Q_COMMENT_WITH_COMMAND)
04848 {
04849
04850 command->type= Q_QUERY;
04851 }
04852 else
04853 {
04854
04855 command->type= Q_COMMENT;
04856 warning_msg("Suspicious command '--%s' detected, was this intentional? " \
04857 "Use # instead of -- to avoid this warning",
04858 command->query);
04859
04860 if (command->first_word_len &&
04861 strcmp(command->query + command->first_word_len - 1, delimiter) == 0)
04862 {
04863
04864
04865
04866
04867
04868
04869 save= command->query[command->first_word_len-1];
04870 command->query[command->first_word_len-1]= 0;
04871 if (command_typelib.find_type(command->query, TYPELIB::e_default) > 0)
04872 die("Extra delimiter \";\" found");
04873 command->query[command->first_word_len-1]= save;
04874
04875 }
04876 }
04877 }
04878
04879
04880 memcpy(&command->expected_errors, &saved_expected_errors, sizeof(saved_expected_errors));
04881 command->abort_on_error= (command->expected_errors.count == 0 && abort_on_error);
04882 }
04883
04884
04885
04886
04887
04888
04889
04890
04891
04892
04893
04894
04895 static void mark_progress(st_command*, int line)
04896 {
04897 uint64_t timer= timer_now();
04898 if (!progress_start)
04899 progress_start= timer;
04900 timer-= progress_start;
04901
04902 ostringstream buf;
04903
04904 buf << timer << "\t";
04905
04906
04907 buf << line << "\t";
04908
04909
04910 buf << cur_file->file_name << ":";
04911
04912
04913 buf << cur_file->lineno << endl;
04914
04915 ds_progress += buf.str();
04916
04917 }
04918
04919 static void check_retries(uint32_t in_opt_max_connect_retries)
04920 {
04921 if (in_opt_max_connect_retries > 10000 || opt_max_connect_retries<1)
04922 {
04923 cout << N_("Error: Invalid Value for opt_max_connect_retries");
04924 exit(-1);
04925 }
04926 opt_max_connect_retries= in_opt_max_connect_retries;
04927 }
04928
04929 static void check_tail_lines(uint32_t in_opt_tail_lines)
04930 {
04931 if (in_opt_tail_lines > 10000)
04932 {
04933 cout << N_("Error: Invalid Value for opt_tail_lines");
04934 exit(-1);
04935 }
04936 opt_tail_lines= in_opt_tail_lines;
04937 }
04938
04939 static void check_sleep(int32_t in_opt_sleep)
04940 {
04941 if (in_opt_sleep < -1)
04942 {
04943 cout << N_("Error: Invalid Value for opt_sleep");
04944 exit(-1);
04945 }
04946 opt_sleep= in_opt_sleep;
04947 }
04948
04949 int main(int argc, char **argv)
04950 {
04951 try
04952 {
04953 bool q_send_flag= 0, abort_flag= 0;
04954 uint32_t command_executed= 0, last_command_executed= 0;
04955 string save_file;
04956
04957 TMPDIR[0]= 0;
04958
04959 internal::my_init();
04960
04961 po::options_description commandline_options("Options used only in command line");
04962 commandline_options.add_options()
04963 ("help,?", "Display this help and exit.")
04964 ("mark-progress", po::value<bool>(&opt_mark_progress)->default_value(false)->zero_tokens(),
04965 "Write linenumber and elapsed time to <testname>.progress ")
04966 ("sleep,T", po::value<int32_t>(&opt_sleep)->default_value(-1)->notifier(&check_sleep),
04967 "Sleep always this many seconds on sleep commands.")
04968 ("test-file,x", po::value<string>(),
04969 "Read test from/in this file (default stdin).")
04970 ("timer-file,f", po::value<string>(),
04971 "File where the timing in micro seconds is stored.")
04972 ("tmpdir,t", po::value<string>(),
04973 "Temporary directory where sockets are put.")
04974 ("verbose,v", po::value<bool>(&verbose)->default_value(false),
04975 "Write more.")
04976 ("version,V", "Output version information and exit.")
04977 ("no-defaults", po::value<bool>()->default_value(false)->zero_tokens(),
04978 "Configuration file defaults are not used if no-defaults is set")
04979 ;
04980
04981 po::options_description test_options("Options specific to the drizzleimport");
04982 test_options.add_options()
04983 ("basedir,b", po::value<string>(&opt_basedir)->default_value(""),
04984 "Basedir for tests.")
04985 ("character-sets-dir", po::value<string>(&opt_charsets_dir)->default_value(""),
04986 "Directory where character sets are.")
04987 ("database,D", po::value<string>(&opt_db)->default_value(""),
04988 "Database to use.")
04989 ("include,i", po::value<string>(&opt_include)->default_value(""),
04990 "Include SQL before each test case.")
04991 ("testdir", po::value<string>(&opt_testdir)->default_value(""),
04992 "Path to use to search for test files")
04993 ("logdir", po::value<string>(&opt_logdir)->default_value(""),
04994 "Directory for log files")
04995 ("max-connect-retries", po::value<uint32_t>(&opt_max_connect_retries)->default_value(500)->notifier(&check_retries),
04996 "Max number of connection attempts when connecting to server")
04997 ("quiet,s", po::value<bool>(&silent)->default_value(false)->zero_tokens(),
04998 "Suppress all normal output.")
04999 ("record,r", "Record output of test_file into result file.")
05000 ("result-file,R", po::value<string>(&result_file_name)->default_value(""),
05001 "Read/Store result from/in this file.")
05002 ("silent,s", po::value<bool>(&silent)->default_value(false)->zero_tokens(),
05003 "Suppress all normal output. Synonym for --quiet.")
05004 ("tail-lines", po::value<uint32_t>(&opt_tail_lines)->default_value(0)->notifier(&check_tail_lines),
05005 "Number of lines of the resul to include in a failure report")
05006 ;
05007
05008 po::options_description client_options("Options specific to the client");
05009 client_options.add_options()
05010
05011 ("host,h", po::value<string>(&opt_host)->default_value("localhost"),
05012 "Connect to host.")
05013 ("password,P", po::value<string>(&password)->default_value("PASSWORD_SENTINEL"),
05014 "Password to use when connecting to server.")
05015 ("port,p", po::value<uint32_t>(&opt_port)->default_value(0),
05016 "Port number to use for connection or 0 for default")
05017 ("protocol", po::value<string>(&opt_protocol),
05018 "The protocol of connection (mysql or drizzle).")
05019 ("user,u", po::value<string>(&opt_user)->default_value(""),
05020 "User for login.")
05021 ;
05022
05023 po::positional_options_description p;
05024 p.add("database", 1);
05025
05026 po::options_description long_options("Allowed Options");
05027 long_options.add(commandline_options).add(test_options).add(client_options);
05028
05029 std::string system_config_dir_test(SYSCONFDIR);
05030 system_config_dir_test += "/drizzle/drizzletest.cnf";
05031
05032 std::string system_config_dir_client(SYSCONFDIR);
05033 system_config_dir_client += "/drizzle/client.cnf";
05034
05035 std::string user_config_dir((getenv("XDG_CONFIG_HOME")? getenv("XDG_CONFIG_HOME"):"~/.config"));
05036
05037 if (user_config_dir.compare(0, 2, "~/") == 0)
05038 {
05039 if (const char *homedir= getenv("HOME"))
05040 user_config_dir.replace(0, 1, homedir);
05041 }
05042
05043 po::variables_map vm;
05044
05045
05046 int style = po::command_line_style::default_style & ~po::command_line_style::allow_guessing;
05047
05048 po::store(po::command_line_parser(argc, argv).options(long_options).
05049 style(style).positional(p).extra_parser(parse_password_arg).run(),
05050 vm);
05051
05052 if (! vm["no-defaults"].as<bool>())
05053 {
05054 std::string user_config_dir_test(user_config_dir);
05055 user_config_dir_test += "/drizzle/drizzletest.cnf";
05056
05057 std::string user_config_dir_client(user_config_dir);
05058 user_config_dir_client += "/drizzle/client.cnf";
05059
05060 ifstream user_test_ifs(user_config_dir_test.c_str());
05061 po::store(parse_config_file(user_test_ifs, test_options), vm);
05062
05063 ifstream user_client_ifs(user_config_dir_client.c_str());
05064 po::store(parse_config_file(user_client_ifs, client_options), vm);
05065
05066 ifstream system_test_ifs(system_config_dir_test.c_str());
05067 store(parse_config_file(system_test_ifs, test_options), vm);
05068
05069 ifstream system_client_ifs(system_config_dir_client.c_str());
05070 po::store(parse_config_file(system_client_ifs, client_options), vm);
05071 }
05072
05073 po::notify(vm);
05074
05075
05076 memset(&saved_expected_errors, 0, sizeof(saved_expected_errors));
05077
05078
05079 memset(file_stack.data(), 0, sizeof(file_stack));
05080 cur_file= file_stack.data();
05081
05082
05083 memset(block_stack, 0, sizeof(block_stack));
05084 block_stack_end=
05085 block_stack + (sizeof(block_stack)/sizeof(struct st_block)) - 1;
05086 cur_block= block_stack;
05087 cur_block->ok= true;
05088 cur_block->cmd= cmd_none;
05089
05090 var_set_string("$DRIZZLE_SERVER_VERSION", drizzle_version());
05091
05092 memset(&master_pos, 0, sizeof(master_pos));
05093
05094 parser.current_line= parser.read_lines= 0;
05095 memset(&var_reg, 0, sizeof(var_reg));
05096
05097 init_builtin_echo();
05098
05099 ds_res.reserve(65536);
05100 ds_progress.reserve(2048);
05101 ds_warning_messages.reserve(2048);
05102
05103
05104 if (vm.count("record"))
05105 {
05106 record = 1;
05107 }
05108
05109 if (vm.count("test-file"))
05110 {
05111 string tmp= vm["test-file"].as<string>();
05112 char buff[FN_REFLEN];
05113 if (!internal::test_if_hard_path(tmp.c_str()))
05114 {
05115 snprintf(buff, sizeof(buff), "%s%s",opt_basedir.c_str(),tmp.c_str());
05116 tmp= buff;
05117 }
05118 internal::fn_format(buff, tmp.c_str(), "", "", MY_UNPACK_FILENAME);
05119 assert(cur_file == file_stack.data() && cur_file->file == 0);
05120 if (!(cur_file->file= fopen(buff, "r")))
05121 {
05122 fprintf(stderr, _("Could not open '%s' for reading: errno = %d"), buff, errno);
05123 return EXIT_ARGUMENT_INVALID;
05124 }
05125 cur_file->file_name= strdup(buff);
05126 cur_file->lineno= 1;
05127 }
05128
05129 if (vm.count("timer-file"))
05130 {
05131 string tmp= vm["timer-file"].as<string>().c_str();
05132 static char buff[FN_REFLEN];
05133 if (!internal::test_if_hard_path(tmp.c_str()))
05134 {
05135 snprintf(buff, sizeof(buff), "%s%s",opt_basedir.c_str(),tmp.c_str());
05136 tmp= buff;
05137 }
05138 internal::fn_format(buff, tmp.c_str(), "", "", MY_UNPACK_FILENAME);
05139 timer_file= buff;
05140 unlink(timer_file);
05141 }
05142
05143 if (vm.count("protocol"))
05144 {
05145 boost::to_lower(opt_protocol);
05146 if (not opt_protocol.compare("mysql"))
05147 use_drizzle_protocol=false;
05148 else if (not opt_protocol.compare("drizzle"))
05149 use_drizzle_protocol=true;
05150 else
05151 {
05152 cout << _("Error: Unknown protocol") << " '" << opt_protocol << "'" << endl;
05153 exit(-1);
05154 }
05155 }
05156
05157 if (vm.count("port"))
05158 {
05159
05160
05161
05162 if (opt_port > 65535)
05163 {
05164 fprintf(stderr, _("Value supplied for port is not valid.\n"));
05165 exit(EXIT_ARGUMENT_INVALID);
05166 }
05167 }
05168
05169 if( vm.count("password") )
05170 {
05171 if (!opt_password.empty())
05172 opt_password.erase();
05173 if (password == PASSWORD_SENTINEL)
05174 {
05175 opt_password= "";
05176 }
05177 else
05178 {
05179 opt_password= password;
05180 tty_password= false;
05181 }
05182 }
05183 else
05184 {
05185 tty_password= true;
05186 }
05187
05188 if (vm.count("tmpdir"))
05189 {
05190 strncpy(TMPDIR, vm["tmpdir"].as<string>().c_str(), sizeof(TMPDIR));
05191 }
05192
05193 if (vm.count("version"))
05194 {
05195 printf("%s Ver %s Distrib %s, for %s-%s (%s)\n",internal::my_progname,MTEST_VERSION,
05196 drizzle_version(),HOST_VENDOR,HOST_OS,HOST_CPU);
05197 exit(0);
05198 }
05199
05200 if (vm.count("help"))
05201 {
05202 printf("%s Ver %s Distrib %s, for %s-%s (%s)\n",internal::my_progname,MTEST_VERSION,
05203 drizzle_version(),HOST_VENDOR,HOST_OS,HOST_CPU);
05204 printf("MySQL AB, by Sasha, Matt, Monty & Jani\n");
05205 printf("Drizzle version modified by Brian, Jay, Monty Taylor, PatG and Stewart\n");
05206 printf("This software comes with ABSOLUTELY NO WARRANTY\n\n");
05207 printf("Runs a test against the DRIZZLE server and compares output with a results file.\n\n");
05208 printf("Usage: %s [OPTIONS] [database] < test_file\n", internal::my_progname);
05209 exit(0);
05210 }
05211
05212 if (tty_password)
05213 {
05214 opt_pass= client_get_tty_password(NULL);
05215 }
05216
05217 server_initialized= true;
05218 if (cur_file == file_stack.data() && cur_file->file == 0)
05219 {
05220 cur_file->file= stdin;
05221 cur_file->file_name= strdup("<stdin>");
05222 cur_file->lineno= 1;
05223 }
05224 cur_con= safe_connect("default", opt_host, opt_user, opt_pass, opt_db, opt_port);
05225 g_connections["default"] = cur_con;
05226
05227 fill_global_error_names();
05228
05229
05230 timer_start= timer_now();
05231
05232
05233
05234
05235
05236
05237 var_set_errno(-1);
05238
05239
05240 var_set_drizzleclient_get_server_version(*cur_con);
05241
05242 if (! opt_include.empty())
05243 {
05244 open_file(opt_include.c_str());
05245 }
05246
05247 st_command* command;
05248 while (!read_command(&command) && !abort_flag)
05249 {
05250 int current_line_inc = 1, processed = 0;
05251 if (command->type == Q_UNKNOWN || command->type == Q_COMMENT_WITH_COMMAND)
05252 get_command_type(command);
05253
05254 if (parsing_disabled &&
05255 command->type != Q_ENABLE_PARSING &&
05256 command->type != Q_DISABLE_PARSING)
05257 {
05258 command->type= Q_COMMENT;
05259 scan_command_for_warnings(command);
05260 }
05261
05262 if (cur_block->ok)
05263 {
05264 command->last_argument= command->first_argument;
05265 processed = 1;
05266 switch (command->type) {
05267 case Q_CONNECT:
05268 do_connect(command);
05269 break;
05270 case Q_CONNECTION:
05271 select_connection(command);
05272 break;
05273 case Q_DISCONNECT:
05274 case Q_DIRTY_CLOSE:
05275 do_close_connection(command); break;
05276 case Q_ENABLE_QUERY_LOG: disable_query_log=0; break;
05277 case Q_DISABLE_QUERY_LOG: disable_query_log=1; break;
05278 case Q_ENABLE_ABORT_ON_ERROR: abort_on_error=1; break;
05279 case Q_DISABLE_ABORT_ON_ERROR: abort_on_error=0; break;
05280 case Q_ENABLE_RESULT_LOG: disable_result_log=0; break;
05281 case Q_DISABLE_RESULT_LOG: disable_result_log=1; break;
05282 case Q_ENABLE_WARNINGS: disable_warnings=0; break;
05283 case Q_DISABLE_WARNINGS: disable_warnings=1; break;
05284 case Q_ENABLE_INFO: disable_info=0; break;
05285 case Q_DISABLE_INFO: disable_info=1; break;
05286 case Q_ENABLE_METADATA: display_metadata=1; break;
05287 case Q_DISABLE_METADATA: display_metadata=0; break;
05288 case Q_SOURCE: do_source(command); break;
05289 case Q_SLEEP: do_sleep(command, 0); break;
05290 case Q_REAL_SLEEP: do_sleep(command, 1); break;
05291 case Q_WAIT_FOR_SLAVE_TO_STOP: do_wait_for_slave_to_stop(); break;
05292 case Q_INC: do_modify_var(command, DO_INC); break;
05293 case Q_DEC: do_modify_var(command, DO_DEC); break;
05294 case Q_ECHO: do_echo(command); command_executed++; break;
05295 case Q_SYSTEM: do_system(command); break;
05296 case Q_REMOVE_FILE: do_remove_file(command); break;
05297 case Q_MKDIR: do_mkdir(command); break;
05298 case Q_RMDIR: do_rmdir(command); break;
05299 case Q_FILE_EXIST: do_file_exist(command); break;
05300 case Q_WRITE_FILE: do_write_file(command); break;
05301 case Q_APPEND_FILE: do_append_file(command); break;
05302 case Q_DIFF_FILES: do_diff_files(command); break;
05303 case Q_SEND_QUIT: do_send_quit(command); break;
05304 case Q_CHANGE_USER: do_change_user(command); break;
05305 case Q_CAT_FILE: do_cat_file(command); break;
05306 case Q_COPY_FILE: do_copy_file(command); break;
05307 case Q_CHMOD_FILE: do_chmod_file(command); break;
05308 case Q_PERL: do_perl(command); break;
05309 case Q_DELIMITER:
05310 do_delimiter(command);
05311 break;
05312 case Q_DISPLAY_VERTICAL_RESULTS:
05313 display_result_vertically= true;
05314 break;
05315 case Q_DISPLAY_HORIZONTAL_RESULTS:
05316 display_result_vertically= false;
05317 break;
05318 case Q_SORTED_RESULT:
05319
05320
05321
05322
05323 display_result_sorted= true;
05324 break;
05325 case Q_LET: do_let(command); break;
05326 case Q_EVAL_RESULT:
05327 die("'eval_result' command is deprecated");
05328 case Q_EVAL:
05329 case Q_QUERY_VERTICAL:
05330 case Q_QUERY_HORIZONTAL:
05331 if (command->query == command->query_buf)
05332 {
05333
05334 command->query= command->first_argument;
05335 command->first_word_len= 0;
05336 }
05337
05338 case Q_QUERY:
05339 case Q_REAP:
05340 {
05341 bool old_display_result_vertically= display_result_vertically;
05342
05343 int flags= QUERY_REAP_FLAG | QUERY_SEND_FLAG;
05344
05345 if (q_send_flag)
05346 {
05347
05348 flags= QUERY_SEND_FLAG;
05349 q_send_flag= 0;
05350 }
05351 else if (command->type == Q_REAP)
05352 {
05353 flags= QUERY_REAP_FLAG;
05354 }
05355
05356
05357 display_result_vertically|= (command->type == Q_QUERY_VERTICAL);
05358
05359 if (! save_file.empty())
05360 {
05361 command->require_file= save_file;
05362 save_file.clear();
05363 }
05364 run_query(*cur_con, command, flags);
05365 command_executed++;
05366 command->last_argument= command->end;
05367
05368
05369 display_result_vertically= old_display_result_vertically;
05370
05371 break;
05372 }
05373 case Q_SEND:
05374 if (!*command->first_argument)
05375 {
05376
05377
05378
05379
05380 q_send_flag= 1;
05381 break;
05382 }
05383
05384
05385 if (command->query == command->query_buf)
05386 command->query= command->first_argument;
05387
05388
05389
05390
05391
05392
05393
05394 run_query(*cur_con, command, QUERY_SEND_FLAG);
05395 command_executed++;
05396 command->last_argument= command->end;
05397 break;
05398 case Q_REQUIRE:
05399 do_get_file_name(command, save_file);
05400 break;
05401 case Q_ERROR:
05402 do_get_errcodes(command);
05403 break;
05404 case Q_REPLACE:
05405 do_get_replace(command);
05406 break;
05407 case Q_REPLACE_REGEX:
05408 do_get_replace_regex(command);
05409 break;
05410 case Q_REPLACE_COLUMN:
05411 do_get_replace_column(command);
05412 break;
05413 case Q_SAVE_MASTER_POS: do_save_master_pos(); break;
05414 case Q_SYNC_WITH_MASTER: do_sync_with_master(command); break;
05415 case Q_SYNC_SLAVE_WITH_MASTER:
05416 {
05417 do_save_master_pos();
05418 if (*command->first_argument)
05419 select_connection(command);
05420 else
05421 select_connection_name("slave");
05422 do_sync_with_master2(0);
05423 break;
05424 }
05425 case Q_COMMENT:
05426 command->last_argument= command->end;
05427 break;
05428 case Q_PING:
05429 {
05430 drizzle::result_c result;
05431 drizzle_return_t ret;
05432 (void) drizzle_ping(*cur_con, result, &ret);
05433 }
05434 break;
05435 case Q_EXEC:
05436 do_exec(command);
05437 command_executed++;
05438 break;
05439 case Q_START_TIMER:
05440
05441 timer_start= timer_now();
05442 break;
05443 case Q_END_TIMER:
05444
05445 timer_output();
05446 break;
05447 case Q_CHARACTER_SET:
05448 do_set_charset(command);
05449 break;
05450 case Q_DISABLE_RECONNECT:
05451 set_reconnect(*cur_con, 0);
05452 break;
05453 case Q_ENABLE_RECONNECT:
05454 set_reconnect(*cur_con, 1);
05455 break;
05456 case Q_DISABLE_PARSING:
05457 if (parsing_disabled == 0)
05458 parsing_disabled= 1;
05459 else
05460 die("Parsing is already disabled");
05461 break;
05462 case Q_ENABLE_PARSING:
05463
05464
05465
05466
05467 if (parsing_disabled == 1)
05468 parsing_disabled= 0;
05469 else
05470 die("Parsing is already enabled");
05471 break;
05472 case Q_DIE:
05473
05474 die("%s", command->first_argument);
05475 break;
05476 case Q_EXIT:
05477
05478 abort_flag= 1;
05479 break;
05480 case Q_SKIP:
05481 abort_not_supported_test("%s", command->first_argument);
05482 break;
05483
05484 case Q_RESULT:
05485 die("result, deprecated command");
05486 break;
05487
05488 default:
05489 processed= 0;
05490 break;
05491 }
05492 }
05493
05494 if (!processed)
05495 {
05496 current_line_inc= 0;
05497 switch (command->type) {
05498 case Q_WHILE: do_block(cmd_while, command); break;
05499 case Q_IF: do_block(cmd_if, command); break;
05500 case Q_END_BLOCK: do_done(command); break;
05501 default: current_line_inc = 1; break;
05502 }
05503 }
05504 else
05505 check_eol_junk(command->last_argument);
05506
05507 if (command->type != Q_ERROR &&
05508 command->type != Q_COMMENT)
05509 {
05510
05511
05512
05513
05514 memset(&saved_expected_errors, 0, sizeof(saved_expected_errors));
05515 }
05516
05517 if (command_executed != last_command_executed)
05518 {
05519
05520
05521
05522
05523 free_all_replace();
05524
05525
05526 display_result_sorted= false;
05527 }
05528 last_command_executed= command_executed;
05529
05530 parser.current_line += current_line_inc;
05531 if ( opt_mark_progress )
05532 mark_progress(command, parser.current_line);
05533 }
05534
05535 start_lineno= 0;
05536
05537 if (parsing_disabled)
05538 die("Test ended with parsing disabled");
05539
05540
05541
05542
05543
05544
05545 if (ds_res.empty())
05546 die("The test didn't produce any output");
05547 if (result_file_name.empty())
05548 {
05549
05550 printf("%s", ds_res.c_str());
05551 }
05552 else if (record)
05553 {
05554
05555 str_to_file(result_file_name.c_str(), ds_res.c_str(), ds_res.length());
05556 }
05557 else
05558 {
05559
05560
05561
05562
05563 check_result(ds_res);
05564 }
05565
05566 struct stat res_info;
05567 if (not command_executed && not result_file_name.empty() && not stat(result_file_name.c_str(), &res_info))
05568 {
05569
05570
05571
05572
05573
05574
05575
05576 die("No queries executed but result file found!");
05577 }
05578
05579 if ( opt_mark_progress && ! result_file_name.empty() )
05580 dump_progress();
05581
05582
05583 if (not result_file_name.empty() && ds_warning_messages.length())
05584 dump_warning_messages();
05585
05586 timer_output();
05587
05588 cleanup_and_exit(0);
05589 }
05590
05591 catch(exception &err)
05592 {
05593 cerr<<err.what()<<endl;
05594 }
05595
05596 return 0;
05597 }
05598
05599
05600
05601
05602
05603
05604
05605
05606
05607
05608
05609
05610
05611
05612
05613
05614
05615
05616
05617
05618
05619
05620
05621 void timer_output()
05622 {
05623 if (timer_file)
05624 {
05625 ostringstream buf;
05626 uint64_t timer= timer_now() - timer_start;
05627 buf << timer;
05628 str_to_file(timer_file,buf.str().c_str(), buf.str().size() );
05629
05630 timer_file= 0;
05631 }
05632 }
05633
05634
05635 uint64_t timer_now()
05636 {
05637 #if defined(HAVE_GETHRTIME)
05638 return gethrtime()/1000/1000;
05639 #else
05640 uint64_t newtime;
05641 struct timeval t;
05642
05643
05644
05645 while (gettimeofday(&t, NULL) != 0)
05646 {}
05647 newtime= (uint64_t)t.tv_sec * 1000000 + t.tv_usec;
05648 return newtime/1000;
05649 #endif
05650 }
05651
05652
05653
05654
05655
05656
05657
05658
05659
05660
05661 void do_get_replace_column(st_command* command)
05662 {
05663 char *from= command->first_argument;
05664 char *buff, *start;
05665
05666
05667 free_replace_column();
05668 if (!*from)
05669 die("Missing argument in %s", command->query);
05670
05671
05672 start= buff= (char *)malloc(strlen(from)+1);
05673 while (*from)
05674 {
05675 uint32_t column_number;
05676
05677 char *to= get_string(&buff, &from, command);
05678 if (!(column_number= atoi(to)) || column_number > MAX_COLUMNS)
05679 die("Wrong column number to replace_column in '%s'", command->query);
05680 if (!*from)
05681 die("Wrong number of arguments to replace_column in '%s'", command->query);
05682 to= get_string(&buff, &from, command);
05683 free(replace_column[column_number-1]);
05684 replace_column[column_number-1]= strdup(to);
05685 set_if_bigger(max_replace_column, column_number);
05686 }
05687 free(start);
05688 command->last_argument= command->end;
05689 }
05690
05691
05692 void free_replace_column()
05693 {
05694 for (uint32_t i= 0; i < max_replace_column; i++)
05695 {
05696 free(replace_column[i]);
05697 replace_column[i]= 0;
05698 }
05699 max_replace_column= 0;
05700 }
05701
05702
05703
05704
05705
05706
05707
05708
05709
05710 class POINTER_ARRAY
05711 {
05712 public:
05713 ~POINTER_ARRAY();
05714 int insert(char* name);
05715
05716 POINTER_ARRAY()
05717 {
05718 memset(this, 0, sizeof(*this));
05719 }
05720
05721 TYPELIB typelib;
05722 unsigned char *str;
05723 uint8_t* flag;
05724 uint32_t array_allocs;
05725 uint32_t max_count;
05726 uint32_t length;
05727 uint32_t max_length;
05728 };
05729
05730 struct st_replace;
05731 struct st_replace *init_replace(const char **from, const char **to, uint32_t count,
05732 char *word_end_chars);
05733
05734 void replace_strings_append(struct st_replace *rep, string& ds, const char *from, int len);
05735
05736 st_replace *glob_replace= NULL;
05737
05738
05739
05740
05741
05742
05743
05744
05745
05746
05747 POINTER_ARRAY::~POINTER_ARRAY()
05748 {
05749 if (!typelib.count)
05750 return;
05751 typelib.count= 0;
05752 free((char*) typelib.type_names);
05753 typelib.type_names=0;
05754 free(str);
05755 }
05756
05757 void do_get_replace(st_command* command)
05758 {
05759 char *from= command->first_argument;
05760 if (!*from)
05761 die("Missing argument in %s", command->query);
05762 free_replace();
05763 POINTER_ARRAY to_array, from_array;
05764 char* start= (char*)malloc(strlen(from) + 1);
05765 char* buff= start;
05766 while (*from)
05767 {
05768 char *to= get_string(&buff, &from, command);
05769 if (!*from)
05770 die("Wrong number of arguments to replace_result in '%s'", command->query);
05771 from_array.insert(to);
05772 to= get_string(&buff, &from, command);
05773 to_array.insert(to);
05774 }
05775 char word_end_chars[256];
05776 char* pos= word_end_chars;
05777 for (int i= 1; i < 256; i++)
05778 {
05779 if (charset_info->isspace(i))
05780 *pos++= i;
05781 }
05782 *pos=0;
05783 if (!(glob_replace= init_replace(from_array.typelib.type_names,
05784 to_array.typelib.type_names,
05785 from_array.typelib.count,
05786 word_end_chars)))
05787 die("Can't initialize replace from '%s'", command->query);
05788 free(start);
05789 command->last_argument= command->end;
05790 return;
05791 }
05792
05793
05794 void free_replace()
05795 {
05796 free(glob_replace);
05797 glob_replace=0;
05798 }
05799
05800
05801 typedef struct st_replace {
05802 bool found;
05803 struct st_replace *next[256];
05804 } REPLACE;
05805
05806 typedef struct st_replace_found {
05807 bool found;
05808 char *replace_string;
05809 uint32_t to_offset;
05810 int from_offset;
05811 } REPLACE_STRING;
05812
05813
05814 void replace_strings_append(REPLACE *rep, string& ds, const char *str, int len)
05815 {
05816 REPLACE_STRING *rep_str;
05817 const char* start= str;
05818 const char* from= str;
05819
05820 REPLACE* rep_pos=rep+1;
05821 for (;;)
05822 {
05823
05824 while (!rep_pos->found)
05825 rep_pos= rep_pos->next[(unsigned char) *from++];
05826
05827
05828 if (!(rep_str = ((REPLACE_STRING*) rep_pos))->replace_string)
05829 {
05830
05831 ds.append(start, from - start - 1);
05832 return;
05833 }
05834
05835
05836 ds.append(start, (from - rep_str->to_offset) - start);
05837
05838
05839 ds.append(rep_str->replace_string, strlen(rep_str->replace_string));
05840
05841 if (!*(from-=rep_str->from_offset) && rep_pos->found != 2)
05842 return;
05843
05844 assert(from <= str+len);
05845 start= from;
05846 rep_pos=rep;
05847 }
05848 }
05849
05850
05851
05852
05853
05854
05855
05856
05857
05858 struct st_regex
05859 {
05860 char* pattern;
05861 char* replace;
05862 int icase;
05863 int global;
05864
05865 };
05866
05867 class st_replace_regex
05868 {
05869 public:
05870 st_replace_regex(char* expr);
05871 int multi_reg_replace(char* val);
05872
05873
05874
05875
05876
05877
05878
05879
05880 typedef vector<st_regex> regex_arr_t;
05881
05882 char* buf_;
05883 char* even_buf;
05884 char* odd_buf;
05885 int even_buf_len;
05886 int odd_buf_len;
05887 boost::array<char, 8 << 10> buf0_;
05888 boost::array<char, 8 << 10> buf1_;
05889 regex_arr_t regex_arr;
05890 };
05891
05892 boost::scoped_ptr<st_replace_regex> glob_replace_regex;
05893
05894 int reg_replace(char** buf_p, int* buf_len_p, char *pattern, char *replace,
05895 char *string, int icase, int global);
05896
05897
05898
05899
05900
05901
05902
05903
05904 #define PARSE_REGEX_ARG \
05905 while (p < expr_end) \
05906 { \
05907 char c= *p; \
05908 if (c == '/') \
05909 { \
05910 if (last_c == '\\') \
05911 { \
05912 buf_p[-1]= '/'; \
05913 } \
05914 else \
05915 { \
05916 *buf_p++ = 0; \
05917 break; \
05918 } \
05919 } \
05920 else \
05921 *buf_p++ = c; \
05922 \
05923 last_c= c; \
05924 p++; \
05925 } \
05926 \
05927
05928
05929
05930
05931
05932
05933
05934 st_replace_regex::st_replace_regex(char* expr)
05935 {
05936 uint32_t expr_len= strlen(expr);
05937 char last_c = 0;
05938 st_regex reg;
05939
05940 char* buf= new char[expr_len];
05941 char* expr_end= expr + expr_len;
05942 char* p= expr;
05943 char* buf_p= buf;
05944
05945
05946 while (p < expr_end)
05947 {
05948 memset(®, 0, sizeof(reg));
05949
05950 while (p < expr_end)
05951 {
05952 if (*p == '/')
05953 break;
05954 p++;
05955 }
05956
05957 if (p == expr_end || ++p == expr_end)
05958 {
05959 if (!regex_arr.empty())
05960 break;
05961 else
05962 goto err;
05963 }
05964
05965 reg.pattern= buf_p;
05966
05967
05968 PARSE_REGEX_ARG
05969
05970 if (p == expr_end || ++p == expr_end)
05971 goto err;
05972
05973
05974 reg.replace= buf_p;
05975
05976
05977 PARSE_REGEX_ARG
05978
05979 if (p == expr_end)
05980 goto err;
05981
05982
05983 p++;
05984
05985
05986 if (p < expr_end && *p == 'i')
05987 {
05988 p++;
05989 reg.icase= 1;
05990 }
05991
05992
05993 if (p < expr_end && *p == 'g')
05994 {
05995 p++;
05996 reg.global= 1;
05997 }
05998 regex_arr.push_back(reg);
05999 }
06000 odd_buf_len= even_buf_len= buf0_.size();
06001 even_buf= buf0_.data();
06002 odd_buf= buf1_.data();
06003 buf_= even_buf;
06004
06005 return;
06006
06007 err:
06008 die("Error parsing replace_regex \"%s\"", expr);
06009 }
06010
06011
06012
06013
06014
06015
06016
06017
06018
06019
06020
06021
06022
06023
06024
06025
06026
06027
06028
06029
06030 int st_replace_regex::multi_reg_replace(char* val)
06031 {
06032 char* in_buf= val;
06033 char* out_buf= even_buf;
06034 int* buf_len_p= &even_buf_len;
06035 buf_= 0;
06036
06037
06038 BOOST_FOREACH(regex_arr_t::const_reference i, regex_arr)
06039 {
06040 char* save_out_buf= out_buf;
06041 if (!reg_replace(&out_buf, buf_len_p, i.pattern, i.replace,
06042 in_buf, i.icase, i.global))
06043 {
06044
06045 if (save_out_buf != out_buf)
06046 {
06047 if (save_out_buf == even_buf)
06048 even_buf= out_buf;
06049 else
06050 odd_buf= out_buf;
06051 }
06052 buf_= out_buf;
06053 if (in_buf == val)
06054 in_buf= odd_buf;
06055 std::swap(in_buf, out_buf);
06056 buf_len_p= (out_buf == even_buf) ? &even_buf_len : &odd_buf_len;
06057 }
06058 }
06059 return buf_ == 0;
06060 }
06061
06062
06063
06064
06065
06066
06067
06068
06069
06070
06071 void do_get_replace_regex(st_command* command)
06072 {
06073 char *expr= command->first_argument;
06074 glob_replace_regex.reset(new st_replace_regex(expr));
06075 command->last_argument= command->end;
06076 }
06077
06078
06079
06080
06081
06082
06083
06084
06085
06086
06087
06088
06089
06090 int reg_replace(char** buf_p, int* buf_len_p, char *pattern,
06091 char *replace, char *in_string, int icase, int global)
06092 {
06093 const char *error= NULL;
06094 int erroffset;
06095 int ovector[3];
06096 pcre *re= pcre_compile(pattern,
06097 icase ? PCRE_CASELESS | PCRE_MULTILINE : PCRE_MULTILINE,
06098 &error, &erroffset, NULL);
06099 if (re == NULL)
06100 return 1;
06101
06102 if (! global)
06103 {
06104
06105 int rc= pcre_exec(re, NULL, in_string, (int)strlen(in_string),
06106 0, 0, ovector, 3);
06107 if (rc < 0)
06108 {
06109 pcre_free(re);
06110 return 1;
06111 }
06112
06113 char *substring_to_replace= in_string + ovector[0];
06114 int substring_length= ovector[1] - ovector[0];
06115 *buf_len_p= strlen(in_string) - substring_length + strlen(replace);
06116 char* new_buf= (char*)malloc(*buf_len_p+1);
06117
06118 memset(new_buf, 0, *buf_len_p+1);
06119 strncpy(new_buf, in_string, substring_to_replace-in_string);
06120 strncpy(new_buf+(substring_to_replace-in_string), replace, strlen(replace));
06121 strncpy(new_buf+(substring_to_replace-in_string)+strlen(replace),
06122 substring_to_replace + substring_length,
06123 strlen(in_string)
06124 - substring_length
06125 - (substring_to_replace-in_string));
06126 *buf_p= new_buf;
06127
06128 pcre_free(re);
06129 return 0;
06130 }
06131 else
06132 {
06133
06134 string subject(in_string);
06135 size_t replace_length= strlen(replace);
06136 size_t length_of_replacement= strlen(replace);
06137 size_t current_position= 0;
06138 int rc= 0;
06139
06140 while (true)
06141 {
06142 rc= pcre_exec(re, NULL, subject.c_str(), subject.length(),
06143 current_position, 0, ovector, 3);
06144 if (rc < 0)
06145 {
06146 break;
06147 }
06148
06149 current_position= static_cast<size_t>(ovector[0]);
06150 replace_length= static_cast<size_t>(ovector[1] - ovector[0]);
06151 subject.replace(current_position, replace_length, replace, length_of_replacement);
06152 current_position= current_position + length_of_replacement;
06153 }
06154
06155 char* new_buf = (char*) malloc(subject.length() + 1);
06156 memset(new_buf, 0, subject.length() + 1);
06157 strncpy(new_buf, subject.c_str(), subject.length());
06158 *buf_len_p= subject.length() + 1;
06159 *buf_p= new_buf;
06160
06161 pcre_free(re);
06162 return 0;
06163 }
06164 }
06165
06166
06167 #ifndef WORD_BIT
06168 #define WORD_BIT (8*sizeof(uint32_t))
06169 #endif
06170
06171 #define SET_MALLOC_HUNC 64
06172 #define LAST_CHAR_CODE 259
06173
06174 class REP_SET
06175 {
06176 public:
06177 void internal_set_bit(uint32_t bit);
06178 void internal_clear_bit(uint32_t bit);
06179 void or_bits(const REP_SET *from);
06180 void copy_bits(const REP_SET *from);
06181 int cmp_bits(const REP_SET *set2) const;
06182 int get_next_bit(uint32_t lastpos) const;
06183
06184 uint32_t *bits;
06185 short next[LAST_CHAR_CODE];
06186 uint32_t found_len;
06187 int found_offset;
06188 uint32_t table_offset;
06189 uint32_t size_of_bits;
06190 };
06191
06192 class REP_SETS
06193 {
06194 public:
06195 int find_set(const REP_SET *find);
06196 void free_last_set();
06197 void free_sets();
06198 void make_sets_invisible();
06199
06200 uint32_t count;
06201 uint32_t extra;
06202 uint32_t invisible;
06203 uint32_t size_of_bits;
06204 REP_SET *set,*set_buffer;
06205 uint32_t *bit_buffer;
06206 };
06207
06208 struct FOUND_SET
06209 {
06210 uint32_t table_offset;
06211 int found_offset;
06212 };
06213
06214 struct FOLLOWS
06215 {
06216 int chr;
06217 uint32_t table_offset;
06218 uint32_t len;
06219 };
06220
06221 void init_sets(REP_SETS *sets, uint32_t states);
06222 REP_SET *make_new_set(REP_SETS *sets);
06223 int find_found(FOUND_SET *found_set, uint32_t table_offset, int found_offset);
06224
06225 static uint32_t found_sets= 0;
06226
06227 static uint32_t replace_len(const char *str)
06228 {
06229 uint32_t len=0;
06230 while (*str)
06231 {
06232 if (str[0] == '\\' && str[1])
06233 str++;
06234 str++;
06235 len++;
06236 }
06237 return len;
06238 }
06239
06240
06241
06242 static bool start_at_word(const char *pos)
06243 {
06244 return (!memcmp(pos, "\\b",2) && pos[2]) || !memcmp(pos, "\\^", 2);
06245 }
06246
06247 static bool end_of_word(const char *pos)
06248 {
06249 const char *end= strchr(pos, '\0');
06250 return (end > pos+2 && !memcmp(end-2, "\\b", 2)) || (end >= pos+2 && !memcmp(end-2, "\\$",2));
06251 }
06252
06253
06254
06255 REPLACE *init_replace(const char **from, const char **to, uint32_t count, char *word_end_chars)
06256 {
06257 const int SPACE_CHAR= 256;
06258 const int START_OF_LINE= 257;
06259 const int END_OF_LINE= 258;
06260
06261 uint32_t i,j,states,set_nr,len,result_len,max_length,found_end,bits_set,bit_nr;
06262 int used_sets,chr,default_state;
06263 char used_chars[LAST_CHAR_CODE],is_word_end[256];
06264 char *to_pos, **to_array;
06265
06266
06267 for (i=result_len=max_length=0 , states=2; i < count; i++)
06268 {
06269 len=replace_len(from[i]);
06270 if (!len)
06271 {
06272 errno=EINVAL;
06273 return(0);
06274 }
06275 states+=len+1;
06276 result_len+=(uint32_t) strlen(to[i])+1;
06277 if (len > max_length)
06278 max_length=len;
06279 }
06280 memset(is_word_end, 0, sizeof(is_word_end));
06281 for (i=0; word_end_chars[i]; i++)
06282 is_word_end[(unsigned char) word_end_chars[i]]=1;
06283
06284 REP_SETS sets;
06285 REP_SET *set,*start_states,*word_states,*new_set;
06286 REPLACE_STRING *rep_str;
06287 init_sets(&sets, states);
06288 found_sets=0;
06289 vector<FOUND_SET> found_set(max_length * count);
06290 make_new_set(&sets);
06291 sets.make_sets_invisible();
06292 used_sets=-1;
06293 word_states=make_new_set(&sets);
06294 start_states=make_new_set(&sets);
06295 vector<FOLLOWS> follow(states + 2);
06296 FOLLOWS *follow_ptr= &follow[1];
06297
06298 for (i=0, states=1; i < count; i++)
06299 {
06300 if (from[i][0] == '\\' && from[i][1] == '^')
06301 {
06302 start_states->internal_set_bit(states + 1);
06303 if (!from[i][2])
06304 {
06305 start_states->table_offset=i;
06306 start_states->found_offset=1;
06307 }
06308 }
06309 else if (from[i][0] == '\\' && from[i][1] == '$')
06310 {
06311 start_states->internal_set_bit(states);
06312 word_states->internal_set_bit(states);
06313 if (!from[i][2] && start_states->table_offset == UINT32_MAX)
06314 {
06315 start_states->table_offset=i;
06316 start_states->found_offset=0;
06317 }
06318 }
06319 else
06320 {
06321 word_states->internal_set_bit(states);
06322 if (from[i][0] == '\\' && (from[i][1] == 'b' && from[i][2]))
06323 start_states->internal_set_bit(states + 1);
06324 else
06325 start_states->internal_set_bit(states);
06326 }
06327 const char *pos;
06328 for (pos= from[i], len=0; *pos; pos++)
06329 {
06330 if (*pos == '\\' && *(pos+1))
06331 {
06332 pos++;
06333 switch (*pos) {
06334 case 'b':
06335 follow_ptr->chr = SPACE_CHAR;
06336 break;
06337 case '^':
06338 follow_ptr->chr = START_OF_LINE;
06339 break;
06340 case '$':
06341 follow_ptr->chr = END_OF_LINE;
06342 break;
06343 case 'r':
06344 follow_ptr->chr = '\r';
06345 break;
06346 case 't':
06347 follow_ptr->chr = '\t';
06348 break;
06349 case 'v':
06350 follow_ptr->chr = '\v';
06351 break;
06352 default:
06353 follow_ptr->chr = (unsigned char) *pos;
06354 break;
06355 }
06356 }
06357 else
06358 follow_ptr->chr= (unsigned char) *pos;
06359 follow_ptr->table_offset=i;
06360 follow_ptr->len= ++len;
06361 follow_ptr++;
06362 }
06363 follow_ptr->chr=0;
06364 follow_ptr->table_offset=i;
06365 follow_ptr->len=len;
06366 follow_ptr++;
06367 states+=(uint32_t) len+1;
06368 }
06369
06370
06371 for (set_nr=0; set_nr < sets.count; set_nr++)
06372 {
06373 set=sets.set+set_nr;
06374 default_state= 0;
06375
06376
06377
06378 for (i= UINT32_MAX; (i= set->get_next_bit(i));)
06379 {
06380 if (!follow[i].chr && !default_state)
06381 default_state= find_found(&found_set.front(), set->table_offset, set->found_offset+1);
06382 }
06383 sets.set[used_sets].copy_bits(set);
06384 if (!default_state)
06385 sets.set[used_sets].or_bits(sets.set);
06386
06387
06388 memset(used_chars, 0, sizeof(used_chars));
06389 for (i= UINT32_MAX; (i= sets.set[used_sets].get_next_bit(i));)
06390 {
06391 used_chars[follow[i].chr]=1;
06392 if ((follow[i].chr == SPACE_CHAR && !follow[i+1].chr &&
06393 follow[i].len > 1) || follow[i].chr == END_OF_LINE)
06394 used_chars[0]=1;
06395 }
06396
06397
06398 if (used_chars[SPACE_CHAR])
06399 for (const char *pos= word_end_chars; *pos; pos++)
06400 used_chars[(int) (unsigned char) *pos] = 1;
06401
06402
06403 for (chr= 0; chr < 256; chr++)
06404 {
06405 if (! used_chars[chr])
06406 set->next[chr]= chr ? default_state : -1;
06407 else
06408 {
06409 new_set=make_new_set(&sets);
06410 set=sets.set+set_nr;
06411 new_set->table_offset=set->table_offset;
06412 new_set->found_len=set->found_len;
06413 new_set->found_offset=set->found_offset+1;
06414 found_end=0;
06415
06416 for (i= UINT32_MAX; (i= sets.set[used_sets].get_next_bit(i));)
06417 {
06418 if (!follow[i].chr || follow[i].chr == chr ||
06419 (follow[i].chr == SPACE_CHAR &&
06420 (is_word_end[chr] ||
06421 (!chr && follow[i].len > 1 && ! follow[i+1].chr))) ||
06422 (follow[i].chr == END_OF_LINE && ! chr))
06423 {
06424 if ((! chr || (follow[i].chr && !follow[i+1].chr)) &&
06425 follow[i].len > found_end)
06426 found_end=follow[i].len;
06427 if (chr && follow[i].chr)
06428 new_set->internal_set_bit(i + 1);
06429 else
06430 new_set->internal_set_bit(i);
06431 }
06432 }
06433 if (found_end)
06434 {
06435 new_set->found_len=0;
06436 bits_set=0;
06437 for (i= UINT32_MAX; (i= new_set->get_next_bit(i));)
06438 {
06439 if ((follow[i].chr == SPACE_CHAR ||
06440 follow[i].chr == END_OF_LINE) && ! chr)
06441 bit_nr=i+1;
06442 else
06443 bit_nr=i;
06444 if (follow[bit_nr-1].len < found_end ||
06445 (new_set->found_len &&
06446 (chr == 0 || !follow[bit_nr].chr)))
06447 new_set->internal_clear_bit(i);
06448 else
06449 {
06450 if (chr == 0 || !follow[bit_nr].chr)
06451 {
06452 new_set->table_offset=follow[bit_nr].table_offset;
06453 if (chr || (follow[i].chr == SPACE_CHAR ||
06454 follow[i].chr == END_OF_LINE))
06455 new_set->found_offset=found_end;
06456 new_set->found_len=found_end;
06457 }
06458 bits_set++;
06459 }
06460 }
06461 if (bits_set == 1)
06462 {
06463 set->next[chr] = find_found(&found_set.front(), new_set->table_offset, new_set->found_offset);
06464 sets.free_last_set();
06465 }
06466 else
06467 set->next[chr] = sets.find_set(new_set);
06468 }
06469 else
06470 set->next[chr] = sets.find_set(new_set);
06471 }
06472 }
06473 }
06474
06475
06476
06477 REPLACE *replace= (REPLACE*)malloc(sizeof(REPLACE) * (sets.count)
06478 + sizeof(REPLACE_STRING) * (found_sets + 1) + sizeof(char*) * count + result_len);
06479 {
06480 memset(replace, 0, sizeof(REPLACE)*(sets.count)+
06481 sizeof(REPLACE_STRING)*(found_sets+1)+
06482 sizeof(char *)*count+result_len);
06483 rep_str=(REPLACE_STRING*) (replace+sets.count);
06484 to_array= (char **) (rep_str+found_sets+1);
06485 to_pos=(char *) (to_array+count);
06486 for (i=0; i < count; i++)
06487 {
06488 to_array[i]=to_pos;
06489 to_pos=strcpy(to_pos,to[i])+strlen(to[i])+1;
06490 }
06491 rep_str[0].found=1;
06492 rep_str[0].replace_string=0;
06493 for (i=1; i <= found_sets; i++)
06494 {
06495 const char *pos= from[found_set[i-1].table_offset];
06496 rep_str[i].found= !memcmp(pos, "\\^", 3) ? 2 : 1;
06497 rep_str[i].replace_string= to_array[found_set[i-1].table_offset];
06498 rep_str[i].to_offset= found_set[i-1].found_offset-start_at_word(pos);
06499 rep_str[i].from_offset= found_set[i-1].found_offset-replace_len(pos) + end_of_word(pos);
06500 }
06501 for (i=0; i < sets.count; i++)
06502 {
06503 for (j=0; j < 256; j++)
06504 if (sets.set[i].next[j] >= 0)
06505 replace[i].next[j]=replace+sets.set[i].next[j];
06506 else
06507 replace[i].next[j]=(REPLACE*) (rep_str+(-sets.set[i].next[j]-1));
06508 }
06509 }
06510 sets.free_sets();
06511 return replace;
06512 }
06513
06514
06515 void init_sets(REP_SETS *sets,uint32_t states)
06516 {
06517 memset(sets, 0, sizeof(*sets));
06518 sets->size_of_bits=((states+7)/8);
06519 sets->set_buffer=(REP_SET*) malloc(sizeof(REP_SET) * SET_MALLOC_HUNC);
06520 sets->bit_buffer=(uint*) malloc(sizeof(uint32_t) * sets->size_of_bits * SET_MALLOC_HUNC);
06521 }
06522
06523
06524
06525 void REP_SETS::make_sets_invisible()
06526 {
06527 invisible= count;
06528 set += count;
06529 count= 0;
06530 }
06531
06532 REP_SET *make_new_set(REP_SETS *sets)
06533 {
06534 REP_SET *set;
06535 if (sets->extra)
06536 {
06537 sets->extra--;
06538 set=sets->set+ sets->count++;
06539 memset(set->bits, 0, sizeof(uint32_t)*sets->size_of_bits);
06540 memset(&set->next[0], 0, sizeof(set->next[0])*LAST_CHAR_CODE);
06541 set->found_offset=0;
06542 set->found_len=0;
06543 set->table_offset= UINT32_MAX;
06544 set->size_of_bits=sets->size_of_bits;
06545 return set;
06546 }
06547 uint32_t count= sets->count + sets->invisible + SET_MALLOC_HUNC;
06548 set= (REP_SET*) realloc((unsigned char*) sets->set_buffer, sizeof(REP_SET)*count);
06549 sets->set_buffer=set;
06550 sets->set=set+sets->invisible;
06551 uint32_t* bit_buffer= (uint*) realloc((unsigned char*) sets->bit_buffer, (sizeof(uint32_t)*sets->size_of_bits)*count);
06552 sets->bit_buffer=bit_buffer;
06553 for (uint32_t i= 0; i < count; i++)
06554 {
06555 sets->set_buffer[i].bits=bit_buffer;
06556 bit_buffer+=sets->size_of_bits;
06557 }
06558 sets->extra=SET_MALLOC_HUNC;
06559 return make_new_set(sets);
06560 }
06561
06562 void REP_SETS::free_last_set()
06563 {
06564 count--;
06565 extra++;
06566 }
06567
06568 void REP_SETS::free_sets()
06569 {
06570 free(set_buffer);
06571 free(bit_buffer);
06572 }
06573
06574 void REP_SET::internal_set_bit(uint32_t bit)
06575 {
06576 bits[bit / WORD_BIT] |= 1 << (bit % WORD_BIT);
06577 }
06578
06579 void REP_SET::internal_clear_bit(uint32_t bit)
06580 {
06581 bits[bit / WORD_BIT] &= ~ (1 << (bit % WORD_BIT));
06582 }
06583
06584
06585 void REP_SET::or_bits(const REP_SET *from)
06586 {
06587 for (uint32_t i= 0; i < size_of_bits; i++)
06588 bits[i]|=from->bits[i];
06589 }
06590
06591 void REP_SET::copy_bits(const REP_SET *from)
06592 {
06593 memcpy(bits, from->bits, sizeof(uint32_t) * size_of_bits);
06594 }
06595
06596 int REP_SET::cmp_bits(const REP_SET *set2) const
06597 {
06598 return memcmp(bits, set2->bits, sizeof(uint32_t) * size_of_bits);
06599 }
06600
06601
06602
06603 int REP_SET::get_next_bit(uint32_t lastpos) const
06604 {
06605 uint32_t *start= bits + ((lastpos+1) / WORD_BIT);
06606 uint32_t *end= bits + size_of_bits;
06607 uint32_t bits0= start[0] & ~((1 << ((lastpos+1) % WORD_BIT)) -1);
06608
06609 while (!bits0 && ++start < end)
06610 bits0= start[0];
06611 if (!bits0)
06612 return 0;
06613 uint32_t pos= (start - bits) * WORD_BIT;
06614 while (!(bits0 & 1))
06615 {
06616 bits0 >>=1;
06617 pos++;
06618 }
06619 return pos;
06620 }
06621
06622
06623
06624
06625
06626 int REP_SETS::find_set(const REP_SET *find)
06627 {
06628 uint32_t i= 0;
06629 for (; i < count - 1; i++)
06630 {
06631 if (!set[i].cmp_bits(find))
06632 {
06633 free_last_set();
06634 return i;
06635 }
06636 }
06637 return i;
06638 }
06639
06640
06641
06642
06643
06644
06645
06646
06647 int find_found(FOUND_SET *found_set, uint32_t table_offset, int found_offset)
06648 {
06649 uint32_t i= 0;
06650 for (; i < found_sets; i++)
06651 {
06652 if (found_set[i].table_offset == table_offset &&
06653 found_set[i].found_offset == found_offset)
06654 return - i - 2;
06655 }
06656 found_set[i].table_offset= table_offset;
06657 found_set[i].found_offset= found_offset;
06658 found_sets++;
06659 return - i - 2;
06660 }
06661
06662
06663
06664
06665
06666 #define PC_MALLOC 256
06667 #define PS_MALLOC 512
06668
06669 static int insert_pointer_name(POINTER_ARRAY* pa, char* name)
06670 {
06671 uint32_t i,length,old_count;
06672 unsigned char *new_pos;
06673 const char **new_array;
06674
06675
06676 if (! pa->typelib.count)
06677 {
06678 pa->typelib.type_names=(const char **)
06679 malloc(((PC_MALLOC-MALLOC_OVERHEAD)/
06680 (sizeof(char *)+sizeof(*pa->flag))*
06681 (sizeof(char *)+sizeof(*pa->flag))));
06682 pa->str= (unsigned char*) malloc(PS_MALLOC-MALLOC_OVERHEAD);
06683 pa->max_count=(PC_MALLOC-MALLOC_OVERHEAD)/(sizeof(unsigned char*)+
06684 sizeof(*pa->flag));
06685 pa->flag= (uint8_t*) (pa->typelib.type_names+pa->max_count);
06686 pa->length=0;
06687 pa->max_length=PS_MALLOC-MALLOC_OVERHEAD;
06688 pa->array_allocs=1;
06689 }
06690 length=(uint32_t) strlen(name)+1;
06691 if (pa->length+length >= pa->max_length)
06692 {
06693 new_pos= (unsigned char*)realloc((unsigned char*)pa->str, (size_t)(pa->max_length+PS_MALLOC));
06694 if (new_pos != pa->str)
06695 {
06696 ptrdiff_t diff= PTR_BYTE_DIFF(new_pos,pa->str);
06697 for (i=0; i < pa->typelib.count; i++)
06698 pa->typelib.type_names[i]= ADD_TO_PTR(pa->typelib.type_names[i],diff,
06699 char*);
06700 pa->str=new_pos;
06701 }
06702 pa->max_length+=PS_MALLOC;
06703 }
06704 if (pa->typelib.count >= pa->max_count-1)
06705 {
06706 size_t len;
06707 pa->array_allocs++;
06708 len=(PC_MALLOC*pa->array_allocs - MALLOC_OVERHEAD);
06709 new_array= (const char **)realloc((unsigned char*) pa->typelib.type_names,
06710 len/
06711 (sizeof(unsigned char*)+sizeof(*pa->flag))*
06712 (sizeof(unsigned char*)+sizeof(*pa->flag)));
06713 pa->typelib.type_names=new_array;
06714 old_count=pa->max_count;
06715 pa->max_count=len/(sizeof(unsigned char*) + sizeof(*pa->flag));
06716 pa->flag= (uint8_t*) (pa->typelib.type_names+pa->max_count);
06717 memcpy(pa->flag, pa->typelib.type_names+old_count,
06718 old_count*sizeof(*pa->flag));
06719 }
06720 pa->flag[pa->typelib.count]=0;
06721 pa->typelib.type_names[pa->typelib.count++]= (char*) pa->str+pa->length;
06722 pa->typelib.type_names[pa->typelib.count]= NULL;
06723 strcpy((char*) pa->str+pa->length,name);
06724 pa->length+=length;
06725 return(0);
06726 }
06727
06728 int POINTER_ARRAY::insert(char* name)
06729 {
06730 return insert_pointer_name(this, name);
06731 }
06732
06733
06734
06735
06736
06737 void replace_append_mem(string& ds, const char *val, int len)
06738 {
06739 char *v= strdup(val);
06740
06741 if (glob_replace_regex && !glob_replace_regex->multi_reg_replace(v))
06742 {
06743 v= glob_replace_regex->buf_;
06744 len= strlen(v);
06745 }
06746 if (glob_replace)
06747 {
06748
06749 replace_strings_append(glob_replace, ds, v, len);
06750 }
06751 else
06752 ds.append(v, len);
06753 }
06754
06755
06756
06757 void replace_append(string *ds, const char *val)
06758 {
06759 replace_append_mem(*ds, val, strlen(val));
06760 }
06761
06762
06763 void replace_append_uint(string& ds, uint32_t val)
06764 {
06765 ostringstream buff;
06766 buff << val;
06767 replace_append_mem(ds, buff.str().c_str(), buff.str().size());
06768
06769 }
06770
06771
06772
06773
06774
06775
06776
06777
06778
06779
06780
06781
06782
06783
06784
06785
06786 void append_sorted(string& ds, const string& ds_input)
06787 {
06788 priority_queue<string, vector<string>, greater<string> > lines;
06789
06790 if (ds_input.empty())
06791 return;
06792
06793 unsigned long eol_pos= ds_input.find_first_of('\n', 0);
06794 if (eol_pos == string::npos)
06795 return;
06796
06797 ds.append(ds_input.substr(0, eol_pos+1));
06798
06799 unsigned long start_pos= eol_pos+1;
06800
06801
06802 do {
06803
06804 eol_pos= ds_input.find_first_of('\n', start_pos);
06805
06806 lines.push(ds_input.substr(start_pos, eol_pos-start_pos+1));
06807 start_pos= eol_pos+1;
06808
06809 } while ( eol_pos != string::npos);
06810
06811
06812 while (!lines.empty())
06813 {
06814 ds.append(lines.top());
06815 lines.pop();
06816 }
06817 }
06818
06819 static void free_all_replace()
06820 {
06821 free_replace();
06822 glob_replace_regex.reset();
06823 free_replace_column();
06824 }