~ubuntu-branches/ubuntu/precise/mysql-5.1/precise

« back to all changes in this revision

Viewing changes to server-tools/instance-manager/parse.cc

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Tretkowski
  • Date: 2010-03-17 14:56:02 UTC
  • Revision ID: james.westby@ubuntu.com-20100317145602-x7e30l1b2sb5s6w6
Tags: upstream-5.1.45
ImportĀ upstreamĀ versionĀ 5.1.45

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2004 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 */
 
15
 
 
16
#include "parse.h"
 
17
#include "commands.h"
 
18
 
 
19
 
 
20
enum Token
 
21
{
 
22
  TOK_CREATE= 0,
 
23
  TOK_DROP,
 
24
  TOK_ERROR, /* Encodes the "ERROR" word, it doesn't indicate error. */
 
25
  TOK_FILES,
 
26
  TOK_FLUSH,
 
27
  TOK_GENERAL,
 
28
  TOK_INSTANCE,
 
29
  TOK_INSTANCES,
 
30
  TOK_LOG,
 
31
  TOK_OPTIONS,
 
32
  TOK_SET,
 
33
  TOK_SLOW,
 
34
  TOK_START,
 
35
  TOK_STATUS,
 
36
  TOK_STOP,
 
37
  TOK_SHOW,
 
38
  TOK_UNSET,
 
39
  TOK_NOT_FOUND, // must be after all tokens
 
40
  TOK_END
 
41
};
 
42
 
 
43
 
 
44
struct tokens_st
 
45
{
 
46
  uint length;
 
47
  const char *tok_name;
 
48
};
 
49
 
 
50
 
 
51
static struct tokens_st tokens[]= {
 
52
  {6, "CREATE"},
 
53
  {4, "DROP"},
 
54
  {5, "ERROR"},
 
55
  {5, "FILES"},
 
56
  {5, "FLUSH"},
 
57
  {7, "GENERAL"},
 
58
  {8, "INSTANCE"},
 
59
  {9, "INSTANCES"},
 
60
  {3, "LOG"},
 
61
  {7, "OPTIONS"},
 
62
  {3, "SET"},
 
63
  {4, "SLOW"},
 
64
  {5, "START"},
 
65
  {6, "STATUS"},
 
66
  {4, "STOP"},
 
67
  {4, "SHOW"},
 
68
  {5, "UNSET"}
 
69
};
 
70
 
 
71
/************************************************************************/
 
72
 
 
73
Named_value_arr::Named_value_arr() :
 
74
  initialized(FALSE)
 
75
{
 
76
}
 
77
 
 
78
 
 
79
bool Named_value_arr::init()
 
80
{
 
81
  if (my_init_dynamic_array(&arr, sizeof(Named_value), 0, 32))
 
82
    return TRUE;
 
83
 
 
84
  initialized= TRUE;
 
85
 
 
86
  return FALSE;
 
87
}
 
88
 
 
89
 
 
90
Named_value_arr::~Named_value_arr()
 
91
{
 
92
  if (!initialized)
 
93
    return;
 
94
 
 
95
  for (int i= 0; i < get_size(); ++i)
 
96
    get_element(i).free();
 
97
 
 
98
  delete_dynamic(&arr);
 
99
}
 
100
 
 
101
/************************************************************************/
 
102
 
 
103
/*
 
104
  Returns token no if word corresponds to some token, otherwise returns
 
105
  TOK_NOT_FOUND
 
106
*/
 
107
 
 
108
inline Token find_token(const char *word, size_t word_len)
 
109
{
 
110
  int i= 0;
 
111
  do
 
112
  {
 
113
    if (my_strnncoll(default_charset_info, (const uchar *) tokens[i].tok_name,
 
114
                     tokens[i].length, (const uchar *) word, word_len) == 0)
 
115
      break;
 
116
  }
 
117
  while (++i < TOK_NOT_FOUND);
 
118
  return (Token) i;
 
119
}
 
120
 
 
121
 
 
122
Token get_token(const char **text, size_t *word_len)
 
123
{
 
124
  get_word(text, word_len);
 
125
  if (*word_len)
 
126
    return find_token(*text, *word_len);
 
127
  return TOK_END;
 
128
}
 
