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.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +5 -6
  3. data/bin/innodb_log +13 -18
  4. data/bin/innodb_space +654 -778
  5. data/lib/innodb/checksum.rb +26 -24
  6. data/lib/innodb/data_dictionary.rb +490 -550
  7. data/lib/innodb/data_type.rb +362 -325
  8. data/lib/innodb/field.rb +102 -89
  9. data/lib/innodb/fseg_entry.rb +22 -26
  10. data/lib/innodb/history.rb +21 -21
  11. data/lib/innodb/history_list.rb +72 -76
  12. data/lib/innodb/ibuf_bitmap.rb +36 -36
  13. data/lib/innodb/ibuf_index.rb +6 -2
  14. data/lib/innodb/index.rb +245 -276
  15. data/lib/innodb/inode.rb +166 -124
  16. data/lib/innodb/list.rb +196 -183
  17. data/lib/innodb/log.rb +139 -110
  18. data/lib/innodb/log_block.rb +100 -91
  19. data/lib/innodb/log_group.rb +53 -64
  20. data/lib/innodb/log_reader.rb +97 -96
  21. data/lib/innodb/log_record.rb +328 -279
  22. data/lib/innodb/lsn.rb +86 -81
  23. data/lib/innodb/page/blob.rb +82 -83
  24. data/lib/innodb/page/fsp_hdr_xdes.rb +174 -165
  25. data/lib/innodb/page/ibuf_bitmap.rb +34 -34
  26. data/lib/innodb/page/index.rb +965 -924
  27. data/lib/innodb/page/index_compressed.rb +34 -34
  28. data/lib/innodb/page/inode.rb +103 -112
  29. data/lib/innodb/page/sys.rb +13 -15
  30. data/lib/innodb/page/sys_data_dictionary_header.rb +81 -59
  31. data/lib/innodb/page/sys_ibuf_header.rb +45 -42
  32. data/lib/innodb/page/sys_rseg_header.rb +88 -82
  33. data/lib/innodb/page/trx_sys.rb +204 -182
  34. data/lib/innodb/page/undo_log.rb +106 -92
  35. data/lib/innodb/page.rb +417 -414
  36. data/lib/innodb/record.rb +121 -164
  37. data/lib/innodb/record_describer.rb +66 -68
  38. data/lib/innodb/space.rb +381 -413
  39. data/lib/innodb/stats.rb +33 -35
  40. data/lib/innodb/system.rb +149 -171
  41. data/lib/innodb/undo_log.rb +129 -107
  42. data/lib/innodb/undo_record.rb +255 -247
  43. data/lib/innodb/util/buffer_cursor.rb +81 -79
  44. data/lib/innodb/util/read_bits_at_offset.rb +2 -1
  45. data/lib/innodb/version.rb +2 -2
  46. data/lib/innodb/xdes.rb +144 -142
  47. data/lib/innodb.rb +4 -5
  48. metadata +100 -25
@@ -1,31 +1,33 @@
1
- # -*- encoding : utf-8 -*-
1
+ # frozen_string_literal: true
2
2
 
3
- class Innodb::Checksum
4
- MAX = 0xFFFFFFFF.freeze
5
- MASK1 = 1463735687.freeze
6
- MASK2 = 1653893711.freeze
3
+ module Innodb
4
+ class Checksum
5
+ MAX = 0xFFFFFFFF
6
+ MASK1 = 1_463_735_687
7
+ MASK2 = 1_653_893_711
7
8
 
8
- # This is derived from ut_fold_ulint_pair in include/ut0rnd.ic in the
9
- # InnoDB source code. Since Ruby's Bignum class is *much* slower than its
10
- # Fixnum class, we mask back to 32 bits to keep things from overflowing
11
- # and being promoted to Bignum.
12
- def self.fold_pair(n1, n2)
13
- (((((((n1 ^ n2 ^ MASK2) << 8) & MAX) + n1) & MAX) ^ MASK1) + n2) & MAX
14
- end
9
+ # This is derived from ut_fold_ulint_pair in include/ut0rnd.ic in the
10
+ # InnoDB source code. Since Ruby's Bignum class is *much* slower than its
11
+ # Integer class, we mask back to 32 bits to keep things from overflowing
12
+ # and being promoted to Bignum.
13
+ def self.fold_pair(num1, num2)
14
+ (((((((num1 ^ num2 ^ MASK2) << 8) & MAX) + num1) & MAX) ^ MASK1) + num2) & MAX
15
+ end
15
16
 
16
- # Iterate through the provided enumerator, which is expected to return a
17
- # Fixnum (or something coercible to it), and "fold" them together to produce
18
- # a single value.
19
- def self.fold_enumerator(enumerator)
20
- fold = 0
21
- enumerator.each do |byte|
22
- fold = fold_pair(fold, byte)
17
+ # Iterate through the provided enumerator, which is expected to return a
18
+ # Integer (or something coercible to it), and "fold" them together to produce
19
+ # a single value.
20
+ def self.fold_enumerator(enumerator)
21
+ fold = 0
22
+ enumerator.each do |byte|
23
+ fold = fold_pair(fold, byte)
24
+ end
25
+ fold
23
26
  end
24
- fold
25
- end
26
27
 
27
- # A simple helper (and example) to fold a provided string.
28
- def self.fold_string(string)
29
- fold_enumerator(string.bytes)
28
+ # A simple helper (and example) to fold a provided string.
29
+ def self.fold_string(string)
30
+ fold_enumerator(string.bytes)
31
+ end
30
32
  end
31
33
  end
@@ -1,689 +1,629 @@
1
- # -*- encoding : utf-8 -*-
1
+ # frozen_string_literal: true
2
2
 
3
3
  # A class representing InnoDB's data dictionary, which contains metadata about
4
4
  # tables, columns, and indexes.
