activerecord-rdb-adapter 0.9.4 → 0.9.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +8 -8
- data/extconf.rb +93 -93
- data/fb.c +3072 -3072
- data/fb_extensions.rb +21 -21
- data/lib/active_model/type/integer.rb +67 -67
- data/lib/active_record/connection_adapters/rdb/database_limits.rb +35 -35
- data/lib/active_record/connection_adapters/rdb/database_statements.rb +186 -183
- data/lib/active_record/connection_adapters/rdb/quoting.rb +152 -152
- data/lib/active_record/connection_adapters/rdb/schema_creation.rb +52 -52
- data/lib/active_record/connection_adapters/rdb/schema_dumper.rb +23 -23
- data/lib/active_record/connection_adapters/rdb/schema_statements.rb +431 -431
- data/lib/active_record/connection_adapters/rdb/table_definition.rb +28 -28
- data/lib/active_record/connection_adapters/rdb_adapter.rb +163 -163
- data/lib/active_record/connection_adapters/rdb_column.rb +69 -69
- data/lib/active_record/rdb_base.rb +34 -34
- data/lib/active_record/tasks/rdb_database_tasks.rb +78 -78
- data/lib/activerecord-rdb-adapter.rb +10 -10
- data/lib/arel/visitors/rdb_visitor.rb +135 -135
- metadata +3 -4
@@ -1,34 +1,34 @@
|
|
1
|
-
module ActiveRecord
|
2
|
-
module ConnectionHandling # :nodoc:
|
3
|
-
def rdb_connection(config)
|
4
|
-
require 'fb'
|
5
|
-
config = rdb_connection_config(config)
|
6
|
-
db = ::Fb::Database.new(config)
|
7
|
-
@database = db
|
8
|
-
begin
|
9
|
-
connection = db.connect
|
10
|
-
rescue StandardError
|
11
|
-
unless config[:create]
|
12
|
-
require 'pp'
|
13
|
-
pp config
|
14
|
-
raise ConnectionNotEstablished, 'No Firebird connections established.'
|
15
|
-
end
|
16
|
-
connection = db.create.connect
|
17
|
-
end
|
18
|
-
ConnectionAdapters::RdbAdapter.new(connection, logger, config)
|
19
|
-
end
|
20
|
-
|
21
|
-
def rdb_connection_config(config)
|
22
|
-
config = config.symbolize_keys.dup.reverse_merge(downcase_names: true)
|
23
|
-
port = config[:port] || 3050
|
24
|
-
raise ArgumentError, 'No database specified. Missing argument: database.' unless config[:database]
|
25
|
-
config[:database] = File.expand_path(config[:database], defined?(Rails) && Rails.root) if config[:host].nil? || /localhost/i.match?(config[:host])
|
26
|
-
config[:database] = "#{config[:host]}/#{port}:#{config[:database]}" if config[:host]
|
27
|
-
# config[:charset] = config[:charset].gsub(/-/, '') if config[:charset]
|
28
|
-
# config[:encoding] = config[:encoding].gsub(/-/, '') if config[:encoding]
|
29
|
-
config[:page_size] = 8192 unless config[:page_size]
|
30
|
-
config[:readonly_selects] = true unless config[:readonly_selects].present?
|
31
|
-
config
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionHandling # :nodoc:
|
3
|
+
def rdb_connection(config)
|
4
|
+
require 'fb'
|
5
|
+
config = rdb_connection_config(config)
|
6
|
+
db = ::Fb::Database.new(config)
|
7
|
+
@database = db
|
8
|
+
begin
|
9
|
+
connection = db.connect
|
10
|
+
rescue StandardError
|
11
|
+
unless config[:create]
|
12
|
+
require 'pp'
|
13
|
+
pp config
|
14
|
+
raise ConnectionNotEstablished, 'No Firebird connections established.'
|
15
|
+
end
|
16
|
+
connection = db.create.connect
|
17
|
+
end
|
18
|
+
ConnectionAdapters::RdbAdapter.new(connection, logger, config)
|
19
|
+
end
|
20
|
+
|
21
|
+
def rdb_connection_config(config)
|
22
|
+
config = config.symbolize_keys.dup.reverse_merge(downcase_names: true)
|
23
|
+
port = config[:port] || 3050
|
24
|
+
raise ArgumentError, 'No database specified. Missing argument: database.' unless config[:database]
|
25
|
+
config[:database] = File.expand_path(config[:database], defined?(Rails) && Rails.root) if config[:host].nil? || /localhost/i.match?(config[:host])
|
26
|
+
config[:database] = "#{config[:host]}/#{port}:#{config[:database]}" if config[:host]
|
27
|
+
# config[:charset] = config[:charset].gsub(/-/, '') if config[:charset]
|
28
|
+
# config[:encoding] = config[:encoding].gsub(/-/, '') if config[:encoding]
|
29
|
+
config[:page_size] = 8192 unless config[:page_size]
|
30
|
+
config[:readonly_selects] = true unless config[:readonly_selects].present?
|
31
|
+
config
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -1,78 +1,78 @@
|
|
1
|
-
module ActiveRecord
|
2
|
-
module Tasks # :nodoc:
|
3
|
-
class RdbDatabaseTasks # :nodoc:
|
4
|
-
delegate :rdb_connection, :rdb_connection_config, :establish_connection, to: ::ActiveRecord::Base
|
5
|
-
|
6
|
-
def initialize(configuration)
|
7
|
-
@configuration = rdb_connection_config(configuration)
|
8
|
-
end
|
9
|
-
|
10
|
-
def create
|
11
|
-
rdb_database.create
|
12
|
-
# create_db
|
13
|
-
establish_connection configuration
|
14
|
-
rescue ::Fb::Error => e
|
15
|
-
raise unless e.message.include?('File exists')
|
16
|
-
raise DatabaseAlreadyExists
|
17
|
-
end
|
18
|
-
|
19
|
-
def drop
|
20
|
-
establish_connection configuration
|
21
|
-
rdb_database.drop
|
22
|
-
rescue ::Fb::Error => e
|
23
|
-
raise ::ActiveRecord::ConnectionNotEstablished, e.message
|
24
|
-
end
|
25
|
-
|
26
|
-
def purge
|
27
|
-
begin
|
28
|
-
drop
|
29
|
-
rescue StandardError
|
30
|
-
nil
|
31
|
-
end
|
32
|
-
create
|
33
|
-
end
|
34
|
-
|
35
|
-
def structure_dump(filename, structure_dump_flags = nil)
|
36
|
-
isql :extract, output: filename
|
37
|
-
end
|
38
|
-
|
39
|
-
def structure_load(filename, structure_load_flags = nil)
|
40
|
-
isql input: filename
|
41
|
-
end
|
42
|
-
|
43
|
-
private
|
44
|
-
|
45
|
-
def rdb_database
|
46
|
-
::Fb::Database.new(configuration)
|
47
|
-
end
|
48
|
-
|
49
|
-
# Executes isql commands to load/dump the schema.
|
50
|
-
# The generated command might look like this:
|
51
|
-
# isql db/development.fdb -user SYSDBA -password masterkey -extract
|
52
|
-
def isql(*args)
|
53
|
-
opts = args.extract_options!
|
54
|
-
user, pass = configuration.values_at(:username, :password)
|
55
|
-
user ||= configuration[:user]
|
56
|
-
opts.reverse_merge!(user: user, password: pass)
|
57
|
-
cmd = [isql_executable, configuration[:database]]
|
58
|
-
cmd += opts.map { |name, val| "-#{name} #{val}" }
|
59
|
-
cmd += args.map { |flag| "-#{flag}" }
|
60
|
-
cmd = cmd.join(' ')
|
61
|
-
raise "Error running: #{cmd}" unless Kernel.system(cmd)
|
62
|
-
end
|
63
|
-
|
64
|
-
def isql_create(*_args)
|
65
|
-
"#{isql_executable} -input "
|
66
|
-
end
|
67
|
-
|
68
|
-
# Finds the isql command line utility from the PATH
|
69
|
-
# Many linux distros call this program isql-fb, instead of isql
|
70
|
-
def isql_executable
|
71
|
-
"/opt/RedDatabase/bin/isql"
|
72
|
-
end
|
73
|
-
|
74
|
-
attr_reader :configuration
|
75
|
-
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
1
|
+
module ActiveRecord
|
2
|
+
module Tasks # :nodoc:
|
3
|
+
class RdbDatabaseTasks # :nodoc:
|
4
|
+
delegate :rdb_connection, :rdb_connection_config, :establish_connection, to: ::ActiveRecord::Base
|
5
|
+
|
6
|
+
def initialize(configuration)
|
7
|
+
@configuration = rdb_connection_config(configuration)
|
8
|
+
end
|
9
|
+
|
10
|
+
def create
|
11
|
+
rdb_database.create
|
12
|
+
# create_db
|
13
|
+
establish_connection configuration
|
14
|
+
rescue ::Fb::Error => e
|
15
|
+
raise unless e.message.include?('File exists')
|
16
|
+
raise DatabaseAlreadyExists
|
17
|
+
end
|
18
|
+
|
19
|
+
def drop
|
20
|
+
establish_connection configuration
|
21
|
+
rdb_database.drop
|
22
|
+
rescue ::Fb::Error => e
|
23
|
+
raise ::ActiveRecord::ConnectionNotEstablished, e.message
|
24
|
+
end
|
25
|
+
|
26
|
+
def purge
|
27
|
+
begin
|
28
|
+
drop
|
29
|
+
rescue StandardError
|
30
|
+
nil
|
31
|
+
end
|
32
|
+
create
|
33
|
+
end
|
34
|
+
|
35
|
+
def structure_dump(filename, structure_dump_flags = nil)
|
36
|
+
isql :extract, output: filename
|
37
|
+
end
|
38
|
+
|
39
|
+
def structure_load(filename, structure_load_flags = nil)
|
40
|
+
isql input: filename
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def rdb_database
|
46
|
+
::Fb::Database.new(configuration)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Executes isql commands to load/dump the schema.
|
50
|
+
# The generated command might look like this:
|
51
|
+
# isql db/development.fdb -user SYSDBA -password masterkey -extract
|
52
|
+
def isql(*args)
|
53
|
+
opts = args.extract_options!
|
54
|
+
user, pass = configuration.values_at(:username, :password)
|
55
|
+
user ||= configuration[:user]
|
56
|
+
opts.reverse_merge!(user: user, password: pass)
|
57
|
+
cmd = [isql_executable, configuration[:database]]
|
58
|
+
cmd += opts.map { |name, val| "-#{name} #{val}" }
|
59
|
+
cmd += args.map { |flag| "-#{flag}" }
|
60
|
+
cmd = cmd.join(' ')
|
61
|
+
raise "Error running: #{cmd}" unless Kernel.system(cmd)
|
62
|
+
end
|
63
|
+
|
64
|
+
def isql_create(*_args)
|
65
|
+
"#{isql_executable} -input "
|
66
|
+
end
|
67
|
+
|
68
|
+
# Finds the isql command line utility from the PATH
|
69
|
+
# Many linux distros call this program isql-fb, instead of isql
|
70
|
+
def isql_executable
|
71
|
+
"/opt/RedDatabase/bin/isql"
|
72
|
+
end
|
73
|
+
|
74
|
+
attr_reader :configuration
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -1,10 +1,10 @@
|
|
1
|
-
require 'active_record/connection_adapters/rdb_adapter'
|
2
|
-
|
3
|
-
if defined?(::Rails::Railtie) && ::ActiveRecord::VERSION::MAJOR > 3
|
4
|
-
class Railtie < ::Rails::Railtie # :nodoc:
|
5
|
-
rake_tasks do
|
6
|
-
load 'active_record/tasks/rdb_database_tasks.rb'
|
7
|
-
ActiveRecord::Tasks::DatabaseTasks.register_task(/rdb/, ActiveRecord::Tasks::RdbDatabaseTasks)
|
8
|
-
end
|
9
|
-
end
|
10
|
-
end
|
1
|
+
require 'active_record/connection_adapters/rdb_adapter'
|
2
|
+
|
3
|
+
if defined?(::Rails::Railtie) && ::ActiveRecord::VERSION::MAJOR > 3
|
4
|
+
class Railtie < ::Rails::Railtie # :nodoc:
|
5
|
+
rake_tasks do
|
6
|
+
load 'active_record/tasks/rdb_database_tasks.rb'
|
7
|
+
ActiveRecord::Tasks::DatabaseTasks.register_task(/rdb/, ActiveRecord::Tasks::RdbDatabaseTasks)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -1,135 +1,135 @@
|
|
1
|
-
module Arel
|
2
|
-
module Visitors
|
3
|
-
class Rdb < Arel::Visitors::ToSql # :nodoc
|
4
|
-
private
|
5
|
-
|
6
|
-
def visit_Arel_Nodes_InsertStatement(o, collector)
|
7
|
-
collector << "INSERT INTO "
|
8
|
-
collector = visit o.relation, collector
|
9
|
-
|
10
|
-
unless o.columns.empty?
|
11
|
-
collector << " ("
|
12
|
-
o.columns.each_with_index do |x, i|
|
13
|
-
collector << ", " unless i == 0
|
14
|
-
collector << quote_column_name(x.name)
|
15
|
-
end
|
16
|
-
collector << ")"
|
17
|
-
end
|
18
|
-
|
19
|
-
if o.values
|
20
|
-
maybe_visit o.values, collector
|
21
|
-
elsif o.select
|
22
|
-
maybe_visit o.select, collector
|
23
|
-
else
|
24
|
-
collector
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def visit_Arel_Nodes_SelectStatement(o, collector)
|
29
|
-
collector << 'SELECT '
|
30
|
-
collector = visit o.offset, collector if o.offset && !o.limit
|
31
|
-
|
32
|
-
collector = o.cores.inject(collector) do |c, x|
|
33
|
-
visit_Arel_Nodes_SelectCore(x, c)
|
34
|
-
end
|
35
|
-
|
36
|
-
unless o.orders.empty?
|
37
|
-
collector << ORDER_BY
|
38
|
-
len = o.orders.length - 1
|
39
|
-
o.orders.each_with_index do |x, i|
|
40
|
-
collector = visit(x, collector)
|
41
|
-
collector << COMMA unless len == i
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
if o.limit && o.offset
|
46
|
-
collector = limit_with_rows o, collector
|
47
|
-
elsif o.limit && !o.offset
|
48
|
-
collector = visit o.limit, collector
|
49
|
-
end
|
50
|
-
|
51
|
-
maybe_visit o.lock, collector
|
52
|
-
end
|
53
|
-
|
54
|
-
def visit_Arel_Nodes_SelectCore(o, collector)
|
55
|
-
if o.set_quantifier
|
56
|
-
collector = visit o.set_quantifier, collector
|
57
|
-
collector << SPACE
|
58
|
-
end
|
59
|
-
|
60
|
-
unless o.projections.empty?
|
61
|
-
len = o.projections.length - 1
|
62
|
-
o.projections.each_with_index do |x, i|
|
63
|
-
collector = visit(x, collector)
|
64
|
-
collector << COMMA unless len == i
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
if o.source && !o.source.empty?
|
69
|
-
collector << ' FROM '
|
70
|
-
collector = visit o.source, collector
|
71
|
-
end
|
72
|
-
|
73
|
-
unless o.wheres.empty?
|
74
|
-
collector << WHERE
|
75
|
-
len = o.wheres.length - 1
|
76
|
-
o.wheres.each_with_index do |x, i|
|
77
|
-
collector = visit(x, collector)
|
78
|
-
collector << AND unless len == i
|
79
|
-
end
|
80
|
-
end
|
81
|
-
unless o.groups.empty?
|
82
|
-
collector << GROUP_BY
|
83
|
-
len = o.groups.length - 1
|
84
|
-
o.groups.each_with_index do |x, i|
|
85
|
-
collector = visit(x, collector)
|
86
|
-
collector << COMMA unless len == i
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
if Rails::VERSION::MAJOR < 5
|
91
|
-
collector = maybe_visit o.having, collector
|
92
|
-
else
|
93
|
-
unless o.havings.empty?
|
94
|
-
collector << ' HAVING '
|
95
|
-
inject_join o.havings, collector, AND
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
collector
|
100
|
-
end
|
101
|
-
|
102
|
-
def visit_Arel_Nodes_Limit(o, collector)
|
103
|
-
collector << ' ROWS '
|
104
|
-
visit o.expr, collector
|
105
|
-
end
|
106
|
-
|
107
|
-
def visit_Arel_Nodes_Offset(o, collector)
|
108
|
-
collector << ' SKIP '
|
109
|
-
visit o.expr, collector
|
110
|
-
end
|
111
|
-
|
112
|
-
def limit_with_rows o, collector
|
113
|
-
o.offset.expr.value = ActiveModel::Attribute.with_cast_value('OFFSET'.freeze,
|
114
|
-
o.offset.expr.value.value + 1,
|
115
|
-
ActiveModel::Type.default_value)
|
116
|
-
offset = o.offset.expr.value
|
117
|
-
o.limit.expr.value = ActiveModel::Attribute.with_cast_value('LIMIT'.freeze,
|
118
|
-
o.limit.expr.value.value + (offset.value - 1),
|
119
|
-
ActiveModel::Type.default_value)
|
120
|
-
limit = o.limit.expr.value
|
121
|
-
collector << ' ROWS '
|
122
|
-
collector.add_bind(offset) { |i| '?' }
|
123
|
-
collector << ' TO '
|
124
|
-
collector.add_bind(limit) { |i| '?' }
|
125
|
-
end
|
126
|
-
|
127
|
-
def quote_column_name name
|
128
|
-
return name if Arel::Nodes::SqlLiteral === name
|
129
|
-
|
130
|
-
@connection.quote_column_name(name)
|
131
|
-
end
|
132
|
-
|
133
|
-
end
|
134
|
-
end
|
135
|
-
end
|
1
|
+
module Arel
|
2
|
+
module Visitors
|
3
|
+
class Rdb < Arel::Visitors::ToSql # :nodoc
|
4
|
+
private
|
5
|
+
|
6
|
+
def visit_Arel_Nodes_InsertStatement(o, collector)
|
7
|
+
collector << "INSERT INTO "
|
8
|
+
collector = visit o.relation, collector
|
9
|
+
|
10
|
+
unless o.columns.empty?
|
11
|
+
collector << " ("
|
12
|
+
o.columns.each_with_index do |x, i|
|
13
|
+
collector << ", " unless i == 0
|
14
|
+
collector << quote_column_name(x.name)
|
15
|
+
end
|
16
|
+
collector << ")"
|
17
|
+
end
|
18
|
+
|
19
|
+
if o.values
|
20
|
+
maybe_visit o.values, collector
|
21
|
+
elsif o.select
|
22
|
+
maybe_visit o.select, collector
|
23
|
+
else
|
24
|
+
collector
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def visit_Arel_Nodes_SelectStatement(o, collector)
|
29
|
+
collector << 'SELECT '
|
30
|
+
collector = visit o.offset, collector if o.offset && !o.limit
|
31
|
+
|
32
|
+
collector = o.cores.inject(collector) do |c, x|
|
33
|
+
visit_Arel_Nodes_SelectCore(x, c)
|
34
|
+
end
|
35
|
+
|
36
|
+
unless o.orders.empty?
|
37
|
+
collector << ORDER_BY
|
38
|
+
len = o.orders.length - 1
|
39
|
+
o.orders.each_with_index do |x, i|
|
40
|
+
collector = visit(x, collector)
|
41
|
+
collector << COMMA unless len == i
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
if o.limit && o.offset
|
46
|
+
collector = limit_with_rows o, collector
|
47
|
+
elsif o.limit && !o.offset
|
48
|
+
collector = visit o.limit, collector
|
49
|
+
end
|
50
|
+
|
51
|
+
maybe_visit o.lock, collector
|
52
|
+
end
|
53
|
+
|
54
|
+
def visit_Arel_Nodes_SelectCore(o, collector)
|
55
|
+
if o.set_quantifier
|
56
|
+
collector = visit o.set_quantifier, collector
|
57
|
+
collector << SPACE
|
58
|
+
end
|
59
|
+
|
60
|
+
unless o.projections.empty?
|
61
|
+
len = o.projections.length - 1
|
62
|
+
o.projections.each_with_index do |x, i|
|
63
|
+
collector = visit(x, collector)
|
64
|
+
collector << COMMA unless len == i
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
if o.source && !o.source.empty?
|
69
|
+
collector << ' FROM '
|
70
|
+
collector = visit o.source, collector
|
71
|
+
end
|
72
|
+
|
73
|
+
unless o.wheres.empty?
|
74
|
+
collector << WHERE
|
75
|
+
len = o.wheres.length - 1
|
76
|
+
o.wheres.each_with_index do |x, i|
|
77
|
+
collector = visit(x, collector)
|
78
|
+
collector << AND unless len == i
|
79
|
+
end
|
80
|
+
end
|
81
|
+
unless o.groups.empty?
|
82
|
+
collector << GROUP_BY
|
83
|
+
len = o.groups.length - 1
|
84
|
+
o.groups.each_with_index do |x, i|
|
85
|
+
collector = visit(x, collector)
|
86
|
+
collector << COMMA unless len == i
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
if Rails::VERSION::MAJOR < 5
|
91
|
+
collector = maybe_visit o.having, collector
|
92
|
+
else
|
93
|
+
unless o.havings.empty?
|
94
|
+
collector << ' HAVING '
|
95
|
+
inject_join o.havings, collector, AND
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
collector
|
100
|
+
end
|
101
|
+
|
102
|
+
def visit_Arel_Nodes_Limit(o, collector)
|
103
|
+
collector << ' ROWS '
|
104
|
+
visit o.expr, collector
|
105
|
+
end
|
106
|
+
|
107
|
+
def visit_Arel_Nodes_Offset(o, collector)
|
108
|
+
collector << ' SKIP '
|
109
|
+
visit o.expr, collector
|
110
|
+
end
|
111
|
+
|
112
|
+
def limit_with_rows o, collector
|
113
|
+
o.offset.expr.value = ActiveModel::Attribute.with_cast_value('OFFSET'.freeze,
|
114
|
+
o.offset.expr.value.value + 1,
|
115
|
+
ActiveModel::Type.default_value)
|
116
|
+
offset = o.offset.expr.value
|
117
|
+
o.limit.expr.value = ActiveModel::Attribute.with_cast_value('LIMIT'.freeze,
|
118
|
+
o.limit.expr.value.value + (offset.value - 1),
|
119
|
+
ActiveModel::Type.default_value)
|
120
|
+
limit = o.limit.expr.value
|
121
|
+
collector << ' ROWS '
|
122
|
+
collector.add_bind(offset) { |i| '?' }
|
123
|
+
collector << ' TO '
|
124
|
+
collector.add_bind(limit) { |i| '?' }
|
125
|
+
end
|
126
|
+
|
127
|
+
def quote_column_name name
|
128
|
+
return name if Arel::Nodes::SqlLiteral === name
|
129
|
+
|
130
|
+
@connection.quote_column_name(name)
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|