summaryrefslogtreecommitdiffstats
path: root/sql/sql_bootstrap.cc
blob: dbeb971cd5aac51fbf560f9b2ca3689498b2ca3f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/* Copyright (c) 2010, Oracle and/or its affiliates.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; version 2 of the License.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software Foundation,
   51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */


#include "mariadb.h"
#include <ctype.h>
#include <string.h>
#include "sql_bootstrap.h"

int read_bootstrap_query(char *query, int *query_length,
                         fgets_input_t input, fgets_fn_t fgets_fn, int *error)
{
  char line_buffer[MAX_BOOTSTRAP_LINE_SIZE];
  const char *line;
  size_t len;
  size_t query_len= 0;
  int fgets_error= 0;
  *error= 0;

  *query_length= 0;
  for ( ; ; )
  {
    line= (*fgets_fn)(line_buffer, sizeof(line_buffer), input, &fgets_error);
    
    if (error)
      *error= fgets_error;

    if (fgets_error != 0)
      return READ_BOOTSTRAP_ERROR;
      
    if (line == NULL)
      return (query_len == 0) ? READ_BOOTSTRAP_EOF : READ_BOOTSTRAP_ERROR;

    len= strlen(line);

    /*
      Remove trailing whitespace characters.
      This assumes:
      - no multibyte encoded character can be found at the very end of a line,
      - whitespace characters from the "C" locale only.
     which is sufficient for the kind of queries found
     in the bootstrap scripts.
    */
    while (len && (isspace(line[len - 1])))
      len--;
    /*
      Cleanly end the string, so we don't have to test len > x
      all the time before reading line[x], in the code below.
    */
    line_buffer[len]= '\0';

    /* Skip blank lines */
    if (len == 0)
      continue;

    /* Skip # comments */
    if (line[0] == '#')
      continue;
    
    /* Skip -- comments */
    if ((line[0] == '-') && (line[1] == '-'))
      continue;

    /* Skip delimiter, ignored. */
    if (strncmp(line, "delimiter", 9) == 0)
      continue;

    /* Append the current line to a multi line query. If the new line will make
       the query too long, preserve the partial line to provide context for the
       error message.
    */
    if (query_len + len + 1 >= MAX_BOOTSTRAP_QUERY_SIZE)
    {
      size_t new_len= MAX_BOOTSTRAP_QUERY_SIZE - query_len - 1;
      if ((new_len > 0) && (query_len < MAX_BOOTSTRAP_QUERY_SIZE))
      {
        memcpy(query + query_len, line, new_len);
        query_len+= new_len;
      }
      query[query_len]= '\0';
      *query_length= (int)query_len;
      return READ_BOOTSTRAP_QUERY_SIZE;
    }

    if (query_len != 0)
    {
      /*
        Append a \n to the current line, if any,
        to preserve the intended presentation.
       */
      query[query_len++]= '\n';
    }
    memcpy(query + query_len, line, len);
    query_len+= len;

    if (line[len - 1] == ';')
    {
      /*
        The last line is terminated by ';'.
        Return the query found.
      */
      query[query_len]= '\0';
      *query_length= (int)query_len;
      return READ_BOOTSTRAP_SUCCESS;
    }
  }
}