5
- class Innodb::DataDictionary
6
- # A record describer for SYS_TABLES clustered records.
7
- class SYS_TABLES_PRIMARY < Innodb::RecordDescriber
8
- type :clustered
9
- key "NAME", "VARCHAR(100)", :NOT_NULL
10
- row "ID", :BIGINT, :UNSIGNED, :NOT_NULL
11
- row "N_COLS", :INT, :UNSIGNED, :NOT_NULL
12
- row "TYPE", :INT, :UNSIGNED, :NOT_NULL
13
- row "MIX_ID", :BIGINT, :UNSIGNED, :NOT_NULL
14
- row "MIX_LEN", :INT, :UNSIGNED, :NOT_NULL
15
- row "CLUSTER_NAME", "VARCHAR(100)", :NOT_NULL
16
- row "SPACE", :INT, :UNSIGNED, :NOT_NULL
17
- end
18
-
19
- # A record describer for SYS_TABLES secondary key on ID.
20
- class SYS_TABLES_ID < Innodb::RecordDescriber
21
- type :secondary
22
- key "ID", :BIGINT, :UNSIGNED, :NOT_NULL
23
- row "NAME", "VARCHAR(100)", :NOT_NULL
24
- end
25
-
26
- # A record describer for SYS_COLUMNS clustered records.
27
- class SYS_COLUMNS_PRIMARY < Innodb::RecordDescriber
28
- type :clustered
29
- key "TABLE_ID", :BIGINT, :UNSIGNED, :NOT_NULL
30
- key "POS", :INT, :UNSIGNED, :NOT_NULL
31
- row "NAME", "VARCHAR(100)", :NOT_NULL
32
- row "MTYPE", :INT, :UNSIGNED, :NOT_NULL
33
- row "PRTYPE", :INT, :UNSIGNED, :NOT_NULL
34
- row "LEN", :INT, :UNSIGNED, :NOT_NULL
35
- row "PREC", :INT, :UNSIGNED, :NOT_NULL
36
- end
37
-
38
- # A record describer for SYS_INDEXES clustered records.
39
- class SYS_INDEXES_PRIMARY < Innodb::RecordDescriber
40
- type :clustered
41
- key "TABLE_ID", :BIGINT, :UNSIGNED, :NOT_NULL
42
- key "ID", :BIGINT, :UNSIGNED, :NOT_NULL
43
- row "NAME", "VARCHAR(100)", :NOT_NULL
44
- row "N_FIELDS", :INT, :UNSIGNED, :NOT_NULL
45
- row "TYPE", :INT, :UNSIGNED, :NOT_NULL
46
- row "SPACE", :INT, :UNSIGNED, :NOT_NULL
47
- row "PAGE_NO", :INT, :UNSIGNED, :NOT_NULL
48
- end
49
-
50
- # A record describer for SYS_FIELDS clustered records.
51
- class SYS_FIELDS_PRIMARY < Innodb::RecordDescriber
52
- type :clustered
53
- key "INDEX_ID", :BIGINT, :UNSIGNED, :NOT_NULL
54
- key "POS", :INT, :UNSIGNED, :NOT_NULL
55
- row "COL_NAME", "VARCHAR(100)", :NOT_NULL
56
- end
57
-
58
- # A hash of hashes of table name and index name to describer
59
- # class.
60
- DATA_DICTIONARY_RECORD_DESCRIBERS = {
61
- :SYS_TABLES => {
62
- :PRIMARY => SYS_TABLES_PRIMARY,
63
- :ID => SYS_TABLES_ID
64
- },
65
- :SYS_COLUMNS => { :PRIMARY => SYS_COLUMNS_PRIMARY },
66
- :SYS_INDEXES => { :PRIMARY => SYS_INDEXES_PRIMARY },
67
- :SYS_FIELDS => { :PRIMARY => SYS_FIELDS_PRIMARY },
68
- }
69
-
70
- # A hash of MySQL's internal type system to the stored
71
- # values for those types, and the "external" SQL type.
72
- MYSQL_TYPE = {
73
- # :DECIMAL => { :value => 0, :type => :DECIMAL },
74
- :TINY => { :value => 1, :type => :TINYINT },
75
- :SHORT => { :value => 2, :type => :SMALLINT },
76
- :LONG => { :value => 3, :type => :INT },
77
- :FLOAT => { :value => 4, :type => :FLOAT },
78
- :DOUBLE => { :value => 5, :type => :DOUBLE },
79
- # :NULL => { :value => 6, :type => nil },
80
- :TIMESTAMP => { :value => 7, :type => :TIMESTAMP },
81
- :LONGLONG => { :value => 8, :type => :BIGINT },
82
- :INT24 => { :value => 9, :type => :MEDIUMINT },
83
- # :DATE => { :value => 10, :type => :DATE },
84
- :TIME => { :value => 11, :type => :TIME },
85
- :DATETIME => { :value => 12, :type => :DATETIME },
86
- :YEAR => { :value => 13, :type => :YEAR },
87
- :NEWDATE => { :value => 14, :type => :DATE },
88
- :VARCHAR => { :value => 15, :type => :VARCHAR },
89
- :BIT => { :value => 16, :type => :BIT },
90
- :NEWDECIMAL => { :value => 246, :type => :CHAR },
91
- # :ENUM => { :value => 247, :type => :ENUM },
92
- # :SET => { :value => 248, :type => :SET },
93
- :TINY_BLOB => { :value => 249, :type => :TINYBLOB },
94
- :MEDIUM_BLOB => { :value => 250, :type => :MEDIUMBLOB },
95
- :LONG_BLOB => { :value => 251, :type => :LONGBLOB },
96
- :BLOB => { :value => 252, :type => :BLOB },
97
- # :VAR_STRING => { :value => 253, :type => :VARCHAR },
98
- :STRING => { :value => 254, :type => :CHAR },
99
- :GEOMETRY => { :value => 255, :type => :GEOMETRY },
100
- }
101
-
102
- # A hash of MYSQL_TYPE keys by value :value key.
103
- MYSQL_TYPE_BY_VALUE = MYSQL_TYPE.inject({}) { |h, (k, v)| h[v[:value]] = k; h }
104
-
105
- # A hash of InnoDB's internal type system to the values
106
- # stored for each type.
107
- COLUMN_MTYPE = {
108
- :VARCHAR => 1,
109
- :CHAR => 2,
110
- :FIXBINARY => 3,
111
- :BINARY => 4,
112
- :BLOB => 5,
113
- :INT => 6,
114
- :SYS_CHILD => 7,
115
- :SYS => 8,
116
- :FLOAT => 9,
117
- :DOUBLE => 10,
118
- :DECIMAL => 11,
119
- :VARMYSQL => 12,
120
- :MYSQL => 13,
121
- }
122
-
123
- # A hash of COLUMN_MTYPE keys by value.
124
- COLUMN_MTYPE_BY_VALUE = COLUMN_MTYPE.inject({}) { |h, (k, v)| h[v] = k; h }
125
-
126
- # A hash of InnoDB "precise type" bitwise flags.
127
- COLUMN_PRTYPE_FLAG = {
128
- :NOT_NULL => 256,
129
- :UNSIGNED => 512,
130
- :BINARY => 1024,
131
- :LONG_TRUE_VARCHAR => 4096,
132
- }
133
-
134
- # A hash of COLUMN_PRTYPE keys by value.
135
- COLUMN_PRTYPE_FLAG_BY_VALUE = COLUMN_PRTYPE_FLAG.inject({}) { |h, (k, v)| h[v] = k; h }
136
-
137
- # The bitmask to extract the MySQL internal type
138
- # from the InnoDB "precise type".
139
- COLUMN_PRTYPE_MYSQL_TYPE_MASK = 0xFF
140
-
141
- # A hash of InnoDB's index type flags.
142
- INDEX_TYPE_FLAG = {
143
- :CLUSTERED => 1,
144
- :UNIQUE => 2,
145
- :UNIVERSAL => 4,
146
- :IBUF => 8,
147
- :CORRUPT => 16,
148
- :FTS => 32,
149
- }
150
-
151
- # A hash of INDEX_TYPE_FLAG keys by value.
152
- INDEX_TYPE_FLAG_BY_VALUE = INDEX_TYPE_FLAG.inject({}) { |h, (k, v)| h[v] = k; h }
153
-
154
- # Return the "external" SQL type string (such as "VARCHAR" or
155
- # "INT") given the stored mtype and prtype from the InnoDB
156
- # data dictionary. Note that not all types are extractable
157
- # into fully defined SQL types due to the lossy nature of
158
- # the MySQL-to-InnoDB interface regarding types.
159
- def self.mtype_prtype_to_type_string(mtype, prtype, len, prec)
160
- mysql_type = prtype & COLUMN_PRTYPE_MYSQL_TYPE_MASK
161
- internal_type = MYSQL_TYPE_BY_VALUE[mysql_type]
162
- external_type = MYSQL_TYPE[internal_type][:type]
163
-
164
- case external_type
165
- when :VARCHAR
166
- # One-argument: length.
167
- "%s(%i)" % [external_type, len]
168
- when :FLOAT, :DOUBLE
169
- # Two-argument: length and precision.
170
- "%s(%i,%i)" % [external_type, len, prec]
171
- when :CHAR
172
- if COLUMN_MTYPE_BY_VALUE[mtype] == :MYSQL
173
- # When the mtype is :MYSQL, the column is actually
174
- # stored as VARCHAR despite being a CHAR. This is
175
- # done for CHAR columns having multi-byte character
176
- # sets in order to limit size. Note that such data
177
- # are still space-padded to at least len.
178
- "VARCHAR(%i)" % [len]
179
- else
5
+ module Innodb
6
+ class DataDictionary
7
+ MysqlType = Struct.new(
8
+ :value,
9
+ :type,
10
+ keyword_init: true
11
+ )
12
+
13
+ # rubocop:disable Layout/ExtraSpacing
14
+
15
+ # A record describer for SYS_TABLES clustered records.
16
+ class SysTablesPrimary < Innodb::RecordDescriber
17
+ type :clustered
18
+ key "NAME", "VARCHAR(100)", :NOT_NULL
19
+ row "ID", :BIGINT, :UNSIGNED, :NOT_NULL
20
+ row "N_COLS", :INT, :UNSIGNED, :NOT_NULL
21
+ row "TYPE", :INT, :UNSIGNED, :NOT_NULL
22
+ row "MIX_ID", :BIGINT, :UNSIGNED, :NOT_NULL
23
+ row "MIX_LEN", :INT, :UNSIGNED, :NOT_NULL
24
+ row "CLUSTER_NAME", "VARCHAR(100)", :NOT_NULL
25
+ row "SPACE", :INT, :UNSIGNED, :NOT_NULL
26
+ end
27
+
28
+ # A record describer for SYS_TABLES secondary key on ID.
29
+ class SysTablesId < Innodb::RecordDescriber
30
+ type :secondary
31
+ key "ID", :BIGINT, :UNSIGNED, :NOT_NULL
32
+ row "NAME", "VARCHAR(100)", :NOT_NULL
33
+ end
34
+
35
+ # A record describer for SYS_COLUMNS clustered records.
36
+ class SysColumnsPrimary < Innodb::RecordDescriber
37
+ type :clustered
38
+ key "TABLE_ID", :BIGINT, :UNSIGNED, :NOT_NULL
39
+ key "POS", :INT, :UNSIGNED, :NOT_NULL
40
+ row "NAME", "VARCHAR(100)", :NOT_NULL
41
+ row "MTYPE", :INT, :UNSIGNED, :NOT_NULL
42
+ row "PRTYPE", :INT, :UNSIGNED, :NOT_NULL
43
+ row "LEN", :INT, :UNSIGNED, :NOT_NULL
44
+ row "PREC", :INT, :UNSIGNED, :NOT_NULL
45
+ end
46
+
47
+ # A record describer for SYS_INDEXES clustered records.
48
+ class SysIndexesPrimary < Innodb::RecordDescriber
49
+ type :clustered
50
+ key "TABLE_ID", :BIGINT, :UNSIGNED, :NOT_NULL
51
+ key "ID", :BIGINT, :UNSIGNED, :NOT_NULL
52
+ row "NAME", "VARCHAR(100)", :NOT_NULL
53
+ row "N_FIELDS", :INT, :UNSIGNED, :NOT_NULL
54
+ row "TYPE", :INT, :UNSIGNED, :NOT_NULL
55
+ row "SPACE", :INT, :UNSIGNED, :NOT_NULL
56
+ row "PAGE_NO", :INT, :UNSIGNED, :NOT_NULL
57
+ end
58
+
59
+ # A record describer for SYS_FIELDS clustered records.
60
+ class SysFieldsPrimary < Innodb::RecordDescriber
61
+ type :clustered
62
+ key "INDEX_ID", :BIGINT, :UNSIGNED, :NOT_NULL
63
+ key "POS", :INT, :UNSIGNED, :NOT_NULL
64
+ row "COL_NAME", "VARCHAR(100)", :NOT_NULL
65
+ end
66
+
67
+ # rubocop:enable Layout/ExtraSpacing
68
+
69
+ # A hash of hashes of table name and index name to describer
70
+ # class.
71
+ DATA_DICTIONARY_RECORD_DESCRIBERS = {
72
+ SYS_TABLES: {
73
+ PRIMARY: SysTablesPrimary,
74
+ ID: SysTablesId,
75
+ }.freeze,
76
+ SYS_COLUMNS: { PRIMARY: SysColumnsPrimary }.freeze,
77
+ SYS_INDEXES: { PRIMARY: SysIndexesPrimary }.freeze,
78
+ SYS_FIELDS: { PRIMARY: SysFieldsPrimary }.freeze,
79
+ }.freeze
80
+
81
+ # A hash of MySQL's internal type system to the stored
82
+ # values for those types, and the 'external' SQL type.
83
+ # rubocop:disable Layout/HashAlignment
84
+ # rubocop:disable Layout/CommentIndentation
85
+ MYSQL_TYPE = {
86
+ # DECIMAL: MysqlType.new(value: 0, type: :DECIMAL),
87
+ TINY: MysqlType.new(value: 1, type: :TINYINT),
88
+ SHORT: MysqlType.new(value: 2, type: :SMALLINT),
89
+ LONG: MysqlType.new(value: 3, type: :INT),
90
+ FLOAT: MysqlType.new(value: 4, type: :FLOAT),
91
+ DOUBLE: MysqlType.new(value: 5, type: :DOUBLE),
92
+ # NULL: MysqlType.new(value: 6, type: nil),
93
+ TIMESTAMP: MysqlType.new(value: 7, type: :TIMESTAMP),
94
+ LONGLONG: MysqlType.new(value: 8, type: :BIGINT),
95
+ INT24: MysqlType.new(value: 9, type: :MEDIUMINT),
96
+ # DATE: MysqlType.new(value: 10, type: :DATE),
97
+ TIME: MysqlType.new(value: 11, type: :TIME),
98
+ DATETIME: MysqlType.new(value: 12, type: :DATETIME),
99
+ YEAR: MysqlType.new(value: 13, type: :YEAR),
100
+ NEWDATE: MysqlType.new(value: 14, type: :DATE),
101
+ VARCHAR: MysqlType.new(value: 15, type: :VARCHAR),
102
+ BIT: MysqlType.new(value: 16, type: :BIT),
103
+ NEWDECIMAL: MysqlType.new(value: 246, type: :CHAR),
104
+ # ENUM: MysqlType.new(value: 247, type: :ENUM),
105
+ # SET: MysqlType.new(value: 248, type: :SET),
106
+ TINY_BLOB: MysqlType.new(value: 249, type: :TINYBLOB),
107
+ MEDIUM_BLOB: MysqlType.new(value: 250, type: :MEDIUMBLOB),
108
+ LONG_BLOB: MysqlType.new(value: 251, type: :LONGBLOB),
109
+ BLOB: MysqlType.new(value: 252, type: :BLOB),
110
+ # VAR_STRING: MysqlType.new(value: 253, type: :VARCHAR),
111
+ STRING: MysqlType.new(value: 254, type: :CHAR),
112
+ GEOMETRY: MysqlType.new(value: 255, type: :GEOMETRY),
113
+ }.freeze
114
+ # rubocop:enable Layout/CommentIndentation
115
+ # rubocop:enable Layout/HashAlignment
116
+
117
+ # A hash of MYSQL_TYPE keys by value :value key.
118
+ MYSQL_TYPE_BY_VALUE = MYSQL_TYPE.transform_values(&:value).invert.freeze
119
+
120
+ # A hash of InnoDB's internal type system to the values
121
+ # stored for each type.
122
+ COLUMN_MTYPE = {
123
+ VARCHAR: 1,
124
+ CHAR: 2,
125
+ FIXBINARY: 3,
126
+ BINARY: 4,
127
+ BLOB: 5,
128
+ INT: 6,
129
+ SYS_CHILD: 7,
130
+ SYS: 8,
131
+ FLOAT: 9,
132
+ DOUBLE: 10,
133
+ DECIMAL: 11,
134
+ VARMYSQL: 12,
135
+ MYSQL: 13,
136
+ }.freeze
137
+
138
+ # A hash of COLUMN_MTYPE keys by value.
139
+ COLUMN_MTYPE_BY_VALUE = COLUMN_MTYPE.invert.freeze
140
+
141
+ # A hash of InnoDB 'precise type' bitwise flags.
142
+ COLUMN_PRTYPE_FLAG = {
143
+ NOT_NULL: 256,
144
+ UNSIGNED: 512,
145
+ BINARY: 1024,
146
+ LONG_TRUE_VARCHAR: 4096,
147
+ }.freeze
148
+
149
+ # A hash of COLUMN_PRTYPE keys by value.
150
+ COLUMN_PRTYPE_FLAG_BY_VALUE = COLUMN_PRTYPE_FLAG.invert.freeze
151
+
152
+ # The bitmask to extract the MySQL internal type
153
+ # from the InnoDB 'precise type'.
154
+ COLUMN_PRTYPE_MYSQL_TYPE_MASK = 0xFF
155
+
156
+ # A hash of InnoDB's index type flags.
157
+ INDEX_TYPE_FLAG = {
158
+ CLUSTERED: 1,
159
+ UNIQUE: 2,
160
+ UNIVERSAL: 4,
161
+ IBUF: 8,
162
+ CORRUPT: 16,
163
+ FTS: 32,
164
+ }.freeze
165
+
166
+ # A hash of INDEX_TYPE_FLAG keys by value.
167
+ INDEX_TYPE_FLAG_BY_VALUE = INDEX_TYPE_FLAG.invert.freeze
168
+
169
+ # Return the 'external' SQL type string (such as 'VARCHAR' or
170
+ # 'INT') given the stored mtype and prtype from the InnoDB
171
+ # data dictionary. Note that not all types are extractable
172
+ # into fully defined SQL types due to the lossy nature of
173
+ # the MySQL-to-InnoDB interface regarding types.
174
+ def self.mtype_prtype_to_type_string(mtype, prtype, len, prec)
175
+ mysql_type = prtype & COLUMN_PRTYPE_MYSQL_TYPE_MASK
176
+ internal_type = MYSQL_TYPE_BY_VALUE[mysql_type]
177
+ external_type = MYSQL_TYPE[internal_type].type
178
+
179
+ case external_type
180
+ when :VARCHAR
181
+ # One-argument: length.
182
+ "%s(%i)" % [external_type, len]
183
+ when :FLOAT, :DOUBLE
184
+ # Two-argument: length and precision.
185
+ "%s(%i,%i)" % [external_type, len, prec]
186
+ when :CHAR
187
+ if COLUMN_MTYPE_BY_VALUE[mtype] == :MYSQL
188
+ # When the mtype is :MYSQL, the column is actually
189
+ # stored as VARCHAR despite being a CHAR. This is
190
+ # done for CHAR columns having multi-byte character
191
+ # sets in order to limit size. Note that such data
192
+ # are still space-padded to at least len.
193
+ "VARCHAR(%i)" % [len]
194
+ else
195
+ "CHAR(%i)" % [len]
196
+ end
197
+ when :DECIMAL
198
+ # The DECIMAL type is designated as DECIMAL(M,D)
199
+ # however the M and D definitions are not stored
200
+ # in the InnoDB data dictionary. We need to define
201
+ # the column as something which will extract the
202
+ # raw bytes in order to read the column, but we
203
+ # can't figure out the right decimal type. The
204
+ # len stored here is actually the on-disk storage
205
+ # size.
180
206
  "CHAR(%i)" % [len]
