activerecord 1.13.2 → 1.14.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- data/CHANGELOG +452 -10
- data/RUNNING_UNIT_TESTS +1 -1
- data/lib/active_record.rb +5 -2
- data/lib/active_record/acts/list.rb +1 -1
- data/lib/active_record/acts/tree.rb +29 -25
- data/lib/active_record/aggregations.rb +3 -2
- data/lib/active_record/associations.rb +783 -337
- data/lib/active_record/associations/association_collection.rb +7 -12
- data/lib/active_record/associations/association_proxy.rb +62 -24
- data/lib/active_record/associations/belongs_to_association.rb +27 -46
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +50 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +38 -38
- data/lib/active_record/associations/has_many_association.rb +61 -56
- data/lib/active_record/associations/has_many_through_association.rb +144 -0
- data/lib/active_record/associations/has_one_association.rb +22 -16
- data/lib/active_record/base.rb +482 -182
- data/lib/active_record/calculations.rb +225 -0
- data/lib/active_record/callbacks.rb +7 -7
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +162 -47
- data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +2 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +21 -1
- data/lib/active_record/connection_adapters/abstract_adapter.rb +34 -2
- data/lib/active_record/connection_adapters/db2_adapter.rb +107 -61
- data/lib/active_record/connection_adapters/mysql_adapter.rb +29 -6
- data/lib/active_record/connection_adapters/openbase_adapter.rb +349 -0
- data/lib/active_record/connection_adapters/{oci_adapter.rb → oracle_adapter.rb} +125 -59
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +24 -21
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +47 -8
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +36 -16
- data/lib/active_record/connection_adapters/sybase_adapter.rb +684 -0
- data/lib/active_record/fixtures.rb +42 -17
- data/lib/active_record/locking.rb +36 -15
- data/lib/active_record/migration.rb +111 -8
- data/lib/active_record/observer.rb +25 -1
- data/lib/active_record/reflection.rb +103 -41
- data/lib/active_record/schema.rb +2 -2
- data/lib/active_record/schema_dumper.rb +55 -18
- data/lib/active_record/timestamp.rb +6 -6
- data/lib/active_record/validations.rb +65 -40
- data/lib/active_record/vendor/db2.rb +10 -5
- data/lib/active_record/vendor/simple.rb +693 -702
- data/lib/active_record/version.rb +2 -2
- data/rakefile +4 -4
- data/test/aaa_create_tables_test.rb +25 -6
- data/test/abstract_unit.rb +39 -1
- data/test/adapter_test.rb +31 -4
- data/test/associations_cascaded_eager_loading_test.rb +106 -0
- data/test/associations_go_eager_test.rb +85 -16
- data/test/associations_join_model_test.rb +338 -0
- data/test/associations_test.rb +129 -50
- data/test/base_test.rb +204 -49
- data/test/binary_test.rb +1 -1
- data/test/calculations_test.rb +169 -0
- data/test/callbacks_test.rb +5 -23
- data/test/class_inheritable_attributes_test.rb +1 -1
- data/test/column_alias_test.rb +1 -1
- data/test/connections/native_mysql/connection.rb +1 -0
- data/test/connections/native_openbase/connection.rb +22 -0
- data/test/connections/{native_oci → native_oracle}/connection.rb +7 -9
- data/test/connections/native_sqlite/connection.rb +1 -1
- data/test/connections/native_sqlite3/connection.rb +1 -0
- data/test/connections/native_sqlite3/in_memory_connection.rb +1 -0
- data/test/connections/native_sybase/connection.rb +24 -0
- data/test/defaults_test.rb +18 -0
- data/test/deprecated_associations_test.rb +2 -2
- data/test/deprecated_finder_test.rb +0 -6
- data/test/finder_test.rb +26 -23
- data/test/fixtures/accounts.yml +10 -0
- data/test/fixtures/author.rb +31 -6
- data/test/fixtures/author_favorites.yml +4 -0
- data/test/fixtures/categories/special_categories.yml +9 -0
- data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -0
- data/test/fixtures/categories_posts.yml +4 -0
- data/test/fixtures/categorization.rb +5 -0
- data/test/fixtures/categorizations.yml +11 -0
- data/test/fixtures/category.rb +6 -0
- data/test/fixtures/company.rb +17 -5
- data/test/fixtures/company_in_module.rb +19 -5
- data/test/fixtures/db_definitions/db2.drop.sql +3 -0
- data/test/fixtures/db_definitions/db2.sql +121 -100
- data/test/fixtures/db_definitions/db22.sql +2 -2
- data/test/fixtures/db_definitions/firebird.drop.sql +4 -0
- data/test/fixtures/db_definitions/firebird.sql +26 -0
- data/test/fixtures/db_definitions/mysql.drop.sql +3 -0
- data/test/fixtures/db_definitions/mysql.sql +21 -1
- data/test/fixtures/db_definitions/openbase.drop.sql +2 -0
- data/test/fixtures/db_definitions/openbase.sql +282 -0
- data/test/fixtures/db_definitions/openbase2.drop.sql +2 -0
- data/test/fixtures/db_definitions/openbase2.sql +7 -0
- data/test/fixtures/db_definitions/{oci.drop.sql → oracle.drop.sql} +6 -0
- data/test/fixtures/db_definitions/{oci.sql → oracle.sql} +25 -4
- data/test/fixtures/db_definitions/{oci2.drop.sql → oracle2.drop.sql} +0 -0
- data/test/fixtures/db_definitions/{oci2.sql → oracle2.sql} +0 -0
- data/test/fixtures/db_definitions/postgresql.drop.sql +4 -0
- data/test/fixtures/db_definitions/postgresql.sql +22 -1
- data/test/fixtures/db_definitions/schema.rb +32 -0
- data/test/fixtures/db_definitions/sqlite.drop.sql +3 -0
- data/test/fixtures/db_definitions/sqlite.sql +18 -0
- data/test/fixtures/db_definitions/sqlserver.drop.sql +3 -0
- data/test/fixtures/db_definitions/sqlserver.sql +23 -3
- data/test/fixtures/db_definitions/sybase.drop.sql +31 -0
- data/test/fixtures/db_definitions/sybase.sql +204 -0
- data/test/fixtures/db_definitions/sybase2.drop.sql +4 -0
- data/test/fixtures/db_definitions/sybase2.sql +5 -0
- data/test/fixtures/developers.yml +6 -1
- data/test/fixtures/developers_projects.yml +4 -0
- data/test/fixtures/funny_jokes.yml +14 -0
- data/test/fixtures/joke.rb +6 -0
- data/test/fixtures/legacy_thing.rb +3 -0
- data/test/fixtures/legacy_things.yml +3 -0
- data/test/fixtures/mixin.rb +1 -1
- data/test/fixtures/person.rb +4 -1
- data/test/fixtures/post.rb +26 -1
- data/test/fixtures/project.rb +1 -0
- data/test/fixtures/reader.rb +4 -0
- data/test/fixtures/readers.yml +4 -0
- data/test/fixtures/reply.rb +2 -1
- data/test/fixtures/tag.rb +5 -0
- data/test/fixtures/tagging.rb +6 -0
- data/test/fixtures/taggings.yml +18 -0
- data/test/fixtures/tags.yml +7 -0
- data/test/fixtures/tasks.yml +2 -2
- data/test/fixtures/topic.rb +2 -2
- data/test/fixtures/topics.yml +1 -0
- data/test/fixtures_test.rb +47 -13
- data/test/inheritance_test.rb +2 -2
- data/test/locking_test.rb +15 -1
- data/test/method_scoping_test.rb +248 -13
- data/test/migration_test.rb +68 -11
- data/test/mixin_nested_set_test.rb +1 -1
- data/test/modules_test.rb +6 -1
- data/test/readonly_test.rb +1 -1
- data/test/reflection_test.rb +63 -9
- data/test/schema_dumper_test.rb +41 -0
- data/test/{synonym_test_oci.rb → synonym_test_oracle.rb} +1 -1
- data/test/threaded_connections_test.rb +10 -0
- data/test/unconnected_test.rb +12 -5
- data/test/validations_test.rb +197 -10
- metadata +295 -260
- data/test/fixtures/db_definitions/create_oracle_db.bat +0 -0
- data/test/fixtures/db_definitions/create_oracle_db.sh +0 -0
- data/test/fixtures/fixture_database.sqlite +0 -0
- data/test/fixtures/fixture_database_2.sqlite +0 -0
@@ -6,7 +6,7 @@ module ActiveRecord
|
|
6
6
|
def quote(value, column = nil)
|
7
7
|
case value
|
8
8
|
when String
|
9
|
-
if column && column.type == :binary
|
9
|
+
if column && column.type == :binary && column.class.respond_to?(:string_to_binary)
|
10
10
|
"'#{quote_string(column.class.string_to_binary(value))}'" # ' (for ruby-mode)
|
11
11
|
elsif column && [:integer, :float].include?(column.type)
|
12
12
|
value.to_s
|
@@ -4,7 +4,7 @@ module ActiveRecord
|
|
4
4
|
module ConnectionAdapters #:nodoc:
|
5
5
|
# An abstract definition of a column in a table.
|
6
6
|
class Column
|
7
|
-
attr_reader :name, :default, :type, :limit, :null
|
7
|
+
attr_reader :name, :default, :type, :limit, :null, :sql_type
|
8
8
|
attr_accessor :primary
|
9
9
|
|
10
10
|
# Instantiates a new column in the table.
|
@@ -15,6 +15,7 @@ module ActiveRecord
|
|
15
15
|
# +null+ determines if this column allows +NULL+ values.
|
16
16
|
def initialize(name, default, sql_type = nil, null = true)
|
17
17
|
@name, @type, @null = name, simplified_type(sql_type), null
|
18
|
+
@sql_type = sql_type
|
18
19
|
# have to do this one separately because type_cast depends on #type
|
19
20
|
@default = type_cast(default)
|
20
21
|
@limit = extract_limit(sql_type) unless sql_type.nil?
|
@@ -8,6 +8,16 @@ module ActiveRecord
|
|
8
8
|
{}
|
9
9
|
end
|
10
10
|
|
11
|
+
# This is the maximum length a table alias can be
|
12
|
+
def table_alias_length
|
13
|
+
255
|
14
|
+
end
|
15
|
+
|
16
|
+
# Truncates a table alias according to the limits of the current adapter.
|
17
|
+
def table_alias_for(table_name)
|
18
|
+
table_name[0..table_alias_length-1].gsub(/\./, '_')
|
19
|
+
end
|
20
|
+
|
11
21
|
# def tables(name = nil) end
|
12
22
|
|
13
23
|
# Returns an array of indexes for the given table.
|
@@ -153,6 +163,13 @@ module ActiveRecord
|
|
153
163
|
# The index will be named after the table and the first column names,
|
154
164
|
# unless you pass +:name+ as an option.
|
155
165
|
#
|
166
|
+
# When creating an index on multiple columns, the first column is used as a name
|
167
|
+
# for the index. For example, when you specify an index on two columns
|
168
|
+
# [+:first+, +:last+], the DBMS creates an index for both columns as well as an
|
169
|
+
# index for the first colum +:first+. Using just the first name for this index
|
170
|
+
# makes sense, because you will never have to create a singular index with this
|
171
|
+
# name.
|
172
|
+
#
|
156
173
|
# ===== Examples
|
157
174
|
# ====== Creating a simple index
|
158
175
|
# add_index(:suppliers, :name)
|
@@ -187,7 +204,10 @@ module ActiveRecord
|
|
187
204
|
# remove_index :accounts, :column => :branch_id
|
188
205
|
# Remove the index named by_branch_party in the accounts table.
|
189
206
|
# remove_index :accounts, :name => :by_branch_party
|
190
|
-
|
207
|
+
#
|
208
|
+
# You can remove an index on multiple columns by specifying the first column.
|
209
|
+
# add_index :accounts, [:username, :password]
|
210
|
+
# remove_index :accounts, :username
|
191
211
|
def remove_index(table_name, options = {})
|
192
212
|
execute "DROP INDEX #{index_name(table_name, options)} ON #{table_name}"
|
193
213
|
end
|
@@ -21,10 +21,11 @@ module ActiveRecord
|
|
21
21
|
class AbstractAdapter
|
22
22
|
include Quoting, DatabaseStatements, SchemaStatements
|
23
23
|
@@row_even = true
|
24
|
-
|
24
|
+
|
25
25
|
def initialize(connection, logger = nil) #:nodoc:
|
26
26
|
@connection, @logger = connection, logger
|
27
27
|
@runtime = 0
|
28
|
+
@last_verification = 0
|
28
29
|
end
|
29
30
|
|
30
31
|
# Returns the human-readable name of the adapter. Use mixed case - one
|
@@ -38,6 +39,12 @@ module ActiveRecord
|
|
38
39
|
def supports_migrations?
|
39
40
|
false
|
40
41
|
end
|
42
|
+
|
43
|
+
# Does this adapter support using DISTINCT within COUNT? This is +true+
|
44
|
+
# for all adapters except sqlite.
|
45
|
+
def supports_count_distinct?
|
46
|
+
true
|
47
|
+
end
|
41
48
|
|
42
49
|
# Should primary key values be selected from their corresponding
|
43
50
|
# sequence before the insert statement? If true, next_sequence_value
|
@@ -57,13 +64,35 @@ module ActiveRecord
|
|
57
64
|
|
58
65
|
# Is this connection active and ready to perform queries?
|
59
66
|
def active?
|
60
|
-
|
67
|
+
@active != false
|
61
68
|
end
|
62
69
|
|
63
70
|
# Close this connection and open a new one in its place.
|
64
71
|
def reconnect!
|
72
|
+
@active = true
|
65
73
|
end
|
66
74
|
|
75
|
+
# Close this connection
|
76
|
+
def disconnect!
|
77
|
+
@active = false
|
78
|
+
end
|
79
|
+
|
80
|
+
# Lazily verify this connection, calling +active?+ only if it hasn't
|
81
|
+
# been called for +timeout+ seconds.
|
82
|
+
def verify!(timeout)
|
83
|
+
now = Time.now.to_i
|
84
|
+
if (now - @last_verification) > timeout
|
85
|
+
reconnect! unless active?
|
86
|
+
@last_verification = now
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Provides access to the underlying database connection. Useful for
|
91
|
+
# when you need to call a proprietary method such as postgresql's lo_*
|
92
|
+
# methods
|
93
|
+
def raw_connection
|
94
|
+
@connection
|
95
|
+
end
|
67
96
|
|
68
97
|
protected
|
69
98
|
def log(sql, name)
|
@@ -83,6 +112,9 @@ module ActiveRecord
|
|
83
112
|
end
|
84
113
|
rescue Exception => e
|
85
114
|
# Log message and raise exception.
|
115
|
+
# Set last_verfication to 0, so that connection gets verified
|
116
|
+
# upon reentering the request loop
|
117
|
+
@last_verification = 0
|
86
118
|
message = "#{e.class.name}: #{e.message}: #{sql}"
|
87
119
|
log_info(message, name, 0)
|
88
120
|
raise ActiveRecord::StatementInvalid, message
|
@@ -14,16 +14,17 @@ begin
|
|
14
14
|
config = config.symbolize_keys
|
15
15
|
usr = config[:username]
|
16
16
|
pwd = config[:password]
|
17
|
+
schema = config[:schema]
|
17
18
|
|
18
19
|
if config.has_key?(:database)
|
19
20
|
database = config[:database]
|
20
21
|
else
|
21
|
-
raise ArgumentError,
|
22
|
+
raise ArgumentError, 'No database specified. Missing argument: database.'
|
22
23
|
end
|
23
24
|
|
24
25
|
connection = DB2::Connection.new(DB2::Environment.new)
|
25
26
|
connection.connect(database, usr, pwd)
|
26
|
-
ConnectionAdapters::DB2Adapter.new(connection)
|
27
|
+
ConnectionAdapters::DB2Adapter.new(connection, logger, :schema => schema)
|
27
28
|
end
|
28
29
|
end
|
29
30
|
|
@@ -35,7 +36,18 @@ begin
|
|
35
36
|
# * <tt>:username</tt> -- Defaults to nothing
|
36
37
|
# * <tt>:password</tt> -- Defaults to nothing
|
37
38
|
# * <tt>:database</tt> -- The name of the database. No default, must be provided.
|
39
|
+
# * <tt>:schema</tt> -- Database schema to be set initially.
|
38
40
|
class DB2Adapter < AbstractAdapter
|
41
|
+
def initialize(connection, logger, connection_options)
|
42
|
+
super(connection, logger)
|
43
|
+
@connection_options = connection_options
|
44
|
+
if schema = @connection_options[:schema]
|
45
|
+
with_statement do |stmt|
|
46
|
+
stmt.exec_direct("SET SCHEMA=#{schema}")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
39
51
|
def select_all(sql, name = nil)
|
40
52
|
select(sql, name)
|
41
53
|
end
|
@@ -51,14 +63,12 @@ begin
|
|
51
63
|
|
52
64
|
def execute(sql, name = nil)
|
53
65
|
rows_affected = 0
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
stmt.free
|
66
|
+
with_statement do |stmt|
|
67
|
+
log(sql, name) do
|
68
|
+
stmt.exec_direct(sql)
|
69
|
+
rows_affected = stmt.row_count
|
70
|
+
end
|
60
71
|
end
|
61
|
-
|
62
72
|
rows_affected
|
63
73
|
end
|
64
74
|
|
@@ -92,64 +102,72 @@ begin
|
|
92
102
|
end
|
93
103
|
|
94
104
|
def add_limit_offset!(sql, options)
|
95
|
-
if
|
96
|
-
|
97
|
-
#
|
98
|
-
|
99
|
-
|
100
|
-
sql.sub!(/WHERE/i, 'WHERE 1 = 2 AND ')
|
101
|
-
elsif
|
102
|
-
sql =~ /ORDER\s+BY/i
|
103
|
-
sql.sub!(/ORDER\s+BY/i, 'WHERE 1 = 2 ORDER BY')
|
104
|
-
else
|
105
|
-
sql << 'WHERE 1 = 2'
|
106
|
-
end
|
107
|
-
else
|
108
|
-
sql << " FETCH FIRST #{options[:limit]} ROWS ONLY"
|
109
|
-
end
|
110
|
-
end
|
111
|
-
if options[:offset] and !options[:offset].nil?
|
112
|
-
raise ArgumentError, ':offset option is not yet supported!'
|
105
|
+
if limit = options[:limit]
|
106
|
+
offset = options[:offset] || 0
|
107
|
+
# The following trick was added by andrea+rails@webcom.it.
|
108
|
+
sql.gsub!(/SELECT/i, 'SELECT B.* FROM (SELECT A.*, row_number() over () AS internal$rownum FROM (SELECT')
|
109
|
+
sql << ") A ) B WHERE B.internal$rownum > #{offset} AND B.internal$rownum <= #{limit + offset}"
|
113
110
|
end
|
114
111
|
end
|
115
112
|
|
116
113
|
def tables(name = nil)
|
117
|
-
stmt = DB2::Statement.new(@connection)
|
118
114
|
result = []
|
119
|
-
|
120
|
-
stmt
|
115
|
+
schema = @connection_options[:schema] || '%'
|
116
|
+
with_statement do |stmt|
|
117
|
+
stmt.tables(schema).each { |t| result << t[2].downcase }
|
118
|
+
end
|
121
119
|
result
|
122
120
|
end
|
123
121
|
|
122
|
+
def indexes(table_name, name = nil)
|
123
|
+
tmp = {}
|
124
|
+
schema = @connection_options[:schema] || ''
|
125
|
+
with_statement do |stmt|
|
126
|
+
stmt.indexes(table_name, schema).each do |t|
|
127
|
+
next unless t[5]
|
128
|
+
next if t[4] == 'SYSIBM' # Skip system indexes.
|
129
|
+
idx_name = t[5].downcase
|
130
|
+
col_name = t[8].downcase
|
131
|
+
if tmp.has_key?(idx_name)
|
132
|
+
tmp[idx_name].columns << col_name
|
133
|
+
else
|
134
|
+
is_unique = t[3] == 0
|
135
|
+
tmp[idx_name] = IndexDefinition.new(table_name, idx_name, is_unique, [col_name])
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
tmp.values
|
140
|
+
end
|
141
|
+
|
124
142
|
def columns(table_name, name = nil)
|
125
|
-
stmt = DB2::Statement.new(@connection)
|
126
143
|
result = []
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
144
|
+
schema = @connection_options[:schema] || '%'
|
145
|
+
with_statement do |stmt|
|
146
|
+
stmt.columns(table_name, schema).each do |c|
|
147
|
+
c_name = c[3].downcase
|
148
|
+
c_default = c[12] == 'NULL' ? nil : c[12]
|
149
|
+
c_default.gsub!(/^'(.*)'$/, '\1') if !c_default.nil?
|
150
|
+
c_type = c[5].downcase
|
151
|
+
c_type += "(#{c[6]})" if !c[6].nil? && c[6] != ''
|
152
|
+
result << Column.new(c_name, c_default, c_type, c[17] == 'YES')
|
153
|
+
end
|
154
|
+
end
|
137
155
|
result
|
138
156
|
end
|
139
157
|
|
140
158
|
def native_database_types
|
141
159
|
{
|
142
|
-
:primary_key =>
|
143
|
-
:string => { :name =>
|
144
|
-
:text => { :name =>
|
145
|
-
:integer => { :name =>
|
146
|
-
:float => { :name =>
|
147
|
-
:datetime => { :name =>
|
148
|
-
:timestamp => { :name =>
|
149
|
-
:time => { :name =>
|
150
|
-
:date => { :name =>
|
151
|
-
:binary => { :name =>
|
152
|
-
:boolean => { :name =>
|
160
|
+
:primary_key => 'int generated by default as identity (start with 42) primary key',
|
161
|
+
:string => { :name => 'varchar', :limit => 255 },
|
162
|
+
:text => { :name => 'clob', :limit => 32768 },
|
163
|
+
:integer => { :name => 'int' },
|
164
|
+
:float => { :name => 'float' },
|
165
|
+
:datetime => { :name => 'timestamp' },
|
166
|
+
:timestamp => { :name => 'timestamp' },
|
167
|
+
:time => { :name => 'time' },
|
168
|
+
:date => { :name => 'date' },
|
169
|
+
:binary => { :name => 'blob', :limit => 32768 },
|
170
|
+
:boolean => { :name => 'decimal', :limit => 1 }
|
153
171
|
}
|
154
172
|
end
|
155
173
|
|
@@ -161,8 +179,28 @@ begin
|
|
161
179
|
'0'
|
162
180
|
end
|
163
181
|
|
182
|
+
def active?
|
183
|
+
@connection.select_one 'select 1 from ibm.sysdummy1'
|
184
|
+
true
|
185
|
+
rescue Exception
|
186
|
+
false
|
187
|
+
end
|
188
|
+
|
189
|
+
def reconnect!
|
190
|
+
end
|
191
|
+
|
192
|
+
def table_alias_length
|
193
|
+
128
|
194
|
+
end
|
195
|
+
|
164
196
|
private
|
165
197
|
|
198
|
+
def with_statement
|
199
|
+
stmt = DB2::Statement.new(@connection)
|
200
|
+
yield stmt
|
201
|
+
stmt.free
|
202
|
+
end
|
203
|
+
|
166
204
|
def last_insert_id
|
167
205
|
row = select_one(<<-GETID.strip)
|
168
206
|
with temp(id) as (values (identity_val_local())) select * from temp
|
@@ -171,17 +209,17 @@ begin
|
|
171
209
|
end
|
172
210
|
|
173
211
|
def select(sql, name = nil)
|
174
|
-
stmt = nil
|
175
|
-
log(sql, name) do
|
176
|
-
stmt = DB2::Statement.new(@connection)
|
177
|
-
stmt.exec_direct("#{sql.gsub(/=\s*null/i, 'IS NULL')} with ur")
|
178
|
-
end
|
179
|
-
|
180
212
|
rows = []
|
181
|
-
|
182
|
-
|
213
|
+
with_statement do |stmt|
|
214
|
+
log(sql, name) do
|
215
|
+
stmt.exec_direct("#{sql.gsub(/=\s*null/i, 'IS NULL')} with ur")
|
216
|
+
end
|
217
|
+
|
218
|
+
while row = stmt.fetch_as_hash
|
219
|
+
row.delete('internal$rownum')
|
220
|
+
rows << row
|
221
|
+
end
|
183
222
|
end
|
184
|
-
stmt.free
|
185
223
|
rows
|
186
224
|
end
|
187
225
|
end
|
@@ -189,4 +227,12 @@ begin
|
|
189
227
|
end
|
190
228
|
rescue LoadError
|
191
229
|
# DB2 driver is unavailable.
|
230
|
+
module ActiveRecord # :nodoc:
|
231
|
+
class Base
|
232
|
+
def self.db2_connection(config) # :nodoc:
|
233
|
+
# Set up a reasonable error message
|
234
|
+
raise LoadError, "DB2 Libraries could not be loaded."
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
192
238
|
end
|
@@ -42,7 +42,8 @@ module ActiveRecord
|
|
42
42
|
class MysqlColumn < Column #:nodoc:
|
43
43
|
private
|
44
44
|
def simplified_type(field_type)
|
45
|
-
return :boolean if MysqlAdapter.emulate_booleans && field_type.downcase
|
45
|
+
return :boolean if MysqlAdapter.emulate_booleans && field_type.downcase.index("tinyint(1)")
|
46
|
+
return :string if field_type =~ /enum/i
|
46
47
|
super
|
47
48
|
end
|
48
49
|
end
|
@@ -115,7 +116,7 @@ module ActiveRecord
|
|
115
116
|
# QUOTING ==================================================
|
116
117
|
|
117
118
|
def quote(value, column = nil)
|
118
|
-
if value.kind_of?(String) && column && column.type == :binary
|
119
|
+
if value.kind_of?(String) && column && column.type == :binary && column.class.respond_to?(:string_to_binary)
|
119
120
|
s = column.class.string_to_binary(value).unpack("H*")[0]
|
120
121
|
"x'#{s}'"
|
121
122
|
else
|
@@ -160,9 +161,13 @@ module ActiveRecord
|
|
160
161
|
end
|
161
162
|
|
162
163
|
def reconnect!
|
163
|
-
|
164
|
+
disconnect!
|
164
165
|
connect
|
165
166
|
end
|
167
|
+
|
168
|
+
def disconnect!
|
169
|
+
@connection.close rescue nil
|
170
|
+
end
|
166
171
|
|
167
172
|
|
168
173
|
# DATABASE STATEMENTS ======================================
|
@@ -232,7 +237,14 @@ module ActiveRecord
|
|
232
237
|
# SCHEMA STATEMENTS ========================================
|
233
238
|
|
234
239
|
def structure_dump #:nodoc:
|
235
|
-
|
240
|
+
if supports_views?
|
241
|
+
sql = "SHOW FULL TABLES WHERE Table_type = 'BASE TABLE'"
|
242
|
+
else
|
243
|
+
sql = "SHOW TABLES"
|
244
|
+
end
|
245
|
+
|
246
|
+
select_all(sql).inject("") do |structure, table|
|
247
|
+
table.delete('Table_type')
|
236
248
|
structure += select_one("SHOW CREATE TABLE #{table.to_a.first.last}")["Create Table"] + ";\n\n"
|
237
249
|
end
|
238
250
|
end
|
@@ -243,13 +255,16 @@ module ActiveRecord
|
|
243
255
|
end
|
244
256
|
|
245
257
|
def create_database(name) #:nodoc:
|
246
|
-
execute "CREATE DATABASE
|
258
|
+
execute "CREATE DATABASE `#{name}`"
|
247
259
|
end
|
248
260
|
|
249
261
|
def drop_database(name) #:nodoc:
|
250
|
-
execute "DROP DATABASE IF EXISTS
|
262
|
+
execute "DROP DATABASE IF EXISTS `#{name}`"
|
251
263
|
end
|
252
264
|
|
265
|
+
def current_database
|
266
|
+
select_one("SELECT DATABASE() as db")["db"]
|
267
|
+
end
|
253
268
|
|
254
269
|
def tables(name = nil) #:nodoc:
|
255
270
|
tables = []
|
@@ -330,6 +345,14 @@ module ActiveRecord
|
|
330
345
|
result.free
|
331
346
|
rows
|
332
347
|
end
|
348
|
+
|
349
|
+
def supports_views?
|
350
|
+
version[0] >= 5
|
351
|
+
end
|
352
|
+
|
353
|
+
def version
|
354
|
+
@version ||= @connection.server_info.scan(/^(\d+)\.(\d+)\.(\d+)/).flatten.map { |v| v.to_i }
|
355
|
+
end
|
333
356
|
end
|
334
357
|
end
|
335
358
|
end
|