mysql_binlog 0.1.4 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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