207
+ else
208
+ external_type
181
209
  end
182
- when :DECIMAL
183
- # The DECIMAL type is designated as DECIMAL(M,D)
184
- # however the M and D definitions are not stored
185
- # in the InnoDB data dictionary. We need to define
186
- # the column as something which will extract the
187
- # raw bytes in order to read the column, but we
188
- # can't figure out the right decimal type. The
189
- # len stored here is actually the on-disk storage
190
- # size.
191
- "CHAR(%i)" % [len]
192
- else
193
- external_type
194
210
  end
195
- end
196
211
 
197
- # Return a full data type given an mtype and prtype, such
198
- # as ["VARCHAR(10)", :NOT_NULL] or [:INT, :UNSIGNED].
199
- def self.mtype_prtype_to_data_type(mtype, prtype, len, prec)
200
- data_type = []
212
+ # Return a full data type given an mtype and prtype, such
213
+ # as ['VARCHAR(10)', :NOT_NULL] or [:INT, :UNSIGNED].
214
+ def self.mtype_prtype_to_data_type(mtype, prtype, len, prec)
215
+ type = mtype_prtype_to_type_string(mtype, prtype, len, prec)
216
+ raise "Unsupported type (mtype #{mtype}, prtype #{prtype})" unless type
201
217
 
202
- if type = mtype_prtype_to_type_string(mtype, prtype, len, prec)
203
- data_type << type
204
- else
205
- raise "Unsupported type (mtype #{mtype}, prtype #{prtype})"
206
- end
218
+ data_type = [type]
219
+ data_type << :NOT_NULL if prtype & COLUMN_PRTYPE_FLAG[:NOT_NULL] != 0
220
+ data_type << :UNSIGNED if prtype & COLUMN_PRTYPE_FLAG[:UNSIGNED] != 0
207
221
 