129
 
 
130
 
 
131
Token shift_token(const char **text, size_t *word_len)
 
132
{
 
133
  Token save= get_token(text, word_len);
 
134
  (*text)+= *word_len;
 
135
  return save;
 
136
}
 
137
 
 
138
 
 
139
int get_text_id(const char **text, LEX_STRING *token)
 
140
{
 
141
  get_word(text, &token->length);
 
142
  if (token->length == 0)
 
143
    return 1;
 
144
  token->str= (char *) *text;
 
145
  return 0;
 
146
}
 
147
 
 
148
 
 
149
static bool parse_long(const LEX_STRING *token, long *value)
 
150
{
 
151
  int err_code;
 
152
  char *end_ptr= token->str + token->length;
 
153
 
 
154
  *value= (long)my_strtoll10(token->str, &end_ptr, &err_code);
 
155
 
 
156
  return err_code != 0;
 
157
}
 
158
 
 
159
 
 
160
bool parse_option_value(const char *text, size_t *text_len, char **value)
 
161
{
 
162
  char beginning_quote;
 
163
  const char *text_start_ptr;
 
164
  char *v;
 
165
  bool escape_mode= FALSE;
 
166
 
 
167
  if (!*text || (*text != '\'' && *text != '"'))
 
168
    return TRUE; /* syntax error: string expected. */
 
169
 
 
170
  beginning_quote= *text;
 
171
 
 
172
  ++text; /* skip the beginning quote. */
 
173
 
 
174
  text_start_ptr= text;
 
175
 
 
176
  if (!(v= Named_value::alloc_str(text)))
 
177
    return TRUE;
 
178
 
 
179
  *value= v;
 
180
 
 
181
  while (TRUE)
 
182
  {
 
183
    if (!*text)
 
184
    {
 
185
      Named_value::free_str(value);
 
186
      return TRUE; /* syntax error: missing terminating ' character. */
 
187
    }
 
188
 
 
189
    if (*text == '\n' || *text == '\r')
 
190
    {
 
191
      Named_value::free_str(value);
 
192
      return TRUE; /* syntax error: option value should be a single line. */
 
193
    }
 
194
 
 
195
    if (!escape_mode && *text == beginning_quote)
 
196
      break;
 
197
 
 
198
    if (escape_mode)
 
199
    {
 
200
      switch (*text)
 
201
      {
 
202
        case 'b': /* \b -- backspace */
 
203
          if (v > *value)
 
204
            --v;
 
205
          break;
 
206
 
 
207
        case 't': /* \t -- tab */
 
208
          *v= '\t';
 
209
          ++v;
 
210
          break;
 
211
 
 
212
        case 'n': /* \n -- newline */
 
213
          *v= '\n';
 
214
          ++v;
 
215
          break;
 
216
 
 
217
        case 'r': /* \r -- carriage return */
 
218
          *v= '\r';
 
219
          ++v;
 
220
          break;
 
221
 
 
222
        case '\\': /* \\ -- back slash */
 
223
          *v= '\\';
 
224
          ++v;
 
225
          break;
 
226
 
 
227
        case 's': /* \s -- space */
 
228
          *v= ' ';
 
229
          ++v;
 
230
          break;
 
231
 
 
232
        default: /* Unknown escape sequence. Treat as error. */
 
233
          Named_value::free_str(value);
 
234
          return TRUE;
 
235
      }
 
236
 
 
237
      escape_mode= FALSE;
 
238
    }
 
239
    else
 
240
    {
 
241
      if (*text == '\\')
 
242
      {
 
243
        escape_mode= TRUE;
 
244
      }
 
245
      else
 
246
      {
 
247
        *v= *text;
 
248
        ++v;
 
249
      }
 
250
    }
 
251
 
 
252
    ++text;
 
253
  }
 
254
 
 
255
  *v= 0;
 
256
 
 
257
  /* "2" below stands for beginning and ending quotes. */
 
258
  *text_len= text - text_start_ptr + 2;
 
259
 
 
260
  return FALSE;
 
261
}
 
262
 
 
263
 
 
264
void skip_spaces(const char **text)
 
265
{
 
266
  while (**text && my_isspace(default_charset_info, **text))
 
267
    ++(*text);
 
268
}
 
