40 #define MTEST_VERSION "3.3"
43 #include <client/get_password.h>
44 #include <libdrizzle-2.0/libdrizzle.hpp>
54 #ifdef HAVE_SYS_WAIT_H
59 #include <sys/types.h>
61 #include <boost/array.hpp>
62 #include <boost/foreach.hpp>
63 #include <boost/program_options.hpp>
64 #include <boost/smart_ptr.hpp>
69 #include <boost/unordered_map.hpp>
72 #include <drizzled/gettext.h>
75 #include <drizzled/internal/my_sys.h>
76 #include <drizzled/type/time.h>
77 #include <drizzled/charset.h>
78 #include <drizzled/typelib.h>
79 #include <drizzled/configmake.h>
80 #include <drizzled/util/find_ptr.h>
82 #define PTR_BYTE_DIFF(A,B) (ptrdiff_t) (reinterpret_cast<const unsigned char*>(A) - reinterpret_cast<const unsigned char*>(B))
84 namespace po= boost::program_options;
86 using namespace drizzled;
88 unsigned char *get_var_key(
const unsigned char*
var,
size_t *len,
bool);
90 int get_one_option(
int optid,
const struct option *,
char *argument);
92 #define MAX_VAR_NAME_LENGTH 256
93 #define MAX_COLUMNS 256
94 #define MAX_DELIMITER_LENGTH 16
96 #define QUERY_SEND_FLAG 1
97 #define QUERY_REAP_FLAG 2
99 typedef boost::unordered_map<std::string, uint32_t> ErrorCodes;
100 ErrorCodes global_error_names;
103 OPT_PS_PROTOCOL, OPT_SP_PROTOCOL, OPT_CURSOR_PROTOCOL, OPT_VIEW_PROTOCOL,
104 OPT_MAX_CONNECT_RETRIES, OPT_MARK_PROGRESS, OPT_LOG_DIR, OPT_TAIL_LINES,
108 static int record= 0, opt_sleep= -1;
109 static char *opt_pass= NULL;
110 const char *unix_sock= NULL;
111 static uint32_t opt_port= 0;
112 static uint32_t opt_max_connect_retries;
113 static bool silent=
false, verbose=
false;
114 static bool opt_mark_progress=
false;
115 static bool parsing_disabled=
false;
116 static bool display_result_vertically=
false,
117 display_metadata=
false, display_result_sorted=
false;
118 static bool disable_query_log=
false, disable_result_log=
false;
119 static bool disable_warnings=
false;
120 static bool disable_info=
true;
121 static bool abort_on_error=
true;
122 static bool server_initialized=
false;
123 static bool is_windows=
false;
124 static bool use_drizzle_protocol=
false;
125 static char line_buffer[MAX_DELIMITER_LENGTH], *line_buffer_pos= line_buffer;
126 static void free_all_replace();
128 std::string opt_basedir,
141 static uint32_t start_lineno= 0;
144 static uint32_t opt_tail_lines= 0;
146 static char delimiter[MAX_DELIMITER_LENGTH]=
";";
147 static uint32_t delimiter_length= 1;
149 static char TMPDIR[FN_REFLEN];
165 static struct st_block block_stack[32];
166 static struct st_block *cur_block, *block_stack_end;
172 const char *file_name;
176 static boost::array<st_test_file, 16> file_stack;
179 static const charset_info_st *charset_info= &my_charset_utf8_general_ci;
185 static char *timer_file = NULL;
186 static uint64_t timer_start;
187 static void timer_output();
188 static uint64_t timer_now();
190 static uint64_t progress_start= 0;
192 vector<struct st_command*> q_lines;
202 char file[FN_REFLEN];
225 boost::array<VAR, 10> var_reg;
227 typedef boost::unordered_map<string, VAR *> var_hash_t;
235 drizzle_con_add_options(*
this, use_drizzle_protocol ? DRIZZLE_CON_EXPERIMENTAL : DRIZZLE_CON_MYSQL);
238 operator drizzle::connection_c&()
243 operator drizzle_con_st*()
248 drizzle::drizzle_c drizzle;
249 drizzle::connection_c con;
252 typedef map<string, st_connection*> connections_t;
253 connections_t g_connections;
263 Q_CONNECTION=1, Q_QUERY,
264 Q_CONNECT, Q_SLEEP, Q_REAL_SLEEP,
266 Q_SOURCE, Q_DISCONNECT,
268 Q_WHILE, Q_END_BLOCK,
273 Q_DIRTY_CLOSE, Q_REPLACE, Q_REPLACE_COLUMN,
276 Q_ENABLE_QUERY_LOG, Q_DISABLE_QUERY_LOG,
277 Q_ENABLE_RESULT_LOG, Q_DISABLE_RESULT_LOG,
278 Q_WAIT_FOR_SLAVE_TO_STOP,
279 Q_ENABLE_WARNINGS, Q_DISABLE_WARNINGS,
280 Q_ENABLE_INFO, Q_DISABLE_INFO,
281 Q_ENABLE_METADATA, Q_DISABLE_METADATA,
283 Q_DISABLE_ABORT_ON_ERROR, Q_ENABLE_ABORT_ON_ERROR,
284 Q_DISPLAY_VERTICAL_RESULTS, Q_DISPLAY_HORIZONTAL_RESULTS,
285 Q_QUERY_VERTICAL, Q_QUERY_HORIZONTAL, Q_SORTED_RESULT,
286 Q_START_TIMER, Q_END_TIMER,
288 Q_DISABLE_RECONNECT, Q_ENABLE_RECONNECT,
290 Q_DISABLE_PARSING, Q_ENABLE_PARSING,
291 Q_REPLACE_REGEX, Q_REMOVE_FILE, Q_FILE_EXIST,
292 Q_WRITE_FILE, Q_COPY_FILE, Q_PERL, Q_DIE, Q_EXIT, Q_SKIP,
293 Q_CHMOD_FILE, Q_APPEND_FILE, Q_CAT_FILE, Q_DIFF_FILES,
294 Q_SEND_QUIT, Q_CHANGE_USER, Q_MKDIR, Q_RMDIR,
298 Q_COMMENT_WITH_COMMAND
302 const char *command_names[]=
334 "disable_result_log",
335 "wait_for_slave_to_stop",
344 "disable_abort_on_error",
345 "enable_abort_on_error",
347 "horizontal_results",
399 enum match_err_type type;
403 char sqlstate[DRIZZLE_MAX_SQLSTATE_SIZE+1];
418 char *query, *query_buf,*first_argument,*last_argument,*end;
419 int first_word_len, query_len;
426 : query(NULL), query_buf(NULL), first_argument(NULL), last_argument(NULL),
427 end(NULL), first_word_len(0), query_len(0), abort_on_error(
false),
428 require_file(
""), type(Q_CONNECTION)
439 TYPELIB command_typelib= {array_elements(command_names),
"",
442 string ds_res, ds_progress, ds_warning_messages;
444 char builtin_echo[FN_REFLEN];
446 void die(
const char *fmt, ...)
447 __attribute__((format(printf, 1, 2)));
448 void abort_not_supported_test(const
char *fmt, ...)
449 __attribute__((format(printf, 1, 2)));
450 void verbose_msg(const
char *fmt, ...)
451 __attribute__((format(printf, 1, 2)));
452 void warning_msg(const
char *fmt, ...)
453 __attribute__((format(printf, 1, 2)));
454 void log_msg(const
char *fmt, ...)
455 __attribute__((format(printf, 1, 2)));
457 VAR* var_from_env(const
char *, const
char *);
458 VAR* var_init(
VAR* v, const
char *name,
int name_len, const
char *val,
460 VAR* var_get(const
char *var_name, const
char** var_name_end,
461 bool raw,
bool ignore_not_existing);
462 void eval_expr(
VAR* v, const
char *p, const
char** p_end);
463 bool match_delimiter(
int c, const
char *delim, uint32_t length);
464 void dump_result_to_reject_file(
char *buf,
int size);
465 void dump_result_to_log_file(const
char *buf,
int size);
466 void dump_warning_messages();
467 void dump_progress();
469 void do_eval(
string *query_eval, const
char *query,
470 const
char *query_end,
bool pass_through_escape_chars);
471 void str_to_file(const
char *fname, const
char *str,
int size);
472 void str_to_file2(const
char *fname, const
char *str,
int size,
bool append);
475 static
char *replace_column[MAX_COLUMNS];
476 static uint32_t max_replace_column= 0;
478 void free_replace_column();
481 void do_get_replace(st_command* command);
485 void do_get_replace_regex(st_command* command);
487 void replace_append_mem(
string& ds, const
char *val,
int len);
488 void replace_append(
string *ds, const
char *val);
489 void replace_append_uint(
string& ds, uint32_t val);
490 void append_sorted(
string& ds, const
string& ds_input);
492 void handle_error(st_command*,
493 unsigned int err_errno, const
char *err_error,
494 const
char *err_sqlstate,
string *ds);
495 void handle_no_error(st_command*);
498 void do_eval(
string *query_eval, const
char *query,
499 const
char *query_end,
bool pass_through_escape_chars)
504 for (
const char *p= query; (c= *p) && p < query_end; ++p)
512 query_eval->append(p, 1);
516 VAR* v= var_get(p, &p, 0, 0);
518 die(
"Bad variable in eval");
519 query_eval->append(v->str_val, v->str_val_len);
527 query_eval->append(p, 1);
529 else if (next_c ==
'\\' || next_c ==
'$' || next_c ==
'"')
534 if (pass_through_escape_chars)
537 query_eval->append(p, 1);
541 query_eval->append(p, 1);
545 query_eval->append(p, 1);
565 static void append_os_quoted(
string *str,
const char *append, ...)
567 const char *quote_str=
"\'";
568 const uint32_t quote_len= 1;
572 str->append(quote_str, quote_len);
573 va_start(dirty_text, append);
574 while (append != NULL)
576 const char *cur_pos= append;
577 const char *next_pos= cur_pos;
580 while ((next_pos= strrchr(cur_pos, quote_str[0])) != NULL)
582 str->append(cur_pos, next_pos - cur_pos);
583 str->append(
"\\", 1);
584 str->append(quote_str, quote_len);
585 cur_pos= next_pos + 1;
587 str->append(cur_pos);
588 append= va_arg(dirty_text,
char *);
591 str->append(quote_str, quote_len);
608 static int dt_query_log(drizzle::connection_c& con, drizzle::result_c& res,
const std::string& query)
610 if (drizzle_return_t ret= con.query(res, query))
612 if (ret == DRIZZLE_RETURN_ERROR_CODE)
614 log_msg(
"Error running query '%s': %d %s", query.c_str(), res.error_code(), res.error());
618 log_msg(
"Error running query '%s': %d %s", query.c_str(), ret, con.error());
622 return res.column_count() == 0;
638 static void show_warnings_before_error(drizzle::connection_c& con)
640 drizzle::result_c res;
641 if (dt_query_log(con, res,
"show warnings"))
644 if (res.row_count() >= 2)
646 unsigned int row_num= 0;
647 unsigned int num_fields= res.column_count();
649 fprintf(stderr,
"\nWarnings from just before the error:\n");
650 while (drizzle_row_t row= res.row_next())
652 size_t *lengths= res.row_field_sizes();
654 if (++row_num >= res.row_count())
660 for (uint32_t i= 0; i < num_fields; i++)
662 fprintf(stderr,
"%.*s ", (
int)lengths[i], row[i] ? row[i] :
"NULL");
664 fprintf(stderr,
"\n");
681 const char *description;
685 static void check_command_args(st_command* command,
686 const char *arguments,
688 int num_args,
const char delimiter_arg)
690 const char *ptr= arguments;
693 for (
int i= 0; i < num_args; i++)
698 bool known_arg_type=
true;
703 while (*ptr && *ptr ==
' ')
707 while (*ptr && *ptr != delimiter_arg)
711 do_eval(arg->ds, start, ptr,
false);
718 command->last_argument= (
char*)ptr;
721 if (*ptr && *ptr == delimiter_arg)
728 do_eval(arg->ds, start, command->end,
false);
729 command->last_argument= command->end;
733 known_arg_type=
false;
736 assert(known_arg_type);
739 if (arg->ds->length() == 0 && arg->required)
740 die(
"Missing required argument '%s' to command '%.*s'", arg->argname,
741 command->first_word_len, command->query);
745 ptr= command->last_argument;
746 while (ptr <= command->end)
748 if (*ptr && *ptr !=
' ')
749 die(
"Extra argument '%s' passed to '%.*s'",
750 ptr, command->first_word_len, command->query);
757 static void handle_command_error(st_command* command, uint32_t error)
761 if (command->abort_on_error)
762 die(
"command \"%.*s\" failed with error %d", command->first_word_len, command->query, error);
763 for (uint32_t i= 0; i < command->expected_errors.count; i++)
765 if (command->expected_errors.err[i].type == ERR_ERRNO &&
766 command->expected_errors.err[i].code.errnum == error)
771 die(
"command \"%.*s\" failed with wrong error: %d",
772 command->first_word_len, command->query, error);
774 else if (command->expected_errors.err[0].type == ERR_ERRNO &&
775 command->expected_errors.err[0].code.errnum != 0)
778 die(
"command \"%.*s\" succeeded - should have failed with errno %d...",
779 command->first_word_len, command->query,
780 command->expected_errors.err[0].code.errnum);
784 static void cleanup_and_exit(
int exit_code)
800 printf(
"unknown exit code: %d\n", exit_code);
807 void die(
const char *fmt, ...)
814 static bool dying=
false;
820 fprintf(stderr,
"drizzletest: ");
821 if (cur_file && cur_file != file_stack.data())
822 fprintf(stderr,
"In included file \"%s\": ", cur_file->file_name);
823 if (start_lineno > 0)
824 fprintf(stderr,
"At line %u: ", start_lineno);
829 vfprintf(stderr, fmt, args);
833 fprintf(stderr,
"unknown error");
834 fprintf(stderr,
"\n");
838 if (ds_res.length() && opt_tail_lines)
840 int tail_lines= opt_tail_lines;
841 const char* show_from= ds_res.c_str() + ds_res.length() - 1;
842 while (show_from > ds_res.c_str() && tail_lines > 0 )
845 if (*show_from ==
'\n')
848 fprintf(stderr,
"\nThe result from queries just before the failure was:\n");
849 if (show_from > ds_res.c_str())
850 fprintf(stderr,
"< snip >");
851 fprintf(stderr,
"%s", show_from);
856 if (! result_file_name.empty() && ds_res.length())
857 dump_result_to_log_file(ds_res.c_str(), ds_res.length());
860 if (! result_file_name.empty() && ds_warning_messages.length())
861 dump_warning_messages();
869 show_warnings_before_error(*cur_con);
876 void abort_not_supported_test(
const char *fmt, ...)
883 fprintf(stderr,
"The test '%s' is not supported by this installation\n",
884 file_stack[0].file_name);
885 fprintf(stderr,
"Detected in file %s at line %d\n",
886 err_file->file_name, err_file->lineno);
887 while (err_file != file_stack.data())
890 fprintf(stderr,
"included from %s at line %d\n",
891 err_file->file_name, err_file->lineno);
898 fprintf(stderr,
"reason: ");
899 vfprintf(stderr, fmt, args);
900 fprintf(stderr,
"\n");
905 cleanup_and_exit(62);
909 void verbose_msg(
const char *fmt, ...)
915 fprintf(stderr,
"drizzletest: ");
916 if (cur_file && cur_file != file_stack.data())
917 fprintf(stderr,
"In included file \"%s\": ", cur_file->file_name);
918 if (start_lineno != 0)
919 fprintf(stderr,
"At line %u: ", start_lineno);
920 vfprintf(stderr, fmt, args);
921 fprintf(stderr,
"\n");
926 void warning_msg(
const char *fmt, ...)
933 ds_warning_messages +=
"drizzletest: ";
934 if (start_lineno != 0)
936 ds_warning_messages +=
"Warning detected ";
937 if (cur_file && cur_file != file_stack.data())
939 len= snprintf(buff,
sizeof(buff),
"in included file %s ", cur_file->file_name);
940 ds_warning_messages.append(buff, len);
942 len= snprintf(buff,
sizeof(buff),
"at line %d: ", start_lineno);
943 ds_warning_messages.append(buff, len);
946 len= vsnprintf(buff,
sizeof(buff), fmt, args);
947 ds_warning_messages.append(buff, len);
949 ds_warning_messages +=
"\n";
956 void log_msg(
const char *fmt, ...)
962 size_t len= vsnprintf(buff,
sizeof(buff)-1, fmt, args);
965 ds_res.append(buff, len);
980 static void cat_file(
string& ds,
const char* filename)
982 int fd= internal::my_open(filename, O_RDONLY, MYF(0));
984 die(
"Failed to open file '%s'", filename);
986 while (uint32_t len= internal::my_read(fd, (
unsigned char*)&buff,
sizeof(buff), MYF(0)))
988 char *p= buff, *start= buff;
992 if (*p ==
'\r' && *(p+1) && *(p+1)==
'\n')
997 ds.append(start, p - start);
1005 ds.append(start, p - start);
1007 internal::my_close(fd, MYF(0));
1021 static int run_command(
const char* cmd,
string& result)
1023 FILE* res_file= popen(cmd,
"r");
1025 die(
"popen(\"%s\", \"r\") failed", cmd);
1028 while (fgets(buf,
sizeof(buf), res_file))
1033 int error= pclose(res_file);
1034 return WEXITSTATUS(error);
1050 static int run_tool(
const char *tool_path,
string& result, ...)
1053 append_os_quoted(&ds_cmdline, tool_path, NULL);
1057 va_start(args, result);
1058 while (
const char* arg= va_arg(args,
char *))
1061 if (strncmp(arg,
"--", 2) == 0)
1062 append_os_quoted(&ds_cmdline, arg, NULL);
1070 return run_command(ds_cmdline.c_str(), result);
1087 static void show_diff(
string* ds,
const char* filename1,
const char* filename2)
1092 if (run_tool(
"diff",
1102 if (run_tool(
"diff",
1116 "The two files differ but it was not possible to execute 'diff' in\n"
1117 "order to show only the difference, tried both 'diff -u' or 'diff -c'.\n"
1118 "Instead the whole content of the two files was shown for you to diff manually. ;)\n"
1120 "To get a better report you should install 'diff' on your system, which you\n"
1121 "for example can get from http://www.gnu.org/software/diffutils/diffutils.html\n"
1125 ds_tmp += filename1;
1127 cat_file(ds_tmp, filename1);
1128 ds_tmp +=
"<<<\n --- ";
1129 ds_tmp += filename1;
1131 cat_file(ds_tmp, filename2);
1144 fprintf(stderr,
"%s\n", ds_tmp.c_str());
1149 enum compare_files_result_enum
1152 RESULT_CONTENT_MISMATCH= 1,
1153 RESULT_LENGTH_MISMATCH= 2
1170 static int compare_files2(
int fd,
const char* filename2)
1172 int error= RESULT_OK;
1174 char buff[512], buff2[512];
1175 const char *fname= filename2;
1178 int fd2= internal::my_open(fname, O_RDONLY, MYF(0));
1181 internal::my_close(fd, MYF(0));
1182 if (! opt_testdir.empty())
1184 tmpfile= opt_testdir;
1185 if (tmpfile[tmpfile.length()] !=
'/')
1187 tmpfile += filename2;
1188 fname= tmpfile.c_str();
1190 if ((fd2= internal::my_open(fname, O_RDONLY, MYF(0))) < 0)
1192 internal::my_close(fd, MYF(0));
1194 die(
"Failed to open second file: '%s'", fname);
1197 while ((len= internal::my_read(fd, (
unsigned char*)&buff,
1198 sizeof(buff), MYF(0))) > 0)
1200 if ((len2= internal::my_read(fd2, (
unsigned char*)&buff2,
1201 sizeof(buff2), MYF(0))) < len)
1204 error= RESULT_LENGTH_MISMATCH;
1210 error= RESULT_LENGTH_MISMATCH;
1213 if ((memcmp(buff, buff2, len)))
1216 error= RESULT_CONTENT_MISMATCH;
1220 if (!error && internal::my_read(fd2, (
unsigned char*)&buff2,
1221 sizeof(buff2), MYF(0)) > 0)
1224 error= RESULT_LENGTH_MISMATCH;
1227 internal::my_close(fd2, MYF(0));
1246 static int compare_files(
const char* filename1,
const char* filename2)
1248 int fd= internal::my_open(filename1, O_RDONLY, MYF(0));
1250 die(
"Failed to open first file: '%s'", filename1);
1251 int error= compare_files2(fd, filename2);
1252 internal::my_close(fd, MYF(0));
1269 static int string_cmp(
const string& ds,
const char *fname)
1271 char temp_file_path[FN_REFLEN];
1273 int fd= internal::create_temp_file(temp_file_path, TMPDIR,
"tmp", MYF(MY_WME));
1275 die(
"Failed to create temporary file for ds");
1278 if (internal::my_write(fd, (
unsigned char *) ds.data(), ds.length(), MYF(MY_FNABP | MY_WME)) ||
1279 lseek(fd, 0, SEEK_SET) == MY_FILEPOS_ERROR)
1281 internal::my_close(fd, MYF(0));
1283 internal::my_delete(temp_file_path, MYF(0));
1284 die(
"Failed to write file '%s'", temp_file_path);
1287 int error= compare_files2(fd, fname);
1289 internal::my_close(fd, MYF(0));
1291 internal::my_delete(temp_file_path, MYF(0));
1309 static void check_result(
string& ds)
1311 const char* mess=
"Result content mismatch\n";
1313 if (access(result_file_name.c_str(), F_OK) != 0)
1314 die(
"The specified result file does not exist: '%s'", result_file_name.c_str());
1316 switch (string_cmp(ds, result_file_name.c_str()))
1320 case RESULT_LENGTH_MISMATCH:
1321 mess=
"Result length mismatch\n";
1323 case RESULT_CONTENT_MISMATCH:
1329 char reject_file[FN_REFLEN];
1330 size_t reject_length;
1331 internal::dirname_part(reject_file, result_file_name.c_str(), &reject_length);
1333 if (access(reject_file, W_OK) == 0)
1336 internal::fn_format(reject_file, result_file_name.c_str(), NULL,
".reject", MY_REPLACE_EXT);
1341 internal::fn_format(reject_file, result_file_name.c_str(), opt_logdir.c_str(),
".reject", MY_REPLACE_DIR | MY_REPLACE_EXT);
1343 str_to_file(reject_file, ds.data(), ds.length());
1347 show_diff(NULL, result_file_name.c_str(), reject_file);
1352 die(
"Unknown error code from dyn_string_cmp()");
1372 static void check_require(
const string& ds,
const string& fname)
1374 if (string_cmp(ds, fname.c_str()))
1376 char reason[FN_REFLEN];
1377 internal::fn_format(reason, fname.c_str(),
"",
"", MY_REPLACE_EXT | MY_REPLACE_DIR);
1378 abort_not_supported_test(
"Test requires: '%s'", reason);
1388 static int strip_surrounding(
char* str,
char c1,
char c2)
1393 while (*ptr && charset_info->isspace(*ptr))
1401 ptr= strchr(str,
'\0')-1;
1402 while (*ptr && charset_info->isspace(*ptr))
1419 static void strip_parentheses(st_command* command)
1421 if (strip_surrounding(command->first_argument,
'(',
')'))
1422 die(
"%.*s - argument list started with '%c' must be ended with '%c'",
1423 command->first_word_len, command->query,
'(',
')');
1428 VAR *var_init(
VAR *v,
const char *name,
int name_len,
const char *val,
1431 if (!name_len && name)
1432 name_len = strlen(name);
1433 if (!val_len && val)
1434 val_len = strlen(val) ;
1435 VAR *tmp_var = v ? v : (
VAR*)malloc(
sizeof(*tmp_var) + name_len+1);
1437 tmp_var->name = name ? (
char*)&tmp_var[1] : 0;
1438 tmp_var->alloced = (v == 0);
1440 int val_alloc_len = val_len + 16;
1441 tmp_var->str_val = (
char*)malloc(val_alloc_len+1);
1443 memcpy(tmp_var->name, name, name_len);
1446 memcpy(tmp_var->str_val, val, val_len);
1447 tmp_var->str_val[val_len]= 0;
1449 tmp_var->name_len = name_len;
1450 tmp_var->str_val_len = val_len;
1451 tmp_var->alloced_len = val_alloc_len;
1452 tmp_var->int_val = val ? atoi(val) : 0;
1453 tmp_var->int_dirty =
false;
1458 VAR* var_from_env(
const char *name,
const char *def_val)
1460 const char *tmp= getenv(name);
1463 return var_hash[name] = var_init(0, name, strlen(name), tmp, strlen(tmp));
1466 VAR* var_get(
const char *var_name,
const char **var_name_end,
bool raw,
1467 bool ignore_not_existing)
1471 if (*var_name !=
'$')
1473 digit = *++var_name -
'0';
1474 if (digit < 0 || digit >= 10)
1476 const char *save_var_name = var_name, *end;
1478 end = (var_name_end) ? *var_name_end : 0;
1479 while (charset_info->isvar(*var_name) && var_name != end)
1481 if (var_name == save_var_name)
1483 if (ignore_not_existing)
1485 die(
"Empty variable");
1487 length= (uint32_t) (var_name - save_var_name);
1488 if (length >= MAX_VAR_NAME_LENGTH)
1489 die(
"Too long variable name: %s", save_var_name);
1491 string save_var_name_str(save_var_name, length);
1492 if (var_hash_t::mapped_type* ptr= find_ptr(var_hash, save_var_name_str))
1496 char buff[MAX_VAR_NAME_LENGTH+1];
1497 strncpy(buff, save_var_name, length);
1499 v= var_from_env(buff,
"");
1504 v = &var_reg[digit];
1506 if (!raw && v->int_dirty)
1508 sprintf(v->str_val,
"%d", v->int_val);
1510 v->str_val_len = strlen(v->str_val);
1513 *var_name_end = var_name ;
1518 die(
"Unsupported variable name: %s", var_name);
1523 static VAR *var_obtain(
const char *name,
int len)
1525 string var_name(name, len);
1526 if (var_hash_t::mapped_type* ptr= find_ptr(var_hash, var_name))
1528 return var_hash[var_name] = var_init(0, name, len,
"", 0);
1538 static void var_set(
const char *var_name,
const char *var_name_end,
1539 const char *var_val,
const char *var_val_end)
1541 int digit, env_var= 0;
1544 if (*var_name !=
'$')
1549 digit= *var_name -
'0';
1550 if (!(digit < 10 && digit >= 0))
1552 v= var_obtain(var_name, (uint32_t) (var_name_end - var_name));
1557 eval_expr(v, var_val, (
const char**) &var_val_end);
1561 char buf[1024], *old_env_s= v->env_s;
1564 sprintf(v->str_val,
"%d", v->int_val);
1566 v->str_val_len= strlen(v->str_val);
1568 snprintf(buf,
sizeof(buf),
"%.*s=%.*s",
1569 v->name_len, v->name,
1570 v->str_val_len, v->str_val);
1571 v->env_s= strdup(buf);
1579 static void var_set_string(
const char* name,
const char* value)
1581 var_set(name, name + strlen(name), value, value + strlen(value));
1585 static void var_set_int(
const char* name,
int value)
1588 snprintf(buf,
sizeof(buf),
"%d", value);
1589 var_set_string(name, buf);
1598 static void var_set_errno(
int sql_errno)
1600 var_set_int(
"$drizzleclient_errno", sql_errno);
1609 static void var_set_drizzleclient_get_server_version(drizzle_con_st *con)
1611 var_set_int(
"$drizzle_con_server_version", drizzle_con_server_version_number(con));
1638 static void dt_query(drizzle::connection_c& con, drizzle::result_c& res,
const std::string& query)
1640 if (drizzle_return_t ret= con.query(res, query))
1642 if (ret == DRIZZLE_RETURN_ERROR_CODE)
1644 die(
"Error running query '%s': %d %s", query.c_str(), res.error_code(), res.error());
1648 die(
"Error running query '%s': %d %s", query.c_str(), ret, con.error());
1652 if (res.column_count() == 0)
1654 die(
"Query '%s' didn't return a result set", query.c_str());
1658 static void var_query_set(
VAR *
var,
const char *query,
const char** query_end)
1660 const char *end = ((query_end && *query_end) ? *query_end : query + strlen(query));
1661 drizzle::connection_c& con= *cur_con;
1663 while (end > query && *end !=
'`')
1666 die(
"Syntax error in query, missing '`'");
1671 do_eval(&ds_query, query, end,
false);
1673 drizzle::result_c res;
1674 dt_query(con, res, ds_query);
1676 drizzle_row_t row= res.row_next();
1684 size_t* lengths= res.row_field_sizes();
1685 for (uint32_t i= 0; i < res.column_count(); i++)
1690 result.append(row[i], lengths[i]);
1694 end= result.c_str() + result.length() - 1;
1695 eval_expr(var, result.c_str(), (
const char**) &end);
1698 eval_expr(var,
"", 0);
1724 static void var_set_query_get_value(st_command* command,
VAR *var)
1727 drizzle::connection_c& con= *cur_con;
1732 const struct command_arg query_get_value_args[] = {
1733 {
"query", ARG_STRING,
true, &ds_query,
"Query to run"},
1734 {
"column name", ARG_STRING,
true, &ds_col,
"Name of column"},
1735 {
"row number", ARG_STRING,
true, &ds_row,
"Number for row"}
1740 strip_parentheses(command);
1741 check_command_args(command, command->first_argument, query_get_value_args,
1742 sizeof(query_get_value_args)/
sizeof(
struct command_arg),
1746 long row_no= atoi(ds_row.c_str());
1748 istringstream buff(ds_row);
1749 if ((buff >> row_no).fail())
1750 die(
"Invalid row number: '%s'", ds_row.c_str());
1754 char* unstripped_query= strdup(ds_query.c_str());
1755 if (strip_surrounding(unstripped_query,
'"',
'"'))
1756 die(
"Mismatched \"'s around query '%s'", ds_query.c_str());
1757 ds_query= unstripped_query;
1759 drizzle::result_c res;
1760 dt_query(con, res, ds_query);
1764 uint32_t num_fields= res.column_count();
1765 for (uint32_t i= 0; i < num_fields; i++)
1767 drizzle_column_st* column= res.column_next();
1768 if (strcmp(drizzle_column_name(column), ds_col.c_str()) == 0 &&
1769 strlen(drizzle_column_name(column)) == ds_col.length())
1777 die(
"Could not find column '%s' in the result of '%s'", ds_col.c_str(), ds_query.c_str());
1784 const char* value=
"No such row";
1786 while (drizzle_row_t row= res.row_next())
1788 if (++rows == row_no)
1791 value= row[col_no] ? row[col_no] :
"NULL";
1795 eval_expr(var, value, 0);
1800 static void var_copy(
VAR *dest,
VAR *src)
1802 dest->int_val= src->int_val;
1803 dest->int_dirty= src->int_dirty;
1806 if (dest->alloced_len < src->alloced_len)
1808 char *tmpptr= (
char *)realloc(dest->str_val, src->alloced_len);
1809 dest->str_val= tmpptr;
1812 dest->alloced_len= src->alloced_len;
1815 dest->str_val_len= src->str_val_len;
1816 if (src->str_val_len)
1817 memcpy(dest->str_val, src->str_val, src->str_val_len);
1821 void eval_expr(
VAR *v,
const char *p,
const char **p_end)
1825 VAR *vp= var_get(p, p_end, 0, 0);
1833 var_query_set(v, p, p_end);
1839 const char* get_value_str=
"query_get_value";
1840 const size_t len= strlen(get_value_str);
1841 if (strncmp(p, get_value_str, len)==0)
1844 command.query= (
char*)p;
1845 command.first_word_len= len;
1846 command.first_argument= command.query + len;
1847 command.end= (
char*)*p_end;
1848 var_set_query_get_value(&command, v);
1854 int new_val_len = (p_end && *p_end) ?
1855 (
int) (*p_end - p) : (
int) strlen(p);
1856 if (new_val_len + 1 >= v->alloced_len)
1858 static int MIN_VAR_ALLOC= 32;
1859 v->alloced_len = (new_val_len < MIN_VAR_ALLOC - 1) ?
1860 MIN_VAR_ALLOC : new_val_len + 1;
1861 char *tmpptr= (
char *)realloc(v->str_val, v->alloced_len+1);
1864 v->str_val_len = new_val_len;
1865 memcpy(v->str_val, p, new_val_len);
1866 v->str_val[new_val_len] = 0;
1874 static void open_file(
const char *name)
1876 char buff[FN_REFLEN];
1878 if (!internal::test_if_hard_path(name))
1880 snprintf(buff,
sizeof(buff),
"%s%s",opt_basedir.c_str(),name);
1883 internal::fn_format(buff, name,
"",
"", MY_UNPACK_FILENAME);
1886 if (cur_file == &*file_stack.end())
1887 die(
"Source directives are nesting too deep");
1888 if (!(cur_file->file= fopen(buff,
"r")))
1891 die(
"Could not open '%s' for reading", buff);
1893 cur_file->file_name= strdup(buff);
1912 static void do_source(st_command* command)
1916 {
"filename", ARG_STRING,
true, &ds_filename,
"File to source" }
1920 check_command_args(command, command->first_argument, source_args,
1928 if (parser.current_line < (parser.read_lines - 1))
1932 if (! opt_testdir.empty())
1934 string testdir(opt_testdir);
1935 if (testdir[testdir.length()] !=
'/')
1937 testdir += ds_filename;
1938 ds_filename.swap(testdir);
1940 open_file(ds_filename.c_str());
1945 static void init_builtin_echo()
1967 static int replace(
string *ds_str,
1968 const char *search_str, uint32_t search_len,
1969 const char *replace_str, uint32_t replace_len)
1972 const char *start= strstr(ds_str->c_str(), search_str);
1975 ds_tmp.append(ds_str->c_str(), start - ds_str->c_str());
1976 ds_tmp.append(replace_str, replace_len);
1977 ds_tmp.append(start + search_len);
2004 static void do_exec(st_command* command)
2009 char *cmd= command->first_argument;
2013 while (*cmd && charset_info->isspace(*cmd))
2016 die(
"Missing argument in exec");
2017 command->last_argument= command->end;
2020 do_eval(&ds_cmd, cmd, command->end, !is_windows);
2023 if (builtin_echo[0] && strncmp(cmd,
"echo", 4) == 0)
2026 replace(&ds_cmd,
"echo", 4, builtin_echo, strlen(builtin_echo));
2029 if (!(res_file= popen(ds_cmd.c_str(),
"r")) && command->abort_on_error)
2031 die(
"popen(\"%s\", \"r\") failed", command->first_argument);
2034 while (fgets(buf,
sizeof(buf), res_file))
2036 if (disable_result_log)
2038 buf[strlen(buf)-1]=0;
2042 replace_append(&ds_res, buf);
2045 error= pclose(res_file);
2048 uint32_t status= WEXITSTATUS(error), i;
2051 if (command->abort_on_error)
2053 log_msg(
"exec of '%s' failed, error: %d, status: %d, errno: %d", ds_cmd.c_str(), error, status, errno);
2054 die(
"command \"%s\" failed", command->first_argument);
2057 for (i= 0; i < command->expected_errors.count; i++)
2059 if ((command->expected_errors.err[i].type == ERR_ERRNO) &&
2060 (command->expected_errors.err[i].code.errnum == status))
2067 die(
"command \"%s\" failed with wrong error: %d",
2068 command->first_argument, status);
2071 else if (command->expected_errors.err[0].type == ERR_ERRNO &&
2072 command->expected_errors.err[0].code.errnum != 0)
2075 log_msg(
"exec of '%s failed, error: %d, errno: %d", ds_cmd.c_str(), error, errno);
2076 die(
"command \"%s\" succeeded - should have failed with errno %d...",
2077 command->first_argument, command->expected_errors.err[0].code.errnum);
2104 static int do_modify_var(st_command* command,
2105 enum enum_operator op)
2107 const char *p= command->first_argument;
2110 die(
"Missing argument to %.*s", command->first_word_len, command->query);
2112 die(
"The argument to %.*s must be a variable (start with $)",
2113 command->first_word_len, command->query);
2114 v= var_get(p, &p, 1, 0);
2123 die(
"Invalid operator to do_modify_var");
2127 command->last_argument= (
char*)++p;
2145 static void do_system(st_command* command)
2150 if (strlen(command->first_argument) == 0)
2151 die(
"Missing arguments to system, nothing to do!");
2154 do_eval(&ds_cmd, command->first_argument, command->end, !is_windows);
2156 if (system(ds_cmd.c_str()))
2158 if (command->abort_on_error)
2159 die(
"system command '%s' failed", command->first_argument);
2162 ds_res +=
"system command '";
2163 replace_append(&ds_res, command->first_argument);
2164 ds_res +=
"' failed\n";
2167 command->last_argument= command->end;
2182 static void do_remove_file(st_command* command)
2186 {
"filename", ARG_STRING,
true, &ds_filename,
"File to delete" }
2190 check_command_args(command, command->first_argument,
2191 rm_args,
sizeof(rm_args)/
sizeof(
struct command_arg),
2194 int error= internal::my_delete(ds_filename.c_str(), MYF(0)) != 0;
2195 handle_command_error(command, error);
2211 static void do_copy_file(st_command* command)
2213 string ds_from_file;
2216 {
"from_file", ARG_STRING,
true, &ds_from_file,
"Filename to copy from" },
2217 {
"to_file", ARG_STRING,
true, &ds_to_file,
"Filename to copy to" }
2221 check_command_args(command, command->first_argument,
2223 sizeof(copy_file_args)/
sizeof(
struct command_arg),
2226 int error= (internal::my_copy(ds_from_file.c_str(), ds_to_file.c_str(),
2227 MYF(MY_DONT_OVERWRITE_FILE)) != 0);
2228 handle_command_error(command, error);
2243 static void do_chmod_file(st_command* command)
2249 {
"mode", ARG_STRING,
true, &ds_mode,
"Mode of file(octal) ex. 0660"},
2250 {
"filename", ARG_STRING,
true, &ds_file,
"Filename of file to modify" }
2254 check_command_args(command, command->first_argument,
2256 sizeof(chmod_file_args)/
sizeof(
struct command_arg),
2260 istringstream buff(ds_mode);
2261 if (ds_mode.length() != 4 ||
2262 (buff >> oct >> mode).fail())
2263 die(
"You must write a 4 digit octal number for mode");
2265 handle_command_error(command, chmod(ds_file.c_str(), mode));
2279 static void do_file_exist(st_command* command)
2283 {
"filename", ARG_STRING,
true, &ds_filename,
"File to check if it exist" }
2287 check_command_args(command, command->first_argument,
2289 sizeof(file_exist_args)/
sizeof(
struct command_arg),
2292 int error= access(ds_filename.c_str(), F_OK) != 0;
2293 handle_command_error(command, error);
2307 static void do_mkdir(st_command* command)
2311 {
"dirname", ARG_STRING,
true, &ds_dirname,
"Directory to create"}
2315 check_command_args(command, command->first_argument,
2316 mkdir_args,
sizeof(mkdir_args)/
sizeof(
struct command_arg),
2319 int error= mkdir(ds_dirname.c_str(), (0777 & internal::my_umask_dir)) != 0;
2320 handle_command_error(command, error);
2333 static void do_rmdir(st_command* command)
2337 {
"dirname", ARG_STRING,
true, &ds_dirname,
"Directory to remove"}
2341 check_command_args(command, command->first_argument,
2342 rmdir_args,
sizeof(rmdir_args)/
sizeof(
struct command_arg),
2345 int error= rmdir(ds_dirname.c_str()) != 0;
2346 handle_command_error(command, error);
2360 static int my_getc(FILE *file)
2362 if (line_buffer_pos == line_buffer)
2364 return *--line_buffer_pos;
2368 static void my_ungetc(
int c)
2370 *line_buffer_pos++= (char) c;
2374 static void read_until_delimiter(
string *ds,
2375 string *ds_delimiter)
2377 if (ds_delimiter->length() > MAX_DELIMITER_LENGTH)
2378 die(
"Max delimiter length(%d) exceeded", MAX_DELIMITER_LENGTH);
2383 char c= my_getc(cur_file->file);
2390 if (start_lineno == (cur_file->lineno - 1))
2393 else if (start_lineno == cur_file->lineno)
2399 die(
"Trailing characters found after command");
2402 if (feof(cur_file->file))
2403 die(
"End of file encountered before '%s' delimiter was found",
2404 ds_delimiter->c_str());
2406 if (match_delimiter(c, ds_delimiter->c_str(), ds_delimiter->length()))
2414 static void do_write_file_command(st_command* command,
bool append)
2418 string ds_delimiter;
2420 {
"filename", ARG_STRING,
true, &ds_filename,
"File to write to" },
2421 {
"delimiter", ARG_STRING,
false, &ds_delimiter,
"Delimiter to read until" }
2425 check_command_args(command,
2426 command->first_argument,
2428 sizeof(write_file_args)/
sizeof(
struct command_arg),
2432 if (ds_delimiter.length() == 0)
2433 ds_delimiter +=
"EOF";
2435 if (!append && access(ds_filename.c_str(), F_OK) == 0)
2438 die(
"File already exist: '%s'", ds_filename.c_str());
2441 read_until_delimiter(&ds_content, &ds_delimiter);
2442 str_to_file2(ds_filename.c_str(), ds_content.c_str(), ds_content.length(), append);
2473 static void do_write_file(st_command* command)
2475 do_write_file_command(command,
false);
2504 static void do_append_file(st_command* command)
2506 do_write_file_command(command,
true);
2522 static void do_cat_file(st_command* command)
2524 static string ds_filename;
2526 {
"filename", ARG_STRING,
true, &ds_filename,
"File to read from" }
2530 check_command_args(command,
2531 command->first_argument,
2536 cat_file(ds_res, ds_filename.c_str());
2552 static void do_diff_files(st_command* command)
2555 string ds_filename2;
2557 {
"file1", ARG_STRING,
true, &ds_filename,
"First file to diff" },
2558 {
"file2", ARG_STRING,
true, &ds_filename2,
"Second file to diff" }
2562 check_command_args(command,
2563 command->first_argument,
2565 sizeof(diff_file_args)/
sizeof(
struct command_arg),
2568 int error= compare_files(ds_filename.c_str(), ds_filename2.c_str());
2574 show_diff(&ds_res, ds_filename.c_str(), ds_filename2.c_str());
2577 handle_command_error(command, error);
2590 static void do_send_quit(st_command* command)
2592 char* p= command->first_argument;
2595 die(
"Missing connection name in send_quit");
2597 while (*p && !charset_info->isspace(*p))
2602 command->last_argument= p;
2606 die(
"connection '%s' not found in connection pool", name);
2608 drizzle::result_c result;
2609 drizzle_return_t ret;
2610 drizzle_quit(*con, result, &ret);
2630 static void do_change_user(st_command *)
2654 static void do_perl(st_command* command)
2656 char buf[FN_REFLEN];
2657 char temp_file_path[FN_REFLEN];
2659 string ds_delimiter;
2661 {
"delimiter", ARG_STRING,
false, &ds_delimiter,
"Delimiter to read until" }
2665 check_command_args(command,
2666 command->first_argument,
2672 if (ds_delimiter.length() == 0)
2673 ds_delimiter +=
"EOF";
2675 read_until_delimiter(&ds_script, &ds_delimiter);
2678 int fd= internal::create_temp_file(temp_file_path, getenv(
"MYSQLTEST_VARDIR"),
"tmp", MYF(MY_WME));
2680 die(
"Failed to create temporary file for perl command");
2681 internal::my_close(fd, MYF(0));
2683 str_to_file(temp_file_path, ds_script.c_str(), ds_script.length());
2686 snprintf(buf,
sizeof(buf),
"perl %s", temp_file_path);
2688 FILE* res_file= popen(buf,
"r");
2689 if (not res_file && command->abort_on_error)
2690 die(
"popen(\"%s\", \"r\") failed", buf);
2692 while (fgets(buf,
sizeof(buf), res_file))
2694 if (disable_result_log)
2695 buf[strlen(buf)-1]=0;
2697 replace_append(&ds_res, buf);
2699 int error= pclose(res_file);
2702 internal::my_delete(temp_file_path, MYF(0));
2704 handle_command_error(command, WEXITSTATUS(error));
2732 static void do_echo(st_command* command)
2735 do_eval(&ds_echo, command->first_argument, command->end,
false);
2738 command->last_argument= command->end;
2741 static void do_wait_for_slave_to_stop()
2743 static int SLAVE_POLL_INTERVAL= 300000;
2744 drizzle::connection_c& con= *cur_con;
2747 drizzle::result_c res;
2748 dt_query(con, res,
"show status like 'Slave_running'");
2749 drizzle_row_t row= res.row_next();
2750 if (!row || !row[1])
2752 die(
"Strange result from query while probing slave for stop");
2754 if (!strcmp(row[1],
"OFF"))
2756 usleep(SLAVE_POLL_INTERVAL);
2779 static void do_let(st_command* command)
2781 char *p= command->first_argument;
2782 char *var_name, *var_name_end;
2783 string let_rhs_expr;
2788 die(
"Missing arguments to let");
2790 while (*p && (*p !=
'=') && !charset_info->isspace(*p))
2793 if (var_name == var_name_end ||
2794 (var_name+1 == var_name_end && *var_name ==
'$'))
2795 die(
"Missing variable name in let");
2796 while (charset_info->isspace(*p))
2799 die(
"Missing assignment operator in let");
2802 while (*p && charset_info->isspace(*p))
2805 do_eval(&let_rhs_expr, p, command->end,
false);
2807 command->last_argument= command->end;
2809 var_set(var_name, var_name_end, let_rhs_expr.c_str(),
2810 (let_rhs_expr.c_str() + let_rhs_expr.length()));
2837 static void do_sleep(st_command* command,
bool real_sleep)
2839 char *p= command->first_argument;
2840 char *sleep_start, *sleep_end= command->end;
2841 double sleep_val= 0;
2843 while (charset_info->isspace(*p))
2846 die(
"Missing argument to %.*s", command->first_word_len, command->query);
2849 if (!charset_info->isdigit(*sleep_start))
2850 die(
"Invalid argument to %.*s \"%s\"", command->first_word_len,
2851 command->query,command->first_argument);
2852 string buff_str(sleep_start, sleep_end-sleep_start);
2853 istringstream buff(buff_str);
2856 die(
"Invalid argument to %.*s \"%s\"", command->first_word_len, command->query, command->first_argument);
2859 if (opt_sleep >= 0 && !real_sleep)
2860 sleep_val= opt_sleep;
2863 usleep(sleep_val * 1000000);
2864 command->last_argument= sleep_end;
2868 static void do_get_file_name(st_command* command,
string &dest)
2870 char *p= command->first_argument;
2872 die(
"Missing file name argument");
2874 while (*p && !charset_info->isspace(*p))
2878 command->last_argument= p;
2879 if (! opt_testdir.empty())
2882 if (dest[dest.length()] !=
'/')
2889 static void do_set_charset(st_command* command)
2891 char *charset_name= command->first_argument;
2894 if (!charset_name || !*charset_name)
2895 die(
"Missing charset name in 'character_set'");
2898 while (*p && !charset_info->isspace(*p))
2902 command->last_argument= p;
2903 charset_info= get_charset_by_csname(charset_name, MY_CS_PRIMARY);
2905 abort_not_supported_test(
"Test requires charset '%s'", charset_name);
2908 static void fill_global_error_names()
2910 drizzle::connection_c& con= *cur_con;
2912 global_error_names.clear();
2914 drizzle::result_c res;
2915 dt_query(con, res,
"select error_name, error_code from data_dictionary.errors");
2916 while (drizzle_row_t row= res.row_next())
2924 size_t *lengths= res.row_field_sizes();
2927 global_error_names[string(row[0], lengths[0])] = boost::lexical_cast<uint32_t>(string(row[1], lengths[1]));
2929 catch (boost::bad_lexical_cast &ex)
2931 die(
"Invalid error_code from Drizzle: %s", ex.what());
2936 static uint32_t get_errcode_from_name(
const char *error_name,
const char *error_end)
2938 string error_name_s(error_name, error_end);
2940 if (ErrorCodes::mapped_type* ptr= find_ptr(global_error_names, error_name_s))
2943 die(
"Unknown SQL error name '%s'", error_name_s.c_str());
2947 static void do_get_errcodes(st_command* command)
2950 char *p= command->first_argument;
2956 die(
"Missing argument(s) to 'error'");
2963 while (*p && *p ==
' ')
2968 while (*end && *end !=
',' && *end !=
' ')
2973 char *to_ptr= to->code.sqlstate;
2981 if ((end - p) != DRIZZLE_MAX_SQLSTATE_SIZE)
2982 die(
"The sqlstate must be exactly %d chars long", DRIZZLE_MAX_SQLSTATE_SIZE);
2985 while (*p && p < end)
2987 if (charset_info->isdigit(*p) || charset_info->isupper(*p))
2990 die(
"The sqlstate may only consist of digits[0-9] and _uppercase_ letters");
2994 to->type= ERR_SQLSTATE;
2998 die(
"The sqlstate definition must start with an uppercase S");
3004 to->code.errnum= get_errcode_from_name(p, end);
3005 to->type= ERR_ERRNO;
3009 die(
"The error name definition must start with an uppercase E");
3015 to->code.errnum= get_errcode_from_name(p, end);
3016 to->type= ERR_ERRNO;
3020 die (
"You must either use the SQLSTATE or built in drizzle error label, numbers are not accepted");
3025 if (count >= (
sizeof(saved_expected_errors.err) /
3027 die(
"Too many errorcodes specified");
3033 while (*p && *p !=
',')
3041 command->last_argument= p;
3042 to->type= ERR_EMPTY;
3044 saved_expected_errors.count= count;
3056 static char *get_string(
char **to_ptr,
char **from_ptr,
3057 st_command* command)
3060 char *to= *to_ptr, *from= *from_ptr, *start=to;
3064 if (*from ==
'"' || *from ==
'\'')
3069 for ( ; (c=*from) ; from++)
3071 if (c ==
'\\' && from[1])
3097 if (c ==
' ' || c != *++from)
3104 if (*from !=
' ' && *from)
3105 die(
"Wrong string argument in %s", command->query);
3107 while (charset_info->isspace(*from))
3117 const char *end= to;
3118 VAR *var=var_get(start, &end, 0, 1);
3119 if (var && to == (
char*) end+1)
3120 return(var->str_val);
3126 static void set_reconnect(drizzle_con_st *con,
int val)
3138 static void select_connection_name(
const char *name)
3140 if (!(cur_con= find_ptr2(g_connections, name)))
3141 die(
"connection '%s' not found in connection pool", name);
3144 var_set_drizzleclient_get_server_version(*cur_con);
3148 static void select_connection(st_command* command)
3150 char *p= command->first_argument;
3152 die(
"Missing connection name in connect");
3154 while (*p && !charset_info->isspace(*p))
3158 command->last_argument= p;
3159 select_connection_name(name);
3163 static void do_close_connection(st_command* command)
3165 char* p= command->first_argument;
3167 die(
"Missing connection name in disconnect");
3169 while (*p && !charset_info->isspace(*p))
3174 command->last_argument= p;
3178 die(
"connection '%s' not found in connection pool", name);
3179 g_connections.erase(name);
3209 static st_connection* safe_connect(
const char *name,
const string host,
const string user,
const char *pass,
const string db, uint32_t port)
3211 uint32_t failed_attempts= 0;
3213 drizzle_con_st* con= *con0;
3214 drizzle_con_set_tcp(con, host.c_str(), port);
3215 drizzle_con_set_auth(con, user.c_str(), pass);
3216 while (drizzle_return_t ret= drizzle_con_connect(con))
3226 if ((ret == DRIZZLE_RETURN_GETADDRINFO ||
3227 ret == DRIZZLE_RETURN_COULD_NOT_CONNECT) &&
3228 failed_attempts < opt_max_connect_retries)
3230 verbose_msg(
"Connect attempt %d/%d failed: %d: %s", failed_attempts, opt_max_connect_retries, ret, drizzle_con_error(con));
3235 if (failed_attempts > 0)
3236 die(
"Could not open connection '%s' after %d attempts: %d %s", name, failed_attempts, ret, drizzle_con_error(con));
3238 die(
"Could not open connection '%s': %d %s", name, ret, drizzle_con_error(con));
3244 std::string sql_string(
"CREATE SCHEMA IF NOT EXISTS mysql");
3245 drizzle_return_t ret;
3246 drizzle_result_st *result= drizzle_query(con, NULL, sql_string.c_str(), sql_string.size(), &ret);
3247 if (ret != DRIZZLE_RETURN_OK)
3249 die(
"Failed to create schema '%s': %d %s", db.c_str(), ret, drizzle_con_error(con));
3254 drizzle_result_free(result);
3259 std::string sql_string(
"CREATE SCHEMA IF NOT EXISTS ");
3261 drizzle_return_t ret;
3262 drizzle_result_st *result= drizzle_query(con, NULL, sql_string.c_str(), sql_string.size(), &ret);
3263 if (ret != DRIZZLE_RETURN_OK)
3265 die(
"Failed to create schema '%s': %d %s", db.c_str(), ret, drizzle_con_error(con));
3270 drizzle_result_free(result);
3275 std::string sql_string(
"USE ");
3277 drizzle_return_t ret;
3278 drizzle_result_st *result= drizzle_query(con, NULL, sql_string.c_str(), sql_string.size(), &ret);
3279 if (ret != DRIZZLE_RETURN_OK)
3281 die(
"Failed to use schema '%s': %d %s", db.c_str(), ret, drizzle_con_error(con));
3286 drizzle_result_free(result);
3317 static int connect_n_handle_errors(st_command* command,
3318 drizzle_con_st *con,
const char* host,
3319 const char* user,
const char* pass,
3320 const char* db,
int port,
const char* sock)
3323 if (!command->abort_on_error &&
3329 ds_res +=
"connect(";
3330 replace_append(&ds_res, host);
3332 replace_append(&ds_res, user);
3334 replace_append(&ds_res, pass);
3337 replace_append(&ds_res, db);
3339 replace_append_uint(ds_res, port);
3342 replace_append(&ds_res, sock);
3344 ds_res += delimiter;
3347 drizzle_con_set_tcp(con, host, port);
3348 drizzle_con_set_auth(con, user, pass);
3349 drizzle_con_set_db(con, db);
3350 if (drizzle_return_t ret= drizzle_con_connect(con))
3352 if (ret == DRIZZLE_RETURN_HANDSHAKE_FAILED)
3354 var_set_errno(drizzle_con_error_code(con));
3355 handle_error(command, drizzle_con_error_code(con), drizzle_con_error(con), drizzle_con_sqlstate(con), &ds_res);
3360 handle_error(command, ret, drizzle_con_error(con),
"", &ds_res);
3365 handle_no_error(command);
3395 static void do_connect(st_command* command)
3397 uint32_t con_port= opt_port;
3399 string ds_connection_name;
3408 {
"connection name", ARG_STRING,
true, &ds_connection_name,
"Name of the connection" },
3409 {
"host", ARG_STRING,
true, &ds_host,
"Host to connect to" },
3410 {
"user", ARG_STRING,
false, &ds_user,
"User to connect as" },
3411 {
"passsword", ARG_STRING,
false, &ds_password,
"Password used when connecting" },
3412 {
"database", ARG_STRING,
false, &ds_database,
"Database to select after connect" },
3413 {
"port", ARG_STRING,
false, &ds_port,
"Port to connect to" },
3414 {
"socket", ARG_STRING,
false, &ds_sock,
"Socket to connect with" },
3415 {
"options", ARG_STRING,
false, &ds_options,
"Options to use while connecting" }
3418 strip_parentheses(command);
3419 check_command_args(command, command->first_argument, connect_args,
3424 if (ds_port.length())
3426 con_port= atoi(ds_port.c_str());
3428 die(
"Illegal argument for port: '%s'", ds_port.c_str());
3432 if (!ds_sock.empty())
3438 if (*ds_sock.c_str() != FN_LIBCHAR)
3440 char buff[FN_REFLEN];
3441 internal::fn_format(buff, ds_sock.c_str(), TMPDIR,
"", 0);
3447 const char* con_options= ds_options.c_str();
3448 while (*con_options)
3451 while (*con_options && charset_info->isspace(*con_options))
3454 const char* end= con_options;
3455 while (*end && !charset_info->isspace(*end))
3457 die(
"Illegal option to connect: %.*s", (
int) (end - con_options), con_options);
3462 if (find_ptr2(g_connections, ds_connection_name))
3463 die(
"Connection %s already exists", ds_connection_name.c_str());
3468 if (ds_database.empty())
3470 ds_database= opt_db;
3474 if (ds_database ==
"*NO-ONE*")
3476 ds_database.clear();
3479 if (connect_n_handle_errors(command, *con_slot, ds_host.c_str(), ds_user.c_str(),
3480 ds_password.c_str(), ds_database.c_str(), con_port, ds_sock.c_str()))
3482 g_connections[ds_connection_name]= con_slot;
3487 var_set_drizzleclient_get_server_version(*cur_con);
3491 static void do_done(st_command* command)
3494 if (cur_block == block_stack)
3496 if (*command->query !=
'}')
3497 die(
"Stray 'end' command - end of block before beginning");
3498 die(
"Stray '}' - end of block before beginning");
3502 if (cur_block->ok && cur_block->cmd == cmd_while)
3506 parser.current_line = cur_block->line;
3512 parser.current_line++;
3543 static void do_block(
enum block_cmd cmd, st_command* command)
3545 char *p= command->first_argument;
3546 const char *expr_start, *expr_end;
3547 const char *cmd_name= (cmd == cmd_while ?
"while" :
"if");
3548 bool not_expr=
false;
3551 if (cur_block == block_stack_end)
3552 die(
"Nesting too deeply");
3555 cur_block->line= parser.current_line++;
3562 cur_block->cmd= cmd;
3563 cur_block->ok=
false;
3568 expr_start= strchr(p,
'(');
3570 die(
"missing '(' in %s", cmd_name);
3573 if (*expr_start ==
'!')
3579 expr_end= strrchr(expr_start,
')');
3581 die(
"missing ')' in %s", cmd_name);
3582 p= (
char*)expr_end+1;
3584 while (*p && charset_info->isspace(*p))
3586 if (*p && *p !=
'{')
3587 die(
"Missing '{' after %s. Found \"%s\"", cmd_name, p);
3590 var_init(&v,0,0,0,0);
3591 eval_expr(&v, expr_start, &expr_end);
3595 cur_block->cmd= cmd;
3596 cur_block->ok= (v.int_val ?
true :
false);
3599 cur_block->ok = !cur_block->ok;
3606 static void do_delimiter(st_command* command)
3608 char* p= command->first_argument;
3610 while (*p && charset_info->isspace(*p))
3615 die(
"Can't set empty delimiter");
3618 strncpy(delimiter, p,
sizeof(delimiter) - 1);
3619 delimiter_length= strlen(delimiter);
3621 command->last_argument= p + delimiter_length;
3625 bool match_delimiter(
int c,
const char *delim, uint32_t length)
3628 char tmp[MAX_DELIMITER_LENGTH];
3633 for (i= 1; i < length &&
3634 (c= my_getc(cur_file->file)) == *(delim + i);
3644 my_ungetc(tmp[--i]);
3649 static bool end_of_query(
int c)
3651 return match_delimiter(c, delimiter, delimiter_length);
3680 static int my_strnncoll_simple(
const charset_info_st *
const cs,
const unsigned char *s,
size_t slen,
3681 const unsigned char *t,
size_t tlen,
3684 size_t len = ( slen > tlen ) ? tlen : slen;
3685 unsigned char *map= cs->sort_order;
3686 if (t_is_prefix && slen > tlen)
3690 if (map[*s++] != map[*t++])
3691 return ((
int) map[s[-1]] - (int) map[t[-1]]);
3697 return slen > tlen ? 1 : slen < tlen ? -1 : 0 ;
3700 static int read_line(
char *buf,
int size)
3702 char c, last_quote= 0;
3703 char *p= buf, *buf_end= buf + size - 1;
3705 enum {R_NORMAL, R_Q, R_SLASH_IN_Q,
3706 R_COMMENT, R_LINE_START} state= R_LINE_START;
3709 start_lineno= cur_file->lineno;
3710 for (; p < buf_end ;)
3713 c= my_getc(cur_file->file);
3714 if (feof(cur_file->file))
3717 if (cur_file->file != stdin)
3719 fclose(cur_file->file);
3722 free((
unsigned char*) cur_file->file_name);
3723 cur_file->file_name= 0;
3724 if (cur_file == file_stack.data())
3729 if (cur_block != block_stack)
3730 die(
"Missing end of block");
3736 start_lineno= cur_file->lineno;
3746 if (p != buf && *(p-1) ==
'\r')
3752 if (end_of_query(c))
3757 else if ((c ==
'{' &&
3758 (!my_strnncoll_simple(charset_info, (
const unsigned char*)
"while", 5,
3759 (
unsigned char*) buf, min((ptrdiff_t)5, p - buf), 0) ||
3760 !my_strnncoll_simple(charset_info, (
const unsigned char*)
"if", 2,
3761 (
unsigned char*) buf, min((ptrdiff_t)2, p - buf), 0))))
3768 else if (c ==
'\'' || c ==
'"' || c ==
'`')
3785 if (c ==
'#' || c ==
'-')
3790 else if (charset_info->isspace(c))
3796 start_lineno= cur_file->lineno;
3800 else if (end_of_query(c))
3812 else if (c ==
'\'' || c ==
'"' || c ==
'`')
3822 if (c == last_quote)
3825 state= R_SLASH_IN_Q;
3838 int charlen = my_mbcharlen(charset_info, c);
3841 if ((charlen > 1) && (p + charlen) <= buf_end)
3848 for (i= 1; i < charlen; i++)
3850 if (feof(cur_file->file))
3852 c= my_getc(cur_file->file);
3855 if (! my_ismbchar(charset_info, mb_start, p))
3859 while (p > mb_start)
3867 die(
"The input buffer is too small for this query.x\n" \
3868 "check your query or increase MAX_QUERY and recompile");
3884 static void convert_to_format_v1(
char* query)
3886 int last_c_was_quote= 0;
3887 char *p= query, *to= query;
3888 char *end= strchr(query,
'\0');
3893 if (*p ==
'\n' && !last_c_was_quote)
3898 while (*p && charset_info->isspace(*p))
3901 last_c_was_quote= 0;
3903 else if (*p ==
'\'' || *p ==
'"' || *p ==
'`')
3909 while (*p && *p != last_c)
3914 last_c_was_quote= 1;
3919 last_c_was_quote= 0;
3931 static void scan_command_for_warnings(st_command* command)
3933 const char *ptr= command->query;
3941 if (ptr[0] ==
'\n' &&
3942 ptr[1] && ptr[1] ==
'-' &&
3943 ptr[2] && ptr[2] ==
'-' &&
3948 char *end, *start= (
char*)ptr+3;
3950 while (*start && charset_info->isspace(*start))
3954 while (*end && !charset_info->isspace(*end))
3958 type= command_typelib.find_type(start, TYPELIB::e_default);
3960 warning_msg(
"Embedded drizzletest command '--%s' detected in query '%s' was this intentional? ", start, command->query);
3973 static void check_eol_junk_line(
const char *line)
3975 const char *p= line;
3978 if (*p && !strncmp(p, delimiter, delimiter_length))
3979 die(
"Extra delimiter \"%s\" found", delimiter);
3982 if (*p && *p !=
'#')
3985 die(
"Missing delimiter");
3986 die(
"End of line junk detected: \"%s\"", p);
3991 static void check_eol_junk(
const char *eol)
3996 while (*p && (charset_info->isspace(*p) || *p ==
'#' || *p ==
'\n'))
3999 if (*p && *p ==
'#')
4002 while (*p && *p !=
'\n')
4007 if (*p && *p ==
'\n')
4008 check_eol_junk_line(p);
4014 check_eol_junk_line(p);
4036 #define MAX_QUERY (768*1024*2)
4037 static char read_command_buf[MAX_QUERY];
4039 static int read_command(st_command** command_ptr)
4041 char *p= read_command_buf;
4042 st_command* command;
4045 if (parser.current_line < parser.read_lines)
4047 *command_ptr= q_lines[parser.current_line];
4050 *command_ptr= command=
new st_command;
4051 q_lines.push_back(command);
4052 command->type= Q_UNKNOWN;
4054 read_command_buf[0]= 0;
4055 if (read_line(read_command_buf,
sizeof(read_command_buf)))
4057 check_eol_junk(read_command_buf);
4061 convert_to_format_v1(read_command_buf);
4065 command->type= Q_COMMENT;
4067 else if (p[0] ==
'-' && p[1] ==
'-')
4069 command->type= Q_COMMENT_WITH_COMMAND;
4074 while (*p && charset_info->isspace(*p))
4077 command->query_buf= command->query= strdup(p);
4081 while (*p && !charset_info->isspace(*p) && *p !=
'(')
4083 command->first_word_len= (uint32_t) (p - command->query);
4086 while (*p && charset_info->isspace(*p))
4088 command->first_argument= p;
4090 command->end= strchr(command->query,
'\0');
4091 command->query_len= (command->end - command->query);
4092 parser.read_lines++;
4108 void str_to_file2(
const char *fname,
const char *str,
int size,
bool append)
4110 char buff[FN_REFLEN];
4111 if (!internal::test_if_hard_path(fname))
4113 snprintf(buff,
sizeof(buff),
"%s%s",opt_basedir.c_str(),fname);
4116 internal::fn_format(buff, fname,
"",
"", MY_UNPACK_FILENAME);
4118 int flags= O_WRONLY | O_CREAT;
4121 int fd= internal::my_open(buff, flags, MYF(MY_WME | MY_FFNF));
4123 die(
"Could not open '%s' for writing: errno = %d", buff, errno);
4124 if (append && lseek(fd, 0, SEEK_END) == MY_FILEPOS_ERROR)
4125 die(
"Could not find end of file '%s': errno = %d", buff, errno);
4126 if (internal::my_write(fd, (
unsigned char*)str, size, MYF(MY_WME|MY_FNABP)))
4127 die(
"write failed");
4128 internal::my_close(fd, MYF(0));
4141 void str_to_file(
const char *fname,
const char *str,
int size)
4143 str_to_file2(fname, str, size,
false);
4147 void dump_result_to_log_file(
const char *buf,
int size)
4149 char log_file[FN_REFLEN];
4150 str_to_file(internal::fn_format(log_file, result_file_name.c_str(), opt_logdir.c_str(),
".log",
4151 ! opt_logdir.empty() ? MY_REPLACE_DIR | MY_REPLACE_EXT :
4154 fprintf(stderr,
"\nMore results from queries before failure can be found in %s\n", log_file);
4157 void dump_progress()
4159 char progress_file[FN_REFLEN];
4160 str_to_file(internal::fn_format(progress_file, result_file_name.c_str(),
4161 opt_logdir.c_str(),
".progress",
4162 ! opt_logdir.empty() ? MY_REPLACE_DIR | MY_REPLACE_EXT :
4164 ds_progress.c_str(), ds_progress.length());
4167 void dump_warning_messages()
4169 char warn_file[FN_REFLEN];
4171 str_to_file(internal::fn_format(warn_file, result_file_name.c_str(), opt_logdir.c_str(),
".warnings",
4172 ! opt_logdir.empty() ? MY_REPLACE_DIR | MY_REPLACE_EXT :
4174 ds_warning_messages.c_str(), ds_warning_messages.length());
4182 static void append_field(
string *ds, uint32_t col_idx, drizzle_column_st *column,
4183 const char* val, uint64_t len,
bool is_null)
4185 if (col_idx < max_replace_column && replace_column[col_idx])
4187 val= replace_column[col_idx];
4196 if (!display_result_vertically)
4200 replace_append_mem(*ds, val, (
int)len);
4204 ds->append(drizzle_column_name(column));
4206 replace_append_mem(*ds, val, (
int)len);
4217 static void append_result(
string *ds, drizzle::result_c& res)
4219 uint32_t num_fields= res.column_count();
4220 while (drizzle_row_t row = res.row_next())
4222 size_t* lengths = res.row_field_sizes();
4224 for (uint32_t i = 0; i < num_fields; i++)
4226 drizzle_column_st* column= res.column_next();
4227 if (row[i] && drizzle_column_type(column) == DRIZZLE_COLUMN_TYPE_TINY)
4229 if (boost::lexical_cast<uint32_t>(row[i]))
4231 if (drizzle_column_flags(column) & DRIZZLE_COLUMN_FLAGS_UNSIGNED)
4233 append_field(ds, i, column,
"YES", 3,
false);
4237 append_field(ds, i, column,
"TRUE", 4,
false);
4242 if (drizzle_column_flags(column) & DRIZZLE_COLUMN_FLAGS_UNSIGNED)
4244 append_field(ds, i, column,
"NO", 2,
false);
4248 append_field(ds, i, column,
"FALSE", 5,
false);
4254 append_field(ds, i, column, (
const char*)row[i], lengths[i], !row[i]);
4257 if (!display_result_vertically)
4267 static void append_metadata(
string& ds, drizzle::result_c& res)
4269 ds +=
"Catalog\tDatabase\tTable\tTable_alias\tColumn\tColumn_alias\tType\tLength\tMax length\tIs_null\tFlags\tDecimals\tCharsetnr\n";
4271 while (drizzle_column_st* column= res.column_next())
4273 ds += drizzle_column_catalog(column);
4275 ds += drizzle_column_db(column);
4277 ds += drizzle_column_orig_table(column);
4279 ds += drizzle_column_table(column);
4281 ds += drizzle_column_orig_name(column);
4283 ds += drizzle_column_name(column);
4285 replace_append_uint(ds, drizzle_column_type_drizzle(column));
4287 replace_append_uint(ds, drizzle_column_size(column));
4289 replace_append_uint(ds, drizzle_column_type(column) == DRIZZLE_COLUMN_TYPE_TINY ? 1 : drizzle_column_max_size(column));
4291 ds += drizzle_column_flags(column) & DRIZZLE_COLUMN_FLAGS_NOT_NULL ?
"N" :
"Y";
4293 replace_append_uint(ds, drizzle_column_flags(column));
4295 replace_append_uint(ds, drizzle_column_decimals(column));
4297 replace_append_uint(ds, drizzle_column_charset(column));
4307 static void append_info(
string *ds, uint64_t affected_rows,
4311 buf <<
"affected rows: " << affected_rows << endl;
4312 ds->append(buf.str());
4313 if (info && strcmp(info,
""))
4315 ds->append(
"info: ");
4317 ds->append(
"\n", 1);
4326 static void append_table_headings(
string& ds, drizzle::result_c& res)
4328 uint32_t col_idx= 0;
4330 while (drizzle_column_st* column= res.column_next())
4334 replace_append(&ds, drizzle_column_name(column));
4347 static int append_warnings(
string& ds, drizzle::connection_c& con, drizzle::result_c& res)
4349 uint32_t count= drizzle_result_warning_count(res);
4353 drizzle::result_c warn_res;
4354 dt_query(con, warn_res,
"show warnings");
4355 append_result(&ds, warn_res);
4374 st_command* command,
4375 int flags,
char *query,
int query_len,
4376 string *ds,
string& ds_warnings)
4378 drizzle_return_t ret;
4379 drizzle_con_st *con= cn;
4382 drizzle_con_add_options(con, DRIZZLE_CON_NO_RESULT_READ);
4384 drizzle::result_c res;
4385 if (flags & QUERY_SEND_FLAG)
4391 (void) drizzle_query(con, res, query, query_len, &ret);
4392 if (ret != DRIZZLE_RETURN_OK)
4394 if (ret == DRIZZLE_RETURN_ERROR_CODE ||
4395 ret == DRIZZLE_RETURN_HANDSHAKE_FAILED)
4397 err= res.error_code();
4398 handle_error(command, err, res.error(), drizzle_result_sqlstate(res), ds);
4402 handle_error(command, ret, drizzle_con_error(con),
"", ds);
4408 if (!(flags & QUERY_REAP_FLAG))
4415 if (drizzle_result_read(con, res, &ret) == NULL ||
4416 ret != DRIZZLE_RETURN_OK)
4418 if (ret == DRIZZLE_RETURN_ERROR_CODE)
4420 handle_error(command, res.error_code(), res.error(), drizzle_result_sqlstate(res), ds);
4423 handle_error(command, ret, drizzle_con_error(con),
"", ds);
4431 if (res.column_count() && (ret= drizzle_result_buffer(res)) != DRIZZLE_RETURN_OK)
4433 if (ret == DRIZZLE_RETURN_ERROR_CODE)
4435 handle_error(command, res.error_code(), res.error(), drizzle_result_sqlstate(res), ds);
4438 handle_error(command, ret, drizzle_con_error(con),
"", ds);
4443 if (!disable_result_log)
4445 uint64_t affected_rows= 0;
4447 if (res.column_count())
4449 if (display_metadata)
4450 append_metadata(*ds, res);
4452 if (!display_result_vertically)
4453 append_table_headings(*ds, res);
4455 append_result(ds, res);
4463 affected_rows= drizzle_result_affected_rows(res);
4470 if (!disable_warnings)
4472 drizzle_con_remove_options(con, DRIZZLE_CON_NO_RESULT_READ);
4473 if (append_warnings(ds_warnings, cn, res) || not ds_warnings.empty())
4475 ds->append(
"Warnings:\n", 10);
4481 append_info(ds, affected_rows, drizzle_result_info(res));
4487 handle_no_error(command);
4496 drizzle_con_remove_options(con, DRIZZLE_CON_NO_RESULT_READ);
4517 void handle_error(st_command* command,
4518 unsigned int err_errno,
const char *err_error,
4519 const char *err_sqlstate,
string *ds)
4521 if (! command->require_file.empty())
4528 if (err_errno == DRIZZLE_RETURN_LOST_CONNECTION)
4529 die(
"require query '%s' failed: %d: %s", command->query, err_errno, err_error);
4532 abort_not_supported_test(
"Query '%s' failed, required functionality not supported", command->query);
4535 if (command->abort_on_error)
4536 die(
"query '%s' failed: %d: %s", command->query, err_errno, err_error);
4539 for (; i < command->expected_errors.count; i++)
4541 if (((command->expected_errors.err[i].type == ERR_ERRNO) &&
4542 (command->expected_errors.err[i].code.errnum == err_errno)) ||
4543 ((command->expected_errors.err[i].type == ERR_SQLSTATE) &&
4544 (strncmp(command->expected_errors.err[i].code.sqlstate,
4545 err_sqlstate, DRIZZLE_MAX_SQLSTATE_SIZE) == 0)))
4547 if (!disable_result_log)
4549 if (command->expected_errors.count == 1)
4552 ds->append(
"ERROR ", 6);
4553 replace_append(ds, err_sqlstate);
4554 ds->append(
": ", 2);
4555 replace_append(ds, err_error);
4559 else if (command->expected_errors.err[0].type == ERR_SQLSTATE ||
4560 (command->expected_errors.err[0].type == ERR_ERRNO &&
4561 command->expected_errors.err[0].code.errnum != 0))
4562 ds->append(
"Got one of the listed errors\n");
4569 if (!disable_result_log)
4571 ds->append(
"ERROR ",6);
4572 replace_append(ds, err_sqlstate);
4573 ds->append(
": ", 2);
4574 replace_append(ds, err_error);
4575 ds->append(
"\n", 1);
4580 if (command->expected_errors.err[0].type == ERR_ERRNO)
4581 die(
"query '%s' failed with wrong errno %d: '%s', instead of %d...",
4582 command->query, err_errno, err_error,
4583 command->expected_errors.err[0].code.errnum);
4585 die(
"query '%s' failed with wrong sqlstate %s: '%s', instead of %s...",
4586 command->query, err_sqlstate, err_error,
4587 command->expected_errors.err[0].code.sqlstate);
4603 void handle_no_error(st_command* command)
4605 if (command->expected_errors.err[0].type == ERR_ERRNO &&
4606 command->expected_errors.err[0].code.errnum != 0)
4609 die(
"query '%s' succeeded - should have failed with errno %d...", command->query, command->expected_errors.err[0].code.errnum);
4611 else if (command->expected_errors.err[0].type == ERR_SQLSTATE &&
4612 strcmp(command->expected_errors.err[0].code.sqlstate,
"00000") != 0)
4615 die(
"query '%s' succeeded - should have failed with sqlstate %s...", command->query, command->expected_errors.err[0].code.sqlstate);
4634 st_command* command,
4643 scan_command_for_warnings(command);
4648 if (command->type == Q_EVAL)
4650 do_eval(&eval_query, command->query, command->end,
false);
4651 query = strdup(eval_query.c_str());
4652 query_len = eval_query.length();
4656 query = command->query;
4657 query_len = strlen(query);
4667 string* ds= command->require_file.empty() ? &ds_res : &ds_result;
4671 if (!disable_query_log && (flags & QUERY_SEND_FLAG))
4673 replace_append_mem(*ds, query, query_len);
4674 ds->append(delimiter, delimiter_length);
4678 string* save_ds= NULL;
4680 if (display_result_sorted)
4696 run_query_normal(cn, command, flags, query, query_len, ds, ds_warnings);
4698 if (display_result_sorted)
4701 append_sorted(*save_ds, ds_sorted);
4705 if (! command->require_file.empty())
4711 check_require(*ds, command->require_file);
4718 static void get_command_type(st_command* command)
4720 if (*command->query ==
'}')
4722 command->type = Q_END_BLOCK;
4726 char save= command->query[command->first_word_len];
4727 command->query[command->first_word_len]= 0;
4728 uint32_t type= command_typelib.find_type(command->query, TYPELIB::e_default);
4729 command->query[command->first_word_len]= save;
4732 command->type=(
enum enum_commands) type;
4738 if (type == Q_QUERY)
4741 command->query= command->first_argument;
4748 if (command->type != Q_COMMENT_WITH_COMMAND)
4751 command->type= Q_QUERY;
4756 command->type= Q_COMMENT;
4757 warning_msg(
"Suspicious command '--%s' detected, was this intentional? " \
4758 "Use # instead of -- to avoid this warning",
4761 if (command->first_word_len &&
4762 strcmp(command->query + command->first_word_len - 1, delimiter) == 0)
4770 save= command->query[command->first_word_len-1];
4771 command->query[command->first_word_len-1]= 0;
4772 if (command_typelib.find_type(command->query, TYPELIB::e_default) > 0)
4773 die(
"Extra delimiter \";\" found");
4774 command->query[command->first_word_len-1]= save;
4781 memcpy(&command->expected_errors, &saved_expected_errors,
sizeof(saved_expected_errors));
4782 command->abort_on_error= (command->expected_errors.count == 0 && abort_on_error);
4796 static void mark_progress(st_command*,
int line)
4798 uint64_t timer= timer_now();
4799 if (!progress_start)
4800 progress_start= timer;
4801 timer-= progress_start;
4805 buf << timer <<
"\t";
4808 buf << line <<
"\t";
4811 buf << cur_file->file_name <<
":";
4814 buf << cur_file->lineno << endl;
4816 ds_progress += buf.str();
4820 static void check_retries(uint32_t in_opt_max_connect_retries)
4822 if (in_opt_max_connect_retries > 10000 || opt_max_connect_retries<1)
4824 cout << N_(
"Error: Invalid Value for opt_max_connect_retries");
4827 opt_max_connect_retries= in_opt_max_connect_retries;
4830 static void check_tail_lines(uint32_t in_opt_tail_lines)
4832 if (in_opt_tail_lines > 10000)
4834 cout << N_(
"Error: Invalid Value for opt_tail_lines");
4837 opt_tail_lines= in_opt_tail_lines;
4840 static void check_sleep(int32_t in_opt_sleep)
4842 if (in_opt_sleep < -1)
4844 cout << N_(
"Error: Invalid Value for opt_sleep");
4847 opt_sleep= in_opt_sleep;
4850 int main(
int argc,
char **argv)
4854 bool q_send_flag= 0, abort_flag= 0;
4855 uint32_t command_executed= 0, last_command_executed= 0;
4860 internal::my_init();
4862 po::options_description commandline_options(
"Options used only in command line");
4863 commandline_options.add_options()
4864 (
"help,?",
"Display this help and exit.")
4865 (
"mark-progress", po::value<bool>(&opt_mark_progress)->default_value(
false)->zero_tokens(),
4866 "Write linenumber and elapsed time to <testname>.progress ")
4867 (
"sleep,T", po::value<int32_t>(&opt_sleep)->default_value(-1)->notifier(&check_sleep),
4868 "Sleep always this many seconds on sleep commands.")
4869 (
"test-file,x", po::value<string>(),
4870 "Read test from/in this file (default stdin).")
4871 (
"timer-file,f", po::value<string>(),
4872 "File where the timing in micro seconds is stored.")
4873 (
"tmpdir,t", po::value<string>(),
4874 "Temporary directory where sockets are put.")
4875 (
"verbose,v", po::value<bool>(&verbose)->default_value(
false),
4877 (
"version,V",
"Output version information and exit.")
4878 (
"no-defaults", po::value<bool>()->default_value(
false)->zero_tokens(),
4879 "Configuration file defaults are not used if no-defaults is set")
4882 po::options_description test_options(
"Options specific to the drizzleimport");
4883 test_options.add_options()
4884 (
"basedir,b", po::value<string>(&opt_basedir)->default_value(
""),
4885 "Basedir for tests.")
4886 (
"character-sets-dir", po::value<string>(&opt_charsets_dir)->default_value(
""),
4887 "Directory where character sets are.")
4888 (
"database,D", po::value<string>(&opt_db)->default_value(
""),
4890 (
"include,i", po::value<string>(&opt_include)->default_value(
""),
4891 "Include SQL before each test case.")
4892 (
"testdir", po::value<string>(&opt_testdir)->default_value(
""),
4893 "Path to use to search for test files")
4894 (
"logdir", po::value<string>(&opt_logdir)->default_value(
""),
4895 "Directory for log files")
4896 (
"max-connect-retries", po::value<uint32_t>(&opt_max_connect_retries)->default_value(500)->notifier(&check_retries),
4897 "Max number of connection attempts when connecting to server")
4898 (
"quiet,s", po::value<bool>(&silent)->default_value(
false)->zero_tokens(),
4899 "Suppress all normal output.")
4900 (
"record,r",
"Record output of test_file into result file.")
4901 (
"result-file,R", po::value<string>(&result_file_name)->default_value(
""),
4902 "Read/Store result from/in this file.")
4903 (
"silent,s", po::value<bool>(&silent)->default_value(
false)->zero_tokens(),
4904 "Suppress all normal output. Synonym for --quiet.")
4905 (
"tail-lines", po::value<uint32_t>(&opt_tail_lines)->default_value(0)->notifier(&check_tail_lines),
4906 "Number of lines of the resul to include in a failure report")
4909 po::options_description client_options(
"Options specific to the client");
4910 client_options.add_options()
4912 (
"host,h", po::value<string>(&opt_host)->default_value(
"localhost"),
4914 (
"password,P", po::value<string>(&password)->default_value(
"PASSWORD_SENTINEL"),
4915 "Password to use when connecting to server.")
4916 (
"port,p", po::value<uint32_t>(&opt_port)->default_value(0),
4917 "Port number to use for connection or 0 for default")
4918 (
"protocol", po::value<string>(&opt_protocol),
4919 "The protocol of connection (mysql or drizzle).")
4920 (
"user,u", po::value<string>(&opt_user)->default_value(
""),
4924 po::positional_options_description p;
4925 p.add(
"database", 1);
4927 po::options_description long_options(
"Allowed Options");
4928 long_options.add(commandline_options).add(test_options).add(client_options);
4930 std::string system_config_dir_test(SYSCONFDIR);
4931 system_config_dir_test +=
"/drizzle/drizzletest.cnf";
4933 std::string system_config_dir_client(SYSCONFDIR);
4934 system_config_dir_client +=
"/drizzle/client.cnf";
4936 std::string user_config_dir((getenv(
"XDG_CONFIG_HOME")? getenv(
"XDG_CONFIG_HOME"):
"~/.config"));
4938 if (user_config_dir.compare(0, 2,
"~/") == 0)
4940 if (
const char *homedir= getenv(
"HOME"))
4941 user_config_dir.replace(0, 1, homedir);
4944 po::variables_map vm;
4947 int style = po::command_line_style::default_style & ~po::command_line_style::allow_guessing;
4949 po::store(po::command_line_parser(argc, argv).options(long_options).
4950 style(style).positional(p).extra_parser(parse_password_arg).run(),
4953 if (! vm[
"no-defaults"].as<bool>())
4955 std::string user_config_dir_test(user_config_dir);
4956 user_config_dir_test +=
"/drizzle/drizzletest.cnf";
4958 std::string user_config_dir_client(user_config_dir);
4959 user_config_dir_client +=
"/drizzle/client.cnf";
4961 ifstream user_test_ifs(user_config_dir_test.c_str());
4962 po::store(parse_config_file(user_test_ifs, test_options), vm);
4964 ifstream user_client_ifs(user_config_dir_client.c_str());
4965 po::store(parse_config_file(user_client_ifs, client_options), vm);
4967 ifstream system_test_ifs(system_config_dir_test.c_str());
4968 store(parse_config_file(system_test_ifs, test_options), vm);
4970 ifstream system_client_ifs(system_config_dir_client.c_str());
4971 po::store(parse_config_file(system_client_ifs, client_options), vm);
4977 memset(&saved_expected_errors, 0,
sizeof(saved_expected_errors));
4980 memset(file_stack.data(), 0,
sizeof(file_stack));
4981 cur_file= file_stack.data();
4984 memset(block_stack, 0,
sizeof(block_stack));
4986 block_stack + (
sizeof(block_stack)/
sizeof(
struct st_block)) - 1;
4987 cur_block= block_stack;
4988 cur_block->ok=
true;
4989 cur_block->cmd= cmd_none;
4991 var_set_string(
"$DRIZZLE_SERVER_VERSION", drizzle_version());
4993 memset(&master_pos, 0,
sizeof(master_pos));
4995 parser.current_line= parser.read_lines= 0;
4996 memset(&var_reg, 0,
sizeof(var_reg));
4998 init_builtin_echo();
5000 ds_res.reserve(65536);
5001 ds_progress.reserve(2048);
5002 ds_warning_messages.reserve(2048);
5005 if (vm.count(
"record"))
5010 if (vm.count(
"test-file"))
5012 string tmp= vm[
"test-file"].as<
string>();
5013 char buff[FN_REFLEN];
5014 if (!internal::test_if_hard_path(tmp.c_str()))
5016 snprintf(buff,
sizeof(buff),
"%s%s",opt_basedir.c_str(),tmp.c_str());
5019 internal::fn_format(buff, tmp.c_str(),
"",
"", MY_UNPACK_FILENAME);
5020 assert(cur_file == file_stack.data() && cur_file->file == 0);
5021 if (!(cur_file->file= fopen(buff,
"r")))
5023 fprintf(stderr, _(
"Could not open '%s' for reading: errno = %d"), buff, errno);
5024 return EXIT_ARGUMENT_INVALID;
5026 cur_file->file_name= strdup(buff);
5027 cur_file->lineno= 1;
5030 if (vm.count(
"timer-file"))
5032 string tmp= vm[
"timer-file"].as<
string>().c_str();
5033 static char buff[FN_REFLEN];
5034 if (!internal::test_if_hard_path(tmp.c_str()))
5036 snprintf(buff,
sizeof(buff),
"%s%s",opt_basedir.c_str(),tmp.c_str());
5039 internal::fn_format(buff, tmp.c_str(),
"",
"", MY_UNPACK_FILENAME);
5044 if (vm.count(
"protocol"))
5046 boost::to_lower(opt_protocol);
5047 if (not opt_protocol.compare(
"mysql"))
5048 use_drizzle_protocol=
false;
5049 else if (not opt_protocol.compare(
"drizzle"))
5050 use_drizzle_protocol=
true;
5053 cout << _(
"Error: Unknown protocol") <<
" '" << opt_protocol <<
"'" << endl;
5058 if (vm.count(
"port"))
5063 if (opt_port > 65535)
5065 fprintf(stderr, _(
"Value supplied for port is not valid.\n"));
5066 exit(EXIT_ARGUMENT_INVALID);
5070 if( vm.count(
"password") )
5072 if (!opt_password.empty())
5073 opt_password.erase();
5074 if (password == PASSWORD_SENTINEL)
5080 opt_password= password;
5081 tty_password=
false;
5089 if (vm.count(
"tmpdir"))
5091 strncpy(TMPDIR, vm[
"tmpdir"].as<string>().c_str(),
sizeof(TMPDIR));
5094 if (vm.count(
"version"))
5096 printf(
"%s Ver %s Distrib %s, for %s-%s (%s)\n",internal::my_progname,MTEST_VERSION,
5097 drizzle_version(),HOST_VENDOR,HOST_OS,HOST_CPU);
5101 if (vm.count(
"help"))
5103 printf(
"%s Ver %s Distrib %s, for %s-%s (%s)\n",internal::my_progname,MTEST_VERSION,
5104 drizzle_version(),HOST_VENDOR,HOST_OS,HOST_CPU);
5105 printf(
"MySQL AB, by Sasha, Matt, Monty & Jani\n");
5106 printf(
"Drizzle version modified by Brian, Jay, Monty Taylor, PatG and Stewart\n");
5107 printf(
"This software comes with ABSOLUTELY NO WARRANTY\n\n");
5108 printf(
"Runs a test against the DRIZZLE server and compares output with a results file.\n\n");
5109 printf(
"Usage: %s [OPTIONS] [database] < test_file\n", internal::my_progname);
5115 opt_pass= client_get_tty_password(NULL);
5118 server_initialized=
true;
5119 if (cur_file == file_stack.data() && cur_file->file == 0)
5121 cur_file->file= stdin;
5122 cur_file->file_name= strdup(
"<stdin>");
5123 cur_file->lineno= 1;
5125 cur_con= safe_connect(
"default", opt_host, opt_user, opt_pass, opt_db, opt_port);
5126 g_connections[
"default"] = cur_con;
5128 fill_global_error_names();
5131 timer_start= timer_now();
5141 var_set_drizzleclient_get_server_version(*cur_con);
5143 if (! opt_include.empty())
5145 open_file(opt_include.c_str());
5148 st_command* command;
5149 while (!read_command(&command) && !abort_flag)
5151 int current_line_inc = 1, processed = 0;
5152 if (command->type == Q_UNKNOWN || command->type == Q_COMMENT_WITH_COMMAND)
5153 get_command_type(command);
5155 if (parsing_disabled &&
5156 command->type != Q_ENABLE_PARSING &&
5157 command->type != Q_DISABLE_PARSING)
5159 command->type= Q_COMMENT;
5160 scan_command_for_warnings(command);
5165 command->last_argument= command->first_argument;
5167 switch (command->type) {
5169 do_connect(command);
5172 select_connection(command);
5176 do_close_connection(command);
break;
5177 case Q_ENABLE_QUERY_LOG: disable_query_log=0;
break;
5178 case Q_DISABLE_QUERY_LOG: disable_query_log=1;
break;
5179 case Q_ENABLE_ABORT_ON_ERROR: abort_on_error=1;
break;
5180 case Q_DISABLE_ABORT_ON_ERROR: abort_on_error=0;
break;
5181 case Q_ENABLE_RESULT_LOG: disable_result_log=0;
break;
5182 case Q_DISABLE_RESULT_LOG: disable_result_log=1;
break;
5183 case Q_ENABLE_WARNINGS: disable_warnings=0;
break;
5184 case Q_DISABLE_WARNINGS: disable_warnings=1;
break;
5185 case Q_ENABLE_INFO: disable_info=0;
break;
5186 case Q_DISABLE_INFO: disable_info=1;
break;
5187 case Q_ENABLE_METADATA: display_metadata=1;
break;
5188 case Q_DISABLE_METADATA: display_metadata=0;
break;
5189 case Q_SOURCE: do_source(command);
break;
5190 case Q_SLEEP: do_sleep(command, 0);
break;
5191 case Q_REAL_SLEEP: do_sleep(command, 1);
break;
5192 case Q_WAIT_FOR_SLAVE_TO_STOP: do_wait_for_slave_to_stop();
break;
5193 case Q_INC: do_modify_var(command, DO_INC);
break;
5194 case Q_DEC: do_modify_var(command, DO_DEC);
break;
5195 case Q_ECHO: do_echo(command); command_executed++;
break;
5196 case Q_SYSTEM: do_system(command);
break;
5197 case Q_REMOVE_FILE: do_remove_file(command);
break;
5198 case Q_MKDIR: do_mkdir(command);
break;
5199 case Q_RMDIR: do_rmdir(command);
break;
5200 case Q_FILE_EXIST: do_file_exist(command);
break;
5201 case Q_WRITE_FILE: do_write_file(command);
break;
5202 case Q_APPEND_FILE: do_append_file(command);
break;
5203 case Q_DIFF_FILES: do_diff_files(command);
break;
5204 case Q_SEND_QUIT: do_send_quit(command);
break;
5205 case Q_CHANGE_USER: do_change_user(command);
break;
5206 case Q_CAT_FILE: do_cat_file(command);
break;
5207 case Q_COPY_FILE: do_copy_file(command);
break;
5208 case Q_CHMOD_FILE: do_chmod_file(command);
break;
5209 case Q_PERL: do_perl(command);
break;
5211 do_delimiter(command);
5213 case Q_DISPLAY_VERTICAL_RESULTS:
5214 display_result_vertically=
true;
5216 case Q_DISPLAY_HORIZONTAL_RESULTS:
5217 display_result_vertically=
false;
5219 case Q_SORTED_RESULT:
5224 display_result_sorted=
true;
5226 case Q_LET: do_let(command);
break;
5228 die(
"'eval_result' command is deprecated");
5230 case Q_QUERY_VERTICAL:
5231 case Q_QUERY_HORIZONTAL:
5232 if (command->query == command->query_buf)
5235 command->query= command->first_argument;
5236 command->first_word_len= 0;
5242 bool old_display_result_vertically= display_result_vertically;
5244 int flags= QUERY_REAP_FLAG | QUERY_SEND_FLAG;
5249 flags= QUERY_SEND_FLAG;
5252 else if (command->type == Q_REAP)
5254 flags= QUERY_REAP_FLAG;
5258 display_result_vertically|= (command->type == Q_QUERY_VERTICAL);
5260 if (! save_file.empty())
5262 command->require_file= save_file;
5265 run_query(*cur_con, command, flags);
5267 command->last_argument= command->end;
5270 display_result_vertically= old_display_result_vertically;
5275 if (!*command->first_argument)
5286 if (command->query == command->query_buf)
5287 command->query= command->first_argument;
5295 run_query(*cur_con, command, QUERY_SEND_FLAG);
5297 command->last_argument= command->end;
5300 do_get_file_name(command, save_file);
5303 do_get_errcodes(command);
5306 do_get_replace(command);
5308 case Q_REPLACE_REGEX:
5309 do_get_replace_regex(command);
5311 case Q_REPLACE_COLUMN:
5312 do_get_replace_column(command);
5315 command->last_argument= command->end;
5319 drizzle::result_c result;
5320 drizzle_return_t ret;
5321 (void) drizzle_ping(*cur_con, result, &ret);
5330 timer_start= timer_now();
5336 case Q_CHARACTER_SET:
5337 do_set_charset(command);
5339 case Q_DISABLE_RECONNECT:
5340 set_reconnect(*cur_con, 0);
5342 case Q_ENABLE_RECONNECT:
5343 set_reconnect(*cur_con, 1);
5345 case Q_DISABLE_PARSING:
5346 if (parsing_disabled == 0)
5347 parsing_disabled= 1;
5349 die(
"Parsing is already disabled");
5351 case Q_ENABLE_PARSING:
5356 if (parsing_disabled == 1)
5357 parsing_disabled= 0;
5359 die(
"Parsing is already enabled");
5363 die(
"%s", command->first_argument);
5370 abort_not_supported_test(
"%s", command->first_argument);
5374 die(
"result, deprecated command");
5385 current_line_inc= 0;
5386 switch (command->type) {
5387 case Q_WHILE: do_block(cmd_while, command);
break;
5388 case Q_IF: do_block(cmd_if, command);
break;
5389 case Q_END_BLOCK: do_done(command);
break;
5390 default: current_line_inc = 1;
break;
5394 check_eol_junk(command->last_argument);
5396 if (command->type != Q_ERROR &&
5397 command->type != Q_COMMENT)
5403 memset(&saved_expected_errors, 0,
sizeof(saved_expected_errors));
5406 if (command_executed != last_command_executed)
5415 display_result_sorted=
false;
5417 last_command_executed= command_executed;
5419 parser.current_line += current_line_inc;
5420 if ( opt_mark_progress )
5421 mark_progress(command, parser.current_line);
5426 if (parsing_disabled)
5427 die(
"Test ended with parsing disabled");
5435 die(
"The test didn't produce any output");
5436 if (result_file_name.empty())
5439 printf(
"%s", ds_res.c_str());
5444 str_to_file(result_file_name.c_str(), ds_res.c_str(), ds_res.length());
5452 check_result(ds_res);
5455 struct stat res_info;
5456 if (not command_executed && not result_file_name.empty() && not stat(result_file_name.c_str(), &res_info))
5465 die(
"No queries executed but result file found!");
5468 if ( opt_mark_progress && ! result_file_name.empty() )
5472 if (not result_file_name.empty() && ds_warning_messages.length())
5473 dump_warning_messages();
5477 cleanup_and_exit(0);
5480 catch(exception &err)
5482 cerr<<err.what()<<endl;
5515 uint64_t timer= timer_now() - timer_start;
5517 str_to_file(timer_file,buf.str().c_str(), buf.str().size() );
5524 uint64_t timer_now()
5526 #if defined(HAVE_GETHRTIME)
5527 return gethrtime()/1000/1000;
5534 while (gettimeofday(&t, NULL) != 0)
5536 newtime= (uint64_t)t.tv_sec * 1000000 + t.tv_usec;
5537 return newtime/1000;
5550 void do_get_replace_column(st_command* command)
5552 char *from= command->first_argument;
5556 free_replace_column();
5558 die(
"Missing argument in %s", command->query);
5561 start= buff= (
char *)malloc(strlen(from)+1);
5564 uint32_t column_number;
5566 char *to= get_string(&buff, &from, command);
5567 if (!(column_number= atoi(to)) || column_number > MAX_COLUMNS)
5568 die(
"Wrong column number to replace_column in '%s'", command->query);
5570 die(
"Wrong number of arguments to replace_column in '%s'", command->query);
5571 to= get_string(&buff, &from, command);
5572 free(replace_column[column_number-1]);
5573 replace_column[column_number-1]= strdup(to);
5574 set_if_bigger(max_replace_column, column_number);
5577 command->last_argument= command->end;
5581 void free_replace_column()
5583 for (uint32_t i= 0; i < max_replace_column; i++)
5585 free(replace_column[i]);
5586 replace_column[i]= 0;
5588 max_replace_column= 0;
5603 int insert(
char* name);
5607 memset(
this, 0,
sizeof(*
this));
5613 uint32_t array_allocs;
5616 uint32_t max_length;
5620 struct st_replace *init_replace(
const char **from,
const char **to, uint32_t count,
5621 char *word_end_chars);
5623 void replace_strings_append(
struct st_replace *rep,
string& ds,
const char *from,
int len);
5636 POINTER_ARRAY::~POINTER_ARRAY()
5641 free((
char*) typelib.type_names);
5642 typelib.type_names=0;
5646 void do_get_replace(st_command* command)
5648 char *from= command->first_argument;
5650 die(
"Missing argument in %s", command->query);
5653 char* start= (
char*)malloc(strlen(from) + 1);
5657 char *to= get_string(&buff, &from, command);
5659 die(
"Wrong number of arguments to replace_result in '%s'", command->query);
5660 from_array.insert(to);
5661 to= get_string(&buff, &from, command);
5662 to_array.insert(to);
5664 char word_end_chars[256];
5665 char* pos= word_end_chars;
5666 for (
int i= 1; i < 256; i++)
5668 if (charset_info->isspace(i))
5672 if (!(glob_replace= init_replace(from_array.typelib.type_names,
5673 to_array.typelib.type_names,
5674 from_array.typelib.count,
5676 die(
"Can't initialize replace from '%s'", command->query);
5678 command->last_argument= command->end;
5697 char *replace_string;
5703 void replace_strings_append(
REPLACE *rep,
string& ds,
const char *str,
int len)
5706 const char* start= str;
5707 const char* from= str;
5713 while (!rep_pos->found)
5714 rep_pos= rep_pos->next[(
unsigned char) *from++];
5720 ds.append(start, from - start - 1);
5725 ds.append(start, (from - rep_str->to_offset) - start);
5728 ds.append(rep_str->replace_string, strlen(rep_str->replace_string));
5730 if (!*(from-=rep_str->from_offset) && rep_pos->found != 2)
5733 assert(from <= str+len);
5760 int multi_reg_replace(
char* val);
5769 typedef vector<st_regex> regex_arr_t;
5776 boost::array<char, 8 << 10> buf0_;
5777 boost::array<char, 8 << 10> buf1_;
5778 regex_arr_t regex_arr;
5781 boost::scoped_ptr<st_replace_regex> glob_replace_regex;
5783 int reg_replace(
char** buf_p,
int* buf_len_p,
char *pattern,
char *replace,
5784 char *
string,
int icase,
int global);
5793 #define PARSE_REGEX_ARG \
5794 while (p < expr_end) \
5799 if (last_c == '\\') \
5823 st_replace_regex::st_replace_regex(
char* expr)
5825 uint32_t expr_len= strlen(expr);
5829 char* buf=
new char[expr_len];
5830 char* expr_end= expr + expr_len;
5835 while (p < expr_end)
5837 memset(®, 0,
sizeof(reg));
5839 while (p < expr_end)
5846 if (p == expr_end || ++p == expr_end)
5848 if (!regex_arr.empty())
5859 if (p == expr_end || ++p == expr_end)
5875 if (p < expr_end && *p ==
'i')
5882 if (p < expr_end && *p ==
'g')
5887 regex_arr.push_back(reg);
5889 odd_buf_len= even_buf_len= buf0_.size();
5890 even_buf= buf0_.data();
5891 odd_buf= buf1_.data();
5897 die(
"Error parsing replace_regex \"%s\"", expr);
5919 int st_replace_regex::multi_reg_replace(
char* val)
5922 char* out_buf= even_buf;
5923 int* buf_len_p= &even_buf_len;
5927 BOOST_FOREACH(regex_arr_t::const_reference i, regex_arr)
5929 char* save_out_buf= out_buf;
5930 if (!reg_replace(&out_buf, buf_len_p, i.pattern, i.replace,
5931 in_buf, i.icase, i.global))
5934 if (save_out_buf != out_buf)
5936 if (save_out_buf == even_buf)
5944 std::swap(in_buf, out_buf);
5945 buf_len_p= (out_buf == even_buf) ? &even_buf_len : &odd_buf_len;
5960 void do_get_replace_regex(st_command* command)
5962 char *expr= command->first_argument;
5964 command->last_argument= command->end;
5979 int reg_replace(
char** buf_p,
int* buf_len_p,
char *pattern,
5980 char *replace,
char *
in_string,
int icase,
int global)
5982 const char *error= NULL;
5985 pcre *re= pcre_compile(pattern,
5986 icase ? PCRE_CASELESS | PCRE_MULTILINE : PCRE_MULTILINE,
5987 &error, &erroffset, NULL);
5994 int rc= pcre_exec(re, NULL, in_string, (
int)strlen(in_string),
6002 char *substring_to_replace= in_string + ovector[0];
6003 int substring_length= ovector[1] - ovector[0];
6004 *buf_len_p= strlen(in_string) - substring_length + strlen(replace);
6005 char* new_buf= (
char*)malloc(*buf_len_p+1);
6007 memset(new_buf, 0, *buf_len_p+1);
6008 strncpy(new_buf, in_string, substring_to_replace-in_string);
6009 strncpy(new_buf+(substring_to_replace-in_string), replace, strlen(replace));
6010 strncpy(new_buf+(substring_to_replace-in_string)+strlen(replace),
6011 substring_to_replace + substring_length,
6014 - (substring_to_replace-in_string));
6023 string subject(in_string);
6024 size_t replace_length= strlen(replace);
6025 size_t length_of_replacement= strlen(replace);
6026 size_t current_position= 0;
6031 rc= pcre_exec(re, NULL, subject.c_str(), subject.length(),
6032 current_position, 0, ovector, 3);
6038 current_position=
static_cast<size_t>(ovector[0]);
6039 replace_length=
static_cast<size_t>(ovector[1] - ovector[0]);
6040 subject.replace(current_position, replace_length, replace, length_of_replacement);
6041 current_position= current_position + length_of_replacement;
6044 char* new_buf = (
char*) malloc(subject.length() + 1);
6045 memset(new_buf, 0, subject.length() + 1);
6046 strncpy(new_buf, subject.c_str(), subject.length());
6047 *buf_len_p= subject.length() + 1;
6057 #define WORD_BIT (8*sizeof(uint32_t))
6060 #define SET_MALLOC_HUNC 64
6061 #define LAST_CHAR_CODE 259
6066 void internal_set_bit(uint32_t bit);
6067 void internal_clear_bit(uint32_t bit);
6068 void or_bits(
const REP_SET *from);
6069 void copy_bits(
const REP_SET *from);
6070 int cmp_bits(
const REP_SET *set2)
const;
6071 int get_next_bit(uint32_t lastpos)
const;
6074 short next[LAST_CHAR_CODE];
6077 uint32_t table_offset;
6078 uint32_t size_of_bits;
6084 int find_set(
const REP_SET *find);
6085 void free_last_set();
6087 void make_sets_invisible();
6092 uint32_t size_of_bits;
6094 uint32_t *bit_buffer;
6099 uint32_t table_offset;
6106 uint32_t table_offset;
6110 void init_sets(
REP_SETS *sets, uint32_t states);
6112 int find_found(
FOUND_SET *found_set, uint32_t table_offset,
int found_offset);
6114 static uint32_t found_sets= 0;
6116 static uint32_t replace_len(
const char *str)
6121 if (str[0] ==
'\\' && str[1])
6131 static bool start_at_word(
const char *pos)
6133 return (!memcmp(pos,
"\\b",2) && pos[2]) || !memcmp(pos,
"\\^", 2);
6136 static bool end_of_word(
const char *pos)
6138 const char *end= strchr(pos,
'\0');
6139 return (end > pos+2 && !memcmp(end-2,
"\\b", 2)) || (end >= pos+2 && !memcmp(end-2,
"\\$",2));
6144 REPLACE *init_replace(
const char **from,
const char **to, uint32_t count,
char *word_end_chars)
6146 const int SPACE_CHAR= 256;
6147 const int START_OF_LINE= 257;
6148 const int END_OF_LINE= 258;
6150 uint32_t i,j,states,set_nr,len,result_len,max_length,found_end,bits_set,bit_nr;
6151 int used_sets,chr,default_state;
6152 char used_chars[LAST_CHAR_CODE],is_word_end[256];
6153 char *to_pos, **to_array;
6156 for (i=result_len=max_length=0 , states=2; i < count; i++)
6158 len=replace_len(from[i]);
6165 result_len+=(uint32_t) strlen(to[i])+1;
6166 if (len > max_length)
6169 memset(is_word_end, 0,
sizeof(is_word_end));
6170 for (i=0; word_end_chars[i]; i++)
6171 is_word_end[(
unsigned char) word_end_chars[i]]=1;
6174 REP_SET *set,*start_states,*word_states,*new_set;
6176 init_sets(&sets, states);
6178 vector<FOUND_SET> found_set(max_length * count);
6179 make_new_set(&sets);
6180 sets.make_sets_invisible();
6182 word_states=make_new_set(&sets);
6183 start_states=make_new_set(&sets);
6184 vector<FOLLOWS> follow(states + 2);
6185 FOLLOWS *follow_ptr= &follow[1];
6187 for (i=0, states=1; i < count; i++)
6189 if (from[i][0] ==
'\\' && from[i][1] ==
'^')
6191 start_states->internal_set_bit(states + 1);
6194 start_states->table_offset=i;
6195 start_states->found_offset=1;
6198 else if (from[i][0] ==
'\\' && from[i][1] ==
'$')
6200 start_states->internal_set_bit(states);
6201 word_states->internal_set_bit(states);
6202 if (!from[i][2] && start_states->table_offset == UINT32_MAX)
6204 start_states->table_offset=i;
6205 start_states->found_offset=0;
6210 word_states->internal_set_bit(states);
6211 if (from[i][0] ==
'\\' && (from[i][1] ==
'b' && from[i][2]))
6212 start_states->internal_set_bit(states + 1);
6214 start_states->internal_set_bit(states);
6217 for (pos= from[i], len=0; *pos; pos++)
6219 if (*pos ==
'\\' && *(pos+1))
6224 follow_ptr->chr = SPACE_CHAR;
6227 follow_ptr->chr = START_OF_LINE;
6230 follow_ptr->chr = END_OF_LINE;
6233 follow_ptr->chr =
'\r';
6236 follow_ptr->chr =
'\t';
6239 follow_ptr->chr =
'\v';
6242 follow_ptr->chr = (
unsigned char) *pos;
6247 follow_ptr->chr= (
unsigned char) *pos;
6248 follow_ptr->table_offset=i;
6249 follow_ptr->len= ++len;
6253 follow_ptr->table_offset=i;
6254 follow_ptr->len=len;
6256 states+=(uint32_t) len+1;
6260 for (set_nr=0; set_nr < sets.count; set_nr++)
6262 set=sets.set+set_nr;
6267 for (i= UINT32_MAX; (i= set->get_next_bit(i));)
6269 if (!follow[i].chr && !default_state)
6270 default_state= find_found(&found_set.front(), set->table_offset, set->found_offset+1);
6272 sets.set[used_sets].copy_bits(set);
6274 sets.set[used_sets].or_bits(sets.set);
6277 memset(used_chars, 0,
sizeof(used_chars));
6278 for (i= UINT32_MAX; (i= sets.set[used_sets].get_next_bit(i));)
6280 used_chars[follow[i].chr]=1;
6281 if ((follow[i].chr == SPACE_CHAR && !follow[i+1].chr &&
6282 follow[i].len > 1) || follow[i].chr == END_OF_LINE)
6287 if (used_chars[SPACE_CHAR])
6288 for (
const char *pos= word_end_chars; *pos; pos++)
6289 used_chars[(
int) (
unsigned char) *pos] = 1;
6292 for (chr= 0; chr < 256; chr++)
6294 if (! used_chars[chr])
6295 set->next[chr]= chr ? default_state : -1;
6298 new_set=make_new_set(&sets);
6299 set=sets.set+set_nr;
6300 new_set->table_offset=set->table_offset;
6301 new_set->found_len=set->found_len;
6302 new_set->found_offset=set->found_offset+1;
6305 for (i= UINT32_MAX; (i= sets.set[used_sets].get_next_bit(i));)
6307 if (!follow[i].chr || follow[i].chr == chr ||
6308 (follow[i].chr == SPACE_CHAR &&
6309 (is_word_end[chr] ||
6310 (!chr && follow[i].len > 1 && ! follow[i+1].chr))) ||
6311 (follow[i].chr == END_OF_LINE && ! chr))
6313 if ((! chr || (follow[i].chr && !follow[i+1].chr)) &&
6314 follow[i].len > found_end)
6315 found_end=follow[i].len;
6316 if (chr && follow[i].chr)
6317 new_set->internal_set_bit(i + 1);
6319 new_set->internal_set_bit(i);
6324 new_set->found_len=0;
6326 for (i= UINT32_MAX; (i= new_set->get_next_bit(i));)
6328 if ((follow[i].chr == SPACE_CHAR ||
6329 follow[i].chr == END_OF_LINE) && ! chr)
6333 if (follow[bit_nr-1].len < found_end ||
6334 (new_set->found_len &&
6335 (chr == 0 || !follow[bit_nr].chr)))
6336 new_set->internal_clear_bit(i);
6339 if (chr == 0 || !follow[bit_nr].chr)
6341 new_set->table_offset=follow[bit_nr].table_offset;
6342 if (chr || (follow[i].chr == SPACE_CHAR ||
6343 follow[i].chr == END_OF_LINE))
6344 new_set->found_offset=found_end;
6345 new_set->found_len=found_end;
6352 set->next[chr] = find_found(&found_set.front(), new_set->table_offset, new_set->found_offset);
6353 sets.free_last_set();
6356 set->next[chr] = sets.find_set(new_set);
6359 set->next[chr] = sets.find_set(new_set);
6367 +
sizeof(
REPLACE_STRING) * (found_sets + 1) +
sizeof(
char*) * count + result_len);
6369 memset(replace, 0,
sizeof(
REPLACE)*(sets.count)+
6371 sizeof(
char *)*count+result_len);
6373 to_array= (
char **) (rep_str+found_sets+1);
6374 to_pos=(
char *) (to_array+count);
6375 for (i=0; i < count; i++)
6378 to_pos=strcpy(to_pos,to[i])+strlen(to[i])+1;
6381 rep_str[0].replace_string=0;
6382 for (i=1; i <= found_sets; i++)
6384 const char *pos= from[found_set[i-1].table_offset];
6385 rep_str[i].found= !memcmp(pos,
"\\^", 3) ? 2 : 1;
6386 rep_str[i].replace_string= to_array[found_set[i-1].table_offset];
6387 rep_str[i].to_offset= found_set[i-1].found_offset-start_at_word(pos);
6388 rep_str[i].from_offset= found_set[i-1].found_offset-replace_len(pos) + end_of_word(pos);
6390 for (i=0; i < sets.count; i++)
6392 for (j=0; j < 256; j++)
6393 if (sets.set[i].next[j] >= 0)
6394 replace[i].next[j]=replace+sets.set[i].next[j];
6396 replace[i].next[j]=(
REPLACE*) (rep_str+(-sets.set[i].next[j]-1));
6404 void init_sets(
REP_SETS *sets,uint32_t states)
6406 memset(sets, 0,
sizeof(*sets));
6407 sets->size_of_bits=((states+7)/8);
6408 sets->set_buffer=(
REP_SET*) malloc(
sizeof(
REP_SET) * SET_MALLOC_HUNC);
6409 sets->bit_buffer=(uint*) malloc(
sizeof(uint32_t) * sets->size_of_bits * SET_MALLOC_HUNC);
6414 void REP_SETS::make_sets_invisible()
6427 set=sets->set+ sets->count++;
6428 memset(set->bits, 0,
sizeof(uint32_t)*sets->size_of_bits);
6429 memset(&set->next[0], 0,
sizeof(set->next[0])*LAST_CHAR_CODE);
6430 set->found_offset=0;
6432 set->table_offset= UINT32_MAX;
6433 set->size_of_bits=sets->size_of_bits;
6436 uint32_t count= sets->count + sets->invisible + SET_MALLOC_HUNC;
6437 set= (
REP_SET*) realloc((
unsigned char*) sets->set_buffer,
sizeof(
REP_SET)*count);
6438 sets->set_buffer=set;
6439 sets->set=set+sets->invisible;
6440 uint32_t* bit_buffer= (uint*) realloc((
unsigned char*) sets->bit_buffer, (
sizeof(uint32_t)*sets->size_of_bits)*count);
6441 sets->bit_buffer=bit_buffer;
6442 for (uint32_t i= 0; i < count; i++)
6444 sets->set_buffer[i].bits=bit_buffer;
6445 bit_buffer+=sets->size_of_bits;
6447 sets->extra=SET_MALLOC_HUNC;
6448 return make_new_set(sets);
6451 void REP_SETS::free_last_set()
6457 void REP_SETS::free_sets()
6463 void REP_SET::internal_set_bit(uint32_t bit)
6465 bits[bit / WORD_BIT] |= 1 << (bit % WORD_BIT);
6468 void REP_SET::internal_clear_bit(uint32_t bit)
6470 bits[bit / WORD_BIT] &= ~ (1 << (bit % WORD_BIT));
6474 void REP_SET::or_bits(
const REP_SET *from)
6476 for (uint32_t i= 0; i < size_of_bits; i++)
6477 bits[i]|=from->bits[i];
6480 void REP_SET::copy_bits(
const REP_SET *from)
6482 memcpy(bits, from->bits,
sizeof(uint32_t) * size_of_bits);
6485 int REP_SET::cmp_bits(
const REP_SET *set2)
const
6487 return memcmp(bits, set2->bits,
sizeof(uint32_t) * size_of_bits);
6492 int REP_SET::get_next_bit(uint32_t lastpos)
const
6494 uint32_t *start= bits + ((lastpos+1) / WORD_BIT);
6495 uint32_t *end= bits + size_of_bits;
6496 uint32_t bits0= start[0] & ~((1 << ((lastpos+1) % WORD_BIT)) -1);
6498 while (!bits0 && ++start < end)
6502 uint32_t pos= (start - bits) * WORD_BIT;
6503 while (!(bits0 & 1))
6515 int REP_SETS::find_set(
const REP_SET *find)
6518 for (; i < count - 1; i++)
6520 if (!set[i].cmp_bits(find))
6536 int find_found(
FOUND_SET *found_set, uint32_t table_offset,
int found_offset)
6539 for (; i < found_sets; i++)
6541 if (found_set[i].table_offset == table_offset &&
6542 found_set[i].found_offset == found_offset)
6545 found_set[i].table_offset= table_offset;
6546 found_set[i].found_offset= found_offset;
6555 #define PC_MALLOC 256
6556 #define PS_MALLOC 512
6558 static int insert_pointer_name(
POINTER_ARRAY* pa,
char* name)
6560 uint32_t i,length,old_count;
6561 unsigned char *new_pos;
6562 const char **new_array;
6565 if (! pa->typelib.count)
6567 pa->typelib.type_names=(
const char **)
6568 malloc(((PC_MALLOC-MALLOC_OVERHEAD)/
6569 (
sizeof(
char *)+
sizeof(*pa->flag))*
6570 (
sizeof(
char *)+
sizeof(*pa->flag))));
6571 pa->str= (
unsigned char*) malloc(PS_MALLOC-MALLOC_OVERHEAD);
6572 pa->max_count=(PC_MALLOC-MALLOC_OVERHEAD)/(
sizeof(
unsigned char*)+
6574 pa->flag= (uint8_t*) (pa->typelib.type_names+pa->max_count);
6576 pa->max_length=PS_MALLOC-MALLOC_OVERHEAD;
6579 length=(uint32_t) strlen(name)+1;
6580 if (pa->length+length >= pa->max_length)
6582 new_pos= (
unsigned char*)realloc((
unsigned char*)pa->str, (size_t)(pa->max_length+PS_MALLOC));
6583 if (new_pos != pa->str)
6585 ptrdiff_t diff= PTR_BYTE_DIFF(new_pos,pa->str);
6586 for (i=0; i < pa->typelib.count; i++)
6587 pa->typelib.type_names[i]= ADD_TO_PTR(pa->typelib.type_names[i],diff,
6591 pa->max_length+=PS_MALLOC;
6593 if (pa->typelib.count >= pa->max_count-1)
6597 len=(PC_MALLOC*pa->array_allocs - MALLOC_OVERHEAD);
6598 new_array= (
const char **)realloc((
unsigned char*) pa->typelib.type_names,
6600 (
sizeof(
unsigned char*)+
sizeof(*pa->flag))*
6601 (
sizeof(
unsigned char*)+
sizeof(*pa->flag)));
6602 pa->typelib.type_names=new_array;
6603 old_count=pa->max_count;
6604 pa->max_count=len/(
sizeof(
unsigned char*) +
sizeof(*pa->flag));
6605 pa->flag= (uint8_t*) (pa->typelib.type_names+pa->max_count);
6606 memcpy(pa->flag, pa->typelib.type_names+old_count,
6607 old_count*
sizeof(*pa->flag));
6609 pa->flag[pa->typelib.count]=0;
6610 pa->typelib.type_names[pa->typelib.count++]= (
char*) pa->str+pa->length;
6611 pa->typelib.type_names[pa->typelib.count]= NULL;
6612 strcpy((
char*) pa->str+pa->length,name);
6617 int POINTER_ARRAY::insert(
char* name)
6619 return insert_pointer_name(
this, name);
6626 void replace_append_mem(
string& ds,
const char *val,
int len)
6628 char *v= strdup(val);
6630 if (glob_replace_regex && !glob_replace_regex->multi_reg_replace(v))
6632 v= glob_replace_regex->buf_;
6638 replace_strings_append(glob_replace, ds, v, len);
6646 void replace_append(
string *ds,
const char *val)
6648 replace_append_mem(*ds, val, strlen(val));
6652 void replace_append_uint(
string& ds, uint32_t val)
6656 replace_append_mem(ds, buff.str().c_str(), buff.str().size());
6675 void append_sorted(
string& ds,
const string& ds_input)
6677 priority_queue<string, vector<string>, greater<string> > lines;
6679 if (ds_input.empty())
6682 unsigned long eol_pos= ds_input.find_first_of(
'\n', 0);
6683 if (eol_pos == string::npos)
6686 ds.append(ds_input.substr(0, eol_pos+1));
6688 unsigned long start_pos= eol_pos+1;
6693 eol_pos= ds_input.find_first_of(
'\n', start_pos);
6695 lines.push(ds_input.substr(start_pos, eol_pos-start_pos+1));
6696 start_pos= eol_pos+1;
6698 }
while ( eol_pos != string::npos);
6701 while (!lines.empty())
6703 ds.append(lines.top());
6708 static void free_all_replace()
6711 glob_replace_regex.reset();
6712 free_replace_column();
DRIZZLED_API int tmpfile(const char *prefix)