208
- if prtype & COLUMN_PRTYPE_FLAG[:NOT_NULL] != 0
209
- data_type << :NOT_NULL
222
+ data_type
210
223
  end
211
224
 
212
- if prtype & COLUMN_PRTYPE_FLAG[:UNSIGNED] != 0
213
- data_type << :UNSIGNED
214
- end
225
+ attr_reader :system_space
215
226
 
216
- data_type
217
- end
218
-
219
- attr_reader :system_space
227
+ def initialize(system_space)
228
+ @system_space = system_space
229
+ end
220
230
 
221
- def initialize(system_space)
222
- @system_space = system_space
223
- end
231
+ # A helper method to reach inside the system space and retrieve
232
+ # the data dictionary index locations from the data dictionary
233
+ # header.
234
+ def data_dictionary_indexes
235
+ system_space.data_dictionary_page.data_dictionary_header[:indexes]
236
+ end
224
237
 
225
- # A helper method to reach inside the system space and retrieve
226
- # the data dictionary index locations from the data dictionary
227
- # header.
228
- def data_dictionary_indexes
229
- system_space.data_dictionary_page.data_dictionary_header[:indexes]
230
- end
238
+ def data_dictionary_index_ids
239
+ return @data_dictionary_index_ids if @data_dictionary_index_ids
231
240
 
