summaryrefslogtreecommitdiff
path: root/sql/sql_binlog.cc
blob: 0939ad66cd0879bcd474c0294944ef38c8bd29f9 (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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/* Copyright (C) 2005 MySQL AB & MySQL Finland AB & TCX DataKonsult AB

   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; either version 2 of the License, or
   (at your option) any later version.

   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, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#include "mysql_priv.h"
#include "base64.h"

/*
  Execute a BINLOG statement

  TODO: This currently assumes a MySQL 5.x binlog.
  When we'll have binlog with a different format, to execute the
  BINLOG command properly the server will need to know which format
  the BINLOG command's event is in.  mysqlbinlog should then send
  the Format_description_log_event of the binlog it reads and the
  server thread should cache this format into
  rli->description_event_for_exec.
*/

void mysql_client_binlog_statement(THD* thd)
{
  DBUG_PRINT("info",("binlog base64: '%*s'",
                     (thd->lex->comment.length < 2048 ?
                      thd->lex->comment.length : 2048),
                     thd->lex->comment.str));

  /*
    Temporarily turn off send_ok, since different events handle this
    differently
  */
  my_bool nsok= thd->net.no_send_ok;
  thd->net.no_send_ok= TRUE;

  const my_size_t coded_len= thd->lex->comment.length + 1;
  const my_size_t event_len= base64_needed_decoded_length(coded_len);
  DBUG_ASSERT(coded_len > 0);

  /*
    Allocation
  */
  if (!thd->rli_fake)
    thd->rli_fake= new RELAY_LOG_INFO;

  const Format_description_log_event *desc=
    new Format_description_log_event(4);

  const char *error= 0;
  char *buf= (char *) my_malloc(event_len, MYF(MY_WME));
  Log_event *ev = 0;
  int res;

  /*
    Out of memory check
  */
  if (!(thd->rli_fake && desc && buf))
  {
    my_error(ER_OUTOFMEMORY, MYF(0), 1);  /* needed 1 bytes */
    goto end;
  }

  thd->rli_fake->sql_thd= thd;
  thd->rli_fake->no_storage= TRUE;

  res= base64_decode(thd->lex->comment.str, coded_len, buf);

  DBUG_PRINT("info",("binlog base64 decoded_len=%d, event_len=%d\n",
                     res, uint4korr(buf + EVENT_LEN_OFFSET)));
  /*
    Note that 'res' is the correct event length, 'event_len' was
    calculated based on the base64-string that possibly contained
    extra spaces, so it can be longer than the real event.
  */
  if (res < EVENT_LEN_OFFSET
      || (uint) res != uint4korr(buf+EVENT_LEN_OFFSET))
  {
    my_error(ER_SYNTAX_ERROR, MYF(0));
    goto end;
  }

  ev= Log_event::read_log_event(buf, res, &error, desc);

  DBUG_PRINT("info",("binlog base64 err=%s", error));
  if (!ev)
  {
    /*
      This could actually be an out-of-memory, but it is more
      likely causes by a bad statement
    */
    my_error(ER_SYNTAX_ERROR, MYF(0));
    goto end;
  }

  DBUG_PRINT("info",("ev->get_type_code()=%d", ev->get_type_code()));
  DBUG_PRINT("info",("buf+EVENT_TYPE_OFFSET=%d", buf+EVENT_TYPE_OFFSET));

  ev->thd= thd;
  if (ev->exec_event(thd->rli_fake))
  {
    my_error(ER_UNKNOWN_ERROR, MYF(0), "Error executing BINLOG statement");
    goto end;
  }

  /*
    Restore setting of no_send_ok
  */
  thd->net.no_send_ok= nsok;

  DBUG_PRINT("info",("binlog base64 execution finished successfully"));
  send_ok(thd);

end:
  /*
    Restore setting of no_send_ok
  */
  thd->net.no_send_ok= nsok;

  if (ev)
    delete ev;
  if (desc)
    delete desc;
  if (buf)
    my_free(buf, MYF(0));
}