mysql_binlog 0.1.4 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
data/lib/mysql_binlog.rb CHANGED
@@ -1,6 +1,6 @@
1
- require 'mysql_binlog/mysql_binlog'
2
- require 'mysql_binlog/binlog_parser'
3
- require 'mysql_binlog/binlog_event_field_parser'
1
+ require 'mysql_binlog/binlog'
2
+ require 'mysql_binlog/binlog_field_parser'
3
+ require 'mysql_binlog/binlog_event_parser'
4
4
  require 'mysql_binlog/reader/debugging_reader'
5
5
  require 'mysql_binlog/reader/binlog_file_reader'
6
6
  require 'mysql_binlog/reader/binlog_stream_reader'
@@ -0,0 +1,141 @@
1
+ module MysqlBinlog
2
+ class UnsupportedVersionException < Exception; end
3
+ class MalformedBinlogException < Exception; end
4
+ class ZeroReadException < Exception; end
5
+ class ShortReadException < Exception; end
6
+
7
+ class Binlog
8
+ attr_reader :fde
9
+ attr_accessor :reader
10
+ attr_accessor :field_parser
11
+ attr_accessor :event_parser
12
+ attr_accessor :filter_event_types
13
+ attr_accessor :filter_flags
14
+ attr_accessor :max_query_length
15
+
16
+ def initialize(reader)
17
+ @reader = reader
18
+ @field_parser = BinlogFieldParser.new(self)
19
+ @event_parser = BinlogEventParser.new(self)
20
+ @fde = nil
21
+ @filter_event_types = nil
22
+ @filter_flags = nil
23
+ @max_query_length = 1048576
24
+ end
25
+
26
+ # Rewind to the beginning of the log, if supported by the reader. The
27
+ # reader may throw an exception if rewinding is not supported (e.g. for
28
+ # a stream-based reader).
29
+ def rewind
30
+ reader.rewind
31
+ end
32
+
33
+ # Skip the remainder of this event. This can be used to skip an entire
34
+ # event or merely the parts of the event this library does not understand.
35
+ def skip_event(header)
36
+ reader.skip(header)
37
+ end
38
+
39
+ # Read the content of the event, which follows the header.
40
+ def read_event_fields(header)
41
+ event_type = EVENT_TYPES[header[:event_type]]
42
+
43
+ # Delegate the parsing of the event content to a method of the same name
44
+ # in BinlogEventParser.
45
+ if event_parser.methods.include? event_type.to_s
46
+ fields = event_parser.send(event_type, header)
47
+ end
48
+
49
+ # Anything left unread at this point is skipped based on the event length
50
+ # provided in the header. In this way, it is possible to skip over events
51
+ # that are not able to be parsed correctly by this library.
52
+ skip_event(header)
53
+
54
+ fields
55
+ end
56
+
57
+ # Scan events until finding one that isn't rejected by the filter rules.
58
+ # If there are no filter rules, this will return the next event provided
59
+ # by the reader.
60
+ def read_event
61
+ while true
62
+ skip_this_event = false
63
+ return nil if reader.end?
64
+
65
+ filename = reader.filename
66
+ position = reader.position
67
+
68
+ # Read the common header for an event. Every event has a header.
69
+ unless header = event_parser.event_header
70
+ return nil
71
+ end
72
+
73
+ event_type = EVENT_TYPES[header[:event_type]]
74
+
75
+ if @filter_event_types
76
+ unless @filter_event_types.include? event_type
77
+ skip_this_event = true
78
+ end
79
+ end
80
+
81
+ if @filter_flags
82
+ unless @filter_flags.include? header[:flags]
83
+ skip_this_event = true
84
+ end
85
+ end
86
+
87
+ # Never skip over rotate_event or format_description_event as they
88
+ # are critical to understanding the format of this event stream.
89
+ if skip_this_event
90
+ unless [:rotate_event, :format_description_event].include? event_type
91
+ skip_event(header)
92
+ next
93
+ end
94
+ end
95
+
96
+ fields = read_event_fields(header)
97
+
98
+ case event_type
99
+ when :rotate_event
100
+ reader.rotate(fields[:name], fields[:pos])
101
+ when :format_description_event
102
+ process_fde(fields)
103
+ end
104
+
105
+ break
106
+ end
107
+
108
+ {
109
+ :type => event_type,
110
+ :filename => filename,
111
+ :position => position,
112
+ :header => header,
113
+ :event => fields,
114
+ }
115
+ end
116
+
117
+ # Process a format description event, which describes the version of this
118
+ # file, and the format of events which will appear in this file. This also
119
+ # provides the version of the MySQL server which generated this file.
120
+ def process_fde(fde)
121
+ if (version = fde[:binlog_version]) != 4
122
+ raise UnsupportedVersionException.new("Binlog version #{version} is not supported")
123
+ end
124
+
125
+ # Save the interesting fields from an FDE so that this information is
126
+ # available at any time later.
127
+ @fde = {
128
+ :header_length => fde[:header_length],
129
+ :binlog_version => fde[:binlog_version],
130
+ :server_version => fde[:server_version],
131
+ }
132
+ end
133
+
134
+ # Iterate through all events.
135
+ def each_event
136
+ while event = read_event
137
+ yield event
138
+ end
139
+ end
140
+ end
141
+ end
@@ -1,4 +1,57 @@
1
1
  module MysqlBinlog