232
- def data_dictionary_index_ids
233
- if @data_dictionary_index_ids
234
- return @data_dictionary_index_ids
235
- end
241
+ # TODO: This could probably be done a lot more Ruby-like.
242
+ @data_dictionary_index_ids = {}
243
+ data_dictionary_indexes.each do |table, indexes|
244
+ indexes.each do |index, root_page_number|
245
+ root_page = system_space.page(root_page_number)
246
+ next unless root_page
236
247
 
237
- @data_dictionary_index_ids = {}
238
- data_dictionary_indexes.each do |table, indexes|
239
- indexes.each do |index, root_page_number|
240
- if root_page = system_space.page(root_page_number)
241
248
  @data_dictionary_index_ids[root_page.index_id] = {
242
- :table => table,
243
- :index => index
249
+ table: table,
250
+ index: index,
244
251
  }
245
252
  end
246
253
  end
247
- end
248
254
 
249
- @data_dictionary_index_ids
250
- end
255
+ @data_dictionary_index_ids
256
+ end
251
257
 
252
- def data_dictionary_table?(table_name)
253
- DATA_DICTIONARY_RECORD_DESCRIBERS.include?(table_name.to_sym)
254
- end
258
+ def data_dictionary_table?(table_name)
259
+ DATA_DICTIONARY_RECORD_DESCRIBERS.include?(table_name.to_sym)
260
+ end
255
261
 
256
- def data_dictionary_index?(table_name, index_name)
257
- return unless data_dictionary_table?(table_name)
258
- DATA_DICTIONARY_RECORD_DESCRIBERS[table_name.to_sym].include?(index_name.to_sym)
259
- end
262
+ def data_dictionary_index?(table_name, index_name)
263
+ return unless data_dictionary_table?(table_name)
260
264
 
261
- def data_dictionary_index_describer(table_name, index_name)
262
- return unless data_dictionary_index?(table_name, index_name)
265
+ DATA_DICTIONARY_RECORD_DESCRIBERS[table_name.to_sym].include?(index_name.to_sym)
266
+ end
263
267
 
264
- DATA_DICTIONARY_RECORD_DESCRIBERS[table_name.to_sym][index_name.to_sym].new
265
- end
268
+ def data_dictionary_index_describer(table_name, index_name)
269
+ return unless data_dictionary_index?(table_name, index_name)
266
270
 
267
- # Return an Innodb::Index object initialized to the
268
- # internal data dictionary index with an appropriate
269
- # record describer so that records can be recursed.
270
- def data_dictionary_index(table_name, index_name)
271
- unless table_entry = data_dictionary_indexes[table_name]
272
- raise "Unknown data dictionary table #{table_name}"
271
+ DATA_DICTIONARY_RECORD_DESCRIBERS[table_name.to_sym][index_name.to_sym].new
273
272
  end
274
273
 
275
- unless index_root_page = table_entry[index_name]
276
- raise "Unknown data dictionary index #{table_name}.#{index_name}"
277
- end
274
+ # Return an Innodb::Index object initialized to the
275
+ # internal data dictionary index with an appropriate
276
+ # record describer so that records can be recursed.
277
+ def data_dictionary_index(table_name, index_name)
278
+ table_entry = data_dictionary_indexes[table_name]
279
+ raise "Unknown data dictionary table #{table_name}" unless table_entry
278
280
 
279
- # If we have a record describer for this index, load it.
280
- record_describer = data_dictionary_index_describer(table_name, index_name)
281
+ index_root_page = table_entry[index_name]
282
+ raise "Unknown data dictionary index #{table_name}.#{index_name}" unless index_root_page
281
283
 
282
- system_space.index(index_root_page, record_describer)
283
- end
284
+ # If we have a record describer for this index, load it.
285
+ record_describer = data_dictionary_index_describer(table_name, index_name)
284
286
 
285
- # Iterate through all data dictionary indexes, yielding the
286
- # table name, index name, and root page number.
287
- def each_data_dictionary_index_root_page_number
288
- unless block_given?
289
- return enum_for(:each_data_dictionary_index_root_page_number)
287
+ system_space.index(index_root_page, record_describer)
290
288
  end
291
289
 
292
- data_dictionary_indexes.each do |table_name, indexes|
293
- indexes.each do |index_name, root_page_number|
294
- yield table_name, index_name, root_page_number
295
- end
296
- end
290
+ # Iterate through all data dictionary indexes, yielding the
291
+ # table name, index name, and root page number.
292
+ def each_data_dictionary_index_root_page_number
293
+ return enum_for(:each_data_dictionary_index_root_page_number) unless block_given?
297
294
 
298
- nil
299
- end
295
+ data_dictionary_indexes.each do |table_name, indexes|
296
+ indexes.each do |index_name, root_page_number|
297
+ yield table_name, index_name, root_page_number
298
+ end
299
+ end
300
300
 
301
- # Iterate through all data dictionary indexes, yielding the table
302
- # name, index name, and the index itself as an Innodb::Index.
303
- def each_data_dictionary_index
304
- unless block_given?
305
- return enum_for(:each_data_dictionary_index)
301
+ nil
306
302
  end
307
303
 
308
- data_dictionary_indexes.each do |table_name, indexes|
309
- indexes.each do |index_name, root_page_number|
310
- yield table_name, index_name,
311
- data_dictionary_index(table_name, index_name)
312
- end
313
- end
304
+ # Iterate through all data dictionary indexes, yielding the table
305
+ # name, index name, and the index itself as an Innodb::Index.
306
+ def each_data_dictionary_index
307
+ return enum_for(:each_data_dictionary_index) unless block_given?
314
308
 
315
- nil
316
- end
309
+ data_dictionary_indexes.each do |table_name, indexes|
310
+ indexes.each do |index_name, _root_page_number|
311
+ yield table_name, index_name,
312
+ data_dictionary_index(table_name, index_name)
313
+ end
314
+ end
317
315
 
318
- # Iterate through records from a data dictionary index yielding each record
319
- # as a Innodb::Record object.
320
- def each_record_from_data_dictionary_index(table, index)
321
- unless block_given?
322
- return enum_for(:each_index, table, index)
316
+ nil
323
317
  end
324
318
 
325
- data_dictionary_index(table, index).each_record do |record|
326
- yield record
327
- end
319
+ # Iterate through records from a data dictionary index yielding each record
320
+ # as a Innodb::Record object.
321
+ def each_record_from_data_dictionary_index(table, index, &block)
322
+ return enum_for(:each_record_from_data_dictionary_index, table, index) unless block_given?
328
323
 
