mysql_binlog 0.1.1 → 0.1.2
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.
@@ -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
|