activerecord 1.10.1 → 1.11.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 +187 -19
- data/RUNNING_UNIT_TESTS +11 -0
- data/lib/active_record.rb +3 -1
- data/lib/active_record/acts/list.rb +25 -14
- data/lib/active_record/acts/nested_set.rb +4 -4
- data/lib/active_record/acts/tree.rb +18 -1
- data/lib/active_record/associations.rb +90 -17
- data/lib/active_record/associations/association_collection.rb +44 -5
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +17 -4
- data/lib/active_record/associations/has_many_association.rb +13 -3
- data/lib/active_record/associations/has_one_association.rb +19 -0
- data/lib/active_record/base.rb +292 -268
- data/lib/active_record/callbacks.rb +14 -14
- data/lib/active_record/connection_adapters/abstract_adapter.rb +137 -75
- data/lib/active_record/connection_adapters/db2_adapter.rb +10 -8
- data/lib/active_record/connection_adapters/mysql_adapter.rb +91 -64
- data/lib/active_record/connection_adapters/oci_adapter.rb +6 -6
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +113 -60
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +15 -12
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +159 -132
- data/lib/active_record/fixtures.rb +59 -12
- data/lib/active_record/locking.rb +10 -9
- data/lib/active_record/migration.rb +112 -5
- data/lib/active_record/query_cache.rb +64 -0
- data/lib/active_record/timestamp.rb +10 -8
- data/lib/active_record/validations.rb +121 -26
- data/rakefile +16 -10
- data/test/aaa_create_tables_test.rb +26 -48
- data/test/abstract_unit.rb +3 -0
- data/test/aggregations_test.rb +19 -19
- data/test/association_callbacks_test.rb +110 -0
- data/test/associations_go_eager_test.rb +48 -14
- data/test/associations_test.rb +344 -142
- data/test/base_test.rb +150 -31
- data/test/binary_test.rb +7 -0
- data/test/callbacks_test.rb +24 -5
- data/test/column_alias_test.rb +2 -2
- data/test/connections/native_sqlserver_odbc/connection.rb +26 -0
- data/test/deprecated_associations_test.rb +27 -28
- data/test/deprecated_finder_test.rb +8 -9
- data/test/finder_test.rb +52 -17
- data/test/fixtures/author.rb +39 -0
- data/test/fixtures/categories.yml +7 -0
- data/test/fixtures/categories_posts.yml +8 -0
- data/test/fixtures/category.rb +2 -0
- data/test/fixtures/comment.rb +3 -1
- data/test/fixtures/comments.yml +43 -1
- data/test/fixtures/companies.yml +14 -0
- data/test/fixtures/company.rb +1 -1
- data/test/fixtures/computers.yml +2 -1
- data/test/fixtures/db_definitions/db2.sql +7 -2
- data/test/fixtures/db_definitions/mysql.drop.sql +2 -0
- data/test/fixtures/db_definitions/mysql.sql +11 -6
- data/test/fixtures/db_definitions/oci.sql +7 -2
- data/test/fixtures/db_definitions/postgresql.drop.sql +3 -1
- data/test/fixtures/db_definitions/postgresql.sql +8 -5
- data/test/fixtures/db_definitions/sqlite.drop.sql +2 -0
- data/test/fixtures/db_definitions/sqlite.sql +9 -4
- data/test/fixtures/db_definitions/sqlserver.drop.sql +2 -0
- data/test/fixtures/db_definitions/sqlserver.sql +12 -7
- data/test/fixtures/developer.rb +8 -1
- data/test/fixtures/migrations/3_innocent_jointable.rb +12 -0
- data/test/fixtures/post.rb +8 -2
- data/test/fixtures/posts.yml +21 -0
- data/test/fixtures/project.rb +14 -1
- data/test/fixtures/subscriber.rb +3 -0
- data/test/fixtures_test.rb +14 -0
- data/test/inheritance_test.rb +30 -22
- data/test/lifecycle_test.rb +3 -4
- data/test/locking_test.rb +2 -4
- data/test/migration_test.rb +186 -0
- data/test/mixin_nested_set_test.rb +19 -19
- data/test/mixin_test.rb +88 -88
- data/test/modules_test.rb +5 -10
- data/test/multiple_db_test.rb +2 -0
- data/test/pk_test.rb +8 -12
- data/test/reflection_test.rb +8 -4
- data/test/schema_test_postgresql.rb +63 -0
- data/test/thread_safety_test.rb +4 -1
- data/test/transactions_test.rb +9 -2
- data/test/unconnected_test.rb +1 -0
- data/test/validations_test.rb +151 -8
- metadata +11 -5
- data/test/migration_mysql.rb +0 -104
@@ -90,20 +90,21 @@ module ActiveRecord
|
|
90
90
|
def native_database_types
|
91
91
|
{
|
92
92
|
:primary_key => "INTEGER PRIMARY KEY NOT NULL",
|
93
|
-
:string => "
|
94
|
-
:text => "
|
95
|
-
:integer => "
|
96
|
-
:float => "float",
|
97
|
-
:datetime => "
|
98
|
-
:timestamp => "
|
99
|
-
:time => "
|
100
|
-
:date => "
|
101
|
-
:binary => "
|
102
|
-
:boolean => "
|
93
|
+
:string => { :name => "varchar", :limit => 255 },
|
94
|
+
:text => { :name => "text" },
|
95
|
+
:integer => { :name => "integer" },
|
96
|
+
:float => { :name => "float" },
|
97
|
+
:datetime => { :name => "datetime" },
|
98
|
+
:timestamp => { :name => "datetime" },
|
99
|
+
:time => { :name => "datetime" },
|
100
|
+
:date => { :name => "date" },
|
101
|
+
:binary => { :name => "blob" },
|
102
|
+
:boolean => { :name => "integer" }
|
103
103
|
}
|
104
104
|
end
|
105
105
|
|
106
106
|
def execute(sql, name = nil)
|
107
|
+
#log(sql, name, @connection) { |connection| connection.execute(sql) }
|
107
108
|
log(sql, name) { @connection.execute(sql) }
|
108
109
|
end
|
109
110
|
|
@@ -127,7 +128,9 @@ module ActiveRecord
|
|
127
128
|
execute(sql, name).map do |row|
|
128
129
|
record = {}
|
129
130
|
row.each_key do |key|
|
130
|
-
|
131
|
+
if key.is_a?(String)
|
132
|
+
record[key.sub(/^\w+\./, '')] = row[key]
|
133
|
+
end
|
131
134
|
end
|
132
135
|
record
|
133
136
|
end
|
@@ -159,7 +162,7 @@ module ActiveRecord
|
|
159
162
|
end
|
160
163
|
|
161
164
|
def quote_column_name(name)
|
162
|
-
|
165
|
+
"'#{name}'"
|
163
166
|
end
|
164
167
|
|
165
168
|
def adapter_name()
|
@@ -8,26 +8,8 @@ require 'active_record/connection_adapters/abstract_adapter'
|
|
8
8
|
# Modifications: DeLynn Berry <delynnb@megastarfinancial.com>
|
9
9
|
# Date: 3/22/2005
|
10
10
|
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
# It relies on the ADO support in the DBI module. If you are using the
|
15
|
-
# one-click installer of Ruby, then you already have DBI installed, but
|
16
|
-
# the ADO module is *NOT* installed. You will need to get the latest
|
17
|
-
# source distribution of Ruby-DBI from http://ruby-dbi.sourceforge.net/
|
18
|
-
# unzip it, and copy the file <tt>src/lib/dbd_ado/ADO.rb</tt> to
|
19
|
-
# <tt>X:/Ruby/lib/ruby/site_ruby/1.8/DBD/ADO/ADO.rb</tt> (you will need to create
|
20
|
-
# the ADO directory). Once you've installed that file, you are ready to go.
|
21
|
-
#
|
22
|
-
# Options:
|
23
|
-
#
|
24
|
-
# * <tt>:host</tt> -- Defaults to localhost
|
25
|
-
# * <tt>:username</tt> -- Defaults to sa
|
26
|
-
# * <tt>:password</tt> -- Defaults to nothing
|
27
|
-
# * <tt>:database</tt> -- The name of the database. No default, must be provided.
|
28
|
-
#
|
29
|
-
# I have tested this code on a WindowsXP Pro SP1 system,
|
30
|
-
# ruby 1.8.2 (2004-07-29) [i386-mswin32], SQL Server 2000.
|
11
|
+
# Modifications (ODBC): Mark Imbriaco <mark.imbriaco@pobox.com>
|
12
|
+
# Date: 6/26/2005
|
31
13
|
#
|
32
14
|
module ActiveRecord
|
33
15
|
class Base
|
@@ -36,44 +18,47 @@ module ActiveRecord
|
|
36
18
|
|
37
19
|
symbolize_strings_in_hash(config)
|
38
20
|
|
39
|
-
|
40
|
-
username
|
41
|
-
password
|
42
|
-
|
43
|
-
|
44
|
-
|
21
|
+
mode = config[:mode] ? config[:mode].to_s.upcase : 'ADO'
|
22
|
+
username = config[:username] ? config[:username].to_s : 'sa'
|
23
|
+
password = config[:password] ? config[:password].to_s : ''
|
24
|
+
if mode == "ODBC"
|
25
|
+
raise ArgumentError, "Missing DSN. Argument ':dsn' must be set in order for this adapter to work." unless config.has_key?(:dsn)
|
26
|
+
dsn = config[:dsn]
|
27
|
+
conn = DBI.connect("DBI:ODBC:#{dsn}", username, password)
|
45
28
|
else
|
46
|
-
raise ArgumentError, "
|
29
|
+
raise ArgumentError, "Missing Database. Argument ':database' must be set in order for this adapter to work." unless config.has_key?(:database)
|
30
|
+
database = config[:database]
|
31
|
+
host = config[:host] ? config[:host].to_s : 'localhost'
|
32
|
+
conn = DBI.connect("DBI:ADO:Provider=SQLOLEDB;Data Source=#{host};Initial Catalog=#{database};User Id=#{username};Password=#{password};")
|
47
33
|
end
|
48
34
|
|
49
|
-
conn = DBI.connect("DBI:ADO:Provider=SQLOLEDB;Data Source=#{host};Initial Catalog=#{database};User Id=#{username};Password=#{password};")
|
50
35
|
conn["AutoCommit"] = true
|
51
|
-
|
52
36
|
ConnectionAdapters::SQLServerAdapter.new(conn, logger)
|
53
37
|
end
|
54
|
-
end
|
38
|
+
end # class Base
|
55
39
|
|
56
40
|
module ConnectionAdapters
|
57
41
|
class ColumnWithIdentity < Column# :nodoc:
|
58
|
-
attr_reader :identity, :scale
|
42
|
+
attr_reader :identity, :is_special, :scale
|
59
43
|
|
60
44
|
def initialize(name, default, sql_type = nil, is_identity = false, scale_value = 0)
|
61
45
|
super(name, default, sql_type)
|
62
|
-
@scale = scale_value
|
63
46
|
@identity = is_identity
|
47
|
+
@is_special = sql_type =~ /text|ntext|image/i ? true : false
|
48
|
+
@scale = scale_value
|
64
49
|
end
|
65
50
|
|
66
51
|
def simplified_type(field_type)
|
67
52
|
case field_type
|
68
|
-
when /int|bigint|smallint|tinyint/i
|
69
|
-
when /float|double|decimal|money|numeric|real|smallmoney/i
|
70
|
-
when /datetime|smalldatetime/i
|
71
|
-
when /timestamp/i
|
72
|
-
when /time/i
|
73
|
-
when /text|ntext/i
|
74
|
-
when /binary|image|varbinary/i
|
75
|
-
when /char|nchar|nvarchar|string|varchar/i
|
76
|
-
when /bit/i
|
53
|
+
when /int|bigint|smallint|tinyint/i then :integer
|
54
|
+
when /float|double|decimal|money|numeric|real|smallmoney/i then @scale == 0 ? :integer : :float
|
55
|
+
when /datetime|smalldatetime/i then :datetime
|
56
|
+
when /timestamp/i then :timestamp
|
57
|
+
when /time/i then :time
|
58
|
+
when /text|ntext/i then :text
|
59
|
+
when /binary|image|varbinary/i then :binary
|
60
|
+
when /char|nchar|nvarchar|string|varchar/i then :string
|
61
|
+
when /bit/i then :boolean
|
77
62
|
end
|
78
63
|
end
|
79
64
|
|
@@ -83,28 +68,32 @@ module ActiveRecord
|
|
83
68
|
when :string then value
|
84
69
|
when :integer then value == true || value == false ? value == true ? '1' : '0' : value.to_i
|
85
70
|
when :float then value.to_f
|
86
|
-
when :datetime then
|
71
|
+
when :datetime then cast_to_datetime(value)
|
87
72
|
when :timestamp then cast_to_time(value)
|
88
73
|
when :time then cast_to_time(value)
|
89
74
|
else value
|
90
75
|
end
|
91
76
|
end
|
92
77
|
|
93
|
-
def cast_to_date_or_time(value)
|
94
|
-
return value if value.is_a?(Date)
|
95
|
-
guess_date_or_time (value.is_a?(Time)) ? value : cast_to_time(value)
|
96
|
-
end
|
97
|
-
|
98
78
|
def cast_to_time(value)
|
99
79
|
return value if value.is_a?(Time)
|
100
|
-
time_array = ParseDate.parsedate
|
101
|
-
time_array[0] ||= 2000
|
102
|
-
|
80
|
+
time_array = ParseDate.parsedate(value)
|
81
|
+
time_array[0] ||= 2000
|
82
|
+
time_array[1] ||= 1
|
83
|
+
time_array[2] ||= 1
|
84
|
+
Time.send(Base.default_timezone, *time_array) rescue nil
|
103
85
|
end
|
104
86
|
|
105
|
-
def
|
106
|
-
|
107
|
-
|
87
|
+
def cast_to_datetime(value)
|
88
|
+
if value.is_a?(Time)
|
89
|
+
if value.year != 0 and value.month != 0 and value.day != 0
|
90
|
+
return value
|
91
|
+
else
|
92
|
+
return Time.mktime(2000, 1, 1, value.hour, value.min, value.sec) rescue nil
|
93
|
+
end
|
94
|
+
end
|
95
|
+
return cast_to_time(value) if value.is_a?(Date) or value.is_a?(String) rescue nil
|
96
|
+
value
|
108
97
|
end
|
109
98
|
|
110
99
|
# These methods will only allow the adapter to insert binary data with a length of 7K or less
|
@@ -112,14 +101,10 @@ module ActiveRecord
|
|
112
101
|
def string_to_binary(value)
|
113
102
|
value.gsub(/(\r|\n|\0|\x1a)/) do
|
114
103
|
case $1
|
115
|
-
when "\r"
|
116
|
-
|
117
|
-
when "\
|
118
|
-
|
119
|
-
when "\0"
|
120
|
-
"%02"
|
121
|
-
when "\x1a"
|
122
|
-
"%03"
|
104
|
+
when "\r" then "%00"
|
105
|
+
when "\n" then "%01"
|
106
|
+
when "\0" then "%02"
|
107
|
+
when "\x1a" then "%03"
|
123
108
|
end
|
124
109
|
end
|
125
110
|
end
|
@@ -127,22 +112,56 @@ module ActiveRecord
|
|
127
112
|
def binary_to_string(value)
|
128
113
|
value.gsub(/(%00|%01|%02|%03)/) do
|
129
114
|
case $1
|
130
|
-
when "%00"
|
131
|
-
|
132
|
-
when "%
|
133
|
-
|
134
|
-
when "%02\0"
|
135
|
-
"\0"
|
136
|
-
when "%03"
|
137
|
-
"\x1a"
|
115
|
+
when "%00" then "\r"
|
116
|
+
when "%01" then "\n"
|
117
|
+
when "%02\0" then "\0"
|
118
|
+
when "%03" then "\x1a"
|
138
119
|
end
|
139
120
|
end
|
140
121
|
end
|
141
|
-
|
142
122
|
end
|
143
123
|
|
124
|
+
# In ADO mode, this adapter will ONLY work on Windows systems,
|
125
|
+
# since it relies on Win32OLE, which, to my knowledge, is only
|
126
|
+
# available on Windows.
|
127
|
+
#
|
128
|
+
# This mode also relies on the ADO support in the DBI module. If you are using the
|
129
|
+
# one-click installer of Ruby, then you already have DBI installed, but
|
130
|
+
# the ADO module is *NOT* installed. You will need to get the latest
|
131
|
+
# source distribution of Ruby-DBI from http://ruby-dbi.sourceforge.net/
|
132
|
+
# unzip it, and copy the file
|
133
|
+
# <tt>src/lib/dbd_ado/ADO.rb</tt>
|
134
|
+
# to
|
135
|
+
# <tt>X:/Ruby/lib/ruby/site_ruby/1.8/DBD/ADO/ADO.rb</tt>
|
136
|
+
# (you will more than likely need to create the ADO directory).
|
137
|
+
# Once you've installed that file, you are ready to go.
|
138
|
+
#
|
139
|
+
# In ODBC mode, the adapter requires the ODBC support in the DBI module which requires
|
140
|
+
# the Ruby ODBC module. Ruby ODBC 0.996 was used in development and testing,
|
141
|
+
# and it is available at http://www.ch-werner.de/rubyodbc/
|
142
|
+
#
|
143
|
+
# Options:
|
144
|
+
#
|
145
|
+
# * <tt>:mode</tt> -- ADO or ODBC. Defaults to ADO.
|
146
|
+
# * <tt>:username</tt> -- Defaults to sa.
|
147
|
+
# * <tt>:password</tt> -- Defaults to empty string.
|
148
|
+
#
|
149
|
+
# ADO specific options:
|
150
|
+
#
|
151
|
+
# * <tt>:host</tt> -- Defaults to localhost.
|
152
|
+
# * <tt>:database</tt> -- The name of the database. No default, must be provided.
|
153
|
+
#
|
154
|
+
# ODBC specific options:
|
155
|
+
#
|
156
|
+
# * <tt>:dsn</tt> -- Defaults to nothing.
|
157
|
+
#
|
158
|
+
# ADO code tested on Windows 2000 and higher systems,
|
159
|
+
# running ruby 1.8.2 (2004-07-29) [i386-mswin32], and SQL Server 2000 SP3.
|
160
|
+
#
|
161
|
+
# ODBC code tested on a Fedora Core 4 system, running FreeTDS 0.63,
|
162
|
+
# unixODBC 2.2.11, Ruby ODBC 0.996, Ruby DBI 0.0.23 and Ruby 1.8.2.
|
163
|
+
# [Linux strongmad 2.6.11-1.1369_FC4 #1 Thu Jun 2 22:55:56 EDT 2005 i686 i686 i386 GNU/Linux]
|
144
164
|
class SQLServerAdapter < AbstractAdapter
|
145
|
-
|
146
165
|
def native_database_types
|
147
166
|
{
|
148
167
|
:primary_key => "int NOT NULL IDENTITY(1, 1) PRIMARY KEY",
|
@@ -164,7 +183,6 @@ module ActiveRecord
|
|
164
183
|
end
|
165
184
|
|
166
185
|
def select_all(sql, name = nil)
|
167
|
-
add_limit!(sql, nil)
|
168
186
|
select(sql, name)
|
169
187
|
end
|
170
188
|
|
@@ -175,12 +193,11 @@ module ActiveRecord
|
|
175
193
|
end
|
176
194
|
|
177
195
|
def columns(table_name, name = nil)
|
178
|
-
sql = "SELECT COLUMN_NAME as ColName, COLUMN_DEFAULT as DefaultValue, DATA_TYPE as ColType, COL_LENGTH('#{table_name}', COLUMN_NAME) as Length, COLUMNPROPERTY(OBJECT_ID('#{table_name}'), COLUMN_NAME, 'IsIdentity') as IsIdentity, NUMERIC_SCALE as Scale FROM INFORMATION_SCHEMA.
|
179
|
-
|
180
|
-
# Uncomment if you want to have the Columns select statment logged.
|
196
|
+
sql = "SELECT COLUMN_NAME as ColName, COLUMN_DEFAULT as DefaultValue, DATA_TYPE as ColType, COL_LENGTH('#{table_name}', COLUMN_NAME) as Length, COLUMNPROPERTY(OBJECT_ID('#{table_name}'), COLUMN_NAME, 'IsIdentity') as IsIdentity, NUMERIC_SCALE as Scale FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '#{table_name}'"
|
197
|
+
# Comment out if you want to have the Columns select statment logged.
|
181
198
|
# Personnally, I think it adds unneccessary bloat to the log.
|
182
|
-
# If you do
|
183
|
-
log(sql, name
|
199
|
+
# If you do comment it out, make sure to un-comment the "result" line that follows
|
200
|
+
result = log(sql, name) { @connection.select_all(sql) }
|
184
201
|
#result = @connection.select_all(sql)
|
185
202
|
columns = []
|
186
203
|
result.each { |field| columns << ColumnWithIdentity.new(field[:ColName], field[:DefaultValue].to_s.gsub!(/[()\']/,"") =~ /null/ ? nil : field[:DefaultValue], "#{field[:ColType]}(#{field[:Length]})", field[:IsIdentity] == 1 ? true : false, field[:Scale]) }
|
@@ -199,12 +216,12 @@ module ActiveRecord
|
|
199
216
|
execute enable_identity_insert(table_name, true)
|
200
217
|
ii_enabled = true
|
201
218
|
rescue Exception => e
|
202
|
-
|
219
|
+
raise ActiveRecordError, "IDENTITY_INSERT could not be turned ON"
|
203
220
|
end
|
204
221
|
end
|
205
222
|
end
|
206
|
-
log(sql, name
|
207
|
-
|
223
|
+
log(sql, name) do
|
224
|
+
@connection.execute(sql)
|
208
225
|
select_one("SELECT @@IDENTITY AS Ident")["Ident"]
|
209
226
|
end
|
210
227
|
ensure
|
@@ -212,7 +229,7 @@ module ActiveRecord
|
|
212
229
|
begin
|
213
230
|
execute enable_identity_insert(table_name, false)
|
214
231
|
rescue Exception => e
|
215
|
-
|
232
|
+
raise ActiveRecordError, "IDENTITY_INSERT could not be turned OFF"
|
216
233
|
end
|
217
234
|
end
|
218
235
|
end
|
@@ -222,14 +239,12 @@ module ActiveRecord
|
|
222
239
|
if sql =~ /^INSERT/i
|
223
240
|
insert(sql, name)
|
224
241
|
elsif sql =~ /^UPDATE|DELETE/i
|
225
|
-
log(sql, name
|
226
|
-
|
242
|
+
log(sql, name) do
|
243
|
+
@connection.execute(sql)
|
227
244
|
retVal = select_one("SELECT @@ROWCOUNT AS AffectedRows")["AffectedRows"]
|
228
245
|
end
|
229
246
|
else
|
230
|
-
log(sql, name
|
231
|
-
conn.execute(sql)
|
232
|
-
end
|
247
|
+
log(sql, name) { @connection.execute(sql) }
|
233
248
|
end
|
234
249
|
end
|
235
250
|
|
@@ -239,27 +254,21 @@ module ActiveRecord
|
|
239
254
|
alias_method :delete, :update
|
240
255
|
|
241
256
|
def begin_db_transaction
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
@connection["AutoCommit"] = true
|
246
|
-
end
|
257
|
+
@connection["AutoCommit"] = false
|
258
|
+
rescue Exception => e
|
259
|
+
@connection["AutoCommit"] = true
|
247
260
|
end
|
248
261
|
|
249
262
|
def commit_db_transaction
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
@connection["AutoCommit"] = true
|
254
|
-
end
|
263
|
+
@connection.commit
|
264
|
+
ensure
|
265
|
+
@connection["AutoCommit"] = true
|
255
266
|
end
|
256
267
|
|
257
268
|
def rollback_db_transaction
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
@connection["AutoCommit"] = true
|
262
|
-
end
|
269
|
+
@connection.rollback
|
270
|
+
ensure
|
271
|
+
@connection["AutoCommit"] = true
|
263
272
|
end
|
264
273
|
|
265
274
|
def quote(value, column = nil)
|
@@ -280,21 +289,25 @@ module ActiveRecord
|
|
280
289
|
end
|
281
290
|
end
|
282
291
|
|
283
|
-
def quote_string(
|
284
|
-
|
292
|
+
def quote_string(string)
|
293
|
+
string.gsub(/\'/, "''")
|
285
294
|
end
|
286
295
|
|
287
296
|
def quote_column_name(name)
|
288
297
|
"[#{name}]"
|
289
298
|
end
|
290
299
|
|
291
|
-
def
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
300
|
+
def add_limit_offset!(sql, options)
|
301
|
+
if options.has_key?(:limit) and options.has_key?(:offset) and !options[:limit].nil? and !options[:offset].nil?
|
302
|
+
options[:order] ||= "id ASC"
|
303
|
+
total_rows = @connection.select_all("SELECT count(*) as TotalRows from #{get_table_name(sql)}")[0][:TotalRows].to_i
|
304
|
+
if (options[:limit] + options[:offset]) > total_rows
|
305
|
+
options[:limit] = (total_rows - options[:offset] > 0) ? (total_rows - options[:offset]) : 1
|
306
|
+
end
|
307
|
+
sql.gsub!(/SELECT/i, "SELECT * FROM ( SELECT TOP #{options[:limit]} * FROM ( SELECT TOP #{options[:limit] + options[:offset]}")<<" ) AS tmp1 ORDER BY #{change_order_direction(options[:order])} ) AS tmp2 ORDER BY #{options[:order]}"
|
308
|
+
else
|
309
|
+
sql.gsub!(/SELECT/i, "SELECT TOP #{options[:limit]}") unless options[:limit].nil?
|
310
|
+
end
|
298
311
|
end
|
299
312
|
|
300
313
|
def recreate_database(name)
|
@@ -313,8 +326,9 @@ module ActiveRecord
|
|
313
326
|
private
|
314
327
|
def select(sql, name = nil)
|
315
328
|
rows = []
|
316
|
-
|
317
|
-
|
329
|
+
repair_special_columns(sql)
|
330
|
+
log(sql, name) do
|
331
|
+
@connection.select_all(sql) do |row|
|
318
332
|
record = {}
|
319
333
|
row.column_names.each do |col|
|
320
334
|
record[col] = row[col]
|
@@ -332,8 +346,9 @@ module ActiveRecord
|
|
332
346
|
end
|
333
347
|
|
334
348
|
def get_table_name(sql)
|
335
|
-
if sql =~ /into\s*([^\s]+)\s*/i
|
336
|
-
|
349
|
+
if sql =~ /into\s*([^\s]+)\s*|update\s*([^\s]+)\s*/i
|
350
|
+
$1
|
351
|
+
elsif sql =~ /from\s*([^\s]+)\s*/i
|
337
352
|
$1
|
338
353
|
else
|
339
354
|
nil
|
@@ -341,18 +356,12 @@ module ActiveRecord
|
|
341
356
|
end
|
342
357
|
|
343
358
|
def has_identity_column(table_name)
|
344
|
-
|
359
|
+
!get_identity_column(table_name).nil?
|
345
360
|
end
|
346
361
|
|
347
362
|
def get_identity_column(table_name)
|
348
|
-
|
349
|
-
|
350
|
-
end
|
351
|
-
|
352
|
-
if @table_columns[table_name] == nil
|
353
|
-
@table_columns[table_name] = columns(table_name)
|
354
|
-
end
|
355
|
-
|
363
|
+
@table_columns = {} unless @table_columns
|
364
|
+
@table_columns[table_name] = columns(table_name) if @table_columns[table_name] == nil
|
356
365
|
@table_columns[table_name].each do |col|
|
357
366
|
return col.name if col.identity
|
358
367
|
end
|
@@ -361,17 +370,35 @@ module ActiveRecord
|
|
361
370
|
end
|
362
371
|
|
363
372
|
def query_contains_identity_column(sql, col)
|
364
|
-
|
373
|
+
sql =~ /\[#{col}\]/
|
374
|
+
end
|
375
|
+
|
376
|
+
def change_order_direction(order)
|
377
|
+
case order
|
378
|
+
when /DESC/i then order.gsub(/DESC/i, "ASC")
|
379
|
+
when /ASC/i then order.gsub(/ASC/i, "DESC")
|
380
|
+
else String.new(order).insert(-1, " DESC")
|
381
|
+
end
|
365
382
|
end
|
366
383
|
|
367
|
-
def
|
368
|
-
|
384
|
+
def get_special_columns(table_name)
|
385
|
+
special = []
|
386
|
+
@table_columns = {} unless @table_columns
|
387
|
+
@table_columns[table_name] = columns(table_name) if @table_columns[table_name] == nil
|
388
|
+
@table_columns[table_name].each do |col|
|
389
|
+
special << col.name if col.is_special
|
390
|
+
end
|
391
|
+
special
|
369
392
|
end
|
370
393
|
|
371
|
-
def
|
372
|
-
|
373
|
-
|
394
|
+
def repair_special_columns(sql)
|
395
|
+
special_cols = get_special_columns(get_table_name(sql))
|
396
|
+
for col in special_cols.to_a
|
397
|
+
sql.gsub!(Regexp.new(" #{col.to_s} = "), " #{col.to_s} LIKE ")
|
398
|
+
end
|
399
|
+
sql
|
374
400
|
end
|
375
|
-
|
376
|
-
|
377
|
-
end
|
401
|
+
|
402
|
+
end #class SQLServerAdapter < AbstractAdapter
|
403
|
+
end #module ConnectionAdapters
|
404
|
+
end #module ActiveRecord
|