329
- nil
330
- end
324
+ data_dictionary_index(table, index).each_record(&block)
331
325
 
332
- # Iterate through the records in the SYS_TABLES data dictionary table.
333
- def each_table
334
- unless block_given?
335
- return enum_for(:each_table)
326
+ nil
336
327
  end
337
328
 
338
- each_record_from_data_dictionary_index(:SYS_TABLES, :PRIMARY) do |record|
339
- yield record.fields
340
- end
329
+ # Iterate through the records in the SYS_TABLES data dictionary table.
330
+ def each_table
331
+ return enum_for(:each_table) unless block_given?
341
332
 
342
- nil
343
- end
333
+ each_record_from_data_dictionary_index(:SYS_TABLES, :PRIMARY) do |record|
334
+ yield record.fields
335
+ end
344
336
 
345
- # Iterate through the records in the SYS_COLUMNS data dictionary table.
346
- def each_column
347
- unless block_given?
348
- return enum_for(:each_column)
337
+ nil
349
338
  end
350
339
 
351
- each_record_from_data_dictionary_index(:SYS_COLUMNS, :PRIMARY) do |record|
352
- yield record.fields
353
- end
340
+ # Iterate through the records in the SYS_COLUMNS data dictionary table.
341
+ def each_column
342
+ return enum_for(:each_column) unless block_given?
354
343
 
355
- nil
356
- end
344
+ each_record_from_data_dictionary_index(:SYS_COLUMNS, :PRIMARY) do |record|
345
+ yield record.fields
346
+ end
357
347
 
358
- # Iterate through the records in the SYS_INDEXES dictionary table.
359
- def each_index
360
- unless block_given?
361
- return enum_for(:each_index)
348
+ nil
362
349
  end
363
350
 
364
- each_record_from_data_dictionary_index(:SYS_INDEXES, :PRIMARY) do |record|
365
- yield record.fields
366
- end
351
+ # Iterate through the records in the SYS_INDEXES dictionary table.
352
+ def each_index
353
+ return enum_for(:each_index) unless block_given?
367
354
 
368
- nil
369
- end
355
+ each_record_from_data_dictionary_index(:SYS_INDEXES, :PRIMARY) do |record|
356
+ yield record.fields
357
+ end
370
358
 
371
- # Iterate through the records in the SYS_FIELDS data dictionary table.
372
- def each_field
373
- unless block_given?
374
- return enum_for(:each_field)
359
+ nil
375
360
  end
376
361
 
377
- each_record_from_data_dictionary_index(:SYS_FIELDS, :PRIMARY) do |record|
378
- yield record.fields
379
- end
362
+ # Iterate through the records in the SYS_FIELDS data dictionary table.
363
+ def each_field
364
+ return enum_for(:each_field) unless block_given?
380
365
 
381
- nil
382
- end
366
+ each_record_from_data_dictionary_index(:SYS_FIELDS, :PRIMARY) do |record|
367
+ yield record.fields
368
+ end
383
369
 
384
- # A helper to iterate the method provided and return the first record
385
- # where the record's field matches the provided value.
386
- def object_by_field(method, field, value)
387
- send(method).select { |o| o[field] == value }.first
388
- end
370
+ nil
371
+ end
389
372
 
390
- # A helper to iterate the method provided and return the first record
391
- # where the record's fields f1 and f2 match the provided values v1 and v2.
392
- def object_by_two_fields(method, f1, v1, f2, v2)
393
- send(method).select { |o| o[f1] == v1 && o[f2] == v2 }.first
394
- end
373
+ # A helper to iterate the method provided and return the first record
374
+ # where the record's field matches the provided value.
375
+ def object_by_field(method, field, value)
376
+ send(method).select { |o| o[field] == value }.first
377
+ end
395
378
 
396
- # Lookup a table by table ID.
397
- def table_by_id(table_id)
398
- object_by_field(:each_table,
399
- "ID", table_id)
400
- end
379
+ # A helper to iterate the method provided and return the first record
380
+ # where the record's fields f1 and f2 match the provided values v1 and v2.
381
+ def object_by_two_fields(method, field1, value1, field2, value2)
382
+ send(method).select { |o| o[field1] == value1 && o[field2] == value2 }.first
383
+ end
401
384
 
402
- # Lookup a table by table name.
403
- def table_by_name(table_name)
404
- object_by_field(:each_table,
405
- "NAME", table_name)
406
- end
385
+ # Lookup a table by table ID.
386
+ def table_by_id(table_id)
387
+ object_by_field(:each_table, "ID", table_id)
388
+ end
407
389
 
408
- # Lookup a table by space ID.
409
- def table_by_space_id(space_id)
410
- object_by_field(:each_table,
411
- "SPACE", space_id)
412
- end
390
+ # Lookup a table by table name.
391
+ def table_by_name(table_name)
392
+ object_by_field(:each_table, "NAME", table_name)
393
+ end
413
394
 
414
- # Lookup a column by table name and column name.
415
- def column_by_name(table_name, column_name)
416
- unless table = table_by_name(table_name)
417
- return nil
395
+ # Lookup a table by space ID.
396
+ def table_by_space_id(space_id)
397
+ object_by_field(:each_table, "SPACE", space_id)
418
398
  end
419
399
 
420
- object_by_two_fields(:each_column,
421
- "TABLE_ID", table["ID"],
422
- "NAME", column_name)
423
- end
400
+ # Lookup a column by table name and column name.
401
+ def column_by_name(table_name, column_name)
402
+ table = table_by_name(table_name)
403
+ return unless table
424
404
 
425
- # Lookup an index by index ID.
426
- def index_by_id(index_id)
427
- object_by_field(:each_index,
428
- "ID", index_id)
429
- end
405
+ object_by_two_fields(:each_column, "TABLE_ID", table["ID"], "NAME", column_name)
406
+ end
430
407
 
431
- # Lookup an index by table name and index name.
432
- def index_by_name(table_name, index_name)
433
- unless table = table_by_name(table_name)
434
- return nil
408
+ # Lookup an index by index ID.
409
+ def index_by_id(index_id)
410
+ object_by_field(:each_index, "ID", index_id)
435
411
  end
436
412
 
437
- object_by_two_fields(:each_index,
438
- "TABLE_ID", table["ID"],
439
- "NAME", index_name)
440
- end
413
+ # Lookup an index by table name and index name.
414
+ def index_by_name(table_name, index_name)
415
+ table = table_by_name(table_name)
416
+ return unless table
441
417
 
442
- # Iterate through indexes by space ID.
443
- def each_index_by_space_id(space_id)
444
- unless block_given?
445
- return enum_for(:each_index_by_space_id, space_id)
418
+ object_by_two_fields(:each_index, "TABLE_ID", table["ID"], "NAME", index_name)
446
419
  end
447
420
 
448
- each_index do |record|
449
- yield record if record["SPACE"] == space_id
450
- end
421
+ # Iterate through indexes by space ID.
422
+ def each_index_by_space_id(space_id)
423
+ return enum_for(:each_index_by_space_id, space_id) unless block_given?
451
424
 
452
- nil
453
- end
425
+ each_index do |record|
426
+ yield record if record["SPACE"] == space_id
427
+ end
454
428
 
