innodb_ruby 0.9.16 → 0.11.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 +5 -5
- data/README.md +5 -6
- data/bin/innodb_log +13 -18
- data/bin/innodb_space +377 -757
- data/lib/innodb.rb +4 -5
- data/lib/innodb/checksum.rb +26 -24
- data/lib/innodb/data_dictionary.rb +490 -550
- data/lib/innodb/data_type.rb +362 -326
- 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 +154 -155
- data/lib/innodb/list.rb +191 -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.rb +417 -414
- 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 +964 -943
- 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/record.rb +121 -160
- data/lib/innodb/record_describer.rb +66 -68
- data/lib/innodb/space.rb +380 -418
- 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
- metadata +80 -11
data/lib/innodb/data_type.rb
CHANGED
@@ -1,416 +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
|
-
|
132
|
-
frac = "0" if frac.empty?
|
147
|
+
private
|
133
148
|
|
134
|
-
#
|
135
|
-
|
149
|
+
# Ensure width specification (if any) is compliant.
|
150
|
+
def sanity_check(modifiers)
|
151
|
+
raise "Invalid width specification" unless modifiers.size <= 2
|
136
152
|
|
137
|
-
|
138
|
-
|
153
|
+
precision = modifiers.fetch(0, 10)
|
154
|
+
raise "Unsupported precision for DECIMAL type" unless precision >= 1 && precision <= 65
|
139
155
|
|
140
|
-
|
141
|
-
|
142
|
-
# Ensure width specification (if any) is compliant.
|
143
|
-
def sanity_check(modifiers)
|
144
|
-
raise "Invalid width specification" unless modifiers.size <= 2
|
145
|
-
precision = modifiers.fetch(0, 10)
|
146
|
-
raise "Unsupported precision for DECIMAL type" unless
|
147
|
-
precision >= 1 and precision <= 65
|
148
|
-
scale = modifiers.fetch(1, 0)
|
149
|
-
raise "Unsupported scale for DECIMAL type" unless
|
150
|
-
scale >= 0 and scale <= 30 and scale <= precision
|
151
|
-
[precision, scale]
|
152
|
-
end
|
156
|
+
scale = modifiers.fetch(1, 0)
|
157
|
+
raise "Unsupported scale for DECIMAL type" unless scale >= 0 && scale <= 30 && scale <= precision
|
153
158
|
|
154
|
-
|
155
|
-
|
156
|
-
# back the byte into the stream.
|
157
|
-
def sign_mask(stream)
|
158
|
-
byte = BinData::Uint8.read(stream)
|
159
|
-
sign = byte & 0x80
|
160
|
-
byte.assign(byte ^ 0x80)
|
161
|
-
stream.rewind
|
162
|
-
byte.write(stream)
|
163
|
-
stream.rewind
|
164
|
-
(sign == 0) ? -1 : 0
|
165
|
-
end
|
159
|
+
[precision, scale]
|
160
|
+
end
|
166
161
|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
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
|
176
174
|
|
177
|
-
|
178
|
-
|
179
|
-
|
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?
|
180
179
|
|
181
|
-
|
182
|
-
|
183
|
-
|
180
|
+
value = (BinData.const_get("Int%dbe" % nbits).read(stream) ^ mask)
|
181
|
+
# Preserve leading zeros.
|
182
|
+
"%0#{digits}d" % value
|
183
|
+
end
|
184
184
|
end
|
185
185
|
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
end
|
191
|
-
end
|
186
|
+
# Fixed-length character type.
|
187
|
+
class CharacterType
|
188
|
+
attr_reader :name
|
189
|
+
attr_reader :width
|
192
190
|
|
193
|
-
|
194
|
-
|
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
|
195
195
|
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
196
|
+
def value(data)
|
197
|
+
# The SQL standard defines that CHAR fields should have end-spaces
|
198
|
+
# stripped off.
|
199
|
+
data.sub(/ +$/, "")
|
200
|
+
end
|
200
201
|
end
|
201
202
|
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
data.sub(/[ ]+$/, "")
|
206
|
-
end
|
207
|
-
end
|
203
|
+
class VariableCharacterType
|
204
|
+
attr_reader :name
|
205
|
+
attr_reader :width
|
208
206
|
|
209
|
-
|
210
|
-
|
211
|
-
|
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
|
212
213
|
|
213
|
-
|
214
|
-
|
215
|
-
|
214
|
+
def value(data)
|
215
|
+
# The SQL standard defines that VARCHAR fields should have end-spaces
|
216
|
+
# stripped off.
|
217
|
+
data.sub(/ +$/, "")
|
218
|
+
end
|
216
219
|
end
|
217
|
-
end
|
218
220
|
|
219
|
-
|
220
|
-
|
221
|
+
# Fixed-length binary type.
|
222
|
+
class BinaryType
|
223
|
+
attr_reader :name
|
224
|
+
attr_reader :width
|
221
225
|
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
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
|
226
230
|
end
|
227
|
-
end
|
228
231
|
|
229
|
-
|
230
|
-
|
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
|
231
239
|
|
232
|
-
|
233
|
-
|
240
|
+
@name = Innodb::DataType.make_name(base_type, modifiers, properties)
|
241
|
+
end
|
234
242
|
end
|
235
|
-
end
|
236
243
|
|
237
|
-
|
238
|
-
|
244
|
+
class BlobType
|
245
|
+
attr_reader :name
|
239
246
|
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
@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
|
244
250
|
end
|
245
251
|
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
return (year + 1900).to_s if year != 0
|
250
|
-
"0000"
|
251
|
-
end
|
252
|
-
end
|
252
|
+
class YearType
|
253
|
+
attr_reader :name
|
254
|
+
attr_reader :width
|
253
255
|
|
254
|
-
|
255
|
-
|
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
|
256
261
|
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
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
|
261
266
|
|
262
|
-
|
263
|
-
|
264
|
-
sign = "-" if time < 0
|
265
|
-
time = time.abs
|
266
|
-
"%s%02d:%02d:%02d" % [sign, time / 10000, (time / 100) % 100, time % 100]
|
267
|
+
"0000"
|
268
|
+
end
|
267
269
|
end
|
268
|
-
end
|
269
270
|
|
270
|
-
|
271
|
-
|
271
|
+
class TimeType
|
272
|
+
attr_reader :name
|
273
|
+
attr_reader :width
|
272
274
|
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
275
|
+
def initialize(base_type, modifiers, properties)
|
276
|
+
@width = 3
|
277
|
+
@name = Innodb::DataType.make_name(base_type, modifiers, properties)
|
278
|
+
end
|
277
279
|
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
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
|
284
286
|
end
|
285
|
-
end
|
286
287
|
|
287
|
-
|
288
|
-
|
288
|
+
class DateType
|
289
|
+
attr_reader :name
|
290
|
+
attr_reader :width
|
289
291
|
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
292
|
+
def initialize(base_type, modifiers, properties)
|
293
|
+
@width = 3
|
294
|
+
@name = Innodb::DataType.make_name(base_type, modifiers, properties)
|
295
|
+
end
|
294
296
|
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
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
|
302
304
|
end
|
303
|
-
end
|
304
305
|
|
305
|
-
|
306
|
-
|
306
|
+
class DatetimeType
|
307
|
+
attr_reader :name
|
308
|
+
attr_reader :width
|
307
309
|
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
310
|
+
def initialize(base_type, modifiers, properties)
|
311
|
+
@width = 8
|
312
|
+
@name = Innodb::DataType.make_name(base_type, modifiers, properties)
|
313
|
+
end
|
312
314
|
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
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
|
318
327
|
end
|
319
|
-
end
|
320
328
|
|
321
|
-
|
322
|
-
|
323
|
-
|
329
|
+
class TimestampType
|
330
|
+
attr_reader :name
|
331
|
+
attr_reader :width
|
324
332
|
|
325
|
-
|
326
|
-
|
327
|
-
|
333
|
+
def initialize(base_type, modifiers, properties)
|
334
|
+
@width = 4
|
335
|
+
@name = Innodb::DataType.make_name(base_type, modifiers, properties)
|
336
|
+
end
|
328
337
|
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
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?
|
333
342
|
|
334
|
-
|
335
|
-
|
343
|
+
DateTime.strptime(timestamp.to_s, "%s").strftime "%Y-%m-%d %H:%M:%S"
|
344
|
+
end
|
336
345
|
end
|
337
|
-
end
|
338
346
|
|
339
|
-
|
340
|
-
|
341
|
-
|
347
|
+
#
|
348
|
+
# Data types for InnoDB system columns.
|
349
|
+
#
|
342
350
|
|
343
|
-
|
351
|
+
# Transaction ID.
|
352
|
+
class TransactionIdType
|
353
|
+
attr_reader :name
|
354
|
+
attr_reader :width
|
344
355
|
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
356
|
+
def initialize(base_type, modifiers, properties)
|
357
|
+
@width = 6
|
358
|
+
@name = Innodb::DataType.make_name(base_type, modifiers, properties)
|
359
|
+
end
|
349
360
|
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
:rseg_id => read_bits_at_offset(roll_ptr, 7, 48),
|
354
|
-
:undo_log => {
|
355
|
-
:page => read_bits_at_offset(roll_ptr, 32, 16),
|
356
|
-
:offset => read_bits_at_offset(roll_ptr, 16, 0),
|
357
|
-
}
|
358
|
-
}
|
361
|
+
def read(cursor)
|
362
|
+
cursor.name("transaction_id") { cursor.read_uint48 }
|
363
|
+
end
|
359
364
|
end
|
360
365
|
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
end
|
366
|
+
# Rollback data pointer.
|
367
|
+
class RollPointerType
|
368
|
+
extend ReadBitsAtOffset
|
365
369
|
|
366
|
-
|
370
|
+
Pointer = Struct.new(
|
371
|
+
:is_insert,
|
372
|
+
:rseg_id,
|
373
|
+
:undo_log,
|
374
|
+
keyword_init: true
|
375
|
+
)
|
367
376
|
|
368
|
-
|
369
|
-
|
370
|
-
:BIT => BitType,
|
371
|
-
:BOOL => IntegerType,
|
372
|
-
:BOOLEAN => IntegerType,
|
373
|
-
:TINYINT => IntegerType,
|
374
|
-
:SMALLINT => IntegerType,
|
375
|
-
:MEDIUMINT => IntegerType,
|
376
|
-
:INT => IntegerType,
|
377
|
-
:INT6 => IntegerType,
|
378
|
-
:BIGINT => IntegerType,
|
379
|
-
:FLOAT => FloatType,
|
380
|
-
:DOUBLE => DoubleType,
|
381
|
-
:DECIMAL => DecimalType,
|
382
|
-
:NUMERIC => DecimalType,
|
383
|
-
:CHAR => CharacterType,
|
384
|
-
:VARCHAR => VariableCharacterType,
|
385
|
-
:BINARY => BinaryType,
|
386
|
-
:VARBINARY => VariableBinaryType,
|
387
|
-
:TINYBLOB => BlobType,
|
388
|
-
:BLOB => BlobType,
|
389
|
-
:MEDIUMBLOB => BlobType,
|
390
|
-
:LONGBLOB => BlobType,
|
391
|
-
:TINYTEXT => BlobType,
|
392
|
-
:TEXT => BlobType,
|
393
|
-
:MEDIUMTEXT => BlobType,
|
394
|
-
:LONGTEXT => BlobType,
|
395
|
-
:YEAR => YearType,
|
396
|
-
:TIME => TimeType,
|
397
|
-
:DATE => DateType,
|
398
|
-
:DATETIME => DatetimeType,
|
399
|
-
:TIMESTAMP => TimestampType,
|
400
|
-
:TRX_ID => TransactionIdType,
|
401
|
-
:ROLL_PTR => RollPointerType,
|
402
|
-
}
|
403
|
-
|
404
|
-
def self.make_name(base_type, modifiers, properties)
|
405
|
-
name = base_type.to_s
|
406
|
-
name << '(' + modifiers.join(',') + ')' if not modifiers.empty?
|
407
|
-
name << " "
|
408
|
-
name << properties.join(' ')
|
409
|
-
name.strip
|
410
|
-
end
|
377
|
+
attr_reader :name
|
378
|
+
attr_reader :width
|
411
379
|
|
412
|
-
|
413
|
-
|
414
|
-
|
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
|
415
451
|
end
|
416
452
|
end
|