269
 
 
270
 
 
271
Command *parse_command(const char *text)
 
272
{
 
273
  size_t word_len;
 
274
  LEX_STRING instance_name;
 
275
  Command *command= 0;
 
276
 
 
277
  Token tok1= shift_token(&text, &word_len);
 
278
 
 
279
  switch (tok1) {
 
280
  case TOK_START:                               // fallthrough
 
281
  case TOK_STOP:
 
282
  case TOK_CREATE:
 
283
  case TOK_DROP:
 
284
    if (shift_token(&text, &word_len) != TOK_INSTANCE)
 
285
      goto syntax_error;
 
286
    get_word(&text, &word_len);
 
287
    if (word_len == 0)
 
288
      goto syntax_error;
 
289
    instance_name.str= (char *) text;
 
290
    instance_name.length= word_len;
 
291
    text+= word_len;
 
292
 
 
293
    if (tok1 == TOK_CREATE)
 
294
    {
 
295
      Create_instance *cmd= new Create_instance(&instance_name);
 
296
 
 
297
      if (!cmd)
 
298
        return NULL; /* Report ER_OUT_OF_RESOURCES. */
 
299
 
 
300
      if (cmd->init(&text))
 
301
      {
 
302
        delete cmd;
 
303
        goto syntax_error;
 
304
      }
 
305
 
 
306
      command= cmd;
 
307
    }
 
308
    else
 
309
    {
 
310
      /* it should be the end of command */
 
311
      get_word(&text, &word_len, NONSPACE);
 
312
      if (word_len)
 
313
        goto syntax_error;
 
314
    }
 
315
 
 
316
    switch (tok1) {
 
317
    case TOK_START:
 
318
      command= new Start_instance(&instance_name);
 
319
      break;
 
320
    case TOK_STOP:
 
321
      command= new Stop_instance(&instance_name);
 
322
      break;
 
323
    case TOK_CREATE:
 
324
      ; /* command already initialized. */
 
325
      break;
 
326
    case TOK_DROP:
 
327
      command= new Drop_instance(&instance_name);
 
328
      break;
 
329
    default: /* this is impossible, but nevertheless... */
 
330
      DBUG_ASSERT(0);
 
331
    }
 
332
    break;
 
333
  case TOK_FLUSH:
 
334
    if (shift_token(&text, &word_len) != TOK_INSTANCES)
 
335
      goto syntax_error;
 
336
 
 
337
    get_word(&text, &word_len, NONSPACE);
 
338
    if (word_len)
 
339
      goto syntax_error;
 
340
 
 
341
    command= new Flush_instances();
 
342
    break;
 
343
  case TOK_UNSET:
 
344
  case TOK_SET:
 
345
    {
 
346
      Abstract_option_cmd *cmd;
 
347
 
 
348
      if (tok1 == TOK_SET)
 
349
        cmd= new Set_option();
 
350
      else
 
351
        cmd= new Unset_option();
 
352
 
 
353
      if (!cmd)
 
354
        return NULL; /* Report ER_OUT_OF_RESOURCES. */
 
355
 
 
356
      if (cmd->init(&text))
 
357
      {
 
358
        delete cmd;
 
359
        goto syntax_error;
 
360
      }
 
361
 
 
362
      command= cmd;
 
363
 
 
364
      break;
 
365
    }
 
366
  case TOK_SHOW:
 
367
    switch (shift_token(&text, &word_len)) {
 
368
    case TOK_INSTANCES:
 
369
      get_word(&text, &word_len, NONSPACE);
 
370
      if (word_len)
 
371
        goto syntax_error;
 
372
      command= new Show_instances();
 
373
      break;
 
374
    case TOK_INSTANCE:
 
375
      switch (Token tok2= shift_token(&text, &word_len)) {
 
376
      case TOK_OPTIONS:
 
377
      case TOK_STATUS:
 
378
        if (get_text_id(&text, &instance_name))
 
379
          goto syntax_error;
 
380
        text+= instance_name.length;
 
381
        /* check that this is the end of the command */
 
382
        get_word(&text, &word_len, NONSPACE);
 
383
        if (word_len)
 
384
          goto syntax_error;
 
385
        if (tok2 == TOK_STATUS)
 
386
          command= new Show_instance_status(&instance_name);
 
387
        else
 
388
          command= new Show_instance_options(&instance_name);
 
389
        break;
 
390
      default:
 
391
        goto syntax_error;
 
392
      }
 
393
      break;
 
394
    default:
 
395
      instance_name.str= (char *) text - word_len;
 
396
      instance_name.length= word_len;
 
397
      if (instance_name.length)
 
398
      {
 
399
        Log_type log_type;
 
400
 
 
401
        long log_size;
 
402
        LEX_STRING log_size_str;
 
403
 
 
404
        long log_offset= 0;
 
405
        LEX_STRING log_offset_str= { NULL, 0 };
 
406
 
 
407
        switch (shift_token(&text, &word_len)) {
 
408
        case TOK_LOG:
 
409
          switch (Token tok3= shift_token(&text, &word_len)) {
 
410
          case TOK_FILES:
 
411
            get_word(&text, &word_len, NONSPACE);
 
412
            /* check that this is the end of the command */
 
413
            if (word_len)
 
414
              goto syntax_error;
 
415
            command= new Show_instance_log_files(&instance_name);
 
416
            break;
 
417
          case TOK_ERROR:
 
418
          case TOK_GENERAL:
 
419
          case TOK_SLOW:
 
420
            /* define a log type */
 
421
            switch (tok3) {
 
422
            case TOK_ERROR:
 
423
              log_type= IM_LOG_ERROR;
 
424
              break;
 
425
            case TOK_GENERAL:
 
426
              log_type= IM_LOG_GENERAL;
 
427
              break;
 
428
            case TOK_SLOW:
 
429
              log_type= IM_LOG_SLOW;
 
430
              break;
 
431
            default:
 
432
              goto syntax_error;
 
433
            }
 
434
            /* get the size of the log we want to retrieve */
 
435
            if (get_text_id(&text, &log_size_str))
 
436
              goto syntax_error;
 
437
            text+= log_size_str.length;
 
438
 
 
439
            /* this parameter is required */
 
440
            if (!log_size_str.length)
 
441
              goto syntax_error;
 
442
 
 
443
            /* the next token should be comma, or nothing */
 
444
            get_word(&text, &word_len);
 
445
            switch (*text) {
 
446
              case ',':
 
447
                text++; /* swallow the comma */
 
448
                /* read the next word */
 
449
                get_word(&text, &word_len);
 
450
                if (!word_len)
 
451
                  goto syntax_error;
 
452
                log_offset_str.str= (char *) text;
 
453
                log_offset_str.length= word_len;
 
454
                text+= word_len;
 
455
                get_word(&text, &word_len, NONSPACE);
 
456
                /* check that this is the end of the command */
 
457
                if (word_len)
 
458
                  goto syntax_error;
 
459
                break;
 
460
              case '\0':
 
461
                break; /* this is ok */
 
462
              default:
 
463
                goto syntax_error;
 
464
            }
 
465
 
 
466
            /* Parse size parameter. */
 
467
 
 
468
            if (parse_long(&log_size_str, &log_size))
 
469
              goto syntax_error;
 
470
 
 
471
            if (log_size <= 0)
 
472
              goto syntax_error;
 
473
 
 
474
            /* Parse offset parameter (if specified). */
 
475
 
 
476
            if (log_offset_str.length)
 
477
            {
 
478
              if (parse_long(&log_offset_str, &log_offset))
 
479
                goto syntax_error;
 
480
 
 
481
              if (log_offset <= 0)
 
482
                goto syntax_error;
 
483
            }
 
484
 
 
485
            command= new Show_instance_log(&instance_name,
 
486
                                           log_type, log_size, log_offset);
 
487
          break;
 
488
          default:
 
489
            goto syntax_error;
 
490
          }
 
491
        break;
 
492
        default:
 
493
          goto syntax_error;
 
494
        }
 
495
      }
 
496
      else
 
497
        goto syntax_error;
 
498
      break;
 
499
    }
 
500
    break;
 
501
  default:
 
502
syntax_error:
 
503
    command= new Syntax_error();
 
504
  }
 
505
 
 
506
  DBUG_ASSERT(command);
 
507
 
 
508
  return command;
 
509
}