455
- # Iterate through all indexes in a table by table ID.
456
- def each_index_by_table_id(table_id)
457
- unless block_given?
458
- return enum_for(:each_index_by_table_id, table_id)
429
+ nil
459
430
  end
460
431
 
461
- each_index do |record|
462
- yield record if record["TABLE_ID"] == table_id
463
- end
432
+ # Iterate through all indexes in a table by table ID.
433
+ def each_index_by_table_id(table_id)
434
+ return enum_for(:each_index_by_table_id, table_id) unless block_given?
464
435
 
465
- nil
466
- end
436
+ each_index do |record|
437
+ yield record if record["TABLE_ID"] == table_id
438
+ end
467
439
 
468
- # Iterate through all indexes in a table by table name.
469
- def each_index_by_table_name(table_name)
470
- unless block_given?
471
- return enum_for(:each_index_by_table_name, table_name)
440
+ nil
472
441
  end
473
442
 
474
- unless table = table_by_name(table_name)
475
- raise "Table #{table_name} not found"
476
- end
443
+ # Iterate through all indexes in a table by table name.
444
+ def each_index_by_table_name(table_name, &block)
445
+ return enum_for(:each_index_by_table_name, table_name) unless block_given?
477
446
 
478
- each_index_by_table_id(table["ID"]) do |record|
479
- yield record
480
- end
447
+ table = table_by_name(table_name)
448
+ raise "Table #{table_name} not found" unless table
481
449
 
482
- nil
483
- end
450
+ each_index_by_table_id(table["ID"], &block)
484
451
 
485
- # Iterate through all fields in an index by index ID.
486
- def each_field_by_index_id(index_id)
487
- unless block_given?
488
- return enum_for(:each_field_by_index_id, index_id)
452
+ nil
489
453
  end
490
454
 
491
- each_field do |record|
492
- yield record if record["INDEX_ID"] == index_id
493
- end
455
+ # Iterate through all fields in an index by index ID.
456
+ def each_field_by_index_id(index_id)
457
+ return enum_for(:each_field_by_index_id, index_id) unless block_given?
494
458
 
495
- nil
496
- end
459
+ each_field do |record|
460
+ yield record if record["INDEX_ID"] == index_id
461
+ end
497
462
 
498
- # Iterate through all fields in an index by index name.
499
- def each_field_by_index_name(table_name, index_name)
500
- unless block_given?
501
- return enum_for(:each_field_by_name, table_name, index_name)
463
+ nil
502
464
  end
503
465
 
504
- unless index = index_by_name(table_name, index_name)
505
- raise "Index #{index_name} for table #{table_name} not found"
506
- end
466
+ # Iterate through all fields in an index by index name.
467
+ def each_field_by_index_name(table_name, index_name, &block)
468
+ return enum_for(:each_field_by_index_name, table_name, index_name) unless block_given?
507
469
 
508
- each_field_by_index_id(index["ID"]) do |record|
509
- yield record
510
- end
470
+ index = index_by_name(table_name, index_name)
471
+ raise "Index #{index_name} for table #{table_name} not found" unless index
511
472
 
512
- nil
513
- end
473
+ each_field_by_index_id(index["ID"], &block)
514
474
 
515
- # Iterate through all columns in a table by table ID.
516
- def each_column_by_table_id(table_id)
517
- unless block_given?
518
- return enum_for(:each_column_by_table_id, table_id)
475
+ nil
519
476
  end
520
477
 
521
- each_column do |record|
522
- yield record if record["TABLE_ID"] == table_id
523
- end
478
+ # Iterate through all columns in a table by table ID.
479
+ def each_column_by_table_id(table_id)
480
+ return enum_for(:each_column_by_table_id, table_id) unless block_given?
524
481
 
525
- nil
526
- end
482
+ each_column do |record|
483
+ yield record if record["TABLE_ID"] == table_id
484
+ end
527
485
 
528
- # Iterate through all columns in a table by table name.
529
- def each_column_by_table_name(table_name)
530
- unless block_given?
531
- return enum_for(:each_column_by_table_name, table_name)
486
+ nil
532
487
  end
533
488
 
534
- unless table = table_by_name(table_name)
535
- raise "Table #{table_name} not found"
536
- end
489
+ # Iterate through all columns in a table by table name.
490
+ def each_column_by_table_name(table_name, &block)
491
+ return enum_for(:each_column_by_table_name, table_name) unless block_given?
492
+ raise "Table #{table_name} not found" unless (table = table_by_name(table_name))
537
493
 
538
- each_column_by_table_id(table["ID"]) do |record|
539
- yield record
494
+ each_column_by_table_id(table["ID"], &block)
495
+
496
+ nil
540
497
  end
541
498
 
542
- nil
543
- end
499
+ # Iterate through all columns in an index by table name and index name.
500
+ def each_column_in_index_by_name(table_name, index_name)
501
+ return enum_for(:each_column_in_index_by_name, table_name, index_name) unless block_given?
544
502
 
545
- # Iterate through all columns in an index by table name and index name.
546
- def each_column_in_index_by_name(table_name, index_name)
547
- unless block_given?
548
- return enum_for(:each_column_in_index_by_name, table_name, index_name)
549
- end
503
+ each_field_by_index_name(table_name, index_name) do |record|
504
+ yield column_by_name(table_name, record["COL_NAME"])
505
+ end
550
506
 
551
- each_field_by_index_name(table_name, index_name) do |record|
552
- yield column_by_name(table_name, record["COL_NAME"])
507
+ nil
553
508
  end
554
509
 
555
- nil
556
- end
510
+ # Iterate through all columns not in an index by table name and index name.
511
+ # This is useful when building index descriptions for secondary indexes.
512
+ def each_column_not_in_index_by_name(table_name, index_name)
513
+ return enum_for(:each_column_not_in_index_by_name, table_name, index_name) unless block_given?
557
514
 
558
- # Iterate through all columns not in an index by table name and index name.
559
- # This is useful when building index descriptions for secondary indexes.
560
- def each_column_not_in_index_by_name(table_name, index_name)
561
- unless block_given?
562
- return enum_for(:each_column_not_in_index_by_name, table_name, index_name)
563
- end
515
+ columns_in_index = {}
516
+ each_column_in_index_by_name(table_name, index_name) do |record|
517
+ columns_in_index[record["NAME"]] = 1
518
+ end
564
519
 
565
- columns_in_index = {}
566
- each_column_in_index_by_name(table_name, index_name) do |record|
567
- columns_in_index[record["NAME"]] = 1
568
- end
520
+ each_column_by_table_name(table_name) do |record|
521
+ yield record unless columns_in_index.include?(record["NAME"])
522
+ end
569
523
 
570
- each_column_by_table_name(table_name) do |record|
571
- yield record unless columns_in_index.include?(record["NAME"])
524
+ nil
572
525
  end
573
526
 
574
- nil
575
- end
527
+ # Return the name of the clustered index (usually 'PRIMARY', but not always)
528
+ # for a given table name.
529
+ def clustered_index_name_by_table_name(table_name)
530
+ table_record = table_by_name(table_name)
531
+ raise "Table #{table_name} not found" unless table_record
576
532
 
