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