innodb_ruby 0.8.1 → 0.8.5
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.
- data/AUTHORS.md +12 -0
- data/LICENSE +29 -0
- data/bin/innodb_log +64 -9
- data/bin/innodb_space +95 -42
- data/lib/innodb/checksum.rb +1 -0
- data/lib/innodb/cursor.rb +8 -63
- data/lib/innodb/data_dictionary.rb +2 -0
- data/lib/innodb/data_type.rb +360 -0
- data/lib/innodb/field.rb +65 -10
- data/lib/innodb/fseg_entry.rb +2 -0
- data/lib/innodb/index.rb +5 -0
- data/lib/innodb/inode.rb +1 -0
- data/lib/innodb/list.rb +2 -0
- data/lib/innodb/log.rb +2 -0
- data/lib/innodb/log_block.rb +1 -0
- data/lib/innodb/log_group.rb +79 -0
- data/lib/innodb/page/fsp_hdr_xdes.rb +1 -0
- data/lib/innodb/page/index.rb +38 -42
- data/lib/innodb/page/index_compressed.rb +42 -0
- data/lib/innodb/page/inode.rb +1 -0
- data/lib/innodb/page/sys.rb +1 -0
- data/lib/innodb/page/sys_rseg_header.rb +1 -0
- data/lib/innodb/page/trx_sys.rb +1 -0
- data/lib/innodb/page.rb +1 -0
- data/lib/innodb/record.rb +49 -0
- data/lib/innodb/record_describer.rb +8 -0
- data/lib/innodb/space.rb +6 -0
- data/lib/innodb/system.rb +58 -0
- data/lib/innodb/undo_log.rb +1 -0
- data/lib/innodb/version.rb +2 -1
- data/lib/innodb/xdes.rb +1 -0
- data/lib/innodb.rb +4 -0
- metadata +13 -5
- data/lib/innodb/field_type.rb +0 -124
data/lib/innodb/page/index.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
|
+
|
2
3
|
require "innodb/fseg_entry"
|
3
4
|
|
4
5
|
# A specialized class for handling INDEX pages, which contain a portion of
|
@@ -335,22 +336,22 @@ class Innodb::Page::Index < Innodb::Page
|
|
335
336
|
|
336
337
|
# Return an array indicating which fields are null.
|
337
338
|
def record_header_compact_null_bitmap(cursor)
|
338
|
-
|
339
|
+
fields = (record_format[:key] + record_format[:row])
|
339
340
|
|
340
341
|
# The number of bits in the bitmap is the number of nullable fields.
|
341
|
-
size =
|
342
|
+
size = fields.count { |f| f.nullable? }
|
342
343
|
|
343
344
|
# There is no bitmap if there are no nullable fields.
|
344
345
|
return nil unless size > 0
|
345
346
|
|
346
347
|
# To simplify later checks, expand bitmap to one for each field.
|
347
|
-
bitmap = Array.new(
|
348
|
+
bitmap = Array.new(fields.last.position + 1, false)
|
348
349
|
|
349
350
|
null_bit_array = cursor.get_bit_array(size).reverse!
|
350
351
|
|
351
352
|
# For every nullable field, set whether the field is actually null.
|
352
|
-
|
353
|
-
bitmap[
|
353
|
+
fields.each do |f|
|
354
|
+
bitmap[f.position] = f.nullable? ? (null_bit_array.shift == 1) : false
|
354
355
|
end
|
355
356
|
|
356
357
|
return bitmap
|
@@ -359,23 +360,22 @@ class Innodb::Page::Index < Innodb::Page
|
|
359
360
|
# Return an array containing an array of the length of each variable-length
|
360
361
|
# field and an array indicating which fields are stored externally.
|
361
362
|
def record_header_compact_variable_lengths_and_externs(cursor, null_bitmap)
|
362
|
-
|
363
|
+
fields = (record_format[:key] + record_format[:row])
|
363
364
|
|
364
|
-
len_array = Array.new(
|
365
|
-
ext_array = Array.new(
|
365
|
+
len_array = Array.new(fields.last.position + 1, 0)
|
366
|
+
ext_array = Array.new(fields.last.position + 1, false)
|
366
367
|
|
367
368
|
# For each non-NULL variable-length field, the record header contains
|
368
369
|
# the length in one or two bytes.
|
369
|
-
|
370
|
-
f
|
371
|
-
next if !f.type.variable? or (null_bitmap && null_bitmap[f.position])
|
370
|
+
fields.each do |f|
|
371
|
+
next if !f.variable? or (null_bitmap && null_bitmap[f.position])
|
372
372
|
|
373
373
|
len = cursor.get_uint8
|
374
374
|
ext = false
|
375
375
|
|
376
376
|
# Two bytes are used only if the length exceeds 127 bytes and the
|
377
377
|
# maximum length exceeds 255 bytes (or the field is a BLOB type).
|
378
|
-
if len > 127 && (f.
|
378
|
+
if len > 127 && (f.blob? || f.data_type.width > 255)
|
379
379
|
ext = (0x40 & len) != 0
|
380
380
|
len = ((len & 0x3f) << 8) + cursor.get_uint8
|
381
381
|
end
|
@@ -429,12 +429,12 @@ class Innodb::Page::Index < Innodb::Page
|
|
429
429
|
def system_record(offset)
|
430
430
|
cursor(offset).name("record[#{offset}]") do |c|
|
431
431
|
header = c.peek { record_header(c) }
|
432
|
-
{
|
432
|
+
Innodb::Record.new({
|
433
433
|
:offset => offset,
|
434
434
|
:header => header,
|
435
435
|
:next => header[:next],
|
436
436
|
:data => c.name("data") { c.get_bytes(size_mum_record) },
|
437
|
-
}
|
437
|
+
})
|
438
438
|
end
|
439
439
|
end
|
440
440
|
|
@@ -456,10 +456,7 @@ class Innodb::Page::Index < Innodb::Page
|
|
456
456
|
fields = {:type => description[:type], :key => [], :row => []}
|
457
457
|
|
458
458
|
description[:key].each do |field|
|
459
|
-
fields[:key] <<
|
460
|
-
:name => field[:name],
|
461
|
-
:field => Innodb::Field.new(position, *field[:type]),
|
462
|
-
}
|
459
|
+
fields[:key] << Innodb::Field.new(position, field[:name], *field[:type])
|
463
460
|
position += 1
|
464
461
|
end
|
465
462
|
|
@@ -469,10 +466,7 @@ class Innodb::Page::Index < Innodb::Page
|
|
469
466
|
end
|
470
467
|
|
471
468
|
description[:row].each do |field|
|
472
|
-
fields[:row] <<
|
473
|
-
:name => field[:name],
|
474
|
-
:field => Innodb::Field.new(position, *field[:type]),
|
475
|
-
}
|
469
|
+
fields[:row] << Innodb::Field.new(position, field[:name], *field[:type])
|
476
470
|
position += 1
|
477
471
|
end
|
478
472
|
|
@@ -508,12 +502,13 @@ class Innodb::Page::Index < Innodb::Page
|
|
508
502
|
|
509
503
|
# Read the key fields present in all types of pages.
|
510
504
|
this_record[:key] = []
|
511
|
-
record_format[:key].each do |
|
512
|
-
c.name("key[#{
|
505
|
+
record_format[:key].each do |f|
|
506
|
+
c.name("key[#{f.name}]") do
|
513
507
|
this_record[:key] << {
|
514
|
-
:name =>
|
515
|
-
:
|
516
|
-
:
|
508
|
+
:name => f.name,
|
509
|
+
:type => f.data_type.name,
|
510
|
+
:value => f.value(this_record, c),
|
511
|
+
:extern => f.extern(this_record, c),
|
517
512
|
}
|
518
513
|
end
|
519
514
|
end
|
@@ -543,12 +538,13 @@ class Innodb::Page::Index < Innodb::Page
|
|
543
538
|
(record_format[:type] == :secondary)
|
544
539
|
# Read the non-key fields.
|
545
540
|
this_record[:row] = []
|
546
|
-
record_format[:row].each do |
|
547
|
-
c.name("row[#{
|
541
|
+
record_format[:row].each do |f|
|
542
|
+
c.name("row[#{f.name}]") do
|
548
543
|
this_record[:row] << {
|
549
|
-
:name =>
|
550
|
-
:
|
551
|
-
:
|
544
|
+
:name => f.name,
|
545
|
+
:type => f.data_type.name,
|
546
|
+
:value => f.value(this_record, c),
|
547
|
+
:extern => f.extern(this_record, c),
|
552
548
|
}
|
553
549
|
end
|
554
550
|
end
|
@@ -563,7 +559,7 @@ class Innodb::Page::Index < Innodb::Page
|
|
563
559
|
end
|
564
560
|
end
|
565
561
|
|
566
|
-
this_record
|
562
|
+
Innodb::Record.new(this_record)
|
567
563
|
end
|
568
564
|
end
|
569
565
|
|
@@ -584,13 +580,13 @@ class Innodb::Page::Index < Innodb::Page
|
|
584
580
|
if record == @page.supremum
|
585
581
|
# We've reached the end of the linked list at supremum.
|
586
582
|
@offset = nil
|
587
|
-
elsif record
|
583
|
+
elsif record.next == @offset
|
588
584
|
# The record links to itself; go ahead and return it (once), but set
|
589
585
|
# the next offset to nil to end the loop.
|
590
586
|
@offset = nil
|
591
587
|
record
|
592
588
|
else
|
593
|
-
@offset = record
|
589
|
+
@offset = record.next
|
594
590
|
record
|
595
591
|
end
|
596
592
|
end
|
@@ -603,7 +599,7 @@ class Innodb::Page::Index < Innodb::Page
|
|
603
599
|
|
604
600
|
# Return the first record on this page.
|
605
601
|
def first_record
|
606
|
-
first = record(infimum
|
602
|
+
first = record(infimum.next)
|
607
603
|
first if first != supremum
|
608
604
|
end
|
609
605
|
|
@@ -613,7 +609,7 @@ class Innodb::Page::Index < Innodb::Page
|
|
613
609
|
return enum_for(:each_record)
|
614
610
|
end
|
615
611
|
|
616
|
-
c = record_cursor(infimum
|
612
|
+
c = record_cursor(infimum.next)
|
617
613
|
|
618
614
|
while rec = c.record
|
619
615
|
yield rec
|
@@ -651,7 +647,7 @@ class Innodb::Page::Index < Innodb::Page
|
|
651
647
|
end
|
652
648
|
|
653
649
|
each_record do |rec|
|
654
|
-
yield rec
|
650
|
+
yield rec.child_page_number, rec.key
|
655
651
|
end
|
656
652
|
|
657
653
|
nil
|
@@ -701,20 +697,20 @@ class Innodb::Page::Index < Innodb::Page
|
|
701
697
|
puts
|
702
698
|
|
703
699
|
puts "system records:"
|
704
|
-
pp infimum
|
705
|
-
pp supremum
|
700
|
+
pp infimum.record
|
701
|
+
pp supremum.record
|
706
702
|
puts
|
707
703
|
|
708
704
|
puts "garbage records:"
|
709
705
|
each_garbage_record do |rec|
|
710
|
-
pp rec
|
706
|
+
pp rec.record
|
711
707
|
puts
|
712
708
|
end
|
713
709
|
puts
|
714
710
|
|
715
711
|
puts "records:"
|
716
712
|
each_record do |rec|
|
717
|
-
pp rec
|
713
|
+
pp rec.record
|
718
714
|
puts
|
719
715
|
end
|
720
716
|
puts
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
|
3
|
+
class Innodb::Page::Index::Compressed < Innodb::Page::Index
|
4
|
+
# The number of directory slots in use.
|
5
|
+
def directory_slots
|
6
|
+
page_header[:n_heap] - 2
|
7
|
+
end
|
8
|
+
|
9
|
+
def directory
|
10
|
+
super.map { |n| n & 0x3fff }
|
11
|
+
end
|
12
|
+
|
13
|
+
def uncompressed_columns_size
|
14
|
+
if level == 0
|
15
|
+
if record_format && record_format[:type] == :clustered
|
16
|
+
6 + 7 # Transaction ID + Roll Pointer
|
17
|
+
else
|
18
|
+
0
|
19
|
+
end
|
20
|
+
else
|
21
|
+
4 # Node pointer for non-leaf pages
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Return the amount of free space in the page.
|
26
|
+
def free_space
|
27
|
+
free_space_start = size - size_fil_trailer - directory_space -
|
28
|
+
(uncompressed_columns_size * (page_header[:n_heap] - 2))
|
29
|
+
puts "Free space start == %04x" % [offset * size + free_space_start]
|
30
|
+
c = cursor(free_space_start).backward
|
31
|
+
zero_bytes = 0
|
32
|
+
while (b = c.get_uint8) == 0
|
33
|
+
zero_bytes += 1
|
34
|
+
end
|
35
|
+
zero_bytes
|
36
|
+
#page_header[:garbage] +
|
37
|
+
# (size - size_fil_trailer - directory_space - page_header[:heap_top])
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
Innodb::Page::SPECIALIZED_CLASSES[{:type => :INDEX, :compressed => true}] = Innodb::Page::Index::Compressed
|
42
|
+
|
data/lib/innodb/page/inode.rb
CHANGED
data/lib/innodb/page/sys.rb
CHANGED
data/lib/innodb/page/trx_sys.rb
CHANGED
data/lib/innodb/page.rb
CHANGED
@@ -0,0 +1,49 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
|
3
|
+
class Innodb::Record
|
4
|
+
attr_accessor :record
|
5
|
+
|
6
|
+
def initialize(record)
|
7
|
+
@record = record
|
8
|
+
end
|
9
|
+
|
10
|
+
def header
|
11
|
+
record[:header]
|
12
|
+
end
|
13
|
+
|
14
|
+
def offset
|
15
|
+
record[:offset]
|
16
|
+
end
|
17
|
+
|
18
|
+
def next
|
19
|
+
record[:next]
|
20
|
+
end
|
21
|
+
|
22
|
+
def key
|
23
|
+
record[:key]
|
24
|
+
end
|
25
|
+
|
26
|
+
def row
|
27
|
+
record[:row]
|
28
|
+
end
|
29
|
+
|
30
|
+
def child_page_number
|
31
|
+
record[:child_page_number]
|
32
|
+
end
|
33
|
+
|
34
|
+
def uncached_fields
|
35
|
+
fields_hash = {}
|
36
|
+
[:key, :row].each do |group|
|
37
|
+
if record[group]
|
38
|
+
record[group].each do |column|
|
39
|
+
fields_hash[column[:name]] = column[:value]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
fields_hash
|
44
|
+
end
|
45
|
+
|
46
|
+
def fields
|
47
|
+
@fields ||= uncached_fields
|
48
|
+
end
|
49
|
+
end
|
@@ -110,6 +110,14 @@ class Innodb::RecordDescriber
|
|
110
110
|
add_field :row, name, type
|
111
111
|
end
|
112
112
|
|
113
|
+
def field_names
|
114
|
+
names = []
|
115
|
+
[:key, :row].each do |group|
|
116
|
+
names += description[group].map { |n| n[:name] }
|
117
|
+
end
|
118
|
+
names
|
119
|
+
end
|
120
|
+
|
113
121
|
def generate_class(name="Describer_#{object_id}")
|
114
122
|
str = "class #{name}\n"
|
115
123
|
str << " type %s\n" % [
|
data/lib/innodb/space.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
|
+
|
2
3
|
# An InnoDB space file, which can be either a multi-table ibdataN file
|
3
4
|
# or a single-table "innodb_file_per_table" .ibd file.
|
5
|
+
|
4
6
|
class Innodb::Space
|
5
7
|
# InnoDB's default page size is 16KiB.
|
6
8
|
DEFAULT_PAGE_SIZE = 16384
|
@@ -175,6 +177,10 @@ class Innodb::Space
|
|
175
177
|
@fsp ||= page(page_fsp_hdr).fsp_header
|
176
178
|
end
|
177
179
|
|
180
|
+
def space_id
|
181
|
+
fsp[:space_id]
|
182
|
+
end
|
183
|
+
|
178
184
|
# Return the page number for the space's TRX_SYS page.
|
179
185
|
def page_trx_sys
|
180
186
|
5
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
|
3
|
+
class Innodb::System
|
4
|
+
attr_reader :config
|
5
|
+
attr_accessor :spaces
|
6
|
+
|
7
|
+
def initialize(system_space_file)
|
8
|
+
@config = {
|
9
|
+
:datadir => ".",
|
10
|
+
}
|
11
|
+
@spaces = {}
|
12
|
+
@spaces[0] = Innodb::Space.new(system_space_file)
|
13
|
+
end
|
14
|
+
|
15
|
+
def system_space
|
16
|
+
@spaces[0]
|
17
|
+
end
|
18
|
+
|
19
|
+
def each_record_from_data_dictionary_index(table, index)
|
20
|
+
unless block_given?
|
21
|
+
return enum_for(:each_record_from_data_dictionary_index, table, index)
|
22
|
+
end
|
23
|
+
|
24
|
+
index = system_space.data_dictionary.index(table, index)
|
25
|
+
index.each_record do |record|
|
26
|
+
yield record
|
27
|
+
end
|
28
|
+
nil
|
29
|
+
end
|
30
|
+
|
31
|
+
def each_table
|
32
|
+
unless block_given?
|
33
|
+
return enum_for(:each_table)
|
34
|
+
end
|
35
|
+
|
36
|
+
each_record_from_data_dictionary_index(:SYS_TABLES, :PRIMARY) do |record|
|
37
|
+
yield record.fields
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def each_index
|
42
|
+
unless block_given?
|
43
|
+
return enum_for(:each_index)
|
44
|
+
end
|
45
|
+
|
46
|
+
each_record_from_data_dictionary_index(:SYS_INDEXES, :PRIMARY) do |record|
|
47
|
+
yield record.fields
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def add_space(space)
|
52
|
+
@spaces[space.space_id] = space
|
53
|
+
end
|
54
|
+
|
55
|
+
def add_space_file(space_file)
|
56
|
+
add_space(Innodb::Space.new(space_file))
|
57
|
+
end
|
58
|
+
end
|
data/lib/innodb/undo_log.rb
CHANGED
data/lib/innodb/version.rb
CHANGED
data/lib/innodb/xdes.rb
CHANGED
data/lib/innodb.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
|
+
|
2
3
|
# A set of classes for parsing and working with InnoDB data files.
|
4
|
+
|
3
5
|
module Innodb; end
|
4
6
|
|
5
7
|
require "enumerator"
|
@@ -16,8 +18,10 @@ require "innodb/page/index"
|
|
16
18
|
require "innodb/page/trx_sys"
|
17
19
|
require "innodb/page/sys"
|
18
20
|
require "innodb/page/undo_log"
|
21
|
+
require "innodb/record"
|
19
22
|
require "innodb/field"
|
20
23
|
require "innodb/space"
|
24
|
+
require "innodb/system"
|
21
25
|
require "innodb/inode"
|
22
26
|
require "innodb/index"
|
23
27
|
require "innodb/log_block"
|
metadata
CHANGED
@@ -1,15 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: innodb_ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.5
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Jeremy Cole
|
9
|
+
- Davi Arnaut
|
9
10
|
autorequire:
|
10
11
|
bindir: bin
|
11
12
|
cert_chain: []
|
12
|
-
date:
|
13
|
+
date: 2014-01-30 00:00:00.000000000 Z
|
13
14
|
dependencies:
|
14
15
|
- !ruby/object:Gem::Dependency
|
15
16
|
name: bindata
|
@@ -35,38 +36,45 @@ executables:
|
|
35
36
|
extensions: []
|
36
37
|
extra_rdoc_files: []
|
37
38
|
files:
|
39
|
+
- LICENSE
|
40
|
+
- AUTHORS.md
|
38
41
|
- README.md
|
39
42
|
- lib/innodb.rb
|
40
43
|
- lib/innodb/checksum.rb
|
41
44
|
- lib/innodb/cursor.rb
|
42
45
|
- lib/innodb/data_dictionary.rb
|
46
|
+
- lib/innodb/data_type.rb
|
43
47
|
- lib/innodb/field.rb
|
44
|
-
- lib/innodb/field_type.rb
|
45
48
|
- lib/innodb/fseg_entry.rb
|
46
49
|
- lib/innodb/index.rb
|
47
50
|
- lib/innodb/inode.rb
|
48
51
|
- lib/innodb/list.rb
|
49
52
|
- lib/innodb/log.rb
|
50
53
|
- lib/innodb/log_block.rb
|
54
|
+
- lib/innodb/log_group.rb
|
51
55
|
- lib/innodb/page.rb
|
52
56
|
- lib/innodb/page/blob.rb
|
53
57
|
- lib/innodb/page/fsp_hdr_xdes.rb
|
54
58
|
- lib/innodb/page/index.rb
|
59
|
+
- lib/innodb/page/index_compressed.rb
|
55
60
|
- lib/innodb/page/inode.rb
|
56
61
|
- lib/innodb/page/sys.rb
|
57
62
|
- lib/innodb/page/sys_data_dictionary_header.rb
|
58
63
|
- lib/innodb/page/sys_rseg_header.rb
|
59
64
|
- lib/innodb/page/trx_sys.rb
|
60
65
|
- lib/innodb/page/undo_log.rb
|
66
|
+
- lib/innodb/record.rb
|
61
67
|
- lib/innodb/record_describer.rb
|
62
68
|
- lib/innodb/space.rb
|
69
|
+
- lib/innodb/system.rb
|
63
70
|
- lib/innodb/undo_log.rb
|
64
71
|
- lib/innodb/version.rb
|
65
72
|
- lib/innodb/xdes.rb
|
66
73
|
- bin/innodb_log
|
67
74
|
- bin/innodb_space
|
68
|
-
homepage:
|
69
|
-
licenses:
|
75
|
+
homepage: https://github.com/jeremycole/innodb_ruby
|
76
|
+
licenses:
|
77
|
+
- New BSD (3-clause)
|
70
78
|
post_install_message:
|
71
79
|
rdoc_options: []
|
72
80
|
require_paths:
|
data/lib/innodb/field_type.rb
DELETED
@@ -1,124 +0,0 @@
|
|
1
|
-
# -*- encoding : utf-8 -*-
|
2
|
-
class Innodb::FieldType
|
3
|
-
class GenericType
|
4
|
-
attr_reader :type
|
5
|
-
|
6
|
-
def initialize(type)
|
7
|
-
@type = type
|
8
|
-
end
|
9
|
-
|
10
|
-
def read(cursor, length)
|
11
|
-
cursor.get_bytes(length)
|
12
|
-
end
|
13
|
-
|
14
|
-
def read_extern(cursor)
|
15
|
-
cursor.name("extern") { get_extern_field(cursor) }
|
16
|
-
end
|
17
|
-
|
18
|
-
# Return an external reference field. An extern field contains the page
|
19
|
-
# address and the length of the externally stored part of the record data.
|
20
|
-
def get_extern_field(cursor)
|
21
|
-
{
|
22
|
-
:space_id => cursor.name("space_id") { cursor.get_uint32 },
|
23
|
-
:page_number => cursor.name("page_number") { cursor.get_uint32 },
|
24
|
-
:offset => cursor.name("offset") { cursor.get_uint32 },
|
25
|
-
:length => cursor.name("length") { cursor.get_uint64 & 0x3fffffff }
|
26
|
-
}
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
class IntegerType < GenericType
|
31
|
-
def read(cursor, length)
|
32
|
-
method = type.unsigned? ? :get_uint_by_size : :get_i_sint_by_size
|
33
|
-
cursor.send(method, type.length)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
class VariableStringType < GenericType
|
38
|
-
def read(cursor, length)
|
39
|
-
# The SQL standard defines that VARCHAR fields should have end-spaces
|
40
|
-
# stripped off.
|
41
|
-
super.sub(/[ ]+$/, "")
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
# Maps data type to fixed storage length.
|
46
|
-
TYPES = {
|
47
|
-
:TINYINT => { :class => IntegerType, :length => 1 },
|
48
|
-
:SMALLINT => { :class => IntegerType, :length => 2 },
|
49
|
-
:MEDIUMINT => { :class => IntegerType, :length => 3 },
|
50
|
-
:INT => { :class => IntegerType, :length => 4 },
|
51
|
-
:INT6 => { :class => IntegerType, :length => 6 },
|
52
|
-
:BIGINT => { :class => IntegerType, :length => 8 },
|
53
|
-
:CHAR => { :class => GenericType },
|
54
|
-
:VARCHAR => { :class => VariableStringType },
|
55
|
-
:BLOB => { :class => GenericType },
|
56
|
-
}
|
57
|
-
|
58
|
-
def self.parse_base_type_and_modifiers(type_string)
|
59
|
-
if matches = /^([a-zA-Z0-9]+)(\(([0-9, ]+)\))?$/.match(type_string)
|
60
|
-
base_type = matches[1].upcase.to_sym
|
61
|
-
if matches[3]
|
62
|
-
modifiers = matches[3].sub(/[ ]/, "").split(/,/).map { |s| s.to_i }
|
63
|
-
else
|
64
|
-
modifiers = []
|
65
|
-
end
|
66
|
-
[base_type, modifiers]
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
attr_reader :base_type
|
71
|
-
attr_reader :length
|
72
|
-
attr_reader :reader
|
73
|
-
def initialize(type_string, properties)
|
74
|
-
@base_type, modifiers = self.class.parse_base_type_and_modifiers(type_string)
|
75
|
-
@length = nil
|
76
|
-
@nullable = !properties.include?(:NOT_NULL)
|
77
|
-
@unsigned = properties.include?(:UNSIGNED)
|
78
|
-
@variable = false
|
79
|
-
@blob = false
|
80
|
-
case
|
81
|
-
when TYPES[base_type][:class] == IntegerType
|
82
|
-
@length = TYPES[base_type][:length]
|
83
|
-
when base_type == :CHAR
|
84
|
-
@length = modifiers[0]
|
85
|
-
when base_type == :VARCHAR
|
86
|
-
@length = modifiers[0]
|
87
|
-
@variable = true
|
88
|
-
when base_type == :BLOB
|
89
|
-
@blob = true
|
90
|
-
@variable = true
|
91
|
-
else
|
92
|
-
raise "Data type '#{type_string}' is not supported"
|
93
|
-
end
|
94
|
-
@reader = TYPES[base_type][:class].new(self)
|
95
|
-
end
|
96
|
-
|
97
|
-
def unsigned?
|
98
|
-
@unsigned
|
99
|
-
end
|
100
|
-
|
101
|
-
def nullable?
|
102
|
-
@nullable
|
103
|
-
end
|
104
|
-
|
105
|
-
def variable?
|
106
|
-
@variable
|
107
|
-
end
|
108
|
-
|
109
|
-
def blob?
|
110
|
-
@blob
|
111
|
-
end
|
112
|
-
|
113
|
-
def name_suffix
|
114
|
-
if [:CHAR, :VARCHAR].include?(base_type)
|
115
|
-
"(#{length})"
|
116
|
-
else
|
117
|
-
""
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
def name
|
122
|
-
"#{base_type}#{name_suffix}"
|
123
|
-
end
|
124
|
-
end
|