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;
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);
737 if (known_arg_type ==
false)
743 if (arg->ds->length() == 0 && arg->required)
744 die(
"Missing required argument '%s' to command '%.*s'", arg->argname,
745 command->first_word_len, command->query);
749 ptr= command->last_argument;
750 while (ptr <= command->end)
752 if (*ptr && *ptr !=
' ')
753 die(
"Extra argument '%s' passed to '%.*s'",
754 ptr, command->first_word_len, command->query);
761 static void handle_command_error(st_command* command, uint32_t error)
765 if (command->abort_on_error)
766 die(
"command \"%.*s\" failed with error %d", command->first_word_len, command->query, error);
767 for (uint32_t i= 0; i < command->expected_errors.count; i++)
769 if (command->expected_errors.err[i].type == ERR_ERRNO &&
770 command->expected_errors.err[i].code.errnum == error)
775 die(
"command \"%.*s\" failed with wrong error: %d",
776 command->first_word_len, command->query, error);
778 else if (command->expected_errors.err[0].type == ERR_ERRNO &&
779 command->expected_errors.err[0].code.errnum != 0)
782 die(
"command \"%.*s\" succeeded - should have failed with errno %d...",
783 command->first_word_len, command->query,
784 command->expected_errors.err[0].code.errnum);
788 static void cleanup_and_exit(
int exit_code)
804 printf(
"unknown exit code: %d\n", exit_code);
811 void die(
const char *fmt, ...)
818 static bool dying=
false;
824 fprintf(stderr,
"drizzletest: ");
825 if (cur_file && cur_file != file_stack.data())
826 fprintf(stderr,
"In included file \"%s\": ", cur_file->file_name);
827 if (start_lineno > 0)
828 fprintf(stderr,
"At line %u: ", start_lineno);
833 vfprintf(stderr, fmt, args);
837 fprintf(stderr,
"unknown error");
838 fprintf(stderr,
"\n");
842 if (ds_res.length() && opt_tail_lines)
844 int tail_lines= opt_tail_lines;
845 const char* show_from= ds_res.c_str() + ds_res.length() - 1;
846 while (show_from > ds_res.c_str() && tail_lines > 0 )
849 if (*show_from ==
'\n')
852 fprintf(stderr,
"\nThe result from queries just before the failure was:\n");
853 if (show_from > ds_res.c_str())
854 fprintf(stderr,
"< snip >");
855 fprintf(stderr,
"%s", show_from);
860 if (! result_file_name.empty() && ds_res.length())
861 dump_result_to_log_file(ds_res.c_str(), ds_res.length());
864 if (! result_file_name.empty() && ds_warning_messages.length())
865 dump_warning_messages();
873 show_warnings_before_error(*cur_con);
880 void abort_not_supported_test(
const char *fmt, ...)
887 fprintf(stderr,
"The test '%s' is not supported by this installation\n",
888 file_stack[0].file_name);
889 fprintf(stderr,
"Detected in file %s at line %d\n",
890 err_file->file_name, err_file->lineno);
891 while (err_file != file_stack.data())
894 fprintf(stderr,
"included from %s at line %d\n",
895 err_file->file_name, err_file->lineno);
902 fprintf(stderr,
"reason: ");
903 vfprintf(stderr, fmt, args);
904 fprintf(stderr,
"\n");
909 cleanup_and_exit(62);
913 void verbose_msg(
const char *fmt, ...)
919 fprintf(stderr,
"drizzletest: ");
920 if (cur_file && cur_file != file_stack.data())
921 fprintf(stderr,
"In included file \"%s\": ", cur_file->file_name);
922 if (start_lineno != 0)
923 fprintf(stderr,
"At line %u: ", start_lineno);
924 vfprintf(stderr, fmt, args);
925 fprintf(stderr,
"\n");
930 void warning_msg(
const char *fmt, ...)
937 ds_warning_messages +=
"drizzletest: ";
938 if (start_lineno != 0)
940 ds_warning_messages +=
"Warning detected ";
941 if (cur_file && cur_file != file_stack.data())
943 len= snprintf(buff,
sizeof(buff),
"in included file %s ", cur_file->file_name);
944 ds_warning_messages.append(buff, len);
946 len= snprintf(buff,
sizeof(buff),
"at line %d: ", start_lineno);
947 ds_warning_messages.append(buff, len);
950 len= vsnprintf(buff,
sizeof(buff), fmt, args);
951 ds_warning_messages.append(buff, len);
953 ds_warning_messages +=
"\n";
960 void log_msg(
const char *fmt, ...)
966 size_t len= vsnprintf(buff,
sizeof(buff)-1, fmt, args);
969 ds_res.append(buff, len);
984 static void cat_file(
string& ds,
const char* filename)
986 int fd= internal::my_open(filename, O_RDONLY, MYF(0));
988 die(
"Failed to open file '%s'", filename);
990 while (uint32_t len= internal::my_read(fd, (
unsigned char*)&buff,
sizeof(buff), MYF(0)))
992 char *p= buff, *start= buff;
996 if (*p ==
'\r' && *(p+1) && *(p+1)==
'\n')
1001 ds.append(start, p - start);
1009 ds.append(start, p - start);
1011 internal::my_close(fd, MYF(0));
1025 static int run_command(
const char* cmd,
string& result)
1027 FILE* res_file= popen(cmd,
"r");
1029 die(
"popen(\"%s\", \"r\") failed", cmd);
1032 while (fgets(buf,
sizeof(buf), res_file))
1037 int error= pclose(res_file);
1038 return WEXITSTATUS(error);
1054 static int run_tool(
const char *tool_path,
string& result, ...)
1057 append_os_quoted(&ds_cmdline, tool_path, NULL);
1061 va_start(args, result);
1062 while (
const char* arg= va_arg(args,
char *))
1065 if (strncmp(arg,
"--", 2) == 0)
1066 append_os_quoted(&ds_cmdline, arg, NULL);
1074 return run_command(ds_cmdline.c_str(), result);
1091 static void show_diff(
string* ds,
const char* filename1,
const char* filename2)
1096 if (run_tool(
"diff",
1106 if (run_tool(
"diff",
1120 "The two files differ but it was not possible to execute 'diff' in\n"
1121 "order to show only the difference, tried both 'diff -u' or 'diff -c'.\n"
1122 "Instead the whole content of the two files was shown for you to diff manually. ;)\n"
1124 "To get a better report you should install 'diff' on your system, which you\n"
1125 "for example can get from http://www.gnu.org/software/diffutils/diffutils.html\n"
1129 ds_tmp += filename1;
1131 cat_file(ds_tmp, filename1);
1132 ds_tmp +=
"<<<\n --- ";
1133 ds_tmp += filename1;
1135 cat_file(ds_tmp, filename2);
1148 fprintf(stderr,
"%s\n", ds_tmp.c_str());
1153 enum compare_files_result_enum
1156 RESULT_CONTENT_MISMATCH= 1,
1157 RESULT_LENGTH_MISMATCH= 2
1174 static int compare_files2(
int fd,
const char* filename2)
1176 int error= RESULT_OK;
1178 char buff[512], buff2[512];
1179 const char *fname= filename2;
1182 int fd2= internal::my_open(fname, O_RDONLY, MYF(0));
1185 internal::my_close(fd, MYF(0));
1186 if (! opt_testdir.empty())
1188 tmpfile= opt_testdir;
1189 if (tmpfile[tmpfile.length()] !=
'/')
1191 tmpfile += filename2;
1192 fname= tmpfile.c_str();
1194 if ((fd2= internal::my_open(fname, O_RDONLY, MYF(0))) < 0)
1196 internal::my_close(fd, MYF(0));
1198 die(
"Failed to open second file: '%s'", fname);
1201 while ((len= internal::my_read(fd, (
unsigned char*)&buff,
1202 sizeof(buff), MYF(0))) > 0)
1204 if ((len2= internal::my_read(fd2, (
unsigned char*)&buff2,
1205 sizeof(buff2), MYF(0))) < len)
1208 error= RESULT_LENGTH_MISMATCH;
1214 error= RESULT_LENGTH_MISMATCH;
1217 if ((memcmp(buff, buff2, len)))
1220 error= RESULT_CONTENT_MISMATCH;
1224 if (!error && internal::my_read(fd2, (
unsigned char*)&buff2,
1225 sizeof(buff2), MYF(0)) > 0)
1228 error= RESULT_LENGTH_MISMATCH;
1231 internal::my_close(fd2, MYF(0));
1250 static int compare_files(
const char* filename1,
const char* filename2)
1252 int fd= internal::my_open(filename1, O_RDONLY, MYF(0));
1254 die(
"Failed to open first file: '%s'", filename1);
1255 int error= compare_files2(fd, filename2);
1256 internal::my_close(fd, MYF(0));
1273 static int string_cmp(
const string& ds,
const char *fname)
1275 char temp_file_path[FN_REFLEN];
1277 int fd= internal::create_temp_file(temp_file_path, TMPDIR,
"tmp", MYF(MY_WME));
1279 die(
"Failed to create temporary file for ds");
1282 if (internal::my_write(fd, (
unsigned char *) ds.data(), ds.length(), MYF(MY_FNABP | MY_WME)) ||
1283 lseek(fd, 0, SEEK_SET) == MY_FILEPOS_ERROR)
1285 internal::my_close(fd, MYF(0));
1287 internal::my_delete(temp_file_path, MYF(0));
1288 die(
"Failed to write file '%s'", temp_file_path);
1291 int error= compare_files2(fd, fname);
1293 internal::my_close(fd, MYF(0));
1295 internal::my_delete(temp_file_path, MYF(0));
1313 static void check_result(
string& ds)
1315 const char* mess=
"Result content mismatch\n";
1317 if (access(result_file_name.c_str(), F_OK) != 0)
1318 die(
"The specified result file does not exist: '%s'", result_file_name.c_str());
1320 switch (string_cmp(ds, result_file_name.c_str()))
1324 case RESULT_LENGTH_MISMATCH:
1325 mess=
"Result length mismatch\n";
1327 case RESULT_CONTENT_MISMATCH:
1333 char reject_file[FN_REFLEN];
1334 size_t reject_length;
1335 internal::dirname_part(reject_file, result_file_name.c_str(), &reject_length);
1337 if (access(reject_file, W_OK) == 0)
1340 internal::fn_format(reject_file, result_file_name.c_str(), NULL,
".reject", MY_REPLACE_EXT);
1345 internal::fn_format(reject_file, result_file_name.c_str(), opt_logdir.c_str(),
".reject", MY_REPLACE_DIR | MY_REPLACE_EXT);
1347 str_to_file(reject_file, ds.data(), ds.length());
1351 show_diff(NULL, result_file_name.c_str(), reject_file);
1356 die(
"Unknown error code from dyn_string_cmp()");
1376 static void check_require(
const string& ds,
const string& fname)
1378 if (string_cmp(ds, fname.c_str()))
1380 char reason[FN_REFLEN];
1381 internal::fn_format(reason, fname.c_str(),
"",
"", MY_REPLACE_EXT | MY_REPLACE_DIR);
1382 abort_not_supported_test(
"Test requires: '%s'", reason);
1392 static int strip_surrounding(
char* str,
char c1,
char c2)
1397 while (*ptr && charset_info->isspace(*ptr))
1405 ptr= strchr(str,
'\0')-1;
1406 while (*ptr && charset_info->isspace(*ptr))
1423 static void strip_parentheses(st_command* command)
1425 if (strip_surrounding(command->first_argument,
'(',
')'))
1426 die(
"%.*s - argument list started with '%c' must be ended with '%c'",
1427 command->first_word_len, command->query,
'(',
')');
1432 VAR *var_init(
VAR *v,
const char *name,
int name_len,
const char *val,
1435 if (!name_len && name)
1436 name_len = strlen(name);
1437 if (!val_len && val)
1438 val_len = strlen(val) ;
1439 VAR *tmp_var = v ? v : (
VAR*)malloc(
sizeof(*tmp_var) + name_len+1);
1441 tmp_var->name = name ? (
char*)&tmp_var[1] : 0;
1442 tmp_var->alloced = (v == 0);
1444 int val_alloc_len = val_len + 16;
1445 tmp_var->str_val = (
char*)malloc(val_alloc_len+1);
1447 memcpy(tmp_var->name, name, name_len);
1450 memcpy(tmp_var->str_val, val, val_len);
1451 tmp_var->str_val[val_len]= 0;
1453 tmp_var->name_len = name_len;
1454 tmp_var->str_val_len = val_len;
1455 tmp_var->alloced_len = val_alloc_len;
1456 tmp_var->int_val = val ? atoi(val) : 0;
1457 tmp_var->int_dirty =
false;
1462 VAR* var_from_env(
const char *name,
const char *def_val)
1464 const char *tmp= getenv(name);
1467 return var_hash[name] = var_init(0, name, strlen(name), tmp, strlen(tmp));
1470 VAR* var_get(
const char *var_name,
const char **var_name_end,
bool raw,
1471 bool ignore_not_existing)
1475 if (*var_name !=
'$')
1477 digit = *++var_name -
'0';
1478 if (digit < 0 || digit >= 10)
1480 const char *save_var_name = var_name, *end;
1482 end = (var_name_end) ? *var_name_end : 0;
1483 while (charset_info->isvar(*var_name) && var_name != end)
1485 if (var_name == save_var_name)
1487 if (ignore_not_existing)
1489 die(
"Empty variable");
1491 length= (uint32_t) (var_name - save_var_name);
1492 if (length >= MAX_VAR_NAME_LENGTH)
1493 die(
"Too long variable name: %s", save_var_name);
1495 string save_var_name_str(save_var_name, length);
1496 if (var_hash_t::mapped_type* ptr= find_ptr(var_hash, save_var_name_str))
1500 char buff[MAX_VAR_NAME_LENGTH+1];
1501 strncpy(buff, save_var_name, length);
1503 v= var_from_env(buff,
"");
1508 v = &var_reg[digit];
1510 if (!raw && v->int_dirty)
1512 sprintf(v->str_val,
"%d", v->int_val);
1514 v->str_val_len = strlen(v->str_val);
1517 *var_name_end = var_name ;
1522 die(
"Unsupported variable name: %s", var_name);
1527 static VAR *var_obtain(
const char *name,
int len)
1529 string var_name(name, len);
1530 if (var_hash_t::mapped_type* ptr= find_ptr(var_hash, var_name))
1532 return var_hash[var_name] = var_init(0, name, len,
"", 0);
1542 static void var_set(
const char *var_name,
const char *var_name_end,
1543 const char *var_val,
const char *var_val_end)
1545 int digit, env_var= 0;
1548 if (*var_name !=
'$')
1553 digit= *var_name -
'0';
1554 if (!(digit < 10 && digit >= 0))
1556 v= var_obtain(var_name, (uint32_t) (var_name_end - var_name));
1561 eval_expr(v, var_val, (
const char**) &var_val_end);
1565 char buf[1024], *old_env_s= v->env_s;
1568 sprintf(v->str_val,
"%d", v->int_val);
1570 v->str_val_len= strlen(v->str_val);
1572 snprintf(buf,
sizeof(buf),
"%.*s=%.*s",
1573 v->name_len, v->name,
1574 v->str_val_len, v->str_val);
1575 v->env_s= strdup(buf);
1583 static void var_set_string(
const char* name,
const char* value)
1585 var_set(name, name + strlen(name), value, value + strlen(value));
1589 static void var_set_int(
const char* name,
int value)
1592 snprintf(buf,
sizeof(buf),
"%d", value);
1593 var_set_string(name, buf);
1602 static void var_set_errno(
int sql_errno)
1604 var_set_int(
"$drizzleclient_errno", sql_errno);
1613 static void var_set_drizzleclient_get_server_version(drizzle_con_st *con)
1615 var_set_int(
"$drizzle_con_server_version", drizzle_con_server_version_number(con));
1642 static void dt_query(drizzle::connection_c& con, drizzle::result_c& res,
const std::string& query)
1644 if (drizzle_return_t ret= con.query(res, query))
1646 if (ret == DRIZZLE_RETURN_ERROR_CODE)
1648 die(
"Error running query '%s': %d %s", query.c_str(), res.error_code(), res.error());
1652 die(
"Error running query '%s': %d %s", query.c_str(), ret, con.error());
1656 if (res.column_count() == 0)
1658 die(
"Query '%s' didn't return a result set", query.c_str());
1662 static void var_query_set(
VAR *
var,
const char *query,
const char** query_end)
1664 const char *end = ((query_end && *query_end) ? *query_end : query + strlen(query));
1665 drizzle::connection_c& con= *cur_con;
1667 while (end > query && *end !=
'`')
1670 die(
"Syntax error in query, missing '`'");
1675 do_eval(&ds_query, query, end,
false);
1677 drizzle::result_c res;
1678 dt_query(con, res, ds_query);
1680 drizzle_row_t row= res.row_next();
1688 size_t* lengths= res.row_field_sizes();
1689 for (uint32_t i= 0; i < res.column_count(); i++)
1694 result.append(row[i], lengths[i]);
1698 end= result.c_str() + result.length() - 1;
1699 eval_expr(var, result.c_str(), (
const char**) &end);
1702 eval_expr(var,
"", 0);
1728 static void var_set_query_get_value(st_command* command,
VAR *var)
1731 drizzle::connection_c& con= *cur_con;
1736 const struct command_arg query_get_value_args[] = {
1737 {
"query", ARG_STRING,
true, &ds_query,
"Query to run"},
1738 {
"column name", ARG_STRING,
true, &ds_col,
"Name of column"},
1739 {
"row number", ARG_STRING,
true, &ds_row,
"Number for row"}
1744 strip_parentheses(command);
1745 check_command_args(command, command->first_argument, query_get_value_args,
1746 sizeof(query_get_value_args)/
sizeof(
struct command_arg),
1750 long row_no= atoi(ds_row.c_str());
1752 istringstream buff(ds_row);
1753 if ((buff >> row_no).fail())
1754 die(
"Invalid row number: '%s'", ds_row.c_str());
1758 char* unstripped_query= strdup(ds_query.c_str());
1759 if (strip_surrounding(unstripped_query,
'"',
'"'))
1760 die(
"Mismatched \"'s around query '%s'", ds_query.c_str());
1761 ds_query= unstripped_query;
1763 drizzle::result_c res;
1764 dt_query(con, res, ds_query);
1768 uint32_t num_fields= res.column_count();
1769 for (uint32_t i= 0; i < num_fields; i++)
1771 drizzle_column_st* column= res.column_next();
1772 if (strcmp(drizzle_column_name(column), ds_col.c_str()) == 0 &&
1773 strlen(drizzle_column_name(column)) == ds_col.length())
1781 die(
"Could not find column '%s' in the result of '%s'", ds_col.c_str(), ds_query.c_str());
1788 const char* value=
"No such row";
1790 while (drizzle_row_t row= res.row_next())
1792 if (++rows == row_no)
1795 value= row[col_no] ? row[col_no] :
"NULL";
1799 eval_expr(var, value, 0);
1804 static void var_copy(
VAR *dest,
VAR *src)
1806 dest->int_val= src->int_val;
1807 dest->int_dirty= src->int_dirty;
1810 if (dest->alloced_len < src->alloced_len)
1812 char *tmpptr= (
char *)realloc(dest->str_val, src->alloced_len);
1813 dest->str_val= tmpptr;
1816 dest->alloced_len= src->alloced_len;
1819 dest->str_val_len= src->str_val_len;
1820 if (src->str_val_len)
1821 memcpy(dest->str_val, src->str_val, src->str_val_len);
1825 void eval_expr(
VAR *v,
const char *p,
const char **p_end)
1829 VAR *vp= var_get(p, p_end, 0, 0);
1837 var_query_set(v, p, p_end);
1843 const char* get_value_str=
"query_get_value";
1844 const size_t len= strlen(get_value_str);
1845 if (strncmp(p, get_value_str, len)==0)
1848 command.query= (
char*)p;
1849 command.first_word_len= len;
1850 command.first_argument= command.query + len;
1851 command.end= (
char*)*p_end;
1852 var_set_query_get_value(&command, v);
1858 int new_val_len = (p_end && *p_end) ?
1859 (
int) (*p_end - p) : (
int) strlen(p);
1860 if (new_val_len + 1 >= v->alloced_len)
1862 static int MIN_VAR_ALLOC= 32;
1863 v->alloced_len = (new_val_len < MIN_VAR_ALLOC - 1) ?
1864 MIN_VAR_ALLOC : new_val_len + 1;
1865 char *tmpptr= (
char *)realloc(v->str_val, v->alloced_len+1);
1868 v->str_val_len = new_val_len;
1869 memcpy(v->str_val, p, new_val_len);
1870 v->str_val[new_val_len] = 0;
1878 static void open_file(
const char *name)
1880 char buff[FN_REFLEN];
1882 if (!internal::test_if_hard_path(name))
1884 snprintf(buff,
sizeof(buff),
"%s%s",opt_basedir.c_str(),name);
1887 internal::fn_format(buff, name,
"",
"", MY_UNPACK_FILENAME);
1890 if (cur_file == &*file_stack.end())
1891 die(
"Source directives are nesting too deep");
1892 if (!(cur_file->file= fopen(buff,
"r")))
1895 die(
"Could not open '%s' for reading", buff);
1897 cur_file->file_name= strdup(buff);
1916 static void do_source(st_command* command)
1920 {
"filename", ARG_STRING,
true, &ds_filename,
"File to source" }
1924 check_command_args(command, command->first_argument, source_args,
1932 if (parser.current_line < (parser.read_lines - 1))
1936 if (! opt_testdir.empty())
1938 string testdir(opt_testdir);
1939 if (testdir[testdir.length()] !=
'/')
1941 testdir += ds_filename;
1942 ds_filename.swap(testdir);
1944 open_file(ds_filename.c_str());
1949 static void init_builtin_echo()
1971 static int replace(
string *ds_str,
1972 const char *search_str, uint32_t search_len,
1973 const char *replace_str, uint32_t replace_len)
1976 const char *start= strstr(ds_str->c_str(), search_str);
1979 ds_tmp.append(ds_str->c_str(), start - ds_str->c_str());
1980 ds_tmp.append(replace_str, replace_len);
1981 ds_tmp.append(start + search_len);
2008 static void do_exec(st_command* command)
2013 char *cmd= command->first_argument;
2017 while (*cmd && charset_info->isspace(*cmd))
2020 die(
"Missing argument in exec");
2021 command->last_argument= command->end;
2024 do_eval(&ds_cmd, cmd, command->end, !is_windows);
2027 if (builtin_echo[0] && strncmp(cmd,
"echo", 4) == 0)
2030 replace(&ds_cmd,
"echo", 4, builtin_echo, strlen(builtin_echo));
2033 if (!(res_file= popen(ds_cmd.c_str(),
"r")) && command->abort_on_error)
2035 die(
"popen(\"%s\", \"r\") failed", command->first_argument);
2038 while (fgets(buf,
sizeof(buf), res_file))
2040 if (disable_result_log)
2042 buf[strlen(buf)-1]=0;
2046 replace_append(&ds_res, buf);
2049 error= pclose(res_file);
2052 uint32_t status= WEXITSTATUS(error), i;
2055 if (command->abort_on_error)
2057 log_msg(
"exec of '%s' failed, error: %d, status: %d, errno: %d", ds_cmd.c_str(), error, status, errno);
2058 die(
"command \"%s\" failed", command->first_argument);
2061 for (i= 0; i < command->expected_errors.count; i++)
2063 if ((command->expected_errors.err[i].type == ERR_ERRNO) &&
2064 (command->expected_errors.err[i].code.errnum == status))
2071 die(
"command \"%s\" failed with wrong error: %d",
2072 command->first_argument, status);
2075 else if (command->expected_errors.err[0].type == ERR_ERRNO &&
2076 command->expected_errors.err[0].code.errnum != 0)
2079 log_msg(
"exec of '%s failed, error: %d, errno: %d", ds_cmd.c_str(), error, errno);
2080 die(
"command \"%s\" succeeded - should have failed with errno %d...",
2081 command->first_argument, command->expected_errors.err[0].code.errnum);
2108 static int do_modify_var(st_command* command,
2109 enum enum_operator op)
2111 const char *p= command->first_argument;
2114 die(
"Missing argument to %.*s", command->first_word_len, command->query);
2116 die(
"The argument to %.*s must be a variable (start with $)",
2117 command->first_word_len, command->query);
2118 v= var_get(p, &p, 1, 0);
2127 die(
"Invalid operator to do_modify_var");
2131 command->last_argument= (
char*)++p;
2149 static void do_system(st_command* command)
2154 if (strlen(command->first_argument) == 0)
2155 die(
"Missing arguments to system, nothing to do!");
2158 do_eval(&ds_cmd, command->first_argument, command->end, !is_windows);
2160 if (system(ds_cmd.c_str()))
2162 if (command->abort_on_error)
2163 die(
"system command '%s' failed", command->first_argument);
2166 ds_res +=
"system command '";
2167 replace_append(&ds_res, command->first_argument);
2168 ds_res +=
"' failed\n";
2171 command->last_argument= command->end;
2186 static void do_remove_file(st_command* command)
2190 {
"filename", ARG_STRING,
true, &ds_filename,
"File to delete" }
2194 check_command_args(command, command->first_argument,
2195 rm_args,
sizeof(rm_args)/
sizeof(
struct command_arg),
2198 int error= internal::my_delete(ds_filename.c_str(), MYF(0)) != 0;
2199 handle_command_error(command, error);
2215 static void do_copy_file(st_command* command)
2217 string ds_from_file;
2220 {
"from_file", ARG_STRING,
true, &ds_from_file,
"Filename to copy from" },
2221 {
"to_file", ARG_STRING,
true, &ds_to_file,
"Filename to copy to" }
2225 check_command_args(command, command->first_argument,
2227 sizeof(copy_file_args)/
sizeof(
struct command_arg),
2230 int error= (internal::my_copy(ds_from_file.c_str(), ds_to_file.c_str(),
2231 MYF(MY_DONT_OVERWRITE_FILE)) != 0);
2232 handle_command_error(command, error);
2247 static void do_chmod_file(st_command* command)
2253 {
"mode", ARG_STRING,
true, &ds_mode,
"Mode of file(octal) ex. 0660"},
2254 {
"filename", ARG_STRING,
true, &ds_file,
"Filename of file to modify" }
2258 check_command_args(command, command->first_argument,
2260 sizeof(chmod_file_args)/
sizeof(
struct command_arg),
2264 istringstream buff(ds_mode);
2265 if (ds_mode.length() != 4 ||
2266 (buff >> oct >> mode).fail())
2267 die(
"You must write a 4 digit octal number for mode");
2269 handle_command_error(command, chmod(ds_file.c_str(), mode));
2283 static void do_file_exist(st_command* command)
2287 {
"filename", ARG_STRING,
true, &ds_filename,
"File to check if it exist" }
2291 check_command_args(command, command->first_argument,
2293 sizeof(file_exist_args)/
sizeof(
struct command_arg),
2296 int error= access(ds_filename.c_str(), F_OK) != 0;
2297 handle_command_error(command, error);
2311 static void do_mkdir(st_command* command)
2315 {
"dirname", ARG_STRING,
true, &ds_dirname,
"Directory to create"}
2319 check_command_args(command, command->first_argument,
2320 mkdir_args,
sizeof(mkdir_args)/
sizeof(
struct command_arg),
2323 int error= mkdir(ds_dirname.c_str(), (0777 & internal::my_umask_dir)) != 0;
2324 handle_command_error(command, error);
2337 static void do_rmdir(st_command* command)
2341 {
"dirname", ARG_STRING,
true, &ds_dirname,
"Directory to remove"}
2345 check_command_args(command, command->first_argument,
2346 rmdir_args,
sizeof(rmdir_args)/
sizeof(
struct command_arg),
2349 int error= rmdir(ds_dirname.c_str()) != 0;
2350 handle_command_error(command, error);
2364 static int my_getc(FILE *file)
2366 if (line_buffer_pos == line_buffer)
2368 return *--line_buffer_pos;
2372 static void my_ungetc(
int c)
2374 *line_buffer_pos++= (char) c;
2378 static void read_until_delimiter(
string *ds,
2379 string *ds_delimiter)
2381 if (ds_delimiter->length() > MAX_DELIMITER_LENGTH)
2382 die(
"Max delimiter length(%d) exceeded", MAX_DELIMITER_LENGTH);
2387 char c= my_getc(cur_file->file);
2394 if (start_lineno == (cur_file->lineno - 1))
2397 else if (start_lineno == cur_file->lineno)
2403 die(
"Trailing characters found after command");
2406 if (feof(cur_file->file))
2407 die(
"End of file encountered before '%s' delimiter was found",
2408 ds_delimiter->c_str());
2410 if (match_delimiter(c, ds_delimiter->c_str(), ds_delimiter->length()))
2418 static void do_write_file_command(st_command* command,
bool append)
2422 string ds_delimiter;
2424 {
"filename", ARG_STRING,
true, &ds_filename,
"File to write to" },
2425 {
"delimiter", ARG_STRING,
false, &ds_delimiter,
"Delimiter to read until" }
2429 check_command_args(command,
2430 command->first_argument,
2432 sizeof(write_file_args)/
sizeof(
struct command_arg),
2436 if (ds_delimiter.length() == 0)
2437 ds_delimiter +=
"EOF";
2439 if (!append && access(ds_filename.c_str(), F_OK) == 0)
2442 die(
"File already exist: '%s'", ds_filename.c_str());
2445 read_until_delimiter(&ds_content, &ds_delimiter);
2446 str_to_file2(ds_filename.c_str(), ds_content.c_str(), ds_content.length(), append);
2477 static void do_write_file(st_command* command)
2479 do_write_file_command(command,
false);
2508 static void do_append_file(st_command* command)
2510 do_write_file_command(command,
true);
2526 static void do_cat_file(st_command* command)
2528 static string ds_filename;
2530 {
"filename", ARG_STRING,
true, &ds_filename,
"File to read from" }
2534 check_command_args(command,
2535 command->first_argument,
2540 cat_file(ds_res, ds_filename.c_str());
2556 static void do_diff_files(st_command* command)
2559 string ds_filename2;
2561 {
"file1", ARG_STRING,
true, &ds_filename,
"First file to diff" },
2562 {
"file2", ARG_STRING,
true, &ds_filename2,
"Second file to diff" }
2566 check_command_args(command,
2567 command->first_argument,
2569 sizeof(diff_file_args)/
sizeof(
struct command_arg),
2572 int error= compare_files(ds_filename.c_str(), ds_filename2.c_str());
2578 show_diff(&ds_res, ds_filename.c_str(), ds_filename2.c_str());
2581 handle_command_error(command, error);
2594 static void do_send_quit(st_command* command)
2596 char* p= command->first_argument;
2599 die(
"Missing connection name in send_quit");
2601 while (*p && !charset_info->isspace(*p))
2606 command->last_argument= p;
2610 die(
"connection '%s' not found in connection pool", name);
2612 drizzle::result_c result;
2613 drizzle_return_t ret;
2614 drizzle_quit(*con, result, &ret);
2634 static void do_change_user(st_command *)
2658 static void do_perl(st_command* command)
2660 char buf[FN_REFLEN];
2661 char temp_file_path[FN_REFLEN];
2663 string ds_delimiter;
2665 {
"delimiter", ARG_STRING,
false, &ds_delimiter,
"Delimiter to read until" }
2669 check_command_args(command,
2670 command->first_argument,
2676 if (ds_delimiter.length() == 0)
2677 ds_delimiter +=
"EOF";
2679 read_until_delimiter(&ds_script, &ds_delimiter);
2682 int fd= internal::create_temp_file(temp_file_path, getenv(
"MYSQLTEST_VARDIR"),
"tmp", MYF(MY_WME));
2684 die(
"Failed to create temporary file for perl command");
2685 internal::my_close(fd, MYF(0));
2687 str_to_file(temp_file_path, ds_script.c_str(), ds_script.length());
2690 snprintf(buf,
sizeof(buf),
"perl %s", temp_file_path);
2692 FILE* res_file= popen(buf,
"r");
2693 if (not res_file && command->abort_on_error)
2694 die(
"popen(\"%s\", \"r\") failed", buf);
2696 while (fgets(buf,
sizeof(buf), res_file))
2698 if (disable_result_log)
2699 buf[strlen(buf)-1]=0;
2701 replace_append(&ds_res, buf);
2703 int error= pclose(res_file);
2706 internal::my_delete(temp_file_path, MYF(0));
2708 handle_command_error(command, WEXITSTATUS(error));
2736 static void do_echo(st_command* command)
2739 do_eval(&ds_echo, command->first_argument, command->end,
false);
2742 command->last_argument= command->end;
2745 static void do_wait_for_slave_to_stop()
2747 static int SLAVE_POLL_INTERVAL= 300000;
2748 drizzle::connection_c& con= *cur_con;
2751 drizzle::result_c res;
2752 dt_query(con, res,
"show status like 'Slave_running'");
2753 drizzle_row_t row= res.row_next();
2754 if (!row || !row[1])
2756 die(
"Strange result from query while probing slave for stop");
2758 if (!strcmp(row[1],
"OFF"))
2760 usleep(SLAVE_POLL_INTERVAL);
2783 static void do_let(st_command* command)
2785 char *p= command->first_argument;
2786 char *var_name, *var_name_end;
2787 string let_rhs_expr;
2792 die(
"Missing arguments to let");
2794 while (*p && (*p !=
'=') && !charset_info->isspace(*p))
2797 if (var_name == var_name_end ||
2798 (var_name+1 == var_name_end && *var_name ==
'$'))
2799 die(
"Missing variable name in let");
2800 while (charset_info->isspace(*p))
2803 die(
"Missing assignment operator in let");
2806 while (*p && charset_info->isspace(*p))
2809 do_eval(&let_rhs_expr, p, command->end,
false);
2811 command->last_argument= command->end;
2813 var_set(var_name, var_name_end, let_rhs_expr.c_str(),
2814 (let_rhs_expr.c_str() + let_rhs_expr.length()));
2841 static void do_sleep(st_command* command,
bool real_sleep)
2843 char *p= command->first_argument;
2844 char *sleep_start, *sleep_end= command->end;
2845 double sleep_val= 0;
2847 while (charset_info->isspace(*p))
2850 die(
"Missing argument to %.*s", command->first_word_len, command->query);
2853 if (!charset_info->isdigit(*sleep_start))
2854 die(
"Invalid argument to %.*s \"%s\"", command->first_word_len,
2855 command->query,command->first_argument);
2856 string buff_str(sleep_start, sleep_end-sleep_start);
2857 istringstream buff(buff_str);
2860 die(
"Invalid argument to %.*s \"%s\"", command->first_word_len, command->query, command->first_argument);
2863 if (opt_sleep >= 0 && !real_sleep)
2864 sleep_val= opt_sleep;
2867 usleep(sleep_val * 1000000);
2868 command->last_argument= sleep_end;
2872 static void do_get_file_name(st_command* command,
string &dest)
2874 char *p= command->first_argument;
2876 die(
"Missing file name argument");
2878 while (*p && !charset_info->isspace(*p))
2882 command->last_argument= p;
2883 if (! opt_testdir.empty())
2886 if (dest[dest.length()] !=
'/')
2893 static void do_set_charset(st_command* command)
2895 char *charset_name= command->first_argument;
2898 if (!charset_name || !*charset_name)
2899 die(
"Missing charset name in 'character_set'");
2902 while (*p && !charset_info->isspace(*p))
2906 command->last_argument= p;
2907 charset_info= get_charset_by_csname(charset_name, MY_CS_PRIMARY);
2909 abort_not_supported_test(
"Test requires charset '%s'", charset_name);
2912 static void fill_global_error_names()
2914 drizzle::connection_c& con= *cur_con;
2916 global_error_names.clear();
2918 drizzle::result_c res;
2919 dt_query(con, res,
"select error_name, error_code from data_dictionary.errors");
2920 while (drizzle_row_t row= res.row_next())
2928 size_t *lengths= res.row_field_sizes();
2931 global_error_names[string(row[0], lengths[0])] = boost::lexical_cast<uint32_t>(string(row[1], lengths[1]));
2933 catch (boost::bad_lexical_cast &ex)
2935 die(
"Invalid error_code from Drizzle: %s", ex.what());
2940 static uint32_t get_errcode_from_name(
const char *error_name,
const char *error_end)
2942 string error_name_s(error_name, error_end);
2944 if (ErrorCodes::mapped_type* ptr= find_ptr(global_error_names, error_name_s))
2947 die(
"Unknown SQL error name '%s'", error_name_s.c_str());
2951 static void do_get_errcodes(st_command* command)
2954 char *p= command->first_argument;
2960 die(
"Missing argument(s) to 'error'");
2967 while (*p && *p ==
' ')
2972 while (*end && *end !=
',' && *end !=
' ')
2977 char *to_ptr= to->code.sqlstate;
2985 if ((end - p) != DRIZZLE_MAX_SQLSTATE_SIZE)
2986 die(
"The sqlstate must be exactly %d chars long", DRIZZLE_MAX_SQLSTATE_SIZE);
2989 while (*p && p < end)
2991 if (charset_info->isdigit(*p) || charset_info->isupper(*p))
2994 die(
"The sqlstate may only consist of digits[0-9] and _uppercase_ letters");
2998 to->type= ERR_SQLSTATE;
3002 die(
"The sqlstate definition must start with an uppercase S");
3008 to->code.errnum= get_errcode_from_name(p, end);
3009 to->type= ERR_ERRNO;
3013 die(
"The error name definition must start with an uppercase E");
3019 to->code.errnum= get_errcode_from_name(p, end);
3020 to->type= ERR_ERRNO;
3024 die (
"You must either use the SQLSTATE or built in drizzle error label, numbers are not accepted");
3029 if (count >= (
sizeof(saved_expected_errors.err) /
3031 die(
"Too many errorcodes specified");
3037 while (*p && *p !=
',')
3045 command->last_argument= p;
3046 to->type= ERR_EMPTY;
3048 saved_expected_errors.count= count;
3060 static char *get_string(
char **to_ptr,
char **from_ptr,
3061 st_command* command)
3064 char *to= *to_ptr, *from= *from_ptr, *start=to;
3068 if (*from ==
'"' || *from ==
'\'')
3073 for ( ; (c=*from) ; from++)
3075 if (c ==
'\\' && from[1])
3101 if (c ==
' ' || c != *++from)
3108 if (*from !=
' ' && *from)
3109 die(
"Wrong string argument in %s", command->query);
3111 while (charset_info->isspace(*from))
3121 const char *end= to;
3122 VAR *var=var_get(start, &end, 0, 1);
3123 if (var && to == (
char*) end+1)
3124 return(var->str_val);
3130 static void set_reconnect(drizzle_con_st *con,
int val)
3142 static void select_connection_name(
const char *name)
3144 if (!(cur_con= find_ptr2(g_connections, name)))
3145 die(
"connection '%s' not found in connection pool", name);
3148 var_set_drizzleclient_get_server_version(*cur_con);
3152 static void select_connection(st_command* command)
3154 char *p= command->first_argument;
3156 die(
"Missing connection name in connect");
3158 while (*p && !charset_info->isspace(*p))
3162 command->last_argument= p;
3163 select_connection_name(name);
3167 static void do_close_connection(st_command* command)
3169 char* p= command->first_argument;
3171 die(
"Missing connection name in disconnect");
3173 while (*p && !charset_info->isspace(*p))
3178 command->last_argument= p;
3182 die(
"connection '%s' not found in connection pool", name);
3183 g_connections.erase(name);
3213 static st_connection* safe_connect(
const char *name,
const string host,
const string user,
const char *pass,
const string db, uint32_t port)
3215 uint32_t failed_attempts= 0;
3217 drizzle_con_st* con= *con0;
3218 drizzle_con_set_tcp(con, host.c_str(), port);
3219 drizzle_con_set_auth(con, user.c_str(), pass);
3220 while (drizzle_return_t ret= drizzle_con_connect(con))
3230 if ((ret == DRIZZLE_RETURN_GETADDRINFO ||
3231 ret == DRIZZLE_RETURN_COULD_NOT_CONNECT) &&
3232 failed_attempts < opt_max_connect_retries)
3234 verbose_msg(
"Connect attempt %d/%d failed: %d: %s", failed_attempts, opt_max_connect_retries, ret, drizzle_con_error(con));
3239 if (failed_attempts > 0)
3240 die(
"Could not open connection '%s' after %d attempts: %d %s", name, failed_attempts, ret, drizzle_con_error(con));
3242 die(
"Could not open connection '%s': %d %s", name, ret, drizzle_con_error(con));
3248 std::string sql_string(
"CREATE SCHEMA IF NOT EXISTS mysql");
3249 drizzle_return_t ret;
3250 drizzle_result_st *result= drizzle_query(con, NULL, sql_string.c_str(), sql_string.size(), &ret);
3251 if (ret != DRIZZLE_RETURN_OK)
3253 die(
"Failed to create schema '%s': %d %s", db.c_str(), ret, drizzle_con_error(con));
3258 drizzle_result_free(result);
3263 std::string sql_string(
"CREATE SCHEMA IF NOT EXISTS ");
3265 drizzle_return_t ret;
3266 drizzle_result_st *result= drizzle_query(con, NULL, sql_string.c_str(), sql_string.size(), &ret);
3267 if (ret != DRIZZLE_RETURN_OK)
3269 die(
"Failed to create schema '%s': %d %s", db.c_str(), ret, drizzle_con_error(con));
3274 drizzle_result_free(result);
3279 std::string sql_string(
"USE ");
3281 drizzle_return_t ret;
3282 drizzle_result_st *result= drizzle_query(con, NULL, sql_string.c_str(), sql_string.size(), &ret);
3283 if (ret != DRIZZLE_RETURN_OK)
3285 die(
"Failed to use schema '%s': %d %s", db.c_str(), ret, drizzle_con_error(con));
3290 drizzle_result_free(result);
3321 static int connect_n_handle_errors(st_command* command,
3322 drizzle_con_st *con,
const char* host,
3323 const char* user,
const char* pass,
3324 const char* db,
int port,
const char* sock)
3327 if (!command->abort_on_error &&
3333 ds_res +=
"connect(";
3334 replace_append(&ds_res, host);
3336 replace_append(&ds_res, user);
3338 replace_append(&ds_res, pass);
3341 replace_append(&ds_res, db);
3343 replace_append_uint(ds_res, port);
3346 replace_append(&ds_res, sock);
3348 ds_res += delimiter;
3351 drizzle_con_set_tcp(con, host, port);
3352 drizzle_con_set_auth(con, user, pass);
3353 drizzle_con_set_db(con, db);
3354 if (drizzle_return_t ret= drizzle_con_connect(con))
3356 if (ret == DRIZZLE_RETURN_HANDSHAKE_FAILED)
3358 var_set_errno(drizzle_con_error_code(con));
3359 handle_error(command, drizzle_con_error_code(con), drizzle_con_error(con), drizzle_con_sqlstate(con), &ds_res);
3364 handle_error(command, ret, drizzle_con_error(con),
"", &ds_res);
3369 handle_no_error(command);
3399 static void do_connect(st_command* command)
3401 uint32_t con_port= opt_port;
3403 string ds_connection_name;
3412 {
"connection name", ARG_STRING,
true, &ds_connection_name,
"Name of the connection" },
3413 {
"host", ARG_STRING,
true, &ds_host,
"Host to connect to" },
3414 {
"user", ARG_STRING,
false, &ds_user,
"User to connect as" },
3415 {
"passsword", ARG_STRING,
false, &ds_password,
"Password used when connecting" },
3416 {
"database", ARG_STRING,
false, &ds_database,
"Database to select after connect" },
3417 {
"port", ARG_STRING,
false, &ds_port,
"Port to connect to" },
3418 {
"socket", ARG_STRING,
false, &ds_sock,
"Socket to connect with" },
3419 {
"options", ARG_STRING,
false, &ds_options,
"Options to use while connecting" }
3422 strip_parentheses(command);
3423 check_command_args(command, command->first_argument, connect_args,
3428 if (ds_port.length())
3430 con_port= atoi(ds_port.c_str());
3432 die(
"Illegal argument for port: '%s'", ds_port.c_str());
3436 if (!ds_sock.empty())
3442 if (*ds_sock.c_str() != FN_LIBCHAR)
3444 char buff[FN_REFLEN];
3445 internal::fn_format(buff, ds_sock.c_str(), TMPDIR,
"", 0);
3451 const char* con_options= ds_options.c_str();
3452 while (*con_options)
3455 while (*con_options && charset_info->isspace(*con_options))
3458 const char* end= con_options;
3459 while (*end && !charset_info->isspace(*end))
3461 die(
"Illegal option to connect: %.*s", (
int) (end - con_options), con_options);
3466 if (find_ptr2(g_connections, ds_connection_name))
3467 die(
"Connection %s already exists", ds_connection_name.c_str());
3472 if (ds_database.empty())
3474 ds_database= opt_db;
3478 if (ds_database ==
"*NO-ONE*")
3480 ds_database.clear();
3483 if (connect_n_handle_errors(command, *con_slot, ds_host.c_str(), ds_user.c_str(),
3484 ds_password.c_str(), ds_database.c_str(), con_port, ds_sock.c_str()))
3486 g_connections[ds_connection_name]= con_slot;
3491 var_set_drizzleclient_get_server_version(*cur_con);
3495 static void do_done(st_command* command)
3498 if (cur_block == block_stack)
3500 if (*command->query !=
'}')
3501 die(
"Stray 'end' command - end of block before beginning");
3502 die(
"Stray '}' - end of block before beginning");
3506 if (cur_block->ok && cur_block->cmd == cmd_while)
3510 parser.current_line = cur_block->line;
3516 parser.current_line++;
3547 static void do_block(
enum block_cmd cmd, st_command* command)
3549 char *p= command->first_argument;
3550 const char *expr_start, *expr_end;
3551 const char *cmd_name= (cmd == cmd_while ?
"while" :
"if");
3552 bool not_expr=
false;
3555 if (cur_block == block_stack_end)
3556 die(
"Nesting too deeply");
3559 cur_block->line= parser.current_line++;
3566 cur_block->cmd= cmd;
3567 cur_block->ok=
false;
3572 expr_start= strchr(p,
'(');
3574 die(
"missing '(' in %s", cmd_name);
3577 if (*expr_start ==
'!')
3583 expr_end= strrchr(expr_start,
')');
3585 die(
"missing ')' in %s", cmd_name);
3586 p= (
char*)expr_end+1;
3588 while (*p && charset_info->isspace(*p))
3590 if (*p && *p !=
'{')
3591 die(
"Missing '{' after %s. Found \"%s\"", cmd_name, p);
3594 var_init(&v,0,0,0,0);
3595 eval_expr(&v, expr_start, &expr_end);
3599 cur_block->cmd= cmd;
3600 cur_block->ok= (v.int_val ?
true :
false);
3603 cur_block->ok = !cur_block->ok;
3610 static void do_delimiter(st_command* command)
3612 char* p= command->first_argument;
3614 while (*p && charset_info->isspace(*p))
3619 die(
"Can't set empty delimiter");
3622 strncpy(delimiter, p,
sizeof(delimiter) - 1);
3623 delimiter_length= strlen(delimiter);
3625 command->last_argument= p + delimiter_length;
3629 bool match_delimiter(
int c,
const char *delim, uint32_t length)
3632 char tmp[MAX_DELIMITER_LENGTH];
3637 for (i= 1; i < length &&
3638 (c= my_getc(cur_file->file)) == *(delim + i);
3648 my_ungetc(tmp[--i]);
3653 static bool end_of_query(
int c)
3655 return match_delimiter(c, delimiter, delimiter_length);
3684 static int my_strnncoll_simple(
const charset_info_st *
const cs,
const unsigned char *s,
size_t slen,
3685 const unsigned char *t,
size_t tlen,
3688 size_t len = ( slen > tlen ) ? tlen : slen;
3689 unsigned char *map= cs->sort_order;
3690 if (t_is_prefix && slen > tlen)
3694 if (map[*s++] != map[*t++])
3695 return ((
int) map[s[-1]] - (int) map[t[-1]]);
3701 return slen > tlen ? 1 : slen < tlen ? -1 : 0 ;
3704 static int read_line(
char *buf,
int size)
3706 char c, last_quote= 0;
3707 char *p= buf, *buf_end= buf + size - 1;
3709 enum {R_NORMAL, R_Q, R_SLASH_IN_Q,
3710 R_COMMENT, R_LINE_START} state= R_LINE_START;
3713 start_lineno= cur_file->lineno;
3714 for (; p < buf_end ;)
3717 c= my_getc(cur_file->file);
3718 if (feof(cur_file->file))
3721 if (cur_file->file != stdin)
3723 fclose(cur_file->file);
3726 free((
unsigned char*) cur_file->file_name);
3727 cur_file->file_name= 0;
3728 if (cur_file == file_stack.data())
3733 if (cur_block != block_stack)
3734 die(
"Missing end of block");
3740 start_lineno= cur_file->lineno;
3750 if (p != buf && *(p-1) ==
'\r')
3756 if (end_of_query(c))
3761 else if ((c ==
'{' &&
3762 (!my_strnncoll_simple(charset_info, (
const unsigned char*)
"while", 5,
3763 (
unsigned char*) buf, min((ptrdiff_t)5, p - buf), 0) ||
3764 !my_strnncoll_simple(charset_info, (
const unsigned char*)
"if", 2,
3765 (
unsigned char*) buf, min((ptrdiff_t)2, p - buf), 0))))
3772 else if (c ==
'\'' || c ==
'"' || c ==
'`')
3789 if (c ==
'#' || c ==
'-')
3794 else if (charset_info->isspace(c))
3800 start_lineno= cur_file->lineno;
3804 else if (end_of_query(c))
3816 else if (c ==
'\'' || c ==
'"' || c ==
'`')
3826 if (c == last_quote)
3829 state= R_SLASH_IN_Q;
3842 int charlen = my_mbcharlen(charset_info, c);
3845 if ((charlen > 1) && (p + charlen) <= buf_end)
3852 for (i= 1; i < charlen; i++)
3854 if (feof(cur_file->file))
3856 c= my_getc(cur_file->file);
3859 if (! my_ismbchar(charset_info, mb_start, p))
3863 while (p > mb_start)
3871 die(
"The input buffer is too small for this query.x\n" \
3872 "check your query or increase MAX_QUERY and recompile");
3888 static void convert_to_format_v1(
char* query)
3890 int last_c_was_quote= 0;
3891 char *p= query, *to= query;
3892 char *end= strchr(query,
'\0');
3897 if (*p ==
'\n' && !last_c_was_quote)
3902 while (*p && charset_info->isspace(*p))
3905 last_c_was_quote= 0;
3907 else if (*p ==
'\'' || *p ==
'"' || *p ==
'`')
3913 while (*p && *p != last_c)
3918 last_c_was_quote= 1;
3923 last_c_was_quote= 0;
3935 static void scan_command_for_warnings(st_command* command)
3937 const char *ptr= command->query;
3945 if (ptr[0] ==
'\n' &&
3946 ptr[1] && ptr[1] ==
'-' &&
3947 ptr[2] && ptr[2] ==
'-' &&
3952 char *end, *start= (
char*)ptr+3;
3954 while (*start && charset_info->isspace(*start))
3958 while (*end && !charset_info->isspace(*end))
3962 type= command_typelib.find_type(start, TYPELIB::e_default);
3964 warning_msg(
"Embedded drizzletest command '--%s' detected in query '%s' was this intentional? ", start, command->query);
3977 static void check_eol_junk_line(
const char *line)
3979 const char *p= line;
3982 if (*p && !strncmp(p, delimiter, delimiter_length))
3983 die(
"Extra delimiter \"%s\" found", delimiter);
3986 if (*p && *p !=
'#')
3989 die(
"Missing delimiter");
3990 die(
"End of line junk detected: \"%s\"", p);
3995 static void check_eol_junk(
const char *eol)
4000 while (*p && (charset_info->isspace(*p) || *p ==
'#' || *p ==
'\n'))
4003 if (*p && *p ==
'#')
4006 while (*p && *p !=
'\n')
4011 if (*p && *p ==
'\n')
4012 check_eol_junk_line(p);
4018 check_eol_junk_line(p);
4040 #define MAX_QUERY (768*1024*2)
4041 static char read_command_buf[MAX_QUERY];
4043 static int read_command(st_command** command_ptr)
4045 char *p= read_command_buf;
4046 st_command* command;
4049 if (parser.current_line < parser.read_lines)
4051 *command_ptr= q_lines[parser.current_line];
4054 *command_ptr= command=
new st_command;
4055 q_lines.push_back(command);
4056 command->type= Q_UNKNOWN;
4058 read_command_buf[0]= 0;
4059 if (read_line(read_command_buf,
sizeof(read_command_buf)))
4061 check_eol_junk(read_command_buf);
4065 convert_to_format_v1(read_command_buf);
4069 command->type= Q_COMMENT;
4071 else if (p[0] ==
'-' && p[1] ==
'-')
4073 command->type= Q_COMMENT_WITH_COMMAND;
4078 while (*p && charset_info->isspace(*p))
4081 command->query_buf= command->query= strdup(p);
4085 while (*p && !charset_info->isspace(*p) && *p !=
'(')
4087 command->first_word_len= (uint32_t) (p - command->query);
4090 while (*p && charset_info->isspace(*p))
4092 command->first_argument= p;
4094 command->end= strchr(command->query,
'\0');
4095 command->query_len= (command->end - command->query);
4096 parser.read_lines++;
4112 void str_to_file2(
const char *fname,
const char *str,
int size,
bool append)
4114 char buff[FN_REFLEN];
4115 if (!internal::test_if_hard_path(fname))
4117 snprintf(buff,
sizeof(buff),
"%s%s",opt_basedir.c_str(),fname);
4120 internal::fn_format(buff, fname,
"",
"", MY_UNPACK_FILENAME);
4122 int flags= O_WRONLY | O_CREAT;
4125 int fd= internal::my_open(buff, flags, MYF(MY_WME | MY_FFNF));
4127 die(
"Could not open '%s' for writing: errno = %d", buff, errno);
4128 if (append && lseek(fd, 0, SEEK_END) == MY_FILEPOS_ERROR)
4129 die(
"Could not find end of file '%s': errno = %d", buff, errno);
4130 if (internal::my_write(fd, (
unsigned char*)str, size, MYF(MY_WME|MY_FNABP)))
4131 die(
"write failed");
4132 internal::my_close(fd, MYF(0));
4145 void str_to_file(
const char *fname,
const char *str,
int size)
4147 str_to_file2(fname, str, size,
false);
4151 void dump_result_to_log_file(
const char *buf,
int size)
4153 char log_file[FN_REFLEN];
4154 str_to_file(internal::fn_format(log_file, result_file_name.c_str(), opt_logdir.c_str(),
".log",
4155 ! opt_logdir.empty() ? MY_REPLACE_DIR | MY_REPLACE_EXT :
4158 fprintf(stderr,
"\nMore results from queries before failure can be found in %s\n", log_file);
4161 void dump_progress()
4163 char progress_file[FN_REFLEN];
4164 str_to_file(internal::fn_format(progress_file, result_file_name.c_str(),
4165 opt_logdir.c_str(),
".progress",
4166 ! opt_logdir.empty() ? MY_REPLACE_DIR | MY_REPLACE_EXT :
4168 ds_progress.c_str(), ds_progress.length());
4171 void dump_warning_messages()
4173 char warn_file[FN_REFLEN];
4175 str_to_file(internal::fn_format(warn_file, result_file_name.c_str(), opt_logdir.c_str(),
".warnings",
4176 ! opt_logdir.empty() ? MY_REPLACE_DIR | MY_REPLACE_EXT :
4178 ds_warning_messages.c_str(), ds_warning_messages.length());
4186 static void append_field(
string *ds, uint32_t col_idx, drizzle_column_st *column,
4187 const char* val, uint64_t len,
bool is_null)
4189 if (col_idx < max_replace_column && replace_column[col_idx])
4191 val= replace_column[col_idx];
4200 if (!display_result_vertically)
4204 replace_append_mem(*ds, val, (
int)len);
4208 ds->append(drizzle_column_name(column));
4210 replace_append_mem(*ds, val, (
int)len);
4221 static void append_result(
string *ds, drizzle::result_c& res)
4223 uint32_t num_fields= res.column_count();
4224 while (drizzle_row_t row = res.row_next())
4226 size_t* lengths = res.row_field_sizes();
4228 for (uint32_t i = 0; i < num_fields; i++)
4230 drizzle_column_st* column= res.column_next();
4231 if (row[i] && drizzle_column_type(column) == DRIZZLE_COLUMN_TYPE_TINY)
4233 if (boost::lexical_cast<uint32_t>(row[i]))
4235 if (drizzle_column_flags(column) & DRIZZLE_COLUMN_FLAGS_UNSIGNED)
4237 append_field(ds, i, column,
"YES", 3,
false);
4241 append_field(ds, i, column,
"TRUE", 4,
false);
4246 if (drizzle_column_flags(column) & DRIZZLE_COLUMN_FLAGS_UNSIGNED)
4248 append_field(ds, i, column,
"NO", 2,
false);
4252 append_field(ds, i, column,
"FALSE", 5,
false);
4258 append_field(ds, i, column, (
const char*)row[i], lengths[i], !row[i]);
4261 if (!display_result_vertically)
4271 static void append_metadata(
string& ds, drizzle::result_c& res)
4273 ds +=
"Catalog\tDatabase\tTable\tTable_alias\tColumn\tColumn_alias\tType\tLength\tMax length\tIs_null\tFlags\tDecimals\tCharsetnr\n";
4275 while (drizzle_column_st* column= res.column_next())
4277 ds += drizzle_column_catalog(column);
4279 ds += drizzle_column_db(column);
4281 ds += drizzle_column_orig_table(column);
4283 ds += drizzle_column_table(column);
4285 ds += drizzle_column_orig_name(column);
4287 ds += drizzle_column_name(column);
4289 replace_append_uint(ds, drizzle_column_type_drizzle(column));
4291 replace_append_uint(ds, drizzle_column_size(column));
4293 replace_append_uint(ds, drizzle_column_type(column) == DRIZZLE_COLUMN_TYPE_TINY ? 1 : drizzle_column_max_size(column));
4295 ds += drizzle_column_flags(column) & DRIZZLE_COLUMN_FLAGS_NOT_NULL ?
"N" :
"Y";
4297 replace_append_uint(ds, drizzle_column_flags(column));
4299 replace_append_uint(ds, drizzle_column_decimals(column));
4301 replace_append_uint(ds, drizzle_column_charset(column));
4311 static void append_info(
string *ds, uint64_t affected_rows,
4315 buf <<
"affected rows: " << affected_rows << endl;
4316 ds->append(buf.str());
4317 if (info && strcmp(info,
""))
4319 ds->append(
"info: ");
4321 ds->append(
"\n", 1);
4330 static void append_table_headings(
string& ds, drizzle::result_c& res)
4332 uint32_t col_idx= 0;
4334 while (drizzle_column_st* column= res.column_next())
4338 replace_append(&ds, drizzle_column_name(column));
4351 static int append_warnings(
string& ds, drizzle::connection_c& con, drizzle::result_c& res)
4353 uint32_t count= drizzle_result_warning_count(res);
4357 drizzle::result_c warn_res;
4358 dt_query(con, warn_res,
"show warnings");
4359 append_result(&ds, warn_res);
4378 st_command* command,
4379 int flags,
char *query,
int query_len,
4380 string *ds,
string& ds_warnings)
4382 drizzle_return_t ret;
4383 drizzle_con_st *con= cn;
4386 drizzle_con_add_options(con, DRIZZLE_CON_NO_RESULT_READ);
4388 drizzle::result_c res;
4389 if (flags & QUERY_SEND_FLAG)
4395 (void) drizzle_query(con, res, query, query_len, &ret);
4396 if (ret != DRIZZLE_RETURN_OK)
4398 if (ret == DRIZZLE_RETURN_ERROR_CODE ||
4399 ret == DRIZZLE_RETURN_HANDSHAKE_FAILED)
4401 err= res.error_code();
4402 handle_error(command, err, res.error(), drizzle_result_sqlstate(res), ds);
4406 handle_error(command, ret, drizzle_con_error(con),
"", ds);
4412 if (!(flags & QUERY_REAP_FLAG))
4419 if (drizzle_result_read(con, res, &ret) == NULL ||
4420 ret != DRIZZLE_RETURN_OK)
4422 if (ret == DRIZZLE_RETURN_ERROR_CODE)
4424 handle_error(command, res.error_code(), res.error(), drizzle_result_sqlstate(res), ds);
4427 handle_error(command, ret, drizzle_con_error(con),
"", ds);
4435 if (res.column_count() && (ret= drizzle_result_buffer(res)) != DRIZZLE_RETURN_OK)
4437 if (ret == DRIZZLE_RETURN_ERROR_CODE)
4439 handle_error(command, res.error_code(), res.error(), drizzle_result_sqlstate(res), ds);
4442 handle_error(command, ret, drizzle_con_error(con),
"", ds);
4447 if (!disable_result_log)
4449 uint64_t affected_rows= 0;
4451 if (res.column_count())
4453 if (display_metadata)
4454 append_metadata(*ds, res);
4456 if (!display_result_vertically)
4457 append_table_headings(*ds, res);
4459 append_result(ds, res);
4467 affected_rows= drizzle_result_affected_rows(res);
4474 if (!disable_warnings)
4476 drizzle_con_remove_options(con, DRIZZLE_CON_NO_RESULT_READ);
4477 if (append_warnings(ds_warnings, cn, res) || not ds_warnings.empty())
4479 ds->append(
"Warnings:\n", 10);
4485 append_info(ds, affected_rows, drizzle_result_info(res));
4491 handle_no_error(command);
4500 drizzle_con_remove_options(con, DRIZZLE_CON_NO_RESULT_READ);
4521 void handle_error(st_command* command,
4522 unsigned int err_errno,
const char *err_error,
4523 const char *err_sqlstate,
string *ds)
4525 if (! command->require_file.empty())
4532 if (err_errno == DRIZZLE_RETURN_LOST_CONNECTION)
4533 die(
"require query '%s' failed: %d: %s", command->query, err_errno, err_error);
4536 abort_not_supported_test(
"Query '%s' failed, required functionality not supported", command->query);
4539 if (command->abort_on_error)
4540 die(
"query '%s' failed: %d: %s", command->query, err_errno, err_error);
4543 for (; i < command->expected_errors.count; i++)
4545 if (((command->expected_errors.err[i].type == ERR_ERRNO) &&
4546 (command->expected_errors.err[i].code.errnum == err_errno)) ||
4547 ((command->expected_errors.err[i].type == ERR_SQLSTATE) &&
4548 (strncmp(command->expected_errors.err[i].code.sqlstate,
4549 err_sqlstate, DRIZZLE_MAX_SQLSTATE_SIZE) == 0)))
4551 if (!disable_result_log)
4553 if (command->expected_errors.count == 1)
4556 ds->append(
"ERROR ", 6);
4557 replace_append(ds, err_sqlstate);
4558 ds->append(
": ", 2);
4559 replace_append(ds, err_error);
4563 else if (command->expected_errors.err[0].type == ERR_SQLSTATE ||
4564 (command->expected_errors.err[0].type == ERR_ERRNO &&
4565 command->expected_errors.err[0].code.errnum != 0))
4566 ds->append(
"Got one of the listed errors\n");
4573 if (!disable_result_log)
4575 ds->append(
"ERROR ",6);
4576 replace_append(ds, err_sqlstate);
4577 ds->append(
": ", 2);
4578 replace_append(ds, err_error);
4579 ds->append(
"\n", 1);
4584 if (command->expected_errors.err[0].type == ERR_ERRNO)
4585 die(
"query '%s' failed with wrong errno %d: '%s', instead of %d...",
4586 command->query, err_errno, err_error,
4587 command->expected_errors.err[0].code.errnum);
4589 die(
"query '%s' failed with wrong sqlstate %s: '%s', instead of %s...",
4590 command->query, err_sqlstate, err_error,
4591 command->expected_errors.err[0].code.sqlstate);
4607 void handle_no_error(st_command* command)
4609 if (command->expected_errors.err[0].type == ERR_ERRNO &&
4610 command->expected_errors.err[0].code.errnum != 0)
4613 die(
"query '%s' succeeded - should have failed with errno %d...", command->query, command->expected_errors.err[0].code.errnum);
4615 else if (command->expected_errors.err[0].type == ERR_SQLSTATE &&
4616 strcmp(command->expected_errors.err[0].code.sqlstate,
"00000") != 0)
4619 die(
"query '%s' succeeded - should have failed with sqlstate %s...", command->query, command->expected_errors.err[0].code.sqlstate);
4638 st_command* command,
4647 scan_command_for_warnings(command);
4652 if (command->type == Q_EVAL)
4654 do_eval(&eval_query, command->query, command->end,
false);
4655 query = strdup(eval_query.c_str());
4656 query_len = eval_query.length();
4660 query = command->query;
4661 query_len = strlen(query);
4671 string* ds= command->require_file.empty() ? &ds_res : &ds_result;
4675 if (!disable_query_log && (flags & QUERY_SEND_FLAG))
4677 replace_append_mem(*ds, query, query_len);
4678 ds->append(delimiter, delimiter_length);
4682 string* save_ds= NULL;
4684 if (display_result_sorted)
4700 run_query_normal(cn, command, flags, query, query_len, ds, ds_warnings);
4702 if (display_result_sorted)
4705 append_sorted(*save_ds, ds_sorted);
4709 if (! command->require_file.empty())
4715 check_require(*ds, command->require_file);
4722 static void get_command_type(st_command* command)
4724 if (*command->query ==
'}')
4726 command->type = Q_END_BLOCK;
4730 char save= command->query[command->first_word_len];
4731 command->query[command->first_word_len]= 0;
4732 uint32_t type= command_typelib.find_type(command->query, TYPELIB::e_default);
4733 command->query[command->first_word_len]= save;
4736 command->type=(
enum enum_commands) type;
4742 if (type == Q_QUERY)
4745 command->query= command->first_argument;
4752 if (command->type != Q_COMMENT_WITH_COMMAND)
4755 command->type= Q_QUERY;
4760 command->type= Q_COMMENT;
4761 warning_msg(
"Suspicious command '--%s' detected, was this intentional? " \
4762 "Use # instead of -- to avoid this warning",
4765 if (command->first_word_len &&
4766 strcmp(command->query + command->first_word_len - 1, delimiter) == 0)
4774 save= command->query[command->first_word_len-1];
4775 command->query[command->first_word_len-1]= 0;
4776 if (command_typelib.find_type(command->query, TYPELIB::e_default) > 0)
4777 die(
"Extra delimiter \";\" found");
4778 command->query[command->first_word_len-1]= save;
4785 memcpy(&command->expected_errors, &saved_expected_errors,
sizeof(saved_expected_errors));
4786 command->abort_on_error= (command->expected_errors.count == 0 && abort_on_error);
4800 static void mark_progress(st_command*,
int line)
4802 uint64_t timer= timer_now();
4803 if (!progress_start)
4804 progress_start= timer;
4805 timer-= progress_start;
4809 buf << timer <<
"\t";
4812 buf << line <<
"\t";
4815 buf << cur_file->file_name <<
":";
4818 buf << cur_file->lineno << endl;
4820 ds_progress += buf.str();
4824 static void check_retries(uint32_t in_opt_max_connect_retries)
4826 if (in_opt_max_connect_retries > 10000 || opt_max_connect_retries<1)
4828 cout << N_(
"Error: Invalid Value for opt_max_connect_retries");
4831 opt_max_connect_retries= in_opt_max_connect_retries;
4834 static void check_tail_lines(uint32_t in_opt_tail_lines)
4836 if (in_opt_tail_lines > 10000)
4838 cout << N_(
"Error: Invalid Value for opt_tail_lines");
4841 opt_tail_lines= in_opt_tail_lines;
4844 static void check_sleep(int32_t in_opt_sleep)
4846 if (in_opt_sleep < -1)
4848 cout << N_(
"Error: Invalid Value for opt_sleep");
4851 opt_sleep= in_opt_sleep;
4854 int main(
int argc,
char **argv)
4858 bool q_send_flag= 0, abort_flag= 0;
4859 uint32_t command_executed= 0, last_command_executed= 0;
4864 internal::my_init();
4866 po::options_description commandline_options(
"Options used only in command line");
4867 commandline_options.add_options()
4868 (
"help,?",
"Display this help and exit.")
4869 (
"mark-progress", po::value<bool>(&opt_mark_progress)->default_value(
false)->zero_tokens(),
4870 "Write linenumber and elapsed time to <testname>.progress ")
4871 (
"sleep,T", po::value<int32_t>(&opt_sleep)->default_value(-1)->notifier(&check_sleep),
4872 "Sleep always this many seconds on sleep commands.")
4873 (
"test-file,x", po::value<string>(),
4874 "Read test from/in this file (default stdin).")
4875 (
"timer-file,f", po::value<string>(),
4876 "File where the timing in micro seconds is stored.")
4877 (
"tmpdir,t", po::value<string>(),
4878 "Temporary directory where sockets are put.")
4879 (
"verbose,v", po::value<bool>(&verbose)->default_value(
false),
4881 (
"version,V",
"Output version information and exit.")
4882 (
"no-defaults", po::value<bool>()->default_value(
false)->zero_tokens(),
4883 "Configuration file defaults are not used if no-defaults is set")
4886 po::options_description test_options(
"Options specific to the drizzleimport");
4887 test_options.add_options()
4888 (
"basedir,b", po::value<string>(&opt_basedir)->default_value(
""),
4889 "Basedir for tests.")
4890 (
"character-sets-dir", po::value<string>(&opt_charsets_dir)->default_value(
""),
4891 "Directory where character sets are.")
4892 (
"database,D", po::value<string>(&opt_db)->default_value(
""),
4894 (
"include,i", po::value<string>(&opt_include)->default_value(
""),
4895 "Include SQL before each test case.")
4896 (
"testdir", po::value<string>(&opt_testdir)->default_value(
""),
4897 "Path to use to search for test files")
4898 (
"logdir", po::value<string>(&opt_logdir)->default_value(
""),
4899 "Directory for log files")
4900 (
"max-connect-retries", po::value<uint32_t>(&opt_max_connect_retries)->default_value(500)->notifier(&check_retries),
4901 "Max number of connection attempts when connecting to server")
4902 (
"quiet,s", po::value<bool>(&silent)->default_value(
false)->zero_tokens(),
4903 "Suppress all normal output.")
4904 (
"record,r",
"Record output of test_file into result file.")
4905 (
"result-file,R", po::value<string>(&result_file_name)->default_value(
""),
4906 "Read/Store result from/in this file.")
4907 (
"silent,s", po::value<bool>(&silent)->default_value(
false)->zero_tokens(),
4908 "Suppress all normal output. Synonym for --quiet.")
4909 (
"tail-lines", po::value<uint32_t>(&opt_tail_lines)->default_value(0)->notifier(&check_tail_lines),
4910 "Number of lines of the resul to include in a failure report")
4913 po::options_description client_options(
"Options specific to the client");
4914 client_options.add_options()
4916 (
"host,h", po::value<string>(&opt_host)->default_value(
"localhost"),
4918 (
"password,P", po::value<string>(&password)->default_value(
"PASSWORD_SENTINEL"),
4919 "Password to use when connecting to server.")
4920 (
"port,p", po::value<uint32_t>(&opt_port)->default_value(0),
4921 "Port number to use for connection or 0 for default")
4922 (
"protocol", po::value<string>(&opt_protocol),
4923 "The protocol of connection (mysql or drizzle).")
4924 (
"user,u", po::value<string>(&opt_user)->default_value(
""),
4928 po::positional_options_description p;
4929 p.add(
"database", 1);
4931 po::options_description long_options(
"Allowed Options");
4932 long_options.add(commandline_options).add(test_options).add(client_options);
4934 std::string system_config_dir_test(SYSCONFDIR);
4935 system_config_dir_test +=
"/drizzle/drizzletest.cnf";
4937 std::string system_config_dir_client(SYSCONFDIR);
4938 system_config_dir_client +=
"/drizzle/client.cnf";
4940 std::string user_config_dir((getenv(
"XDG_CONFIG_HOME")? getenv(
"XDG_CONFIG_HOME"):
"~/.config"));
4942 if (user_config_dir.compare(0, 2,
"~/") == 0)
4944 if (
const char *homedir= getenv(
"HOME"))
4945 user_config_dir.replace(0, 1, homedir);
4948 po::variables_map vm;
4951 int style = po::command_line_style::default_style & ~po::command_line_style::allow_guessing;
4953 po::store(po::command_line_parser(argc, argv).options(long_options).
4954 style(style).positional(p).extra_parser(parse_password_arg).run(),
4957 if (! vm[
"no-defaults"].as<bool>())
4959 std::string user_config_dir_test(user_config_dir);
4960 user_config_dir_test +=
"/drizzle/drizzletest.cnf";
4962 std::string user_config_dir_client(user_config_dir);
4963 user_config_dir_client +=
"/drizzle/client.cnf";
4965 ifstream user_test_ifs(user_config_dir_test.c_str());
4966 po::store(parse_config_file(user_test_ifs, test_options), vm);
4968 ifstream user_client_ifs(user_config_dir_client.c_str());
4969 po::store(parse_config_file(user_client_ifs, client_options), vm);
4971 ifstream system_test_ifs(system_config_dir_test.c_str());
4972 store(parse_config_file(system_test_ifs, test_options), vm);
4974 ifstream system_client_ifs(system_config_dir_client.c_str());
4975 po::store(parse_config_file(system_client_ifs, client_options), vm);
4981 memset(&saved_expected_errors, 0,
sizeof(saved_expected_errors));
4984 memset(file_stack.data(), 0,
sizeof(file_stack));
4985 cur_file= file_stack.data();
4988 memset(block_stack, 0,
sizeof(block_stack));
4990 block_stack + (
sizeof(block_stack)/
sizeof(
struct st_block)) - 1;
4991 cur_block= block_stack;
4992 cur_block->ok=
true;
4993 cur_block->cmd= cmd_none;
4995 var_set_string(
"$DRIZZLE_SERVER_VERSION", drizzle_version());
4997 memset(&master_pos, 0,
sizeof(master_pos));
4999 parser.current_line= parser.read_lines= 0;
5000 memset(&var_reg, 0,
sizeof(var_reg));
5002 init_builtin_echo();
5004 ds_res.reserve(65536);
5005 ds_progress.reserve(2048);
5006 ds_warning_messages.reserve(2048);
5009 if (vm.count(
"record"))
5014 if (vm.count(
"test-file"))
5016 string tmp= vm[
"test-file"].as<
string>();
5017 char buff[FN_REFLEN];
5018 if (!internal::test_if_hard_path(tmp.c_str()))
5020 snprintf(buff,
sizeof(buff),
"%s%s",opt_basedir.c_str(),tmp.c_str());
5023 internal::fn_format(buff, tmp.c_str(),
"",
"", MY_UNPACK_FILENAME);
5024 assert(cur_file == file_stack.data() && cur_file->file == 0);
5025 if (!(cur_file->file= fopen(buff,
"r")))
5027 fprintf(stderr, _(
"Could not open '%s' for reading: errno = %d"), buff, errno);
5028 return EXIT_ARGUMENT_INVALID;
5030 cur_file->file_name= strdup(buff);
5031 cur_file->lineno= 1;
5034 if (vm.count(
"timer-file"))
5036 string tmp= vm[
"timer-file"].as<
string>().c_str();
5037 static char buff[FN_REFLEN];
5038 if (!internal::test_if_hard_path(tmp.c_str()))
5040 snprintf(buff,
sizeof(buff),
"%s%s",opt_basedir.c_str(),tmp.c_str());
5043 internal::fn_format(buff, tmp.c_str(),
"",
"", MY_UNPACK_FILENAME);
5048 if (vm.count(
"protocol"))
5050 boost::to_lower(opt_protocol);
5051 if (not opt_protocol.compare(
"mysql"))
5052 use_drizzle_protocol=
false;
5053 else if (not opt_protocol.compare(
"drizzle"))
5054 use_drizzle_protocol=
true;
5057 cout << _(
"Error: Unknown protocol") <<
" '" << opt_protocol <<
"'" << endl;
5062 if (vm.count(
"port"))
5067 if (opt_port > 65535)
5069 fprintf(stderr, _(
"Value supplied for port is not valid.\n"));
5070 exit(EXIT_ARGUMENT_INVALID);
5074 if( vm.count(
"password") )
5076 if (!opt_password.empty())
5077 opt_password.erase();
5078 if (password == PASSWORD_SENTINEL)
5084 opt_password= password;
5085 tty_password=
false;
5093 if (vm.count(
"tmpdir"))
5095 strncpy(TMPDIR, vm[
"tmpdir"].as<string>().c_str(),
sizeof(TMPDIR));
5098 if (vm.count(
"version"))
5100 printf(
"%s Ver %s Distrib %s, for %s-%s (%s)\n",internal::my_progname,MTEST_VERSION,
5101 drizzle_version(),HOST_VENDOR,HOST_OS,HOST_CPU);
5105 if (vm.count(
"help"))
5107 printf(
"%s Ver %s Distrib %s, for %s-%s (%s)\n",internal::my_progname,MTEST_VERSION,
5108 drizzle_version(),HOST_VENDOR,HOST_OS,HOST_CPU);
5109 printf(
"MySQL AB, by Sasha, Matt, Monty & Jani\n");
5110 printf(
"Drizzle version modified by Brian, Jay, Monty Taylor, PatG and Stewart\n");
5111 printf(
"This software comes with ABSOLUTELY NO WARRANTY\n\n");
5112 printf(
"Runs a test against the DRIZZLE server and compares output with a results file.\n\n");
5113 printf(
"Usage: %s [OPTIONS] [database] < test_file\n", internal::my_progname);
5119 opt_pass= client_get_tty_password(NULL);
5122 server_initialized=
true;
5123 if (cur_file == file_stack.data() && cur_file->file == 0)
5125 cur_file->file= stdin;
5126 cur_file->file_name= strdup(
"<stdin>");
5127 cur_file->lineno= 1;
5129 cur_con= safe_connect(
"default", opt_host, opt_user, opt_pass, opt_db, opt_port);
5130 g_connections[
"default"] = cur_con;
5132 fill_global_error_names();
5135 timer_start= timer_now();
5145 var_set_drizzleclient_get_server_version(*cur_con);
5147 if (! opt_include.empty())
5149 open_file(opt_include.c_str());
5152 st_command* command;
5153 while (!read_command(&command) && !abort_flag)
5155 int current_line_inc = 1, processed = 0;
5156 if (command->type == Q_UNKNOWN || command->type == Q_COMMENT_WITH_COMMAND)
5157 get_command_type(command);
5159 if (parsing_disabled &&
5160 command->type != Q_ENABLE_PARSING &&
5161 command->type != Q_DISABLE_PARSING)
5163 command->type= Q_COMMENT;
5164 scan_command_for_warnings(command);
5169 command->last_argument= command->first_argument;
5171 switch (command->type) {
5173 do_connect(command);
5176 select_connection(command);
5180 do_close_connection(command);
break;
5181 case Q_ENABLE_QUERY_LOG: disable_query_log=0;
break;
5182 case Q_DISABLE_QUERY_LOG: disable_query_log=1;
break;
5183 case Q_ENABLE_ABORT_ON_ERROR: abort_on_error=1;
break;
5184 case Q_DISABLE_ABORT_ON_ERROR: abort_on_error=0;
break;
5185 case Q_ENABLE_RESULT_LOG: disable_result_log=0;
break;
5186 case Q_DISABLE_RESULT_LOG: disable_result_log=1;
break;
5187 case Q_ENABLE_WARNINGS: disable_warnings=0;
break;
5188 case Q_DISABLE_WARNINGS: disable_warnings=1;
break;
5189 case Q_ENABLE_INFO: disable_info=0;
break;
5190 case Q_DISABLE_INFO: disable_info=1;
break;
5191 case Q_ENABLE_METADATA: display_metadata=1;
break;
5192 case Q_DISABLE_METADATA: display_metadata=0;
break;
5193 case Q_SOURCE: do_source(command);
break;
5194 case Q_SLEEP: do_sleep(command, 0);
break;
5195 case Q_REAL_SLEEP: do_sleep(command, 1);
break;
5196 case Q_WAIT_FOR_SLAVE_TO_STOP: do_wait_for_slave_to_stop();
break;
5197 case Q_INC: do_modify_var(command, DO_INC);
break;
5198 case Q_DEC: do_modify_var(command, DO_DEC);
break;
5199 case Q_ECHO: do_echo(command); command_executed++;
break;
5200 case Q_SYSTEM: do_system(command);
break;
5201 case Q_REMOVE_FILE: do_remove_file(command);
break;
5202 case Q_MKDIR: do_mkdir(command);
break;
5203 case Q_RMDIR: do_rmdir(command);
break;
5204 case Q_FILE_EXIST: do_file_exist(command);
break;
5205 case Q_WRITE_FILE: do_write_file(command);
break;
5206 case Q_APPEND_FILE: do_append_file(command);
break;
5207 case Q_DIFF_FILES: do_diff_files(command);
break;
5208 case Q_SEND_QUIT: do_send_quit(command);
break;
5209 case Q_CHANGE_USER: do_change_user(command);
break;
5210 case Q_CAT_FILE: do_cat_file(command);
break;
5211 case Q_COPY_FILE: do_copy_file(command);
break;
5212 case Q_CHMOD_FILE: do_chmod_file(command);
break;
5213 case Q_PERL: do_perl(command);
break;
5215 do_delimiter(command);
5217 case Q_DISPLAY_VERTICAL_RESULTS:
5218 display_result_vertically=
true;
5220 case Q_DISPLAY_HORIZONTAL_RESULTS:
5221 display_result_vertically=
false;
5223 case Q_SORTED_RESULT:
5228 display_result_sorted=
true;
5230 case Q_LET: do_let(command);
break;
5232 die(
"'eval_result' command is deprecated");
5234 case Q_QUERY_VERTICAL:
5235 case Q_QUERY_HORIZONTAL:
5236 if (command->query == command->query_buf)
5239 command->query= command->first_argument;
5240 command->first_word_len= 0;
5246 bool old_display_result_vertically= display_result_vertically;
5248 int flags= QUERY_REAP_FLAG | QUERY_SEND_FLAG;
5253 flags= QUERY_SEND_FLAG;
5256 else if (command->type == Q_REAP)
5258 flags= QUERY_REAP_FLAG;
5262 display_result_vertically|= (command->type == Q_QUERY_VERTICAL);
5264 if (! save_file.empty())
5266 command->require_file= save_file;
5269 run_query(*cur_con, command, flags);
5271 command->last_argument= command->end;
5274 display_result_vertically= old_display_result_vertically;
5279 if (!*command->first_argument)
5290 if (command->query == command->query_buf)
5291 command->query= command->first_argument;
5299 run_query(*cur_con, command, QUERY_SEND_FLAG);
5301 command->last_argument= command->end;
5304 do_get_file_name(command, save_file);
5307 do_get_errcodes(command);
5310 do_get_replace(command);
5312 case Q_REPLACE_REGEX:
5313 do_get_replace_regex(command);
5315 case Q_REPLACE_COLUMN:
5316 do_get_replace_column(command);
5319 command->last_argument= command->end;
5323 drizzle::result_c result;
5324 drizzle_return_t ret;
5325 (void) drizzle_ping(*cur_con, result, &ret);
5334 timer_start= timer_now();
5340 case Q_CHARACTER_SET:
5341 do_set_charset(command);
5343 case Q_DISABLE_RECONNECT:
5344 set_reconnect(*cur_con, 0);
5346 case Q_ENABLE_RECONNECT:
5347 set_reconnect(*cur_con, 1);
5349 case Q_DISABLE_PARSING:
5350 if (parsing_disabled == 0)
5351 parsing_disabled= 1;
5353 die(
"Parsing is already disabled");
5355 case Q_ENABLE_PARSING:
5360 if (parsing_disabled == 1)
5361 parsing_disabled= 0;
5363 die(
"Parsing is already enabled");
5367 die(
"%s", command->first_argument);
5374 abort_not_supported_test(
"%s", command->first_argument);
5378 die(
"result, deprecated command");
5389 current_line_inc= 0;
5390 switch (command->type) {
5391 case Q_WHILE: do_block(cmd_while, command);
break;
5392 case Q_IF: do_block(cmd_if, command);
break;
5393 case Q_END_BLOCK: do_done(command);
break;
5394 default: current_line_inc = 1;
break;
5398 check_eol_junk(command->last_argument);
5400 if (command->type != Q_ERROR &&
5401 command->type != Q_COMMENT)
5407 memset(&saved_expected_errors, 0,
sizeof(saved_expected_errors));
5410 if (command_executed != last_command_executed)
5419 display_result_sorted=
false;
5421 last_command_executed= command_executed;
5423 parser.current_line += current_line_inc;
5424 if ( opt_mark_progress )
5425 mark_progress(command, parser.current_line);
5430 if (parsing_disabled)
5431 die(
"Test ended with parsing disabled");
5439 die(
"The test didn't produce any output");
5440 if (result_file_name.empty())
5443 printf(
"%s", ds_res.c_str());
5448 str_to_file(result_file_name.c_str(), ds_res.c_str(), ds_res.length());
5456 check_result(ds_res);
5459 struct stat res_info;
5460 if (not command_executed && not result_file_name.empty() && not stat(result_file_name.c_str(), &res_info))
5469 die(
"No queries executed but result file found!");
5472 if ( opt_mark_progress && ! result_file_name.empty() )
5476 if (not result_file_name.empty() && ds_warning_messages.length())
5477 dump_warning_messages();
5481 cleanup_and_exit(0);
5484 catch(exception &err)
5486 cerr<<err.what()<<endl;
5519 uint64_t timer= timer_now() - timer_start;
5521 str_to_file(timer_file,buf.str().c_str(), buf.str().size() );
5528 uint64_t timer_now()
5530 #if defined(HAVE_GETHRTIME)
5531 return gethrtime()/1000/1000;
5538 while (gettimeofday(&t, NULL) != 0)
5540 newtime= (uint64_t)t.tv_sec * 1000000 + t.tv_usec;
5541 return newtime/1000;
5554 void do_get_replace_column(st_command* command)
5556 char *from= command->first_argument;
5560 free_replace_column();
5562 die(
"Missing argument in %s", command->query);
5565 start= buff= (
char *)malloc(strlen(from)+1);
5568 uint32_t column_number;
5570 char *to= get_string(&buff, &from, command);
5571 if (!(column_number= atoi(to)) || column_number > MAX_COLUMNS)
5572 die(
"Wrong column number to replace_column in '%s'", command->query);
5574 die(
"Wrong number of arguments to replace_column in '%s'", command->query);
5575 to= get_string(&buff, &from, command);
5576 free(replace_column[column_number-1]);
5577 replace_column[column_number-1]= strdup(to);
5578 set_if_bigger(max_replace_column, column_number);
5581 command->last_argument= command->end;
5585 void free_replace_column()
5587 for (uint32_t i= 0; i < max_replace_column; i++)
5589 free(replace_column[i]);
5590 replace_column[i]= 0;
5592 max_replace_column= 0;
5607 int insert(
char* name);
5611 memset(
this, 0,
sizeof(*
this));
5617 uint32_t array_allocs;
5620 uint32_t max_length;
5624 struct st_replace *init_replace(
const char **from,
const char **to, uint32_t count,
5625 char *word_end_chars);
5627 void replace_strings_append(
struct st_replace *rep,
string& ds,
const char *from,
int len);
5640 POINTER_ARRAY::~POINTER_ARRAY()
5645 free((
char*) typelib.type_names);
5646 typelib.type_names=0;
5650 void do_get_replace(st_command* command)
5652 char *from= command->first_argument;
5654 die(
"Missing argument in %s", command->query);
5657 char* start= (
char*)malloc(strlen(from) + 1);
5661 char *to= get_string(&buff, &from, command);
5663 die(
"Wrong number of arguments to replace_result in '%s'", command->query);
5664 from_array.insert(to);
5665 to= get_string(&buff, &from, command);
5666 to_array.insert(to);
5668 char word_end_chars[256];
5669 char* pos= word_end_chars;
5670 for (
int i= 1; i < 256; i++)
5672 if (charset_info->isspace(i))
5676 if (!(glob_replace= init_replace(from_array.typelib.type_names,
5677 to_array.typelib.type_names,
5678 from_array.typelib.count,
5680 die(
"Can't initialize replace from '%s'", command->query);
5682 command->last_argument= command->end;
5701 char *replace_string;
5707 void replace_strings_append(
REPLACE *rep,
string& ds,
const char *str,
int len)
5710 const char* start= str;
5711 const char* from= str;
5717 while (!rep_pos->found)
5718 rep_pos= rep_pos->next[(
unsigned char) *from++];
5724 ds.append(start, from - start - 1);
5729 ds.append(start, (from - rep_str->to_offset) - start);
5732 ds.append(rep_str->replace_string, strlen(rep_str->replace_string));
5734 if (!*(from-=rep_str->from_offset) && rep_pos->found != 2)
5737 assert(from <= str+len);
5764 int multi_reg_replace(
char* val);
5773 typedef vector<st_regex> regex_arr_t;
5780 boost::array<char, 8 << 10> buf0_;
5781 boost::array<char, 8 << 10> buf1_;
5782 regex_arr_t regex_arr;
5785 boost::scoped_ptr<st_replace_regex> glob_replace_regex;
5787 int reg_replace(
char** buf_p,
int* buf_len_p,
char *pattern,
char *replace,
5788 char *
string,
int icase,
int global);
5797 #define PARSE_REGEX_ARG \
5798 while (p < expr_end) \
5803 if (last_c == '\\') \
5827 st_replace_regex::st_replace_regex(
char* expr)
5829 uint32_t expr_len= strlen(expr);
5833 char* buf=
new char[expr_len];
5834 char* expr_end= expr + expr_len;
5839 while (p < expr_end)
5841 memset(®, 0,
sizeof(reg));
5843 while (p < expr_end)
5850 if (p == expr_end || ++p == expr_end)
5852 if (!regex_arr.empty())
5863 if (p == expr_end || ++p == expr_end)
5879 if (p < expr_end && *p ==
'i')
5886 if (p < expr_end && *p ==
'g')
5891 regex_arr.push_back(reg);
5893 odd_buf_len= even_buf_len= buf0_.size();
5894 even_buf= buf0_.data();
5895 odd_buf= buf1_.data();
5901 die(
"Error parsing replace_regex \"%s\"", expr);
5923 int st_replace_regex::multi_reg_replace(
char* val)
5926 char* out_buf= even_buf;
5927 int* buf_len_p= &even_buf_len;
5931 BOOST_FOREACH(regex_arr_t::const_reference i, regex_arr)
5933 char* save_out_buf= out_buf;
5934 if (!reg_replace(&out_buf, buf_len_p, i.pattern, i.replace,
5935 in_buf, i.icase, i.global))
5938 if (save_out_buf != out_buf)
5940 if (save_out_buf == even_buf)
5948 std::swap(in_buf, out_buf);
5949 buf_len_p= (out_buf == even_buf) ? &even_buf_len : &odd_buf_len;
5964 void do_get_replace_regex(st_command* command)
5966 char *expr= command->first_argument;
5968 command->last_argument= command->end;
5983 int reg_replace(
char** buf_p,
int* buf_len_p,
char *pattern,
5984 char *replace,
char *
in_string,
int icase,
int global)
5986 const char *error= NULL;
5989 pcre *re= pcre_compile(pattern,
5990 icase ? PCRE_CASELESS | PCRE_MULTILINE : PCRE_MULTILINE,
5991 &error, &erroffset, NULL);
5998 int rc= pcre_exec(re, NULL, in_string, (
int)strlen(in_string),
6006 char *substring_to_replace= in_string + ovector[0];
6007 int substring_length= ovector[1] - ovector[0];
6008 *buf_len_p= strlen(in_string) - substring_length + strlen(replace);
6009 char* new_buf= (
char*)malloc(*buf_len_p+1);
6011 memset(new_buf, 0, *buf_len_p+1);
6012 strncpy(new_buf, in_string, substring_to_replace-in_string);
6013 strncpy(new_buf+(substring_to_replace-in_string), replace, strlen(replace));
6014 strncpy(new_buf+(substring_to_replace-in_string)+strlen(replace),
6015 substring_to_replace + substring_length,
6018 - (substring_to_replace-in_string));
6027 string subject(in_string);
6028 size_t replace_length= strlen(replace);
6029 size_t length_of_replacement= strlen(replace);
6030 size_t current_position= 0;
6035 rc= pcre_exec(re, NULL, subject.c_str(), subject.length(),
6036 current_position, 0, ovector, 3);
6042 current_position=
static_cast<size_t>(ovector[0]);
6043 replace_length=
static_cast<size_t>(ovector[1] - ovector[0]);
6044 subject.replace(current_position, replace_length, replace, length_of_replacement);
6045 current_position= current_position + length_of_replacement;
6048 char* new_buf = (
char*) malloc(subject.length() + 1);
6049 memset(new_buf, 0, subject.length() + 1);
6050 strncpy(new_buf, subject.c_str(), subject.length());
6051 *buf_len_p= subject.length() + 1;
6061 #define WORD_BIT (8*sizeof(uint32_t))
6064 #define SET_MALLOC_HUNC 64
6065 #define LAST_CHAR_CODE 259
6070 void internal_set_bit(uint32_t bit);
6071 void internal_clear_bit(uint32_t bit);
6072 void or_bits(
const REP_SET *from);
6073 void copy_bits(
const REP_SET *from);
6074 int cmp_bits(
const REP_SET *set2)
const;
6075 int get_next_bit(uint32_t lastpos)
const;
6078 short next[LAST_CHAR_CODE];
6081 uint32_t table_offset;
6082 uint32_t size_of_bits;
6088 int find_set(
const REP_SET *find);
6089 void free_last_set();
6091 void make_sets_invisible();
6096 uint32_t size_of_bits;
6098 uint32_t *bit_buffer;
6103 uint32_t table_offset;
6110 uint32_t table_offset;
6114 void init_sets(
REP_SETS *sets, uint32_t states);
6116 int find_found(
FOUND_SET *found_set, uint32_t table_offset,
int found_offset);
6118 static uint32_t found_sets= 0;
6120 static uint32_t replace_len(
const char *str)
6125 if (str[0] ==
'\\' && str[1])
6135 static bool start_at_word(
const char *pos)
6137 return (!memcmp(pos,
"\\b",2) && pos[2]) || !memcmp(pos,
"\\^", 2);
6140 static bool end_of_word(
const char *pos)
6142 const char *end= strchr(pos,
'\0');
6143 return (end > pos+2 && !memcmp(end-2,
"\\b", 2)) || (end >= pos+2 && !memcmp(end-2,
"\\$",2));
6148 REPLACE *init_replace(
const char **from,
const char **to, uint32_t count,
char *word_end_chars)
6150 const int SPACE_CHAR= 256;
6151 const int START_OF_LINE= 257;
6152 const int END_OF_LINE= 258;
6154 uint32_t i,j,states,set_nr,len,result_len,max_length,found_end,bits_set,bit_nr;
6155 int used_sets,chr,default_state;
6156 char used_chars[LAST_CHAR_CODE],is_word_end[256];
6157 char *to_pos, **to_array;
6160 for (i=result_len=max_length=0 , states=2; i < count; i++)
6162 len=replace_len(from[i]);
6169 result_len+=(uint32_t) strlen(to[i])+1;
6170 if (len > max_length)
6173 memset(is_word_end, 0,
sizeof(is_word_end));
6174 for (i=0; word_end_chars[i]; i++)
6175 is_word_end[(
unsigned char) word_end_chars[i]]=1;
6178 REP_SET *set,*start_states,*word_states,*new_set;
6180 init_sets(&sets, states);
6182 vector<FOUND_SET> found_set(max_length * count);
6183 make_new_set(&sets);
6184 sets.make_sets_invisible();
6186 word_states=make_new_set(&sets);
6187 start_states=make_new_set(&sets);
6188 vector<FOLLOWS> follow(states + 2);
6189 FOLLOWS *follow_ptr= &follow[1];
6191 for (i=0, states=1; i < count; i++)
6193 if (from[i][0] ==
'\\' && from[i][1] ==
'^')
6195 start_states->internal_set_bit(states + 1);
6198 start_states->table_offset=i;
6199 start_states->found_offset=1;
6202 else if (from[i][0] ==
'\\' && from[i][1] ==
'$')
6204 start_states->internal_set_bit(states);
6205 word_states->internal_set_bit(states);
6206 if (!from[i][2] && start_states->table_offset == UINT32_MAX)
6208 start_states->table_offset=i;
6209 start_states->found_offset=0;
6214 word_states->internal_set_bit(states);
6215 if (from[i][0] ==
'\\' && (from[i][1] ==
'b' && from[i][2]))
6216 start_states->internal_set_bit(states + 1);
6218 start_states->internal_set_bit(states);
6221 for (pos= from[i], len=0; *pos; pos++)
6223 if (*pos ==
'\\' && *(pos+1))
6228 follow_ptr->chr = SPACE_CHAR;
6231 follow_ptr->chr = START_OF_LINE;
6234 follow_ptr->chr = END_OF_LINE;
6237 follow_ptr->chr =
'\r';
6240 follow_ptr->chr =
'\t';
6243 follow_ptr->chr =
'\v';
6246 follow_ptr->chr = (
unsigned char) *pos;
6251 follow_ptr->chr= (
unsigned char) *pos;
6252 follow_ptr->table_offset=i;
6253 follow_ptr->len= ++len;
6257 follow_ptr->table_offset=i;
6258 follow_ptr->len=len;
6260 states+=(uint32_t) len+1;
6264 for (set_nr=0; set_nr < sets.count; set_nr++)
6266 set=sets.set+set_nr;
6271 for (i= UINT32_MAX; (i= set->get_next_bit(i));)
6273 if (!follow[i].chr && !default_state)
6274 default_state= find_found(&found_set.front(), set->table_offset, set->found_offset+1);
6276 sets.set[used_sets].copy_bits(set);
6278 sets.set[used_sets].or_bits(sets.set);
6281 memset(used_chars, 0,
sizeof(used_chars));
6282 for (i= UINT32_MAX; (i= sets.set[used_sets].get_next_bit(i));)
6284 used_chars[follow[i].chr]=1;
6285 if ((follow[i].chr == SPACE_CHAR && !follow[i+1].chr &&
6286 follow[i].len > 1) || follow[i].chr == END_OF_LINE)
6291 if (used_chars[SPACE_CHAR])
6292 for (
const char *pos= word_end_chars; *pos; pos++)
6293 used_chars[(
int) (
unsigned char) *pos] = 1;
6296 for (chr= 0; chr < 256; chr++)
6298 if (! used_chars[chr])
6299 set->next[chr]= chr ? default_state : -1;
6302 new_set=make_new_set(&sets);
6303 set=sets.set+set_nr;
6304 new_set->table_offset=set->table_offset;
6305 new_set->found_len=set->found_len;
6306 new_set->found_offset=set->found_offset+1;
6309 for (i= UINT32_MAX; (i= sets.set[used_sets].get_next_bit(i));)
6311 if (!follow[i].chr || follow[i].chr == chr ||
6312 (follow[i].chr == SPACE_CHAR &&
6313 (is_word_end[chr] ||
6314 (!chr && follow[i].len > 1 && ! follow[i+1].chr))) ||
6315 (follow[i].chr == END_OF_LINE && ! chr))
6317 if ((! chr || (follow[i].chr && !follow[i+1].chr)) &&
6318 follow[i].len > found_end)
6319 found_end=follow[i].len;
6320 if (chr && follow[i].chr)
6321 new_set->internal_set_bit(i + 1);
6323 new_set->internal_set_bit(i);
6328 new_set->found_len=0;
6330 for (i= UINT32_MAX; (i= new_set->get_next_bit(i));)
6332 if ((follow[i].chr == SPACE_CHAR ||
6333 follow[i].chr == END_OF_LINE) && ! chr)
6337 if (follow[bit_nr-1].len < found_end ||
6338 (new_set->found_len &&
6339 (chr == 0 || !follow[bit_nr].chr)))
6340 new_set->internal_clear_bit(i);
6343 if (chr == 0 || !follow[bit_nr].chr)
6345 new_set->table_offset=follow[bit_nr].table_offset;
6346 if (chr || (follow[i].chr == SPACE_CHAR ||
6347 follow[i].chr == END_OF_LINE))
6348 new_set->found_offset=found_end;
6349 new_set->found_len=found_end;
6356 set->next[chr] = find_found(&found_set.front(), new_set->table_offset, new_set->found_offset);
6357 sets.free_last_set();
6360 set->next[chr] = sets.find_set(new_set);
6363 set->next[chr] = sets.find_set(new_set);
6371 +
sizeof(
REPLACE_STRING) * (found_sets + 1) +
sizeof(
char*) * count + result_len);
6373 memset(replace, 0,
sizeof(
REPLACE)*(sets.count)+
6375 sizeof(
char *)*count+result_len);
6377 to_array= (
char **) (rep_str+found_sets+1);
6378 to_pos=(
char *) (to_array+count);
6379 for (i=0; i < count; i++)
6382 to_pos=strcpy(to_pos,to[i])+strlen(to[i])+1;
6385 rep_str[0].replace_string=0;
6386 for (i=1; i <= found_sets; i++)
6388 const char *pos= from[found_set[i-1].table_offset];
6389 rep_str[i].found= !memcmp(pos,
"\\^", 3) ? 2 : 1;
6390 rep_str[i].replace_string= to_array[found_set[i-1].table_offset];
6391 rep_str[i].to_offset= found_set[i-1].found_offset-start_at_word(pos);
6392 rep_str[i].from_offset= found_set[i-1].found_offset-replace_len(pos) + end_of_word(pos);
6394 for (i=0; i < sets.count; i++)
6396 for (j=0; j < 256; j++)
6397 if (sets.set[i].next[j] >= 0)
6398 replace[i].next[j]=replace+sets.set[i].next[j];
6400 replace[i].next[j]=(
REPLACE*) (rep_str+(-sets.set[i].next[j]-1));
6408 void init_sets(
REP_SETS *sets,uint32_t states)
6410 memset(sets, 0,
sizeof(*sets));
6411 sets->size_of_bits=((states+7)/8);
6412 sets->set_buffer=(
REP_SET*) malloc(
sizeof(
REP_SET) * SET_MALLOC_HUNC);
6413 sets->bit_buffer=(uint*) malloc(
sizeof(uint32_t) * sets->size_of_bits * SET_MALLOC_HUNC);
6418 void REP_SETS::make_sets_invisible()
6431 set=sets->set+ sets->count++;
6432 memset(set->bits, 0,
sizeof(uint32_t)*sets->size_of_bits);
6433 memset(&set->next[0], 0,
sizeof(set->next[0])*LAST_CHAR_CODE);
6434 set->found_offset=0;
6436 set->table_offset= UINT32_MAX;
6437 set->size_of_bits=sets->size_of_bits;
6440 uint32_t count= sets->count + sets->invisible + SET_MALLOC_HUNC;
6441 set= (
REP_SET*) realloc((
unsigned char*) sets->set_buffer,
sizeof(
REP_SET)*count);
6442 sets->set_buffer=set;
6443 sets->set=set+sets->invisible;
6444 uint32_t* bit_buffer= (uint*) realloc((
unsigned char*) sets->bit_buffer, (
sizeof(uint32_t)*sets->size_of_bits)*count);
6445 sets->bit_buffer=bit_buffer;
6446 for (uint32_t i= 0; i < count; i++)
6448 sets->set_buffer[i].bits=bit_buffer;
6449 bit_buffer+=sets->size_of_bits;
6451 sets->extra=SET_MALLOC_HUNC;
6452 return make_new_set(sets);
6455 void REP_SETS::free_last_set()
6461 void REP_SETS::free_sets()
6467 void REP_SET::internal_set_bit(uint32_t bit)
6469 bits[bit / WORD_BIT] |= 1 << (bit % WORD_BIT);
6472 void REP_SET::internal_clear_bit(uint32_t bit)
6474 bits[bit / WORD_BIT] &= ~ (1 << (bit % WORD_BIT));
6478 void REP_SET::or_bits(
const REP_SET *from)
6480 for (uint32_t i= 0; i < size_of_bits; i++)
6481 bits[i]|=from->bits[i];
6484 void REP_SET::copy_bits(
const REP_SET *from)
6486 memcpy(bits, from->bits,
sizeof(uint32_t) * size_of_bits);
6489 int REP_SET::cmp_bits(
const REP_SET *set2)
const
6491 return memcmp(bits, set2->bits,
sizeof(uint32_t) * size_of_bits);
6496 int REP_SET::get_next_bit(uint32_t lastpos)
const
6498 uint32_t *start= bits + ((lastpos+1) / WORD_BIT);
6499 uint32_t *end= bits + size_of_bits;
6500 uint32_t bits0= start[0] & ~((1 << ((lastpos+1) % WORD_BIT)) -1);
6502 while (!bits0 && ++start < end)
6506 uint32_t pos= (start - bits) * WORD_BIT;
6507 while (!(bits0 & 1))
6519 int REP_SETS::find_set(
const REP_SET *find)
6522 for (; i < count - 1; i++)
6524 if (!set[i].cmp_bits(find))
6540 int find_found(
FOUND_SET *found_set, uint32_t table_offset,
int found_offset)
6543 for (; i < found_sets; i++)
6545 if (found_set[i].table_offset == table_offset &&
6546 found_set[i].found_offset == found_offset)
6549 found_set[i].table_offset= table_offset;
6550 found_set[i].found_offset= found_offset;
6559 #define PC_MALLOC 256
6560 #define PS_MALLOC 512
6562 static int insert_pointer_name(
POINTER_ARRAY* pa,
char* name)
6564 uint32_t i,length,old_count;
6565 unsigned char *new_pos;
6566 const char **new_array;
6569 if (! pa->typelib.count)
6571 pa->typelib.type_names=(
const char **)
6572 malloc(((PC_MALLOC-MALLOC_OVERHEAD)/
6573 (
sizeof(
char *)+
sizeof(*pa->flag))*
6574 (
sizeof(
char *)+
sizeof(*pa->flag))));
6575 pa->str= (
unsigned char*) malloc(PS_MALLOC-MALLOC_OVERHEAD);
6576 pa->max_count=(PC_MALLOC-MALLOC_OVERHEAD)/(
sizeof(
unsigned char*)+
6578 pa->flag= (uint8_t*) (pa->typelib.type_names+pa->max_count);
6580 pa->max_length=PS_MALLOC-MALLOC_OVERHEAD;
6583 length=(uint32_t) strlen(name)+1;
6584 if (pa->length+length >= pa->max_length)
6586 new_pos= (
unsigned char*)realloc((
unsigned char*)pa->str, (size_t)(pa->max_length+PS_MALLOC));
6587 if (new_pos != pa->str)
6589 ptrdiff_t diff= PTR_BYTE_DIFF(new_pos,pa->str);
6590 for (i=0; i < pa->typelib.count; i++)
6591 pa->typelib.type_names[i]= ADD_TO_PTR(pa->typelib.type_names[i],diff,
6595 pa->max_length+=PS_MALLOC;
6597 if (pa->typelib.count >= pa->max_count-1)
6601 len=(PC_MALLOC*pa->array_allocs - MALLOC_OVERHEAD);
6602 new_array= (
const char **)realloc((
unsigned char*) pa->typelib.type_names,
6604 (
sizeof(
unsigned char*)+
sizeof(*pa->flag))*
6605 (
sizeof(
unsigned char*)+
sizeof(*pa->flag)));
6606 pa->typelib.type_names=new_array;
6607 old_count=pa->max_count;
6608 pa->max_count=len/(
sizeof(
unsigned char*) +
sizeof(*pa->flag));
6609 pa->flag= (uint8_t*) (pa->typelib.type_names+pa->max_count);
6610 memcpy(pa->flag, pa->typelib.type_names+old_count,
6611 old_count*
sizeof(*pa->flag));
6613 pa->flag[pa->typelib.count]=0;
6614 pa->typelib.type_names[pa->typelib.count++]= (
char*) pa->str+pa->length;
6615 pa->typelib.type_names[pa->typelib.count]= NULL;
6616 strcpy((
char*) pa->str+pa->length,name);
6621 int POINTER_ARRAY::insert(
char* name)
6623 return insert_pointer_name(
this, name);
6630 void replace_append_mem(
string& ds,
const char *val,
int len)
6632 char *v= strdup(val);
6634 if (glob_replace_regex && !glob_replace_regex->multi_reg_replace(v))
6636 v= glob_replace_regex->buf_;
6642 replace_strings_append(glob_replace, ds, v, len);
6650 void replace_append(
string *ds,
const char *val)
6652 replace_append_mem(*ds, val, strlen(val));
6656 void replace_append_uint(
string& ds, uint32_t val)
6660 replace_append_mem(ds, buff.str().c_str(), buff.str().size());
6679 void append_sorted(
string& ds,
const string& ds_input)
6681 priority_queue<string, vector<string>, greater<string> > lines;
6683 if (ds_input.empty())
6686 unsigned long eol_pos= ds_input.find_first_of(
'\n', 0);
6687 if (eol_pos == string::npos)
6690 ds.append(ds_input.substr(0, eol_pos+1));
6692 unsigned long start_pos= eol_pos+1;
6697 eol_pos= ds_input.find_first_of(
'\n', start_pos);
6699 lines.push(ds_input.substr(start_pos, eol_pos-start_pos+1));
6700 start_pos= eol_pos+1;
6702 }
while ( eol_pos != string::npos);
6705 while (!lines.empty())
6707 ds.append(lines.top());
6712 static void free_all_replace()
6715 glob_replace_regex.reset();
6716 free_replace_column();
TODO: Rename this file - func.h is stupid.
DRIZZLED_API int tmpfile(const char *prefix)