577
- # Return the name of the clustered index (usually "PRIMARY", but not always)
578
- # for a given table name.
579
- def clustered_index_name_by_table_name(table_name)
580
- unless table_record = table_by_name(table_name)
581
- raise "Table #{table_name} not found"
533
+ index_record = object_by_two_fields(:each_index, "TABLE_ID", table_record["ID"], "TYPE", 3)
534
+ index_record["NAME"] if index_record
582
535
  end
583
536
 
584
- if index_record = object_by_two_fields(:each_index,
585
- "TABLE_ID", table_record["ID"],
586
- "TYPE", 3)
587
- index_record["NAME"]
537
+ # Produce a Innodb::RecordDescriber-compatible column description
538
+ # given a type (:key, :row) and data dictionary SYS_COLUMNS record.
539
+ def _make_column_description(type, record)
540
+ {
541
+ type: type,
542
+ name: record["NAME"],
543
+ description: self.class.mtype_prtype_to_data_type(
544
+ record["MTYPE"],
545
+ record["PRTYPE"],
546
+ record["LEN"],
547
+ record["PREC"]
548
+ ),
549
+ }
588
550
  end
589
- end
590
551
 
591
- # Produce a Innodb::RecordDescriber-compatible column description
592
- # given a type (:key, :row) and data dictionary SYS_COLUMNS record.
593
- def _make_column_description(type, record)
594
- {
595
- :type => type,
596
- :name => record["NAME"],
597
- :description => self.class.mtype_prtype_to_data_type(
598
- record["MTYPE"],
599
- record["PRTYPE"],
600
- record["LEN"],
601
- record["PREC"]
602
- )
603
- }
604
- end
552
+ # Iterate through Innodb::RecordDescriber-compatible column descriptions
553
+ # for a given index by table name and index name.
554
+ def each_column_description_by_index_name(table_name, index_name)
555
+ return enum_for(:each_column_description_by_index_name, table_name, index_name) unless block_given?
605
556
 
606
- # Iterate through Innodb::RecordDescriber-compatible column descriptions
607
- # for a given index by table name and index name.
608
- def each_column_description_by_index_name(table_name, index_name)
609
- unless block_given?
610
- return enum_for(:each_column_description_by_index_name, table_name, index_name)
611
- end
557
+ unless (index = index_by_name(table_name, index_name))
558
+ raise "Index #{index_name} for table #{table_name} not found"
559
+ end
612
560
 
613
- unless index = index_by_name(table_name, index_name)
614
- raise "Index #{index_name} for table #{table_name} not found"
615
- end
561
+ columns_in_index = {}
562
+ each_column_in_index_by_name(table_name, index_name) do |record|
563
+ columns_in_index[record["NAME"]] = 1
564
+ yield _make_column_description(:key, record)
565
+ end
616
566
 
617
- columns_in_index = {}
618
- each_column_in_index_by_name(table_name, index_name) do |record|
619
- columns_in_index[record["NAME"]] = 1
620
- yield _make_column_description(:key, record)
621
- end
567
+ if (index["TYPE"] & INDEX_TYPE_FLAG[:CLUSTERED]).zero?
568
+ clustered_index_name = clustered_index_name_by_table_name(table_name)
622
569
 
623
- if index["TYPE"] & INDEX_TYPE_FLAG[:CLUSTERED] != 0
624
- each_column_by_table_name(table_name) do |record|
625
- unless columns_in_index.include?(record["NAME"])
570
+ each_column_in_index_by_name(table_name, clustered_index_name) do |record|
626
571
  yield _make_column_description(:row, record)
627
572
  end
573
+ else
574
+ each_column_by_table_name(table_name) do |record|
575
+ yield _make_column_description(:row, record) unless columns_in_index.include?(record["NAME"])
576
+ end
628
577
  end
629
- else
630
- clustered_index_name = clustered_index_name_by_table_name(table_name)
631
578
 
632
- each_column_in_index_by_name(table_name, clustered_index_name) do |record|
633
- yield _make_column_description(:row, record)
634
- end
579
+ nil
635
580
  end
636
581
 
637
- nil
638
- end
639
-
640
- # Return an Innodb::RecordDescriber object describing records for a given
641
- # index by table name and index name.
642
- def record_describer_by_index_name(table_name, index_name)
643
- if data_dictionary_index?(table_name, index_name)
644
- return data_dictionary_index_describer(table_name, index_name)
645
- end
582
+ # Return an Innodb::RecordDescriber object describing records for a given
583
+ # index by table name and index name.
584
+ def record_describer_by_index_name(table_name, index_name)
585
+ return data_dictionary_index_describer(table_name, index_name) if data_dictionary_index?(table_name, index_name)
646
586
 
647
- unless index = index_by_name(table_name, index_name)
648
- raise "Index #{index_name} for table #{table_name} not found"
649
- end
587
+ unless (index = index_by_name(table_name, index_name))
588
+ raise "Index #{index_name} for table #{table_name} not found"
589
+ end
650
590
 
651
- describer = Innodb::RecordDescriber.new
591
+ describer = Innodb::RecordDescriber.new
652
592
 
653
- if index["TYPE"] & INDEX_TYPE_FLAG[:CLUSTERED] != 0
654
- describer.type :clustered
655
- else
656
- describer.type :secondary
657
- end
593
+ if (index["TYPE"] & INDEX_TYPE_FLAG[:CLUSTERED]).zero?
594
+ describer.type :secondary
595
+ else
596
+ describer.type :clustered
597
+ end
658
598
 
659
- each_column_description_by_index_name(table_name, index_name) do |column|
660
- case column[:type]
661
- when :key
662
- describer.key column[:name], *column[:description]
663
- when :row
664
- describer.row column[:name], *column[:description]
599
+ each_column_description_by_index_name(table_name, index_name) do |column|
600
+ case column[:type]
601
+ when :key
602
+ describer.key column[:name], *column[:description]
603
+ when :row
604
+ describer.row column[:name], *column[:description]
605
+ end
665
606
  end
607
+
608
+ describer
666
609
  end
667
610
 
668
- describer
669
- end
611
+ # Return an Innodb::RecordDescriber object describing the records
612
+ # in a given index by index ID.
613
+ def record_describer_by_index_id(index_id)
614
+ if (dd_index = data_dictionary_index_ids[index_id])
615
+ return data_dictionary_index_describer(dd_index[:table], dd_index[:index])
616
+ end
670
617
 
671
- # Return an Innodb::RecordDescriber object describing the records
672
- # in a given index by index ID.
673
- def record_describer_by_index_id(index_id)
674
- if dd_index = data_dictionary_index_ids[index_id]
675
- return data_dictionary_index_describer(dd_index[:table], dd_index[:index])
676
- end
618
+ unless (index = index_by_id(index_id))
619
+ raise "Index #{index_id} not found"
620
+ end
677
621
 
678
- unless index = index_by_id(index_id)
679
- raise "Index #{index_id} not found"
680
- end
622
+ unless (table = table_by_id(index["TABLE_ID"]))
623
+ raise "Table #{INDEX['TABLE_ID']} not found"
624
+ end
681
625
 
682
- unless table = table_by_id(index["TABLE_ID"])
683
- raise "Table #{INDEX["TABLE_ID"]} not found"
626
+ record_describer_by_index_name(table["NAME"], index["NAME"])
684
627
  end
685
-
686
- record_describer_by_index_name(table["NAME"], index["NAME"])
687
628
  end
688
-
689
629
  end