2
+ # A common fixed-length header that is included with each event.
3
+ EVENT_HEADER = [
4
+ { :name => :timestamp, :length => 4, :format => "V" },
5
+ { :name => :event_type, :length => 1, :format => "C" },
6
+ { :name => :server_id, :length => 4, :format => "V" },
7
+ { :name => :event_length, :length => 4, :format => "V" },
8
+ { :name => :next_position, :length => 4, :format => "V" },
9
+ { :name => :flags, :length => 2, :format => "v" },
10
+ ]
11
+
12
+ # Values for the 'flags' field that may appear in binlogs. There are
13
+ # several other values that never appear in a file but may be used
14
+ # in events in memory.
15
+ EVENT_HEADER_FLAGS = {
16
+ :binlog_in_use => 0x01,
17
+ :thread_specific => 0x04,
18
+ :suppress_use => 0x08,
19
+ :artificial => 0x20,
20
+ :relay_log => 0x40,
21
+ }
22
+
23
+ # An array to quickly map an integer event type to its symbol.
24
+ EVENT_TYPES = [
25
+ :unknown_event, # 0
26
+ :start_event_v3, # 1
27
+ :query_event, # 2
28
+ :stop_event, # 3
29
+ :rotate_event, # 4
30
+ :intvar_event, # 5
31
+ :load_event, # 6
32
+ :slave_event, # 7
33
+ :create_file_event, # 8
34
+ :append_block_event, # 9
35
+ :exec_load_event, # 10
36
+ :delete_file_event, # 11
37
+ :new_load_event, # 12
38
+ :rand_event, # 13
39
+ :user_var_event, # 14
40
+ :format_description_event, # 15
41
+ :xid_event, # 16
42
+ :begin_load_query_event, # 17
43
+ :execute_load_query_event, # 18
44
+ :table_map_event, # 19
45
+ :pre_ga_write_rows_event, # 20
46
+ :pre_ga_update_rows_event, # 21
47
+ :pre_ga_delete_rows_event, # 22
48
+ :write_rows_event, # 23
49
+ :update_rows_event, # 24
50
+ :delete_rows_event, # 25
51
+ :incident_event, # 26
52
+ :heartbeat_log_event, # 27
53
+ ]
54
+
2
55
  # A mapping array for all values that may appear in the +status+ field of
3
56
  # a query_event.
4
57
  QUERY_EVENT_STATUS_TYPES = [
@@ -23,7 +76,13 @@ module MysqlBinlog
23
76
  :relaxed_unique_checks => 1 << 27,
24
77
  }
25
78
 
26
- class BinlogEventFieldParser
79
+ INTVAR_EVENT_INTVAR_TYPES = [
80
+ nil,
81
+ :last_insert_id,
82
+ :insert_id,
83
+ ]
84
+
85
+ class BinlogEventParser
27
86
  attr_accessor :binlog
28
87
  attr_accessor :reader
29
88
  attr_accessor :parser
@@ -31,14 +90,46 @@ module MysqlBinlog
31
90
  def initialize(binlog_instance)
32
91
  @binlog = binlog_instance
33
92
  @reader = binlog_instance.reader
34
- @parser = binlog_instance.parser
93
+ @parser = binlog_instance.field_parser
35
94
  @table_map = {}
36
95
  end
37
96
 
