mysql_binlog 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
@@ -4,11 +4,11 @@ module MysqlBinlog
|
|
4
4
|
QUERY_EVENT_STATUS_TYPES = [
|
5
5
|
:flags2, # 0
|
6
6
|
:sql_mode, # 1
|
7
|
-
:
|
7
|
+
:catalog_deprecated, # 2
|
8
8
|
:auto_increment, # 3
|
9
9
|
:charset, # 4
|
10
10
|
:time_zone, # 5
|
11
|
-
:
|
11
|
+
:catalog, # 6
|
12
12
|
:lc_time_names, # 7
|
13
13
|
:charset_database, # 8
|
14
14
|
:table_map_for_update, # 9
|
@@ -58,7 +58,7 @@ module MysqlBinlog
|
|
58
58
|
parser.read_uint32_bitmap_by_name(QUERY_EVENT_FLAGS2)
|
59
59
|
when :sql_mode
|
60
60
|
parser.read_uint64
|
61
|
-
when :
|
61
|
+
when :catalog_deprecated
|
62
62
|
parser.read_lpstringz
|
63
63
|
when :auto_increment
|
64
64
|
{
|
@@ -73,7 +73,7 @@ module MysqlBinlog
|
|
73
73
|
}
|
74
74
|
when :time_zone
|
75
75
|
parser.read_lpstring
|
76
|
-
when :
|
76
|
+
when :catalog
|
77
77
|
parser.read_lpstring
|
78
78
|
when :lc_time_names
|
79
79
|
parser.read_uint16
|
@@ -107,6 +107,13 @@ module MysqlBinlog
|
|
107
107
|
end
|
108
108
|
end
|
109
109
|
|
110
|
+
def _table_map_event_metadata(columns_type)
|
111
|
+
length = parser.read_varint
|
112
|
+
columns_type.map do |c|
|
113
|
+
parser.read_mysql_type_metadata(c)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
110
117
|
# Parse additional fields for a +Table_map+ event.
|
111
118
|
def table_map_event(header, fields)
|
112
119
|
fields[:table_id] = parser.read_uint48
|
@@ -116,13 +123,14 @@ module MysqlBinlog
|
|
116
123
|
map_entry[:table] = parser.read_lpstringz
|
117
124
|
columns = parser.read_varint
|
118
125
|
columns_type = parser.read_uint8_array(columns).map { |c| MYSQL_TYPES[c] }
|
119
|
-
columns_metadata =
|
126
|
+
columns_metadata = _table_map_event_metadata(columns_type)
|
120
127
|
columns_nullable = parser.read_bit_array(columns)
|
121
128
|
|
122
129
|
map_entry[:columns] = columns.times.map do |c|
|
123
130
|
{
|
124
131
|
:type => columns_type[c],
|
125
132
|
:nullable => columns_nullable[c],
|
133
|
+
:metadata => columns_metadata[c],
|
126
134
|
}
|
127
135
|
end
|
128
136
|
|
@@ -132,22 +140,26 @@ module MysqlBinlog
|
|
132
140
|
# Parse the row images present in a row-based replication row event. This
|
133
141
|
# is rather incomplete right now due missing support for many MySQL types,
|
134
142
|
# but can parse some basic events.
|
135
|
-
def _generic_rows_event_row_images(header, fields)
|
143
|
+
def _generic_rows_event_row_images(header, fields, columns_used)
|
144
|
+
row_image_index = 0
|
136
145
|
row_images = []
|
137
146
|
end_position = reader.position + reader.remaining(header)
|
138
147
|
while reader.position < end_position
|
139
148
|
row_image = []
|
140
149
|
columns_null = parser.read_bit_array(fields[:table][:columns].size)
|
141
150
|
fields[:table][:columns].each_with_index do |column, column_index|
|
142
|
-
if !
|
151
|
+
if !columns_used[row_image_index][column_index]
|
143
152
|
row_image << nil
|
144
153
|
elsif columns_null[column_index]
|
145
154
|
row_image << { column => nil }
|
146
155
|
else
|
147
|
-
row_image << {
|
156
|
+
row_image << {
|
157
|
+
column => parser.read_mysql_type(column[:type], column[:metadata])
|
158
|
+
}
|
148
159
|
end
|
149
160
|
end
|
150
161
|
row_images << row_image
|
162
|
+
row_image_index += 1
|
151
163
|
end
|
152
164
|
row_images
|
153
165
|
end
|
@@ -161,12 +173,12 @@ module MysqlBinlog
|
|
161
173
|
fields[:table] = @table_map[table_id]
|
162
174
|
fields[:flags] = parser.read_uint16
|
163
175
|
columns = parser.read_varint
|
164
|
-
|
176
|
+
columns_used = []
|
177
|
+
columns_used[0] = parser.read_bit_array(columns)
|
165
178
|
if EVENT_TYPES[header[:event_type]] == :update_rows_event
|
166
|
-
|
179
|
+
columns_used[1] = parser.read_bit_array(columns)
|
167
180
|
end
|
168
|
-
fields[:row_image] = _generic_rows_event_row_images(header, fields)
|
169
|
-
fields.delete :columns_used
|
181
|
+
fields[:row_image] = _generic_rows_event_row_images(header, fields, columns_used)
|
170
182
|
end
|
171
183
|
alias :write_rows_event :generic_rows_event
|
172
184
|
alias :update_rows_event :generic_rows_event
|
@@ -88,13 +88,31 @@ module MysqlBinlog
|
|
88
88
|
reader.read(8).unpack("G").first
|
89
89
|
end
|
90
90
|
|
91
|
-
# Read a variable-length
|
92
|
-
#
|
93
|
-
#
|
94
|
-
#
|
91
|
+
# Read a variable-length "Length Coded Binary" integer. This is derived
|
92
|
+
# from the MySQL protocol, and re-used in the binary log format. This
|
93
|
+
# format uses the first byte to alternately store the actual value for
|
94
|
+
# integer values <= 250, or to encode the number of following bytes
|
95
|
+
# used to store the actual value, which can be 2, 3, or 8. It also
|
96
|
+
# includes support for SQL NULL as a special case.
|
97
|
+
#
|
98
|
+
# See: http://forge.mysql.com/wiki/MySQL_Internals_ClientServer_Protocol#Elements
|
95
99
|
def read_varint
|
96
|
-
|
97
|
-
|
100
|
+
first_byte = read_uint8
|
101
|
+
|
102
|
+
case
|
103
|
+
when first_byte <= 250
|
104
|
+
first_byte
|
105
|
+
when first_byte == 251
|
106
|
+
nil
|
107
|
+
when first_byte == 252
|
108
|
+
read_uint16
|
109
|
+
when first_byte == 253
|
110
|
+
read_uint24
|
111
|
+
when first_byte == 254
|
112
|
+
read_uint64
|
113
|
+
when first_byte == 255
|
114
|
+
raise "Invalid variable-length integer"
|
115
|
+
end
|
98
116
|
end
|
99
117
|
|
100
118
|
# Read a non-terminated string, provided its length.
|
@@ -110,17 +128,36 @@ module MysqlBinlog
|
|
110
128
|
end
|
111
129
|
|
112
130
|
# Read a (Pascal-style) length-prefixed string. The length is stored as a
|
113
|
-
# 8-bit (1-byte) unsigned integer
|
114
|
-
#
|
115
|
-
|
116
|
-
|
131
|
+
# 8-bit (1-byte) to 32-bit (4-byte) unsigned integer, depending on the
|
132
|
+
# optional size parameter (default 1), followed by the string itself with
|
133
|
+
# no termination character.
|
134
|
+
def read_lpstring(size=1)
|
135
|
+
case size
|
136
|
+
when 1
|
137
|
+
length = read_uint8
|
138
|
+
when 2
|
139
|
+
length = read_uint16
|
140
|
+
when 3
|
141
|
+
length = read_uint24
|
142
|
+
when 4
|
143
|
+
length = read_uint32
|
144
|
+
end
|
117
145
|
read_nstring(length)
|
118
146
|
end
|
119
147
|
|
120
|
-
# Read an lpstring which is also terminated with a null byte.
|
121
|
-
def read_lpstringz
|
122
|
-
|
123
|
-
|
148
|
+
# Read an lpstring (as above) which is also terminated with a null byte.
|
149
|
+
def read_lpstringz(size=1)
|
150
|
+
string = read_lpstring(size)
|
151
|
+
reader.read(1) # null
|
152
|
+
string
|
153
|
+
end
|
154
|
+
|
155
|
+
# Read a MySQL-style varint length-prefixed string. The length is stored
|
156
|
+
# as a variable-length "Length Coded Binary" value (see read_varint) which
|
157
|
+
# is followed by the string content itself. No termination is included.
|
158
|
+
def read_varstring
|
159
|
+
length = read_varint
|
160
|
+
read_nstring(length)
|
124
161
|
end
|
125
162
|
|
126
163
|
# Read an array of unsigned 8-bit (1-byte) integers.
|
@@ -135,6 +172,8 @@ module MysqlBinlog
|
|
135
172
|
data.unpack("b*").first.bytes.to_a.map { |i| (i-48) == 1 }.shift(length)
|
136
173
|
end
|
137
174
|
|
175
|
+
# Read a uint32 value, and convert it to an array of symbols derived
|
176
|
+
# from a mapping table provided.
|
138
177
|
def read_uint32_bitmap_by_name(names)
|
139
178
|
value = read_uint32
|
140
179
|
names.inject([]) do |result, (name, bit_value)|
|
@@ -164,11 +203,35 @@ module MysqlBinlog
|
|
164
203
|
fields
|
165
204
|
end
|
166
205
|
|
206
|
+
def read_mysql_type_metadata(column_type)
|
207
|
+
case column_type
|
208
|
+
when :float, :double
|
209
|
+
{ :size => read_uint8 }
|
210
|
+
when :varchar
|
211
|
+
{ :max_length => read_uint16 }
|
212
|
+
when :bit
|
213
|
+
{ :size => read_uint8 }
|
214
|
+
when :decimal
|
215
|
+
{
|
216
|
+
:precision => read_uint8,
|
217
|
+
:decimals => read_uint8,
|
218
|
+
}
|
219
|
+
when :blob
|
220
|
+
{ :length_size => read_uint8 }
|
221
|
+
when :var_string, :string
|
222
|
+
{
|
223
|
+
:real_type => read_uint8,
|
224
|
+
:length_size => read_uint8,
|
225
|
+
}
|
226
|
+
when :geometry
|
227
|
+
{ :length_size => read_uint8 }
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
167
231
|
# Read a single field, provided the MySQL column type as a symbol. Not all
|
168
232
|
# types are currently supported.
|
169
|
-
def read_mysql_type(
|
170
|
-
case
|
171
|
-
#when :decimal
|
233
|
+
def read_mysql_type(type, metadata=nil)
|
234
|
+
case type
|
172
235
|
when :tiny
|
173
236
|
read_uint8
|
174
237
|
when :short
|
@@ -179,33 +242,27 @@ module MysqlBinlog
|
|
179
242
|
read_uint32
|
180
243
|
when :longlong
|
181
244
|
read_uint64
|
182
|
-
when :string
|
183
|
-
length = read_varint
|
184
|
-
read_nstring(length)
|
185
|
-
|
186
245
|
when :float
|
187
246
|
read_float
|
188
247
|
when :double
|
189
248
|
read_double
|
190
|
-
|
249
|
+
when :string, :var_string
|
250
|
+
read_varstring
|
251
|
+
when :varchar, :blob
|
252
|
+
read_lpstring(metadata[:length_size])
|
191
253
|
when :timestamp
|
192
254
|
read_uint32
|
255
|
+
when :year
|
256
|
+
read_uint8 + 1900
|
193
257
|
#when :date
|
194
258
|
#when :time
|
195
259
|
#when :datetime
|
196
|
-
#when :year
|
197
260
|
#when :newdate
|
198
|
-
#when :varchar
|
199
261
|
#when :bit
|
262
|
+
#when :decimal
|
200
263
|
#when :newdecimal
|
201
264
|
#when :enum
|
202
265
|
#when :set
|
203
|
-
#when :tiny_blob
|
204
|
-
#when :medium_blob
|
205
|
-
#when :long_blob
|
206
|
-
#when :blob
|
207
|
-
#when :var_string
|
208
|
-
#when :string
|
209
266
|
#when :geometry
|
210
267
|
end
|
211
268
|
end
|
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:
|
4
|
+
hash: 31
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 0.1.
|
9
|
+
- 2
|
10
|
+
version: 0.1.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Jeremy Cole
|