~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/* Copyright (C) 2005-2006 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
15
16
#include "mysql_priv.h"
17
#include "rpl_rli.h"
18
#include "base64.h"
19
20
/**
21
  Execute a BINLOG statement
22
23
  To execute the BINLOG command properly the server needs to know
24
  which format the BINLOG command's event is in.  Therefore, the first
25
  BINLOG statement seen must be a base64 encoding of the
26
  Format_description_log_event, as outputted by mysqlbinlog.  This
27
  Format_description_log_event is cached in
28
  rli->description_event_for_exec.
29
*/
30
31
void mysql_client_binlog_statement(THD* thd)
32
{
33
  size_t coded_len= thd->lex->comment.length + 1;
34
  size_t decoded_len= base64_needed_decoded_length(coded_len);
51.1.49 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
35
  assert(coded_len > 0);
1 by brian
clean slate
36
37
  /*
38
    Allocation
39
  */
40
41
  /*
42
    If we do not have a Format_description_event, we create a dummy
43
    one here.  In this case, the first event we read must be a
44
    Format_description_event.
45
  */
199 by Brian Aker
my_bool...
46
  bool have_fd_event= true;
1 by brian
clean slate
47
  if (!thd->rli_fake)
48
  {
49
    thd->rli_fake= new Relay_log_info;
50
#ifdef HAVE_purify
51.1.49 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
51
    thd->rli_fake->is_fake= true;
1 by brian
clean slate
52
#endif
51.1.49 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
53
    have_fd_event= false;
1 by brian
clean slate
54
  }
55
  if (thd->rli_fake && !thd->rli_fake->relay_log.description_event_for_exec)
56
  {
57
    thd->rli_fake->relay_log.description_event_for_exec=
58
      new Format_description_log_event(4);
51.1.49 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
59
    have_fd_event= false;
1 by brian
clean slate
60
  }
61
62
  const char *error= 0;
63
  char *buf= (char *) my_malloc(decoded_len, MYF(MY_WME));
64
  Log_event *ev = 0;
65
66
  /*
67
    Out of memory check
68
  */
69
  if (!(thd->rli_fake &&
70
        thd->rli_fake->relay_log.description_event_for_exec &&
71
        buf))
72
  {
73
    my_error(ER_OUTOFMEMORY, MYF(0), 1);  /* needed 1 bytes */
74
    goto end;
75
  }
76
77
  thd->rli_fake->sql_thd= thd;
51.1.49 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
78
  thd->rli_fake->no_storage= true;
1 by brian
clean slate
79
80
  for (char const *strptr= thd->lex->comment.str ;
81
       strptr < thd->lex->comment.str + thd->lex->comment.length ; )
82
  {
83
    char const *endptr= 0;
84
    int bytes_decoded= base64_decode(strptr, coded_len, buf, &endptr);
85
86
    if (bytes_decoded < 0)
87
    {
88
      my_error(ER_BASE64_DECODE_ERROR, MYF(0));
89
      goto end;
90
    }
91
    else if (bytes_decoded == 0)
92
      break; // If no bytes where read, the string contained only whitespace
93
51.1.49 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
94
    assert(bytes_decoded > 0);
95
    assert(endptr > strptr);
1 by brian
clean slate
96
    coded_len-= endptr - strptr;
97
    strptr= endptr;
98
99
    /*
100
      Now we have one or more events stored in the buffer. The size of
101
      the buffer is computed based on how much base64-encoded data
102
      there were, so there should be ample space for the data (maybe
103
      even too much, since a statement can consist of a considerable
104
      number of events).
105
106
      TODO: Switch to use a stream-based base64 encoder/decoder in
107
      order to be able to read exactly what is necessary.
108
    */
109
110
    /*
111
      Now we start to read events of the buffer, until there are no
112
      more.
113
    */
114
    for (char *bufptr= buf ; bytes_decoded > 0 ; )
115
    {
116
      /*
117
        Checking that the first event in the buffer is not truncated.
118
      */
119
      ulong event_len= uint4korr(bufptr + EVENT_LEN_OFFSET);
120
      if (bytes_decoded < EVENT_LEN_OFFSET || (uint) bytes_decoded < event_len)
121
      {
122
        my_error(ER_SYNTAX_ERROR, MYF(0));
123
        goto end;
124
      }
125
126
      /*
127
        If we have not seen any Format_description_event, then we must
128
        see one; it is the only statement that can be read in base64
129
        without a prior Format_description_event.
130
      */
131
      if (!have_fd_event)
132
      {
133
        int type = bufptr[EVENT_TYPE_OFFSET];
134
        if (type == FORMAT_DESCRIPTION_EVENT || type == START_EVENT_V3)
51.1.49 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
135
          have_fd_event= true;
1 by brian
clean slate
136
        else
137
        {
138
          my_error(ER_NO_FORMAT_DESCRIPTION_EVENT_BEFORE_BINLOG_STATEMENT,
139
                   MYF(0), Log_event::get_type_str((Log_event_type)type));
140
          goto end;
141
        }
142
      }
143
144
      ev= Log_event::read_log_event(bufptr, event_len, &error,
145
                                    thd->rli_fake->relay_log.
146
                                      description_event_for_exec);
147
148
      if (!ev)
149
      {
150
        /*
151
          This could actually be an out-of-memory, but it is more likely
152
          causes by a bad statement
153
        */
154
        my_error(ER_SYNTAX_ERROR, MYF(0));
155
        goto end;
156
      }
157
158
      bytes_decoded -= event_len;
159
      bufptr += event_len;
160
161
      ev->thd= thd;
162
      /*
163
        We go directly to the application phase, since we don't need
164
        to check if the event shall be skipped or not.
165
166
        Neither do we have to update the log positions, since that is
167
        not used at all: the rli_fake instance is used only for error
168
        reporting.
169
      */
170
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
51.1.49 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
171
      if (apply_event_and_update_pos(ev, thd, thd->rli_fake, false))
1 by brian
clean slate
172
      {
173
        /*
174
          TODO: Maybe a better error message since the BINLOG statement
175
          now contains several events.
176
        */
177
        my_error(ER_UNKNOWN_ERROR, MYF(0), "Error executing BINLOG statement");
178
        goto end;
179
      }
180
#endif
181
182
      /*
183
        Format_description_log_event should not be deleted because it
184
        will be used to read info about the relay log's format; it
185
        will be deleted when the SQL thread does not need it,
186
        i.e. when this thread terminates.
187
      */
188
      if (ev->get_type_code() != FORMAT_DESCRIPTION_EVENT)
189
        delete ev;
190
      ev= 0;
191
    }
192
  }
193
194
  my_ok(thd);
195
196
end:
197
  thd->rli_fake->clear_tables_to_lock();
198
  my_free(buf, MYF(MY_ALLOW_ZERO_PTR));
51.1.49 by Jay Pipes
Removed/replaced DBUG symbols and standardized TRUE/FALSE
199
  return;
1 by brian
clean slate
200
}