38
- # Parse additional fields for a +Rotate+ event.
39
- def rotate_event(header, fields)
97
+ # Parse an event header, described by the EVENT_HEADER structure above.
98
+ def event_header
99
+ header = parser.read_and_unpack(EVENT_HEADER)
100
+
101
+ # Merge the read 'flags' bitmap with the EVENT_HEADER_FLAGS hash to return
102
+ # the flags by name instead of returning the bitmap as an integer.
103
+ flags = EVENT_HEADER_FLAGS.inject([]) do |result, (flag_name, flag_bit_value)|
104
+ if (header[:flags] & flag_bit_value) != 0
105
+ result << flag_name
106
+ end
107
+ result
108
+ end
109
+
110
+ # Overwrite the integer version of 'flags' with the array of names.
111
+ header[:flags] = flags
112
+
113
+ header
114
+ end
115
+
116
+ # Parse fields for a +Format_description+ event.
117
+ def format_description_event(header)
118
+ fields = {}
119
+ fields[:binlog_version] = parser.read_uint16
120
+ fields[:server_version] = parser.read_nstringz(50)
121
+ fields[:create_timestamp] = parser.read_uint32
122
+ fields[:header_length] = parser.read_uint8
123
+ fields
124
+ end
125
+
126
+ # Parse fields for a +Rotate+ event.
127
+ def rotate_event(header)
128
+ fields = {}
129
+ fields[:pos] = parser.read_uint64
40
130
  name_length = reader.remaining(header)
41
- fields[:name] = reader.read(name_length)
131
+ fields[:name] = parser.read_nstring(name_length)
132
+ fields
42
133
  end
43
134
 
44
135
  # Parse a dynamic +status+ structure within a query_event, which consists
@@ -86,25 +177,44 @@ module MysqlBinlog
86
177
  status
87
178
  end
88
179
 
89
- # Parse additional fields for a +Query+ event.
90
- def query_event(header, fields)
180
+ # Parse fields for a +Query+ event.
181
+ def query_event(header)
182
+ fields = {}
183
+ fields[:thread_id] = parser.read_uint32
184
+ fields[:elapsed_time] = parser.read_uint32
185
+ db_length = parser.read_uint8
186
+ fields[:error_code] = parser.read_uint16
91
187
  fields[:status] = _query_event_status(header, fields)
92
- fields[:db] = parser.read_nstringz(fields[:db_length])
93
- fields.delete :db_length
188
+ fields[:db] = parser.read_nstringz(db_length + 1)
94
189
  query_length = reader.remaining(header)
95
190
  fields[:query] = reader.read([query_length, binlog.max_query_length].min)
191
+ fields
96
192
  end
97
193
 
98
- # Parse additional fields for an +Intvar+ event.
99
- def intvar_event(header, fields)
100
- case fields[:intvar_type]
101
- when 1
102
- fields[:intvar_name] = :last_insert_id
103
- when 2
104
- fields[:intvar_name] = :insert_id
105
- else
106
- fields[:intvar_name] = nil
107
- end
194
+ # Parse fields for an +Intvar+ event.
195
+ def intvar_event(header)
196
+ fields = {}
197
+
198
+ fields[:intvar_type] = parser.read_uint8
199
+ fields[:intvar_name] = INTVAR_EVENT_INTVAR_TYPES[fields[:intvar_type]]
200
+ fields[:intvar_value] = parser.read_uint64
201
+
202
+ fields
203
+ end
204
+
205
+ # Parse fields for an +Xid+ event.
206
+ def xid_event(header)
207
+ fields = {}
208
+ fields[:xid] = parser.read_uint64
209
+ fields
210
+ end
211
+
212
+ # Parse fields for an +Rand+ event.
213
+ def rand_event(header)
214
+ fields = {}
215
+ fields[:seed1] = parser.read_uint64
216
+ fields[:seed2] = parser.read_uint64
217
+ fields
108
218
  end
109
219
 
110
220
  # Parse column metadata within a table map event.
@@ -115,8 +225,9 @@ module MysqlBinlog
115
225
  end
116
226
  end
117
227
 
118
- # Parse additional fields for a +Table_map+ event.
119
- def table_map_event(header, fields)
228
+ # Parse fields for a +Table_map+ event.
229
+ def table_map_event(header)
230
+ fields = {}
120
231
  fields[:table_id] = parser.read_uint48
