~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to client/mysqltest.cc

  • Committer: Brian Aker
  • Date: 2008-07-14 16:09:55 UTC
  • Revision ID: brian@tangent.org-20080714160955-v5nzzyjj5hhv7bz6
Removing a few "additional" ways of saying uint64_t

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
 
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
 
 * 
4
 
 *  Copyright (C) 2010 Vijay Samuel
5
 
 *  Copyright (C) 2008 MySQL
6
 
 *
7
 
 *  This program is free software; you can redistribute it and/or modify
8
 
 *  it under the terms of the GNU General Public License as published by
9
 
 *  the Free Software Foundation; either version 2 of the License, or
10
 
 *  (at your option) any later version.
11
 
 *
12
 
 *  This program is distributed in the hope that it will be useful,
13
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 
 *  GNU General Public License for more details.
16
 
 *
17
 
 *  You should have received a copy of the GNU General Public License
18
 
 *  along with this program; if not, write to the Free Software
19
 
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20
 
 */
 
1
/* Copyright (C) 2000 MySQL AB
 
2
 
 
3
   This program is free software; you can redistribute it and/or modify
 
4
   it under the terms of the GNU General Public License as published by
 
5
   the Free Software Foundation; version 2 of the License.
 
6
 
 
7
   This program is distributed in the hope that it will be useful,
 
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
10
   GNU General Public License for more details.
 
11
 
 
12
   You should have received a copy of the GNU General Public License
 
13
   along with this program; if not, write to the Free Software
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
21
15
 
22
16
/*
23
 
  drizzletest
 
17
  mysqltest
24
18
 
25
19
  Tool used for executing a .test file
26
20
 
27
 
  See the "DRIZZLE Test framework manual" for more information
28
 
  http://dev.mysql.com/doc/drizzletest/en/index.html
 
21
  See the "MySQL Test framework manual" for more information
 
22
  http://dev.mysql.com/doc/mysqltest/en/index.html
29
23
 
30
24
  Please keep the test framework tools identical in all versions!
31
25
 
38
32
*/
39
33
 
40
34
#define MTEST_VERSION "3.3"
 
35
#include <pcrecpp.h>
41
36
 
42
37
#include "client_priv.h"
43
 
 
44
 
#include <queue>
45
 
#include <map>
46
 
#include <string>
47
 
#include <sstream>
48
 
#include <fstream>
49
 
#include <iostream>
50
 
#include <vector>
51
 
#include <algorithm>
 
38
#include <drizzle_version.h>
 
39
#include <mysqld_error.h>
 
40
#include <m_ctype.h>
 
41
#include <my_dir.h>
 
42
#include <hash.h>
 
43
#include <stdarg.h>
 
44
#include <violite.h>
52
45
#ifdef HAVE_SYS_WAIT_H
53
46
#include <sys/wait.h>
54
47
#endif
55
 
#include <cassert>
56
 
#include <sys/stat.h>
57
 
#include <sys/types.h>
58
 
#include <fcntl.h>
59
 
#include <boost/array.hpp>
60
 
#include <boost/foreach.hpp>
61
 
#include <boost/program_options.hpp>
62
 
#include <boost/smart_ptr.hpp>
63
 
 
64
 
#include PCRE_HEADER
65
 
 
66
 
#include <stdarg.h>
67
 
#include <boost/unordered_map.hpp>
68
 
 
69
 
/* Added this for string translation. */
70
 
#include <drizzled/gettext.h>
71
 
#include <drizzled/type/time.h>
72
 
#include <drizzled/charset.h>
73
 
#include <drizzled/typelib.h>
74
 
#include <drizzled/configmake.h>
75
 
 
76
 
#define PTR_BYTE_DIFF(A,B) (ptrdiff_t) (reinterpret_cast<const unsigned char*>(A) - reinterpret_cast<const unsigned char*>(B))
77
 
 
78
 
#ifndef DRIZZLE_RETURN_SERVER_GONE
79
 
#define DRIZZLE_RETURN_HANDSHAKE_FAILED DRIZZLE_RETURN_ERROR_CODE
80
 
#endif
81
 
namespace po= boost::program_options;
82
 
using namespace std;
83
 
using namespace drizzled;
84
 
 
85
 
extern "C"
86
 
unsigned char *get_var_key(const unsigned char* var, size_t *len, bool);
87
 
 
88
 
int get_one_option(int optid, const struct option *, char *argument);
 
48
 
 
49
 
89
50
 
90
51
#define MAX_VAR_NAME_LENGTH    256
91
52
#define MAX_COLUMNS            256
 
53
#define MAX_EMBEDDED_SERVER_ARGS 64
92
54
#define MAX_DELIMITER_LENGTH 16
 
55
 
93
56
/* Flags controlling send and reap */
94
57
#define QUERY_SEND_FLAG  1
95
58
#define QUERY_REAP_FLAG  2
96
59
 
97
 
typedef boost::unordered_map<std::string, uint32_t> ErrorCodes;
98
 
ErrorCodes global_error_names;
99
 
 
100
60
enum {
 
61
  OPT_SKIP_SAFEMALLOC=OPT_MAX_CLIENT_OPTION,
101
62
  OPT_PS_PROTOCOL, OPT_SP_PROTOCOL, OPT_CURSOR_PROTOCOL, OPT_VIEW_PROTOCOL,
102
 
  OPT_MAX_CONNECT_RETRIES, OPT_MARK_PROGRESS, OPT_LOG_DIR, OPT_TAIL_LINES,
103
 
  OPT_TESTDIR
 
63
  OPT_MAX_CONNECT_RETRIES, OPT_MARK_PROGRESS, OPT_LOG_DIR, OPT_TAIL_LINES
104
64
};
105
65
 
106
66
static int record= 0, opt_sleep= -1;
107
 
static char *opt_pass= NULL;
108
 
const char *unix_sock= NULL;
109
 
static uint32_t opt_port= 0;
110
 
static uint32_t opt_max_connect_retries;
111
 
static bool silent= false, verbose= false;
112
 
static bool opt_mark_progress= false;
113
 
static bool parsing_disabled= false;
114
 
static bool display_result_vertically= false,
115
 
  display_metadata= false, display_result_sorted= false;
116
 
static bool disable_query_log= false, disable_result_log= false;
117
 
static bool disable_warnings= false;
118
 
static bool disable_info= true;
119
 
static bool abort_on_error= true;
120
 
static bool server_initialized= false;
121
 
static bool is_windows= false;
122
 
static bool use_drizzle_protocol= false;
 
67
static char *opt_db= 0, *opt_pass= 0;
 
68
const char *opt_user= 0, *opt_host= 0, *unix_sock= 0, *opt_basedir= "./";
 
69
const char *opt_logdir= "";
 
70
const char *opt_include= 0, *opt_charsets_dir;
 
71
static int opt_port= 0;
 
72
static int opt_max_connect_retries;
 
73
static bool opt_compress= 0, silent= 0, verbose= 0;
 
74
static bool debug_info_flag= 0, debug_check_flag= 0;
 
75
static bool tty_password= 0;
 
76
static bool opt_mark_progress= 0;
 
77
static bool parsing_disabled= 0;
 
78
static bool display_result_vertically= FALSE,
 
79
  display_metadata= FALSE, display_result_sorted= FALSE;
 
80
static bool disable_query_log= 0, disable_result_log= 0;
 
81
static bool disable_warnings= 0;
 
82
static bool disable_info= 1;
 
83
static bool abort_on_error= 1;
 
84
static bool server_initialized= 0;
 
85
static bool is_windows= 0;
 
86
static char **default_argv;
 
87
static const char *load_default_groups[]= { "mysqltest", "client", 0 };
123
88
static char line_buffer[MAX_DELIMITER_LENGTH], *line_buffer_pos= line_buffer;
124
 
static void free_all_replace();
125
 
 
126
 
std::string opt_basedir,
127
 
  opt_charsets_dir,
128
 
  opt_db,
129
 
  opt_host,
130
 
  opt_include,
131
 
  opt_testdir,
132
 
  opt_logdir,
133
 
  password,
134
 
  opt_password,
135
 
  result_file_name,
136
 
  opt_user,
137
 
  opt_protocol;
138
 
 
139
 
static uint32_t start_lineno= 0; /* Start line of current command */
 
89
 
 
90
static uint start_lineno= 0; /* Start line of current command */
 
91
static uint my_end_arg= 0;
140
92
 
141
93
/* Number of lines of the result to include in failure report */
142
 
static uint32_t opt_tail_lines= 0;
 
94
static uint opt_tail_lines= 0;
143
95
 
144
96
static char delimiter[MAX_DELIMITER_LENGTH]= ";";
145
 
static uint32_t delimiter_length= 1;
 
97
static uint delimiter_length= 1;
146
98
 
147
99
static char TMPDIR[FN_REFLEN];
148
100
 
168
120
{
169
121
  FILE* file;
170
122
  const char *file_name;
171
 
  uint32_t lineno; /* Current line in file */
172
 
};
173
 
 
174
 
static boost::array<st_test_file, 16> file_stack;
175
 
static st_test_file* cur_file;
176
 
 
177
 
static const CHARSET_INFO *charset_info= &my_charset_utf8_general_ci; /* Default charset */
 
123
  uint lineno; /* Current line in file */
 
124
};
 
125
 
 
126
static struct st_test_file file_stack[16];
 
127
static struct st_test_file* cur_file;
 
128
static struct st_test_file* file_stack_end;
 
129
 
 
130
 
 
131
static CHARSET_INFO *charset_info= &my_charset_latin1; /* Default charset */
 
132
 
 
133
static const char *embedded_server_groups[]=
 
134
{
 
135
  "server",
 
136
  "embedded",
 
137
  "mysqltest_SERVER",
 
138
  NullS
 
139
};
 
140
 
 
141
static int embedded_server_arg_count=0;
 
142
static char *embedded_server_args[MAX_EMBEDDED_SERVER_ARGS];
178
143
 
179
144
/*
180
145
  Timer related variables
182
147
*/
183
148
static char *timer_file = NULL;
184
149
static uint64_t timer_start;
185
 
static void timer_output();
186
 
static uint64_t timer_now();
 
150
static void timer_output(void);
 
151
static uint64_t timer_now(void);
187
152
 
188
153
static uint64_t progress_start= 0;
189
154
 
190
 
vector<struct st_command*> q_lines;
 
155
DYNAMIC_ARRAY q_lines;
191
156
 
192
157
typedef struct {
193
158
  int read_lines,current_line;
197
162
typedef struct
198
163
{
199
164
  char file[FN_REFLEN];
200
 
  uint32_t pos;
 
165
  ulong pos;
201
166
} master_pos_st;
202
167
 
203
168
master_pos_st master_pos;
204
169
 
205
170
/* if set, all results are concated and compared against this file */
 
171
const char *result_file_name= 0;
206
172
 
207
 
class VAR
 
173
typedef struct st_var
208
174
{
209
 
public:
210
175
  char *name;
211
176
  int name_len;
212
177
  char *str_val;
216
181
  int int_dirty; /* do not update string if int is updated until first read */
217
182
  int alloced;
218
183
  char *env_s;
219
 
};
 
184
} VAR;
220
185
 
221
186
/*Perl/shell-like variable registers */
222
 
boost::array<VAR, 10> var_reg;
 
187
VAR var_reg[10];
223
188
 
224
 
typedef boost::unordered_map<string, VAR *> var_hash_t;
225
 
var_hash_t var_hash;
 
189
HASH var_hash;
226
190
 
227
191
struct st_connection
228
192
{
229
 
  drizzle_st *drizzle;
230
 
  drizzle_con_st con;
 
193
  MYSQL mysql;
231
194
  /* Used when creating views and sp, to avoid implicit commit */
232
 
  drizzle_con_st *util_con;
 
195
  MYSQL* util_mysql;
233
196
  char *name;
234
197
};
235
198
struct st_connection connections[128];
236
199
struct st_connection* cur_con= NULL, *next_con, *connections_end;
237
200
 
238
201
/*
239
 
  List of commands in drizzletest
 
202
  List of commands in mysqltest
240
203
  Must match the "command_names" array
241
204
  Add new commands before Q_UNKNOWN!
242
205
*/
243
206
enum enum_commands {
244
207
  Q_CONNECTION=1,     Q_QUERY,
245
 
  Q_CONNECT,      Q_SLEEP, Q_REAL_SLEEP,
246
 
  Q_INC,        Q_DEC,
247
 
  Q_SOURCE,      Q_DISCONNECT,
248
 
  Q_LET,        Q_ECHO,
249
 
  Q_WHILE,      Q_END_BLOCK,
250
 
  Q_SYSTEM,      Q_RESULT,
251
 
  Q_REQUIRE,      Q_SAVE_MASTER_POS,
 
208
  Q_CONNECT,        Q_SLEEP, Q_REAL_SLEEP,
 
209
  Q_INC,                    Q_DEC,
 
210
  Q_SOURCE,         Q_DISCONNECT,
 
211
  Q_LET,                    Q_ECHO,
 
212
  Q_WHILE,          Q_END_BLOCK,
 
213
  Q_SYSTEM,         Q_RESULT,
 
214
  Q_REQUIRE,        Q_SAVE_MASTER_POS,
252
215
  Q_SYNC_WITH_MASTER,
253
216
  Q_SYNC_SLAVE_WITH_MASTER,
254
217
  Q_ERROR,
255
 
  Q_SEND,        Q_REAP,
256
 
  Q_DIRTY_CLOSE,      Q_REPLACE, Q_REPLACE_COLUMN,
257
 
  Q_PING,        Q_EVAL,
 
218
  Q_SEND,                   Q_REAP,
 
219
  Q_DIRTY_CLOSE,            Q_REPLACE, Q_REPLACE_COLUMN,
 
220
  Q_PING,                   Q_EVAL,
258
221
  Q_EVAL_RESULT,
259
222
  Q_ENABLE_QUERY_LOG, Q_DISABLE_QUERY_LOG,
260
223
  Q_ENABLE_RESULT_LOG, Q_DISABLE_RESULT_LOG,
267
230
  Q_DISPLAY_VERTICAL_RESULTS, Q_DISPLAY_HORIZONTAL_RESULTS,
268
231
  Q_QUERY_VERTICAL, Q_QUERY_HORIZONTAL, Q_SORTED_RESULT,
269
232
  Q_START_TIMER, Q_END_TIMER,
270
 
  Q_CHARACTER_SET,
 
233
  Q_CHARACTER_SET, Q_DISABLE_PS_PROTOCOL, Q_ENABLE_PS_PROTOCOL,
271
234
  Q_DISABLE_RECONNECT, Q_ENABLE_RECONNECT,
272
235
  Q_IF,
273
236
  Q_DISABLE_PARSING, Q_ENABLE_PARSING,
276
239
  Q_CHMOD_FILE, Q_APPEND_FILE, Q_CAT_FILE, Q_DIFF_FILES,
277
240
  Q_SEND_QUIT, Q_CHANGE_USER, Q_MKDIR, Q_RMDIR,
278
241
 
279
 
  Q_UNKNOWN,             /* Unknown command.   */
280
 
  Q_COMMENT,             /* Comments, ignored. */
 
242
  Q_UNKNOWN,                           /* Unknown command.   */
 
243
  Q_COMMENT,                           /* Comments, ignored. */
281
244
  Q_COMMENT_WITH_COMMAND
282
245
};
283
246
 
349
312
  "copy_file",
350
313
  "perl",
351
314
  "die",
352
 
 
 
315
               
353
316
  /* Don't execute any more commands, compare result */
354
317
  "exit",
355
318
  "skip",
385
348
  enum match_err_type type;
386
349
  union
387
350
  {
388
 
    uint32_t errnum;
389
 
    char sqlstate[DRIZZLE_MAX_SQLSTATE_SIZE+1];  /* \0 terminated string */
 
351
    uint errnum;
 
352
    char sqlstate[SQLSTATE_LENGTH+1];  /* \0 terminated string */
390
353
  } code;
391
354
};
392
355
 
393
356
struct st_expected_errors
394
357
{
395
358
  struct st_match_err err[10];
396
 
  uint32_t count;
 
359
  uint count;
397
360
};
398
 
 
399
 
static st_expected_errors saved_expected_errors;
400
 
 
401
 
class st_command
 
361
static struct st_expected_errors saved_expected_errors;
 
362
 
 
363
struct st_command
402
364
{
403
 
public:
404
365
  char *query, *query_buf,*first_argument,*last_argument,*end;
405
366
  int first_word_len, query_len;
406
367
  bool abort_on_error;
407
 
  st_expected_errors expected_errors;
408
 
  string require_file;
409
 
  enum_commands type;
410
 
 
411
 
  st_command()
412
 
    : query(NULL), query_buf(NULL), first_argument(NULL), last_argument(NULL),
413
 
      end(NULL), first_word_len(0), query_len(0), abort_on_error(false),
414
 
      require_file(""), type(Q_CONNECTION)
415
 
  {
416
 
    memset(&expected_errors, 0, sizeof(st_expected_errors));
417
 
  }
418
 
 
419
 
  ~st_command()
420
 
  {
421
 
    free(query_buf);
422
 
  }
 
368
  struct st_expected_errors expected_errors;
 
369
  char require_file[FN_REFLEN];
 
370
  enum enum_commands type;
423
371
};
424
372
 
425
373
TYPELIB command_typelib= {array_elements(command_names),"",
426
 
                          command_names, 0};
 
374
                          command_names, 0};
427
375
 
428
 
string ds_res, ds_progress, ds_warning_messages;
 
376
DYNAMIC_STRING ds_res, ds_progress, ds_warning_messages;
429
377
 
430
378
char builtin_echo[FN_REFLEN];
431
379
 
432
380
void die(const char *fmt, ...)
433
 
  __attribute__((format(printf, 1, 2)));
 
381
  ATTRIBUTE_FORMAT(printf, 1, 2);
434
382
void abort_not_supported_test(const char *fmt, ...)
435
 
  __attribute__((format(printf, 1, 2)));
 
383
  ATTRIBUTE_FORMAT(printf, 1, 2);
436
384
void verbose_msg(const char *fmt, ...)
437
 
  __attribute__((format(printf, 1, 2)));
 
385
  ATTRIBUTE_FORMAT(printf, 1, 2);
438
386
void warning_msg(const char *fmt, ...)
439
 
  __attribute__((format(printf, 1, 2)));
 
387
  ATTRIBUTE_FORMAT(printf, 1, 2);
440
388
void log_msg(const char *fmt, ...)
441
 
  __attribute__((format(printf, 1, 2)));
 
389
  ATTRIBUTE_FORMAT(printf, 1, 2);
442
390
 
443
391
VAR* var_from_env(const char *, const char *);
444
392
VAR* var_init(VAR* v, const char *name, int name_len, const char *val,
445
393
              int val_len);
 
394
void var_free(void* v);
446
395
VAR* var_get(const char *var_name, const char** var_name_end,
447
396
             bool raw, bool ignore_not_existing);
448
397
void eval_expr(VAR* v, const char *p, const char** p_end);
449
 
bool match_delimiter(int c, const char *delim, uint32_t length);
 
398
bool match_delimiter(int c, const char *delim, uint length);
450
399
void dump_result_to_reject_file(char *buf, int size);
451
 
void dump_result_to_log_file(const char *buf, int size);
452
 
void dump_warning_messages();
453
 
void dump_progress();
 
400
void dump_result_to_log_file(char *buf, int size);
 
401
void dump_warning_messages(void);
 
402
void dump_progress(void);
454
403
 
455
 
void do_eval(string *query_eval, const char *query,
 
404
void do_eval(DYNAMIC_STRING *query_eval, const char *query,
456
405
             const char *query_end, bool pass_through_escape_chars);
457
 
void str_to_file(const char *fname, const char *str, int size);
458
 
void str_to_file2(const char *fname, const char *str, int size, bool append);
 
406
void str_to_file(const char *fname, char *str, int size);
 
407
void str_to_file2(const char *fname, char *str, int size, bool append);
459
408
 
460
409
/* For replace_column */
461
410
static char *replace_column[MAX_COLUMNS];
462
 
static uint32_t max_replace_column= 0;
 
411
static uint max_replace_column= 0;
463
412
void do_get_replace_column(struct st_command*);
464
 
void free_replace_column();
 
413
void free_replace_column(void);
465
414
 
466
415
/* For replace */
467
416
void do_get_replace(struct st_command *command);
468
 
void free_replace();
 
417
void free_replace(void);
469
418
 
470
419
/* For replace_regex */
471
420
void do_get_replace_regex(struct st_command *command);
472
 
 
473
 
void replace_append_mem(string *ds, const char *val,
474
 
                        int len);
475
 
void replace_append(string *ds, const char *val);
476
 
void replace_append_uint(string *ds, uint32_t val);
477
 
void append_sorted(string* ds, string* ds_input);
 
421
void free_replace_regex(void);
 
422
 
 
423
 
 
424
void free_all_replace(void);
 
425
 
 
426
 
 
427
void free_all_replace(void){
 
428
  free_replace();
 
429
  free_replace_regex();
 
430
  free_replace_column();
 
431
}
 
432
 
 
433
void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val,
 
434
                               int len);
 
435
void replace_dynstr_append(DYNAMIC_STRING *ds, const char *val);
 
436
void replace_dynstr_append_uint(DYNAMIC_STRING *ds, uint val);
 
437
void dynstr_append_sorted(DYNAMIC_STRING* ds, DYNAMIC_STRING* ds_input);
478
438
 
479
439
void handle_error(struct st_command*,
480
440
                  unsigned int err_errno, const char *err_error,
481
 
                  const char *err_sqlstate, string *ds);
 
441
                  const char *err_sqlstate, DYNAMIC_STRING *ds);
482
442
void handle_no_error(struct st_command*);
483
443
 
484
 
 
485
 
void do_eval(string *query_eval, const char *query,
 
444
#ifdef EMBEDDED_LIBRARY
 
445
 
 
446
/* attributes of the query thread */
 
447
pthread_attr_t cn_thd_attrib;
 
448
 
 
449
/*
 
450
  send_one_query executes query in separate thread, which is
 
451
  necessary in embedded library to run 'send' in proper way.
 
452
  This implementation doesn't handle errors returned
 
453
  by mysql_send_query. It's technically possible, though
 
454
  I don't see where it is needed.
 
455
*/
 
456
pthread_handler_t send_one_query(void *arg)
 
457
{
 
458
  struct st_connection *cn= (struct st_connection*)arg;
 
459
 
 
460
  mysql_thread_init();
 
461
  VOID(mysql_send_query(&cn->mysql, cn->cur_query, cn->cur_query_len));
 
462
 
 
463
  mysql_thread_end();
 
464
  pthread_mutex_lock(&cn->mutex);
 
465
  cn->query_done= 1;
 
466
  VOID(pthread_cond_signal(&cn->cond));
 
467
  pthread_mutex_unlock(&cn->mutex);
 
468
  pthread_exit(0);
 
469
  return 0;
 
470
}
 
471
 
 
472
static int do_send_query(struct st_connection *cn, const char *q, int q_len,
 
473
                         int flags)
 
474
{
 
475
  pthread_t tid;
 
476
 
 
477
  if (flags & QUERY_REAP_FLAG)
 
478
    return mysql_send_query(&cn->mysql, q, q_len);
 
479
 
 
480
  if (pthread_mutex_init(&cn->mutex, NULL) ||
 
481
      pthread_cond_init(&cn->cond, NULL))
 
482
    die("Error in the thread library");
 
483
 
 
484
  cn->cur_query= q;
 
485
  cn->cur_query_len= q_len;
 
486
  cn->query_done= 0;
 
487
  if (pthread_create(&tid, &cn_thd_attrib, send_one_query, (void*)cn))
 
488
    die("Cannot start new thread for query");
 
489
 
 
490
  return 0;
 
491
}
 
492
 
 
493
static void wait_query_thread_end(struct st_connection *con)
 
494
{
 
495
  if (!con->query_done)
 
496
  {
 
497
    pthread_mutex_lock(&con->mutex);
 
498
    while (!con->query_done)
 
499
      pthread_cond_wait(&con->cond, &con->mutex);
 
500
    pthread_mutex_unlock(&con->mutex);
 
501
  }
 
502
}
 
503
 
 
504
#else /*EMBEDDED_LIBRARY*/
 
505
 
 
506
#define do_send_query(cn,q,q_len,flags) mysql_send_query(&cn->mysql, q, q_len)
 
507
 
 
508
#endif /*EMBEDDED_LIBRARY*/
 
509
 
 
510
void do_eval(DYNAMIC_STRING *query_eval, const char *query,
486
511
             const char *query_end, bool pass_through_escape_chars)
487
512
{
488
 
  char c, next_c;
489
 
  int escaped = 0;
 
513
  const char *p;
 
514
  register char c, next_c;
 
515
  register int escaped = 0;
490
516
  VAR *v;
491
517
 
492
 
  for (const char *p= query; (c= *p) && p < query_end; ++p)
 
518
 
 
519
  for (p= query; (c= *p) && p < query_end; ++p)
493
520
  {
494
521
    switch(c) {
495
522
    case '$':
496
523
      if (escaped)
497
524
      {
498
 
        escaped= 0;
499
 
        query_eval->append(p, 1);
 
525
        escaped= 0;
 
526
        dynstr_append_mem(query_eval, p, 1);
500
527
      }
501
528
      else
502
529
      {
503
 
        if (!(v= var_get(p, &p, 0, 0)))
504
 
          die("Bad variable in eval");
505
 
        query_eval->append(v->str_val, v->str_val_len);
 
530
        if (!(v= var_get(p, &p, 0, 0)))
 
531
          die("Bad variable in eval");
 
532
        dynstr_append_mem(query_eval, v->str_val, v->str_val_len);
506
533
      }
507
534
      break;
508
535
    case '\\':
509
536
      next_c= *(p+1);
510
537
      if (escaped)
511
538
      {
512
 
        escaped= 0;
513
 
        query_eval->append(p, 1);
 
539
        escaped= 0;
 
540
        dynstr_append_mem(query_eval, p, 1);
514
541
      }
515
542
      else if (next_c == '\\' || next_c == '$' || next_c == '"')
516
543
      {
517
544
        /* Set escaped only if next char is \, " or $ */
518
 
        escaped= 1;
 
545
        escaped= 1;
519
546
 
520
547
        if (pass_through_escape_chars)
521
548
        {
522
549
          /* The escape char should be added to the output string. */
523
 
          query_eval->append(p, 1);
 
550
          dynstr_append_mem(query_eval, p, 1);
524
551
        }
525
552
      }
526
553
      else
527
 
        query_eval->append(p, 1);
 
554
        dynstr_append_mem(query_eval, p, 1);
528
555
      break;
529
556
    default:
530
557
      escaped= 0;
531
 
      query_eval->append(p, 1);
 
558
      dynstr_append_mem(query_eval, p, 1);
532
559
      break;
533
560
    }
534
561
  }
537
564
 
538
565
 
539
566
/*
540
 
  Concatenates any number of strings, escapes any OS quote in the result then
541
 
  surround the whole affair in another set of quotes which is finally appended
542
 
  to specified string.  This function is especially useful when
543
 
  building strings to be executed with the system() function.
544
 
 
545
 
  @param str string which will have addtional strings appended.
546
 
  @param append string to be appended.
547
 
  @param ... Optional. Additional string(s) to be appended.
548
 
 
549
 
  @note The final argument in the list must be NULL even if no additional
550
 
  options are passed.
551
 
*/
552
 
 
553
 
static void append_os_quoted(string *str, const char *append, ...)
554
 
{
555
 
  const char *quote_str= "\'";
556
 
  const uint32_t  quote_len= 1;
557
 
 
558
 
  va_list dirty_text;
559
 
 
560
 
  str->append(quote_str, quote_len); /* Leading quote */
561
 
  va_start(dirty_text, append);
562
 
  while (append != NULL)
563
 
  {
564
 
    const char  *cur_pos= append;
565
 
    const char *next_pos= cur_pos;
566
 
 
567
 
    /* Search for quote in each string and replace with escaped quote */
568
 
    while((next_pos= strrchr(cur_pos, quote_str[0])) != NULL)
569
 
    {
570
 
      str->append(cur_pos, next_pos - cur_pos);
571
 
      str->append("\\", 1);
572
 
      str->append(quote_str, quote_len);
573
 
      cur_pos= next_pos + 1;
574
 
    }
575
 
    str->append(cur_pos);
576
 
    append= va_arg(dirty_text, char *);
577
 
  }
578
 
  va_end(dirty_text);
579
 
  str->append(quote_str, quote_len); /* Trailing quote */
580
 
}
581
 
 
582
 
 
583
 
/*
584
567
  Run query and dump the result to stdout in vertical format
585
568
 
586
569
  NOTE! This function should be safe to call when an error
588
571
 
589
572
  SYNOPSIS
590
573
  show_query
591
 
  drizzle - connection to use
 
574
  mysql - connection to use
592
575
  query - query to run
593
576
 
594
577
*/
595
578
 
596
 
static void show_query(drizzle_con_st *con, const char* query)
 
579
static void show_query(MYSQL* mysql, const char* query)
597
580
{
598
 
  drizzle_result_st res;
599
 
  drizzle_return_t ret;
600
 
 
601
 
  if (!con)
 
581
  MYSQL_RES* res;
 
582
 
 
583
 
 
584
  if (!mysql)
602
585
    return;
603
586
 
604
 
  if (drizzle_query_str(con, &res, query, &ret) == NULL ||
605
 
      ret != DRIZZLE_RETURN_OK)
 
587
  if (mysql_query(mysql, query))
606
588
  {
607
 
    if (ret == DRIZZLE_RETURN_ERROR_CODE)
608
 
    {
609
 
      log_msg("Error running query '%s': %d %s",
610
 
              query, drizzle_result_error_code(&res),
611
 
              drizzle_result_error(&res));
612
 
      drizzle_result_free(&res);
613
 
    }
614
 
    else
615
 
    {
616
 
      log_msg("Error running query '%s': %d %s",
617
 
              query, ret, drizzle_con_error(con));
618
 
    }
 
589
    log_msg("Error running query '%s': %d %s",
 
590
            query, mysql_errno(mysql), mysql_error(mysql));
619
591
    return;
620
592
  }
621
593
 
622
 
  if (drizzle_result_column_count(&res) == 0 ||
623
 
      drizzle_result_buffer(&res) != DRIZZLE_RETURN_OK)
 
594
  if ((res= mysql_store_result(mysql)) == NULL)
624
595
  {
625
596
    /* No result set returned */
626
 
    drizzle_result_free(&res);
627
597
    return;
628
598
  }
629
599
 
630
600
  {
631
 
    drizzle_row_t row;
 
601
    MYSQL_ROW row;
632
602
    unsigned int i;
633
603
    unsigned int row_num= 0;
634
 
    unsigned int num_fields= drizzle_result_column_count(&res);
635
 
    drizzle_column_st *column;
 
604
    unsigned int num_fields= mysql_num_fields(res);
 
605
    MYSQL_FIELD *fields= mysql_fetch_fields(res);
636
606
 
637
607
    fprintf(stderr, "=== %s ===\n", query);
638
 
    while ((row= drizzle_row_next(&res)))
 
608
    while ((row= mysql_fetch_row(res)))
639
609
    {
640
 
      size_t *lengths= drizzle_row_field_sizes(&res);
 
610
      unsigned long *lengths= mysql_fetch_lengths(res);
641
611
      row_num++;
642
612
 
643
613
      fprintf(stderr, "---- %d. ----\n", row_num);
644
 
      drizzle_column_seek(&res, 0);
645
614
      for(i= 0; i < num_fields; i++)
646
615
      {
647
 
        column= drizzle_column_next(&res);
648
616
        fprintf(stderr, "%s\t%.*s\n",
649
 
                drizzle_column_name(column),
 
617
                fields[i].name,
650
618
                (int)lengths[i], row[i] ? row[i] : "NULL");
651
619
      }
652
620
    }
654
622
      fprintf(stderr, "=");
655
623
    fprintf(stderr, "\n\n");
656
624
  }
657
 
  drizzle_result_free(&res);
 
625
  mysql_free_result(res);
658
626
 
659
627
  return;
660
628
}
669
637
 
670
638
  SYNOPSIS
671
639
  show_warnings_before_error
672
 
  drizzle - connection to use
 
640
  mysql - connection to use
673
641
 
674
642
*/
675
643
 
676
 
static void show_warnings_before_error(drizzle_con_st *con)
 
644
static void show_warnings_before_error(MYSQL* mysql)
677
645
{
678
 
  drizzle_result_st res;
679
 
  drizzle_return_t ret;
 
646
  MYSQL_RES* res;
680
647
  const char* query= "SHOW WARNINGS";
681
648
 
682
 
  if (!con)
 
649
 
 
650
  if (!mysql)
683
651
    return;
684
652
 
685
 
  if (drizzle_query_str(con, &res, query, &ret) == NULL ||
686
 
      ret != DRIZZLE_RETURN_OK)
 
653
  if (mysql_query(mysql, query))
687
654
  {
688
 
    if (ret == DRIZZLE_RETURN_ERROR_CODE)
689
 
    {
690
 
      log_msg("Error running query '%s': %d %s",
691
 
              query, drizzle_result_error_code(&res),
692
 
              drizzle_result_error(&res));
693
 
      drizzle_result_free(&res);
694
 
    }
695
 
    else
696
 
    {
697
 
      log_msg("Error running query '%s': %d %s",
698
 
              query, ret, drizzle_con_error(con));
699
 
    }
 
655
    log_msg("Error running query '%s': %d %s",
 
656
            query, mysql_errno(mysql), mysql_error(mysql));
700
657
    return;
701
658
  }
702
659
 
703
 
  if (drizzle_result_column_count(&res) == 0 ||
704
 
      drizzle_result_buffer(&res) != DRIZZLE_RETURN_OK)
 
660
  if ((res= mysql_store_result(mysql)) == NULL)
705
661
  {
706
662
    /* No result set returned */
707
 
    drizzle_result_free(&res);
708
663
    return;
709
664
  }
710
665
 
711
 
  if (drizzle_result_row_count(&res) <= 1)
 
666
  if (mysql_num_rows(res) <= 1)
712
667
  {
713
668
    /* Don't display the last row, it's "last error" */
714
669
  }
715
670
  else
716
671
  {
717
 
    drizzle_row_t row;
 
672
    MYSQL_ROW row;
718
673
    unsigned int row_num= 0;
719
 
    unsigned int num_fields= drizzle_result_column_count(&res);
 
674
    unsigned int num_fields= mysql_num_fields(res);
720
675
 
721
676
    fprintf(stderr, "\nWarnings from just before the error:\n");
722
 
    while ((row= drizzle_row_next(&res)))
 
677
    while ((row= mysql_fetch_row(res)))
723
678
    {
724
 
      uint32_t i;
725
 
      size_t *lengths= drizzle_row_field_sizes(&res);
 
679
      unsigned int i;
 
680
      unsigned long *lengths= mysql_fetch_lengths(res);
726
681
 
727
 
      if (++row_num >= drizzle_result_row_count(&res))
 
682
      if (++row_num >= mysql_num_rows(res))
728
683
      {
729
684
        /* Don't display the last row, it's "last error" */
730
685
        break;
738
693
      fprintf(stderr, "\n");
739
694
    }
740
695
  }
741
 
  drizzle_result_free(&res);
 
696
  mysql_free_result(res);
742
697
 
743
698
  return;
744
699
}
754
709
  const char *argname;       /* Name of argument   */
755
710
  enum arg_type type;        /* Type of argument   */
756
711
  bool required;          /* Argument required  */
757
 
  string *ds;        /* Storage for argument */
 
712
  DYNAMIC_STRING *ds;        /* Storage for argument */
758
713
  const char *description;   /* Description of the argument */
759
714
};
760
715
 
771
726
  for (i= 0; i < num_args; i++)
772
727
  {
773
728
    const struct command_arg *arg= &args[i];
774
 
    arg->ds->clear();
775
729
 
776
 
    bool known_arg_type= true;
777
730
    switch (arg->type) {
778
731
      /* A string */
779
732
    case ARG_STRING:
786
739
        ptr++;
787
740
      if (ptr > start)
788
741
      {
789
 
        do_eval(arg->ds, start, ptr, false);
 
742
        init_dynamic_string(arg->ds, 0, ptr-start, 32);
 
743
        do_eval(arg->ds, start, ptr, FALSE);
790
744
      }
791
745
      else
792
746
      {
793
747
        /* Empty string */
794
 
        arg->ds->erase();
 
748
        init_dynamic_string(arg->ds, "", 0, 0);
795
749
      }
796
750
      command->last_argument= (char*)ptr;
797
751
 
803
757
      /* Rest of line */
804
758
    case ARG_REST:
805
759
      start= ptr;
806
 
      do_eval(arg->ds, start, command->end, false);
 
760
      init_dynamic_string(arg->ds, 0, command->query_len, 256);
 
761
      do_eval(arg->ds, start, command->end, FALSE);
807
762
      command->last_argument= command->end;
808
763
      break;
809
764
 
810
765
    default:
811
 
      known_arg_type= false;
 
766
      assert("Unknown argument type");
812
767
      break;
813
768
    }
814
 
    assert(known_arg_type);
815
769
 
816
770
    /* Check required arg */
817
 
    if (arg->ds->length() == 0 && arg->required)
 
771
    if (arg->ds->length == 0 && arg->required)
818
772
      die("Missing required argument '%s' to command '%.*s'", arg->argname,
819
773
          command->first_word_len, command->query);
820
774
 
832
786
}
833
787
 
834
788
 
835
 
static void handle_command_error(struct st_command *command, uint32_t error)
 
789
static void handle_command_error(struct st_command *command, uint error)
836
790
{
 
791
 
837
792
  if (error != 0)
838
793
  {
839
 
    uint32_t i;
 
794
    uint i;
840
795
 
841
796
    if (command->abort_on_error)
842
797
      die("command \"%.*s\" failed with error %d",
860
815
        command->first_word_len, command->query,
861
816
        command->expected_errors.err[0].code.errnum);
862
817
  }
 
818
  return;
863
819
}
864
820
 
865
821
 
866
 
static void close_connections()
 
822
static void close_connections(void)
867
823
{
 
824
 
868
825
  for (--next_con; next_con >= connections; --next_con)
869
826
  {
870
 
    if (next_con->drizzle != NULL)
871
 
    {
872
 
      drizzle_free(next_con->drizzle);
873
 
      next_con->drizzle= NULL;
874
 
    }
875
 
    free(next_con->name);
 
827
    mysql_close(&next_con->mysql);
 
828
    if (next_con->util_mysql)
 
829
      mysql_close(next_con->util_mysql);
 
830
    my_free(next_con->name, MYF(MY_ALLOW_ZERO_PTR));
876
831
  }
 
832
  return;
877
833
}
878
834
 
879
835
 
880
 
static void close_files()
 
836
static void close_files(void)
881
837
{
882
 
  for (; cur_file >= file_stack.data(); cur_file--)
 
838
 
 
839
  for (; cur_file >= file_stack; cur_file--)
883
840
  {
884
841
    if (cur_file->file && cur_file->file != stdin)
885
 
      fclose(cur_file->file);
886
 
    free(const_cast<char*>(cur_file->file_name));
 
842
    {
 
843
      my_fclose(cur_file->file, MYF(0));
 
844
    }
 
845
    my_free((uchar*) cur_file->file_name, MYF(MY_ALLOW_ZERO_PTR));
887
846
    cur_file->file_name= 0;
888
847
  }
 
848
  return;
889
849
}
890
850
 
891
 
static void free_used_memory()
 
851
 
 
852
static void free_used_memory(void)
892
853
{
 
854
  uint i;
 
855
 
 
856
 
893
857
  close_connections();
894
858
  close_files();
895
 
  BOOST_FOREACH(var_hash_t::reference i, var_hash)
 
859
  hash_free(&var_hash);
 
860
 
 
861
  for (i= 0 ; i < q_lines.elements ; i++)
896
862
  {
897
 
    free(i.second->str_val);
898
 
    free(i.second->env_s);
899
 
    if (i.second->alloced)
900
 
      free(i.second);
 
863
    struct st_command **q= dynamic_element(&q_lines, i, struct st_command**);
 
864
    my_free((*q)->query_buf,MYF(MY_ALLOW_ZERO_PTR));
 
865
    my_free((*q),MYF(0));
901
866
  }
902
 
  var_hash.clear();
903
 
  BOOST_FOREACH(vector<st_command*>::reference i, q_lines)
904
 
    delete i;
905
 
  for (size_t i= 0; i < var_reg.size(); i++)
 
867
  for (i= 0; i < 10; i++)
906
868
  {
907
869
    if (var_reg[i].alloced_len)
908
 
      free(var_reg[i].str_val);
 
870
      my_free(var_reg[i].str_val, MYF(MY_WME));
909
871
  }
 
872
  while (embedded_server_arg_count > 1)
 
873
    my_free(embedded_server_args[--embedded_server_arg_count],MYF(0));
 
874
  delete_dynamic(&q_lines);
 
875
  dynstr_free(&ds_res);
 
876
  dynstr_free(&ds_progress);
 
877
  dynstr_free(&ds_warning_messages);
910
878
  free_all_replace();
911
 
  free(opt_pass);
 
879
  my_free(opt_pass,MYF(MY_ALLOW_ZERO_PTR));
 
880
  free_defaults(default_argv);
 
881
 
 
882
  /* Only call mysql_server_end if mysql_server_init has been called */
 
883
  if (server_initialized)
 
884
    mysql_server_end();
 
885
 
 
886
  return;
912
887
}
913
888
 
914
889
 
915
890
static void cleanup_and_exit(int exit_code)
916
891
{
917
892
  free_used_memory();
918
 
  internal::my_end();
 
893
  my_end(my_end_arg);
919
894
 
920
895
  if (!silent) {
921
896
    switch (exit_code) {
927
902
      break;
928
903
    case 62:
929
904
      printf("skipped\n");
930
 
      break;
 
905
    break;
931
906
    default:
932
907
      printf("unknown exit code: %d\n", exit_code);
933
908
      assert(0);
934
909
    }
935
910
  }
 
911
 
936
912
  exit(exit_code);
937
913
}
938
914
 
951
927
  dying= 1;
952
928
 
953
929
  /* Print the error message */
954
 
  fprintf(stderr, "drizzletest: ");
955
 
  if (cur_file && cur_file != file_stack.data())
 
930
  fprintf(stderr, "mysqltest: ");
 
931
  if (cur_file && cur_file != file_stack)
956
932
    fprintf(stderr, "In included file \"%s\": ",
957
933
            cur_file->file_name);
958
934
  if (start_lineno > 0)
969
945
  fflush(stderr);
970
946
 
971
947
  /* Show results from queries just before failure */
972
 
  if (ds_res.length() && opt_tail_lines)
 
948
  if (ds_res.length && opt_tail_lines)
973
949
  {
974
950
    int tail_lines= opt_tail_lines;
975
 
    const char* show_from= ds_res.c_str() + ds_res.length() - 1;
976
 
    while(show_from > ds_res.c_str() && tail_lines > 0 )
 
951
    char* show_from= ds_res.str + ds_res.length - 1;
 
952
    while(show_from > ds_res.str && tail_lines > 0 )
977
953
    {
978
954
      show_from--;
979
955
      if (*show_from == '\n')
980
956
        tail_lines--;
981
957
    }
982
958
    fprintf(stderr, "\nThe result from queries just before the failure was:\n");
983
 
    if (show_from > ds_res.c_str())
 
959
    if (show_from > ds_res.str)
984
960
      fprintf(stderr, "< snip >");
985
961
    fprintf(stderr, "%s", show_from);
986
962
    fflush(stderr);
987
963
  }
988
964
 
989
965
  /* Dump the result that has been accumulated so far to .log file */
990
 
  if (! result_file_name.empty() && ds_res.length())
991
 
    dump_result_to_log_file(ds_res.c_str(), ds_res.length());
 
966
  if (result_file_name && ds_res.length)
 
967
    dump_result_to_log_file(ds_res.str, ds_res.length);
992
968
 
993
969
  /* Dump warning messages */
994
 
  if (! result_file_name.empty() && ds_warning_messages.length())
 
970
  if (result_file_name && ds_warning_messages.length)
995
971
    dump_warning_messages();
996
972
 
997
973
  /*
999
975
    been produced prior to the error
1000
976
  */
1001
977
  if (cur_con)
1002
 
    show_warnings_before_error(&cur_con->con);
 
978
    show_warnings_before_error(&cur_con->mysql);
1003
979
 
1004
980
  cleanup_and_exit(1);
1005
981
}
1013
989
 
1014
990
  /* Print include filestack */
1015
991
  fprintf(stderr, "The test '%s' is not supported by this installation\n",
1016
 
          file_stack[0].file_name);
 
992
          file_stack->file_name);
1017
993
  fprintf(stderr, "Detected in file %s at line %d\n",
1018
994
          err_file->file_name, err_file->lineno);
1019
 
  while (err_file != file_stack.data())
 
995
  while (err_file != file_stack)
1020
996
  {
1021
997
    err_file--;
1022
998
    fprintf(stderr, "included from %s at line %d\n",
1046
1022
    return;
1047
1023
 
1048
1024
  va_start(args, fmt);
1049
 
  fprintf(stderr, "drizzletest: ");
1050
 
  if (cur_file && cur_file != file_stack.data())
 
1025
  fprintf(stderr, "mysqltest: ");
 
1026
  if (cur_file && cur_file != file_stack)
1051
1027
    fprintf(stderr, "In included file \"%s\": ",
1052
1028
            cur_file->file_name);
1053
1029
  if (start_lineno != 0)
1055
1031
  vfprintf(stderr, fmt, args);
1056
1032
  fprintf(stderr, "\n");
1057
1033
  va_end(args);
 
1034
 
 
1035
  return;
1058
1036
}
1059
1037
 
1060
1038
 
1066
1044
 
1067
1045
 
1068
1046
  va_start(args, fmt);
1069
 
  ds_warning_messages.append("drizzletest: ");
 
1047
  dynstr_append(&ds_warning_messages, "mysqltest: ");
1070
1048
  if (start_lineno != 0)
1071
1049
  {
1072
 
    ds_warning_messages.append("Warning detected ");
1073
 
    if (cur_file && cur_file != file_stack.data())
 
1050
    dynstr_append(&ds_warning_messages, "Warning detected ");
 
1051
    if (cur_file && cur_file != file_stack)
1074
1052
    {
1075
1053
      len= snprintf(buff, sizeof(buff), "in included file %s ",
1076
 
                    cur_file->file_name);
1077
 
      ds_warning_messages.append(buff, len);
 
1054
                       cur_file->file_name);
 
1055
      dynstr_append_mem(&ds_warning_messages,
 
1056
                        buff, len);
1078
1057
    }
1079
1058
    len= snprintf(buff, sizeof(buff), "at line %d: ",
1080
 
                  start_lineno);
1081
 
    ds_warning_messages.append(buff, len);
 
1059
                     start_lineno);
 
1060
    dynstr_append_mem(&ds_warning_messages,
 
1061
                      buff, len);
1082
1062
  }
1083
1063
 
1084
1064
  len= vsnprintf(buff, sizeof(buff), fmt, args);
1085
 
  ds_warning_messages.append(buff, len);
 
1065
  dynstr_append_mem(&ds_warning_messages, buff, len);
1086
1066
 
1087
 
  ds_warning_messages.append("\n");
 
1067
  dynstr_append(&ds_warning_messages, "\n");
1088
1068
  va_end(args);
1089
1069
 
1090
1070
  return;
1102
1082
  len= vsnprintf(buff, sizeof(buff)-1, fmt, args);
1103
1083
  va_end(args);
1104
1084
 
1105
 
  ds_res.append(buff, len);
1106
 
  ds_res.append("\n");
 
1085
  dynstr_append_mem(&ds_res, buff, len);
 
1086
  dynstr_append(&ds_res, "\n");
1107
1087
 
1108
1088
  return;
1109
1089
}
1119
1099
 
1120
1100
*/
1121
1101
 
1122
 
static void cat_file(string* ds, const char* filename)
 
1102
static void cat_file(DYNAMIC_STRING* ds, const char* filename)
1123
1103
{
1124
1104
  int fd;
1125
 
  uint32_t len;
 
1105
  uint len;
1126
1106
  char buff[512];
1127
1107
 
1128
 
  if ((fd= internal::my_open(filename, O_RDONLY, MYF(0))) < 0)
 
1108
  if ((fd= my_open(filename, O_RDONLY, MYF(0))) < 0)
1129
1109
    die("Failed to open file '%s'", filename);
1130
 
  while((len= internal::my_read(fd, (unsigned char*)&buff,
 
1110
  while((len= my_read(fd, (uchar*)&buff,
1131
1111
                      sizeof(buff), MYF(0))) > 0)
1132
1112
  {
1133
1113
    char *p= buff, *start= buff;
1139
1119
        /* Add fake newline instead of cr and output the line */
1140
1120
        *p= '\n';
1141
1121
        p++; /* Step past the "fake" newline */
1142
 
        ds->append(start, p-start);
 
1122
        dynstr_append_mem(ds, start, p-start);
1143
1123
        p++; /* Step past the "fake" newline */
1144
1124
        start= p;
1145
1125
      }
1146
1126
      else
1147
1127
        p++;
1148
1128
    }
1149
 
    /* Output any chars that might be left */
1150
 
    ds->append(start, p-start);
 
1129
    /* Output any chars that migh be left */
 
1130
    dynstr_append_mem(ds, start, p-start);
1151
1131
  }
1152
 
  internal::my_close(fd, MYF(0));
 
1132
  my_close(fd, MYF(0));
1153
1133
}
1154
1134
 
1155
1135
 
1159
1139
  SYNOPSIS
1160
1140
  run_command
1161
1141
  cmd - command to execute(should be properly quoted
1162
 
  result - pointer to string where to store the result
 
1142
  ds_res- pointer to dynamic string where to store the result
1163
1143
 
1164
1144
*/
1165
1145
 
1166
 
static int run_command(const char * cmd, string * result)
 
1146
static int run_command(char* cmd,
 
1147
                       DYNAMIC_STRING *ds_res)
1167
1148
{
1168
 
  assert(result!=NULL);
1169
1149
  char buf[512]= {0};
1170
1150
  FILE *res_file;
1171
1151
  int error;
1175
1155
 
1176
1156
  while (fgets(buf, sizeof(buf), res_file))
1177
1157
  {
1178
 
    /* Save the output of this command in the supplied string */
1179
 
    result->append(buf);
 
1158
    if(ds_res)
 
1159
    {
 
1160
      /* Save the output of this command in the supplied string */
 
1161
      dynstr_append(ds_res, buf);
 
1162
    }
 
1163
    else
 
1164
    {
 
1165
      /* Print it directly on screen */
 
1166
      fprintf(stdout, "%s", buf);
 
1167
    }
1180
1168
  }
1181
1169
 
1182
1170
  error= pclose(res_file);
1190
1178
  SYNOPSIS
1191
1179
  run_tool
1192
1180
  tool_path - the name of the tool to run
1193
 
  result - pointer to dynamic string where to store the result
 
1181
  ds_res - pointer to dynamic string where to store the result
1194
1182
  ... - variable number of arguments that will be properly
1195
 
  quoted and appended after the tool's name
 
1183
        quoted and appended after the tool's name
1196
1184
 
1197
1185
*/
1198
1186
 
1199
 
static int run_tool(const char *tool_path, string * result, ...)
 
1187
static int run_tool(const char *tool_path, DYNAMIC_STRING *ds_res, ...)
1200
1188
{
1201
1189
  int ret;
1202
1190
  const char* arg;
1203
1191
  va_list args;
1204
 
  string ds_cmdline;
1205
 
 
1206
 
 
1207
 
  append_os_quoted(&ds_cmdline, tool_path, NULL);
1208
 
  ds_cmdline.append(" ");
1209
 
 
1210
 
  va_start(args, result);
 
1192
  DYNAMIC_STRING ds_cmdline;
 
1193
 
 
1194
  if (init_dynamic_string(&ds_cmdline, "", FN_REFLEN, FN_REFLEN))
 
1195
    die("Out of memory");
 
1196
 
 
1197
  dynstr_append_os_quoted(&ds_cmdline, tool_path, NullS);
 
1198
  dynstr_append(&ds_cmdline, " ");
 
1199
 
 
1200
  va_start(args, ds_res);
1211
1201
 
1212
1202
  while ((arg= va_arg(args, char *)))
1213
1203
  {
1214
1204
    /* Options should be os quoted */
1215
1205
    if (strncmp(arg, "--", 2) == 0)
1216
 
      append_os_quoted(&ds_cmdline, arg, NULL);
 
1206
      dynstr_append_os_quoted(&ds_cmdline, arg, NullS);
1217
1207
    else
1218
 
      ds_cmdline.append(arg);
1219
 
    ds_cmdline.append(" ");
 
1208
      dynstr_append(&ds_cmdline, arg);
 
1209
    dynstr_append(&ds_cmdline, " ");
1220
1210
  }
1221
1211
 
1222
1212
  va_end(args);
1223
1213
 
1224
 
  ret= run_command(ds_cmdline.c_str(), result);
 
1214
  ret= run_command(ds_cmdline.str, ds_res);
 
1215
  dynstr_free(&ds_cmdline);
1225
1216
  return(ret);
1226
1217
}
1227
1218
 
1239
1230
 
1240
1231
*/
1241
1232
 
1242
 
static void show_diff(string* ds,
 
1233
static void show_diff(DYNAMIC_STRING* ds,
1243
1234
                      const char* filename1, const char* filename2)
1244
1235
{
1245
1236
 
1246
 
  string ds_tmp;
 
1237
  DYNAMIC_STRING ds_tmp;
 
1238
 
 
1239
  if (init_dynamic_string(&ds_tmp, "", 256, 256))
 
1240
    die("Out of memory");
1247
1241
 
1248
1242
  /* First try with unified diff */
1249
1243
  if (run_tool("diff",
1254
1248
               "2>&1",
1255
1249
               NULL) > 1) /* Most "diff" tools return >1 if error */
1256
1250
  {
 
1251
    dynstr_set(&ds_tmp, "");
1257
1252
 
1258
1253
    /* Fallback to context diff with "diff -c" */
1259
1254
    if (run_tool("diff",
1268
1263
        Fallback to dump both files to result file and inform
1269
1264
        about installing "diff"
1270
1265
      */
1271
 
      ds_tmp.clear();
1272
 
 
1273
 
      ds_tmp.append(
1274
 
                    "\n"
1275
 
                    "The two files differ but it was not possible to execute 'diff' in\n"
1276
 
                    "order to show only the difference, tried both 'diff -u' or 'diff -c'.\n"
1277
 
                    "Instead the whole content of the two files was shown for you to diff manually. ;)\n\n"
1278
 
                    "To get a better report you should install 'diff' on your system, which you\n"
1279
 
                    "for example can get from http://www.gnu.org/software/diffutils/diffutils.html\n"
1280
 
                    "\n");
1281
 
 
1282
 
      ds_tmp.append(" --- ");
1283
 
      ds_tmp.append(filename1);
1284
 
      ds_tmp.append(" >>>\n");
 
1266
      dynstr_set(&ds_tmp, "");
 
1267
 
 
1268
      dynstr_append(&ds_tmp,
 
1269
"\n"
 
1270
"The two files differ but it was not possible to execute 'diff' in\n"
 
1271
"order to show only the difference, tried both 'diff -u' or 'diff -c'.\n"
 
1272
"Instead the whole content of the two files was shown for you to diff manually. ;)\n\n"
 
1273
"To get a better report you should install 'diff' on your system, which you\n"
 
1274
"for example can get from http://www.gnu.org/software/diffutils/diffutils.html\n"
 
1275
"\n");
 
1276
 
 
1277
      dynstr_append(&ds_tmp, " --- ");
 
1278
      dynstr_append(&ds_tmp, filename1);
 
1279
      dynstr_append(&ds_tmp, " >>>\n");
1285
1280
      cat_file(&ds_tmp, filename1);
1286
 
      ds_tmp.append("<<<\n --- ");
1287
 
      ds_tmp.append(filename1);
1288
 
      ds_tmp.append(" >>>\n");
 
1281
      dynstr_append(&ds_tmp, "<<<\n --- ");
 
1282
      dynstr_append(&ds_tmp, filename1);
 
1283
      dynstr_append(&ds_tmp, " >>>\n");
1289
1284
      cat_file(&ds_tmp, filename2);
1290
 
      ds_tmp.append("<<<<\n");
 
1285
      dynstr_append(&ds_tmp, "<<<<\n");
1291
1286
    }
1292
1287
  }
1293
1288
 
1294
1289
  if (ds)
1295
1290
  {
1296
1291
    /* Add the diff to output */
1297
 
    ds->append(ds_tmp.c_str(), ds_tmp.length());
 
1292
    dynstr_append_mem(ds, ds_tmp.str, ds_tmp.length);
1298
1293
  }
1299
1294
  else
1300
1295
  {
1301
1296
    /* Print diff directly to stdout */
1302
 
    fprintf(stderr, "%s\n", ds_tmp.c_str());
 
1297
    fprintf(stderr, "%s\n", ds_tmp.str);
1303
1298
  }
 
1299
 
 
1300
  dynstr_free(&ds_tmp);
1304
1301
 
1305
1302
}
1306
1303
 
1307
1304
 
1308
1305
enum compare_files_result_enum {
1309
 
  RESULT_OK= 0,
1310
 
  RESULT_CONTENT_MISMATCH= 1,
1311
 
  RESULT_LENGTH_MISMATCH= 2
 
1306
   RESULT_OK= 0,
 
1307
   RESULT_CONTENT_MISMATCH= 1,
 
1308
   RESULT_LENGTH_MISMATCH= 2
1312
1309
};
1313
1310
 
1314
1311
/*
1325
1322
 
1326
1323
*/
1327
1324
 
1328
 
static int compare_files2(int fd, const char* filename2)
 
1325
static int compare_files2(File fd, const char* filename2)
1329
1326
{
1330
1327
  int error= RESULT_OK;
1331
 
  int fd2;
1332
 
  uint32_t len, len2;
 
1328
  File fd2;
 
1329
  uint len, len2;
1333
1330
  char buff[512], buff2[512];
1334
 
  const char *fname= filename2;
1335
 
  string tmpfile;
1336
1331
 
1337
 
  if ((fd2= internal::my_open(fname, O_RDONLY, MYF(0))) < 0)
 
1332
  if ((fd2= my_open(filename2, O_RDONLY, MYF(0))) < 0)
1338
1333
  {
1339
 
    internal::my_close(fd, MYF(0));
1340
 
    if (! opt_testdir.empty())
1341
 
    {
1342
 
      tmpfile= opt_testdir;
1343
 
      if (tmpfile[tmpfile.length()] != '/')
1344
 
        tmpfile.append("/");
1345
 
      tmpfile.append(filename2);
1346
 
      fname= tmpfile.c_str();
1347
 
    }
1348
 
    if ((fd2= internal::my_open(fname, O_RDONLY, MYF(0))) < 0)
1349
 
    {
1350
 
      internal::my_close(fd, MYF(0));
1351
 
    
1352
 
      die("Failed to open second file: '%s'", fname);
1353
 
    }
 
1334
    my_close(fd, MYF(0));
 
1335
    die("Failed to open second file: '%s'", filename2);
1354
1336
  }
1355
 
  while((len= internal::my_read(fd, (unsigned char*)&buff,
 
1337
  while((len= my_read(fd, (uchar*)&buff,
1356
1338
                      sizeof(buff), MYF(0))) > 0)
1357
1339
  {
1358
 
    if ((len2= internal::my_read(fd2, (unsigned char*)&buff2,
 
1340
    if ((len2= my_read(fd2, (uchar*)&buff2,
1359
1341
                       sizeof(buff2), MYF(0))) < len)
1360
1342
    {
1361
1343
      /* File 2 was smaller */
1375
1357
      break;
1376
1358
    }
1377
1359
  }
1378
 
  if (!error && internal::my_read(fd2, (unsigned char*)&buff2,
 
1360
  if (!error && my_read(fd2, (uchar*)&buff2,
1379
1361
                        sizeof(buff2), MYF(0)) > 0)
1380
1362
  {
1381
1363
    /* File 1 was smaller */
1382
1364
    error= RESULT_LENGTH_MISMATCH;
1383
1365
  }
1384
1366
 
1385
 
  internal::my_close(fd2, MYF(0));
 
1367
  my_close(fd2, MYF(0));
1386
1368
 
1387
1369
  return error;
1388
1370
}
1403
1385
 
1404
1386
static int compare_files(const char* filename1, const char* filename2)
1405
1387
{
1406
 
  int fd;
 
1388
  File fd;
1407
1389
  int error;
1408
1390
 
1409
 
  if ((fd= internal::my_open(filename1, O_RDONLY, MYF(0))) < 0)
 
1391
  if ((fd= my_open(filename1, O_RDONLY, MYF(0))) < 0)
1410
1392
    die("Failed to open first file: '%s'", filename1);
1411
1393
 
1412
1394
  error= compare_files2(fd, filename2);
1413
1395
 
1414
 
  internal::my_close(fd, MYF(0));
 
1396
  my_close(fd, MYF(0));
1415
1397
 
1416
1398
  return error;
1417
1399
}
1421
1403
  Compare content of the string in ds to content of file fname
1422
1404
 
1423
1405
  SYNOPSIS
1424
 
  string_cmp
 
1406
  dyn_string_cmp
1425
1407
  ds - Dynamic string containing the string o be compared
1426
1408
  fname - Name of file to compare with
1427
1409
 
1429
1411
  See 'compare_files2'
1430
1412
*/
1431
1413
 
1432
 
static int string_cmp(string* ds, const char *fname)
 
1414
static int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname)
1433
1415
{
1434
1416
  int error;
1435
 
  int fd;
 
1417
  File fd;
1436
1418
  char temp_file_path[FN_REFLEN];
1437
1419
 
1438
 
  if ((fd= internal::create_temp_file(temp_file_path, TMPDIR,
1439
 
                            "tmp", MYF(MY_WME))) < 0)
 
1420
  if ((fd= create_temp_file(temp_file_path, NULL,
 
1421
                            "tmp", O_CREAT | O_SHARE | O_RDWR,
 
1422
                            MYF(MY_WME))) < 0)
1440
1423
    die("Failed to create temporary file for ds");
1441
1424
 
1442
1425
  /* Write ds to temporary file and set file pos to beginning*/
1443
 
  if (internal::my_write(fd, (unsigned char *) ds->c_str(), ds->length(),
 
1426
  if (my_write(fd, (uchar *) ds->str, ds->length,
1444
1427
               MYF(MY_FNABP | MY_WME)) ||
1445
 
      lseek(fd, 0, SEEK_SET) == MY_FILEPOS_ERROR)
 
1428
      my_seek(fd, 0, SEEK_SET, MYF(0)) == MY_FILEPOS_ERROR)
1446
1429
  {
1447
 
    internal::my_close(fd, MYF(0));
 
1430
    my_close(fd, MYF(0));
1448
1431
    /* Remove the temporary file */
1449
 
    internal::my_delete(temp_file_path, MYF(0));
 
1432
    my_delete(temp_file_path, MYF(0));
1450
1433
    die("Failed to write file '%s'", temp_file_path);
1451
1434
  }
1452
1435
 
1453
1436
  error= compare_files2(fd, fname);
1454
1437
 
1455
 
  internal::my_close(fd, MYF(0));
 
1438
  my_close(fd, MYF(0));
1456
1439
  /* Remove the temporary file */
1457
 
  internal::my_delete(temp_file_path, MYF(0));
 
1440
  my_delete(temp_file_path, MYF(0));
1458
1441
 
1459
1442
  return(error);
1460
1443
}
1472
1455
 
1473
1456
*/
1474
1457
 
1475
 
static void check_result(string* ds)
 
1458
static void check_result(DYNAMIC_STRING* ds)
1476
1459
{
1477
1460
  const char* mess= "Result content mismatch\n";
1478
1461
 
1479
1462
 
1480
 
  assert(result_file_name.c_str());
1481
 
 
1482
 
  if (access(result_file_name.c_str(), F_OK) != 0)
1483
 
    die("The specified result file does not exist: '%s'", result_file_name.c_str());
1484
 
 
1485
 
  switch (string_cmp(ds, result_file_name.c_str())) {
 
1463
  assert(result_file_name);
 
1464
 
 
1465
  if (access(result_file_name, F_OK) != 0)
 
1466
    die("The specified result file does not exist: '%s'", result_file_name);
 
1467
 
 
1468
  switch (dyn_string_cmp(ds, result_file_name)) {
1486
1469
  case RESULT_OK:
1487
1470
    break; /* ok */
1488
1471
  case RESULT_LENGTH_MISMATCH:
1496
1479
    */
1497
1480
    char reject_file[FN_REFLEN];
1498
1481
    size_t reject_length;
1499
 
    internal::dirname_part(reject_file, result_file_name.c_str(), &reject_length);
 
1482
    dirname_part(reject_file, result_file_name, &reject_length);
1500
1483
 
1501
1484
    if (access(reject_file, W_OK) == 0)
1502
1485
    {
1503
1486
      /* Result file directory is writable, save reject file there */
1504
 
      internal::fn_format(reject_file, result_file_name.c_str(), NULL,
 
1487
      fn_format(reject_file, result_file_name, NULL,
1505
1488
                ".reject", MY_REPLACE_EXT);
1506
1489
    }
1507
1490
    else
1508
1491
    {
1509
1492
      /* Put reject file in opt_logdir */
1510
 
      internal::fn_format(reject_file, result_file_name.c_str(), opt_logdir.c_str(),
 
1493
      fn_format(reject_file, result_file_name, opt_logdir,
1511
1494
                ".reject", MY_REPLACE_DIR | MY_REPLACE_EXT);
1512
1495
    }
1513
 
    str_to_file(reject_file, ds->c_str(), ds->length());
1514
 
 
1515
 
    ds->erase(); /* Don't create a .log file */
1516
 
 
1517
 
    show_diff(NULL, result_file_name.c_str(), reject_file);
1518
 
    die("%s",mess);
 
1496
    str_to_file(reject_file, ds->str, ds->length);
 
1497
 
 
1498
    dynstr_set(ds, NULL); /* Don't create a .log file */
 
1499
 
 
1500
    show_diff(NULL, result_file_name, reject_file);
 
1501
    die(mess);
1519
1502
    break;
1520
1503
  }
1521
1504
  default: /* impossible */
1541
1524
 
1542
1525
*/
1543
1526
 
1544
 
static void check_require(string* ds, const string &fname)
 
1527
static void check_require(DYNAMIC_STRING* ds, const char *fname)
1545
1528
{
1546
1529
 
1547
1530
 
1548
 
  if (string_cmp(ds, fname.c_str()))
 
1531
  if (dyn_string_cmp(ds, fname))
1549
1532
  {
1550
1533
    char reason[FN_REFLEN];
1551
 
    internal::fn_format(reason, fname.c_str(), "", "", MY_REPLACE_EXT | MY_REPLACE_DIR);
 
1534
    fn_format(reason, fname, "", "", MY_REPLACE_EXT | MY_REPLACE_DIR);
1552
1535
    abort_not_supported_test("Test requires: '%s'", reason);
1553
1536
  }
1554
1537
  return;
1556
1539
 
1557
1540
 
1558
1541
/*
1559
 
  Remove surrounding chars from string
 
1542
   Remove surrounding chars from string
1560
1543
 
1561
 
  Return 1 if first character is found but not last
 
1544
   Return 1 if first character is found but not last
1562
1545
*/
1563
1546
static int strip_surrounding(char* str, char c1, char c2)
1564
1547
{
1573
1556
    *ptr= ' ';
1574
1557
 
1575
1558
    /* Last non space charecter should be c2 */
1576
 
    ptr= strchr(str, '\0')-1;
 
1559
    ptr= strend(str)-1;
1577
1560
    while(*ptr && my_isspace(charset_info, *ptr))
1578
1561
      ptr--;
1579
1562
    if (*ptr == c2)
1594
1577
static void strip_parentheses(struct st_command *command)
1595
1578
{
1596
1579
  if (strip_surrounding(command->first_argument, '(', ')'))
1597
 
    die("%.*s - argument list started with '%c' must be ended with '%c'",
1598
 
        command->first_word_len, command->query, '(', ')');
1599
 
}
1600
 
 
 
1580
      die("%.*s - argument list started with '%c' must be ended with '%c'",
 
1581
          command->first_word_len, command->query, '(', ')');
 
1582
}
 
1583
 
 
1584
 
 
1585
static uchar *get_var_key(const uchar* var, size_t *len,
 
1586
                          bool __attribute__((unused)) t)
 
1587
{
 
1588
  register char* key;
 
1589
  key = ((VAR*)var)->name;
 
1590
  *len = ((VAR*)var)->name_len;
 
1591
  return (uchar*)key;
 
1592
}
1601
1593
 
1602
1594
 
1603
1595
VAR *var_init(VAR *v, const char *name, int name_len, const char *val,
1604
1596
              int val_len)
1605
1597
{
 
1598
  int val_alloc_len;
 
1599
  VAR *tmp_var;
1606
1600
  if (!name_len && name)
1607
1601
    name_len = strlen(name);
1608
1602
  if (!val_len && val)
1609
1603
    val_len = strlen(val) ;
1610
 
  VAR *tmp_var = v ? v : (VAR*)malloc(sizeof(*tmp_var) + name_len+1);
 
1604
  val_alloc_len = val_len + 16; /* room to grow */
 
1605
  if (!(tmp_var=v) && !(tmp_var = (VAR*)my_malloc(sizeof(*tmp_var)
 
1606
                                                  + name_len+1, MYF(MY_WME))))
 
1607
    die("Out of memory");
1611
1608
 
1612
 
  tmp_var->name = name ? (char*)&tmp_var[1] : 0;
 
1609
  tmp_var->name = (name) ? (char*) tmp_var + sizeof(*tmp_var) : 0;
1613
1610
  tmp_var->alloced = (v == 0);
1614
1611
 
1615
 
  int val_alloc_len = val_len + 16; /* room to grow */
1616
 
  tmp_var->str_val = (char*)malloc(val_alloc_len+1);
 
1612
  if (!(tmp_var->str_val = (char *)my_malloc(val_alloc_len+1, MYF(MY_WME))))
 
1613
    die("Out of memory");
1617
1614
 
1618
1615
  memcpy(tmp_var->name, name, name_len);
1619
1616
  if (val)
1624
1621
  tmp_var->name_len = name_len;
1625
1622
  tmp_var->str_val_len = val_len;
1626
1623
  tmp_var->alloced_len = val_alloc_len;
1627
 
  tmp_var->int_val = val ? atoi(val) : 0;
1628
 
  tmp_var->int_dirty = false;
 
1624
  tmp_var->int_val = (val) ? atoi(val) : 0;
 
1625
  tmp_var->int_dirty = 0;
1629
1626
  tmp_var->env_s = 0;
1630
1627
  return tmp_var;
1631
1628
}
1632
1629
 
 
1630
 
 
1631
void var_free(void *v)
 
1632
{
 
1633
  my_free(((VAR*) v)->str_val, MYF(MY_WME));
 
1634
  my_free(((VAR*) v)->env_s, MYF(MY_WME|MY_ALLOW_ZERO_PTR));
 
1635
  if (((VAR*)v)->alloced)
 
1636
    my_free(v, MYF(MY_WME));
 
1637
}
 
1638
 
 
1639
 
1633
1640
VAR* var_from_env(const char *name, const char *def_val)
1634
1641
{
1635
 
  const char *tmp= getenv(name);
1636
 
  if (!tmp)
 
1642
  const char *tmp;
 
1643
  VAR *v;
 
1644
  if (!(tmp = getenv(name)))
1637
1645
    tmp = def_val;
1638
 
  return var_hash[name] = var_init(0, name, strlen(name), tmp, strlen(tmp));
 
1646
 
 
1647
  v = var_init(0, name, strlen(name), tmp, strlen(tmp));
 
1648
  my_hash_insert(&var_hash, (uchar*)v);
 
1649
  return v;
1639
1650
}
1640
1651
 
 
1652
 
1641
1653
VAR* var_get(const char *var_name, const char **var_name_end, bool raw,
1642
 
             bool ignore_not_existing)
 
1654
             bool ignore_not_existing)
1643
1655
{
1644
1656
  int digit;
1645
1657
  VAR *v;
 
1658
 
1646
1659
  if (*var_name != '$')
1647
1660
    goto err;
1648
1661
  digit = *++var_name - '0';
1649
1662
  if (digit < 0 || digit >= 10)
1650
1663
  {
1651
1664
    const char *save_var_name = var_name, *end;
1652
 
    uint32_t length;
 
1665
    uint length;
1653
1666
    end = (var_name_end) ? *var_name_end : 0;
1654
1667
    while (my_isvar(charset_info,*var_name) && var_name != end)
1655
1668
      var_name++;
1656
1669
    if (var_name == save_var_name)
1657
1670
    {
1658
1671
      if (ignore_not_existing)
1659
 
        return(0);
 
1672
        return(0);
1660
1673
      die("Empty variable");
1661
1674
    }
1662
 
    length= (uint32_t) (var_name - save_var_name);
 
1675
    length= (uint) (var_name - save_var_name);
1663
1676
    if (length >= MAX_VAR_NAME_LENGTH)
1664
1677
      die("Too long variable name: %s", save_var_name);
1665
1678
 
1666
 
    string save_var_name_str(save_var_name, length);
1667
 
    var_hash_t::iterator iter= var_hash.find(save_var_name_str);
1668
 
    if (iter == var_hash.end())
 
1679
    if (!(v = (VAR*) hash_search(&var_hash, (const uchar*) save_var_name,
 
1680
                                            length)))
1669
1681
    {
1670
1682
      char buff[MAX_VAR_NAME_LENGTH+1];
1671
 
      strncpy(buff, save_var_name, length);
1672
 
      buff[length]= '\0';
 
1683
      strmake(buff, save_var_name, length);
1673
1684
      v= var_from_env(buff, "");
1674
1685
    }
1675
 
    else
1676
 
    {
1677
 
      v= iter->second;
1678
 
    }
1679
 
    var_name--;  /* Point at last character */
 
1686
    var_name--; /* Point at last character */
1680
1687
  }
1681
1688
  else
1682
 
    v = &var_reg[digit];
 
1689
    v = var_reg + digit;
1683
1690
 
1684
1691
  if (!raw && v->int_dirty)
1685
1692
  {
1700
1707
 
1701
1708
static VAR *var_obtain(const char *name, int len)
1702
1709
{
1703
 
  string var_name(name, len);
1704
 
  var_hash_t::iterator iter= var_hash.find(var_name);
1705
 
  if (iter != var_hash.end())
1706
 
    return iter->second;
1707
 
  return var_hash[var_name] = var_init(0, name, len, "", 0);
 
1710
  VAR* v;
 
1711
  if ((v = (VAR*)hash_search(&var_hash, (const uchar *) name, len)))
 
1712
    return v;
 
1713
  v = var_init(0, name, len, "", 0);
 
1714
  my_hash_insert(&var_hash, (uchar*)v);
 
1715
  return v;
1708
1716
}
1709
1717
 
1710
1718
 
1728
1736
  digit= *var_name - '0';
1729
1737
  if (!(digit < 10 && digit >= 0))
1730
1738
  {
1731
 
    v= var_obtain(var_name, (uint32_t) (var_name_end - var_name));
 
1739
    v= var_obtain(var_name, (uint) (var_name_end - var_name));
1732
1740
  }
1733
1741
  else
1734
 
    v= &var_reg[digit];
 
1742
    v= var_reg + digit;
1735
1743
 
1736
1744
  eval_expr(v, var_val, (const char**) &var_val_end);
1737
1745
 
1745
1753
      v->str_val_len= strlen(v->str_val);
1746
1754
    }
1747
1755
    snprintf(buf, sizeof(buf), "%.*s=%.*s",
1748
 
             v->name_len, v->name,
1749
 
             v->str_val_len, v->str_val);
1750
 
    if (!(v->env_s= strdup(buf)))
 
1756
                v->name_len, v->name,
 
1757
                v->str_val_len, v->str_val);
 
1758
    if (!(v->env_s= my_strdup(buf, MYF(MY_WME))))
1751
1759
      die("Out of memory");
1752
1760
    putenv(v->env_s);
1753
 
    free(old_env_s);
 
1761
    my_free(old_env_s, MYF(MY_ALLOW_ZERO_PTR));
1754
1762
  }
1755
1763
  return;
1756
1764
}
1772
1780
 
1773
1781
/*
1774
1782
  Store an integer (typically the returncode of the last SQL)
1775
 
  statement in the drizzletest builtin variable $drizzleclient_errno
 
1783
  statement in the mysqltest builtin variable $mysql_errno
1776
1784
*/
1777
1785
 
1778
1786
static void var_set_errno(int sql_errno)
1779
1787
{
1780
 
  var_set_int("$drizzleclient_errno", sql_errno);
 
1788
  var_set_int("$mysql_errno", sql_errno);
1781
1789
}
1782
1790
 
1783
1791
 
1784
1792
/*
1785
 
  Update $drizzleclient_get_server_version variable with version
 
1793
  Update $mysql_get_server_version variable with version
1786
1794
  of the currently connected server
1787
1795
*/
1788
1796
 
1789
 
static void var_set_drizzleclient_get_server_version(drizzle_con_st *con)
 
1797
static void var_set_mysql_get_server_version(MYSQL* mysql)
1790
1798
{
1791
 
  var_set_int("$drizzle_con_server_version", drizzle_con_server_version_number(con));
 
1799
  var_set_int("$mysql_get_server_version", mysql_get_server_version(mysql));
1792
1800
}
1793
1801
 
1794
1802
 
1797
1805
 
1798
1806
  SYNOPSIS
1799
1807
  var_query_set()
1800
 
  var          variable to set from query
 
1808
  var           variable to set from query
1801
1809
  query       start of query string to execute
1802
1810
  query_end   end of the query string to execute
1803
1811
 
1817
1825
 
1818
1826
static void var_query_set(VAR *var, const char *query, const char** query_end)
1819
1827
{
1820
 
  const char *end = (char*)((query_end && *query_end) ?
1821
 
                            *query_end : query + strlen(query));
1822
 
  drizzle_result_st res;
1823
 
  drizzle_return_t ret;
1824
 
  drizzle_row_t row;
1825
 
  drizzle_con_st *con= &cur_con->con;
1826
 
  string ds_query;
 
1828
  char *end = (char*)((query_end && *query_end) ?
 
1829
                      *query_end : query + strlen(query));
 
1830
  MYSQL_RES *res;
 
1831
  MYSQL_ROW row;
 
1832
  MYSQL* mysql = &cur_con->mysql;
 
1833
  DYNAMIC_STRING ds_query;
1827
1834
 
1828
1835
 
1829
1836
  while (end > query && *end != '`')
1833
1840
  ++query;
1834
1841
 
1835
1842
  /* Eval the query, thus replacing all environment variables */
1836
 
  do_eval(&ds_query, query, end, false);
1837
 
 
1838
 
  if (drizzle_query(con, &res, ds_query.c_str(), ds_query.length(),
1839
 
                    &ret) == NULL ||
1840
 
      ret != DRIZZLE_RETURN_OK)
1841
 
  {
1842
 
    if (ret == DRIZZLE_RETURN_ERROR_CODE)
1843
 
    {
1844
 
      die("Error running query '%s': %d %s", ds_query.c_str(),
1845
 
          drizzle_result_error_code(&res), drizzle_result_error(&res));
1846
 
      drizzle_result_free(&res);
1847
 
    }
1848
 
    else
1849
 
    {
1850
 
      die("Error running query '%s': %d %s", ds_query.c_str(), ret,
1851
 
          drizzle_con_error(con));
1852
 
    }
1853
 
  }
1854
 
  if (drizzle_result_column_count(&res) == 0 ||
1855
 
      drizzle_result_buffer(&res) != DRIZZLE_RETURN_OK)
1856
 
    die("Query '%s' didn't return a result set", ds_query.c_str());
1857
 
 
1858
 
  if ((row= drizzle_row_next(&res)) && row[0])
 
1843
  init_dynamic_string(&ds_query, 0, (end - query) + 32, 256);
 
1844
  do_eval(&ds_query, query, end, FALSE);
 
1845
 
 
1846
  if (mysql_real_query(mysql, ds_query.str, ds_query.length))
 
1847
    die("Error running query '%s': %d %s", ds_query.str,
 
1848
        mysql_errno(mysql), mysql_error(mysql));
 
1849
  if (!(res= mysql_store_result(mysql)))
 
1850
    die("Query '%s' didn't return a result set", ds_query.str);
 
1851
  dynstr_free(&ds_query);
 
1852
 
 
1853
  if ((row= mysql_fetch_row(res)) && row[0])
1859
1854
  {
1860
1855
    /*
1861
1856
      Concatenate all fields in the first row with tab in between
1862
1857
      and assign that string to the $variable
1863
1858
    */
1864
 
    string result;
1865
 
    uint32_t i;
1866
 
    size_t *lengths;
 
1859
    DYNAMIC_STRING result;
 
1860
    uint i;
 
1861
    ulong *lengths;
1867
1862
 
1868
 
    lengths= drizzle_row_field_sizes(&res);
1869
 
    for (i= 0; i < drizzle_result_column_count(&res); i++)
 
1863
    init_dynamic_string(&result, "", 512, 512);
 
1864
    lengths= mysql_fetch_lengths(res);
 
1865
    for (i= 0; i < mysql_num_fields(res); i++)
1870
1866
    {
1871
1867
      if (row[i])
1872
1868
      {
1873
1869
        /* Add column to tab separated string */
1874
 
        result.append(row[i], lengths[i]);
 
1870
        dynstr_append_mem(&result, row[i], lengths[i]);
1875
1871
      }
1876
 
      result.append("\t", 1);
 
1872
      dynstr_append_mem(&result, "\t", 1);
1877
1873
    }
1878
 
    end= result.c_str() + result.length()-1;
1879
 
    eval_expr(var, result.c_str(), (const char**) &end);
 
1874
    end= result.str + result.length-1;
 
1875
    eval_expr(var, result.str, (const char**) &end);
 
1876
    dynstr_free(&result);
1880
1877
  }
1881
1878
  else
1882
1879
    eval_expr(var, "", 0);
1883
1880
 
1884
 
  drizzle_result_free(&res);
 
1881
  mysql_free_result(res);
1885
1882
  return;
1886
1883
}
1887
1884
 
1902
1899
 
1903
1900
  <query to run> -    The query that should be sent to the server
1904
1901
  <column name> -     Name of the column that holds the field be compared
1905
 
  against the expected value
 
1902
                      against the expected value
1906
1903
  <row no> -          Number of the row that holds the field to be
1907
 
  compared against the expected value
 
1904
                      compared against the expected value
1908
1905
 
1909
1906
*/
1910
1907
 
1912
1909
{
1913
1910
  long row_no;
1914
1911
  int col_no= -1;
1915
 
  drizzle_result_st res;
1916
 
  drizzle_return_t ret;
1917
 
  drizzle_con_st *con= &cur_con->con;
 
1912
  MYSQL_RES* res;
 
1913
  MYSQL* mysql= &cur_con->mysql;
1918
1914
 
1919
 
  string ds_query;
1920
 
  string ds_col;
1921
 
  string ds_row;
 
1915
  static DYNAMIC_STRING ds_query;
 
1916
  static DYNAMIC_STRING ds_col;
 
1917
  static DYNAMIC_STRING ds_row;
1922
1918
  const struct command_arg query_get_value_args[] = {
1923
 
    {"query", ARG_STRING, true, &ds_query, "Query to run"},
1924
 
    {"column name", ARG_STRING, true, &ds_col, "Name of column"},
1925
 
    {"row number", ARG_STRING, true, &ds_row, "Number for row"}
 
1919
    {"query", ARG_STRING, TRUE, &ds_query, "Query to run"},
 
1920
    {"column name", ARG_STRING, TRUE, &ds_col, "Name of column"},
 
1921
    {"row number", ARG_STRING, TRUE, &ds_row, "Number for row"}
1926
1922
  };
1927
1923
 
1928
1924
 
1933
1929
                     ',');
1934
1930
 
1935
1931
  /* Convert row number to int */
1936
 
  row_no= atoi(ds_row.c_str());
1937
 
  
1938
 
  istringstream buff(ds_row);
1939
 
  if ((buff >> row_no).fail())
1940
 
    die("Invalid row number: '%s'", ds_row.c_str());
 
1932
  if (!str2int(ds_row.str, 10, (long) 0, (long) INT_MAX, &row_no))
 
1933
    die("Invalid row number: '%s'", ds_row.str);
 
1934
  dynstr_free(&ds_row);
1941
1935
 
1942
1936
  /* Remove any surrounding "'s from the query - if there is any */
1943
 
  // (Don't get me started on this)
1944
 
  char * unstripped_query= strdup(ds_query.c_str());
1945
 
  if (strip_surrounding(unstripped_query, '"', '"'))
1946
 
    die("Mismatched \"'s around query '%s'", ds_query.c_str());
1947
 
  ds_query.clear();
1948
 
  ds_query.append(unstripped_query);
 
1937
  if (strip_surrounding(ds_query.str, '"', '"'))
 
1938
    die("Mismatched \"'s around query '%s'", ds_query.str);
1949
1939
 
1950
1940
  /* Run the query */
1951
 
  if (drizzle_query(con, &res, ds_query.c_str(), ds_query.length(),
1952
 
                    &ret) == NULL ||
1953
 
      ret != DRIZZLE_RETURN_OK)
1954
 
  {
1955
 
    if (ret == DRIZZLE_RETURN_ERROR_CODE)
1956
 
    {
1957
 
      die("Error running query '%s': %d %s", ds_query.c_str(),
1958
 
          drizzle_result_error_code(&res), drizzle_result_error(&res));
1959
 
      drizzle_result_free(&res);
1960
 
    }
1961
 
    else
1962
 
    {
1963
 
      die("Error running query '%s': %d %s", ds_query.c_str(), ret,
1964
 
          drizzle_con_error(con));
1965
 
    }
1966
 
  }
1967
 
  if (drizzle_result_column_count(&res) == 0 ||
1968
 
      drizzle_result_buffer(&res) != DRIZZLE_RETURN_OK)
1969
 
    die("Query '%s' didn't return a result set", ds_query.c_str());
 
1941
  if (mysql_real_query(mysql, ds_query.str, ds_query.length))
 
1942
    die("Error running query '%s': %d %s", ds_query.str,
 
1943
        mysql_errno(mysql), mysql_error(mysql));
 
1944
  if (!(res= mysql_store_result(mysql)))
 
1945
    die("Query '%s' didn't return a result set", ds_query.str);
1970
1946
 
1971
1947
  {
1972
1948
    /* Find column number from the given column name */
1973
 
    uint32_t i;
1974
 
    uint32_t num_fields= drizzle_result_column_count(&res);
1975
 
    drizzle_column_st *column;
 
1949
    uint i;
 
1950
    uint num_fields= mysql_num_fields(res);
 
1951
    MYSQL_FIELD *fields= mysql_fetch_fields(res);
1976
1952
 
1977
1953
    for (i= 0; i < num_fields; i++)
1978
1954
    {
1979
 
      column= drizzle_column_next(&res);
1980
 
      if (strcmp(drizzle_column_name(column), ds_col.c_str()) == 0 &&
1981
 
          strlen(drizzle_column_name(column)) == ds_col.length())
 
1955
      if (strcmp(fields[i].name, ds_col.str) == 0 &&
 
1956
          strlen(fields[i].name) == ds_col.length)
1982
1957
      {
1983
1958
        col_no= i;
1984
1959
        break;
1986
1961
    }
1987
1962
    if (col_no == -1)
1988
1963
    {
1989
 
      drizzle_result_free(&res);
 
1964
      mysql_free_result(res);
1990
1965
      die("Could not find column '%s' in the result of '%s'",
1991
 
          ds_col.c_str(), ds_query.c_str());
 
1966
          ds_col.str, ds_query.str);
1992
1967
    }
1993
1968
  }
 
1969
  dynstr_free(&ds_col);
1994
1970
 
1995
1971
  {
1996
1972
    /* Get the value */
1997
 
    drizzle_row_t row;
 
1973
    MYSQL_ROW row;
1998
1974
    long rows= 0;
1999
1975
    const char* value= "No such row";
2000
1976
 
2001
 
    while ((row= drizzle_row_next(&res)))
 
1977
    while ((row= mysql_fetch_row(res)))
2002
1978
    {
2003
1979
      if (++rows == row_no)
2004
1980
      {
2014
1990
    }
2015
1991
    eval_expr(var, value, 0);
2016
1992
  }
2017
 
  drizzle_result_free(&res);
 
1993
  dynstr_free(&ds_query);
 
1994
  mysql_free_result(res);
 
1995
 
 
1996
  return;
2018
1997
}
2019
1998
 
2020
1999
 
2024
2003
  dest->int_dirty= src->int_dirty;
2025
2004
 
2026
2005
  /* Alloc/realloc data for str_val in dest */
2027
 
  if (dest->alloced_len < src->alloced_len)
2028
 
  {
2029
 
    char *tmpptr= (char *)realloc(dest->str_val, src->alloced_len);
2030
 
    if (tmpptr == NULL)
2031
 
      die("Out of memory");
2032
 
    dest->str_val= tmpptr;
2033
 
  }
 
2006
  if (dest->alloced_len < src->alloced_len &&
 
2007
      !(dest->str_val= dest->str_val
 
2008
        ? (char *)my_realloc(dest->str_val, src->alloced_len, MYF(MY_WME))
 
2009
        : (char *)my_malloc(src->alloced_len, MYF(MY_WME))))
 
2010
    die("Out of memory");
2034
2011
  else
2035
2012
    dest->alloced_len= src->alloced_len;
2036
2013
 
2045
2022
{
2046
2023
  if (*p == '$')
2047
2024
  {
2048
 
    VAR *vp= var_get(p, p_end, 0, 0);
2049
 
    if (vp)
 
2025
    VAR *vp;
 
2026
    if ((vp= var_get(p, p_end, 0, 0)))
2050
2027
      var_copy(v, vp);
2051
2028
    return;
2052
2029
  }
2063
2040
    const size_t len= strlen(get_value_str);
2064
2041
    if (strncmp(p, get_value_str, len)==0)
2065
2042
    {
2066
 
      st_command command;
 
2043
      struct st_command command;
 
2044
      memset(&command, 0, sizeof(command));
2067
2045
      command.query= (char*)p;
2068
2046
      command.first_word_len= len;
2069
2047
      command.first_argument= command.query + len;
2081
2059
      static int MIN_VAR_ALLOC= 32;
2082
2060
      v->alloced_len = (new_val_len < MIN_VAR_ALLOC - 1) ?
2083
2061
        MIN_VAR_ALLOC : new_val_len + 1;
2084
 
      char *tmpptr= (char *)realloc(v->str_val, v->alloced_len+1);
2085
 
      if (tmpptr == NULL)
 
2062
      if (!(v->str_val =
 
2063
            v->str_val ? (char *)my_realloc(v->str_val, v->alloced_len+1,
 
2064
                                    MYF(MY_WME)) :
 
2065
            (char *)my_malloc(v->alloced_len+1, MYF(MY_WME))))
2086
2066
        die("Out of memory");
2087
 
      v->str_val= tmpptr;
2088
2067
    }
2089
2068
    v->str_val_len = new_val_len;
2090
2069
    memcpy(v->str_val, p, new_val_len);
2100
2079
{
2101
2080
  char buff[FN_REFLEN];
2102
2081
 
2103
 
  if (!internal::test_if_hard_path(name))
 
2082
  if (!test_if_hard_path(name))
2104
2083
  {
2105
 
    snprintf(buff, sizeof(buff), "%s%s",opt_basedir.c_str(),name);
 
2084
    strxmov(buff, opt_basedir, name, NullS);
2106
2085
    name=buff;
2107
2086
  }
2108
 
  internal::fn_format(buff, name, "", "", MY_UNPACK_FILENAME);
 
2087
  fn_format(buff, name, "", "", MY_UNPACK_FILENAME);
2109
2088
 
 
2089
  if (cur_file == file_stack_end)
 
2090
    die("Source directives are nesting too deep");
2110
2091
  cur_file++;
2111
 
  if (cur_file == &*file_stack.end())
2112
 
    die("Source directives are nesting too deep");
2113
 
  if (!(cur_file->file= fopen(buff, "r")))
 
2092
  if (!(cur_file->file = my_fopen(buff, O_RDONLY | FILE_BINARY, MYF(0))))
2114
2093
  {
2115
2094
    cur_file--;
2116
2095
    die("Could not open '%s' for reading", buff);
2117
2096
  }
2118
 
  if (!(cur_file->file_name= strdup(buff)))
2119
 
    die("Out of memory");
 
2097
  cur_file->file_name= my_strdup(buff, MYF(MY_FAE));
2120
2098
  cur_file->lineno=1;
2121
2099
  return(0);
2122
2100
}
2127
2105
 
2128
2106
  SYNOPSIS
2129
2107
  do_source()
2130
 
  query  called command
 
2108
  query called command
2131
2109
 
2132
2110
  DESCRIPTION
2133
2111
  source <file_name>
2138
2116
 
2139
2117
static void do_source(struct st_command *command)
2140
2118
{
2141
 
  string ds_filename;
 
2119
  static DYNAMIC_STRING ds_filename;
2142
2120
  const struct command_arg source_args[] = {
2143
 
    { "filename", ARG_STRING, true, &ds_filename, "File to source" }
 
2121
    { "filename", ARG_STRING, TRUE, &ds_filename, "File to source" }
2144
2122
  };
2145
2123
 
2146
2124
 
2156
2134
    ; /* Do nothing */
2157
2135
  else
2158
2136
  {
2159
 
    if (! opt_testdir.empty())
2160
 
    {
2161
 
      string testdir(opt_testdir);
2162
 
      if (testdir[testdir.length()] != '/')
2163
 
        testdir.append("/");
2164
 
      testdir.append(ds_filename);
2165
 
      ds_filename.swap(testdir);
2166
 
    }
2167
 
    open_file(ds_filename.c_str());
 
2137
    open_file(ds_filename.str);
2168
2138
  }
2169
2139
 
 
2140
  dynstr_free(&ds_filename);
2170
2141
  return;
2171
2142
}
2172
2143
 
2173
2144
 
2174
 
static void init_builtin_echo()
 
2145
static FILE* my_popen(DYNAMIC_STRING *ds_cmd, const char *mode)
 
2146
{
 
2147
  return popen(ds_cmd->str, mode);
 
2148
}
 
2149
 
 
2150
 
 
2151
static void init_builtin_echo(void)
2175
2152
{
2176
2153
  builtin_echo[0]= 0;
 
2154
  return;
2177
2155
}
2178
2156
 
2179
2157
 
2181
2159
  Replace a substring
2182
2160
 
2183
2161
  SYNOPSIS
2184
 
  replace
2185
 
  ds_str      The string to search and perform the replace in
2186
 
  search_str  The string to search for
2187
 
  search_len  Length of the string to search for
2188
 
  replace_str The string to replace with
2189
 
  replace_len Length of the string to replace with
 
2162
    replace
 
2163
    ds_str      The string to search and perform the replace in
 
2164
    search_str  The string to search for
 
2165
    search_len  Length of the string to search for
 
2166
    replace_str The string to replace with
 
2167
    replace_len Length of the string to replace with
2190
2168
 
2191
2169
  RETURN
2192
 
  0 String replaced
2193
 
  1 Could not find search_str in str
 
2170
    0 String replaced
 
2171
    1 Could not find search_str in str
2194
2172
*/
2195
2173
 
2196
 
static int replace(string *ds_str,
2197
 
                   const char *search_str, uint32_t search_len,
2198
 
                   const char *replace_str, uint32_t replace_len)
 
2174
static int replace(DYNAMIC_STRING *ds_str,
 
2175
                   const char *search_str, ulong search_len,
 
2176
                   const char *replace_str, ulong replace_len)
2199
2177
{
2200
 
  string ds_tmp;
2201
 
  const char *start= strstr(ds_str->c_str(), search_str);
 
2178
  DYNAMIC_STRING ds_tmp;
 
2179
  const char *start= strstr(ds_str->str, search_str);
2202
2180
  if (!start)
2203
2181
    return 1;
2204
 
  ds_tmp.append(ds_str->c_str(), start - ds_str->c_str());
2205
 
  ds_tmp.append(replace_str, replace_len);
2206
 
  ds_tmp.append(start + search_len);
2207
 
  *ds_str= ds_tmp;
 
2182
  init_dynamic_string(&ds_tmp, "",
 
2183
                      ds_str->length + replace_len, 256);
 
2184
  dynstr_append_mem(&ds_tmp, ds_str->str, start - ds_str->str);
 
2185
  dynstr_append_mem(&ds_tmp, replace_str, replace_len);
 
2186
  dynstr_append(&ds_tmp, start + search_len);
 
2187
  dynstr_set(ds_str, ds_tmp.str);
 
2188
  dynstr_free(&ds_tmp);
2208
2189
  return 0;
2209
2190
}
2210
2191
 
2214
2195
 
2215
2196
  SYNOPSIS
2216
2197
  do_exec()
2217
 
  query  called command
 
2198
  query called command
2218
2199
 
2219
2200
  DESCRIPTION
2220
2201
  exec <command>
2225
2206
  It can thus be used to execute a command that shall fail.
2226
2207
 
2227
2208
  NOTE
2228
 
  Although drizzletest is executed from cygwin shell, the command will be
 
2209
  Although mysqltest is executed from cygwin shell, the command will be
2229
2210
  executed in "cmd.exe". Thus commands like "rm" etc can NOT be used, use
2230
 
  drizzletest commmand(s) like "remove_file" for that
 
2211
  mysqltest commmand(s) like "remove_file" for that
2231
2212
*/
2232
2213
 
2233
2214
static void do_exec(struct st_command *command)
2236
2217
  char buf[512];
2237
2218
  FILE *res_file;
2238
2219
  char *cmd= command->first_argument;
2239
 
  string ds_cmd;
 
2220
  DYNAMIC_STRING ds_cmd;
2240
2221
 
2241
2222
  /* Skip leading space */
2242
2223
  while (*cmd && my_isspace(charset_info, *cmd))
2245
2226
    die("Missing argument in exec");
2246
2227
  command->last_argument= command->end;
2247
2228
 
 
2229
  init_dynamic_string(&ds_cmd, 0, command->query_len+256, 256);
2248
2230
  /* Eval the command, thus replacing all environment variables */
2249
2231
  do_eval(&ds_cmd, cmd, command->end, !is_windows);
2250
2232
 
2255
2237
    replace(&ds_cmd, "echo", 4, builtin_echo, strlen(builtin_echo));
2256
2238
  }
2257
2239
 
2258
 
  if (!(res_file= popen(ds_cmd.c_str(), "r")) && command->abort_on_error)
 
2240
  if (!(res_file= my_popen(&ds_cmd, "r")) && command->abort_on_error)
2259
2241
  {
 
2242
    dynstr_free(&ds_cmd);
2260
2243
    die("popen(\"%s\", \"r\") failed", command->first_argument);
2261
2244
  }
2262
2245
 
2268
2251
    }
2269
2252
    else
2270
2253
    {
2271
 
      replace_append(&ds_res, buf);
 
2254
      replace_dynstr_append(&ds_res, buf);
2272
2255
    }
2273
2256
  }
2274
2257
  error= pclose(res_file);
2275
2258
  if (error > 0)
2276
2259
  {
2277
 
    uint32_t status= WEXITSTATUS(error), i;
 
2260
    uint status= WEXITSTATUS(error), i;
2278
2261
    bool ok= 0;
2279
2262
 
2280
2263
    if (command->abort_on_error)
2281
2264
    {
2282
2265
      log_msg("exec of '%s' failed, error: %d, status: %d, errno: %d",
2283
 
              ds_cmd.c_str(), error, status, errno);
 
2266
              ds_cmd.str, error, status, errno);
 
2267
      dynstr_free(&ds_cmd);
2284
2268
      die("command \"%s\" failed", command->first_argument);
2285
2269
    }
2286
2270
 
2294
2278
    }
2295
2279
    if (!ok)
2296
2280
    {
 
2281
      dynstr_free(&ds_cmd);
2297
2282
      die("command \"%s\" failed with wrong error: %d",
2298
2283
          command->first_argument, status);
2299
2284
    }
2303
2288
  {
2304
2289
    /* Error code we wanted was != 0, i.e. not an expected success */
2305
2290
    log_msg("exec of '%s failed, error: %d, errno: %d",
2306
 
            ds_cmd.c_str(), error, errno);
 
2291
            ds_cmd.str, error, errno);
 
2292
    dynstr_free(&ds_cmd);
2307
2293
    die("command \"%s\" succeeded - should have failed with errno %d...",
2308
2294
        command->first_argument, command->expected_errors.err[0].code.errnum);
2309
2295
  }
2310
2296
 
 
2297
  dynstr_free(&ds_cmd);
2311
2298
  return;
2312
2299
}
2313
2300
 
2323
2310
 
2324
2311
  SYNOPSIS
2325
2312
  do_modify_var()
2326
 
  query  called command
 
2313
  query called command
2327
2314
  operator    operation to perform on the var
2328
2315
 
2329
2316
  DESCRIPTION
2361
2348
 
2362
2349
 
2363
2350
/*
 
2351
  Wrapper for 'system' function
 
2352
 
 
2353
  NOTE
 
2354
  If mysqltest is executed from cygwin shell, the command will be
 
2355
  executed in the "windows command interpreter" cmd.exe and we prepend "sh"
 
2356
  to make it be executed by cygwins "bash". Thus commands like "rm",
 
2357
  "mkdir" as well as shellscripts can executed by "system" in Windows.
 
2358
 
 
2359
*/
 
2360
 
 
2361
static int my_system(DYNAMIC_STRING* ds_cmd)
 
2362
{
 
2363
  return system(ds_cmd->str);
 
2364
}
 
2365
 
 
2366
 
 
2367
/*
2364
2368
  SYNOPSIS
2365
2369
  do_system
2366
 
  command  called command
 
2370
  command       called command
2367
2371
 
2368
2372
  DESCRIPTION
2369
2373
  system <command>
2375
2379
 
2376
2380
static void do_system(struct st_command *command)
2377
2381
{
2378
 
  string ds_cmd;
 
2382
  DYNAMIC_STRING ds_cmd;
2379
2383
 
2380
2384
 
2381
2385
  if (strlen(command->first_argument) == 0)
2382
2386
    die("Missing arguments to system, nothing to do!");
2383
2387
 
 
2388
  init_dynamic_string(&ds_cmd, 0, command->query_len + 64, 256);
 
2389
 
2384
2390
  /* Eval the system command, thus replacing all environment variables */
2385
2391
  do_eval(&ds_cmd, command->first_argument, command->end, !is_windows);
2386
2392
 
2387
 
  if (system(ds_cmd.c_str()))
 
2393
  if (my_system(&ds_cmd))
2388
2394
  {
2389
2395
    if (command->abort_on_error)
2390
2396
      die("system command '%s' failed", command->first_argument);
2391
2397
 
2392
2398
    /* If ! abort_on_error, log message and continue */
2393
 
    ds_res.append("system command '");
2394
 
    replace_append(&ds_res, command->first_argument);
2395
 
    ds_res.append("' failed\n");
 
2399
    dynstr_append(&ds_res, "system command '");
 
2400
    replace_dynstr_append(&ds_res, command->first_argument);
 
2401
    dynstr_append(&ds_res, "' failed\n");
2396
2402
  }
2397
2403
 
2398
2404
  command->last_argument= command->end;
 
2405
  dynstr_free(&ds_cmd);
2399
2406
  return;
2400
2407
}
2401
2408
 
2403
2410
/*
2404
2411
  SYNOPSIS
2405
2412
  do_remove_file
2406
 
  command  called command
 
2413
  command       called command
2407
2414
 
2408
2415
  DESCRIPTION
2409
2416
  remove_file <file_name>
2413
2420
static void do_remove_file(struct st_command *command)
2414
2421
{
2415
2422
  int error;
2416
 
  string ds_filename;
 
2423
  static DYNAMIC_STRING ds_filename;
2417
2424
  const struct command_arg rm_args[] = {
2418
 
    { "filename", ARG_STRING, true, &ds_filename, "File to delete" }
 
2425
    { "filename", ARG_STRING, TRUE, &ds_filename, "File to delete" }
2419
2426
  };
2420
2427
 
2421
2428
 
2423
2430
                     rm_args, sizeof(rm_args)/sizeof(struct command_arg),
2424
2431
                     ' ');
2425
2432
 
2426
 
  error= internal::my_delete(ds_filename.c_str(), MYF(0)) != 0;
 
2433
  error= my_delete(ds_filename.str, MYF(0)) != 0;
2427
2434
  handle_command_error(command, error);
 
2435
  dynstr_free(&ds_filename);
 
2436
  return;
2428
2437
}
2429
2438
 
2430
2439
 
2431
2440
/*
2432
2441
  SYNOPSIS
2433
2442
  do_copy_file
2434
 
  command  command handle
 
2443
  command       command handle
2435
2444
 
2436
2445
  DESCRIPTION
2437
2446
  copy_file <from_file> <to_file>
2443
2452
static void do_copy_file(struct st_command *command)
2444
2453
{
2445
2454
  int error;
2446
 
  string ds_from_file;
2447
 
  string ds_to_file;
 
2455
  static DYNAMIC_STRING ds_from_file;
 
2456
  static DYNAMIC_STRING ds_to_file;
2448
2457
  const struct command_arg copy_file_args[] = {
2449
 
    { "from_file", ARG_STRING, true, &ds_from_file, "Filename to copy from" },
2450
 
    { "to_file", ARG_STRING, true, &ds_to_file, "Filename to copy to" }
 
2458
    { "from_file", ARG_STRING, TRUE, &ds_from_file, "Filename to copy from" },
 
2459
    { "to_file", ARG_STRING, TRUE, &ds_to_file, "Filename to copy to" }
2451
2460
  };
2452
2461
 
2453
2462
 
2456
2465
                     sizeof(copy_file_args)/sizeof(struct command_arg),
2457
2466
                     ' ');
2458
2467
 
2459
 
  error= (internal::my_copy(ds_from_file.c_str(), ds_to_file.c_str(),
 
2468
  error= (my_copy(ds_from_file.str, ds_to_file.str,
2460
2469
                  MYF(MY_DONT_OVERWRITE_FILE)) != 0);
2461
2470
  handle_command_error(command, error);
 
2471
  dynstr_free(&ds_from_file);
 
2472
  dynstr_free(&ds_to_file);
 
2473
  return;
2462
2474
}
2463
2475
 
2464
2476
 
2465
2477
/*
2466
2478
  SYNOPSIS
2467
2479
  do_chmod_file
2468
 
  command  command handle
 
2480
  command       command handle
2469
2481
 
2470
2482
  DESCRIPTION
2471
2483
  chmod <octal> <file_name>
2476
2488
static void do_chmod_file(struct st_command *command)
2477
2489
{
2478
2490
  long mode= 0;
2479
 
  string ds_mode;
2480
 
  string ds_file;
 
2491
  static DYNAMIC_STRING ds_mode;
 
2492
  static DYNAMIC_STRING ds_file;
2481
2493
  const struct command_arg chmod_file_args[] = {
2482
 
    { "mode", ARG_STRING, true, &ds_mode, "Mode of file(octal) ex. 0660"},
2483
 
    { "filename", ARG_STRING, true, &ds_file, "Filename of file to modify" }
 
2494
    { "mode", ARG_STRING, TRUE, &ds_mode, "Mode of file(octal) ex. 0660"}, 
 
2495
    { "filename", ARG_STRING, TRUE, &ds_file, "Filename of file to modify" }
2484
2496
  };
2485
2497
 
2486
2498
 
2490
2502
                     ' ');
2491
2503
 
2492
2504
  /* Parse what mode to set */
2493
 
  istringstream buff(ds_mode);
2494
 
  if (ds_mode.length() != 4 ||
2495
 
      (buff >> oct >> mode).fail())
 
2505
  if (ds_mode.length != 4 ||
 
2506
      str2int(ds_mode.str, 8, 0, INT_MAX, &mode) == NullS)
2496
2507
    die("You must write a 4 digit octal number for mode");
2497
2508
 
2498
 
  handle_command_error(command, chmod(ds_file.c_str(), mode));
 
2509
  handle_command_error(command, chmod(ds_file.str, mode));
 
2510
  dynstr_free(&ds_mode);
 
2511
  dynstr_free(&ds_file);
 
2512
  return;
2499
2513
}
2500
2514
 
2501
2515
 
2502
2516
/*
2503
2517
  SYNOPSIS
2504
2518
  do_file_exists
2505
 
  command  called command
 
2519
  command       called command
2506
2520
 
2507
2521
  DESCRIPTION
2508
2522
  fiile_exist <file_name>
2512
2526
static void do_file_exist(struct st_command *command)
2513
2527
{
2514
2528
  int error;
2515
 
  string ds_filename;
 
2529
  static DYNAMIC_STRING ds_filename;
2516
2530
  const struct command_arg file_exist_args[] = {
2517
 
    { "filename", ARG_STRING, true, &ds_filename, "File to check if it exist" }
 
2531
    { "filename", ARG_STRING, TRUE, &ds_filename, "File to check if it exist" }
2518
2532
  };
2519
2533
 
2520
2534
 
2523
2537
                     sizeof(file_exist_args)/sizeof(struct command_arg),
2524
2538
                     ' ');
2525
2539
 
2526
 
  error= (access(ds_filename.c_str(), F_OK) != 0);
 
2540
  error= (access(ds_filename.str, F_OK) != 0);
2527
2541
  handle_command_error(command, error);
 
2542
  dynstr_free(&ds_filename);
 
2543
  return;
2528
2544
}
2529
2545
 
2530
2546
 
2531
2547
/*
2532
2548
  SYNOPSIS
2533
2549
  do_mkdir
2534
 
  command  called command
 
2550
  command       called command
2535
2551
 
2536
2552
  DESCRIPTION
2537
2553
  mkdir <dir_name>
2540
2556
 
2541
2557
static void do_mkdir(struct st_command *command)
2542
2558
{
2543
 
  string ds_dirname;
2544
2559
  int error;
 
2560
  static DYNAMIC_STRING ds_dirname;
2545
2561
  const struct command_arg mkdir_args[] = {
2546
 
    {"dirname", ARG_STRING, true, &ds_dirname, "Directory to create"}
 
2562
    {"dirname", ARG_STRING, TRUE, &ds_dirname, "Directory to create"}
2547
2563
  };
2548
2564
 
2549
2565
 
2551
2567
                     mkdir_args, sizeof(mkdir_args)/sizeof(struct command_arg),
2552
2568
                     ' ');
2553
2569
 
2554
 
  error= mkdir(ds_dirname.c_str(), (0777 & internal::my_umask_dir)) != 0;
 
2570
  error= my_mkdir(ds_dirname.str, 0777, MYF(0)) != 0;
2555
2571
  handle_command_error(command, error);
 
2572
  dynstr_free(&ds_dirname);
 
2573
  return;
2556
2574
}
2557
2575
 
2558
2576
/*
2559
2577
  SYNOPSIS
2560
2578
  do_rmdir
2561
 
  command  called command
 
2579
  command       called command
2562
2580
 
2563
2581
  DESCRIPTION
2564
2582
  rmdir <dir_name>
2568
2586
static void do_rmdir(struct st_command *command)
2569
2587
{
2570
2588
  int error;
2571
 
  string ds_dirname;
 
2589
  static DYNAMIC_STRING ds_dirname;
2572
2590
  const struct command_arg rmdir_args[] = {
2573
 
    {"dirname", ARG_STRING, true, &ds_dirname, "Directory to remove"}
 
2591
    {"dirname", ARG_STRING, TRUE, &ds_dirname, "Directory to remove"}
2574
2592
  };
2575
2593
 
2576
2594
 
2578
2596
                     rmdir_args, sizeof(rmdir_args)/sizeof(struct command_arg),
2579
2597
                     ' ');
2580
2598
 
2581
 
  error= rmdir(ds_dirname.c_str()) != 0;
 
2599
  error= rmdir(ds_dirname.str) != 0;
2582
2600
  handle_command_error(command, error);
 
2601
  dynstr_free(&ds_dirname);
 
2602
  return;
2583
2603
}
2584
2604
 
2585
2605
 
2607
2627
}
2608
2628
 
2609
2629
 
2610
 
static void read_until_delimiter(string *ds,
2611
 
                                 string *ds_delimiter)
 
2630
static void read_until_delimiter(DYNAMIC_STRING *ds,
 
2631
                                 DYNAMIC_STRING *ds_delimiter)
2612
2632
{
2613
2633
  char c;
2614
2634
 
2615
 
  if (ds_delimiter->length() > MAX_DELIMITER_LENGTH)
 
2635
  if (ds_delimiter->length > MAX_DELIMITER_LENGTH)
2616
2636
    die("Max delimiter length(%d) exceeded", MAX_DELIMITER_LENGTH);
2617
2637
 
2618
2638
  /* Read from file until delimiter is found */
2639
2659
 
2640
2660
    if (feof(cur_file->file))
2641
2661
      die("End of file encountered before '%s' delimiter was found",
2642
 
          ds_delimiter->c_str());
 
2662
          ds_delimiter->str);
2643
2663
 
2644
 
    if (match_delimiter(c, ds_delimiter->c_str(), ds_delimiter->length()))
 
2664
    if (match_delimiter(c, ds_delimiter->str, ds_delimiter->length))
2645
2665
      break;
2646
2666
 
2647
 
    ds->push_back(c);
 
2667
    dynstr_append_mem(ds, (const char*)&c, 1);
2648
2668
  }
2649
2669
  return;
2650
2670
}
2652
2672
 
2653
2673
static void do_write_file_command(struct st_command *command, bool append)
2654
2674
{
2655
 
  string ds_content;
2656
 
  string ds_filename;
2657
 
  string ds_delimiter;
 
2675
  static DYNAMIC_STRING ds_content;
 
2676
  static DYNAMIC_STRING ds_filename;
 
2677
  static DYNAMIC_STRING ds_delimiter;
2658
2678
  const struct command_arg write_file_args[] = {
2659
 
    { "filename", ARG_STRING, true, &ds_filename, "File to write to" },
2660
 
    { "delimiter", ARG_STRING, false, &ds_delimiter, "Delimiter to read until" }
 
2679
    { "filename", ARG_STRING, TRUE, &ds_filename, "File to write to" },
 
2680
    { "delimiter", ARG_STRING, FALSE, &ds_delimiter, "Delimiter to read until" }
2661
2681
  };
2662
2682
 
2663
2683
 
2668
2688
                     ' ');
2669
2689
 
2670
2690
  /* If no delimiter was provided, use EOF */
2671
 
  if (ds_delimiter.length() == 0)
2672
 
    ds_delimiter.append("EOF");
 
2691
  if (ds_delimiter.length == 0)
 
2692
    dynstr_set(&ds_delimiter, "EOF");
2673
2693
 
2674
 
  if (!append && access(ds_filename.c_str(), F_OK) == 0)
 
2694
  if (!append && access(ds_filename.str, F_OK) == 0)
2675
2695
  {
2676
2696
    /* The file should not be overwritten */
2677
 
    die("File already exist: '%s'", ds_filename.c_str());
 
2697
    die("File already exist: '%s'", ds_filename.str);
2678
2698
  }
2679
2699
 
 
2700
  init_dynamic_string(&ds_content, "", 1024, 1024);
2680
2701
  read_until_delimiter(&ds_content, &ds_delimiter);
2681
 
  str_to_file2(ds_filename.c_str(), ds_content.c_str(),
2682
 
               ds_content.length(), append);
 
2702
  str_to_file2(ds_filename.str, ds_content.str, ds_content.length, append);
 
2703
  dynstr_free(&ds_content);
 
2704
  dynstr_free(&ds_filename);
 
2705
  dynstr_free(&ds_delimiter);
2683
2706
  return;
2684
2707
}
2685
2708
 
2687
2710
/*
2688
2711
  SYNOPSIS
2689
2712
  do_write_file
2690
 
  command  called command
 
2713
  command       called command
2691
2714
 
2692
2715
  DESCRIPTION
2693
2716
  write_file <file_name> [<delimiter>];
2713
2736
 
2714
2737
static void do_write_file(struct st_command *command)
2715
2738
{
2716
 
  do_write_file_command(command, false);
 
2739
  do_write_file_command(command, FALSE);
2717
2740
}
2718
2741
 
2719
2742
 
2720
2743
/*
2721
2744
  SYNOPSIS
2722
2745
  do_append_file
2723
 
  command  called command
 
2746
  command       called command
2724
2747
 
2725
2748
  DESCRIPTION
2726
2749
  append_file <file_name> [<delimiter>];
2744
2767
 
2745
2768
static void do_append_file(struct st_command *command)
2746
2769
{
2747
 
  do_write_file_command(command, true);
 
2770
  do_write_file_command(command, TRUE);
2748
2771
}
2749
2772
 
2750
2773
 
2751
2774
/*
2752
2775
  SYNOPSIS
2753
2776
  do_cat_file
2754
 
  command  called command
 
2777
  command       called command
2755
2778
 
2756
2779
  DESCRIPTION
2757
2780
  cat_file <file_name>;
2762
2785
 
2763
2786
static void do_cat_file(struct st_command *command)
2764
2787
{
2765
 
  static string ds_filename;
 
2788
  static DYNAMIC_STRING ds_filename;
2766
2789
  const struct command_arg cat_file_args[] = {
2767
 
    { "filename", ARG_STRING, true, &ds_filename, "File to read from" }
 
2790
    { "filename", ARG_STRING, TRUE, &ds_filename, "File to read from" }
2768
2791
  };
2769
2792
 
2770
2793
 
2774
2797
                     sizeof(cat_file_args)/sizeof(struct command_arg),
2775
2798
                     ' ');
2776
2799
 
2777
 
  cat_file(&ds_res, ds_filename.c_str());
 
2800
  cat_file(&ds_res, ds_filename.str);
2778
2801
 
 
2802
  dynstr_free(&ds_filename);
2779
2803
  return;
2780
2804
}
2781
2805
 
2783
2807
/*
2784
2808
  SYNOPSIS
2785
2809
  do_diff_files
2786
 
  command  called command
 
2810
  command       called command
2787
2811
 
2788
2812
  DESCRIPTION
2789
2813
  diff_files <file1> <file2>;
2795
2819
static void do_diff_files(struct st_command *command)
2796
2820
{
2797
2821
  int error= 0;
2798
 
  string ds_filename;
2799
 
  string ds_filename2;
 
2822
  static DYNAMIC_STRING ds_filename;
 
2823
  static DYNAMIC_STRING ds_filename2;
2800
2824
  const struct command_arg diff_file_args[] = {
2801
 
    { "file1", ARG_STRING, true, &ds_filename, "First file to diff" },
2802
 
    { "file2", ARG_STRING, true, &ds_filename2, "Second file to diff" }
 
2825
    { "file1", ARG_STRING, TRUE, &ds_filename, "First file to diff" },
 
2826
    { "file2", ARG_STRING, TRUE, &ds_filename2, "Second file to diff" }
2803
2827
  };
2804
2828
 
2805
2829
 
2809
2833
                     sizeof(diff_file_args)/sizeof(struct command_arg),
2810
2834
                     ' ');
2811
2835
 
2812
 
  if ((error= compare_files(ds_filename.c_str(), ds_filename2.c_str())))
 
2836
  if ((error= compare_files(ds_filename.str, ds_filename2.str)))
2813
2837
  {
2814
2838
    /* Compare of the two files failed, append them to output
2815
2839
       so the failure can be analyzed
2816
2840
    */
2817
 
    show_diff(&ds_res, ds_filename.c_str(), ds_filename2.c_str());
 
2841
    show_diff(&ds_res, ds_filename.str, ds_filename2.str);
2818
2842
  }
2819
2843
 
 
2844
  dynstr_free(&ds_filename);
 
2845
  dynstr_free(&ds_filename2);
2820
2846
  handle_command_error(command, error);
 
2847
  return;
2821
2848
}
2822
2849
 
2823
2850
 
2838
2865
/*
2839
2866
  SYNOPSIS
2840
2867
  do_send_quit
2841
 
  command  called command
 
2868
  command       called command
2842
2869
 
2843
2870
  DESCRIPTION
2844
2871
  Sends a simple quit command to the server for the named connection.
2849
2876
{
2850
2877
  char *p= command->first_argument, *name;
2851
2878
  struct st_connection *con;
2852
 
  drizzle_result_st result;
2853
 
  drizzle_return_t ret;
2854
2879
 
2855
2880
  if (!*p)
2856
2881
    die("Missing connection name in send_quit");
2865
2890
  if (!(con= find_connection_by_name(name)))
2866
2891
    die("connection '%s' not found in connection pool", name);
2867
2892
 
2868
 
  if (drizzle_quit(&con->con,&result, &ret))
2869
 
    drizzle_result_free(&result);
 
2893
  simple_command(&con->mysql,COM_QUIT,0,0,1);
 
2894
 
 
2895
  return;
2870
2896
}
2871
2897
 
2872
2898
 
2886
2912
 
2887
2913
*/
2888
2914
 
2889
 
static void do_change_user(struct st_command *)
 
2915
static void do_change_user(struct st_command *command)
2890
2916
{
2891
 
  assert(0);
 
2917
  MYSQL *mysql = &cur_con->mysql;
 
2918
  /* static keyword to make the NetWare compiler happy. */
 
2919
  static DYNAMIC_STRING ds_user, ds_passwd, ds_db;
 
2920
  const struct command_arg change_user_args[] = {
 
2921
    { "user", ARG_STRING, FALSE, &ds_user, "User to connect as" },
 
2922
    { "password", ARG_STRING, FALSE, &ds_passwd, "Password used when connecting" },
 
2923
    { "database", ARG_STRING, FALSE, &ds_db, "Database to select after connect" },
 
2924
  };
 
2925
 
 
2926
 
 
2927
 
 
2928
  check_command_args(command, command->first_argument,
 
2929
                     change_user_args,
 
2930
                     sizeof(change_user_args)/sizeof(struct command_arg),
 
2931
                     ',');
 
2932
 
 
2933
  if (!ds_user.length)
 
2934
    dynstr_set(&ds_user, mysql->user);
 
2935
 
 
2936
  if (!ds_passwd.length)
 
2937
    dynstr_set(&ds_passwd, mysql->passwd);
 
2938
 
 
2939
  if (!ds_db.length)
 
2940
    dynstr_set(&ds_db, mysql->db);
 
2941
 
 
2942
  if (mysql_change_user(mysql, ds_user.str, ds_passwd.str, ds_db.str))
 
2943
    die("change user failed: %s", mysql_error(mysql));
 
2944
 
 
2945
  dynstr_free(&ds_user);
 
2946
  dynstr_free(&ds_passwd);
 
2947
  dynstr_free(&ds_db);
 
2948
 
 
2949
  return;
2892
2950
}
2893
2951
 
 
2952
 
2894
2953
/*
2895
2954
  SYNOPSIS
2896
2955
  do_perl
2897
 
  command  command handle
 
2956
  command       command handle
2898
2957
 
2899
2958
  DESCRIPTION
2900
2959
  perl [<delimiter>];
2913
2972
static void do_perl(struct st_command *command)
2914
2973
{
2915
2974
  int error;
2916
 
  int fd;
 
2975
  File fd;
2917
2976
  FILE *res_file;
2918
2977
  char buf[FN_REFLEN];
2919
2978
  char temp_file_path[FN_REFLEN];
2920
 
  string ds_script;
2921
 
  string ds_delimiter;
 
2979
  static DYNAMIC_STRING ds_script;
 
2980
  static DYNAMIC_STRING ds_delimiter;
2922
2981
  const struct command_arg perl_args[] = {
2923
 
    { "delimiter", ARG_STRING, false, &ds_delimiter, "Delimiter to read until" }
 
2982
    { "delimiter", ARG_STRING, FALSE, &ds_delimiter, "Delimiter to read until" }
2924
2983
  };
2925
2984
 
2926
2985
 
2931
2990
                     ' ');
2932
2991
 
2933
2992
  /* If no delimiter was provided, use EOF */
2934
 
  if (ds_delimiter.length() == 0)
2935
 
    ds_delimiter.append("EOF");
 
2993
  if (ds_delimiter.length == 0)
 
2994
    dynstr_set(&ds_delimiter, "EOF");
2936
2995
 
 
2996
  init_dynamic_string(&ds_script, "", 1024, 1024);
2937
2997
  read_until_delimiter(&ds_script, &ds_delimiter);
2938
2998
 
2939
2999
  /* Create temporary file name */
2940
 
  if ((fd= internal::create_temp_file(temp_file_path, getenv("MYSQLTEST_VARDIR"),
2941
 
                            "tmp", MYF(MY_WME))) < 0)
 
3000
  if ((fd= create_temp_file(temp_file_path, getenv("MYSQLTEST_VARDIR"),
 
3001
                            "tmp", O_CREAT | O_SHARE | O_RDWR,
 
3002
                            MYF(MY_WME))) < 0)
2942
3003
    die("Failed to create temporary file for perl command");
2943
 
  internal::my_close(fd, MYF(0));
 
3004
  my_close(fd, MYF(0));
2944
3005
 
2945
 
  str_to_file(temp_file_path, ds_script.c_str(), ds_script.length());
 
3006
  str_to_file(temp_file_path, ds_script.str, ds_script.length);
2946
3007
 
2947
3008
  /* Format the "perl <filename>" command */
2948
3009
  snprintf(buf, sizeof(buf), "perl %s", temp_file_path);
2955
3016
    if (disable_result_log)
2956
3017
      buf[strlen(buf)-1]=0;
2957
3018
    else
2958
 
      replace_append(&ds_res, buf);
 
3019
      replace_dynstr_append(&ds_res, buf);
2959
3020
  }
2960
3021
  error= pclose(res_file);
2961
3022
 
2962
3023
  /* Remove the temporary file */
2963
 
  internal::my_delete(temp_file_path, MYF(0));
 
3024
  my_delete(temp_file_path, MYF(0));
2964
3025
 
2965
3026
  handle_command_error(command, WEXITSTATUS(error));
 
3027
  dynstr_free(&ds_script);
 
3028
  dynstr_free(&ds_delimiter);
 
3029
  return;
2966
3030
}
2967
3031
 
2968
3032
 
2969
3033
/*
2970
3034
  Print the content between echo and <delimiter> to result file.
2971
3035
  Evaluate all variables in the string before printing, allow
2972
 
  for variable names to be escaped using        \
 
3036
  for variable names to be escaped using \
2973
3037
 
2974
3038
  SYNOPSIS
2975
3039
  do_echo()
2992
3056
 
2993
3057
static int do_echo(struct st_command *command)
2994
3058
{
2995
 
  string ds_echo;
2996
 
 
2997
 
 
2998
 
  do_eval(&ds_echo, command->first_argument, command->end, false);
2999
 
  ds_res.append(ds_echo.c_str(), ds_echo.length());
3000
 
  ds_res.append("\n");
 
3059
  DYNAMIC_STRING ds_echo;
 
3060
 
 
3061
 
 
3062
  init_dynamic_string(&ds_echo, "", command->query_len, 256);
 
3063
  do_eval(&ds_echo, command->first_argument, command->end, FALSE);
 
3064
  dynstr_append_mem(&ds_res, ds_echo.str, ds_echo.length);
 
3065
  dynstr_append_mem(&ds_res, "\n", 1);
 
3066
  dynstr_free(&ds_echo);
3001
3067
  command->last_argument= command->end;
3002
3068
  return(0);
3003
3069
}
3004
3070
 
3005
3071
 
3006
3072
static void
3007
 
do_wait_for_slave_to_stop(struct st_command *)
 
3073
do_wait_for_slave_to_stop(struct st_command *c __attribute__((unused)))
3008
3074
{
3009
3075
  static int SLAVE_POLL_INTERVAL= 300000;
3010
 
  drizzle_con_st *con= &cur_con->con;
 
3076
  MYSQL* mysql = &cur_con->mysql;
3011
3077
  for (;;)
3012
3078
  {
3013
 
    drizzle_result_st res;
3014
 
    drizzle_return_t ret;
3015
 
    drizzle_row_t row;
 
3079
    MYSQL_RES *res= NULL;
 
3080
    MYSQL_ROW row;
3016
3081
    int done;
3017
3082
 
3018
 
    if (drizzle_query_str(con,&res,"show status like 'Slave_running'",
3019
 
                          &ret) == NULL || ret != DRIZZLE_RETURN_OK)
3020
 
    {
3021
 
      if (ret == DRIZZLE_RETURN_ERROR_CODE)
3022
 
      {
3023
 
        die("Query failed while probing slave for stop: %s",
3024
 
            drizzle_result_error(&res));
3025
 
        drizzle_result_free(&res);
3026
 
      }
3027
 
      else
3028
 
      {
3029
 
        die("Query failed while probing slave for stop: %s",
3030
 
            drizzle_con_error(con));
3031
 
      }
3032
 
    }
3033
 
 
3034
 
    if (drizzle_result_column_count(&res) == 0 ||
3035
 
        drizzle_result_buffer(&res) != DRIZZLE_RETURN_OK)
3036
 
    {
 
3083
    if (mysql_query(mysql,"show status like 'Slave_running'") ||
 
3084
        !(res=mysql_store_result(mysql)))
3037
3085
      die("Query failed while probing slave for stop: %s",
3038
 
          drizzle_con_error(con));
3039
 
    }
3040
 
 
3041
 
    if (!(row=drizzle_row_next(&res)) || !row[1])
 
3086
          mysql_error(mysql));
 
3087
    if (!(row=mysql_fetch_row(res)) || !row[1])
3042
3088
    {
3043
 
      drizzle_result_free(&res);
 
3089
      mysql_free_result(res);
3044
3090
      die("Strange result from query while probing slave for stop");
3045
3091
    }
3046
3092
    done = !strcmp(row[1],"OFF");
3047
 
    drizzle_result_free(&res);
 
3093
    mysql_free_result(res);
3048
3094
    if (done)
3049
3095
      break;
3050
 
    usleep(SLAVE_POLL_INTERVAL);
 
3096
    my_sleep(SLAVE_POLL_INTERVAL);
3051
3097
  }
3052
3098
  return;
3053
3099
}
3055
3101
 
3056
3102
static void do_sync_with_master2(long offset)
3057
3103
{
3058
 
  drizzle_result_st res;
3059
 
  drizzle_return_t ret;
3060
 
  drizzle_row_t row;
3061
 
  drizzle_con_st *con= &cur_con->con;
 
3104
  MYSQL_RES *res;
 
3105
  MYSQL_ROW row;
 
3106
  MYSQL *mysql= &cur_con->mysql;
3062
3107
  char query_buf[FN_REFLEN+128];
3063
3108
  int tries= 0;
3064
3109
 
3065
3110
  if (!master_pos.file[0])
3066
3111
    die("Calling 'sync_with_master' without calling 'save_master_pos'");
3067
3112
 
3068
 
  snprintf(query_buf, sizeof(query_buf), "select master_pos_wait('%s', %ld)", master_pos.file,
3069
 
          master_pos.pos + offset);
 
3113
  sprintf(query_buf, "select master_pos_wait('%s', %ld)", master_pos.file,
 
3114
          master_pos.pos + offset);
3070
3115
 
3071
3116
wait_for_position:
3072
3117
 
3073
 
  if (drizzle_query_str(con, &res, query_buf, &ret) == NULL ||
3074
 
      ret != DRIZZLE_RETURN_OK)
3075
 
  {
3076
 
    if (ret == DRIZZLE_RETURN_ERROR_CODE)
3077
 
    {
3078
 
      die("failed in '%s': %d: %s", query_buf, drizzle_result_error_code(&res),
3079
 
           drizzle_result_error(&res));
3080
 
      drizzle_result_free(&res);
3081
 
    }
3082
 
    else
3083
 
      die("failed in '%s': %d: %s", query_buf, ret, drizzle_con_error(con));
3084
 
  }
3085
 
 
3086
 
  if (drizzle_result_column_count(&res) == 0 ||
3087
 
      drizzle_result_buffer(&res) != DRIZZLE_RETURN_OK)
3088
 
    die("drizzle_result_buffer() returned NULL for '%s'", query_buf);
3089
 
 
3090
 
  if (!(row= drizzle_row_next(&res)))
3091
 
  {
3092
 
    drizzle_result_free(&res);
 
3118
  if (mysql_query(mysql, query_buf))
 
3119
    die("failed in '%s': %d: %s", query_buf, mysql_errno(mysql),
 
3120
        mysql_error(mysql));
 
3121
 
 
3122
  if (!(res= mysql_store_result(mysql)))
 
3123
    die("mysql_store_result() returned NULL for '%s'", query_buf);
 
3124
  if (!(row= mysql_fetch_row(res)))
 
3125
  {
 
3126
    mysql_free_result(res);
3093
3127
    die("empty result in %s", query_buf);
3094
3128
  }
3095
3129
  if (!row[0])
3098
3132
      It may be that the slave SQL thread has not started yet, though START
3099
3133
      SLAVE has been issued ?
3100
3134
    */
3101
 
    drizzle_result_free(&res);
 
3135
    mysql_free_result(res);
3102
3136
    if (tries++ == 30)
3103
3137
    {
3104
 
      show_query(con, "SHOW MASTER STATUS");
3105
 
      show_query(con, "SHOW SLAVE STATUS");
 
3138
      show_query(mysql, "SHOW MASTER STATUS");
 
3139
      show_query(mysql, "SHOW SLAVE STATUS");
3106
3140
      die("could not sync with master ('%s' returned NULL)", query_buf);
3107
3141
    }
3108
3142
    sleep(1); /* So at most we will wait 30 seconds and make 31 tries */
3109
3143
    goto wait_for_position;
3110
3144
  }
3111
 
  drizzle_result_free(&res);
 
3145
  mysql_free_result(res);
3112
3146
  return;
3113
3147
}
3114
3148
 
3134
3168
 
3135
3169
/*
3136
3170
  when ndb binlog is on, this call will wait until last updated epoch
3137
 
  (locally in the drizzled) has been received into the binlog
 
3171
  (locally in the mysqld) has been received into the binlog
3138
3172
*/
3139
 
static int do_save_master_pos()
 
3173
static int do_save_master_pos(void)
3140
3174
{
3141
 
  drizzle_result_st res;
3142
 
  drizzle_return_t ret;
3143
 
  drizzle_row_t row;
3144
 
  drizzle_con_st *con= &cur_con->con;
 
3175
  MYSQL_RES *res;
 
3176
  MYSQL_ROW row;
 
3177
  MYSQL *mysql = &cur_con->mysql;
3145
3178
  const char *query;
3146
3179
 
3147
3180
 
3148
 
  if (drizzle_query_str(con, &res, query= "show master status", &ret) == NULL ||
3149
 
      ret != DRIZZLE_RETURN_OK)
 
3181
#ifdef HAVE_NDB_BINLOG
 
3182
  /*
 
3183
    Wait for ndb binlog to be up-to-date with all changes
 
3184
    done on the local mysql server
 
3185
  */
3150
3186
  {
3151
 
    if (ret == DRIZZLE_RETURN_ERROR_CODE)
 
3187
    ulong have_ndbcluster;
 
3188
    if (mysql_query(mysql, query= "show variables like 'have_ndbcluster'"))
 
3189
      die("'%s' failed: %d %s", query,
 
3190
          mysql_errno(mysql), mysql_error(mysql));
 
3191
    if (!(res= mysql_store_result(mysql)))
 
3192
      die("mysql_store_result() returned NULL for '%s'", query);
 
3193
    if (!(row= mysql_fetch_row(res)))
 
3194
      die("Query '%s' returned empty result", query);
 
3195
 
 
3196
    have_ndbcluster= strcmp("YES", row[1]) == 0;
 
3197
    mysql_free_result(res);
 
3198
 
 
3199
    if (have_ndbcluster)
3152
3200
    {
3153
 
      die("failed in '%s': %d: %s", query, drizzle_result_error_code(&res),
3154
 
           drizzle_result_error(&res));
3155
 
      drizzle_result_free(&res);
 
3201
      uint64_t start_epoch= 0, handled_epoch= 0,
 
3202
        latest_epoch=0, latest_trans_epoch=0,
 
3203
        latest_handled_binlog_epoch= 0, latest_received_binlog_epoch= 0,
 
3204
        latest_applied_binlog_epoch= 0;
 
3205
      int count= 0;
 
3206
      int do_continue= 1;
 
3207
      while (do_continue)
 
3208
      {
 
3209
        const char binlog[]= "binlog";
 
3210
        const char latest_epoch_str[]=
 
3211
          "latest_epoch=";
 
3212
        const char latest_trans_epoch_str[]=
 
3213
          "latest_trans_epoch=";
 
3214
        const char latest_received_binlog_epoch_str[]=
 
3215
          "latest_received_binlog_epoch";
 
3216
        const char latest_handled_binlog_epoch_str[]=
 
3217
          "latest_handled_binlog_epoch=";
 
3218
        const char latest_applied_binlog_epoch_str[]=
 
3219
          "latest_applied_binlog_epoch=";
 
3220
        if (count)
 
3221
          sleep(1);
 
3222
        if (mysql_query(mysql, query= "show engine ndb status"))
 
3223
          die("failed in '%s': %d %s", query,
 
3224
              mysql_errno(mysql), mysql_error(mysql));
 
3225
        if (!(res= mysql_store_result(mysql)))
 
3226
          die("mysql_store_result() returned NULL for '%s'", query);
 
3227
        while ((row= mysql_fetch_row(res)))
 
3228
        {
 
3229
          if (strcmp(row[1], binlog) == 0)
 
3230
          {
 
3231
            const char *status= row[2];
 
3232
 
 
3233
            /* latest_epoch */
 
3234
            while (*status && strncmp(status, latest_epoch_str,
 
3235
                                      sizeof(latest_epoch_str)-1))
 
3236
              status++;
 
3237
            if (*status)
 
3238
            {
 
3239
              status+= sizeof(latest_epoch_str)-1;
 
3240
              latest_epoch= strtoull(status, (char**) 0, 10);
 
3241
            }
 
3242
            else
 
3243
              die("result does not contain '%s' in '%s'",
 
3244
                  latest_epoch_str, query);
 
3245
            /* latest_trans_epoch */
 
3246
            while (*status && strncmp(status, latest_trans_epoch_str,
 
3247
                                      sizeof(latest_trans_epoch_str)-1))
 
3248
              status++;
 
3249
            if (*status)
 
3250
            {
 
3251
              status+= sizeof(latest_trans_epoch_str)-1;
 
3252
              latest_trans_epoch= strtoull(status, (char**) 0, 10);
 
3253
            }
 
3254
            else
 
3255
              die("result does not contain '%s' in '%s'",
 
3256
                  latest_trans_epoch_str, query);
 
3257
            /* latest_received_binlog_epoch */
 
3258
            while (*status &&
 
3259
                   strncmp(status, latest_received_binlog_epoch_str,
 
3260
                           sizeof(latest_received_binlog_epoch_str)-1))
 
3261
              status++;
 
3262
            if (*status)
 
3263
            {
 
3264
              status+= sizeof(latest_received_binlog_epoch_str)-1;
 
3265
              latest_received_binlog_epoch= strtoull(status, (char**) 0, 10);
 
3266
            }
 
3267
            else
 
3268
              die("result does not contain '%s' in '%s'",
 
3269
                  latest_received_binlog_epoch_str, query);
 
3270
            /* latest_handled_binlog */
 
3271
            while (*status &&
 
3272
                   strncmp(status, latest_handled_binlog_epoch_str,
 
3273
                           sizeof(latest_handled_binlog_epoch_str)-1))
 
3274
              status++;
 
3275
            if (*status)
 
3276
            {
 
3277
              status+= sizeof(latest_handled_binlog_epoch_str)-1;
 
3278
              latest_handled_binlog_epoch= strtoull(status, (char**) 0, 10);
 
3279
            }
 
3280
            else
 
3281
              die("result does not contain '%s' in '%s'",
 
3282
                  latest_handled_binlog_epoch_str, query);
 
3283
            /* latest_applied_binlog_epoch */
 
3284
            while (*status &&
 
3285
                   strncmp(status, latest_applied_binlog_epoch_str,
 
3286
                           sizeof(latest_applied_binlog_epoch_str)-1))
 
3287
              status++;
 
3288
            if (*status)
 
3289
            {
 
3290
              status+= sizeof(latest_applied_binlog_epoch_str)-1;
 
3291
              latest_applied_binlog_epoch= strtoull(status, (char**) 0, 10);
 
3292
            }
 
3293
            else
 
3294
              die("result does not contain '%s' in '%s'",
 
3295
                  latest_applied_binlog_epoch_str, query);
 
3296
            if (count == 0)
 
3297
              start_epoch= latest_trans_epoch;
 
3298
            break;
 
3299
          }
 
3300
        }
 
3301
        if (!row)
 
3302
          die("result does not contain '%s' in '%s'",
 
3303
              binlog, query);
 
3304
        if (latest_handled_binlog_epoch > handled_epoch)
 
3305
          count= 0;
 
3306
        handled_epoch= latest_handled_binlog_epoch;
 
3307
        count++;
 
3308
        if (latest_handled_binlog_epoch >= start_epoch)
 
3309
          do_continue= 0;
 
3310
        else if (count > 30)
 
3311
        {
 
3312
          break;
 
3313
        }
 
3314
        mysql_free_result(res);
 
3315
      }
3156
3316
    }
3157
 
    else
3158
 
      die("failed in '%s': %d: %s", query, ret, drizzle_con_error(con));
3159
3317
  }
 
3318
#endif
 
3319
  if (mysql_query(mysql, query= "show master status"))
 
3320
    die("failed in 'show master status': %d %s",
 
3321
        mysql_errno(mysql), mysql_error(mysql));
3160
3322
 
3161
 
  if (drizzle_result_column_count(&res) == 0 ||
3162
 
      drizzle_result_buffer(&res) != DRIZZLE_RETURN_OK)
3163
 
    die("drizzleclient_store_result() retuned NULL for '%s'", query);
3164
 
  if (!(row = drizzle_row_next(&res)))
 
3323
  if (!(res = mysql_store_result(mysql)))
 
3324
    die("mysql_store_result() retuned NULL for '%s'", query);
 
3325
  if (!(row = mysql_fetch_row(res)))
3165
3326
    die("empty result in show master status");
3166
 
  strncpy(master_pos.file, row[0], sizeof(master_pos.file)-1);
 
3327
  strnmov(master_pos.file, row[0], sizeof(master_pos.file)-1);
3167
3328
  master_pos.pos = strtoul(row[1], (char**) 0, 10);
3168
 
  drizzle_result_free(&res);
 
3329
  mysql_free_result(res);
3169
3330
  return(0);
3170
3331
}
3171
3332
 
3175
3336
 
3176
3337
  SYNOPSIS
3177
3338
  do_let()
3178
 
  query  called command
 
3339
  query called command
3179
3340
 
3180
3341
  DESCRIPTION
3181
3342
  let $<var_name>=<var_val><delimiter>
3193
3354
{
3194
3355
  char *p= command->first_argument;
3195
3356
  char *var_name, *var_name_end;
3196
 
  string let_rhs_expr;
3197
 
 
 
3357
  DYNAMIC_STRING let_rhs_expr;
 
3358
 
 
3359
 
 
3360
  init_dynamic_string(&let_rhs_expr, "", 512, 2048);
3198
3361
 
3199
3362
  /* Find <var_name> */
3200
3363
  if (!*p)
3215
3378
  while (*p && my_isspace(charset_info,*p))
3216
3379
    p++;
3217
3380
 
3218
 
  do_eval(&let_rhs_expr, p, command->end, false);
 
3381
  do_eval(&let_rhs_expr, p, command->end, FALSE);
3219
3382
 
3220
3383
  command->last_argument= command->end;
3221
3384
  /* Assign var_val to var_name */
3222
 
  var_set(var_name, var_name_end, let_rhs_expr.c_str(),
3223
 
          (let_rhs_expr.c_str() + let_rhs_expr.length()));
 
3385
  var_set(var_name, var_name_end, let_rhs_expr.str,
 
3386
          (let_rhs_expr.str + let_rhs_expr.length));
 
3387
  dynstr_free(&let_rhs_expr);
3224
3388
  return;
3225
3389
}
3226
3390
 
3230
3394
 
3231
3395
  SYNOPSIS
3232
3396
  do_sleep()
3233
 
  q         called command
 
3397
  q            called command
3234
3398
  real_sleep   use the value from opt_sleep as number of seconds to sleep
3235
 
  if real_sleep is false
 
3399
               if real_sleep is false
3236
3400
 
3237
3401
  DESCRIPTION
3238
3402
  sleep <seconds>
3249
3413
 
3250
3414
static int do_sleep(struct st_command *command, bool real_sleep)
3251
3415
{
3252
 
  bool error= false;
 
3416
  int error= 0;
3253
3417
  char *p= command->first_argument;
3254
3418
  char *sleep_start, *sleep_end= command->end;
3255
 
  double sleep_val= 0;
 
3419
  double sleep_val;
3256
3420
 
3257
3421
  while (my_isspace(charset_info, *p))
3258
3422
    p++;
3259
3423
  if (!*p)
3260
3424
    die("Missing argument to %.*s", command->first_word_len, command->query);
3261
3425
  sleep_start= p;
3262
 
  /* Check that arg starts with a digit, not handled by internal::my_strtod */
 
3426
  /* Check that arg starts with a digit, not handled by my_strtod */
3263
3427
  if (!my_isdigit(charset_info, *sleep_start))
3264
3428
    die("Invalid argument to %.*s \"%s\"", command->first_word_len,
3265
3429
        command->query,command->first_argument);
3266
 
  string buff_str(sleep_start, sleep_end-sleep_start);
3267
 
  istringstream buff(buff_str);
3268
 
  error= (buff >> sleep_val).fail();
 
3430
  sleep_val= my_strtod(sleep_start, &sleep_end, &error);
3269
3431
  if (error)
3270
3432
    die("Invalid argument to %.*s \"%s\"", command->first_word_len,
3271
3433
        command->query, command->first_argument);
3275
3437
    sleep_val= opt_sleep;
3276
3438
 
3277
3439
  if (sleep_val)
3278
 
    usleep(sleep_val * 1000000);
 
3440
    my_sleep((ulong) (sleep_val * 1000000L));
3279
3441
  command->last_argument= sleep_end;
3280
3442
  return 0;
3281
3443
}
3282
3444
 
3283
3445
 
3284
 
static void do_get_file_name(st_command *command, string &dest)
 
3446
static void do_get_file_name(struct st_command *command,
 
3447
                      char* dest, uint dest_max_len)
3285
3448
{
3286
 
  char *p= command->first_argument;
 
3449
  char *p= command->first_argument, *name;
3287
3450
  if (!*p)
3288
3451
    die("Missing file name argument");
3289
 
  char *name= p;
 
3452
  name= p;
3290
3453
  while (*p && !my_isspace(charset_info,*p))
3291
3454
    p++;
3292
3455
  if (*p)
3293
3456
    *p++= 0;
3294
3457
  command->last_argument= p;
3295
 
  if (! opt_testdir.empty())
3296
 
  {
3297
 
    dest= opt_testdir;
3298
 
    if (dest[dest.length()] != '/')
3299
 
      dest.append("/");
3300
 
  }
3301
 
  dest.append(name);
 
3458
  strmake(dest, name, dest_max_len - 1);
3302
3459
}
3303
3460
 
3304
3461
 
3316
3473
  if(*p)
3317
3474
    *p++= 0;
3318
3475
  command->last_argument= p;
3319
 
  charset_info= get_charset_by_csname(charset_name, MY_CS_PRIMARY);
 
3476
  charset_info= get_charset_by_csname(charset_name,MY_CS_PRIMARY,MYF(MY_WME));
3320
3477
  if (!charset_info)
3321
3478
    abort_not_supported_test("Test requires charset '%s'", charset_name);
3322
3479
}
3323
3480
 
3324
 
static void fill_global_error_names()
3325
 
{
3326
 
  drizzle_result_st res;
3327
 
  drizzle_return_t ret;
3328
 
  drizzle_row_t row;
3329
 
  drizzle_con_st *con= &cur_con->con;
3330
 
 
3331
 
  global_error_names.clear();
3332
 
 
3333
 
  const std::string ds_query("select error_name, error_code "
3334
 
                             "from data_dictionary.errors");
3335
 
  if (drizzle_query_str(con, &res, ds_query.c_str(), &ret) == NULL ||
3336
 
      ret != DRIZZLE_RETURN_OK)
3337
 
  {
3338
 
    if (ret == DRIZZLE_RETURN_ERROR_CODE)
3339
 
    {
3340
 
      die("Error running query '%s': %d %s", ds_query.c_str(),
3341
 
          drizzle_result_error_code(&res), drizzle_result_error(&res));
3342
 
      drizzle_result_free(&res);
3343
 
    }
3344
 
    else
3345
 
    {
3346
 
      die("Error running query '%s': %d %s", ds_query.c_str(), ret,
3347
 
          drizzle_con_error(con));
3348
 
    }
3349
 
  }
3350
 
  if (drizzle_result_column_count(&res) == 0 ||
3351
 
      drizzle_result_buffer(&res) != DRIZZLE_RETURN_OK)
3352
 
  {
3353
 
    drizzle_result_free(&res);
3354
 
    die("Query '%s' didn't return a result set", ds_query.c_str());
3355
 
  }
3356
 
 
3357
 
  while ((row= drizzle_row_next(&res)) && row[0])
 
3481
 
 
3482
#if MYSQL_VERSION_ID >= 50000
 
3483
/* List of error names to error codes, available from 5.0 */
 
3484
typedef struct
 
3485
{
 
3486
  const char *name;
 
3487
  uint        code;
 
3488
} st_error;
 
3489
 
 
3490
static st_error global_error_names[] =
 
3491
{
 
3492
#include <mysqld_ername.h>
 
3493
  { 0, 0 }
 
3494
};
 
3495
 
 
3496
static uint get_errcode_from_name(char *error_name, char *error_end)
 
3497
{
 
3498
  /* SQL error as string */
 
3499
  st_error *e= global_error_names;
 
3500
 
 
3501
  /* Loop through the array of known error names */
 
3502
  for (; e->name; e++)
3358
3503
  {
3359
3504
    /*
3360
 
      Concatenate all fields in the first row with tab in between
3361
 
      and assign that string to the $variable
 
3505
      If we get a match, we need to check the length of the name we
 
3506
      matched against in case it was longer than what we are checking
 
3507
      (as in ER_WRONG_VALUE vs. ER_WRONG_VALUE_COUNT).
3362
3508
    */
3363
 
    size_t *lengths= drizzle_row_field_sizes(&res);
3364
 
    try
3365
 
    {
3366
 
      global_error_names[string(row[0], lengths[0])] = boost::lexical_cast<uint32_t>(string(row[1], lengths[1]));
3367
 
    }
3368
 
    catch (boost::bad_lexical_cast &ex)
3369
 
    {
3370
 
      drizzle_result_free(&res);
3371
 
      die("Invalid error_code from Drizzle: %s", ex.what());
3372
 
    }
3373
 
 
 
3509
    if (!strncmp(error_name, e->name, (int) (error_end - error_name)) &&
 
3510
        (uint) strlen(e->name) == (uint) (error_end - error_name))
 
3511
    {
 
3512
      return(e->code);
 
3513
    }
3374
3514
  }
3375
 
 
3376
 
  drizzle_result_free(&res);
 
3515
  if (!e->name)
 
3516
    die("Unknown SQL error name '%s'", error_name);
 
3517
  return(0);
3377
3518
}
3378
 
 
3379
 
static uint32_t get_errcode_from_name(char *error_name, char *error_end)
 
3519
#else
 
3520
uint get_errcode_from_name(char *error_name __attribute__((unused)),
 
3521
                           char *error_end __attribute__((unused)))
3380
3522
{
3381
 
  size_t err_name_len= error_end - error_name;
3382
 
  string error_name_s(error_name, err_name_len);
3383
 
 
3384
 
  ErrorCodes::iterator it= global_error_names.find(error_name_s);
3385
 
  if (it != global_error_names.end())
3386
 
    return it->second;
3387
 
 
3388
 
  die("Unknown SQL error name '%s'", error_name_s.c_str());
3389
 
  return 0;
 
3523
  abort_not_in_this_version();
 
3524
  return 0; /* Never reached */
3390
3525
}
 
3526
#endif
 
3527
 
 
3528
 
3391
3529
 
3392
3530
static void do_get_errcodes(struct st_command *command)
3393
3531
{
3394
3532
  struct st_match_err *to= saved_expected_errors.err;
3395
3533
  char *p= command->first_argument;
3396
 
  uint32_t count= 0;
 
3534
  uint count= 0;
3397
3535
 
3398
3536
 
3399
3537
 
3419
3557
 
3420
3558
      /*
3421
3559
        SQLSTATE string
3422
 
        - Must be DRIZZLE_MAX_SQLSTATE_SIZE long
 
3560
        - Must be SQLSTATE_LENGTH long
3423
3561
        - May contain only digits[0-9] and _uppercase_ letters
3424
3562
      */
3425
3563
      p++; /* Step past the S */
3426
 
      if ((end - p) != DRIZZLE_MAX_SQLSTATE_SIZE)
3427
 
        die("The sqlstate must be exactly %d chars long", DRIZZLE_MAX_SQLSTATE_SIZE);
 
3564
      if ((end - p) != SQLSTATE_LENGTH)
 
3565
        die("The sqlstate must be exactly %d chars long", SQLSTATE_LENGTH);
3428
3566
 
3429
3567
      /* Check sqlstate string validity */
3430
3568
      while (*p && p < end)
3432
3570
        if (my_isdigit(charset_info, *p) || my_isupper(charset_info, *p))
3433
3571
          *to_ptr++= *p++;
3434
3572
        else
3435
 
          die("The sqlstate may only consist of digits[0-9] "   \
 
3573
          die("The sqlstate may only consist of digits[0-9] " \
3436
3574
              "and _uppercase_ letters");
3437
3575
      }
3438
3576
 
3454
3592
    {
3455
3593
      die("The error name definition must start with an uppercase E");
3456
3594
    }
3457
 
    else if (*p == 'H')
 
3595
    else
3458
3596
    {
3459
 
      /* Error name string */
3460
 
 
3461
 
      to->code.errnum= get_errcode_from_name(p, end);
 
3597
      long val;
 
3598
      char *start= p;
 
3599
      /* Check that the string passed to str2int only contain digits */
 
3600
      while (*p && p != end)
 
3601
      {
 
3602
        if (!my_isdigit(charset_info, *p))
 
3603
          die("Invalid argument to error: '%s' - "\
 
3604
              "the errno may only consist of digits[0-9]",
 
3605
              command->first_argument);
 
3606
        p++;
 
3607
      }
 
3608
 
 
3609
      /* Convert the sting to int */
 
3610
      if (!str2int(start, 10, (long) INT_MIN, (long) INT_MAX, &val))
 
3611
        die("Invalid argument to error: '%s'", command->first_argument);
 
3612
 
 
3613
      to->code.errnum= (uint) val;
3462
3614
      to->type= ERR_ERRNO;
3463
3615
    }
3464
 
    else
3465
 
    {
3466
 
      die ("You must either use the SQLSTATE or built in drizzle error label, numbers are not accepted");
3467
 
    }
3468
3616
    to++;
3469
3617
    count++;
3470
3618
 
3510
3658
  if (*from == '"' || *from == '\'')
3511
3659
    sep= *from++;
3512
3660
  else
3513
 
    sep=' ';        /* Separated with space */
 
3661
    sep=' ';                            /* Separated with space */
3514
3662
 
3515
3663
  for ( ; (c=*from) ; from++)
3516
3664
  {
3517
3665
    if (c == '\\' && from[1])
3518
 
    {          /* Escaped character */
 
3666
    {                                   /* Escaped character */
3519
3667
      /* We can't translate \0 -> ASCII 0 as replace can't handle ASCII 0 */
3520
3668
      switch (*++from) {
3521
3669
      case 'n':
3522
 
        *to++= '\n';
3523
 
        break;
 
3670
        *to++= '\n';
 
3671
        break;
3524
3672
      case 't':
3525
 
        *to++= '\t';
3526
 
        break;
 
3673
        *to++= '\t';
 
3674
        break;
3527
3675
      case 'r':
3528
 
        *to++ = '\r';
3529
 
        break;
 
3676
        *to++ = '\r';
 
3677
        break;
3530
3678
      case 'b':
3531
 
        *to++ = '\b';
3532
 
        break;
3533
 
      case 'Z':        /* ^Z must be escaped on Win32 */
3534
 
        *to++='\032';
3535
 
        break;
 
3679
        *to++ = '\b';
 
3680
        break;
 
3681
      case 'Z':                         /* ^Z must be escaped on Win32 */
 
3682
        *to++='\032';
 
3683
        break;
3536
3684
      default:
3537
 
        *to++ = *from;
3538
 
        break;
 
3685
        *to++ = *from;
 
3686
        break;
3539
3687
      }
3540
3688
    }
3541
3689
    else if (c == sep)
3542
3690
    {
3543
3691
      if (c == ' ' || c != *++from)
3544
 
        break;        /* Found end of string */
3545
 
      *to++=c;        /* Copy duplicated separator */
 
3692
        break;                          /* Found end of string */
 
3693
      *to++=c;                          /* Copy duplicated separator */
3546
3694
    }
3547
3695
    else
3548
3696
      *to++=c;
3550
3698
  if (*from != ' ' && *from)
3551
3699
    die("Wrong string argument in %s", command->query);
3552
3700
 
3553
 
  while (my_isspace(charset_info,*from))  /* Point to next string */
 
3701
  while (my_isspace(charset_info,*from))        /* Point to next string */
3554
3702
    from++;
3555
3703
 
3556
 
  *to =0;        /* End of string marker */
3557
 
  *to_ptr= to+1;      /* Store pointer to end */
 
3704
  *to =0;                               /* End of string marker */
 
3705
  *to_ptr= to+1;                        /* Store pointer to end */
3558
3706
  *from_ptr= from;
3559
3707
 
3560
3708
  /* Check if this was a variable */
3563
3711
    const char *end= to;
3564
3712
    VAR *var=var_get(start, &end, 0, 1);
3565
3713
    if (var && to == (char*) end+1)
3566
 
      return(var->str_val);  /* return found variable value */
 
3714
      return(var->str_val);     /* return found variable value */
3567
3715
  }
3568
3716
  return(start);
3569
3717
}
3570
3718
 
3571
3719
 
3572
 
static void set_reconnect(drizzle_con_st *con, int val)
 
3720
static void set_reconnect(MYSQL* mysql, int val)
3573
3721
{
3574
 
  (void) con;
3575
 
  (void) val;
3576
 
/* XXX
3577
3722
  bool reconnect= val;
3578
3723
 
3579
 
  drizzleclient_options(drizzle, DRIZZLE_OPT_RECONNECT, (char *)&reconnect);
3580
 
*/
 
3724
  mysql_options(mysql, MYSQL_OPT_RECONNECT, (char *)&reconnect);
 
3725
 
 
3726
  return;
3581
3727
}
3582
3728
 
3583
3729
 
3586
3732
  if (!(cur_con= find_connection_by_name(name)))
3587
3733
    die("connection '%s' not found in connection pool", name);
3588
3734
 
3589
 
  /* Update $drizzleclient_get_server_version to that of current connection */
3590
 
  var_set_drizzleclient_get_server_version(&cur_con->con);
 
3735
  /* Update $mysql_get_server_version to that of current connection */
 
3736
  var_set_mysql_get_server_version(&cur_con->mysql);
3591
3737
 
3592
3738
  return(0);
3593
3739
}
3629
3775
  if (!(con= find_connection_by_name(name)))
3630
3776
    die("connection '%s' not found in connection pool", name);
3631
3777
 
3632
 
  if (con->drizzle != NULL)
 
3778
  if (command->type == Q_DIRTY_CLOSE)
3633
3779
  {
3634
 
    drizzle_free(con->drizzle);
3635
 
    con->drizzle= NULL;
 
3780
    if (con->mysql.net.vio)
 
3781
    {
 
3782
      vio_delete(con->mysql.net.vio);
 
3783
      con->mysql.net.vio = 0;
 
3784
    }
3636
3785
  }
3637
 
  free(con->name);
 
3786
 
 
3787
  mysql_close(&con->mysql);
 
3788
 
 
3789
  if (con->util_mysql)
 
3790
    mysql_close(con->util_mysql);
 
3791
  con->util_mysql= 0;
 
3792
 
 
3793
  my_free(con->name, MYF(0));
3638
3794
 
3639
3795
  /*
3640
3796
    When the connection is closed set name to "-closed_connection-"
3641
3797
    to make it possible to reuse the connection name.
3642
3798
  */
3643
 
  if (!(con->name = strdup("-closed_connection-")))
 
3799
  if (!(con->name = my_strdup("-closed_connection-", MYF(MY_WME))))
3644
3800
    die("Out of memory");
3645
3801
 
3646
3802
  return;
3672
3828
 
3673
3829
*/
3674
3830
 
3675
 
static void safe_connect(drizzle_con_st *con, const char *name,
3676
 
                         const string host, const string user, const char *pass,
3677
 
                         const string db, uint32_t port)
 
3831
static void safe_connect(MYSQL* mysql, const char *name, const char *host,
 
3832
                  const char *user, const char *pass, const char *db,
 
3833
                  int port)
3678
3834
{
3679
 
  uint32_t failed_attempts= 0;
3680
 
  static uint32_t connection_retry_sleep= 100000; /* Microseconds */
3681
 
  drizzle_return_t ret;
3682
 
 
3683
 
  drizzle_con_set_tcp(con, host.c_str(), port);
3684
 
  drizzle_con_set_auth(con, user.c_str(), pass);
3685
 
  drizzle_con_set_db(con, db.c_str());
3686
 
  while((ret= drizzle_con_connect(con)) != DRIZZLE_RETURN_OK)
 
3835
  int failed_attempts= 0;
 
3836
  static ulong connection_retry_sleep= 100000; /* Microseconds */
 
3837
 
 
3838
 
 
3839
  while(!mysql_real_connect(mysql, host, user, pass, db, port, NULL,
 
3840
                            CLIENT_MULTI_STATEMENTS | CLIENT_REMEMBER_OPTIONS))
3687
3841
  {
3688
3842
    /*
3689
3843
      Connect failed
3693
3847
      on protocol/connection type
3694
3848
    */
3695
3849
 
3696
 
    if ((ret == DRIZZLE_RETURN_GETADDRINFO ||
3697
 
         ret == DRIZZLE_RETURN_COULD_NOT_CONNECT) &&
 
3850
    if ((mysql_errno(mysql) == CR_CONN_HOST_ERROR ||
 
3851
         mysql_errno(mysql) == CR_CONNECTION_ERROR) &&
3698
3852
        failed_attempts < opt_max_connect_retries)
3699
3853
    {
3700
3854
      verbose_msg("Connect attempt %d/%d failed: %d: %s", failed_attempts,
3701
 
                  opt_max_connect_retries, ret, drizzle_con_error(con));
3702
 
      usleep(connection_retry_sleep);
 
3855
                  opt_max_connect_retries, mysql_errno(mysql),
 
3856
                  mysql_error(mysql));
 
3857
      my_sleep(connection_retry_sleep);
3703
3858
    }
3704
3859
    else
3705
3860
    {
3706
3861
      if (failed_attempts > 0)
3707
3862
        die("Could not open connection '%s' after %d attempts: %d %s", name,
3708
 
            failed_attempts, ret, drizzle_con_error(con));
 
3863
            failed_attempts, mysql_errno(mysql), mysql_error(mysql));
3709
3864
      else
3710
 
        die("Could not open connection '%s': %d %s", name, ret,
3711
 
            drizzle_con_error(con));
 
3865
        die("Could not open connection '%s': %d %s", name,
 
3866
            mysql_errno(mysql), mysql_error(mysql));
3712
3867
    }
3713
3868
    failed_attempts++;
3714
3869
  }
3740
3895
*/
3741
3896
 
3742
3897
static int connect_n_handle_errors(struct st_command *command,
3743
 
                                   drizzle_con_st *con, const char* host,
3744
 
                                   const char* user, const char* pass,
3745
 
                                   const char* db, int port, const char* sock)
 
3898
                            MYSQL* con, const char* host,
 
3899
                            const char* user, const char* pass,
 
3900
                            const char* db, int port, const char* sock)
3746
3901
{
3747
 
  drizzle_return_t ret;
 
3902
  DYNAMIC_STRING *ds;
 
3903
 
 
3904
  ds= &ds_res;
3748
3905
 
3749
3906
  /* Only log if an error is expected */
3750
3907
  if (!command->abort_on_error &&
3753
3910
    /*
3754
3911
      Log the connect to result log
3755
3912
    */
3756
 
    ds_res.append("connect(");
3757
 
    replace_append(&ds_res, host);
3758
 
    ds_res.append(",");
3759
 
    replace_append(&ds_res, user);
3760
 
    ds_res.append(",");
3761
 
    replace_append(&ds_res, pass);
3762
 
    ds_res.append(",");
 
3913
    dynstr_append_mem(ds, "connect(", 8);
 
3914
    replace_dynstr_append(ds, host);
 
3915
    dynstr_append_mem(ds, ",", 1);
 
3916
    replace_dynstr_append(ds, user);
 
3917
    dynstr_append_mem(ds, ",", 1);
 
3918
    replace_dynstr_append(ds, pass);
 
3919
    dynstr_append_mem(ds, ",", 1);
3763
3920
    if (db)
3764
 
      replace_append(&ds_res, db);
3765
 
    ds_res.append(",");
3766
 
    replace_append_uint(&ds_res, port);
3767
 
    ds_res.append(",");
 
3921
      replace_dynstr_append(ds, db);
 
3922
    dynstr_append_mem(ds, ",", 1);
 
3923
    replace_dynstr_append_uint(ds, port);
 
3924
    dynstr_append_mem(ds, ",", 1);
3768
3925
    if (sock)
3769
 
      replace_append(&ds_res, sock);
3770
 
    ds_res.append(")");
3771
 
    ds_res.append(delimiter);
3772
 
    ds_res.append("\n");
 
3926
      replace_dynstr_append(ds, sock);
 
3927
    dynstr_append_mem(ds, ")", 1);
 
3928
    dynstr_append_mem(ds, delimiter, delimiter_length);
 
3929
    dynstr_append_mem(ds, "\n", 1);
3773
3930
  }
3774
 
  drizzle_con_set_tcp(con, host, port);
3775
 
  drizzle_con_set_auth(con, user, pass);
3776
 
  drizzle_con_set_db(con, db);
3777
 
  if ((ret= drizzle_con_connect(con)) != DRIZZLE_RETURN_OK)
 
3931
  if (!mysql_real_connect(con, host, user, pass, db, port, 0,
 
3932
                          CLIENT_MULTI_STATEMENTS))
3778
3933
  {
3779
 
    if (ret == DRIZZLE_RETURN_HANDSHAKE_FAILED)
3780
 
    {
3781
 
      var_set_errno(drizzle_con_error_code(con));
3782
 
      handle_error(command, drizzle_con_error_code(con), drizzle_con_error(con),
3783
 
                   drizzle_con_sqlstate(con), &ds_res);
3784
 
    }
3785
 
    else
3786
 
    {
3787
 
      var_set_errno(ret);
3788
 
      handle_error(command, ret, drizzle_con_error(con), "", &ds_res);
3789
 
    }
3790
 
 
 
3934
    var_set_errno(mysql_errno(con));
 
3935
    handle_error(command, mysql_errno(con), mysql_error(con),
 
3936
                 mysql_sqlstate(con), ds);
3791
3937
    return 0; /* Not connected */
3792
3938
  }
3793
3939
 
3798
3944
 
3799
3945
 
3800
3946
/*
3801
 
  Open a new connection to DRIZZLE Server with the parameters
 
3947
  Open a new connection to MySQL Server with the parameters
3802
3948
  specified. Make the new connection the current connection.
3803
3949
 
3804
3950
  SYNOPSIS
3805
3951
  do_connect()
3806
 
  q         called command
 
3952
  q            called command
3807
3953
 
3808
3954
  DESCRIPTION
3809
3955
  connect(<name>,<host>,<user>,[<pass>,[<db>,[<port>,<sock>[<opts>]]]]);
3817
3963
  <port> - server port
3818
3964
  <sock> - server socket
3819
3965
  <opts> - options to use for the connection
3820
 
  * SSL - use SSL if available
3821
 
  * COMPRESS - use compression if available
 
3966
   * SSL - use SSL if available
 
3967
   * COMPRESS - use compression if available
3822
3968
 
3823
 
  */
 
3969
*/
3824
3970
 
3825
3971
static void do_connect(struct st_command *command)
3826
3972
{
3827
 
  uint32_t con_port= opt_port;
3828
 
  const char *con_options;
3829
 
  bool con_ssl= 0;
 
3973
  int con_port= opt_port;
 
3974
  char *con_options;
 
3975
  bool con_ssl= 0, con_compress= 0;
3830
3976
  struct st_connection* con_slot;
3831
3977
 
3832
 
  string ds_connection_name;
3833
 
  string ds_host;
3834
 
  string ds_user;
3835
 
  string ds_password;
3836
 
  string ds_database;
3837
 
  string ds_port;
3838
 
  string ds_sock;
3839
 
  string ds_options;
 
3978
  static DYNAMIC_STRING ds_connection_name;
 
3979
  static DYNAMIC_STRING ds_host;
 
3980
  static DYNAMIC_STRING ds_user;
 
3981
  static DYNAMIC_STRING ds_password;
 
3982
  static DYNAMIC_STRING ds_database;
 
3983
  static DYNAMIC_STRING ds_port;
 
3984
  static DYNAMIC_STRING ds_sock;
 
3985
  static DYNAMIC_STRING ds_options;
3840
3986
  const struct command_arg connect_args[] = {
3841
 
    { "connection name", ARG_STRING, true, &ds_connection_name, "Name of the connection" },
3842
 
    { "host", ARG_STRING, true, &ds_host, "Host to connect to" },
3843
 
    { "user", ARG_STRING, false, &ds_user, "User to connect as" },
3844
 
    { "passsword", ARG_STRING, false, &ds_password, "Password used when connecting" },
3845
 
    { "database", ARG_STRING, false, &ds_database, "Database to select after connect" },
3846
 
    { "port", ARG_STRING, false, &ds_port, "Port to connect to" },
3847
 
    { "socket", ARG_STRING, false, &ds_sock, "Socket to connect with" },
3848
 
    { "options", ARG_STRING, false, &ds_options, "Options to use while connecting" }
 
3987
    { "connection name", ARG_STRING, TRUE, &ds_connection_name, "Name of the connection" },
 
3988
    { "host", ARG_STRING, TRUE, &ds_host, "Host to connect to" },
 
3989
    { "user", ARG_STRING, FALSE, &ds_user, "User to connect as" },
 
3990
    { "passsword", ARG_STRING, FALSE, &ds_password, "Password used when connecting" },
 
3991
    { "database", ARG_STRING, FALSE, &ds_database, "Database to select after connect" },
 
3992
    { "port", ARG_STRING, FALSE, &ds_port, "Port to connect to" },
 
3993
    { "socket", ARG_STRING, FALSE, &ds_sock, "Socket to connect with" },
 
3994
    { "options", ARG_STRING, FALSE, &ds_options, "Options to use while connecting" }
3849
3995
  };
3850
3996
 
3851
3997
 
3855
4001
                     ',');
3856
4002
 
3857
4003
  /* Port */
3858
 
  if (ds_port.length())
 
4004
  if (ds_port.length)
3859
4005
  {
3860
 
    con_port= atoi(ds_port.c_str());
 
4006
    con_port= atoi(ds_port.str);
3861
4007
    if (con_port == 0)
3862
 
      die("Illegal argument for port: '%s'", ds_port.c_str());
 
4008
      die("Illegal argument for port: '%s'", ds_port.str);
3863
4009
  }
3864
4010
 
3865
4011
  /* Sock */
3866
 
  if (!ds_sock.empty())
 
4012
  if (ds_sock.length)
3867
4013
  {
3868
4014
    /*
3869
4015
      If the socket is specified just as a name without path
3870
4016
      append tmpdir in front
3871
4017
    */
3872
 
    if (*ds_sock.c_str() != FN_LIBCHAR)
 
4018
    if (*ds_sock.str != FN_LIBCHAR)
3873
4019
    {
3874
4020
      char buff[FN_REFLEN];
3875
 
      internal::fn_format(buff, ds_sock.c_str(), TMPDIR, "", 0);
3876
 
      ds_sock.clear();
3877
 
      ds_sock.append(buff);
 
4021
      fn_format(buff, ds_sock.str, TMPDIR, "", 0);
 
4022
      dynstr_set(&ds_sock, buff);
3878
4023
    }
3879
4024
  }
 
4025
  else
 
4026
  {
 
4027
    /* No socket specified, use default */
 
4028
    dynstr_set(&ds_sock, unix_sock);
 
4029
  }
3880
4030
 
3881
4031
  /* Options */
3882
 
  con_options= ds_options.c_str();
 
4032
  con_options= ds_options.str;
3883
4033
  while (*con_options)
3884
4034
  {
3885
 
    const char* end;
 
4035
    char* end;
3886
4036
    /* Step past any spaces in beginning of option*/
3887
4037
    while (*con_options && my_isspace(charset_info, *con_options))
3888
 
      con_options++;
 
4038
     con_options++;
3889
4039
    /* Find end of this option */
3890
4040
    end= con_options;
3891
4041
    while (*end && !my_isspace(charset_info, *end))
3892
4042
      end++;
3893
4043
    if (!strncmp(con_options, "SSL", 3))
3894
4044
      con_ssl= 1;
 
4045
    else if (!strncmp(con_options, "COMPRESS", 8))
 
4046
      con_compress= 1;
3895
4047
    else
3896
 
      die("Illegal option to connect: %.*s",
 
4048
      die("Illegal option to connect: %.*s", 
3897
4049
          (int) (end - con_options), con_options);
3898
4050
    /* Process next option */
3899
4051
    con_options= end;
3900
4052
  }
3901
4053
 
3902
 
  if (find_connection_by_name(ds_connection_name.c_str()))
3903
 
    die("Connection %s already exists", ds_connection_name.c_str());
3904
 
 
 
4054
  if (find_connection_by_name(ds_connection_name.str))
 
4055
    die("Connection %s already exists", ds_connection_name.str);
 
4056
    
3905
4057
  if (next_con != connections_end)
3906
 
  {
3907
4058
    con_slot= next_con;
3908
 
  }
3909
4059
  else
3910
4060
  {
3911
4061
    if (!(con_slot= find_connection_by_name("-closed_connection-")))
3913
4063
          (int) (sizeof(connections)/sizeof(struct st_connection)));
3914
4064
  }
3915
4065
 
3916
 
  if ((con_slot->drizzle= drizzle_create(NULL)) == NULL)
3917
 
    die("Failed on drizzle_create()");
3918
 
  if (!drizzle_con_create(con_slot->drizzle, &con_slot->con))
3919
 
    die("Failed on drizzle_con_create()");
3920
 
  drizzle_con_add_options(&con_slot->con, use_drizzle_protocol ? DRIZZLE_CON_EXPERIMENTAL : DRIZZLE_CON_MYSQL);
 
4066
#ifdef EMBEDDED_LIBRARY
 
4067
  con_slot->query_done= 1;
 
4068
#endif
 
4069
  if (!mysql_init(&con_slot->mysql))
 
4070
    die("Failed on mysql_init()");
 
4071
  if (opt_compress || con_compress)
 
4072
    mysql_options(&con_slot->mysql, MYSQL_OPT_COMPRESS, NullS);
 
4073
  mysql_options(&con_slot->mysql, MYSQL_OPT_LOCAL_INFILE, 0);
 
4074
  mysql_options(&con_slot->mysql, MYSQL_SET_CHARSET_NAME,
 
4075
                charset_info->csname);
 
4076
  int opt_protocol= MYSQL_PROTOCOL_TCP;
 
4077
  mysql_options(&con_slot->mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
 
4078
  if (opt_charsets_dir)
 
4079
    mysql_options(&con_slot->mysql, MYSQL_SET_CHARSET_DIR,
 
4080
                  opt_charsets_dir);
3921
4081
 
3922
4082
  /* Use default db name */
3923
 
  if (ds_database.length() == 0)
3924
 
    ds_database.append(opt_db);
 
4083
  if (ds_database.length == 0)
 
4084
    dynstr_set(&ds_database, opt_db);
3925
4085
 
3926
4086
  /* Special database to allow one to connect without a database name */
3927
 
  if (ds_database.length() && !strcmp(ds_database.c_str(),"*NO-ONE*"))
3928
 
    ds_database.clear();
 
4087
  if (ds_database.length && !strcmp(ds_database.str,"*NO-ONE*"))
 
4088
    dynstr_set(&ds_database, "");
3929
4089
 
3930
 
  if (connect_n_handle_errors(command, &con_slot->con,
3931
 
                              ds_host.c_str(),ds_user.c_str(),
3932
 
                              ds_password.c_str(), ds_database.c_str(),
3933
 
                              con_port, ds_sock.c_str()))
 
4090
  if (connect_n_handle_errors(command, &con_slot->mysql,
 
4091
                              ds_host.str,ds_user.str,
 
4092
                              ds_password.str, ds_database.str,
 
4093
                              con_port, ds_sock.str))
3934
4094
  {
3935
 
    if (!(con_slot->name= strdup(ds_connection_name.c_str())))
 
4095
    if (!(con_slot->name= my_strdup(ds_connection_name.str, MYF(MY_WME))))
3936
4096
      die("Out of memory");
3937
4097
    cur_con= con_slot;
3938
 
 
 
4098
    
3939
4099
    if (con_slot == next_con)
3940
4100
      next_con++; /* if we used the next_con slot, advance the pointer */
3941
4101
  }
3942
4102
 
3943
 
  /* Update $drizzleclient_get_server_version to that of current connection */
3944
 
  var_set_drizzleclient_get_server_version(&cur_con->con);
 
4103
  /* Update $mysql_get_server_version to that of current connection */
 
4104
  var_set_mysql_get_server_version(&cur_con->mysql);
3945
4105
 
 
4106
  dynstr_free(&ds_connection_name);
 
4107
  dynstr_free(&ds_host);
 
4108
  dynstr_free(&ds_user);
 
4109
  dynstr_free(&ds_password);
 
4110
  dynstr_free(&ds_database);
 
4111
  dynstr_free(&ds_port);
 
4112
  dynstr_free(&ds_sock);
 
4113
  dynstr_free(&ds_options);
3946
4114
  return;
3947
4115
}
3948
4116
 
3980
4148
  SYNOPSIS
3981
4149
  do_block()
3982
4150
  cmd        Type of block
3983
 
  q         called command
 
4151
  q            called command
3984
4152
 
3985
4153
  DESCRIPTION
3986
4154
  if ([!]<expr>)
4004
4172
{
4005
4173
  char *p= command->first_argument;
4006
4174
  const char *expr_start, *expr_end;
 
4175
  VAR v;
4007
4176
  const char *cmd_name= (cmd == cmd_while ? "while" : "if");
4008
4177
  bool not_expr= false;
4009
4178
 
4020
4189
    /* Inner block should be ignored too */
4021
4190
    cur_block++;
4022
4191
    cur_block->cmd= cmd;
4023
 
    cur_block->ok= false;
 
4192
    cur_block->ok= FALSE;
4024
4193
    return;
4025
4194
  }
4026
4195
 
4032
4201
  /* Check for !<expr> */
4033
4202
  if (*expr_start == '!')
4034
4203
  {
4035
 
    not_expr= true;
 
4204
    not_expr= TRUE;
4036
4205
    expr_start++; /* Step past the '!' */
4037
4206
  }
4038
4207
  /* Find ending ')' */
4046
4215
  if (*p && *p != '{')
4047
4216
    die("Missing '{' after %s. Found \"%s\"", cmd_name, p);
4048
4217
 
4049
 
  VAR v;
4050
4218
  var_init(&v,0,0,0,0);
4051
4219
  eval_expr(&v, expr_start, &expr_end);
4052
4220
 
4053
4221
  /* Define inner block */
4054
4222
  cur_block++;
4055
4223
  cur_block->cmd= cmd;
4056
 
  cur_block->ok= (v.int_val ? true : false);
 
4224
  cur_block->ok= (v.int_val ? TRUE : FALSE);
4057
4225
 
4058
4226
  if (not_expr)
4059
4227
    cur_block->ok = !cur_block->ok;
4060
4228
 
4061
 
  free(v.str_val);
4062
 
  free(v.env_s);
4063
 
 
 
4229
  var_free(&v);
4064
4230
  return;
4065
4231
}
4066
4232
 
4075
4241
  if (!(*p))
4076
4242
    die("Can't set empty delimiter");
4077
4243
 
4078
 
  strncpy(delimiter, p, sizeof(delimiter) - 1);
 
4244
  strmake(delimiter, p, sizeof(delimiter) - 1);
4079
4245
  delimiter_length= strlen(delimiter);
4080
4246
 
4081
4247
  command->last_argument= p + delimiter_length;
4083
4249
}
4084
4250
 
4085
4251
 
4086
 
bool match_delimiter(int c, const char *delim, uint32_t length)
 
4252
bool match_delimiter(int c, const char *delim, uint length)
4087
4253
{
4088
 
  uint32_t i;
 
4254
  uint i;
4089
4255
  char tmp[MAX_DELIMITER_LENGTH];
4090
4256
 
4091
4257
  if (c != *delim)
4092
4258
    return 0;
4093
4259
 
4094
4260
  for (i= 1; i < length &&
4095
 
         (c= my_getc(cur_file->file)) == *(delim + i);
 
4261
         (c= my_getc(cur_file->file)) == *(delim + i);
4096
4262
       i++)
4097
4263
    tmp[i]= c;
4098
4264
 
4099
4265
  if (i == length)
4100
 
    return 1;          /* Found delimiter */
 
4266
    return 1;                                   /* Found delimiter */
4101
4267
 
4102
4268
  /* didn't find delimiter, push back things that we read */
4103
4269
  my_ungetc(c);
4137
4303
 
4138
4304
*/
4139
4305
 
4140
 
 
4141
 
static int my_strnncoll_simple(const CHARSET_INFO * const  cs, const unsigned char *s, size_t slen,
4142
 
                               const unsigned char *t, size_t tlen,
4143
 
                               bool t_is_prefix)
4144
 
{
4145
 
  size_t len = ( slen > tlen ) ? tlen : slen;
4146
 
  unsigned char *map= cs->sort_order;
4147
 
  if (t_is_prefix && slen > tlen)
4148
 
    slen=tlen;
4149
 
  while (len--)
4150
 
  {
4151
 
    if (map[*s++] != map[*t++])
4152
 
      return ((int) map[s[-1]] - (int) map[t[-1]]);
4153
 
  }
4154
 
  /*
4155
 
    We can't use (slen - tlen) here as the result may be outside of the
4156
 
    precision of a signed int
4157
 
  */
4158
 
  return slen > tlen ? 1 : slen < tlen ? -1 : 0 ;
4159
 
}
4160
 
 
4161
4306
static int read_line(char *buf, int size)
4162
4307
{
4163
4308
  char c, last_quote= 0;
4177
4322
  found_eof:
4178
4323
      if (cur_file->file != stdin)
4179
4324
      {
4180
 
        fclose(cur_file->file);
 
4325
        my_fclose(cur_file->file, MYF(0));
4181
4326
        cur_file->file= 0;
4182
4327
      }
4183
 
      free((unsigned char*) cur_file->file_name);
 
4328
      my_free((uchar*) cur_file->file_name, MYF(MY_ALLOW_ZERO_PTR));
4184
4329
      cur_file->file_name= 0;
4185
 
      if (cur_file == file_stack.data())
 
4330
      if (cur_file == file_stack)
4186
4331
      {
4187
4332
        /* We're back at the first file, check if
4188
4333
           all { have matching }
4212
4357
    case R_NORMAL:
4213
4358
      if (end_of_query(c))
4214
4359
      {
4215
 
        *p= 0;
4216
 
        return(0);
 
4360
        *p= 0;
 
4361
        return(0);
4217
4362
      }
4218
4363
      else if ((c == '{' &&
4219
 
                (!my_strnncoll_simple(charset_info, (const unsigned char*) "while", 5,
4220
 
                                      (unsigned char*) buf, min((ptrdiff_t)5, p - buf), 0) ||
4221
 
                 !my_strnncoll_simple(charset_info, (const unsigned char*) "if", 2,
4222
 
                                      (unsigned char*) buf, min((ptrdiff_t)2, p - buf), 0))))
 
4364
                (!my_strnncoll_simple(charset_info, (const uchar*) "while", 5,
 
4365
                                      (uchar*) buf, min(5, p - buf), 0) ||
 
4366
                 !my_strnncoll_simple(charset_info, (const uchar*) "if", 2,
 
4367
                                      (uchar*) buf, min(2, p - buf), 0))))
4223
4368
      {
4224
4369
        /* Only if and while commands can be terminated by { */
4225
4370
        *p++= c;
4226
 
        *p= 0;
4227
 
        return(0);
 
4371
        *p= 0;
 
4372
        return(0);
4228
4373
      }
4229
4374
      else if (c == '\'' || c == '"' || c == '`')
4230
4375
      {
4231
4376
        last_quote= c;
4232
 
        state= R_Q;
 
4377
        state= R_Q;
4233
4378
      }
4234
4379
      break;
4235
4380
 
4237
4382
      if (c == '\n')
4238
4383
      {
4239
4384
        /* Comments are terminated by newline */
4240
 
        *p= 0;
4241
 
        return(0);
 
4385
        *p= 0;
 
4386
        return(0);
4242
4387
      }
4243
4388
      break;
4244
4389
 
4246
4391
      if (c == '#' || c == '-')
4247
4392
      {
4248
4393
        /* A # or - in the first position of the line - this is a comment */
4249
 
        state = R_COMMENT;
 
4394
        state = R_COMMENT;
4250
4395
      }
4251
4396
      else if (my_isspace(charset_info, c))
4252
4397
      {
4253
4398
        /* Skip all space at begining of line */
4254
 
        if (c == '\n')
 
4399
        if (c == '\n')
4255
4400
        {
4256
4401
          /* Query hasn't started yet */
4257
 
          start_lineno= cur_file->lineno;
 
4402
          start_lineno= cur_file->lineno;
4258
4403
        }
4259
 
        skip_char= 1;
 
4404
        skip_char= 1;
4260
4405
      }
4261
4406
      else if (end_of_query(c))
4262
4407
      {
4263
 
        *p= 0;
4264
 
        return(0);
 
4408
        *p= 0;
 
4409
        return(0);
4265
4410
      }
4266
4411
      else if (c == '}')
4267
4412
      {
4268
4413
        /* A "}" need to be by itself in the begining of a line to terminate */
4269
4414
        *p++= c;
4270
 
        *p= 0;
4271
 
        return(0);
 
4415
        *p= 0;
 
4416
        return(0);
4272
4417
      }
4273
4418
      else if (c == '\'' || c == '"' || c == '`')
4274
4419
      {
4275
4420
        last_quote= c;
4276
 
        state= R_Q;
 
4421
        state= R_Q;
4277
4422
      }
4278
4423
      else
4279
 
        state= R_NORMAL;
 
4424
        state= R_NORMAL;
4280
4425
      break;
4281
4426
 
4282
4427
    case R_Q:
4283
4428
      if (c == last_quote)
4284
 
        state= R_NORMAL;
 
4429
        state= R_NORMAL;
4285
4430
      else if (c == '\\')
4286
 
        state= R_SLASH_IN_Q;
 
4431
        state= R_SLASH_IN_Q;
4287
4432
      break;
4288
4433
 
4289
4434
    case R_SLASH_IN_Q:
4296
4441
    {
4297
4442
      /* Could be a multibyte character */
4298
4443
      /* This code is based on the code in "sql_load.cc" */
 
4444
#ifdef USE_MB
4299
4445
      int charlen = my_mbcharlen(charset_info, c);
4300
4446
      /* We give up if multibyte character is started but not */
4301
4447
      /* completed before we pass buf_end */
4302
4448
      if ((charlen > 1) && (p + charlen) <= buf_end)
4303
4449
      {
4304
 
        int i;
4305
 
        char* mb_start = p;
4306
 
 
4307
 
        *p++ = c;
4308
 
 
4309
 
        for (i= 1; i < charlen; i++)
4310
 
        {
4311
 
          if (feof(cur_file->file))
4312
 
            goto found_eof;
4313
 
          c= my_getc(cur_file->file);
4314
 
          *p++ = c;
4315
 
        }
4316
 
        if (! my_ismbchar(charset_info, mb_start, p))
4317
 
        {
4318
 
          /* It was not a multiline char, push back the characters */
4319
 
          /* We leave first 'c', i.e. pretend it was a normal char */
4320
 
          while (p > mb_start)
4321
 
            my_ungetc(*--p);
4322
 
        }
 
4450
        int i;
 
4451
        char* mb_start = p;
 
4452
 
 
4453
        *p++ = c;
 
4454
 
 
4455
        for (i= 1; i < charlen; i++)
 
4456
        {
 
4457
          if (feof(cur_file->file))
 
4458
            goto found_eof;
 
4459
          c= my_getc(cur_file->file);
 
4460
          *p++ = c;
 
4461
        }
 
4462
        if (! my_ismbchar(charset_info, mb_start, p))
 
4463
        {
 
4464
          /* It was not a multiline char, push back the characters */
 
4465
          /* We leave first 'c', i.e. pretend it was a normal char */
 
4466
          while (p > mb_start)
 
4467
            my_ungetc(*--p);
 
4468
        }
4323
4469
      }
4324
4470
      else
4325
 
        *p++= c;
 
4471
#endif
 
4472
        *p++= c;
4326
4473
    }
4327
4474
  }
4328
 
  die("The input buffer is too small for this query.x\n"        \
 
4475
  die("The input buffer is too small for this query.x\n" \
4329
4476
      "check your query or increase MAX_QUERY and recompile");
4330
4477
  return(0);
4331
4478
}
4346
4493
{
4347
4494
  int last_c_was_quote= 0;
4348
4495
  char *p= query, *to= query;
4349
 
  char *end= strchr(query, '\0');
 
4496
  char *end= strend(query);
4350
4497
  char last_c;
4351
4498
 
4352
4499
  while (p <= end)
4385
4532
 
4386
4533
/*
4387
4534
  Check a command that is about to be sent (or should have been
4388
 
  sent if parsing was enabled) to DRIZZLE server for
 
4535
  sent if parsing was enabled) to mysql server for
4389
4536
  suspicious things and generate warnings.
4390
4537
*/
4391
4538
 
4397
4544
  {
4398
4545
    /*
4399
4546
      Look for query's that lines that start with a -- comment
4400
 
      and has a drizzletest command
 
4547
      and has a mysqltest command
4401
4548
    */
4402
4549
    if (ptr[0] == '\n' &&
4403
4550
        ptr[1] && ptr[1] == '-' &&
4404
4551
        ptr[2] && ptr[2] == '-' &&
4405
4552
        ptr[3])
4406
4553
    {
4407
 
      uint32_t type;
 
4554
      uint type;
4408
4555
      char save;
4409
4556
      char *end, *start= (char*)ptr+3;
4410
4557
      /* Skip leading spaces */
4416
4563
        end++;
4417
4564
      save= *end;
4418
4565
      *end= 0;
4419
 
      type= command_typelib.find_type(start, 1+2);
 
4566
      type= find_type(start, &command_typelib, 1+2);
4420
4567
      if (type)
4421
 
        warning_msg("Embedded drizzletest command '--%s' detected in "
 
4568
        warning_msg("Embedded mysqltest command '--%s' detected in "
4422
4569
                    "query '%s' was this intentional? ",
4423
4570
                    start, command->query);
4424
4571
      *end= save;
4481
4628
  return;
4482
4629
}
4483
4630
 
 
4631
 
 
4632
 
4484
4633
/*
4485
4634
  Create a command from a set of lines
4486
4635
 
4487
4636
  SYNOPSIS
4488
 
  read_command()
4489
 
  command_ptr pointer where to return the new query
 
4637
    read_command()
 
4638
    command_ptr pointer where to return the new query
4490
4639
 
4491
4640
  DESCRIPTION
4492
 
  Converts lines returned by read_line into a command, this involves
4493
 
  parsing the first word in the read line to find the command type.
 
4641
    Converts lines returned by read_line into a command, this involves
 
4642
    parsing the first word in the read line to find the command type.
4494
4643
 
4495
4644
  A -- comment may contain a valid query as the first word after the
4496
4645
  comment start. Thus it's always checked to see if that is the case.
4498
4647
  terminated by new line '\n' regardless how many "delimiter" it contain.
4499
4648
*/
4500
4649
 
4501
 
#define MAX_QUERY (768*1024*2) /* 256K -- a test in sp-big is >128K */
 
4650
#define MAX_QUERY (256*1024*2) /* 256K -- a test in sp-big is >128K */
4502
4651
static char read_command_buf[MAX_QUERY];
4503
4652
 
4504
4653
static int read_command(struct st_command** command_ptr)
4509
4658
 
4510
4659
  if (parser.current_line < parser.read_lines)
4511
4660
  {
4512
 
    *command_ptr= q_lines[parser.current_line];
 
4661
    get_dynamic(&q_lines, (uchar*) command_ptr, parser.current_line) ;
4513
4662
    return(0);
4514
4663
  }
4515
 
  if (!(*command_ptr= command= new st_command))
4516
 
    die("command construction failed");
4517
 
  q_lines.push_back(command);
 
4664
  if (!(*command_ptr= command=
 
4665
        (struct st_command*) my_malloc(sizeof(*command),
 
4666
                                       MYF(MY_WME|MY_ZEROFILL))) ||
 
4667
      insert_dynamic(&q_lines, (uchar*) &command))
 
4668
    die(NullS);
4518
4669
  command->type= Q_UNKNOWN;
4519
4670
 
4520
4671
  read_command_buf[0]= 0;
4540
4691
  while (*p && my_isspace(charset_info, *p))
4541
4692
    p++;
4542
4693
 
4543
 
  if (!(command->query_buf= command->query= strdup(p)))
 
4694
  if (!(command->query_buf= command->query= my_strdup(p, MYF(MY_WME))))
4544
4695
    die("Out of memory");
4545
4696
 
4546
4697
  /* Calculate first word length(the command), terminated by space or ( */
4547
4698
  p= command->query;
4548
4699
  while (*p && !my_isspace(charset_info, *p) && *p != '(')
4549
4700
    p++;
4550
 
  command->first_word_len= (uint32_t) (p - command->query);
 
4701
  command->first_word_len= (uint) (p - command->query);
4551
4702
 
4552
4703
  /* Skip spaces between command and first argument */
4553
4704
  while (*p && my_isspace(charset_info, *p))
4554
4705
    p++;
4555
4706
  command->first_argument= p;
4556
4707
 
4557
 
  command->end= strchr(command->query, '\0');
 
4708
  command->end= strend(command->query);
4558
4709
  command->query_len= (command->end - command->query);
4559
4710
  parser.read_lines++;
4560
4711
  return(0);
4561
4712
}
4562
4713
 
 
4714
 
 
4715
static struct my_option my_long_options[] =
 
4716
{
 
4717
  {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG,
 
4718
   0, 0, 0, 0, 0, 0},
 
4719
  {"basedir", 'b', "Basedir for tests.", (char**) &opt_basedir,
 
4720
   (char**) &opt_basedir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4721
  {"character-sets-dir", OPT_CHARSETS_DIR,
 
4722
   "Directory where character sets are.", (char**) &opt_charsets_dir,
 
4723
   (char**) &opt_charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4724
  {"compress", 'C', "Use the compressed server/client protocol.",
 
4725
   (char**) &opt_compress, (char**) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
 
4726
   0, 0, 0},
 
4727
  {"database", 'D', "Database to use.", (char**) &opt_db, (char**) &opt_db, 0,
 
4728
   GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4729
  {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit.",
 
4730
   (char**) &debug_check_flag, (char**) &debug_check_flag, 0,
 
4731
   GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
4732
  {"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.",
 
4733
   (char**) &debug_info_flag, (char**) &debug_info_flag,
 
4734
   0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
4735
  {"host", 'h', "Connect to host.", (char**) &opt_host, (char**) &opt_host, 0,
 
4736
   GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4737
  {"include", 'i', "Include SQL before each test case.", (char**) &opt_include,
 
4738
   (char**) &opt_include, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4739
  {"logdir", OPT_LOG_DIR, "Directory for log files", (char**) &opt_logdir,
 
4740
   (char**) &opt_logdir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4741
  {"mark-progress", OPT_MARK_PROGRESS,
 
4742
   "Write linenumber and elapsed time to <testname>.progress ",
 
4743
   (char**) &opt_mark_progress, (char**) &opt_mark_progress, 0,
 
4744
   GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
4745
  {"max-connect-retries", OPT_MAX_CONNECT_RETRIES,
 
4746
   "Max number of connection attempts when connecting to server",
 
4747
   (char**) &opt_max_connect_retries, (char**) &opt_max_connect_retries, 0,
 
4748
   GET_INT, REQUIRED_ARG, 500, 1, 10000, 0, 0, 0},
 
4749
  {"password", 'p', "Password to use when connecting to server.",
 
4750
   0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
 
4751
  {"port", 'P', "Port number to use for connection or 0 for default to, in "
 
4752
   "order of preference, my.cnf, $MYSQL_TCP_PORT, "
 
4753
#if MYSQL_PORT_DEFAULT == 0
 
4754
   "/etc/services, "
 
4755
#endif
 
4756
   "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").",
 
4757
   (char**) &opt_port,
 
4758
   (char**) &opt_port, 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4759
  {"quiet", 's', "Suppress all normal output.", (char**) &silent,
 
4760
   (char**) &silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
4761
  {"record", 'r', "Record output of test_file into result file.",
 
4762
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
 
4763
  {"result-file", 'R', "Read/Store result from/in this file.",
 
4764
   (char**) &result_file_name, (char**) &result_file_name, 0,
 
4765
   GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4766
  {"server-arg", 'A', "Send option value to embedded server as a parameter.",
 
4767
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4768
  {"server-file", 'F', "Read embedded server arguments from file.",
 
4769
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4770
  {"silent", 's', "Suppress all normal output. Synonym for --quiet.",
 
4771
   (char**) &silent, (char**) &silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
4772
  {"sleep", 'T', "Sleep always this many seconds on sleep commands.",
 
4773
   (char**) &opt_sleep, (char**) &opt_sleep, 0, GET_INT, REQUIRED_ARG, -1, -1, 0,
 
4774
   0, 0, 0},
 
4775
  {"tail-lines", OPT_TAIL_LINES,
 
4776
   "Number of lines of the resul to include in a failure report",
 
4777
   (char**) &opt_tail_lines, (char**) &opt_tail_lines, 0,
 
4778
   GET_INT, REQUIRED_ARG, 0, 0, 10000, 0, 0, 0},
 
4779
  {"test-file", 'x', "Read test from/in this file (default stdin).",
 
4780
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4781
  {"timer-file", 'm', "File where the timing in micro seconds is stored.",
 
4782
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4783
  {"tmpdir", 't', "Temporary directory where sockets are put.",
 
4784
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4785
  {"user", 'u', "User for login.", (char**) &opt_user, (char**) &opt_user, 0,
 
4786
   GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
4787
  {"verbose", 'v', "Write more.", (char**) &verbose, (char**) &verbose, 0,
 
4788
   GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
4789
  {"version", 'V', "Output version information and exit.",
 
4790
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
 
4791
  { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
 
4792
};
 
4793
 
 
4794
 
 
4795
#include <help_start.h>
 
4796
 
 
4797
static void print_version(void)
 
4798
{
 
4799
  printf("%s  Ver %s Distrib %s, for %s (%s)\n",my_progname,MTEST_VERSION,
 
4800
         MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
 
4801
}
 
4802
 
 
4803
static void usage(void)
 
4804
{
 
4805
  print_version();
 
4806
  printf("MySQL AB, by Sasha, Matt, Monty & Jani\n");
 
4807
  printf("This software comes with ABSOLUTELY NO WARRANTY\n\n");
 
4808
  printf("Runs a test against the mysql server and compares output with a results file.\n\n");
 
4809
  printf("Usage: %s [OPTIONS] [database] < test_file\n", my_progname);
 
4810
  my_print_help(my_long_options);
 
4811
  printf("  --no-defaults       Don't read default options from any options file.\n");
 
4812
  my_print_variables(my_long_options);
 
4813
}
 
4814
 
 
4815
#include <help_end.h>
 
4816
 
 
4817
 
 
4818
/*
 
4819
  Read arguments for embedded server and put them into
 
4820
  embedded_server_args[]
 
4821
*/
 
4822
 
 
4823
static void read_embedded_server_arguments(const char *name)
 
4824
{
 
4825
  char argument[1024],buff[FN_REFLEN], *str=0;
 
4826
  FILE *file;
 
4827
 
 
4828
  if (!test_if_hard_path(name))
 
4829
  {
 
4830
    strxmov(buff, opt_basedir, name, NullS);
 
4831
    name=buff;
 
4832
  }
 
4833
  fn_format(buff, name, "", "", MY_UNPACK_FILENAME);
 
4834
 
 
4835
  if (!embedded_server_arg_count)
 
4836
  {
 
4837
    embedded_server_arg_count=1;
 
4838
    embedded_server_args[0]= (char*) "";                /* Progname */
 
4839
  }
 
4840
  if (!(file=my_fopen(buff, O_RDONLY | FILE_BINARY, MYF(MY_WME))))
 
4841
    die("Failed to open file '%s'", buff);
 
4842
 
 
4843
  while (embedded_server_arg_count < MAX_EMBEDDED_SERVER_ARGS &&
 
4844
         (str=fgets(argument,sizeof(argument), file)))
 
4845
  {
 
4846
    *(strend(str)-1)=0;                         /* Remove end newline */
 
4847
    if (!(embedded_server_args[embedded_server_arg_count]=
 
4848
          (char*) my_strdup(str,MYF(MY_WME))))
 
4849
    {
 
4850
      my_fclose(file,MYF(0));
 
4851
      die("Out of memory");
 
4852
 
 
4853
    }
 
4854
    embedded_server_arg_count++;
 
4855
  }
 
4856
  my_fclose(file,MYF(0));
 
4857
  if (str)
 
4858
    die("Too many arguments in option file: %s",name);
 
4859
 
 
4860
  return;
 
4861
}
 
4862
 
 
4863
 
 
4864
static bool
 
4865
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
 
4866
               char *argument)
 
4867
{
 
4868
  switch(optid) {
 
4869
  case 'r':
 
4870
    record = 1;
 
4871
    break;
 
4872
  case 'x':
 
4873
  {
 
4874
    char buff[FN_REFLEN];
 
4875
    if (!test_if_hard_path(argument))
 
4876
    {
 
4877
      strxmov(buff, opt_basedir, argument, NullS);
 
4878
      argument= buff;
 
4879
    }
 
4880
    fn_format(buff, argument, "", "", MY_UNPACK_FILENAME);
 
4881
    assert(cur_file == file_stack && cur_file->file == 0);
 
4882
    if (!(cur_file->file=
 
4883
          my_fopen(buff, O_RDONLY | FILE_BINARY, MYF(0))))
 
4884
      die("Could not open '%s' for reading: errno = %d", buff, errno);
 
4885
    cur_file->file_name= my_strdup(buff, MYF(MY_FAE));
 
4886
    cur_file->lineno= 1;
 
4887
    break;
 
4888
  }
 
4889
  case 'm':
 
4890
  {
 
4891
    static char buff[FN_REFLEN];
 
4892
    if (!test_if_hard_path(argument))
 
4893
    {
 
4894
      strxmov(buff, opt_basedir, argument, NullS);
 
4895
      argument= buff;
 
4896
    }
 
4897
    fn_format(buff, argument, "", "", MY_UNPACK_FILENAME);
 
4898
    timer_file= buff;
 
4899
    unlink(timer_file);      /* Ignore error, may not exist */
 
4900
    break;
 
4901
  }
 
4902
  case 'p':
 
4903
    if (argument)
 
4904
    {
 
4905
      my_free(opt_pass, MYF(MY_ALLOW_ZERO_PTR));
 
4906
      opt_pass= my_strdup(argument, MYF(MY_FAE));
 
4907
      while (*argument) *argument++= 'x';               /* Destroy argument */
 
4908
      tty_password= 0;
 
4909
    }
 
4910
    else
 
4911
      tty_password= 1;
 
4912
    break;
 
4913
  case 't':
 
4914
    strnmov(TMPDIR, argument, sizeof(TMPDIR));
 
4915
    break;
 
4916
  case 'A':
 
4917
    if (!embedded_server_arg_count)
 
4918
    {
 
4919
      embedded_server_arg_count=1;
 
4920
      embedded_server_args[0]= (char*) "";
 
4921
    }
 
4922
    if (embedded_server_arg_count == MAX_EMBEDDED_SERVER_ARGS-1 ||
 
4923
        !(embedded_server_args[embedded_server_arg_count++]=
 
4924
          my_strdup(argument, MYF(MY_FAE))))
 
4925
    {
 
4926
      die("Can't use server argument");
 
4927
    }
 
4928
    break;
 
4929
  case 'F':
 
4930
    read_embedded_server_arguments(argument);
 
4931
    break;
 
4932
  case 'V':
 
4933
    print_version();
 
4934
    exit(0);
 
4935
  case '?':
 
4936
    usage();
 
4937
    exit(0);
 
4938
  }
 
4939
  return 0;
 
4940
}
 
4941
 
 
4942
 
 
4943
static int parse_args(int argc, char **argv)
 
4944
{
 
4945
  load_defaults("my",load_default_groups,&argc,&argv);
 
4946
  default_argv= argv;
 
4947
 
 
4948
  if ((handle_options(&argc, &argv, my_long_options, get_one_option)))
 
4949
    exit(1);
 
4950
 
 
4951
  if (argc > 1)
 
4952
  {
 
4953
    usage();
 
4954
    exit(1);
 
4955
  }
 
4956
  if (argc == 1)
 
4957
    opt_db= *argv;
 
4958
  if (tty_password)
 
4959
    opt_pass= get_tty_password(NullS);          /* purify tested */
 
4960
  if (debug_info_flag)
 
4961
    my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO;
 
4962
  if (debug_check_flag)
 
4963
    my_end_arg= MY_CHECK_ERROR;
 
4964
 
 
4965
  return 0;
 
4966
}
 
4967
 
4563
4968
/*
4564
4969
  Write the content of str into file
4565
4970
 
4571
4976
  append - append to file instead of overwriting old file
4572
4977
*/
4573
4978
 
4574
 
void str_to_file2(const char *fname, const char *str, int size, bool append)
 
4979
void str_to_file2(const char *fname, char *str, int size, bool append)
4575
4980
{
4576
4981
  int fd;
4577
4982
  char buff[FN_REFLEN];
4578
4983
  int flags= O_WRONLY | O_CREAT;
4579
 
  if (!internal::test_if_hard_path(fname))
 
4984
  if (!test_if_hard_path(fname))
4580
4985
  {
4581
 
    snprintf(buff, sizeof(buff), "%s%s",opt_basedir.c_str(),fname);
 
4986
    strxmov(buff, opt_basedir, fname, NullS);
4582
4987
    fname= buff;
4583
4988
  }
4584
 
  internal::fn_format(buff, fname, "", "", MY_UNPACK_FILENAME);
 
4989
  fn_format(buff, fname, "", "", MY_UNPACK_FILENAME);
4585
4990
 
4586
4991
  if (!append)
4587
4992
    flags|= O_TRUNC;
4588
 
  if ((fd= internal::my_open(buff, flags,
 
4993
  if ((fd= my_open(buff, flags,
4589
4994
                   MYF(MY_WME | MY_FFNF))) < 0)
4590
4995
    die("Could not open '%s' for writing: errno = %d", buff, errno);
4591
 
  if (append && lseek(fd, 0, SEEK_END) == MY_FILEPOS_ERROR)
 
4996
  if (append && my_seek(fd, 0, SEEK_END, MYF(0)) == MY_FILEPOS_ERROR)
4592
4997
    die("Could not find end of file '%s': errno = %d", buff, errno);
4593
 
  if (internal::my_write(fd, (unsigned char*)str, size, MYF(MY_WME|MY_FNABP)))
 
4998
  if (my_write(fd, (uchar*)str, size, MYF(MY_WME|MY_FNABP)))
4594
4999
    die("write failed");
4595
 
  internal::my_close(fd, MYF(0));
 
5000
  my_close(fd, MYF(0));
4596
5001
}
4597
5002
 
4598
5003
/*
4605
5010
  size - size of content witten to file
4606
5011
*/
4607
5012
 
4608
 
void str_to_file(const char *fname, const char *str, int size)
 
5013
void str_to_file(const char *fname, char *str, int size)
4609
5014
{
4610
 
  str_to_file2(fname, str, size, false);
 
5015
  str_to_file2(fname, str, size, FALSE);
4611
5016
}
4612
5017
 
4613
5018
 
4614
 
void dump_result_to_log_file(const char *buf, int size)
 
5019
void dump_result_to_log_file(char *buf, int size)
4615
5020
{
4616
5021
  char log_file[FN_REFLEN];
4617
 
  str_to_file(internal::fn_format(log_file, result_file_name.c_str(), opt_logdir.c_str(), ".log",
4618
 
                        ! opt_logdir.empty() ? MY_REPLACE_DIR | MY_REPLACE_EXT :
 
5022
  str_to_file(fn_format(log_file, result_file_name, opt_logdir, ".log",
 
5023
                        *opt_logdir ? MY_REPLACE_DIR | MY_REPLACE_EXT :
4619
5024
                        MY_REPLACE_EXT),
4620
5025
              buf, size);
4621
5026
  fprintf(stderr, "\nMore results from queries before failure can be found in %s\n",
4622
5027
          log_file);
4623
5028
}
4624
5029
 
4625
 
void dump_progress()
 
5030
void dump_progress(void)
4626
5031
{
4627
5032
  char progress_file[FN_REFLEN];
4628
 
  str_to_file(internal::fn_format(progress_file, result_file_name.c_str(),
4629
 
                        opt_logdir.c_str(), ".progress",
4630
 
                        ! opt_logdir.empty() ? MY_REPLACE_DIR | MY_REPLACE_EXT :
 
5033
  str_to_file(fn_format(progress_file, result_file_name,
 
5034
                        opt_logdir, ".progress",
 
5035
                        *opt_logdir ? MY_REPLACE_DIR | MY_REPLACE_EXT :
4631
5036
                        MY_REPLACE_EXT),
4632
 
              ds_progress.c_str(), ds_progress.length());
 
5037
              ds_progress.str, ds_progress.length);
4633
5038
}
4634
5039
 
4635
 
void dump_warning_messages()
 
5040
void dump_warning_messages(void)
4636
5041
{
4637
5042
  char warn_file[FN_REFLEN];
4638
5043
 
4639
 
  str_to_file(internal::fn_format(warn_file, result_file_name.c_str(), opt_logdir.c_str(), ".warnings",
4640
 
                        ! opt_logdir.empty() ? MY_REPLACE_DIR | MY_REPLACE_EXT :
 
5044
  str_to_file(fn_format(warn_file, result_file_name, opt_logdir, ".warnings",
 
5045
                        *opt_logdir ? MY_REPLACE_DIR | MY_REPLACE_EXT :
4641
5046
                        MY_REPLACE_EXT),
4642
 
              ds_warning_messages.c_str(), ds_warning_messages.length());
 
5047
              ds_warning_messages.str, ds_warning_messages.length);
4643
5048
}
4644
5049
 
4645
5050
 
4647
5052
  Append the result for one field to the dynamic string ds
4648
5053
*/
4649
5054
 
4650
 
static void append_field(string *ds, uint32_t col_idx, drizzle_column_st *column,
 
5055
static void append_field(DYNAMIC_STRING *ds, uint col_idx, MYSQL_FIELD* field,
4651
5056
                         const char* val, uint64_t len, bool is_null)
4652
5057
{
4653
5058
  if (col_idx < max_replace_column && replace_column[col_idx])
4664
5069
  if (!display_result_vertically)
4665
5070
  {
4666
5071
    if (col_idx)
4667
 
      ds->append("\t");
4668
 
    replace_append_mem(ds, val, (int)len);
 
5072
      dynstr_append_mem(ds, "\t", 1);
 
5073
    replace_dynstr_append_mem(ds, val, (int)len);
4669
5074
  }
4670
5075
  else
4671
5076
  {
4672
 
    ds->append(drizzle_column_name(column));
4673
 
    ds->append("\t");
4674
 
    replace_append_mem(ds, val, (int)len);
4675
 
    ds->append("\n");
 
5077
    dynstr_append(ds, field->name);
 
5078
    dynstr_append_mem(ds, "\t", 1);
 
5079
    replace_dynstr_append_mem(ds, val, (int)len);
 
5080
    dynstr_append_mem(ds, "\n", 1);
4676
5081
  }
4677
5082
}
4678
5083
 
4682
5087
  Values may be converted with 'replace_column'
4683
5088
*/
4684
5089
 
4685
 
static void append_result(string *ds, drizzle_result_st *res)
 
5090
static void append_result(DYNAMIC_STRING *ds, MYSQL_RES *res)
4686
5091
{
4687
 
  drizzle_row_t row;
4688
 
  uint32_t num_fields= drizzle_result_column_count(res);
4689
 
  drizzle_column_st *column;
4690
 
  size_t *lengths;
 
5092
  MYSQL_ROW row;
 
5093
  uint num_fields= mysql_num_fields(res);
 
5094
  MYSQL_FIELD *fields= mysql_fetch_fields(res);
 
5095
  ulong *lengths;
4691
5096
 
4692
 
  while ((row = drizzle_row_next(res)))
 
5097
  while ((row = mysql_fetch_row(res)))
4693
5098
  {
4694
 
    uint32_t i;
4695
 
    lengths = drizzle_row_field_sizes(res);
4696
 
    drizzle_column_seek(res, 0);
 
5099
    uint i;
 
5100
    lengths = mysql_fetch_lengths(res);
4697
5101
    for (i = 0; i < num_fields; i++)
4698
 
    {
4699
 
      column= drizzle_column_next(res);
4700
 
      if (row[i] && (drizzle_column_type(column) == DRIZZLE_COLUMN_TYPE_TINY))
4701
 
      {
4702
 
        if (boost::lexical_cast<uint32_t>(row[i]))
4703
 
        {
4704
 
          if ((drizzle_column_flags(column) & DRIZZLE_COLUMN_FLAGS_UNSIGNED))
4705
 
          {
4706
 
            append_field(ds, i, column, "YES", 3, false);
4707
 
          }
4708
 
          else
4709
 
          {
4710
 
            append_field(ds, i, column, "TRUE", 4, false);
4711
 
          }
4712
 
        }
4713
 
        else
4714
 
        {
4715
 
          if ((drizzle_column_flags(column) & DRIZZLE_COLUMN_FLAGS_UNSIGNED))
4716
 
          {
4717
 
            append_field(ds, i, column, "NO", 2, false);
4718
 
          }
4719
 
          else
4720
 
          {
4721
 
            append_field(ds, i, column, "FALSE", 5, false);
4722
 
          }
4723
 
        }
4724
 
      }
4725
 
      else
4726
 
      {
4727
 
        append_field(ds, i, column,
4728
 
                     (const char*)row[i], lengths[i], !row[i]);
4729
 
      }
4730
 
    }
 
5102
      append_field(ds, i, &fields[i],
 
5103
                   (const char*)row[i], lengths[i], !row[i]);
4731
5104
    if (!display_result_vertically)
4732
 
      ds->append("\n");
4733
 
 
 
5105
      dynstr_append_mem(ds, "\n", 1);
4734
5106
  }
4735
5107
}
4736
5108
 
4739
5111
  Append metadata for fields to output
4740
5112
*/
4741
5113
 
4742
 
static void append_metadata(string *ds, drizzle_result_st *res)
 
5114
static void append_metadata(DYNAMIC_STRING *ds,
 
5115
                            MYSQL_FIELD *field,
 
5116
                            uint num_fields)
4743
5117
{
4744
 
  drizzle_column_st *column;
4745
 
  ds->append("Catalog\tDatabase\tTable\tTable_alias\tColumn\t"
4746
 
             "Column_alias\tType\tLength\tMax length\tIs_null\t"
4747
 
             "Flags\tDecimals\tCharsetnr\n");
 
5118
  MYSQL_FIELD *field_end;
 
5119
  dynstr_append(ds,"Catalog\tDatabase\tTable\tTable_alias\tColumn\t"
 
5120
                "Column_alias\tType\tLength\tMax length\tIs_null\t"
 
5121
                "Flags\tDecimals\tCharsetnr\n");
4748
5122
 
4749
 
  drizzle_column_seek(res, 0);
4750
 
  while ((column= drizzle_column_next(res)))
 
5123
  for (field_end= field+num_fields ;
 
5124
       field < field_end ;
 
5125
       field++)
4751
5126
  {
4752
 
    ds->append(drizzle_column_catalog(column),
4753
 
               strlen(drizzle_column_catalog(column)));
4754
 
    ds->append("\t", 1);
4755
 
    ds->append(drizzle_column_db(column), strlen(drizzle_column_db(column)));
4756
 
    ds->append("\t", 1);
4757
 
    ds->append(drizzle_column_orig_table(column),
4758
 
               strlen(drizzle_column_orig_table(column)));
4759
 
    ds->append("\t", 1);
4760
 
    ds->append(drizzle_column_table(column),
4761
 
               strlen(drizzle_column_table(column)));
4762
 
    ds->append("\t", 1);
4763
 
    ds->append(drizzle_column_orig_name(column),
4764
 
               strlen(drizzle_column_orig_name(column)));
4765
 
    ds->append("\t", 1);
4766
 
    ds->append(drizzle_column_name(column),
4767
 
               strlen(drizzle_column_name(column)));
4768
 
    ds->append("\t", 1);
4769
 
    replace_append_uint(ds, drizzle_column_type_drizzle(column));
4770
 
    ds->append("\t", 1);
4771
 
    replace_append_uint(ds, drizzle_column_size(column));
4772
 
    ds->append("\t", 1);
4773
 
    if (drizzle_column_type(column) == DRIZZLE_COLUMN_TYPE_TINY)
4774
 
    {
4775
 
      replace_append_uint(ds, 1);
4776
 
    }
4777
 
    else
4778
 
    {
4779
 
      replace_append_uint(ds, drizzle_column_max_size(column));
4780
 
    }
4781
 
    ds->append("\t", 1);
4782
 
    ds->append((char*) ((drizzle_column_flags(column) & DRIZZLE_COLUMN_FLAGS_NOT_NULL) ? "N" : "Y"), 1);
4783
 
    ds->append("\t", 1);
4784
 
    replace_append_uint(ds, drizzle_column_flags(column));
4785
 
    ds->append("\t", 1);
4786
 
    replace_append_uint(ds, drizzle_column_decimals(column));
4787
 
    ds->append("\t", 1);
4788
 
    replace_append_uint(ds, drizzle_column_charset(column));
4789
 
    ds->append("\n", 1);
 
5127
    dynstr_append_mem(ds, field->catalog,
 
5128
                      field->catalog_length);
 
5129
    dynstr_append_mem(ds, "\t", 1);
 
5130
    dynstr_append_mem(ds, field->db, field->db_length);
 
5131
    dynstr_append_mem(ds, "\t", 1);
 
5132
    dynstr_append_mem(ds, field->org_table,
 
5133
                      field->org_table_length);
 
5134
    dynstr_append_mem(ds, "\t", 1);
 
5135
    dynstr_append_mem(ds, field->table,
 
5136
                      field->table_length);
 
5137
    dynstr_append_mem(ds, "\t", 1);
 
5138
    dynstr_append_mem(ds, field->org_name,
 
5139
                      field->org_name_length);
 
5140
    dynstr_append_mem(ds, "\t", 1);
 
5141
    dynstr_append_mem(ds, field->name, field->name_length);
 
5142
    dynstr_append_mem(ds, "\t", 1);
 
5143
    replace_dynstr_append_uint(ds, field->type);
 
5144
    dynstr_append_mem(ds, "\t", 1);
 
5145
    replace_dynstr_append_uint(ds, field->length);
 
5146
    dynstr_append_mem(ds, "\t", 1);
 
5147
    replace_dynstr_append_uint(ds, field->max_length);
 
5148
    dynstr_append_mem(ds, "\t", 1);
 
5149
    dynstr_append_mem(ds, (char*) (IS_NOT_NULL(field->flags) ?
 
5150
                                   "N" : "Y"), 1);
 
5151
    dynstr_append_mem(ds, "\t", 1);
 
5152
    replace_dynstr_append_uint(ds, field->flags);
 
5153
    dynstr_append_mem(ds, "\t", 1);
 
5154
    replace_dynstr_append_uint(ds, field->decimals);
 
5155
    dynstr_append_mem(ds, "\t", 1);
 
5156
    replace_dynstr_append_uint(ds, field->charsetnr);
 
5157
    dynstr_append_mem(ds, "\n", 1);
4790
5158
  }
4791
5159
}
4792
5160
 
4795
5163
  Append affected row count and other info to output
4796
5164
*/
4797
5165
 
4798
 
static void append_info(string *ds, uint64_t affected_rows,
 
5166
static void append_info(DYNAMIC_STRING *ds, uint64_t affected_rows,
4799
5167
                        const char *info)
4800
5168
{
4801
 
  ostringstream buf;
4802
 
  buf << "affected rows: " << affected_rows << endl;
4803
 
  ds->append(buf.str());
4804
 
  if (info && strcmp(info, ""))
 
5169
  char buf[40], buff2[21];
 
5170
  sprintf(buf,"affected rows: %s\n", llstr(affected_rows, buff2));
 
5171
  dynstr_append(ds, buf);
 
5172
  if (info)
4805
5173
  {
4806
 
    ds->append("info: ");
4807
 
    ds->append(info);
4808
 
    ds->append("\n", 1);
 
5174
    dynstr_append(ds, "info: ");
 
5175
    dynstr_append(ds, info);
 
5176
    dynstr_append_mem(ds, "\n", 1);
4809
5177
  }
4810
5178
}
4811
5179
 
4814
5182
  Display the table headings with the names tab separated
4815
5183
*/
4816
5184
 
4817
 
static void append_table_headings(string *ds, drizzle_result_st *res)
 
5185
static void append_table_headings(DYNAMIC_STRING *ds,
 
5186
                                  MYSQL_FIELD *field,
 
5187
                                  uint num_fields)
4818
5188
{
4819
 
  uint32_t col_idx= 0;
4820
 
  drizzle_column_st *column;
4821
 
  drizzle_column_seek(res, 0);
4822
 
  while ((column= drizzle_column_next(res)))
 
5189
  uint col_idx;
 
5190
  for (col_idx= 0; col_idx < num_fields; col_idx++)
4823
5191
  {
4824
5192
    if (col_idx)
4825
 
      ds->append("\t", 1);
4826
 
    replace_append(ds, drizzle_column_name(column));
4827
 
    col_idx++;
 
5193
      dynstr_append_mem(ds, "\t", 1);
 
5194
    replace_dynstr_append(ds, field[col_idx].name);
4828
5195
  }
4829
 
  ds->append("\n", 1);
 
5196
  dynstr_append_mem(ds, "\n", 1);
4830
5197
}
4831
5198
 
4832
5199
/*
4836
5203
  Number of warnings appended to ds
4837
5204
*/
4838
5205
 
4839
 
static int append_warnings(string *ds, drizzle_con_st *con,
4840
 
                           drizzle_result_st *res)
 
5206
static int append_warnings(DYNAMIC_STRING *ds, MYSQL* mysql)
4841
5207
{
4842
 
  uint32_t count;
4843
 
  drizzle_result_st warn_res;
4844
 
  drizzle_return_t ret;
4845
 
 
4846
 
 
4847
 
  if (!(count= drizzle_result_warning_count(res)))
 
5208
  uint count;
 
5209
  MYSQL_RES *warn_res;
 
5210
 
 
5211
 
 
5212
  if (!(count= mysql_warning_count(mysql)))
4848
5213
    return(0);
4849
5214
 
4850
 
  if (drizzle_query_str(con, &warn_res, "SHOW WARNINGS", &ret) == NULL ||
4851
 
      ret != DRIZZLE_RETURN_OK)
4852
 
  {
4853
 
    if (ret == DRIZZLE_RETURN_ERROR_CODE)
4854
 
      die("Error running query \"SHOW WARNINGS\": %s", drizzle_result_error(&warn_res));
4855
 
    else
4856
 
      die("Error running query \"SHOW WARNINGS\": %s", drizzle_con_error(con));
4857
 
  }
4858
 
 
4859
 
  if (drizzle_result_column_count(&warn_res) == 0 ||
4860
 
      drizzle_result_buffer(&warn_res) != DRIZZLE_RETURN_OK)
4861
 
    die("Warning count is %u but didn't get any warnings", count);
4862
 
 
4863
 
  append_result(ds, &warn_res);
4864
 
  drizzle_result_free(&warn_res);
 
5215
  /*
 
5216
    If one day we will support execution of multi-statements
 
5217
    through PS API we should not issue SHOW WARNINGS until
 
5218
    we have not read all results...
 
5219
  */
 
5220
  assert(!mysql_more_results(mysql));
 
5221
 
 
5222
  if (mysql_real_query(mysql, "SHOW WARNINGS", 13))
 
5223
    die("Error running query \"SHOW WARNINGS\": %s", mysql_error(mysql));
 
5224
 
 
5225
  if (!(warn_res= mysql_store_result(mysql)))
 
5226
    die("Warning count is %u but didn't get any warnings",
 
5227
        count);
 
5228
 
 
5229
  append_result(ds, warn_res);
 
5230
  mysql_free_result(warn_res);
4865
5231
 
4866
5232
  return(count);
4867
5233
}
4868
5234
 
4869
5235
 
4870
5236
/*
4871
 
  Run query using DRIZZLE C API
 
5237
  Run query using MySQL C API
4872
5238
 
4873
5239
  SYNOPSIS
4874
 
  run_query_normal()
4875
 
  drizzle  DRIZZLE handle
4876
 
  command  current command pointer
4877
 
  flags  flags indicating if we should SEND and/or REAP
4878
 
  query  query string to execute
4879
 
  query_len  length query string to execute
4880
 
  ds    output buffer where to store result form query
 
5240
    run_query_normal()
 
5241
    mysql       mysql handle
 
5242
    command     current command pointer
 
5243
    flags       flags indicating if we should SEND and/or REAP
 
5244
    query       query string to execute
 
5245
    query_len   length query string to execute
 
5246
    ds          output buffer where to store result form query
4881
5247
*/
4882
5248
 
4883
5249
static void run_query_normal(struct st_connection *cn,
4884
5250
                             struct st_command *command,
4885
5251
                             int flags, char *query, int query_len,
4886
 
                             string *ds, string *ds_warnings)
 
5252
                             DYNAMIC_STRING *ds, DYNAMIC_STRING *ds_warnings)
4887
5253
{
4888
 
  drizzle_result_st res;
4889
 
  drizzle_return_t ret;
4890
 
  drizzle_con_st *con= &cn->con;
4891
 
  int err= 0;
4892
 
 
4893
 
  drizzle_con_add_options(con, DRIZZLE_CON_NO_RESULT_READ);
 
5254
  MYSQL_RES *res= 0;
 
5255
  MYSQL *mysql= &cn->mysql;
 
5256
  int err= 0, counter= 0;
4894
5257
 
4895
5258
  if (flags & QUERY_SEND_FLAG)
4896
5259
  {
4897
5260
    /*
4898
 
     * Send the query
4899
 
     */
4900
 
 
4901
 
    (void) drizzle_query(con, &res, query, query_len, &ret);
4902
 
    if (ret != DRIZZLE_RETURN_OK)
 
5261
      Send the query
 
5262
    */
 
5263
    if (do_send_query(cn, query, query_len, flags))
4903
5264
    {
4904
 
      if (ret == DRIZZLE_RETURN_ERROR_CODE ||
4905
 
          ret == DRIZZLE_RETURN_HANDSHAKE_FAILED)
4906
 
      {
4907
 
        err= drizzle_result_error_code(&res);
4908
 
        handle_error(command, err, drizzle_result_error(&res),
4909
 
                     drizzle_result_sqlstate(&res), ds);
4910
 
        if (ret == DRIZZLE_RETURN_ERROR_CODE)
4911
 
          drizzle_result_free(&res);
4912
 
      }
4913
 
      else
4914
 
      {
4915
 
        handle_error(command, ret, drizzle_con_error(con), "", ds);
4916
 
        err= ret;
4917
 
      }
 
5265
      handle_error(command, mysql_errno(mysql), mysql_error(mysql),
 
5266
                   mysql_sqlstate(mysql), ds);
4918
5267
      goto end;
4919
5268
    }
4920
5269
  }
 
5270
#ifdef EMBEDDED_LIBRARY
 
5271
  /*
 
5272
    Here we handle 'reap' command, so we need to check if the
 
5273
    query's thread was finished and probably wait
 
5274
  */
 
5275
  else if (flags & QUERY_REAP_FLAG)
 
5276
    wait_query_thread_end(cn);
 
5277
#endif /*EMBEDDED_LIBRARY*/
4921
5278
  if (!(flags & QUERY_REAP_FLAG))
4922
5279
    return;
4923
5280
 
 
5281
  do
4924
5282
  {
4925
5283
    /*
4926
 
     * Read the result packet
4927
 
     */
4928
 
    if (drizzle_result_read(con, &res, &ret) == NULL ||
4929
 
        ret != DRIZZLE_RETURN_OK)
 
5284
      When  on first result set, call mysql_read_query_result to retrieve
 
5285
      answer to the query sent earlier
 
5286
    */
 
5287
    if ((counter==0) && mysql_read_query_result(mysql))
4930
5288
    {
4931
 
      if (ret == DRIZZLE_RETURN_ERROR_CODE)
4932
 
      {
4933
 
        handle_error(command, drizzle_result_error_code(&res),
4934
 
                     drizzle_result_error(&res), drizzle_result_sqlstate(&res),
4935
 
                     ds);
4936
 
      }
4937
 
      else
4938
 
        handle_error(command, ret, drizzle_con_error(con), "", ds);
4939
 
      drizzle_result_free(&res);
4940
 
      err= ret;
 
5289
      handle_error(command, mysql_errno(mysql), mysql_error(mysql),
 
5290
                   mysql_sqlstate(mysql), ds);
4941
5291
      goto end;
 
5292
 
4942
5293
    }
4943
5294
 
4944
5295
    /*
4945
5296
      Store the result of the query if it will return any fields
4946
5297
    */
4947
 
    if (drizzle_result_column_count(&res) &&
4948
 
        (ret= drizzle_result_buffer(&res)) != DRIZZLE_RETURN_OK)
 
5298
    if (mysql_field_count(mysql) && ((res= mysql_store_result(mysql)) == 0))
4949
5299
    {
4950
 
      if (ret == DRIZZLE_RETURN_ERROR_CODE)
4951
 
      {
4952
 
        handle_error(command, drizzle_result_error_code(&res),
4953
 
                     drizzle_result_error(&res), drizzle_result_sqlstate(&res),
4954
 
                     ds);
4955
 
      }
4956
 
      else
4957
 
        handle_error(command, ret, drizzle_con_error(con), "", ds);
4958
 
      drizzle_result_free(&res);
4959
 
      err= ret;
 
5300
      handle_error(command, mysql_errno(mysql), mysql_error(mysql),
 
5301
                   mysql_sqlstate(mysql), ds);
4960
5302
      goto end;
4961
5303
    }
4962
5304
 
4964
5306
    {
4965
5307
      uint64_t affected_rows= 0;    /* Ok to be undef if 'disable_info' is set */
4966
5308
 
4967
 
      if (drizzle_result_column_count(&res))
 
5309
      if (res)
4968
5310
      {
4969
 
        if (display_metadata)
4970
 
          append_metadata(ds, &res);
4971
 
 
4972
 
        if (!display_result_vertically)
4973
 
          append_table_headings(ds, &res);
4974
 
 
4975
 
        append_result(ds, &res);
 
5311
        MYSQL_FIELD *fields= mysql_fetch_fields(res);
 
5312
        uint num_fields= mysql_num_fields(res);
 
5313
 
 
5314
        if (display_metadata)
 
5315
          append_metadata(ds, fields, num_fields);
 
5316
 
 
5317
        if (!display_result_vertically)
 
5318
          append_table_headings(ds, fields, num_fields);
 
5319
 
 
5320
        append_result(ds, res);
4976
5321
      }
4977
5322
 
4978
5323
      /*
4979
 
        Need to call drizzle_result_affected_rows() before the "new"
 
5324
        Need to call mysql_affected_rows() before the "new"
4980
5325
        query to find the warnings
4981
5326
      */
4982
5327
      if (!disable_info)
4983
 
        affected_rows= drizzle_result_affected_rows(&res);
 
5328
        affected_rows= mysql_affected_rows(mysql);
4984
5329
 
4985
5330
      /*
4986
5331
        Add all warnings to the result. We can't do this if we are in
4987
5332
        the middle of processing results from multi-statement, because
4988
5333
        this will break protocol.
4989
5334
      */
4990
 
      if (!disable_warnings)
 
5335
      if (!disable_warnings && !mysql_more_results(mysql))
4991
5336
      {
4992
 
        drizzle_con_remove_options(con, DRIZZLE_CON_NO_RESULT_READ);
4993
 
        if (append_warnings(ds_warnings, con, &res) || ds_warnings->length())
4994
 
        {
4995
 
          ds->append("Warnings:\n", 10);
4996
 
          ds->append(ds_warnings->c_str(), ds_warnings->length());
4997
 
        }
 
5337
        if (append_warnings(ds_warnings, mysql) || ds_warnings->length)
 
5338
        {
 
5339
          dynstr_append_mem(ds, "Warnings:\n", 10);
 
5340
          dynstr_append_mem(ds, ds_warnings->str, ds_warnings->length);
 
5341
        }
4998
5342
      }
4999
5343
 
5000
5344
      if (!disable_info)
5001
 
        append_info(ds, affected_rows, drizzle_result_info(&res));
 
5345
        append_info(ds, affected_rows, mysql_info(mysql));
5002
5346
    }
5003
5347
 
5004
 
    drizzle_result_free(&res);
 
5348
    if (res)
 
5349
    {
 
5350
      mysql_free_result(res);
 
5351
      res= 0;
 
5352
    }
 
5353
    counter++;
 
5354
  } while (!(err= mysql_next_result(mysql)));
 
5355
  if (err > 0)
 
5356
  {
 
5357
    /* We got an error from mysql_next_result, maybe expected */
 
5358
    handle_error(command, mysql_errno(mysql), mysql_error(mysql),
 
5359
                 mysql_sqlstate(mysql), ds);
 
5360
    goto end;
5005
5361
  }
 
5362
  assert(err == -1); /* Successful and there are no more results */
5006
5363
 
5007
5364
  /* If we come here the query is both executed and read successfully */
5008
5365
  handle_no_error(command);
5010
5367
end:
5011
5368
 
5012
5369
  /*
5013
 
    We save the return code (drizzleclient_errno(drizzle)) from the last call sent
5014
 
    to the server into the drizzletest builtin variable $drizzleclient_errno. This
 
5370
    We save the return code (mysql_errno(mysql)) from the last call sent
 
5371
    to the server into the mysqltest builtin variable $mysql_errno. This
5015
5372
    variable then can be used from the test case itself.
5016
5373
  */
5017
 
  drizzle_con_remove_options(con, DRIZZLE_CON_NO_RESULT_READ);
5018
 
  var_set_errno(err);
 
5374
  var_set_errno(mysql_errno(mysql));
5019
5375
  return;
5020
5376
}
5021
5377
 
5032
5388
  ds    - dynamic string which is used for output buffer
5033
5389
 
5034
5390
  NOTE
5035
 
  If there is an unexpected error this function will abort drizzletest
5036
 
  immediately.
 
5391
    If there is an unexpected error this function will abort mysqltest
 
5392
    immediately.
5037
5393
*/
5038
5394
 
5039
5395
void handle_error(struct st_command *command,
5040
5396
                  unsigned int err_errno, const char *err_error,
5041
 
                  const char *err_sqlstate, string *ds)
 
5397
                  const char *err_sqlstate, DYNAMIC_STRING *ds)
5042
5398
{
5043
 
  uint32_t i;
5044
 
 
5045
 
 
5046
 
  if (! command->require_file.empty())
 
5399
  uint i;
 
5400
 
 
5401
 
 
5402
 
 
5403
  if (command->require_file[0])
5047
5404
  {
5048
5405
    /*
5049
5406
      The query after a "--require" failed. This is fine as long the server
5050
5407
      returned a valid reponse. Don't allow 2013 or 2006 to trigger an
5051
5408
      abort_not_supported_test
5052
5409
    */
5053
 
    if (err_errno == DRIZZLE_RETURN_SERVER_GONE)
 
5410
    if (err_errno == CR_SERVER_LOST ||
 
5411
        err_errno == CR_SERVER_GONE_ERROR)
5054
5412
      die("require query '%s' failed: %d: %s", command->query,
5055
5413
          err_errno, err_error);
5056
5414
 
5062
5420
  if (command->abort_on_error)
5063
5421
    die("query '%s' failed: %d: %s", command->query, err_errno, err_error);
5064
5422
 
5065
 
  for (i= 0 ; (uint32_t) i < command->expected_errors.count ; i++)
 
5423
  for (i= 0 ; (uint) i < command->expected_errors.count ; i++)
5066
5424
  {
5067
5425
    if (((command->expected_errors.err[i].type == ERR_ERRNO) &&
5068
5426
         (command->expected_errors.err[i].code.errnum == err_errno)) ||
5069
5427
        ((command->expected_errors.err[i].type == ERR_SQLSTATE) &&
5070
5428
         (strncmp(command->expected_errors.err[i].code.sqlstate,
5071
 
                  err_sqlstate, DRIZZLE_MAX_SQLSTATE_SIZE) == 0)))
 
5429
                  err_sqlstate, SQLSTATE_LENGTH) == 0)))
5072
5430
    {
5073
5431
      if (!disable_result_log)
5074
5432
      {
5075
5433
        if (command->expected_errors.count == 1)
5076
5434
        {
5077
5435
          /* Only log error if there is one possible error */
5078
 
          ds->append("ERROR ", 6);
5079
 
          replace_append(ds, err_sqlstate);
5080
 
          ds->append(": ", 2);
5081
 
          replace_append(ds, err_error);
5082
 
          ds->append("\n",1);
 
5436
          dynstr_append_mem(ds, "ERROR ", 6);
 
5437
          replace_dynstr_append(ds, err_sqlstate);
 
5438
          dynstr_append_mem(ds, ": ", 2);
 
5439
          replace_dynstr_append(ds, err_error);
 
5440
          dynstr_append_mem(ds,"\n",1);
5083
5441
        }
5084
5442
        /* Don't log error if we may not get an error */
5085
5443
        else if (command->expected_errors.err[0].type == ERR_SQLSTATE ||
5086
5444
                 (command->expected_errors.err[0].type == ERR_ERRNO &&
5087
5445
                  command->expected_errors.err[0].code.errnum != 0))
5088
 
          ds->append("Got one of the listed errors\n");
 
5446
          dynstr_append(ds,"Got one of the listed errors\n");
5089
5447
      }
5090
5448
      /* OK */
5091
5449
      return;
5094
5452
 
5095
5453
  if (!disable_result_log)
5096
5454
  {
5097
 
    ds->append("ERROR ",6);
5098
 
    replace_append(ds, err_sqlstate);
5099
 
    ds->append(": ", 2);
5100
 
    replace_append(ds, err_error);
5101
 
    ds->append("\n", 1);
 
5455
    dynstr_append_mem(ds, "ERROR ",6);
 
5456
    replace_dynstr_append(ds, err_sqlstate);
 
5457
    dynstr_append_mem(ds, ": ", 2);
 
5458
    replace_dynstr_append(ds, err_error);
 
5459
    dynstr_append_mem(ds, "\n", 1);
5102
5460
  }
5103
5461
 
5104
5462
  if (i)
5110
5468
    else
5111
5469
      die("query '%s' failed with wrong sqlstate %s: '%s', instead of %s...",
5112
5470
          command->query, err_sqlstate, err_error,
5113
 
          command->expected_errors.err[0].code.sqlstate);
 
5471
          command->expected_errors.err[0].code.sqlstate);
5114
5472
  }
5115
5473
 
5116
5474
  return;
5155
5513
  Run query
5156
5514
 
5157
5515
  SYNPOSIS
5158
 
  run_query()
5159
 
  drizzle  DRIZZLE handle
5160
 
  command  currrent command pointer
 
5516
    run_query()
 
5517
     mysql      mysql handle
 
5518
     command    currrent command pointer
5161
5519
 
5162
5520
  flags control the phased/stages of query execution to be performed
5163
5521
  if QUERY_SEND_FLAG bit is on, the query will be sent. If QUERY_REAP_FLAG
5164
5522
  is on the result will be read - for regular query, both bits must be on
5165
5523
*/
5166
5524
 
5167
 
static void run_query(struct st_connection *cn,
 
5525
static void run_query(struct st_connection *cn, 
5168
5526
                      struct st_command *command,
5169
5527
                      int flags)
5170
5528
{
5171
 
  string *ds= NULL;
5172
 
  string *save_ds= NULL;
5173
 
  string ds_result;
5174
 
  string ds_sorted;
5175
 
  string ds_warnings;
5176
 
  string eval_query;
 
5529
  DYNAMIC_STRING *ds;
 
5530
  DYNAMIC_STRING *save_ds= NULL;
 
5531
  DYNAMIC_STRING ds_result;
 
5532
  DYNAMIC_STRING ds_sorted;
 
5533
  DYNAMIC_STRING ds_warnings;
 
5534
  DYNAMIC_STRING eval_query;
5177
5535
  char *query;
5178
5536
  int query_len;
5179
5537
 
5180
5538
 
 
5539
  init_dynamic_string(&ds_warnings, NULL, 0, 256);
 
5540
 
5181
5541
  /* Scan for warning before sending to server */
5182
5542
  scan_command_for_warnings(command);
5183
5543
 
5186
5546
  */
5187
5547
  if (command->type == Q_EVAL)
5188
5548
  {
5189
 
    do_eval(&eval_query, command->query, command->end, false);
5190
 
    query = strdup(eval_query.c_str());
5191
 
    query_len = eval_query.length();
 
5549
    init_dynamic_string(&eval_query, "", command->query_len+256, 1024);
 
5550
    do_eval(&eval_query, command->query, command->end, FALSE);
 
5551
    query = eval_query.str;
 
5552
    query_len = eval_query.length;
5192
5553
  }
5193
5554
  else
5194
5555
  {
5202
5563
    Create a temporary dynamic string to contain the output from
5203
5564
    this query.
5204
5565
  */
5205
 
  if (! command->require_file.empty())
 
5566
  if (command->require_file[0])
5206
5567
  {
 
5568
    init_dynamic_string(&ds_result, "", 1024, 1024);
5207
5569
    ds= &ds_result;
5208
5570
  }
5209
5571
  else
5210
 
  {
5211
5572
    ds= &ds_res;
5212
 
  }
 
5573
 
5213
5574
  /*
5214
5575
    Log the query into the output buffer
5215
5576
  */
5216
5577
  if (!disable_query_log && (flags & QUERY_SEND_FLAG))
5217
5578
  {
5218
 
    replace_append_mem(ds, query, query_len);
5219
 
    ds->append(delimiter, delimiter_length);
5220
 
    ds->append("\n");
 
5579
    replace_dynstr_append_mem(ds, query, query_len);
 
5580
    dynstr_append_mem(ds, delimiter, delimiter_length);
 
5581
    dynstr_append_mem(ds, "\n", 1);
5221
5582
  }
5222
5583
 
5223
5584
  if (display_result_sorted)
5224
5585
  {
5225
5586
    /*
5226
 
      Collect the query output in a separate string
5227
 
      that can be sorted before it's added to the
5228
 
      global result string
 
5587
       Collect the query output in a separate string
 
5588
       that can be sorted before it's added to the
 
5589
       global result string
5229
5590
    */
 
5591
    init_dynamic_string(&ds_sorted, "", 1024, 1024);
5230
5592
    save_ds= ds; /* Remember original ds */
5231
5593
    ds= &ds_sorted;
5232
5594
  }
5241
5603
  if (display_result_sorted)
5242
5604
  {
5243
5605
    /* Sort the result set and append it to result */
5244
 
    append_sorted(save_ds, &ds_sorted);
 
5606
    dynstr_append_sorted(save_ds, &ds_sorted);
5245
5607
    ds= save_ds;
 
5608
    dynstr_free(&ds_sorted);
5246
5609
  }
5247
5610
 
5248
 
  if (! command->require_file.empty())
 
5611
  if (command->require_file[0])
5249
5612
  {
5250
5613
    /* A result file was specified for _this_ query
5251
5614
       and the output should be checked against an already
5254
5617
    check_require(ds, command->require_file);
5255
5618
  }
5256
5619
 
 
5620
  dynstr_free(&ds_warnings);
 
5621
  if (ds == &ds_result)
 
5622
    dynstr_free(&ds_result);
 
5623
  if (command->type == Q_EVAL)
 
5624
    dynstr_free(&eval_query);
5257
5625
  return;
5258
5626
}
5259
5627
 
5263
5631
static void get_command_type(struct st_command* command)
5264
5632
{
5265
5633
  char save;
5266
 
  uint32_t type;
 
5634
  uint type;
5267
5635
 
5268
5636
 
5269
5637
  if (*command->query == '}')
5274
5642
 
5275
5643
  save= command->query[command->first_word_len];
5276
5644
  command->query[command->first_word_len]= 0;
5277
 
  type= command_typelib.find_type(command->query, 1+2);
 
5645
  type= find_type(command->query, &command_typelib, 1+2);
5278
5646
  command->query[command->first_word_len]= save;
5279
5647
  if (type > 0)
5280
5648
  {
5281
 
    command->type=(enum enum_commands) type;    /* Found command */
 
5649
    command->type=(enum enum_commands) type;            /* Found command */
5282
5650
 
5283
5651
    /*
5284
5652
      Look for case where "query" was explicitly specified to
5292
5660
  }
5293
5661
  else
5294
5662
  {
5295
 
    /* No drizzletest command matched */
 
5663
    /* No mysqltest command matched */
5296
5664
 
5297
5665
    if (command->type != Q_COMMENT_WITH_COMMAND)
5298
5666
    {
5299
 
      /* A query that will sent to drizzled */
 
5667
      /* A query that will sent to mysqld */
5300
5668
      command->type= Q_QUERY;
5301
5669
    }
5302
5670
    else
5303
5671
    {
5304
 
      /* -- comment that didn't contain a drizzletest command */
 
5672
      /* -- comment that didn't contain a mysqltest command */
5305
5673
      command->type= Q_COMMENT;
5306
 
      warning_msg("Suspicious command '--%s' detected, was this intentional? " \
 
5674
      warning_msg("Suspicious command '--%s' detected, was this intentional? "\
5307
5675
                  "Use # instead of -- to avoid this warning",
5308
5676
                  command->query);
5309
5677
 
5318
5686
        */
5319
5687
        save= command->query[command->first_word_len-1];
5320
5688
        command->query[command->first_word_len-1]= 0;
5321
 
        if (command_typelib.find_type(command->query, 1+2) > 0)
 
5689
        if (find_type(command->query, &command_typelib, 1+2) > 0)
5322
5690
          die("Extra delimiter \";\" found");
5323
5691
        command->query[command->first_word_len-1]= save;
5324
5692
 
5346
5714
 
5347
5715
*/
5348
5716
 
5349
 
static void mark_progress(struct st_command*, int line)
 
5717
static void mark_progress(struct st_command* command __attribute__((unused)),
 
5718
                          int line)
5350
5719
{
 
5720
  char buf[32], *end;
5351
5721
  uint64_t timer= timer_now();
5352
5722
  if (!progress_start)
5353
5723
    progress_start= timer;
5354
5724
  timer-= progress_start;
5355
5725
 
5356
 
  ostringstream buf;
5357
5726
  /* Milliseconds since start */
5358
 
  buf << timer << "\t";
 
5727
  end= int64_t2str(timer, buf, 10);
 
5728
  dynstr_append_mem(&ds_progress, buf, (int)(end-buf));
 
5729
  dynstr_append_mem(&ds_progress, "\t", 1);
5359
5730
 
5360
5731
  /* Parser line number */
5361
 
  buf << line << "\t";
 
5732
  end= int10_to_str(line, buf, 10);
 
5733
  dynstr_append_mem(&ds_progress, buf, (int)(end-buf));
 
5734
  dynstr_append_mem(&ds_progress, "\t", 1);
5362
5735
 
5363
5736
  /* Filename */
5364
 
  buf << cur_file->file_name << ":";
 
5737
  dynstr_append(&ds_progress, cur_file->file_name);
 
5738
  dynstr_append_mem(&ds_progress, ":", 1);
5365
5739
 
5366
5740
  /* Line in file */
5367
 
  buf << cur_file->lineno << endl;
5368
 
 
5369
 
  ds_progress.append(buf.str());
5370
 
 
5371
 
}
5372
 
 
5373
 
static void check_retries(uint32_t in_opt_max_connect_retries)
5374
 
{
5375
 
  if (in_opt_max_connect_retries > 10000 || opt_max_connect_retries<1)
5376
 
  {
5377
 
    cout << N_("Error: Invalid Value for opt_max_connect_retries"); 
5378
 
    exit(-1);
5379
 
  }
5380
 
  opt_max_connect_retries= in_opt_max_connect_retries;
5381
 
}
5382
 
 
5383
 
static void check_tail_lines(uint32_t in_opt_tail_lines)
5384
 
{
5385
 
  if (in_opt_tail_lines > 10000)
5386
 
  {
5387
 
    cout << N_("Error: Invalid Value for opt_tail_lines"); 
5388
 
    exit(-1);
5389
 
  }
5390
 
  opt_tail_lines= in_opt_tail_lines;
5391
 
}
5392
 
 
5393
 
static void check_sleep(int32_t in_opt_sleep)
5394
 
{
5395
 
  if (in_opt_sleep < -1)
5396
 
  {
5397
 
    cout << N_("Error: Invalid Value for opt_sleep"); 
5398
 
    exit(-1);
5399
 
  }
5400
 
  opt_sleep= in_opt_sleep;
5401
 
}
 
5741
  end= int10_to_str(cur_file->lineno, buf, 10);
 
5742
  dynstr_append_mem(&ds_progress, buf, (int)(end-buf));
 
5743
 
 
5744
 
 
5745
  dynstr_append_mem(&ds_progress, "\n", 1);
 
5746
 
 
5747
}
 
5748
 
5402
5749
 
5403
5750
int main(int argc, char **argv)
5404
5751
{
5405
 
try
5406
 
{
5407
5752
  struct st_command *command;
5408
5753
  bool q_send_flag= 0, abort_flag= 0;
5409
 
  uint32_t command_executed= 0, last_command_executed= 0;
5410
 
  string save_file("");
 
5754
  uint command_executed= 0, last_command_executed= 0;
 
5755
  char save_file[FN_REFLEN];
5411
5756
  struct stat res_info;
 
5757
  MY_INIT(argv[0]);
5412
5758
 
 
5759
  save_file[0]= 0;
5413
5760
  TMPDIR[0]= 0;
5414
5761
 
5415
 
  internal::my_init();
5416
 
 
5417
 
  po::options_description commandline_options("Options used only in command line");
5418
 
  commandline_options.add_options()
5419
 
  ("help,?", "Display this help and exit.")
5420
 
  ("mark-progress", po::value<bool>(&opt_mark_progress)->default_value(false)->zero_tokens(),
5421
 
  "Write linenumber and elapsed time to <testname>.progress ")
5422
 
  ("sleep,T", po::value<int32_t>(&opt_sleep)->default_value(-1)->notifier(&check_sleep),
5423
 
  "Sleep always this many seconds on sleep commands.")
5424
 
  ("test-file,x", po::value<string>(),
5425
 
  "Read test from/in this file (default stdin).")
5426
 
  ("timer-file,f", po::value<string>(),
5427
 
  "File where the timing in micro seconds is stored.")
5428
 
  ("tmpdir,t", po::value<string>(),
5429
 
  "Temporary directory where sockets are put.")
5430
 
  ("verbose,v", po::value<bool>(&verbose)->default_value(false),
5431
 
  "Write more.")
5432
 
  ("version,V", "Output version information and exit.")
5433
 
  ("no-defaults", po::value<bool>()->default_value(false)->zero_tokens(),
5434
 
  "Configuration file defaults are not used if no-defaults is set")
5435
 
  ;
5436
 
 
5437
 
  po::options_description test_options("Options specific to the drizzleimport");
5438
 
  test_options.add_options()
5439
 
  ("basedir,b", po::value<string>(&opt_basedir)->default_value(""),
5440
 
  "Basedir for tests.")
5441
 
  ("character-sets-dir", po::value<string>(&opt_charsets_dir)->default_value(""),
5442
 
  "Directory where character sets are.")
5443
 
  ("database,D", po::value<string>(&opt_db)->default_value(""),
5444
 
  "Database to use.")
5445
 
  ("include,i", po::value<string>(&opt_include)->default_value(""),
5446
 
  "Include SQL before each test case.")  
5447
 
  ("testdir", po::value<string>(&opt_testdir)->default_value(""),
5448
 
  "Path to use to search for test files")
5449
 
  ("logdir", po::value<string>(&opt_logdir)->default_value(""),
5450
 
  "Directory for log files")
5451
 
  ("max-connect-retries", po::value<uint32_t>(&opt_max_connect_retries)->default_value(500)->notifier(&check_retries),
5452
 
  "Max number of connection attempts when connecting to server")
5453
 
  ("quiet,s", po::value<bool>(&silent)->default_value(false)->zero_tokens(),
5454
 
  "Suppress all normal output.")
5455
 
  ("record,r", "Record output of test_file into result file.")
5456
 
  ("result-file,R", po::value<string>(&result_file_name)->default_value(""),
5457
 
  "Read/Store result from/in this file.")
5458
 
  ("silent,s", po::value<bool>(&silent)->default_value(false)->zero_tokens(),
5459
 
  "Suppress all normal output. Synonym for --quiet.")
5460
 
  ("tail-lines", po::value<uint32_t>(&opt_tail_lines)->default_value(0)->notifier(&check_tail_lines),
5461
 
  "Number of lines of the resul to include in a failure report")
5462
 
  ;
5463
 
 
5464
 
  po::options_description client_options("Options specific to the client");
5465
 
  client_options.add_options()
5466
 
 
5467
 
  ("host,h", po::value<string>(&opt_host)->default_value("localhost"),
5468
 
  "Connect to host.")
5469
 
  ("password,P", po::value<string>(&password)->default_value("PASSWORD_SENTINEL"),
5470
 
  "Password to use when connecting to server.")
5471
 
  ("port,p", po::value<uint32_t>(&opt_port)->default_value(0),
5472
 
  "Port number to use for connection or 0 for default")
5473
 
  ("protocol", po::value<string>(&opt_protocol),
5474
 
  "The protocol of connection (mysql or drizzle).")
5475
 
  ("user,u", po::value<string>(&opt_user)->default_value(""),
5476
 
  "User for login.")
5477
 
  ;
5478
 
 
5479
 
  po::positional_options_description p;
5480
 
  p.add("database", 1);
5481
 
 
5482
 
  po::options_description long_options("Allowed Options");
5483
 
  long_options.add(commandline_options).add(test_options).add(client_options);
5484
 
 
5485
 
  std::string system_config_dir_test(SYSCONFDIR); 
5486
 
  system_config_dir_test.append("/drizzle/drizzletest.cnf");
5487
 
 
5488
 
  std::string system_config_dir_client(SYSCONFDIR); 
5489
 
  system_config_dir_client.append("/drizzle/client.cnf");
5490
 
 
5491
 
  std::string user_config_dir((getenv("XDG_CONFIG_HOME")? getenv("XDG_CONFIG_HOME"):"~/.config"));
5492
 
 
5493
 
  if (user_config_dir.compare(0, 2, "~/") == 0)
5494
 
  {
5495
 
    const char *homedir= getenv("HOME");
5496
 
    if (homedir != NULL)
5497
 
      user_config_dir.replace(0, 1, homedir);
5498
 
  }
5499
 
 
5500
 
  po::variables_map vm;
5501
 
 
5502
 
  // Disable allow_guessing
5503
 
  int style = po::command_line_style::default_style & ~po::command_line_style::allow_guessing;
5504
 
 
5505
 
  po::store(po::command_line_parser(argc, argv).options(long_options).
5506
 
            style(style).positional(p).extra_parser(parse_password_arg).run(),
5507
 
            vm);
5508
 
 
5509
 
  if (! vm["no-defaults"].as<bool>())
5510
 
  {
5511
 
    std::string user_config_dir_test(user_config_dir);
5512
 
    user_config_dir_test.append("/drizzle/drizzletest.cnf"); 
5513
 
 
5514
 
    std::string user_config_dir_client(user_config_dir);
5515
 
    user_config_dir_client.append("/drizzle/client.cnf");
5516
 
 
5517
 
    ifstream user_test_ifs(user_config_dir_test.c_str());
5518
 
    po::store(parse_config_file(user_test_ifs, test_options), vm);
5519
 
 
5520
 
    ifstream user_client_ifs(user_config_dir_client.c_str());
5521
 
    po::store(parse_config_file(user_client_ifs, client_options), vm);
5522
 
 
5523
 
    ifstream system_test_ifs(system_config_dir_test.c_str());
5524
 
    store(parse_config_file(system_test_ifs, test_options), vm);
5525
 
 
5526
 
    ifstream system_client_ifs(system_config_dir_client.c_str());
5527
 
    po::store(parse_config_file(system_client_ifs, client_options), vm);
5528
 
  }
5529
 
 
5530
 
  po::notify(vm);
5531
 
 
5532
5762
  /* Init expected errors */
5533
5763
  memset(&saved_expected_errors, 0, sizeof(saved_expected_errors));
5534
5764
 
5538
5768
    (sizeof(connections)/sizeof(struct st_connection)) - 1;
5539
5769
  next_con= connections + 1;
5540
5770
 
 
5771
#ifdef EMBEDDED_LIBRARY
 
5772
  /* set appropriate stack for the 'query' threads */
 
5773
  (void) pthread_attr_init(&cn_thd_attrib);
 
5774
  pthread_attr_setstacksize(&cn_thd_attrib, DEFAULT_THREAD_STACK);
 
5775
#endif /*EMBEDDED_LIBRARY*/
 
5776
 
5541
5777
  /* Init file stack */
5542
 
  memset(file_stack.data(), 0, sizeof(file_stack));
5543
 
  cur_file= file_stack.data();
 
5778
  memset(file_stack, 0, sizeof(file_stack));
 
5779
  file_stack_end=
 
5780
    file_stack + (sizeof(file_stack)/sizeof(struct st_test_file)) - 1;
 
5781
  cur_file= file_stack;
5544
5782
 
5545
5783
  /* Init block stack */
5546
5784
  memset(block_stack, 0, sizeof(block_stack));
5547
5785
  block_stack_end=
5548
5786
    block_stack + (sizeof(block_stack)/sizeof(struct st_block)) - 1;
5549
5787
  cur_block= block_stack;
5550
 
  cur_block->ok= true; /* Outer block should always be executed */
 
5788
  cur_block->ok= TRUE; /* Outer block should always be executed */
5551
5789
  cur_block->cmd= cmd_none;
5552
5790
 
5553
 
  var_set_string("$DRIZZLE_SERVER_VERSION", drizzle_version());
 
5791
  my_init_dynamic_array(&q_lines, sizeof(struct st_command*), 1024, 1024);
 
5792
 
 
5793
  if (hash_init(&var_hash, charset_info,
 
5794
                1024, 0, 0, get_var_key, var_free, MYF(0)))
 
5795
    die("Variable hash initialization failed");
 
5796
 
 
5797
  var_set_string("$MYSQL_SERVER_VERSION", MYSQL_SERVER_VERSION);
5554
5798
 
5555
5799
  memset(&master_pos, 0, sizeof(master_pos));
5556
5800
 
5559
5803
 
5560
5804
  init_builtin_echo();
5561
5805
 
5562
 
  ds_res.reserve(65536);
5563
 
  ds_progress.reserve(2048);
5564
 
  ds_warning_messages.reserve(2048);
5565
 
 
5566
 
 
5567
 
  if (vm.count("record"))
5568
 
  {
5569
 
    record = 1;
5570
 
  }
5571
 
 
5572
 
  if (vm.count("test-file"))
5573
 
  {
5574
 
    string tmp= vm["test-file"].as<string>();
5575
 
    char buff[FN_REFLEN];
5576
 
    if (!internal::test_if_hard_path(tmp.c_str()))
5577
 
    {
5578
 
      snprintf(buff, sizeof(buff), "%s%s",opt_basedir.c_str(),tmp.c_str());
5579
 
      tmp= buff;
5580
 
    }
5581
 
    internal::fn_format(buff, tmp.c_str(), "", "", MY_UNPACK_FILENAME);
5582
 
    assert(cur_file == file_stack.data() && cur_file->file == 0);
5583
 
    if (!(cur_file->file= fopen(buff, "r")))
5584
 
    {
5585
 
      fprintf(stderr, _("Could not open '%s' for reading: errno = %d"), buff, errno);
5586
 
      return EXIT_ARGUMENT_INVALID;
5587
 
    }
5588
 
    if (!(cur_file->file_name= strdup(buff)))
5589
 
    {
5590
 
      fprintf(stderr, _("Out of memory"));
5591
 
      return EXIT_OUT_OF_MEMORY;
5592
 
    }
5593
 
    cur_file->lineno= 1;
5594
 
  }
5595
 
 
5596
 
  if (vm.count("timer-file"))
5597
 
  {
5598
 
    string tmp= vm["timer-file"].as<string>().c_str();
5599
 
    static char buff[FN_REFLEN];
5600
 
    if (!internal::test_if_hard_path(tmp.c_str()))
5601
 
    {
5602
 
      snprintf(buff, sizeof(buff), "%s%s",opt_basedir.c_str(),tmp.c_str());
5603
 
      tmp= buff;
5604
 
    }
5605
 
    internal::fn_format(buff, tmp.c_str(), "", "", MY_UNPACK_FILENAME);
5606
 
    timer_file= buff;
5607
 
    unlink(timer_file);       /* Ignore error, may not exist */
5608
 
  }
5609
 
 
5610
 
  if (vm.count("protocol"))
5611
 
  {
5612
 
    std::transform(opt_protocol.begin(), opt_protocol.end(),
5613
 
      opt_protocol.begin(), ::tolower);
5614
 
 
5615
 
    if (not opt_protocol.compare("mysql"))
5616
 
      use_drizzle_protocol=false;
5617
 
    else if (not opt_protocol.compare("drizzle"))
5618
 
      use_drizzle_protocol=true;
5619
 
    else
5620
 
    {
5621
 
      cout << _("Error: Unknown protocol") << " '" << opt_protocol << "'" << endl;
5622
 
      exit(-1);
5623
 
    }
5624
 
  }
5625
 
 
5626
 
  if (vm.count("port"))
5627
 
  {
5628
 
    /* If the port number is > 65535 it is not a valid port
5629
 
       This also helps with potential data loss casting unsigned long to a
5630
 
       uint32_t. */
5631
 
    if (opt_port > 65535)
5632
 
    {
5633
 
      fprintf(stderr, _("Value supplied for port is not valid.\n"));
5634
 
      exit(EXIT_ARGUMENT_INVALID);
5635
 
    }
5636
 
  }
5637
 
 
5638
 
  if( vm.count("password") )
5639
 
  {
5640
 
    if (!opt_password.empty())
5641
 
      opt_password.erase();
5642
 
    if (password == PASSWORD_SENTINEL)
5643
 
    {
5644
 
      opt_password= "";
5645
 
    }
5646
 
    else
5647
 
    {
5648
 
      opt_password= password;
5649
 
      tty_password= false;
5650
 
    }
5651
 
  }
5652
 
  else
5653
 
  {
5654
 
      tty_password= true;
5655
 
  }
5656
 
 
5657
 
  if (vm.count("tmpdir"))
5658
 
  {
5659
 
    strncpy(TMPDIR, vm["tmpdir"].as<string>().c_str(), sizeof(TMPDIR));
5660
 
  }
5661
 
 
5662
 
  if (vm.count("version"))
5663
 
  {
5664
 
    printf("%s  Ver %s Distrib %s, for %s-%s (%s)\n",internal::my_progname,MTEST_VERSION,
5665
 
    drizzle_version(),HOST_VENDOR,HOST_OS,HOST_CPU);
5666
 
    exit(0);
5667
 
  }
5668
 
  
5669
 
  if (vm.count("help"))
5670
 
  {
5671
 
    printf("%s  Ver %s Distrib %s, for %s-%s (%s)\n",internal::my_progname,MTEST_VERSION,
5672
 
    drizzle_version(),HOST_VENDOR,HOST_OS,HOST_CPU);
5673
 
    printf("MySQL AB, by Sasha, Matt, Monty & Jani\n");
5674
 
    printf("Drizzle version modified by Brian, Jay, Monty Taylor, PatG and Stewart\n");
5675
 
    printf("This software comes with ABSOLUTELY NO WARRANTY\n\n");
5676
 
    printf("Runs a test against the DRIZZLE server and compares output with a results file.\n\n");
5677
 
    printf("Usage: %s [OPTIONS] [database] < test_file\n", internal::my_progname);
5678
 
    exit(0);
5679
 
  }
5680
 
 
5681
 
  if (tty_password)
5682
 
  {
5683
 
    opt_pass= client_get_tty_password(NULL);          /* purify tested */
5684
 
  }
5685
 
 
 
5806
  init_dynamic_string(&ds_res, "", 65536, 65536);
 
5807
  init_dynamic_string(&ds_progress, "", 0, 2048);
 
5808
  init_dynamic_string(&ds_warning_messages, "", 0, 2048);
 
5809
  parse_args(argc, argv);
 
5810
 
 
5811
  if (mysql_server_init(embedded_server_arg_count,
 
5812
                        embedded_server_args,
 
5813
                        (char**) embedded_server_groups))
 
5814
    die("Can't initialize MySQL server");
5686
5815
  server_initialized= 1;
5687
 
  if (cur_file == file_stack.data() && cur_file->file == 0)
 
5816
  if (cur_file == file_stack && cur_file->file == 0)
5688
5817
  {
5689
5818
    cur_file->file= stdin;
5690
 
    cur_file->file_name= strdup("<stdin>");
5691
 
    if (cur_file->file_name == NULL)
5692
 
      die("Out of memory");
 
5819
    cur_file->file_name= my_strdup("<stdin>", MYF(MY_WME));
5693
5820
    cur_file->lineno= 1;
5694
5821
  }
5695
5822
  cur_con= connections;
5696
 
  if ((cur_con->drizzle= drizzle_create(NULL)) == NULL)
5697
 
    die("Failed in drizzle_create()");
5698
 
  if (!( drizzle_con_create(cur_con->drizzle, &cur_con->con)))
5699
 
    die("Failed in drizzle_con_create()");
5700
 
  drizzle_con_add_options(&cur_con->con, use_drizzle_protocol ? DRIZZLE_CON_EXPERIMENTAL : DRIZZLE_CON_MYSQL);
 
5823
  if (!( mysql_init(&cur_con->mysql)))
 
5824
    die("Failed in mysql_init()");
 
5825
  if (opt_compress)
 
5826
    mysql_options(&cur_con->mysql,MYSQL_OPT_COMPRESS,NullS);
 
5827
  mysql_options(&cur_con->mysql, MYSQL_OPT_LOCAL_INFILE, 0);
 
5828
  mysql_options(&cur_con->mysql, MYSQL_SET_CHARSET_NAME,
 
5829
                charset_info->csname);
 
5830
  int opt_protocol= MYSQL_PROTOCOL_TCP;
 
5831
  mysql_options(&cur_con->mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
 
5832
  if (opt_charsets_dir)
 
5833
    mysql_options(&cur_con->mysql, MYSQL_SET_CHARSET_DIR,
 
5834
                  opt_charsets_dir);
5701
5835
 
5702
 
  if (!(cur_con->name = strdup("default")))
 
5836
  if (!(cur_con->name = my_strdup("default", MYF(MY_WME))))
5703
5837
    die("Out of memory");
5704
 
  safe_connect(&cur_con->con, cur_con->name, opt_host, opt_user, opt_pass,
 
5838
 
 
5839
  safe_connect(&cur_con->mysql, cur_con->name, opt_host, opt_user, opt_pass,
5705
5840
               opt_db, opt_port);
5706
5841
 
5707
 
  fill_global_error_names();
5708
 
 
5709
5842
  /* Use all time until exit if no explicit 'start_timer' */
5710
5843
  timer_start= timer_now();
5711
5844
 
5712
5845
  /*
5713
 
    Initialize $drizzleclient_errno with -1, so we can
 
5846
    Initialize $mysql_errno with -1, so we can
5714
5847
    - distinguish it from valid values ( >= 0 ) and
5715
5848
    - detect if there was never a command sent to the server
5716
5849
  */
5717
5850
  var_set_errno(-1);
5718
5851
 
5719
 
  /* Update $drizzleclient_get_server_version to that of current connection */
5720
 
  var_set_drizzleclient_get_server_version(&cur_con->con);
 
5852
  /* Update $mysql_get_server_version to that of current connection */
 
5853
  var_set_mysql_get_server_version(&cur_con->mysql);
5721
5854
 
5722
 
  if (! opt_include.empty())
 
5855
  if (opt_include)
5723
5856
  {
5724
 
    open_file(opt_include.c_str());
 
5857
    open_file(opt_include);
5725
5858
  }
5726
5859
 
5727
5860
  while (!read_command(&command) && !abort_flag)
5746
5879
      case Q_CONNECT:
5747
5880
        do_connect(command);
5748
5881
        break;
5749
 
      case Q_CONNECTION:
5750
 
        select_connection(command);
5751
 
        break;
 
5882
      case Q_CONNECTION: select_connection(command); break;
5752
5883
      case Q_DISCONNECT:
5753
5884
      case Q_DIRTY_CLOSE:
5754
 
        do_close_connection(command); break;
 
5885
        do_close_connection(command); break;
5755
5886
      case Q_ENABLE_QUERY_LOG:   disable_query_log=0; break;
5756
5887
      case Q_DISABLE_QUERY_LOG:  disable_query_log=1; break;
5757
5888
      case Q_ENABLE_ABORT_ON_ERROR:  abort_on_error=1; break;
5787
5918
      case Q_PERL: do_perl(command); break;
5788
5919
      case Q_DELIMITER:
5789
5920
        do_delimiter(command);
5790
 
        break;
 
5921
        break;
5791
5922
      case Q_DISPLAY_VERTICAL_RESULTS:
5792
 
        display_result_vertically= true;
 
5923
        display_result_vertically= TRUE;
5793
5924
        break;
5794
5925
      case Q_DISPLAY_HORIZONTAL_RESULTS:
5795
 
        display_result_vertically= false;
 
5926
        display_result_vertically= FALSE;
5796
5927
        break;
5797
5928
      case Q_SORTED_RESULT:
5798
5929
        /*
5799
5930
          Turn on sorting of result set, will be reset after next
5800
5931
          command
5801
5932
        */
5802
 
        display_result_sorted= true;
 
5933
        display_result_sorted= TRUE;
5803
5934
        break;
5804
5935
      case Q_LET: do_let(command); break;
5805
5936
      case Q_EVAL_RESULT:
5807
5938
      case Q_EVAL:
5808
5939
      case Q_QUERY_VERTICAL:
5809
5940
      case Q_QUERY_HORIZONTAL:
5810
 
        if (command->query == command->query_buf)
 
5941
        if (command->query == command->query_buf)
5811
5942
        {
5812
5943
          /* Skip the first part of command, i.e query_xxx */
5813
 
          command->query= command->first_argument;
 
5944
          command->query= command->first_argument;
5814
5945
          command->first_word_len= 0;
5815
5946
        }
5816
 
        /* fall through */
 
5947
        /* fall through */
5817
5948
      case Q_QUERY:
5818
5949
      case Q_REAP:
5819
5950
      {
5820
 
        bool old_display_result_vertically= display_result_vertically;
 
5951
        bool old_display_result_vertically= display_result_vertically;
5821
5952
        /* Default is full query, both reap and send  */
5822
5953
        int flags= QUERY_REAP_FLAG | QUERY_SEND_FLAG;
5823
5954
 
5835
5966
        /* Check for special property for this query */
5836
5967
        display_result_vertically|= (command->type == Q_QUERY_VERTICAL);
5837
5968
 
5838
 
        if (! save_file.empty())
5839
 
        {
5840
 
          command->require_file= save_file;
5841
 
          save_file.clear();
5842
 
        }
5843
 
        run_query(cur_con, command, flags);
5844
 
        command_executed++;
 
5969
        if (save_file[0])
 
5970
        {
 
5971
          strmake(command->require_file, save_file, sizeof(save_file) - 1);
 
5972
          save_file[0]= 0;
 
5973
        }
 
5974
        run_query(cur_con, command, flags);
 
5975
        command_executed++;
5845
5976
        command->last_argument= command->end;
5846
5977
 
5847
5978
        /* Restore settings */
5848
 
        display_result_vertically= old_display_result_vertically;
 
5979
        display_result_vertically= old_display_result_vertically;
5849
5980
 
5850
 
        break;
 
5981
        break;
5851
5982
      }
5852
5983
      case Q_SEND:
5853
5984
        if (!*command->first_argument)
5861
5992
        }
5862
5993
 
5863
5994
        /* Remove "send" if this is first iteration */
5864
 
        if (command->query == command->query_buf)
5865
 
          command->query= command->first_argument;
 
5995
        if (command->query == command->query_buf)
 
5996
          command->query= command->first_argument;
5866
5997
 
5867
 
        /*
5868
 
          run_query() can execute a query partially, depending on the flags.
5869
 
          QUERY_SEND_FLAG flag without QUERY_REAP_FLAG tells it to just send
 
5998
        /*
 
5999
          run_query() can execute a query partially, depending on the flags.
 
6000
          QUERY_SEND_FLAG flag without QUERY_REAP_FLAG tells it to just send
5870
6001
          the query and read the result some time later when reap instruction
5871
 
          is given on this connection.
 
6002
          is given on this connection.
5872
6003
        */
5873
 
        run_query(cur_con, command, QUERY_SEND_FLAG);
5874
 
        command_executed++;
 
6004
        run_query(cur_con, command, QUERY_SEND_FLAG);
 
6005
        command_executed++;
5875
6006
        command->last_argument= command->end;
5876
 
        break;
 
6007
        break;
5877
6008
      case Q_REQUIRE:
5878
 
        do_get_file_name(command, save_file);
5879
 
        break;
 
6009
        do_get_file_name(command, save_file, sizeof(save_file));
 
6010
        break;
5880
6011
      case Q_ERROR:
5881
6012
        do_get_errcodes(command);
5882
 
        break;
 
6013
        break;
5883
6014
      case Q_REPLACE:
5884
 
        do_get_replace(command);
5885
 
        break;
 
6015
        do_get_replace(command);
 
6016
        break;
5886
6017
      case Q_REPLACE_REGEX:
5887
6018
        do_get_replace_regex(command);
5888
6019
        break;
5889
6020
      case Q_REPLACE_COLUMN:
5890
 
        do_get_replace_column(command);
5891
 
        break;
 
6021
        do_get_replace_column(command);
 
6022
        break;
5892
6023
      case Q_SAVE_MASTER_POS: do_save_master_pos(); break;
5893
6024
      case Q_SYNC_WITH_MASTER: do_sync_with_master(command); break;
5894
6025
      case Q_SYNC_SLAVE_WITH_MASTER:
5895
6026
      {
5896
 
        do_save_master_pos();
5897
 
        if (*command->first_argument)
5898
 
          select_connection(command);
5899
 
        else
5900
 
          select_connection_name("slave");
5901
 
        do_sync_with_master2(0);
5902
 
        break;
 
6027
        do_save_master_pos();
 
6028
        if (*command->first_argument)
 
6029
          select_connection(command);
 
6030
        else
 
6031
          select_connection_name("slave");
 
6032
        do_sync_with_master2(0);
 
6033
        break;
5903
6034
      }
5904
 
      case Q_COMMENT:        /* Ignore row */
 
6035
      case Q_COMMENT:                           /* Ignore row */
5905
6036
        command->last_argument= command->end;
5906
 
        break;
 
6037
        break;
5907
6038
      case Q_PING:
5908
 
        {
5909
 
          drizzle_result_st result;
5910
 
          drizzle_return_t ret;
5911
 
          (void) drizzle_ping(&cur_con->con, &result, &ret);
5912
 
          if (ret == DRIZZLE_RETURN_OK || ret == DRIZZLE_RETURN_ERROR_CODE)
5913
 
            drizzle_result_free(&result);
5914
 
        }
5915
 
        break;
 
6039
        (void) mysql_ping(&cur_con->mysql);
 
6040
        break;
5916
6041
      case Q_EXEC:
5917
 
        do_exec(command);
5918
 
        command_executed++;
5919
 
        break;
 
6042
        do_exec(command);
 
6043
        command_executed++;
 
6044
        break;
5920
6045
      case Q_START_TIMER:
5921
 
        /* Overwrite possible earlier start of timer */
5922
 
        timer_start= timer_now();
5923
 
        break;
 
6046
        /* Overwrite possible earlier start of timer */
 
6047
        timer_start= timer_now();
 
6048
        break;
5924
6049
      case Q_END_TIMER:
5925
 
        /* End timer before ending drizzletest */
5926
 
        timer_output();
5927
 
        break;
 
6050
        /* End timer before ending mysqltest */
 
6051
        timer_output();
 
6052
        break;
5928
6053
      case Q_CHARACTER_SET:
5929
 
        do_set_charset(command);
5930
 
        break;
 
6054
        do_set_charset(command);
 
6055
        break;
5931
6056
      case Q_DISABLE_RECONNECT:
5932
 
        set_reconnect(&cur_con->con, 0);
 
6057
        set_reconnect(&cur_con->mysql, 0);
5933
6058
        break;
5934
6059
      case Q_ENABLE_RECONNECT:
5935
 
        set_reconnect(&cur_con->con, 1);
 
6060
        set_reconnect(&cur_con->mysql, 1);
5936
6061
        break;
5937
6062
      case Q_DISABLE_PARSING:
5938
6063
        if (parsing_disabled == 0)
6004
6129
      free_all_replace();
6005
6130
 
6006
6131
      /* Also reset "sorted_result" */
6007
 
      display_result_sorted= false;
 
6132
      display_result_sorted= FALSE;
6008
6133
    }
6009
6134
    last_command_executed= command_executed;
6010
6135
 
6023
6148
    Time to compare result or save it to record file.
6024
6149
    The entire output from test is now kept in ds_res.
6025
6150
  */
6026
 
  if (ds_res.length())
 
6151
  if (ds_res.length)
6027
6152
  {
6028
 
    if (! result_file_name.empty())
 
6153
    if (result_file_name)
6029
6154
    {
6030
6155
      /* A result file has been specified */
6031
6156
 
6032
6157
      if (record)
6033
6158
      {
6034
 
        /* Recording - dump the output from test to result file */
6035
 
        str_to_file(result_file_name.c_str(), ds_res.c_str(), ds_res.length());
 
6159
        /* Recording - dump the output from test to result file */
 
6160
        str_to_file(result_file_name, ds_res.str, ds_res.length);
6036
6161
      }
6037
6162
      else
6038
6163
      {
6039
 
        /* Check that the output from test is equal to result file
6040
 
           - detect missing result file
6041
 
           - detect zero size result file
 
6164
        /* Check that the output from test is equal to result file
 
6165
           - detect missing result file
 
6166
           - detect zero size result file
6042
6167
        */
6043
 
        check_result(&ds_res);
 
6168
        check_result(&ds_res);
6044
6169
      }
6045
6170
    }
6046
6171
    else
6047
6172
    {
6048
6173
      /* No result_file_name specified to compare with, print to stdout */
6049
 
      printf("%s", ds_res.c_str());
 
6174
      printf("%s", ds_res.str);
6050
6175
    }
6051
6176
  }
6052
6177
  else
6055
6180
  }
6056
6181
 
6057
6182
  if (!command_executed &&
6058
 
      ! result_file_name.empty() && !stat(result_file_name.c_str(), &res_info))
 
6183
      result_file_name && !stat(result_file_name, &res_info))
6059
6184
  {
6060
6185
    /*
6061
6186
      my_stat() successful on result file. Check if we have not run a
6067
6192
    die("No queries executed but result file found!");
6068
6193
  }
6069
6194
 
6070
 
  if ( opt_mark_progress && ! result_file_name.empty() )
 
6195
  if ( opt_mark_progress && result_file_name )
6071
6196
    dump_progress();
6072
6197
 
6073
6198
  /* Dump warning messages */
6074
 
  if (! result_file_name.empty() && ds_warning_messages.length())
 
6199
  if (result_file_name && ds_warning_messages.length)
6075
6200
    dump_warning_messages();
6076
6201
 
6077
6202
  timer_output();
6078
6203
  /* Yes, if we got this far the test has suceeded! Sakila smiles */
6079
6204
  cleanup_and_exit(0);
6080
 
}
6081
 
 
6082
 
  catch(exception &err)
6083
 
  {
6084
 
    cerr<<err.what()<<endl;
6085
 
  }
6086
 
 
6087
6205
  return 0; /* Keep compiler happy too */
6088
6206
}
6089
6207
 
6096
6214
  before executing any commands. The time we measure is
6097
6215
 
6098
6216
  - If no explicit 'start_timer' or 'end_timer' is given in the
6099
 
  test case, the timer measure how long we execute in drizzletest.
 
6217
  test case, the timer measure how long we execute in mysqltest.
6100
6218
 
6101
6219
  - If only 'start_timer' is given we measure how long we execute
6102
 
  from that point until we terminate drizzletest.
 
6220
  from that point until we terminate mysqltest.
6103
6221
 
6104
6222
  - If only 'end_timer' is given we measure how long we execute
6105
 
  from that we enter drizzletest to the 'end_timer' is command is
 
6223
  from that we enter mysqltest to the 'end_timer' is command is
6106
6224
  executed.
6107
6225
 
6108
6226
  - If both 'start_timer' and 'end_timer' are given we measure
6109
6227
  the time between executing the two commands.
6110
6228
*/
6111
6229
 
6112
 
void timer_output()
 
6230
void timer_output(void)
6113
6231
{
6114
6232
  if (timer_file)
6115
6233
  {
6116
 
    ostringstream buf;
 
6234
    char buf[32], *end;
6117
6235
    uint64_t timer= timer_now() - timer_start;
6118
 
    buf << timer;
6119
 
    str_to_file(timer_file,buf.str().c_str(), buf.str().size() );
 
6236
    end= int64_t2str(timer, buf, 10);
 
6237
    str_to_file(timer_file,buf, (int) (end-buf));
6120
6238
    /* Timer has been written to the file, don't use it anymore */
6121
6239
    timer_file= 0;
6122
6240
  }
6123
6241
}
6124
6242
 
6125
6243
 
6126
 
uint64_t timer_now()
 
6244
uint64_t timer_now(void)
6127
6245
{
6128
 
#if defined(HAVE_GETHRTIME)
6129
 
  return gethrtime()/1000/1000;
6130
 
#else
6131
 
  uint64_t newtime;
6132
 
  struct timeval t;
6133
 
  /*
6134
 
    The following loop is here because gettimeofday may fail on some systems
6135
 
  */
6136
 
  while (gettimeofday(&t, NULL) != 0)
6137
 
  {}
6138
 
  newtime= (uint64_t)t.tv_sec * 1000000 + t.tv_usec;
6139
 
  return newtime/1000;
6140
 
#endif  /* defined(HAVE_GETHRTIME) */
 
6246
  return my_micro_time() / 1000;
6141
6247
}
6142
6248
 
6143
6249
 
6160
6266
    die("Missing argument in %s", command->query);
6161
6267
 
6162
6268
  /* Allocate a buffer for results */
6163
 
  start= buff= (char *)malloc(strlen(from)+1);
 
6269
  start= buff= (char *)my_malloc(strlen(from)+1,MYF(MY_WME | MY_FAE));
6164
6270
  while (*from)
6165
6271
  {
6166
 
    uint32_t column_number;
 
6272
    char *to;
 
6273
    uint column_number;
6167
6274
 
6168
 
    char *to= get_string(&buff, &from, command);
 
6275
    to= get_string(&buff, &from, command);
6169
6276
    if (!(column_number= atoi(to)) || column_number > MAX_COLUMNS)
6170
6277
      die("Wrong column number to replace_column in '%s'", command->query);
6171
6278
    if (!*from)
6172
6279
      die("Wrong number of arguments to replace_column in '%s'", command->query);
6173
6280
    to= get_string(&buff, &from, command);
6174
 
    free(replace_column[column_number-1]);
6175
 
    replace_column[column_number-1]= strdup(to);
6176
 
    if (replace_column[column_number-1] == NULL)
6177
 
      die("Out of memory");
 
6281
    my_free(replace_column[column_number-1], MY_ALLOW_ZERO_PTR);
 
6282
    replace_column[column_number-1]= my_strdup(to, MYF(MY_WME | MY_FAE));
6178
6283
    set_if_bigger(max_replace_column, column_number);
6179
6284
  }
6180
 
  free(start);
 
6285
  my_free(start, MYF(0));
6181
6286
  command->last_argument= command->end;
6182
6287
}
6183
6288
 
6184
6289
 
6185
6290
void free_replace_column()
6186
6291
{
6187
 
  for (uint32_t i= 0 ; i < max_replace_column; i++)
 
6292
  uint i;
 
6293
  for (i=0 ; i < max_replace_column ; i++)
6188
6294
  {
6189
 
    free(replace_column[i]);
6190
 
    replace_column[i]= 0;
 
6295
    if (replace_column[i])
 
6296
    {
 
6297
      my_free(replace_column[i], 0);
 
6298
      replace_column[i]= 0;
 
6299
    }
6191
6300
  }
6192
6301
  max_replace_column= 0;
6193
6302
}
6200
6309
 
6201
6310
/* Definitions for replace result */
6202
6311
 
6203
 
typedef struct st_pointer_array {    /* when using array-strings */
6204
 
  TYPELIB typelib;        /* Pointer to strings */
6205
 
  unsigned char  *str;          /* Strings is here */
6206
 
  uint8_t *flag;          /* Flag about each var. */
6207
 
  uint32_t  array_allocs,max_count,length,max_length;
 
6312
typedef struct st_pointer_array {               /* when using array-strings */
 
6313
  TYPELIB typelib;                              /* Pointer to strings */
 
6314
  uchar *str;                                   /* Strings is here */
 
6315
  int7  *flag;                                  /* Flag about each var. */
 
6316
  uint  array_allocs,max_count,length,max_length;
6208
6317
} POINTER_ARRAY;
6209
6318
 
6210
6319
struct st_replace;
6211
 
struct st_replace *init_replace(const char **from, const char **to, uint32_t count,
6212
 
                                char *word_end_chars);
 
6320
struct st_replace *init_replace(char * *from, char * *to, uint count,
 
6321
                                char * word_end_chars);
6213
6322
int insert_pointer_name(POINTER_ARRAY *pa,char * name);
6214
 
void replace_strings_append(struct st_replace *rep, string* ds,
 
6323
void replace_strings_append(struct st_replace *rep, DYNAMIC_STRING* ds,
6215
6324
                            const char *from, int len);
 
6325
void free_pointer_array(POINTER_ARRAY *pa);
6216
6326
 
6217
 
st_replace *glob_replace= NULL;
6218
 
// boost::scoped_ptr<st_replace> glob_replace;
 
6327
struct st_replace *glob_replace;
6219
6328
 
6220
6329
/*
6221
6330
  Get arguments for replace. The syntax is:
6225
6334
  variable is replaced.
6226
6335
*/
6227
6336
 
6228
 
static void free_pointer_array(POINTER_ARRAY *pa)
6229
 
{
6230
 
  if (!pa->typelib.count)
6231
 
    return;
6232
 
  pa->typelib.count=0;
6233
 
  free((char*) pa->typelib.type_names);
6234
 
  pa->typelib.type_names=0;
6235
 
  free(pa->str);
6236
 
}
6237
 
 
6238
6337
void do_get_replace(struct st_command *command)
6239
6338
{
6240
 
  uint32_t i;
 
6339
  uint i;
6241
6340
  char *from= command->first_argument;
6242
6341
  char *buff, *start;
6243
6342
  char word_end_chars[256], *pos;
6246
6345
 
6247
6346
  free_replace();
6248
6347
 
6249
 
  memset(&to_array, 0, sizeof(to_array));
6250
 
  memset(&from_array, 0, sizeof(from_array));
 
6348
  bzero((char*) &to_array,sizeof(to_array));
 
6349
  bzero((char*) &from_array,sizeof(from_array));
6251
6350
  if (!*from)
6252
6351
    die("Missing argument in %s", command->query);
6253
 
  start= buff= (char *)malloc(strlen(from)+1);
 
6352
  start= buff= (char *)my_malloc(strlen(from)+1,MYF(MY_WME | MY_FAE));
6254
6353
  while (*from)
6255
6354
  {
6256
6355
    char *to= buff;
6265
6364
  for (i= 1,pos= word_end_chars ; i < 256 ; i++)
6266
6365
    if (my_isspace(charset_info,i))
6267
6366
      *pos++= i;
6268
 
  *pos=0;          /* End pointer */
6269
 
  if (!(glob_replace= init_replace(from_array.typelib.type_names,
6270
 
                                   to_array.typelib.type_names,
6271
 
                                   from_array.typelib.count,
6272
 
                                   word_end_chars)))
 
6367
  *pos=0;                                       /* End pointer */
 
6368
  if (!(glob_replace= init_replace((char**) from_array.typelib.type_names,
 
6369
                                  (char**) to_array.typelib.type_names,
 
6370
                                  (uint) from_array.typelib.count,
 
6371
                                  word_end_chars)))
6273
6372
    die("Can't initialize replace from '%s'", command->query);
6274
6373
  free_pointer_array(&from_array);
6275
6374
  free_pointer_array(&to_array);
6276
 
  free(start);
 
6375
  my_free(start, MYF(0));
6277
6376
  command->last_argument= command->end;
6278
6377
  return;
6279
6378
}
6281
6380
 
6282
6381
void free_replace()
6283
6382
{
6284
 
  free(glob_replace);
6285
 
  glob_replace=0;
 
6383
 
 
6384
  if (glob_replace)
 
6385
  {
 
6386
    my_free(glob_replace,MYF(0));
 
6387
    glob_replace=0;
 
6388
  }
 
6389
  return;
6286
6390
}
6287
6391
 
6288
6392
 
6294
6398
typedef struct st_replace_found {
6295
6399
  bool found;
6296
6400
  char *replace_string;
6297
 
  uint32_t to_offset;
 
6401
  uint to_offset;
6298
6402
  int from_offset;
6299
6403
} REPLACE_STRING;
6300
6404
 
6301
6405
 
6302
 
void replace_strings_append(REPLACE *rep, string* ds,
6303
 
                            const char *str, int len)
 
6406
void replace_strings_append(REPLACE *rep, DYNAMIC_STRING* ds,
 
6407
                            const char *str,
 
6408
                            int len __attribute__((unused)))
6304
6409
{
6305
 
  REPLACE *rep_pos;
6306
 
  REPLACE_STRING *rep_str;
 
6410
  register REPLACE *rep_pos;
 
6411
  register REPLACE_STRING *rep_str;
6307
6412
  const char *start, *from;
6308
6413
 
6309
6414
 
6313
6418
  {
6314
6419
    /* Loop through states */
6315
6420
    while (!rep_pos->found)
6316
 
      rep_pos= rep_pos->next[(unsigned char) *from++];
 
6421
      rep_pos= rep_pos->next[(uchar) *from++];
6317
6422
 
6318
6423
    /* Does this state contain a string to be replaced */
6319
6424
    if (!(rep_str = ((REPLACE_STRING*) rep_pos))->replace_string)
6320
6425
    {
6321
6426
      /* No match found */
6322
 
      ds->append(start, from - start - 1);
 
6427
      dynstr_append_mem(ds, start, from - start - 1);
6323
6428
      return;
6324
6429
    }
6325
6430
 
6326
6431
    /* Append part of original string before replace string */
6327
 
    ds->append(start, (from - rep_str->to_offset) - start);
 
6432
    dynstr_append_mem(ds, start, (from - rep_str->to_offset) - start);
6328
6433
 
6329
6434
    /* Append replace string */
6330
 
    ds->append(rep_str->replace_string,
6331
 
               strlen(rep_str->replace_string));
 
6435
    dynstr_append_mem(ds, rep_str->replace_string,
 
6436
                      strlen(rep_str->replace_string));
6332
6437
 
6333
6438
    if (!*(from-=rep_str->from_offset) && rep_pos->found != 2)
6334
6439
      return;
6352
6457
  char* pattern; /* Pattern to be replaced */
6353
6458
  char* replace; /* String or expression to replace the pattern with */
6354
6459
  int icase; /* true if the match is case insensitive */
6355
 
  int global; /* true if the match should be global -- 
6356
 
                 i.e. repeat the matching until the end of the string */
6357
6460
};
6358
6461
 
6359
 
class st_replace_regex
 
6462
struct st_replace_regex
6360
6463
{
6361
 
public:
6362
 
  st_replace_regex(char* expr);
6363
 
  int multi_reg_replace(char* val);
 
6464
  DYNAMIC_ARRAY regex_arr; /* stores a list of st_regex subsitutions */
6364
6465
 
6365
6466
  /*
6366
6467
    Temporary storage areas for substitutions. To reduce unnessary copying
6369
6470
    st_regex substition. At the end of substitutions  buf points to the
6370
6471
    one containing the final result.
6371
6472
  */
6372
 
  typedef vector<st_regex> regex_arr_t;
6373
 
 
6374
 
  char* buf_;
 
6473
  char* buf;
6375
6474
  char* even_buf;
6376
6475
  char* odd_buf;
6377
6476
  int even_buf_len;
6378
6477
  int odd_buf_len;
6379
 
  boost::array<char, 8 << 10> buf0_;
6380
 
  boost::array<char, 8 << 10> buf1_;
6381
 
  regex_arr_t regex_arr;
6382
6478
};
6383
6479
 
6384
 
boost::scoped_ptr<st_replace_regex> glob_replace_regex;
 
6480
struct st_replace_regex *glob_replace_regex= 0;
6385
6481
 
6386
6482
int reg_replace(char** buf_p, int* buf_len_p, char *pattern, char *replace,
6387
 
                char *string, int icase, int global);
 
6483
                char *string, int icase);
6388
6484
 
6389
6485
 
6390
6486
 
6423
6519
  Returns: st_replace_regex struct with pairs of substitutions
6424
6520
*/
6425
6521
 
6426
 
st_replace_regex::st_replace_regex(char* expr)
 
6522
static struct st_replace_regex* init_replace_regex(char* expr)
6427
6523
{
6428
 
  uint32_t expr_len= strlen(expr);
 
6524
  struct st_replace_regex* res;
 
6525
  char* buf,*expr_end;
 
6526
  char* p;
 
6527
  char* buf_p;
 
6528
  uint expr_len= strlen(expr);
6429
6529
  char last_c = 0;
6430
 
  st_regex reg;
6431
 
 
6432
 
  char* buf= new char[expr_len];
6433
 
  char* expr_end= expr + expr_len;
6434
 
  char* p= expr;
6435
 
  char* buf_p= buf;
 
6530
  struct st_regex reg;
 
6531
 
 
6532
  /* my_malloc() will die on fail with MY_FAE */
 
6533
  res=(struct st_replace_regex*)my_malloc(
 
6534
                                          sizeof(*res)+expr_len ,MYF(MY_FAE+MY_WME));
 
6535
  my_init_dynamic_array(&res->regex_arr,sizeof(struct st_regex),128,128);
 
6536
 
 
6537
  buf= (char*)res + sizeof(*res);
 
6538
  expr_end= expr + expr_len;
 
6539
  p= expr;
 
6540
  buf_p= buf;
6436
6541
 
6437
6542
  /* for each regexp substitution statement */
6438
6543
  while (p < expr_end)
6439
6544
  {
6440
 
    memset(&reg, 0, sizeof(reg));
 
6545
    bzero(&reg,sizeof(reg));
6441
6546
    /* find the start of the statement */
6442
6547
    while (p < expr_end)
6443
6548
    {
6448
6553
 
6449
6554
    if (p == expr_end || ++p == expr_end)
6450
6555
    {
6451
 
      if (!regex_arr.empty())
 
6556
      if (res->regex_arr.elements)
6452
6557
        break;
6453
6558
      else
6454
6559
        goto err;
6476
6581
 
6477
6582
    /* Check if we should do matching case insensitive */
6478
6583
    if (p < expr_end && *p == 'i')
6479
 
    {
6480
 
      p++;
6481
6584
      reg.icase= 1;
6482
 
    }
6483
6585
 
6484
 
    /* Check if we should do matching globally */
6485
 
    if (p < expr_end && *p == 'g')
6486
 
    {
6487
 
      p++;
6488
 
      reg.global= 1;
6489
 
    }
6490
 
    regex_arr.push_back(reg);
 
6586
    /* done parsing the statement, now place it in regex_arr */
 
6587
    if (insert_dynamic(&res->regex_arr,(uchar*) &reg))
 
6588
      die("Out of memory");
6491
6589
  }
6492
 
  odd_buf_len= even_buf_len= buf0_.size();
6493
 
  even_buf= buf0_.data();
6494
 
  odd_buf= buf1_.data();
6495
 
  buf_= even_buf;
 
6590
  res->odd_buf_len= res->even_buf_len= 8192;
 
6591
  res->even_buf= (char*)my_malloc(res->even_buf_len,MYF(MY_WME+MY_FAE));
 
6592
  res->odd_buf= (char*)my_malloc(res->odd_buf_len,MYF(MY_WME+MY_FAE));
 
6593
  res->buf= res->even_buf;
6496
6594
 
6497
 
  return;
 
6595
  return res;
6498
6596
 
6499
6597
err:
 
6598
  my_free(res,0);
6500
6599
  die("Error parsing replace_regex \"%s\"", expr);
 
6600
  return 0;
6501
6601
}
6502
6602
 
6503
6603
/*
6519
6619
  in one pass
6520
6620
*/
6521
6621
 
6522
 
int st_replace_regex::multi_reg_replace(char* val)
 
6622
static int multi_reg_replace(struct st_replace_regex* r,char* val)
6523
6623
{
6524
 
  char* in_buf= val;
6525
 
  char* out_buf= even_buf;
6526
 
  int* buf_len_p= &even_buf_len;
6527
 
  buf_= 0;
 
6624
  uint i;
 
6625
  char* in_buf, *out_buf;
 
6626
  int* buf_len_p;
 
6627
 
 
6628
  in_buf= val;
 
6629
  out_buf= r->even_buf;
 
6630
  buf_len_p= &r->even_buf_len;
 
6631
  r->buf= 0;
6528
6632
 
6529
6633
  /* For each substitution, do the replace */
6530
 
  BOOST_FOREACH(regex_arr_t::const_reference i, regex_arr)
 
6634
  for (i= 0; i < r->regex_arr.elements; i++)
6531
6635
  {
 
6636
    struct st_regex re;
6532
6637
    char* save_out_buf= out_buf;
6533
 
    if (!reg_replace(&out_buf, buf_len_p, i.pattern, i.replace,
6534
 
                     in_buf, i.icase, i.global))
 
6638
 
 
6639
    get_dynamic(&r->regex_arr,(uchar*)&re,i);
 
6640
 
 
6641
    if (!reg_replace(&out_buf, buf_len_p, re.pattern, re.replace,
 
6642
                     in_buf, re.icase))
6535
6643
    {
6536
6644
      /* if the buffer has been reallocated, make adjustements */
6537
6645
      if (save_out_buf != out_buf)
6538
6646
      {
6539
 
        if (save_out_buf == even_buf)
6540
 
          even_buf= out_buf;
 
6647
        if (save_out_buf == r->even_buf)
 
6648
          r->even_buf= out_buf;
6541
6649
        else
6542
 
          odd_buf= out_buf;
 
6650
          r->odd_buf= out_buf;
6543
6651
      }
6544
 
      buf_= out_buf;
 
6652
 
 
6653
      r->buf= out_buf;
6545
6654
      if (in_buf == val)
6546
 
        in_buf= odd_buf;
6547
 
      std::swap(in_buf, out_buf);
6548
 
      buf_len_p= (out_buf == even_buf) ? &even_buf_len : &odd_buf_len;
 
6655
        in_buf= r->odd_buf;
 
6656
 
 
6657
      swap_variables(char*,in_buf,out_buf);
 
6658
 
 
6659
      buf_len_p= (out_buf == r->even_buf) ? &r->even_buf_len :
 
6660
        &r->odd_buf_len;
6549
6661
    }
6550
6662
  }
6551
 
  return buf_ == 0;
 
6663
 
 
6664
  return (r->buf == 0);
6552
6665
}
6553
6666
 
6554
6667
/*
6563
6676
void do_get_replace_regex(struct st_command *command)
6564
6677
{
6565
6678
  char *expr= command->first_argument;
6566
 
  glob_replace_regex.reset(new st_replace_regex(expr));
 
6679
  free_replace_regex();
 
6680
  if (!(glob_replace_regex=init_replace_regex(expr)))
 
6681
    die("Could not init replace_regex");
6567
6682
  command->last_argument= command->end;
6568
6683
}
6569
6684
 
 
6685
void free_replace_regex()
 
6686
{
 
6687
  if (glob_replace_regex)
 
6688
  {
 
6689
    delete_dynamic(&glob_replace_regex->regex_arr);
 
6690
    my_free(glob_replace_regex->even_buf,MYF(MY_ALLOW_ZERO_PTR));
 
6691
    my_free(glob_replace_regex->odd_buf,MYF(MY_ALLOW_ZERO_PTR));
 
6692
    my_free(glob_replace_regex,MYF(0));
 
6693
    glob_replace_regex=0;
 
6694
  }
 
6695
}
 
6696
 
 
6697
 
 
6698
 
 
6699
/*
 
6700
  auxiluary macro used by reg_replace
 
6701
  makes sure the result buffer has sufficient length
 
6702
*/
 
6703
#define SECURE_REG_BUF   if (buf_len < need_buf_len)                    \
 
6704
  {                                                                     \
 
6705
    int off= res_p - buf;                                               \
 
6706
    buf= (char*)my_realloc(buf,need_buf_len,MYF(MY_WME+MY_FAE));        \
 
6707
    res_p= buf + off;                                                   \
 
6708
    buf_len= need_buf_len;                                              \
 
6709
  }                                                                     \
 
6710
                                                                        \
6570
6711
/*
6571
6712
  Performs a regex substitution
6572
6713
 
6580
6721
  icase - flag, if set to 1 the match is case insensitive
6581
6722
*/
6582
6723
int reg_replace(char** buf_p, int* buf_len_p, char *pattern,
6583
 
                char *replace, char *in_string, int icase, int global)
 
6724
                char *replace, char *in_string, int icase)
6584
6725
{
6585
 
  const char *error= NULL;
6586
 
  int erroffset;
6587
 
  int ovector[3];
6588
 
  pcre *re= pcre_compile(pattern,
6589
 
                         icase ? PCRE_CASELESS | PCRE_MULTILINE : PCRE_MULTILINE,
6590
 
                         &error, &erroffset, NULL);
6591
 
  if (re == NULL)
6592
 
    return 1;
6593
 
 
6594
 
  if (! global)
6595
 
  {
6596
 
 
6597
 
    int rc= pcre_exec(re, NULL, in_string, (int)strlen(in_string),
6598
 
                      0, 0, ovector, 3);
6599
 
    if (rc < 0)
6600
 
    {
6601
 
      pcre_free(re);
6602
 
      return 1;
6603
 
    }
6604
 
 
6605
 
    char *substring_to_replace= in_string + ovector[0];
6606
 
    int substring_length= ovector[1] - ovector[0];
6607
 
    *buf_len_p= strlen(in_string) - substring_length + strlen(replace);
6608
 
    char * new_buf = (char *)malloc(*buf_len_p+1);
6609
 
    if (new_buf == NULL)
6610
 
    {
6611
 
      pcre_free(re);
6612
 
      return 1;
6613
 
    }
6614
 
 
6615
 
    memset(new_buf, 0, *buf_len_p+1);
6616
 
    strncpy(new_buf, in_string, substring_to_replace-in_string);
6617
 
    strncpy(new_buf+(substring_to_replace-in_string), replace, strlen(replace));
6618
 
    strncpy(new_buf+(substring_to_replace-in_string)+strlen(replace),
6619
 
            substring_to_replace + substring_length,
6620
 
            strlen(in_string)
6621
 
              - substring_length
6622
 
              - (substring_to_replace-in_string));
6623
 
    *buf_p= new_buf;
6624
 
 
6625
 
    pcre_free(re);
6626
 
    return 0;
6627
 
  }
6628
 
  else
6629
 
  {
6630
 
    /* Repeatedly replace the string with the matched regex */
6631
 
    string subject(in_string);
6632
 
    size_t replace_length= strlen(replace);
6633
 
    size_t length_of_replacement= strlen(replace);
6634
 
    size_t current_position= 0;
6635
 
    int rc= 0;
6636
 
 
6637
 
    while (true) 
6638
 
    {
6639
 
      rc= pcre_exec(re, NULL, subject.c_str(), subject.length(), 
6640
 
                    current_position, 0, ovector, 3);
6641
 
      if (rc < 0)
6642
 
      {
6643
 
        break;
6644
 
      }
6645
 
 
6646
 
      current_position= static_cast<size_t>(ovector[0]);
6647
 
      replace_length= static_cast<size_t>(ovector[1] - ovector[0]);
6648
 
      subject.replace(current_position, replace_length, replace, length_of_replacement);
6649
 
      current_position= current_position + length_of_replacement;
6650
 
    }
6651
 
 
6652
 
    char *new_buf = (char *) malloc(subject.length() + 1);
6653
 
    if (new_buf == NULL)
6654
 
    {
6655
 
      pcre_free(re);
6656
 
      return 1;
6657
 
    }
6658
 
    memset(new_buf, 0, subject.length() + 1);
6659
 
    strncpy(new_buf, subject.c_str(), subject.length());
6660
 
    *buf_len_p= subject.length() + 1;
6661
 
    *buf_p= new_buf;
6662
 
          
6663
 
    pcre_free(re);
6664
 
    return 0;
6665
 
  }
 
6726
  string string_to_match(in_string);
 
6727
  pcrecpp::RE_Options opt;
 
6728
 
 
6729
  if (icase)
 
6730
    opt.set_caseless(true);
 
6731
 
 
6732
  if (!pcrecpp::RE(pattern, opt).Replace(replace,&string_to_match)){
 
6733
    return 1;
 
6734
  }
 
6735
 
 
6736
  const char * new_str= string_to_match.c_str();
 
6737
  *buf_len_p= strlen(new_str);
 
6738
  char * new_buf = (char *)malloc(*buf_len_p+1);
 
6739
  if (new_buf == NULL)
 
6740
  {
 
6741
    return 1;
 
6742
  }
 
6743
  strcpy(new_buf, new_str);
 
6744
  buf_p= &new_buf;
 
6745
 
 
6746
  return 0;
6666
6747
}
6667
6748
 
6668
6749
 
6669
6750
#ifndef WORD_BIT
6670
 
#define WORD_BIT (8*sizeof(uint32_t))
 
6751
#define WORD_BIT (8*sizeof(uint))
6671
6752
#endif
6672
6753
 
6673
6754
#define SET_MALLOC_HUNC 64
6674
6755
#define LAST_CHAR_CODE 259
6675
6756
 
6676
 
class REP_SET
6677
 
{
6678
 
public:
6679
 
  void internal_set_bit(uint32_t bit);
6680
 
  void internal_clear_bit(uint32_t bit);
6681
 
  void or_bits(const REP_SET *from);
6682
 
  void copy_bits(const REP_SET *from);
6683
 
  int cmp_bits(const REP_SET *set2) const;
6684
 
  int get_next_bit(uint32_t lastpos) const;
6685
 
 
6686
 
  uint32_t  *bits;        /* Pointer to used sets */
6687
 
  short next[LAST_CHAR_CODE];    /* Pointer to next sets */
6688
 
  uint32_t  found_len;      /* Best match to date */
6689
 
  int  found_offset;
6690
 
  uint32_t  table_offset;
6691
 
  uint32_t  size_of_bits;      /* For convinience */
6692
 
};
6693
 
 
6694
 
class REP_SETS
6695
 
{
6696
 
public:
6697
 
  int find_set(const REP_SET *find);
6698
 
  void free_last_set();
6699
 
  void free_sets();
6700
 
  void make_sets_invisible();
6701
 
 
6702
 
  uint32_t    count;      /* Number of sets */
6703
 
  uint32_t    extra;      /* Extra sets in buffer */
6704
 
  uint32_t    invisible;    /* Sets not shown */
6705
 
  uint32_t    size_of_bits;
6706
 
  REP_SET  *set,*set_buffer;
6707
 
  uint32_t    *bit_buffer;
6708
 
};
6709
 
 
6710
 
struct FOUND_SET 
6711
 
{
6712
 
  uint32_t table_offset;
 
6757
typedef struct st_rep_set {
 
6758
  uint  *bits;                          /* Pointer to used sets */
 
6759
  short next[LAST_CHAR_CODE];           /* Pointer to next sets */
 
6760
  uint  found_len;                      /* Best match to date */
 
6761
  int   found_offset;
 
6762
  uint  table_offset;
 
6763
  uint  size_of_bits;                   /* For convinience */
 
6764
} REP_SET;
 
6765
 
 
6766
typedef struct st_rep_sets {
 
6767
  uint          count;                  /* Number of sets */
 
6768
  uint          extra;                  /* Extra sets in buffer */
 
6769
  uint          invisible;              /* Sets not chown */
 
6770
  uint          size_of_bits;
 
6771
  REP_SET       *set,*set_buffer;
 
6772
  uint          *bit_buffer;
 
6773
} REP_SETS;
 
6774
 
 
6775
typedef struct st_found_set {
 
6776
  uint table_offset;
6713
6777
  int found_offset;
6714
 
};
 
6778
} FOUND_SET;
6715
6779
 
6716
 
struct FOLLOWS
6717
 
{
 
6780
typedef struct st_follow {
6718
6781
  int chr;
6719
 
  uint32_t table_offset;
6720
 
  uint32_t len;
6721
 
};
6722
 
 
6723
 
int init_sets(REP_SETS *sets, uint32_t states);
 
6782
  uint table_offset;
 
6783
  uint len;
 
6784
} FOLLOWS;
 
6785
 
 
6786
 
 
6787
int init_sets(REP_SETS *sets,uint states);
6724
6788
REP_SET *make_new_set(REP_SETS *sets);
6725
 
int find_found(FOUND_SET *found_set, uint32_t table_offset, int found_offset);
6726
 
 
6727
 
static uint32_t found_sets= 0;
6728
 
 
6729
 
static uint32_t replace_len(const char *str)
 
6789
void make_sets_invisible(REP_SETS *sets);
 
6790
void free_last_set(REP_SETS *sets);
 
6791
void free_sets(REP_SETS *sets);
 
6792
void internal_set_bit(REP_SET *set, uint bit);
 
6793
void internal_clear_bit(REP_SET *set, uint bit);
 
6794
void or_bits(REP_SET *to,REP_SET *from);
 
6795
void copy_bits(REP_SET *to,REP_SET *from);
 
6796
int cmp_bits(REP_SET *set1,REP_SET *set2);
 
6797
int get_next_bit(REP_SET *set,uint lastpos);
 
6798
int find_set(REP_SETS *sets,REP_SET *find);
 
6799
int find_found(FOUND_SET *found_set,uint table_offset,
 
6800
               int found_offset);
 
6801
uint start_at_word(char * pos);
 
6802
uint end_of_word(char * pos);
 
6803
 
 
6804
static uint found_sets=0;
 
6805
 
 
6806
 
 
6807
static uint replace_len(char * str)
6730
6808
{
6731
 
  uint32_t len=0;
 
6809
  uint len=0;
6732
6810
  while (*str)
6733
6811
  {
6734
6812
    if (str[0] == '\\' && str[1])
6739
6817
  return len;
6740
6818
}
6741
6819
 
6742
 
/* Return 1 if regexp starts with \b or ends with \b*/
6743
 
 
6744
 
static bool start_at_word(const char *pos)
6745
 
{
6746
 
  return ((!memcmp(pos, "\\b",2) && pos[2]) || !memcmp(pos, "\\^", 2));
6747
 
}
6748
 
 
6749
 
static bool end_of_word(const char *pos)
6750
 
{
6751
 
  const char *end= strchr(pos, '\0');
6752
 
  return (end > pos+2 && !memcmp(end-2, "\\b", 2)) || (end >= pos+2 && !memcmp(end-2, "\\$",2));
6753
 
}
6754
 
 
6755
6820
/* Init a replace structure for further calls */
6756
6821
 
6757
 
REPLACE *init_replace(const char **from, const char **to, uint32_t count, char *word_end_chars)
 
6822
REPLACE *init_replace(char * *from, char * *to,uint count,
 
6823
                      char * word_end_chars)
6758
6824
{
6759
 
  const int SPACE_CHAR= 256;
6760
 
  const int START_OF_LINE= 257;
6761
 
  const int END_OF_LINE= 258;
 
6825
  static const int SPACE_CHAR= 256;
 
6826
  static const int START_OF_LINE= 257;
 
6827
  static const int END_OF_LINE= 258;
6762
6828
 
6763
 
  uint32_t i,j,states,set_nr,len,result_len,max_length,found_end,bits_set,bit_nr;
 
6829
  uint i,j,states,set_nr,len,result_len,max_length,found_end,bits_set,bit_nr;
6764
6830
  int used_sets,chr,default_state;
6765
6831
  char used_chars[LAST_CHAR_CODE],is_word_end[256];
6766
 
  char *to_pos, **to_array;
 
6832
  char * pos, *to_pos, **to_array;
 
6833
  REP_SETS sets;
 
6834
  REP_SET *set,*start_states,*word_states,*new_set;
 
6835
  FOLLOWS *follow,*follow_ptr;
 
6836
  REPLACE *replace;
 
6837
  FOUND_SET *found_set;
 
6838
  REPLACE_STRING *rep_str;
 
6839
 
6767
6840
 
6768
6841
  /* Count number of states */
6769
6842
  for (i=result_len=max_length=0 , states=2 ; i < count ; i++)
6775
6848
      return(0);
6776
6849
    }
6777
6850
    states+=len+1;
6778
 
    result_len+=(uint32_t) strlen(to[i])+1;
 
6851
    result_len+=(uint) strlen(to[i])+1;
6779
6852
    if (len > max_length)
6780
6853
      max_length=len;
6781
6854
  }
6782
 
  memset(is_word_end, 0, sizeof(is_word_end));
 
6855
  bzero((char*) is_word_end,sizeof(is_word_end));
6783
6856
  for (i=0 ; word_end_chars[i] ; i++)
6784
 
    is_word_end[(unsigned char) word_end_chars[i]]=1;
 
6857
    is_word_end[(uchar) word_end_chars[i]]=1;
6785
6858
 
6786
 
  REP_SETS sets;
6787
 
  REP_SET *set,*start_states,*word_states,*new_set;
6788
 
  REPLACE_STRING *rep_str;
6789
 
  if (init_sets(&sets, states))
6790
 
    return 0;
 
6859
  if (init_sets(&sets,states))
 
6860
    return(0);
6791
6861
  found_sets=0;
6792
 
  vector<FOUND_SET> found_set(max_length * count);
6793
 
  make_new_set(&sets);      /* Set starting set */
6794
 
  sets.make_sets_invisible();      /* Hide previus sets */
 
6862
  if (!(found_set= (FOUND_SET*) my_malloc(sizeof(FOUND_SET)*max_length*count,
 
6863
                                          MYF(MY_WME))))
 
6864
  {
 
6865
    free_sets(&sets);
 
6866
    return(0);
 
6867
  }
 
6868
  VOID(make_new_set(&sets));                    /* Set starting set */
 
6869
  make_sets_invisible(&sets);                   /* Hide previus sets */
6795
6870
  used_sets=-1;
6796
 
  word_states=make_new_set(&sets);    /* Start of new word */
6797
 
  start_states=make_new_set(&sets);    /* This is first state */
6798
 
  vector<FOLLOWS> follow(states + 2);
6799
 
  FOLLOWS *follow_ptr= &follow[1];
 
6871
  word_states=make_new_set(&sets);              /* Start of new word */
 
6872
  start_states=make_new_set(&sets);             /* This is first state */
 
6873
  if (!(follow=(FOLLOWS*) my_malloc((states+2)*sizeof(FOLLOWS),MYF(MY_WME))))
 
6874
  {
 
6875
    free_sets(&sets);
 
6876
    my_free(found_set,MYF(0));
 
6877
    return(0);
 
6878
  }
 
6879
 
6800
6880
  /* Init follow_ptr[] */
6801
 
  for (i=0, states=1; i < count; i++)
 
6881
  for (i=0, states=1, follow_ptr=follow+1 ; i < count ; i++)
6802
6882
  {
6803
6883
    if (from[i][0] == '\\' && from[i][1] == '^')
6804
6884
    {
6805
 
      start_states->internal_set_bit(states + 1);
 
6885
      internal_set_bit(start_states,states+1);
6806
6886
      if (!from[i][2])
6807
6887
      {
6808
 
        start_states->table_offset=i;
6809
 
        start_states->found_offset=1;
 
6888
        start_states->table_offset=i;
 
6889
        start_states->found_offset=1;
6810
6890
      }
6811
6891
    }
6812
6892
    else if (from[i][0] == '\\' && from[i][1] == '$')
6813
6893
    {
6814
 
      start_states->internal_set_bit(states);
6815
 
      word_states->internal_set_bit(states);
6816
 
      if (!from[i][2] && start_states->table_offset == UINT32_MAX)
 
6894
      internal_set_bit(start_states,states);
 
6895
      internal_set_bit(word_states,states);
 
6896
      if (!from[i][2] && start_states->table_offset == (uint) ~0)
6817
6897
      {
6818
 
        start_states->table_offset=i;
6819
 
        start_states->found_offset=0;
 
6898
        start_states->table_offset=i;
 
6899
        start_states->found_offset=0;
6820
6900
      }
6821
6901
    }
6822
6902
    else
6823
6903
    {
6824
 
      word_states->internal_set_bit(states);
 
6904
      internal_set_bit(word_states,states);
6825
6905
      if (from[i][0] == '\\' && (from[i][1] == 'b' && from[i][2]))
6826
 
        start_states->internal_set_bit(states + 1);
 
6906
        internal_set_bit(start_states,states+1);
6827
6907
      else
6828
 
        start_states->internal_set_bit(states);
 
6908
        internal_set_bit(start_states,states);
6829
6909
    }
6830
 
    const char *pos;
6831
 
    for (pos= from[i], len=0; *pos ; pos++)
 
6910
    for (pos=from[i], len=0; *pos ; pos++)
6832
6911
    {
6833
6912
      if (*pos == '\\' && *(pos+1))
6834
6913
      {
6835
 
        pos++;
6836
 
        switch (*pos) {
6837
 
        case 'b':
6838
 
          follow_ptr->chr = SPACE_CHAR;
6839
 
          break;
6840
 
        case '^':
6841
 
          follow_ptr->chr = START_OF_LINE;
6842
 
          break;
6843
 
        case '$':
6844
 
          follow_ptr->chr = END_OF_LINE;
6845
 
          break;
6846
 
        case 'r':
6847
 
          follow_ptr->chr = '\r';
6848
 
          break;
6849
 
        case 't':
6850
 
          follow_ptr->chr = '\t';
6851
 
          break;
6852
 
        case 'v':
6853
 
          follow_ptr->chr = '\v';
6854
 
          break;
6855
 
        default:
6856
 
          follow_ptr->chr = (unsigned char) *pos;
6857
 
          break;
6858
 
        }
 
6914
        pos++;
 
6915
        switch (*pos) {
 
6916
        case 'b':
 
6917
          follow_ptr->chr = SPACE_CHAR;
 
6918
          break;
 
6919
        case '^':
 
6920
          follow_ptr->chr = START_OF_LINE;
 
6921
          break;
 
6922
        case '$':
 
6923
          follow_ptr->chr = END_OF_LINE;
 
6924
          break;
 
6925
        case 'r':
 
6926
          follow_ptr->chr = '\r';
 
6927
          break;
 
6928
        case 't':
 
6929
          follow_ptr->chr = '\t';
 
6930
          break;
 
6931
        case 'v':
 
6932
          follow_ptr->chr = '\v';
 
6933
          break;
 
6934
        default:
 
6935
          follow_ptr->chr = (uchar) *pos;
 
6936
          break;
 
6937
        }
6859
6938
      }
6860
6939
      else
6861
 
        follow_ptr->chr= (unsigned char) *pos;
 
6940
        follow_ptr->chr= (uchar) *pos;
6862
6941
      follow_ptr->table_offset=i;
6863
6942
      follow_ptr->len= ++len;
6864
6943
      follow_ptr++;
6867
6946
    follow_ptr->table_offset=i;
6868
6947
    follow_ptr->len=len;
6869
6948
    follow_ptr++;
6870
 
    states+=(uint32_t) len+1;
 
6949
    states+=(uint) len+1;
6871
6950
  }
6872
6951
 
6873
6952
 
6874
 
  for (set_nr=0; set_nr < sets.count ; set_nr++)
 
6953
  for (set_nr=0,pos=0 ; set_nr < sets.count ; set_nr++)
6875
6954
  {
6876
6955
    set=sets.set+set_nr;
6877
 
    default_state= 0;        /* Start from beginning */
 
6956
    default_state= 0;                           /* Start from beginning */
6878
6957
 
6879
6958
    /* If end of found-string not found or start-set with current set */
6880
6959
 
6881
 
    for (i= UINT32_MAX; (i= set->get_next_bit(i)) ;)
 
6960
    for (i= (uint) ~0; (i=get_next_bit(set,i)) ;)
6882
6961
    {
6883
 
      if (!follow[i].chr && !default_state)
6884
 
        default_state= find_found(&found_set.front(), set->table_offset, set->found_offset+1);
 
6962
      if (!follow[i].chr)
 
6963
      {
 
6964
        if (! default_state)
 
6965
          default_state= find_found(found_set,set->table_offset,
 
6966
                                    set->found_offset+1);
 
6967
      }
6885
6968
    }
6886
 
    sets.set[used_sets].copy_bits(set);    /* Save set for changes */
 
6969
    copy_bits(sets.set+used_sets,set);          /* Save set for changes */
6887
6970
    if (!default_state)
6888
 
      sets.set[used_sets].or_bits(sets.set);  /* Can restart from start */
 
6971
      or_bits(sets.set+used_sets,sets.set);     /* Can restart from start */
6889
6972
 
6890
6973
    /* Find all chars that follows current sets */
6891
 
    memset(used_chars, 0, sizeof(used_chars));
6892
 
    for (i= UINT32_MAX; (i= sets.set[used_sets].get_next_bit(i)) ;)
 
6974
    bzero((char*) used_chars,sizeof(used_chars));
 
6975
    for (i= (uint) ~0; (i=get_next_bit(sets.set+used_sets,i)) ;)
6893
6976
    {
6894
6977
      used_chars[follow[i].chr]=1;
6895
6978
      if ((follow[i].chr == SPACE_CHAR && !follow[i+1].chr &&
6896
 
           follow[i].len > 1) || follow[i].chr == END_OF_LINE)
6897
 
        used_chars[0]=1;
 
6979
           follow[i].len > 1) || follow[i].chr == END_OF_LINE)
 
6980
        used_chars[0]=1;
6898
6981
    }
6899
6982
 
6900
6983
    /* Mark word_chars used if \b is in state */
6901
6984
    if (used_chars[SPACE_CHAR])
6902
 
      for (const char *pos= word_end_chars ; *pos ; pos++)
6903
 
        used_chars[(int) (unsigned char) *pos] = 1;
 
6985
      for (pos= word_end_chars ; *pos ; pos++)
 
6986
        used_chars[(int) (uchar) *pos] = 1;
6904
6987
 
6905
6988
    /* Handle other used characters */
6906
6989
    for (chr= 0 ; chr < 256 ; chr++)
6907
6990
    {
6908
6991
      if (! used_chars[chr])
6909
 
        set->next[chr]= chr ? default_state : -1;
 
6992
        set->next[chr]= chr ? default_state : -1;
6910
6993
      else
6911
6994
      {
6912
 
        new_set=make_new_set(&sets);
6913
 
        set=sets.set+set_nr;      /* if realloc */
6914
 
        new_set->table_offset=set->table_offset;
6915
 
        new_set->found_len=set->found_len;
6916
 
        new_set->found_offset=set->found_offset+1;
6917
 
        found_end=0;
 
6995
        new_set=make_new_set(&sets);
 
6996
        set=sets.set+set_nr;                    /* if realloc */
 
6997
        new_set->table_offset=set->table_offset;
 
6998
        new_set->found_len=set->found_len;
 
6999
        new_set->found_offset=set->found_offset+1;
 
7000
        found_end=0;
6918
7001
 
6919
 
        for (i= UINT32_MAX ; (i= sets.set[used_sets].get_next_bit(i)) ; )
6920
 
        {
6921
 
          if (!follow[i].chr || follow[i].chr == chr ||
6922
 
              (follow[i].chr == SPACE_CHAR &&
6923
 
               (is_word_end[chr] ||
6924
 
                (!chr && follow[i].len > 1 && ! follow[i+1].chr))) ||
6925
 
              (follow[i].chr == END_OF_LINE && ! chr))
6926
 
          {
6927
 
            if ((! chr || (follow[i].chr && !follow[i+1].chr)) &&
6928
 
                follow[i].len > found_end)
6929
 
              found_end=follow[i].len;
6930
 
            if (chr && follow[i].chr)
6931
 
              new_set->internal_set_bit(i + 1);    /* To next set */
6932
 
            else
6933
 
              new_set->internal_set_bit(i);
6934
 
          }
6935
 
        }
6936
 
        if (found_end)
6937
 
        {
6938
 
          new_set->found_len=0;      /* Set for testing if first */
6939
 
          bits_set=0;
6940
 
          for (i= UINT32_MAX; (i= new_set->get_next_bit(i)) ;)
6941
 
          {
6942
 
            if ((follow[i].chr == SPACE_CHAR ||
6943
 
                 follow[i].chr == END_OF_LINE) && ! chr)
6944
 
              bit_nr=i+1;
6945
 
            else
6946
 
              bit_nr=i;
6947
 
            if (follow[bit_nr-1].len < found_end ||
6948
 
                (new_set->found_len &&
6949
 
                 (chr == 0 || !follow[bit_nr].chr)))
6950
 
              new_set->internal_clear_bit(i);
6951
 
            else
6952
 
            {
6953
 
              if (chr == 0 || !follow[bit_nr].chr)
6954
 
              {          /* best match  */
6955
 
                new_set->table_offset=follow[bit_nr].table_offset;
6956
 
                if (chr || (follow[i].chr == SPACE_CHAR ||
6957
 
                            follow[i].chr == END_OF_LINE))
6958
 
                  new_set->found_offset=found_end;  /* New match */
6959
 
                new_set->found_len=found_end;
6960
 
              }
6961
 
              bits_set++;
6962
 
            }
6963
 
          }
6964
 
          if (bits_set == 1)
6965
 
          {
6966
 
            set->next[chr] = find_found(&found_set.front(), new_set->table_offset, new_set->found_offset);
6967
 
            sets.free_last_set();
6968
 
          }
6969
 
          else
6970
 
            set->next[chr] = sets.find_set(new_set);
6971
 
        }
6972
 
        else
6973
 
          set->next[chr] = sets.find_set(new_set);
 
7002
        for (i= (uint) ~0 ; (i=get_next_bit(sets.set+used_sets,i)) ; )
 
7003
        {
 
7004
          if (!follow[i].chr || follow[i].chr == chr ||
 
7005
              (follow[i].chr == SPACE_CHAR &&
 
7006
               (is_word_end[chr] ||
 
7007
                (!chr && follow[i].len > 1 && ! follow[i+1].chr))) ||
 
7008
              (follow[i].chr == END_OF_LINE && ! chr))
 
7009
          {
 
7010
            if ((! chr || (follow[i].chr && !follow[i+1].chr)) &&
 
7011
                follow[i].len > found_end)
 
7012
              found_end=follow[i].len;
 
7013
            if (chr && follow[i].chr)
 
7014
              internal_set_bit(new_set,i+1);            /* To next set */
 
7015
            else
 
7016
              internal_set_bit(new_set,i);
 
7017
          }
 
7018
        }
 
7019
        if (found_end)
 
7020
        {
 
7021
          new_set->found_len=0;                 /* Set for testing if first */
 
7022
          bits_set=0;
 
7023
          for (i= (uint) ~0; (i=get_next_bit(new_set,i)) ;)
 
7024
          {
 
7025
            if ((follow[i].chr == SPACE_CHAR ||
 
7026
                 follow[i].chr == END_OF_LINE) && ! chr)
 
7027
              bit_nr=i+1;
 
7028
            else
 
7029
              bit_nr=i;
 
7030
            if (follow[bit_nr-1].len < found_end ||
 
7031
                (new_set->found_len &&
 
7032
                 (chr == 0 || !follow[bit_nr].chr)))
 
7033
              internal_clear_bit(new_set,i);
 
7034
            else
 
7035
            {
 
7036
              if (chr == 0 || !follow[bit_nr].chr)
 
7037
              {                                 /* best match  */
 
7038
                new_set->table_offset=follow[bit_nr].table_offset;
 
7039
                if (chr || (follow[i].chr == SPACE_CHAR ||
 
7040
                            follow[i].chr == END_OF_LINE))
 
7041
                  new_set->found_offset=found_end;      /* New match */
 
7042
                new_set->found_len=found_end;
 
7043
              }
 
7044
              bits_set++;
 
7045
            }
 
7046
          }
 
7047
          if (bits_set == 1)
 
7048
          {
 
7049
            set->next[chr] = find_found(found_set,
 
7050
                                        new_set->table_offset,
 
7051
                                        new_set->found_offset);
 
7052
            free_last_set(&sets);
 
7053
          }
 
7054
          else
 
7055
            set->next[chr] = find_set(&sets,new_set);
 
7056
        }
 
7057
        else
 
7058
          set->next[chr] = find_set(&sets,new_set);
6974
7059
      }
6975
7060
    }
6976
7061
  }
6977
7062
 
6978
7063
  /* Alloc replace structure for the replace-state-machine */
6979
7064
 
6980
 
  REPLACE *replace= (REPLACE*)malloc(sizeof(REPLACE) * (sets.count)
6981
 
    + sizeof(REPLACE_STRING) * (found_sets + 1) + sizeof(char*) * count + result_len);
6982
 
  if (replace)
 
7065
  if ((replace=(REPLACE*) my_malloc(sizeof(REPLACE)*(sets.count)+
 
7066
                                    sizeof(REPLACE_STRING)*(found_sets+1)+
 
7067
                                    sizeof(char *)*count+result_len,
 
7068
                                    MYF(MY_WME | MY_ZEROFILL))))
6983
7069
  {
6984
 
    memset(replace, 0, sizeof(REPLACE)*(sets.count)+
6985
 
                       sizeof(REPLACE_STRING)*(found_sets+1)+
6986
 
                       sizeof(char *)*count+result_len);
6987
7070
    rep_str=(REPLACE_STRING*) (replace+sets.count);
6988
7071
    to_array= (char **) (rep_str+found_sets+1);
6989
7072
    to_pos=(char *) (to_array+count);
6990
7073
    for (i=0 ; i < count ; i++)
6991
7074
    {
6992
7075
      to_array[i]=to_pos;
6993
 
      to_pos=strcpy(to_pos,to[i])+strlen(to[i])+1;
 
7076
      to_pos=strmov(to_pos,to[i])+1;
6994
7077
    }
6995
7078
    rep_str[0].found=1;
6996
7079
    rep_str[0].replace_string=0;
6997
7080
    for (i=1 ; i <= found_sets ; i++)
6998
7081
    {
6999
 
      const char *pos= from[found_set[i-1].table_offset];
7000
 
      rep_str[i].found= !memcmp(pos, "\\^", 3) ? 2 : 1;
7001
 
      rep_str[i].replace_string= to_array[found_set[i-1].table_offset];
7002
 
      rep_str[i].to_offset= found_set[i-1].found_offset-start_at_word(pos);
7003
 
      rep_str[i].from_offset= found_set[i-1].found_offset-replace_len(pos) + end_of_word(pos);
 
7082
      pos=from[found_set[i-1].table_offset];
 
7083
      rep_str[i].found= !bcmp((const uchar*) pos,
 
7084
                              (const uchar*) "\\^", 3) ? 2 : 1;
 
7085
      rep_str[i].replace_string=to_array[found_set[i-1].table_offset];
 
7086
      rep_str[i].to_offset=found_set[i-1].found_offset-start_at_word(pos);
 
7087
      rep_str[i].from_offset=found_set[i-1].found_offset-replace_len(pos)+
 
7088
        end_of_word(pos);
7004
7089
    }
7005
7090
    for (i=0 ; i < sets.count ; i++)
7006
7091
    {
7007
7092
      for (j=0 ; j < 256 ; j++)
7008
 
        if (sets.set[i].next[j] >= 0)
7009
 
          replace[i].next[j]=replace+sets.set[i].next[j];
7010
 
        else
7011
 
          replace[i].next[j]=(REPLACE*) (rep_str+(-sets.set[i].next[j]-1));
 
7093
        if (sets.set[i].next[j] >= 0)
 
7094
          replace[i].next[j]=replace+sets.set[i].next[j];
 
7095
        else
 
7096
          replace[i].next[j]=(REPLACE*) (rep_str+(-sets.set[i].next[j]-1));
7012
7097
    }
7013
7098
  }
7014
 
  sets.free_sets();
7015
 
  return replace;
 
7099
  my_free(follow,MYF(0));
 
7100
  free_sets(&sets);
 
7101
  my_free(found_set,MYF(0));
 
7102
  return(replace);
7016
7103
}
7017
7104
 
7018
7105
 
7019
 
int init_sets(REP_SETS *sets,uint32_t states)
 
7106
int init_sets(REP_SETS *sets,uint states)
7020
7107
{
7021
 
  memset(sets, 0, sizeof(*sets));
 
7108
  bzero((char*) sets,sizeof(*sets));
7022
7109
  sets->size_of_bits=((states+7)/8);
7023
 
  if (!(sets->set_buffer=(REP_SET*) malloc(sizeof(REP_SET)*SET_MALLOC_HUNC)))
 
7110
  if (!(sets->set_buffer=(REP_SET*) my_malloc(sizeof(REP_SET)*SET_MALLOC_HUNC,
 
7111
                                              MYF(MY_WME))))
7024
7112
    return 1;
7025
 
  if (!(sets->bit_buffer=(uint*) malloc(sizeof(uint32_t)*sets->size_of_bits*
7026
 
                                        SET_MALLOC_HUNC)))
 
7113
  if (!(sets->bit_buffer=(uint*) my_malloc(sizeof(uint)*sets->size_of_bits*
 
7114
                                           SET_MALLOC_HUNC,MYF(MY_WME))))
7027
7115
  {
7028
 
    free(sets->set);
 
7116
    my_free(sets->set,MYF(0));
7029
7117
    return 1;
7030
7118
  }
7031
7119
  return 0;
7033
7121
 
7034
7122
/* Make help sets invisible for nicer codeing */
7035
7123
 
7036
 
void REP_SETS::make_sets_invisible()
 
7124
void make_sets_invisible(REP_SETS *sets)
7037
7125
{
7038
 
  invisible= count;
7039
 
  set += count;
7040
 
  count= 0;
 
7126
  sets->invisible=sets->count;
 
7127
  sets->set+=sets->count;
 
7128
  sets->count=0;
7041
7129
}
7042
7130
 
7043
7131
REP_SET *make_new_set(REP_SETS *sets)
7044
7132
{
7045
 
  uint32_t i,count,*bit_buffer;
 
7133
  uint i,count,*bit_buffer;
7046
7134
  REP_SET *set;
7047
7135
  if (sets->extra)
7048
7136
  {
7049
7137
    sets->extra--;
7050
7138
    set=sets->set+ sets->count++;
7051
 
    memset(set->bits, 0, sizeof(uint32_t)*sets->size_of_bits);
7052
 
    memset(&set->next[0], 0, sizeof(set->next[0])*LAST_CHAR_CODE);
 
7139
    bzero((char*) set->bits,sizeof(uint)*sets->size_of_bits);
 
7140
    bzero((char*) &set->next[0],sizeof(set->next[0])*LAST_CHAR_CODE);
7053
7141
    set->found_offset=0;
7054
7142
    set->found_len=0;
7055
 
    set->table_offset= UINT32_MAX;
 
7143
    set->table_offset= (uint) ~0;
7056
7144
    set->size_of_bits=sets->size_of_bits;
7057
7145
    return set;
7058
7146
  }
7059
7147
  count=sets->count+sets->invisible+SET_MALLOC_HUNC;
7060
 
  if (!(set=(REP_SET*) realloc((unsigned char*) sets->set_buffer,
7061
 
                                  sizeof(REP_SET)*count)))
 
7148
  if (!(set=(REP_SET*) my_realloc((uchar*) sets->set_buffer,
 
7149
                                  sizeof(REP_SET)*count,
 
7150
                                  MYF(MY_WME))))
7062
7151
    return 0;
7063
7152
  sets->set_buffer=set;
7064
7153
  sets->set=set+sets->invisible;
7065
 
  if (!(bit_buffer=(uint*) realloc((unsigned char*) sets->bit_buffer,
7066
 
                                   (sizeof(uint32_t)*sets->size_of_bits)*count)))
 
7154
  if (!(bit_buffer=(uint*) my_realloc((uchar*) sets->bit_buffer,
 
7155
                                      (sizeof(uint)*sets->size_of_bits)*count,
 
7156
                                      MYF(MY_WME))))
7067
7157
    return 0;
7068
7158
  sets->bit_buffer=bit_buffer;
7069
7159
  for (i=0 ; i < count ; i++)
7075
7165
  return make_new_set(sets);
7076
7166
}
7077
7167
 
7078
 
void REP_SETS::free_last_set()
7079
 
{
7080
 
  count--;
7081
 
  extra++;
7082
 
}
7083
 
 
7084
 
void REP_SETS::free_sets()
7085
 
{
7086
 
  free(set_buffer);
7087
 
  free(bit_buffer);
7088
 
}
7089
 
 
7090
 
void REP_SET::internal_set_bit(uint32_t bit)
7091
 
{
7092
 
  bits[bit / WORD_BIT] |= 1 << (bit % WORD_BIT);
7093
 
}
7094
 
 
7095
 
void REP_SET::internal_clear_bit(uint32_t bit)
7096
 
{
7097
 
  bits[bit / WORD_BIT] &= ~ (1 << (bit % WORD_BIT));
7098
 
}
7099
 
 
7100
 
 
7101
 
void REP_SET::or_bits(const REP_SET *from)
7102
 
{
7103
 
  for (uint32_t i= 0 ; i < size_of_bits; i++)
7104
 
    bits[i]|=from->bits[i];
7105
 
}
7106
 
 
7107
 
void REP_SET::copy_bits(const REP_SET *from)
7108
 
{
7109
 
  memcpy(bits, from->bits, sizeof(uint32_t) * size_of_bits);
7110
 
}
7111
 
 
7112
 
int REP_SET::cmp_bits(const REP_SET *set2) const
7113
 
{
7114
 
  return memcmp(bits, set2->bits, sizeof(uint32_t) * size_of_bits);
7115
 
}
 
7168
void free_last_set(REP_SETS *sets)
 
7169
{
 
7170
  sets->count--;
 
7171
  sets->extra++;
 
7172
  return;
 
7173
}
 
7174
 
 
7175
void free_sets(REP_SETS *sets)
 
7176
{
 
7177
  my_free(sets->set_buffer,MYF(0));
 
7178
  my_free(sets->bit_buffer,MYF(0));
 
7179
  return;
 
7180
}
 
7181
 
 
7182
void internal_set_bit(REP_SET *set, uint bit)
 
7183
{
 
7184
  set->bits[bit / WORD_BIT] |= 1 << (bit % WORD_BIT);
 
7185
  return;
 
7186
}
 
7187
 
 
7188
void internal_clear_bit(REP_SET *set, uint bit)
 
7189
{
 
7190
  set->bits[bit / WORD_BIT] &= ~ (1 << (bit % WORD_BIT));
 
7191
  return;
 
7192
}
 
7193
 
 
7194
 
 
7195
void or_bits(REP_SET *to,REP_SET *from)
 
7196
{
 
7197
  register uint i;
 
7198
  for (i=0 ; i < to->size_of_bits ; i++)
 
7199
    to->bits[i]|=from->bits[i];
 
7200
  return;
 
7201
}
 
7202
 
 
7203
void copy_bits(REP_SET *to,REP_SET *from)
 
7204
{
 
7205
  memcpy((uchar*) to->bits,(uchar*) from->bits,
 
7206
         (size_t) (sizeof(uint) * to->size_of_bits));
 
7207
}
 
7208
 
 
7209
int cmp_bits(REP_SET *set1,REP_SET *set2)
 
7210
{
 
7211
  return bcmp((uchar*) set1->bits,(uchar*) set2->bits,
 
7212
              sizeof(uint) * set1->size_of_bits);
 
7213
}
 
7214
 
7116
7215
 
7117
7216
/* Get next set bit from set. */
7118
7217
 
7119
 
int REP_SET::get_next_bit(uint32_t lastpos) const
 
7218
int get_next_bit(REP_SET *set,uint lastpos)
7120
7219
{
7121
 
  uint32_t *start= bits + ((lastpos+1) / WORD_BIT);
7122
 
  uint32_t *end= bits + size_of_bits;
7123
 
  uint32_t bits0= start[0] & ~((1 << ((lastpos+1) % WORD_BIT)) -1);
7124
 
 
7125
 
  while (!bits0 && ++start < end)
7126
 
    bits0= start[0];
7127
 
  if (!bits0)
 
7220
  uint pos,*start,*end,bits;
 
7221
 
 
7222
  start=set->bits+ ((lastpos+1) / WORD_BIT);
 
7223
  end=set->bits + set->size_of_bits;
 
7224
  bits=start[0] & ~((1 << ((lastpos+1) % WORD_BIT)) -1);
 
7225
 
 
7226
  while (! bits && ++start < end)
 
7227
    bits=start[0];
 
7228
  if (!bits)
7128
7229
    return 0;
7129
 
  uint32_t pos= (start - bits) * WORD_BIT;
7130
 
  while (!(bits0 & 1))
 
7230
  pos=(uint) (start-set->bits)*WORD_BIT;
 
7231
  while (! (bits & 1))
7131
7232
  {
7132
 
    bits0 >>=1;
 
7233
    bits>>=1;
7133
7234
    pos++;
7134
7235
  }
7135
7236
  return pos;
7139
7240
   free given set, else put in given set in sets and return its
7140
7241
   position */
7141
7242
 
7142
 
int REP_SETS::find_set(const REP_SET *find)
 
7243
int find_set(REP_SETS *sets,REP_SET *find)
7143
7244
{
7144
 
  uint32_t i= 0;
7145
 
  for (; i < count - 1; i++)
 
7245
  uint i;
 
7246
  for (i=0 ; i < sets->count-1 ; i++)
7146
7247
  {
7147
 
    if (!set[i].cmp_bits(find))
 
7248
    if (!cmp_bits(sets->set+i,find))
7148
7249
    {
7149
 
      free_last_set();
 
7250
      free_last_set(sets);
7150
7251
      return i;
7151
7252
    }
7152
7253
  }
7153
 
  return i;        /* return new postion */
 
7254
  return i;                             /* return new postion */
7154
7255
}
7155
7256
 
7156
7257
/* find if there is a found_set with same table_offset & found_offset
7160
7261
   set->next[] == -1 is reserved for end without replaces.
7161
7262
*/
7162
7263
 
7163
 
int find_found(FOUND_SET *found_set, uint32_t table_offset, int found_offset)
 
7264
int find_found(FOUND_SET *found_set,uint table_offset, int found_offset)
7164
7265
{
7165
 
  uint32_t i= 0;
7166
 
  for (; i < found_sets; i++)
7167
 
  {
 
7266
  int i;
 
7267
  for (i=0 ; (uint) i < found_sets ; i++)
7168
7268
    if (found_set[i].table_offset == table_offset &&
7169
 
        found_set[i].found_offset == found_offset)
7170
 
      return - i - 2;
7171
 
  }
7172
 
  found_set[i].table_offset= table_offset;
7173
 
  found_set[i].found_offset= found_offset;
 
7269
        found_set[i].found_offset == found_offset)
 
7270
      return -i-2;
 
7271
  found_set[i].table_offset=table_offset;
 
7272
  found_set[i].found_offset=found_offset;
7174
7273
  found_sets++;
7175
 
  return - i - 2; // return new postion
 
7274
  return -i-2;                          /* return new postion */
 
7275
}
 
7276
 
 
7277
/* Return 1 if regexp starts with \b or ends with \b*/
 
7278
 
 
7279
uint start_at_word(char * pos)
 
7280
{
 
7281
  return (((!bcmp((const uchar*) pos, (const uchar*) "\\b",2) && pos[2]) ||
 
7282
           !bcmp((const uchar*) pos, (const uchar*) "\\^", 2)) ? 1 : 0);
 
7283
}
 
7284
 
 
7285
uint end_of_word(char * pos)
 
7286
{
 
7287
  char * end=strend(pos);
 
7288
  return ((end > pos+2 && !bcmp((const uchar*) end-2,
 
7289
                                (const uchar*) "\\b", 2)) ||
 
7290
          (end >= pos+2 && !bcmp((const uchar*) end-2,
 
7291
                                (const uchar*) "\\$",2))) ? 1 : 0;
7176
7292
}
7177
7293
 
7178
7294
/****************************************************************************
7179
7295
 * Handle replacement of strings
7180
7296
 ****************************************************************************/
7181
7297
 
7182
 
#define PC_MALLOC    256  /* Bytes for pointers */
7183
 
#define PS_MALLOC    512  /* Bytes for data */
 
7298
#define PC_MALLOC               256     /* Bytes for pointers */
 
7299
#define PS_MALLOC               512     /* Bytes for data */
7184
7300
 
7185
7301
int insert_pointer_name(POINTER_ARRAY *pa,char * name)
7186
7302
{
7187
 
  uint32_t i,length,old_count;
7188
 
  unsigned char *new_pos;
 
7303
  uint i,length,old_count;
 
7304
  uchar *new_pos;
7189
7305
  const char **new_array;
7190
7306
 
7191
7307
 
7192
7308
  if (! pa->typelib.count)
7193
7309
  {
7194
7310
    if (!(pa->typelib.type_names=(const char **)
7195
 
          malloc(((PC_MALLOC-MALLOC_OVERHEAD)/
7196
 
                     (sizeof(char *)+sizeof(*pa->flag))*
7197
 
                     (sizeof(char *)+sizeof(*pa->flag))))))
 
7311
          my_malloc(((PC_MALLOC-MALLOC_OVERHEAD)/
 
7312
                     (sizeof(char *)+sizeof(*pa->flag))*
 
7313
                     (sizeof(char *)+sizeof(*pa->flag))),MYF(MY_WME))))
7198
7314
      return(-1);
7199
 
    if (!(pa->str= (unsigned char*) malloc(PS_MALLOC-MALLOC_OVERHEAD)))
 
7315
    if (!(pa->str= (uchar*) my_malloc((uint) (PS_MALLOC-MALLOC_OVERHEAD),
 
7316
                                     MYF(MY_WME))))
7200
7317
    {
7201
 
      free((char*) pa->typelib.type_names);
 
7318
      my_free((char*) pa->typelib.type_names,MYF(0));
7202
7319
      return (-1);
7203
7320
    }
7204
 
    pa->max_count=(PC_MALLOC-MALLOC_OVERHEAD)/(sizeof(unsigned char*)+
7205
 
                                               sizeof(*pa->flag));
7206
 
    pa->flag= (uint8_t*) (pa->typelib.type_names+pa->max_count);
 
7321
    pa->max_count=(PC_MALLOC-MALLOC_OVERHEAD)/(sizeof(uchar*)+
 
7322
                                               sizeof(*pa->flag));
 
7323
    pa->flag= (int7*) (pa->typelib.type_names+pa->max_count);
7207
7324
    pa->length=0;
7208
7325
    pa->max_length=PS_MALLOC-MALLOC_OVERHEAD;
7209
7326
    pa->array_allocs=1;
7210
7327
  }
7211
 
  length=(uint32_t) strlen(name)+1;
 
7328
  length=(uint) strlen(name)+1;
7212
7329
  if (pa->length+length >= pa->max_length)
7213
7330
  {
7214
 
    if (!(new_pos= (unsigned char*)realloc((unsigned char*)pa->str,
7215
 
                                           (size_t)(pa->max_length+PS_MALLOC))))
 
7331
    if (!(new_pos= (uchar*) my_realloc((uchar*) pa->str,
 
7332
                                      (uint) (pa->max_length+PS_MALLOC),
 
7333
                                      MYF(MY_WME))))
7216
7334
      return(1);
7217
7335
    if (new_pos != pa->str)
7218
7336
    {
7219
 
      ptrdiff_t diff= PTR_BYTE_DIFF(new_pos,pa->str);
 
7337
      my_ptrdiff_t diff=PTR_BYTE_DIFF(new_pos,pa->str);
7220
7338
      for (i=0 ; i < pa->typelib.count ; i++)
7221
 
        pa->typelib.type_names[i]= ADD_TO_PTR(pa->typelib.type_names[i],diff,
7222
 
                                              char*);
 
7339
        pa->typelib.type_names[i]= ADD_TO_PTR(pa->typelib.type_names[i],diff,
 
7340
                                              char*);
7223
7341
      pa->str=new_pos;
7224
7342
    }
7225
7343
    pa->max_length+=PS_MALLOC;
7226
7344
  }
7227
7345
  if (pa->typelib.count >= pa->max_count-1)
7228
7346
  {
7229
 
    size_t len;
 
7347
    int len;
7230
7348
    pa->array_allocs++;
7231
7349
    len=(PC_MALLOC*pa->array_allocs - MALLOC_OVERHEAD);
7232
 
    if (!(new_array=
7233
 
         (const char **)realloc((unsigned char*) pa->typelib.type_names,
7234
 
                                 len/
7235
 
                                  (sizeof(unsigned char*)+sizeof(*pa->flag))*
7236
 
                                  (sizeof(unsigned char*)+sizeof(*pa->flag)))))
 
7350
    if (!(new_array=(const char **) my_realloc((uchar*) pa->typelib.type_names,
 
7351
                                               (uint) len/
 
7352
                                               (sizeof(uchar*)+sizeof(*pa->flag))*
 
7353
                                               (sizeof(uchar*)+sizeof(*pa->flag)),
 
7354
                                               MYF(MY_WME))))
7237
7355
      return(1);
7238
7356
    pa->typelib.type_names=new_array;
7239
7357
    old_count=pa->max_count;
7240
 
    pa->max_count=len/(sizeof(unsigned char*) + sizeof(*pa->flag));
7241
 
    pa->flag= (uint8_t*) (pa->typelib.type_names+pa->max_count);
7242
 
    memcpy(pa->flag, pa->typelib.type_names+old_count,
7243
 
           old_count*sizeof(*pa->flag));
 
7358
    pa->max_count=len/(sizeof(uchar*) + sizeof(*pa->flag));
 
7359
    pa->flag= (int7*) (pa->typelib.type_names+pa->max_count);
 
7360
    memcpy((uchar*) pa->flag,(char *) (pa->typelib.type_names+old_count),
 
7361
           old_count*sizeof(*pa->flag));
7244
7362
  }
7245
 
  pa->flag[pa->typelib.count]=0;      /* Reset flag */
 
7363
  pa->flag[pa->typelib.count]=0;                        /* Reset flag */
7246
7364
  pa->typelib.type_names[pa->typelib.count++]= (char*) pa->str+pa->length;
7247
 
  pa->typelib.type_names[pa->typelib.count]= NULL;  /* Put end-mark */
7248
 
  strcpy((char*) pa->str+pa->length,name);
 
7365
  pa->typelib.type_names[pa->typelib.count]= NullS;     /* Put end-mark */
 
7366
  VOID(strmov((char*) pa->str+pa->length,name));
7249
7367
  pa->length+=length;
7250
7368
  return(0);
7251
7369
} /* insert_pointer_name */
7252
7370
 
7253
7371
 
 
7372
/* free pointer array */
 
7373
 
 
7374
void free_pointer_array(POINTER_ARRAY *pa)
 
7375
{
 
7376
  if (pa->typelib.count)
 
7377
  {
 
7378
    pa->typelib.count=0;
 
7379
    my_free((char*) pa->typelib.type_names,MYF(0));
 
7380
    pa->typelib.type_names=0;
 
7381
    my_free(pa->str,MYF(0));
 
7382
  }
 
7383
} /* free_pointer_array */
 
7384
 
 
7385
 
7254
7386
/* Functions that uses replace and replace_regex */
7255
7387
 
7256
7388
/* Append the string to ds, with optional replace */
7257
 
void replace_append_mem(string *ds, const char *val, int len)
 
7389
void replace_dynstr_append_mem(DYNAMIC_STRING *ds,
 
7390
                               const char *val, int len)
7258
7391
{
7259
 
  char *v= strdup(val);
 
7392
  if (glob_replace_regex)
 
7393
  {
 
7394
    /* Regex replace */
 
7395
    if (!multi_reg_replace(glob_replace_regex, (char*)val))
 
7396
    {
 
7397
      val= glob_replace_regex->buf;
 
7398
      len= strlen(val);
 
7399
    }
 
7400
  }
7260
7401
 
7261
 
  if (glob_replace_regex && !glob_replace_regex->multi_reg_replace(v))
7262
 
  {
7263
 
    v= glob_replace_regex->buf_;
7264
 
    len= strlen(v);
7265
 
  }
7266
7402
  if (glob_replace)
7267
7403
  {
7268
7404
    /* Normal replace */
7269
 
    replace_strings_append(glob_replace, ds, v, len);
 
7405
    replace_strings_append(glob_replace, ds, val, len);
7270
7406
  }
7271
7407
  else
7272
 
    ds->append(v, len);
 
7408
    dynstr_append_mem(ds, val, len);
7273
7409
}
7274
7410
 
7275
7411
 
7276
7412
/* Append zero-terminated string to ds, with optional replace */
7277
 
void replace_append(string *ds, const char *val)
 
7413
void replace_dynstr_append(DYNAMIC_STRING *ds, const char *val)
7278
7414
{
7279
 
  replace_append_mem(ds, val, strlen(val));
 
7415
  replace_dynstr_append_mem(ds, val, strlen(val));
7280
7416
}
7281
7417
 
7282
 
/* Append uint32_t to ds, with optional replace */
7283
 
void replace_append_uint(string *ds, uint32_t val)
 
7418
/* Append uint to ds, with optional replace */
 
7419
void replace_dynstr_append_uint(DYNAMIC_STRING *ds, uint val)
7284
7420
{
7285
 
  ostringstream buff;
7286
 
  buff << val;
7287
 
  replace_append_mem(ds, buff.str().c_str(), buff.str().size());
7288
 
 
 
7421
  char buff[22]; /* This should be enough for any int */
 
7422
  char *end= int64_t10_to_str(val, buff, 10);
 
7423
  replace_dynstr_append_mem(ds, buff, end - buff);
7289
7424
}
7290
7425
 
7291
7426
 
7302
7437
 
7303
7438
*/
7304
7439
 
7305
 
 
7306
 
void append_sorted(string* ds, string *ds_input)
7307
 
{
7308
 
  priority_queue<string, vector<string>, greater<string> > lines;
7309
 
 
7310
 
  if (ds_input->empty())
 
7440
static int comp_lines(const char **a, const char **b)
 
7441
{
 
7442
  return (strcmp(*a,*b));
 
7443
}
 
7444
 
 
7445
void dynstr_append_sorted(DYNAMIC_STRING* ds, DYNAMIC_STRING *ds_input)
 
7446
{
 
7447
  unsigned i;
 
7448
  char *start= ds_input->str;
 
7449
  DYNAMIC_ARRAY lines;
 
7450
 
 
7451
 
 
7452
  if (!*start)
7311
7453
    return;  /* No input */
7312
7454
 
7313
 
  unsigned long eol_pos= 0;
7314
 
 
7315
 
  eol_pos= ds_input->find_first_of('\n', 0);
7316
 
  if (eol_pos == string::npos)
7317
 
    return; // We should have at least one header here
7318
 
 
7319
 
  ds->append(ds_input->substr(0, eol_pos+1));
7320
 
 
7321
 
  unsigned long start_pos= eol_pos+1;
 
7455
  my_init_dynamic_array(&lines, sizeof(const char*), 32, 32);
 
7456
 
 
7457
  /* First line is result header, skip past it */
 
7458
  while (*start && *start != '\n')
 
7459
    start++;
 
7460
  start++; /* Skip past \n */
 
7461
  dynstr_append_mem(ds, ds_input->str, start - ds_input->str);
7322
7462
 
7323
7463
  /* Insert line(s) in array */
7324
 
  do {
 
7464
  while (*start)
 
7465
  {
 
7466
    char* line_end= (char*)start;
7325
7467
 
7326
 
    eol_pos= ds_input->find_first_of('\n', start_pos);
7327
7468
    /* Find end of line */
7328
 
    lines.push(ds_input->substr(start_pos, eol_pos-start_pos+1));
7329
 
    start_pos= eol_pos+1;
7330
 
 
7331
 
  } while ( eol_pos != string::npos);
 
7469
    while (*line_end && *line_end != '\n')
 
7470
      line_end++;
 
7471
    *line_end= 0;
 
7472
 
 
7473
    /* Insert pointer to the line in array */
 
7474
    if (insert_dynamic(&lines, (uchar*) &start))
 
7475
      die("Out of memory inserting lines to sort");
 
7476
 
 
7477
    start= line_end+1;
 
7478
  }
 
7479
 
 
7480
  /* Sort array */
 
7481
  qsort(lines.buffer, lines.elements,
 
7482
        sizeof(char**), (qsort_cmp)comp_lines);
7332
7483
 
7333
7484
  /* Create new result */
7334
 
  while (!lines.empty()) {
7335
 
    ds->append(lines.top());
7336
 
    lines.pop();
 
7485
  for (i= 0; i < lines.elements ; i++)
 
7486
  {
 
7487
    const char **line= dynamic_element(&lines, i, const char**);
 
7488
    dynstr_append(ds, *line);
 
7489
    dynstr_append(ds, "\n");
7337
7490
  }
7338
7491
 
 
7492
  delete_dynamic(&lines);
7339
7493
  return;
7340
7494
}
7341
 
 
7342
 
static void free_all_replace()
7343
 
{
7344
 
  free_replace();
7345
 
  glob_replace_regex.reset();
7346
 
  free_replace_column();
7347
 
}