innodb_ruby 0.9.14 → 0.12.0
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.
- checksums.yaml +7 -0
- data/README.md +5 -6
- data/bin/innodb_log +13 -18
- data/bin/innodb_space +654 -778
- data/lib/innodb/checksum.rb +26 -24
- data/lib/innodb/data_dictionary.rb +490 -550
- data/lib/innodb/data_type.rb +362 -325
- data/lib/innodb/field.rb +102 -89
- data/lib/innodb/fseg_entry.rb +22 -26
- data/lib/innodb/history.rb +21 -21
- data/lib/innodb/history_list.rb +72 -76
- data/lib/innodb/ibuf_bitmap.rb +36 -36
- data/lib/innodb/ibuf_index.rb +6 -2
- data/lib/innodb/index.rb +245 -276
- data/lib/innodb/inode.rb +166 -124
- data/lib/innodb/list.rb +196 -183
- data/lib/innodb/log.rb +139 -110
- data/lib/innodb/log_block.rb +100 -91
- data/lib/innodb/log_group.rb +53 -64
- data/lib/innodb/log_reader.rb +97 -96
- data/lib/innodb/log_record.rb +328 -279
- data/lib/innodb/lsn.rb +86 -81
- data/lib/innodb/page/blob.rb +82 -83
- data/lib/innodb/page/fsp_hdr_xdes.rb +174 -165
- data/lib/innodb/page/ibuf_bitmap.rb +34 -34
- data/lib/innodb/page/index.rb +965 -924
- data/lib/innodb/page/index_compressed.rb +34 -34
- data/lib/innodb/page/inode.rb +103 -112
- data/lib/innodb/page/sys.rb +13 -15
- data/lib/innodb/page/sys_data_dictionary_header.rb +81 -59
- data/lib/innodb/page/sys_ibuf_header.rb +45 -42
- data/lib/innodb/page/sys_rseg_header.rb +88 -82
- data/lib/innodb/page/trx_sys.rb +204 -182
- data/lib/innodb/page/undo_log.rb +106 -92
- data/lib/innodb/page.rb +417 -414
- data/lib/innodb/record.rb +121 -164
- data/lib/innodb/record_describer.rb +66 -68
- data/lib/innodb/space.rb +381 -413
- data/lib/innodb/stats.rb +33 -35
- data/lib/innodb/system.rb +149 -171
- data/lib/innodb/undo_log.rb +129 -107
- data/lib/innodb/undo_record.rb +255 -247
- data/lib/innodb/util/buffer_cursor.rb +81 -79
- data/lib/innodb/util/read_bits_at_offset.rb +2 -1
- data/lib/innodb/version.rb +2 -2
- data/lib/innodb/xdes.rb +144 -142
- data/lib/innodb.rb +4 -5
- metadata +100 -25
data/lib/innodb/data_type.rb
CHANGED
@@ -1,415 +1,452 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "stringio"
|
4
4
|
require "bigdecimal"
|
5
5
|
require "date"
|
6
6
|
|
7
|
-
|
7
|
+
module Innodb
|
8
|
+
class DataType
|
9
|
+
# MySQL's Bit-Value Type (BIT).
|
10
|
+
class BitType
|
11
|
+
attr_reader :name
|
12
|
+
attr_reader :width
|
8
13
|
|
9
|
-
|
10
|
-
|
11
|
-
|
14
|
+
def initialize(base_type, modifiers, properties)
|
15
|
+
nbits = modifiers.fetch(0, 1)
|
16
|
+
raise "Unsupported width for BIT type." unless nbits >= 0 && nbits <= 64
|
12
17
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
@width = (nbits + 7) / 8
|
17
|
-
@name = Innodb::DataType.make_name(base_type, modifiers, properties)
|
18
|
-
end
|
18
|
+
@width = (nbits + 7) / 8
|
19
|
+
@name = Innodb::DataType.make_name(base_type, modifiers, properties)
|
20
|
+
end
|
19
21
|
|
20
|
-
|
21
|
-
|
22
|
+
def value(data)
|
23
|
+
"0b%b" % BinData.const_get("Uint%dbe" % (@width * 8)).read(data)
|
24
|
+
end
|
22
25
|
end
|
23
|
-
end
|
24
26
|
|
25
|
-
|
26
|
-
|
27
|
+
class IntegerType
|
28
|
+
attr_reader :name
|
29
|
+
attr_reader :width
|
27
30
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
31
|
+
def initialize(base_type, modifiers, properties)
|
32
|
+
@width = base_type_width_map[base_type]
|
33
|
+
@unsigned = properties.include?(:UNSIGNED)
|
34
|
+
@name = Innodb::DataType.make_name(base_type, modifiers, properties)
|
35
|
+
end
|
33
36
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
37
|
+
def base_type_width_map
|
38
|
+
{
|
39
|
+
BOOL: 1,
|
40
|
+
BOOLEAN: 1,
|
41
|
+
TINYINT: 1,
|
42
|
+
SMALLINT: 2,
|
43
|
+
MEDIUMINT: 3,
|
44
|
+
INT: 4,
|
45
|
+
INT6: 6,
|
46
|
+
BIGINT: 8,
|
47
|
+
}
|
48
|
+
end
|
46
49
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
50
|
+
def value(data)
|
51
|
+
nbits = @width * 8
|
52
|
+
@unsigned ? get_uint(data, nbits) : get_int(data, nbits)
|
53
|
+
end
|
51
54
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
+
def get_uint(data, nbits)
|
56
|
+
BinData.const_get("Uint%dbe" % nbits).read(data)
|
57
|
+
end
|
55
58
|
|
56
|
-
|
57
|
-
|
59
|
+
def get_int(data, nbits)
|
60
|
+
BinData.const_get("Int%dbe" % nbits).read(data) ^ (-1 << (nbits - 1))
|
61
|
+
end
|
58
62
|
end
|
59
|
-
end
|
60
63
|
|
61
|
-
|
62
|
-
|
64
|
+
class FloatType
|
65
|
+
attr_reader :name
|
66
|
+
attr_reader :width
|
63
67
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
+
def initialize(base_type, modifiers, properties)
|
69
|
+
@width = 4
|
70
|
+
@name = Innodb::DataType.make_name(base_type, modifiers, properties)
|
71
|
+
end
|
68
72
|
|
69
|
-
|
70
|
-
|
71
|
-
|
73
|
+
# Read a little-endian single-precision floating-point number.
|
74
|
+
def value(data)
|
75
|
+
BinData::FloatLe.read(data)
|
76
|
+
end
|
72
77
|
end
|
73
|
-
end
|
74
78
|
|
75
|
-
|
76
|
-
|
79
|
+
class DoubleType
|
80
|
+
attr_reader :name
|
81
|
+
attr_reader :width
|
77
82
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
83
|
+
def initialize(base_type, modifiers, properties)
|
84
|
+
@width = 8
|
85
|
+
@name = Innodb::DataType.make_name(base_type, modifiers, properties)
|
86
|
+
end
|
82
87
|
|
83
|
-
|
84
|
-
|
85
|
-
|
88
|
+
# Read a little-endian double-precision floating-point number.
|
89
|
+
def value(data)
|
90
|
+
BinData::DoubleLe.read(data)
|
91
|
+
end
|
86
92
|
end
|
87
|
-
end
|
88
93
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
94
|
+
# MySQL's Fixed-Point Type (DECIMAL), stored in InnoDB as a binary string.
|
95
|
+
class DecimalType
|
96
|
+
attr_reader :name
|
97
|
+
attr_reader :width
|
98
|
+
|
99
|
+
# The value is stored as a sequence of signed big-endian integers, each
|
100
|
+
# representing up to 9 digits of the integral and fractional parts. The
|
101
|
+
# first integer of the integral part and/or the last integer of the
|
102
|
+
# fractional part might be compressed (or packed) and are of variable
|
103
|
+
# length. The remaining integers (if any) are uncompressed and 32 bits
|
104
|
+
# wide.
|
105
|
+
MAX_DIGITS_PER_INTEGER = 9
|
106
|
+
BYTES_PER_DIGIT = [0, 1, 1, 2, 2, 3, 3, 4, 4, 4].freeze
|
107
|
+
|
108
|
+
def initialize(base_type, modifiers, properties)
|
109
|
+
precision, scale = sanity_check(modifiers)
|
110
|
+
integral = precision - scale
|
111
|
+
@uncomp_integral = integral / MAX_DIGITS_PER_INTEGER
|
112
|
+
@uncomp_fractional = scale / MAX_DIGITS_PER_INTEGER
|
113
|
+
@comp_integral = integral - (@uncomp_integral * MAX_DIGITS_PER_INTEGER)
|
114
|
+
@comp_fractional = scale - (@uncomp_fractional * MAX_DIGITS_PER_INTEGER)
|
115
|
+
@width = @uncomp_integral * 4 + BYTES_PER_DIGIT[@comp_integral] +
|
116
|
+
@comp_fractional * 4 + BYTES_PER_DIGIT[@comp_fractional]
|
117
|
+
@name = Innodb::DataType.make_name(base_type, modifiers, properties)
|
118
|
+
end
|
113
119
|
|
114
|
-
|
115
|
-
|
116
|
-
|
120
|
+
def value(data)
|
121
|
+
# Strings representing the integral and fractional parts.
|
122
|
+
intg = "".dup
|
123
|
+
frac = "".dup
|
117
124
|
|
118
|
-
|
119
|
-
|
125
|
+
stream = StringIO.new(data)
|
126
|
+
mask = sign_mask(stream)
|
120
127
|
|
121
|
-
|
128
|
+
intg << get_digits(stream, mask, @comp_integral)
|
122
129
|
|
123
|
-
|
124
|
-
|
125
|
-
|
130
|
+
(1..@uncomp_integral).each do
|
131
|
+
intg << get_digits(stream, mask, MAX_DIGITS_PER_INTEGER)
|
132
|
+
end
|
133
|
+
|
134
|
+
(1..@uncomp_fractional).each do
|
135
|
+
frac << get_digits(stream, mask, MAX_DIGITS_PER_INTEGER)
|
136
|
+
end
|
137
|
+
|
138
|
+
frac << get_digits(stream, mask, @comp_fractional)
|
139
|
+
frac = "0" if frac.empty?
|
140
|
+
|
141
|
+
# Convert to something resembling a string representation.
|
142
|
+
str = "#{mask.to_s.chop}#{intg}.#{frac}"
|
126
143
|
|
127
|
-
|
128
|
-
frac << get_digits(stream, mask, MAX_DIGITS_PER_INTEGER)
|
144
|
+
BigDecimal(str).to_s("F")
|
129
145
|
end
|
130
146
|
|
131
|
-
|
147
|
+
private
|
132
148
|
|
133
|
-
#
|
134
|
-
|
149
|
+
# Ensure width specification (if any) is compliant.
|
150
|
+
def sanity_check(modifiers)
|
151
|
+
raise "Invalid width specification" unless modifiers.size <= 2
|
135
152
|
|
136
|
-
|
137
|
-
|
153
|
+
precision = modifiers.fetch(0, 10)
|
154
|
+
raise "Unsupported precision for DECIMAL type" unless precision >= 1 && precision <= 65
|
138
155
|
|
139
|
-
|
140
|
-
|
141
|
-
# Ensure width specification (if any) is compliant.
|
142
|
-
def sanity_check(modifiers)
|
143
|
-
raise "Invalid width specification" unless modifiers.size <= 2
|
144
|
-
precision = modifiers.fetch(0, 10)
|
145
|
-
raise "Unsupported precision for DECIMAL type" unless
|
146
|
-
precision >= 1 and precision <= 65
|
147
|
-
scale = modifiers.fetch(1, 0)
|
148
|
-
raise "Unsupported scale for DECIMAL type" unless
|
149
|
-
scale >= 0 and scale <= 30 and scale <= precision
|
150
|
-
[precision, scale]
|
151
|
-
end
|
156
|
+
scale = modifiers.fetch(1, 0)
|
157
|
+
raise "Unsupported scale for DECIMAL type" unless scale >= 0 && scale <= 30 && scale <= precision
|
152
158
|
|
153
|
-
|
154
|
-
|
155
|
-
# back the byte into the stream.
|
156
|
-
def sign_mask(stream)
|
157
|
-
byte = BinData::Uint8.read(stream)
|
158
|
-
sign = byte & 0x80
|
159
|
-
byte.assign(byte ^ 0x80)
|
160
|
-
stream.rewind
|
161
|
-
byte.write(stream)
|
162
|
-
stream.rewind
|
163
|
-
(sign == 0) ? -1 : 0
|
164
|
-
end
|
159
|
+
[precision, scale]
|
160
|
+
end
|
165
161
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
162
|
+
# The sign is encoded in the high bit of the first byte/digit. The byte
|
163
|
+
# might be part of a larger integer, so apply the bit-flipper and push
|
164
|
+
# back the byte into the stream.
|
165
|
+
def sign_mask(stream)
|
166
|
+
byte = BinData::Uint8.read(stream)
|
167
|
+
sign = byte & 0x80
|
168
|
+
byte.assign(byte ^ 0x80)
|
169
|
+
stream.rewind
|
170
|
+
byte.write(stream)
|
171
|
+
stream.rewind
|
172
|
+
sign.zero? ? -1 : 0
|
173
|
+
end
|
175
174
|
|
176
|
-
|
177
|
-
|
178
|
-
|
175
|
+
# Return a string representing an integer with a specific number of digits.
|
176
|
+
def get_digits(stream, mask, digits)
|
177
|
+
nbits = BYTES_PER_DIGIT[digits] * 8
|
178
|
+
return "" unless nbits.positive?
|
179
179
|
|
180
|
-
|
181
|
-
|
182
|
-
|
180
|
+
value = (BinData.const_get("Int%dbe" % nbits).read(stream) ^ mask)
|
181
|
+
# Preserve leading zeros.
|
182
|
+
"%0#{digits}d" % value
|
183
|
+
end
|
183
184
|
end
|
184
185
|
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
end
|
190
|
-
end
|
186
|
+
# Fixed-length character type.
|
187
|
+
class CharacterType
|
188
|
+
attr_reader :name
|
189
|
+
attr_reader :width
|
191
190
|
|
192
|
-
|
193
|
-
|
191
|
+
def initialize(base_type, modifiers, properties)
|
192
|
+
@width = modifiers.fetch(0, 1)
|
193
|
+
@name = Innodb::DataType.make_name(base_type, modifiers, properties)
|
194
|
+
end
|
194
195
|
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
196
|
+
def value(data)
|
197
|
+
# The SQL standard defines that CHAR fields should have end-spaces
|
198
|
+
# stripped off.
|
199
|
+
data.sub(/ +$/, "")
|
200
|
+
end
|
199
201
|
end
|
200
202
|
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
data.sub(/[ ]+$/, "")
|
205
|
-
end
|
206
|
-
end
|
203
|
+
class VariableCharacterType
|
204
|
+
attr_reader :name
|
205
|
+
attr_reader :width
|
207
206
|
|
208
|
-
|
209
|
-
|
210
|
-
|
207
|
+
def initialize(base_type, modifiers, properties)
|
208
|
+
@width = modifiers[0]
|
209
|
+
raise "Invalid width specification" unless modifiers.size == 1
|
210
|
+
|
211
|
+
@name = Innodb::DataType.make_name(base_type, modifiers, properties)
|
212
|
+
end
|
211
213
|
|
212
|
-
|
213
|
-
|
214
|
-
|
214
|
+
def value(data)
|
215
|
+
# The SQL standard defines that VARCHAR fields should have end-spaces
|
216
|
+
# stripped off.
|
217
|
+
data.sub(/ +$/, "")
|
218
|
+
end
|
215
219
|
end
|
216
|
-
end
|
217
220
|
|
218
|
-
|
219
|
-
|
221
|
+
# Fixed-length binary type.
|
222
|
+
class BinaryType
|
223
|
+
attr_reader :name
|
224
|
+
attr_reader :width
|
220
225
|
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
226
|
+
def initialize(base_type, modifiers, properties)
|
227
|
+
@width = modifiers.fetch(0, 1)
|
228
|
+
@name = Innodb::DataType.make_name(base_type, modifiers, properties)
|
229
|
+
end
|
225
230
|
end
|
226
|
-
end
|
227
231
|
|
228
|
-
|
229
|
-
|
232
|
+
class VariableBinaryType
|
233
|
+
attr_reader :name
|
234
|
+
attr_reader :width
|
235
|
+
|
236
|
+
def initialize(base_type, modifiers, properties)
|
237
|
+
@width = modifiers[0]
|
238
|
+
raise "Invalid width specification" unless modifiers.size == 1
|
230
239
|
|
231
|
-
|
232
|
-
|
240
|
+
@name = Innodb::DataType.make_name(base_type, modifiers, properties)
|
241
|
+
end
|
233
242
|
end
|
234
|
-
end
|
235
243
|
|
236
|
-
|
237
|
-
|
244
|
+
class BlobType
|
245
|
+
attr_reader :name
|
238
246
|
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
@name = Innodb::DataType.make_name(base_type, modifiers, properties)
|
247
|
+
def initialize(base_type, modifiers, properties)
|
248
|
+
@name = Innodb::DataType.make_name(base_type, modifiers, properties)
|
249
|
+
end
|
243
250
|
end
|
244
251
|
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
return (year + 1900).to_s if year != 0
|
249
|
-
"0000"
|
250
|
-
end
|
251
|
-
end
|
252
|
+
class YearType
|
253
|
+
attr_reader :name
|
254
|
+
attr_reader :width
|
252
255
|
|
253
|
-
|
254
|
-
|
256
|
+
def initialize(base_type, modifiers, properties)
|
257
|
+
@width = 1
|
258
|
+
@display_width = modifiers.fetch(0, 4)
|
259
|
+
@name = Innodb::DataType.make_name(base_type, modifiers, properties)
|
260
|
+
end
|
255
261
|
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
262
|
+
def value(data)
|
263
|
+
year = BinData::Uint8.read(data)
|
264
|
+
return (year % 100).to_s if @display_width != 4
|
265
|
+
return (year + 1900).to_s if year != 0
|
260
266
|
|
261
|
-
|
262
|
-
|
263
|
-
sign = "-" if time < 0
|
264
|
-
time = time.abs
|
265
|
-
"%s%02d:%02d:%02d" % [sign, time / 10000, (time / 100) % 100, time % 100]
|
267
|
+
"0000"
|
268
|
+
end
|
266
269
|
end
|
267
|
-
end
|
268
270
|
|
269
|
-
|
270
|
-
|
271
|
+
class TimeType
|
272
|
+
attr_reader :name
|
273
|
+
attr_reader :width
|
271
274
|
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
275
|
+
def initialize(base_type, modifiers, properties)
|
276
|
+
@width = 3
|
277
|
+
@name = Innodb::DataType.make_name(base_type, modifiers, properties)
|
278
|
+
end
|
276
279
|
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
280
|
+
def value(data)
|
281
|
+
time = BinData::Int24be.read(data) ^ (-1 << 23)
|
282
|
+
sign = "-" if time.negative?
|
283
|
+
time = time.abs
|
284
|
+
"%s%02d:%02d:%02d" % [sign, time / 10_000, (time / 100) % 100, time % 100]
|
285
|
+
end
|
283
286
|
end
|
284
|
-
end
|
285
287
|
|
286
|
-
|
287
|
-
|
288
|
+
class DateType
|
289
|
+
attr_reader :name
|
290
|
+
attr_reader :width
|
288
291
|
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
292
|
+
def initialize(base_type, modifiers, properties)
|
293
|
+
@width = 3
|
294
|
+
@name = Innodb::DataType.make_name(base_type, modifiers, properties)
|
295
|
+
end
|
293
296
|
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
297
|
+
def value(data)
|
298
|
+
date = BinData::Int24be.read(data) ^ (-1 << 23)
|
299
|
+
day = date & 0x1f
|
300
|
+
month = (date >> 5) & 0xf
|
301
|
+
year = date >> 9
|
302
|
+
"%04d-%02d-%02d" % [year, month, day]
|
303
|
+
end
|
301
304
|
end
|
302
|
-
end
|
303
305
|
|
304
|
-
|
305
|
-
|
306
|
+
class DatetimeType
|
307
|
+
attr_reader :name
|
308
|
+
attr_reader :width
|
306
309
|
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
310
|
+
def initialize(base_type, modifiers, properties)
|
311
|
+
@width = 8
|
312
|
+
@name = Innodb::DataType.make_name(base_type, modifiers, properties)
|
313
|
+
end
|
311
314
|
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
315
|
+
def value(data)
|
316
|
+
datetime = BinData::Int64be.read(data) ^ (-1 << 63)
|
317
|
+
date = datetime / 1_000_000
|
318
|
+
year = date / 10_000
|
319
|
+
month = (date / 100) % 100
|
320
|
+
day = date % 100
|
321
|
+
time = datetime - (date * 1_000_000)
|
322
|
+
hour = time / 10_000
|
323
|
+
min = (time / 100) % 100
|
324
|
+
sec = time % 100
|
325
|
+
"%04d-%02d-%02d %02d:%02d:%02d" % [year, month, day, hour, min, sec]
|
326
|
+
end
|
317
327
|
end
|
318
|
-
end
|
319
328
|
|
320
|
-
|
321
|
-
|
322
|
-
|
329
|
+
class TimestampType
|
330
|
+
attr_reader :name
|
331
|
+
attr_reader :width
|
323
332
|
|
324
|
-
|
325
|
-
|
326
|
-
|
333
|
+
def initialize(base_type, modifiers, properties)
|
334
|
+
@width = 4
|
335
|
+
@name = Innodb::DataType.make_name(base_type, modifiers, properties)
|
336
|
+
end
|
327
337
|
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
338
|
+
# Returns the UTC timestamp as a value in 'YYYY-MM-DD HH:MM:SS' format.
|
339
|
+
def value(data)
|
340
|
+
timestamp = BinData::Uint32be.read(data)
|
341
|
+
return "0000-00-00 00:00:00" if timestamp.zero?
|
332
342
|
|
333
|
-
|
334
|
-
|
343
|
+
DateTime.strptime(timestamp.to_s, "%s").strftime "%Y-%m-%d %H:%M:%S"
|
344
|
+
end
|
335
345
|
end
|
336
|
-
end
|
337
346
|
|
338
|
-
|
339
|
-
|
340
|
-
|
347
|
+
#
|
348
|
+
# Data types for InnoDB system columns.
|
349
|
+
#
|
341
350
|
|
342
|
-
|
351
|
+
# Transaction ID.
|
352
|
+
class TransactionIdType
|
353
|
+
attr_reader :name
|
354
|
+
attr_reader :width
|
343
355
|
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
356
|
+
def initialize(base_type, modifiers, properties)
|
357
|
+
@width = 6
|
358
|
+
@name = Innodb::DataType.make_name(base_type, modifiers, properties)
|
359
|
+
end
|
348
360
|
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
:rseg_id => read_bits_at_offset(roll_ptr, 7, 48),
|
353
|
-
:undo_log => {
|
354
|
-
:page => read_bits_at_offset(roll_ptr, 32, 16),
|
355
|
-
:offset => read_bits_at_offset(roll_ptr, 16, 0),
|
356
|
-
}
|
357
|
-
}
|
361
|
+
def read(cursor)
|
362
|
+
cursor.name("transaction_id") { cursor.read_uint48 }
|
363
|
+
end
|
358
364
|
end
|
359
365
|
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
end
|
366
|
+
# Rollback data pointer.
|
367
|
+
class RollPointerType
|
368
|
+
extend ReadBitsAtOffset
|
364
369
|
|
365
|
-
|
370
|
+
Pointer = Struct.new(
|
371
|
+
:is_insert,
|
372
|
+
:rseg_id,
|
373
|
+
:undo_log,
|
374
|
+
keyword_init: true
|
375
|
+
)
|
366
376
|
|
367
|
-
|
368
|
-
|
369
|
-
:BIT => BitType,
|
370
|
-
:BOOL => IntegerType,
|
371
|
-
:BOOLEAN => IntegerType,
|
372
|
-
:TINYINT => IntegerType,
|
373
|
-
:SMALLINT => IntegerType,
|
374
|
-
:MEDIUMINT => IntegerType,
|
375
|
-
:INT => IntegerType,
|
376
|
-
:INT6 => IntegerType,
|
377
|
-
:BIGINT => IntegerType,
|
378
|
-
:FLOAT => FloatType,
|
379
|
-
:DOUBLE => DoubleType,
|
380
|
-
:DECIMAL => DecimalType,
|
381
|
-
:NUMERIC => DecimalType,
|
382
|
-
:CHAR => CharacterType,
|
383
|
-
:VARCHAR => VariableCharacterType,
|
384
|
-
:BINARY => BinaryType,
|
385
|
-
:VARBINARY => VariableBinaryType,
|
386
|
-
:TINYBLOB => BlobType,
|
387
|
-
:BLOB => BlobType,
|
388
|
-
:MEDIUMBLOB => BlobType,
|
389
|
-
:LONGBLOB => BlobType,
|
390
|
-
:TINYTEXT => BlobType,
|
391
|
-
:TEXT => BlobType,
|
392
|
-
:MEDIUMTEXT => BlobType,
|
393
|
-
:LONGTEXT => BlobType,
|
394
|
-
:YEAR => YearType,
|
395
|
-
:TIME => TimeType,
|
396
|
-
:DATE => DateType,
|
397
|
-
:DATETIME => DatetimeType,
|
398
|
-
:TIMESTAMP => TimestampType,
|
399
|
-
:TRX_ID => TransactionIdType,
|
400
|
-
:ROLL_PTR => RollPointerType,
|
401
|
-
}
|
402
|
-
|
403
|
-
def self.make_name(base_type, modifiers, properties)
|
404
|
-
name = base_type.to_s
|
405
|
-
name << '(' + modifiers.join(',') + ')' if not modifiers.empty?
|
406
|
-
name << " "
|
407
|
-
name << properties.join(' ')
|
408
|
-
name.strip
|
409
|
-
end
|
377
|
+
attr_reader :name
|
378
|
+
attr_reader :width
|
410
379
|
|
411
|
-
|
412
|
-
|
413
|
-
|
380
|
+
def initialize(base_type, modifiers, properties)
|
381
|
+
@width = 7
|
382
|
+
@name = Innodb::DataType.make_name(base_type, modifiers, properties)
|
383
|
+
end
|
384
|
+
|
385
|
+
def self.parse_roll_pointer(roll_ptr)
|
386
|
+
Pointer.new(
|
387
|
+
is_insert: read_bits_at_offset(roll_ptr, 1, 55) == 1,
|
388
|
+
rseg_id: read_bits_at_offset(roll_ptr, 7, 48),
|
389
|
+
undo_log: Innodb::Page::Address.new(
|
390
|
+
page: read_bits_at_offset(roll_ptr, 32, 16),
|
391
|
+
offset: read_bits_at_offset(roll_ptr, 16, 0)
|
392
|
+
)
|
393
|
+
)
|
394
|
+
end
|
395
|
+
|
396
|
+
def value(data)
|
397
|
+
roll_ptr = BinData::Uint56be.read(data)
|
398
|
+
self.class.parse_roll_pointer(roll_ptr)
|
399
|
+
end
|
400
|
+
end
|
401
|
+
|
402
|
+
# Maps base type to data type class.
|
403
|
+
TYPES = {
|
404
|
+
BIT: BitType,
|
405
|
+
BOOL: IntegerType,
|
406
|
+
BOOLEAN: IntegerType,
|
407
|
+
TINYINT: IntegerType,
|
408
|
+
SMALLINT: IntegerType,
|
409
|
+
MEDIUMINT: IntegerType,
|
410
|
+
INT: IntegerType,
|
411
|
+
INT6: IntegerType,
|
412
|
+
BIGINT: IntegerType,
|
413
|
+
FLOAT: FloatType,
|
414
|
+
DOUBLE: DoubleType,
|
415
|
+
DECIMAL: DecimalType,
|
416
|
+
NUMERIC: DecimalType,
|
417
|
+
CHAR: CharacterType,
|
418
|
+
VARCHAR: VariableCharacterType,
|
419
|
+
BINARY: BinaryType,
|
420
|
+
VARBINARY: VariableBinaryType,
|
421
|
+
TINYBLOB: BlobType,
|
422
|
+
BLOB: BlobType,
|
423
|
+
MEDIUMBLOB: BlobType,
|
424
|
+
LONGBLOB: BlobType,
|
425
|
+
TINYTEXT: BlobType,
|
426
|
+
TEXT: BlobType,
|
427
|
+
MEDIUMTEXT: BlobType,
|
428
|
+
LONGTEXT: BlobType,
|
429
|
+
YEAR: YearType,
|
430
|
+
TIME: TimeType,
|
431
|
+
DATE: DateType,
|
432
|
+
DATETIME: DatetimeType,
|
433
|
+
TIMESTAMP: TimestampType,
|
434
|
+
TRX_ID: TransactionIdType,
|
435
|
+
ROLL_PTR: RollPointerType,
|
436
|
+
}.freeze
|
437
|
+
|
438
|
+
def self.make_name(base_type, modifiers, properties)
|
439
|
+
name = base_type.to_s.dup
|
440
|
+
name << "(#{modifiers.join(',')})" unless modifiers.empty?
|
441
|
+
name << " "
|
442
|
+
name << properties.join(" ")
|
443
|
+
name.strip
|
444
|
+
end
|
445
|
+
|
446
|
+
def self.new(base_type, modifiers, properties)
|
447
|
+
raise "Data type '#{base_type}' is not supported" unless TYPES.key?(base_type)
|
448
|
+
|
449
|
+
TYPES[base_type].new(base_type, modifiers, properties)
|
450
|
+
end
|
414
451
|
end
|
415
452
|
end
|