121
232
  fields[:flags] = parser.read_uint16
122
233
  map_entry = @table_map[fields[:table_id]] = {}
@@ -136,6 +247,7 @@ module MysqlBinlog
136
247
  end
137
248
 
138
249
  fields[:map_entry] = map_entry
250
+ fields
139
251
  end
140
252
 
141
253
  # Parse a single row image, which is comprised of a series of columns. Not
@@ -180,11 +292,12 @@ module MysqlBinlog
180
292
  row_images
181
293
  end
182
294
 
183
- # Parse additional fields for any of the row-based replication row events:
295
+ # Parse fields for any of the row-based replication row events:
184
296
  # * +Write_rows+ which is used for +INSERT+.
185
297
  # * +Update_rows+ which is used for +UPDATE+.
186
298
  # * +Delete_rows+ which is used for +DELETE+.
187
- def generic_rows_event(header, fields)
299
+ def generic_rows_event(header)
300
+ fields = {}
188
301
  table_id = parser.read_uint48
189
302
  fields[:table] = @table_map[table_id]
190
303
  fields[:flags] = parser.read_uint16
@@ -200,7 +313,9 @@ module MysqlBinlog
200
313
  columns_used[:after] = parser.read_bit_array(columns)
201
314
  end
202
315
  fields[:row_image] = _generic_rows_event_row_images(header, fields, columns_used)
316
+ fields
203
317
  end
318
+
204
319
  alias :write_rows_event :generic_rows_event
205
320
  alias :update_rows_event :generic_rows_event
206
321
  alias :delete_rows_event :generic_rows_event
@@ -36,7 +36,7 @@ module MysqlBinlog
36
36
  type_array
37
37
  end
38
38
 
39
- class BinlogParser
39
+ class BinlogFieldParser
40
40
  attr_accessor :binlog
41
41
  attr_accessor :reader
42
42
 
@@ -120,11 +120,9 @@ module MysqlBinlog
120
120
  reader.read(length)
121
121
  end
122
122
 
123
- # Read a null-terminated string, provided its length (without the null).
123
+ # Read a null-terminated string, provided its length (with the null).
124
124
  def read_nstringz(length)
125
- string = read_nstring(length)
126
- reader.read(1) # null
127
- string
125
+ reader.read(length).unpack("A*").first
128
126
  end
129
127
 
130
128
  # Read a (Pascal-style) length-prefixed string. The length is stored as a
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mysql_binlog
3
3
  version: !ruby/object:Gem::Version
4
- hash: 19
4
+ hash: 17
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 1
9
- - 4
10
- version: 0.1.4
9
+ - 5
10
+ version: 0.1.5
11
11
  platform: ruby
12
12
  authors:
13
13
  - Jeremy Cole
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-06-25 00:00:00 Z
18
+ date: 2012-06-28 00:00:00 Z
19
19
  dependencies: []
20
20
 
21
21
  description: Library for parsing MySQL binary logs in Ruby
@@ -28,9 +28,9 @@ extra_rdoc_files: []
28
28
 
29
29
  files:
30
30
  - lib/mysql_binlog.rb
31
- - lib/mysql_binlog/mysql_binlog.rb
32
- - lib/mysql_binlog/binlog_parser.rb
33
- - lib/mysql_binlog/binlog_event_field_parser.rb
31
+ - lib/mysql_binlog/binlog.rb
32
+ - lib/mysql_binlog/binlog_field_parser.rb
33
+ - lib/mysql_binlog/binlog_event_parser.rb
34
34
  - lib/mysql_binlog/reader/binlog_file_reader.rb
35
35
  - lib/mysql_binlog/reader/binlog_stream_reader.rb
36
36
  - bin/mysql_binlog_dump
@@ -1,262 +0,0 @@
1
- module MysqlBinlog
2
- # An array to quickly map an integer event type to its symbol.
3
- EVENT_TYPES = [
4
- :unknown_event, # 0
5
- :start_event_v3, # 1
6
- :query_event, # 2
7
- :stop_event, # 3
8
- :rotate_event, # 4
9
- :intvar_event, # 5
10
- :load_event, # 6
11
- :slave_event, # 7
12
- :create_file_event, # 8
13
- :append_block_event, # 9
14
- :exec_load_event, # 10
15
- :delete_file_event, # 11
16
- :new_load_event, # 12
17
- :rand_event, # 13
18
- :user_var_event, # 14
19
- :format_description_event, # 15
20
- :xid_event, # 16
21
- :begin_load_query_event, # 17
22
- :execute_load_query_event, # 18
23
- :table_map_event, # 19
24
- :pre_ga_write_rows_event, # 20
25
- :pre_ga_update_rows_event, # 21
26
- :pre_ga_delete_rows_event, # 22
27
- :write_rows_event, # 23
28
- :update_rows_event, # 24
29
- :delete_rows_event, # 25
30
- :incident_event, # 26
31
- :heartbeat_log_event, # 27
32
- ]
33
-
34
- # A common fixed-length header that is included with each event.
35
- EVENT_HEADER = [
36
- { :name => :timestamp, :length => 4, :format => "V" },
37
- { :name => :event_type, :length => 1, :format => "C" },
38
- { :name => :server_id, :length => 4, :format => "V" },
39
- { :name => :event_length, :length => 4, :format => "V" },
40
- { :name => :next_position, :length => 4, :format => "V" },
41
- { :name => :flags, :length => 2, :format => "v" },
42
- ]
43
-
44
- # Values for the 'flags' field that may appear in binlogs. There are
45
- # several other values that never appear in a file but may be used
46
- # in events in memory.
47
- EVENT_FLAGS = {
48
- :binlog_in_use => 0x01,
49
- :thread_specific => 0x04,
50
- :suppress_use => 0x08,
51
- :artificial => 0x20,
52
- :relay_log => 0x40,
53
- }
54
-
55
- # Format descriptions for fixed-length fields that may appear in the data
56
- # for each event. Additional fields may be dynamic and are parsed by the
57
- # methods in the BinlogEventFieldParser class.
58
- EVENT_FORMATS = {
59
- :format_description_event => [
60
- { :name => :binlog_version, :length => 2, :format => "v" },
61
- { :name => :server_version, :length => 50, :format => "A50" },
62
- { :name => :create_timestamp, :length => 4, :format => "V" },
63
- { :name => :header_length, :length => 1, :format => "C" },
64
- ],
65
- :rotate_event => [
66
- { :name => :pos, :length => 8, :format => "Q" },
67
- ],
68
- :query_event => [
69
- { :name => :thread_id, :length => 4, :format => "V" },
70
- { :name => :elapsed_time, :length => 4, :format => "V" },
71
- { :name => :db_length, :length => 1, :format => "C" },
72
- { :name => :error_code, :length => 2, :format => "v" },
73
- ],
74
- :intvar_event => [
75
- { :name => :intvar_type, :length => 1, :format => "C" },
76
- { :name => :intvar_value, :length => 8, :format => "Q" },
77
- ],
78
- :xid_event => [
79
- { :name => :xid, :length => 8, :format => "Q" },
80
- ],
81
- :rand_event => [ # Untested
82
- { :name => :seed1, :length => 8, :format => "Q" },
83
- { :name => :seed2, :length => 8, :format => "Q" },
84
- ],
85
- }
86
-
87
- class UnsupportedVersionException < Exception; end
88
- class MalformedBinlogException < Exception; end
89
- class ZeroReadException < Exception; end
90
- class ShortReadException < Exception; end
91
-
92
- class Binlog
93
- attr_reader :fde
94
- attr_accessor :reader
95
- attr_accessor :parser
96
- attr_accessor :event_field_parser
97
- attr_accessor :filter_event_types
98
- attr_accessor :filter_flags
99
- attr_accessor :max_query_length
100
-
101
- def initialize(reader)
102
- @reader = reader
103
- @parser = BinlogParser.new(self)
104
- @event_field_parser = BinlogEventFieldParser.new(self)
105
- @fde = nil
106
- @filter_event_types = nil
107
- @filter_flags = nil
108
- @max_query_length = 1048576
109
- end
110
-
111
- # Rewind to the beginning of the log, if supported by the reader. The
112
- # reader may throw an exception if rewinding is not supported (e.g. for
113
- # a stream-based reader).
114
- def rewind
115
- reader.rewind
116
- end
117
-
118
- # Read fixed fields using format definitions in 'unpack' format provided
119
- # in the EVENT_FORMATS hash.
120
- def read_fixed_fields(event_type, header)
121
- if EVENT_FORMATS.include? event_type
122
- parser.read_and_unpack(EVENT_FORMATS[event_type])
123
- end
124
- end
125
-
126
- # Read dynamic fields or fields that require more processing before being
127
- # saved in the event.
128
- def read_additional_fields(event_type, header, fields)
129
- if event_field_parser.methods.include? event_type.to_s
130
- event_field_parser.send(event_type, header, fields)
131
- end
132
- end
133
-
134
- # Skip the remainder of this event. This can be used to skip an entire
135
- # event or merely the parts of the event this library does not understand.
136
- def skip_event(header)
137
- reader.skip(header)
138
- end
139
-
140
- # Read the common header for an event. Every event has a header.
141
- def read_event_header
142
- header = parser.read_and_unpack(EVENT_HEADER)
143
-
144
- # Merge the read 'flags' bitmap with the EVENT_FLAGS hash to return
145
- # the flags by name instead of returning the bitmap as an integer.
146
- flags = EVENT_FLAGS.inject([]) do |result, (flag_name, flag_bit_value)|
147
- if (header[:flags] & flag_bit_value) != 0
148
- result << flag_name
149
- end
150
- result
151
- end
152
-
153
- # Overwrite the integer version of 'flags' with the array of names.
154
- header[:flags] = flags
155
-
156
- header
157
- end
158
-
159
- # Read the content of the event, which consists of an optional fixed field
160
- # portion and an optional dynamic portion.
161
- def read_event_content(header)
162
- event_type = EVENT_TYPES[header[:event_type]]
163
-
164
- # Read the fixed portion of the event, if it is understood, or there is
165
- # one. If not, initialize content with an empty hash instead.
166
- content = read_fixed_fields(event_type, header) || {}
167
-
168
- # Read additional fields from the dynamic portion of the event. Some of
169
- # these may actually be fixed width but needed more processing in a
170
- # function instead of the unpack formats possible in read_fixed_fields.
171
- read_additional_fields(event_type, header, content)
172
-
173
- # Anything left unread at this point is skipped based on the event length
174
- # provided in the header. In this way, it is possible to skip over events
175
- # that are not able to be parsed correctly by this library.
176
- skip_event(header)
177
-
178
- content
179
- end
180
-
181
- # Scan events until finding one that isn't rejected by the filter rules.
182
- # If there are no filter rules, this will return the next event provided
183
- # by the reader.
184
- def read_event
185
- while true
186
- skip_this_event = false
187
- return nil if reader.end?
188
-
189
- filename = reader.filename
190
- position = reader.position
191
-
192
- unless header = read_event_header
193
- return nil
194
- end
195
-
196
- event_type = EVENT_TYPES[header[:event_type]]
197
-
198
- if @filter_event_types
199
- unless @filter_event_types.include? event_type or
200
- event_type == :format_description_event
201
- skip_event(header)
202
- skip_this_event = true
203
- end
204
- end
205
-
206
- if @filter_flags
207
- unless @filter_flags.include? header[:flags]
208
- skip_event(header)
209
- skip_this_event = true
210
- end
211
- end
212
-
213
- # Never skip over rotate_event or format_description_event as they
214
- # are critical to understanding the format of this event stream.
215
- unless [:rotate_event, :format_description_event].include? event_type
216
- next if skip_this_event
217
- end
218
-
219
- content = read_event_content(header)
220
-
221
- case event_type
222
- when :rotate_event
223
- reader.rotate(content[:name], content[:pos])
224
- when :format_description_event
225
- process_fde(content)
226
- end
227
-
228
- break
229
- end
230
-
231
- {
232
- :type => event_type,
233
- :filename => filename,
234
- :position => position,
235
- :header => header,
236
- :event => content,
237
- }
238
- end
239
-
240
- # Process a format description event, which describes the version of this
241
- # file, and the format of events which will appear in this file. This also
242
- # provides the version of the MySQL server which generated this file.
243
- def process_fde(fde)
244
- if (version = fde[:binlog_version]) != 4
245
- raise UnsupportedVersionException.new("Binlog version #{version} is not supported")
246
- end
247
-
248
- @fde = {
249
- :header_length => fde[:header_length],
250
- :binlog_version => fde[:binlog_version],
251
- :server_version => fde[:server_version],
252
- }
253
- end
254
-
255
- # Iterate through all events.
256
- def each_event
257
- while event = read_event
258
- yield event
259
- end
260
- end
261
- end
262
- end