activerecord-jdbc-adapter 0.8 → 0.8.1
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +21 -0
- data/Manifest.txt +12 -0
- data/README.txt +1 -0
- data/Rakefile +19 -13
- data/lib/active_record/connection_adapters/cachedb_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/jdbc_adapter.rb +22 -5
- data/lib/active_record/connection_adapters/jdbc_adapter_spec.rb +3 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +13 -0
- data/lib/jdbc_adapter/jdbc.rake +32 -29
- data/lib/jdbc_adapter/jdbc_adapter_internal.jar +0 -0
- data/lib/jdbc_adapter/jdbc_cachedb.rb +33 -0
- data/lib/jdbc_adapter/jdbc_db2.rb +96 -7
- data/lib/jdbc_adapter/jdbc_derby.rb +35 -28
- data/lib/jdbc_adapter/jdbc_mssql.rb +62 -103
- data/lib/jdbc_adapter/jdbc_mysql.rb +34 -25
- data/lib/jdbc_adapter/jdbc_oracle.rb +7 -7
- data/lib/jdbc_adapter/jdbc_postgre.rb +1 -1
- data/lib/jdbc_adapter/jdbc_sqlite3.rb +188 -0
- data/lib/jdbc_adapter/jdbc_sybase.rb +39 -0
- data/lib/jdbc_adapter/tsql_helper.rb +59 -0
- data/lib/jdbc_adapter/version.rb +1 -1
- data/src/java/jdbc_adapter/JdbcAdapterInternalService.java +66 -40
- data/src/java/jdbc_adapter/JdbcMySQLSpec.java +2 -2
- data/test/cachedb_simple_test.rb +6 -0
- data/test/db/cachedb.rb +9 -0
- data/test/db/mssql.rb +9 -0
- data/test/db/oracle.rb +22 -2
- data/test/db/sqlite3.rb +11 -0
- data/test/db2_simple_test.rb +4 -0
- data/test/jdbc_common.rb +3 -1
- data/test/manualTestDatabase.rb +1 -5
- data/test/models/entry.rb +1 -1
- data/test/mssql_simple_test.rb +6 -0
- data/test/mysql_simple_test.rb +9 -0
- data/test/oracle_simple_test.rb +23 -0
- data/test/simple.rb +3 -2
- data/test/sqlite3_simple_test.rb +6 -0
- metadata +14 -2
@@ -26,16 +26,16 @@ module ::JdbcSpec
|
|
26
26
|
def self.adapter_selector
|
27
27
|
[/mysql/i, lambda {|cfg,adapt| adapt.extend(::JdbcSpec::MySQL)}]
|
28
28
|
end
|
29
|
-
|
29
|
+
|
30
30
|
def self.extended(adapter)
|
31
31
|
adapter.execute("SET SQL_AUTO_IS_NULL=0")
|
32
32
|
end
|
33
|
-
|
33
|
+
|
34
34
|
module Column
|
35
35
|
TYPES_ALLOWING_EMPTY_STRING_DEFAULT = Set.new([:binary, :string, :text])
|
36
36
|
|
37
37
|
def simplified_type(field_type)
|
38
|
-
return :boolean if field_type =~ /tinyint\(1\)|bit/i
|
38
|
+
return :boolean if field_type =~ /tinyint\(1\)|bit/i
|
39
39
|
return :string if field_type =~ /enum/i
|
40
40
|
super
|
41
41
|
end
|
@@ -44,7 +44,7 @@ module ::JdbcSpec
|
|
44
44
|
@original_default = default
|
45
45
|
@default = nil if missing_default_forged_as_empty_string?
|
46
46
|
end
|
47
|
-
|
47
|
+
|
48
48
|
# MySQL misreports NOT NULL column default when none is given.
|
49
49
|
# We can't detect this for columns which may have a legitimate ''
|
50
50
|
# default (string, text, binary) but we can for others (integer,
|
@@ -56,7 +56,7 @@ module ::JdbcSpec
|
|
56
56
|
!null && @original_default == '' && !TYPES_ALLOWING_EMPTY_STRING_DEFAULT.include?(type)
|
57
57
|
end
|
58
58
|
end
|
59
|
-
|
59
|
+
|
60
60
|
def modify_types(tp)
|
61
61
|
tp[:primary_key] = "int(11) DEFAULT NULL auto_increment PRIMARY KEY"
|
62
62
|
tp[:decimal] = { :name => "decimal" }
|
@@ -64,12 +64,12 @@ module ::JdbcSpec
|
|
64
64
|
tp[:datetime][:limit] = nil
|
65
65
|
tp
|
66
66
|
end
|
67
|
-
|
67
|
+
|
68
68
|
# QUOTING ==================================================
|
69
|
-
|
69
|
+
|
70
70
|
def quote(value, column = nil)
|
71
71
|
return value.quoted_id if value.respond_to?(:quoted_id)
|
72
|
-
|
72
|
+
|
73
73
|
if column && column.type == :primary_key
|
74
74
|
value.to_s
|
75
75
|
elsif column && String === value && column.type == :binary && column.class.respond_to?(:string_to_binary)
|
@@ -81,7 +81,7 @@ module ::JdbcSpec
|
|
81
81
|
super
|
82
82
|
end
|
83
83
|
end
|
84
|
-
|
84
|
+
|
85
85
|
def quote_column_name(name) #:nodoc:
|
86
86
|
"`#{name}`"
|
87
87
|
end
|
@@ -89,15 +89,15 @@ module ::JdbcSpec
|
|
89
89
|
def quote_table_name(name) #:nodoc:
|
90
90
|
quote_column_name(name).gsub('.', '`.`')
|
91
91
|
end
|
92
|
-
|
92
|
+
|
93
93
|
def quoted_true
|
94
94
|
"1"
|
95
95
|
end
|
96
|
-
|
96
|
+
|
97
97
|
def quoted_false
|
98
98
|
"0"
|
99
99
|
end
|
100
|
-
|
100
|
+
|
101
101
|
def begin_db_transaction #:nodoc:
|
102
102
|
@connection.begin
|
103
103
|
rescue Exception
|
@@ -116,16 +116,25 @@ module ::JdbcSpec
|
|
116
116
|
# Transactions aren't supported
|
117
117
|
end
|
118
118
|
|
119
|
+
def disable_referential_integrity(&block) #:nodoc:
|
120
|
+
old = select_value("SELECT @@FOREIGN_KEY_CHECKS")
|
121
|
+
begin
|
122
|
+
update("SET FOREIGN_KEY_CHECKS = 0")
|
123
|
+
yield
|
124
|
+
ensure
|
125
|
+
update("SET FOREIGN_KEY_CHECKS = #{old}")
|
126
|
+
end
|
127
|
+
end
|
119
128
|
|
120
129
|
# SCHEMA STATEMENTS ========================================
|
121
|
-
|
130
|
+
|
122
131
|
def structure_dump #:nodoc:
|
123
132
|
if supports_views?
|
124
133
|
sql = "SHOW FULL TABLES WHERE Table_type = 'BASE TABLE'"
|
125
134
|
else
|
126
135
|
sql = "SHOW TABLES"
|
127
136
|
end
|
128
|
-
|
137
|
+
|
129
138
|
select_all(sql).inject("") do |structure, table|
|
130
139
|
table.delete('Table_type')
|
131
140
|
|
@@ -135,15 +144,15 @@ module ::JdbcSpec
|
|
135
144
|
structure += table + ";\n\n"
|
136
145
|
elsif(view = hash["Create View"])
|
137
146
|
structure += view + ";\n\n"
|
138
|
-
end
|
147
|
+
end
|
139
148
|
end
|
140
149
|
end
|
141
|
-
|
150
|
+
|
142
151
|
def recreate_database(name) #:nodoc:
|
143
152
|
drop_database(name)
|
144
153
|
create_database(name)
|
145
154
|
end
|
146
|
-
|
155
|
+
|
147
156
|
def create_database(name, options = {}) #:nodoc:
|
148
157
|
if options[:collation]
|
149
158
|
execute "CREATE DATABASE `#{name}` DEFAULT CHARACTER SET `#{options[:charset] || 'utf8'}` COLLATE `#{options[:collation]}`"
|
@@ -151,29 +160,29 @@ module ::JdbcSpec
|
|
151
160
|
execute "CREATE DATABASE `#{name}` DEFAULT CHARACTER SET `#{options[:charset] || 'utf8'}`"
|
152
161
|
end
|
153
162
|
end
|
154
|
-
|
163
|
+
|
155
164
|
def drop_database(name) #:nodoc:
|
156
165
|
execute "DROP DATABASE IF EXISTS `#{name}`"
|
157
166
|
end
|
158
|
-
|
167
|
+
|
159
168
|
def current_database
|
160
169
|
select_one("SELECT DATABASE() as db")["db"]
|
161
170
|
end
|
162
|
-
|
171
|
+
|
163
172
|
def create_table(name, options = {}) #:nodoc:
|
164
173
|
super(name, {:options => "ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin"}.merge(options))
|
165
174
|
end
|
166
|
-
|
175
|
+
|
167
176
|
def rename_table(name, new_name)
|
168
177
|
execute "RENAME TABLE #{quote_table_name(name)} TO #{quote_table_name(new_name)}"
|
169
|
-
end
|
170
|
-
|
178
|
+
end
|
179
|
+
|
171
180
|
def change_column_default(table_name, column_name, default) #:nodoc:
|
172
181
|
current_type = select_one("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE '#{column_name}'")["Type"]
|
173
182
|
|
174
183
|
execute("ALTER TABLE #{quote_table_name(table_name)} CHANGE #{quote_column_name(column_name)} #{quote_column_name(column_name)} #{current_type} DEFAULT #{quote(default)}")
|
175
184
|
end
|
176
|
-
|
185
|
+
|
177
186
|
def change_column(table_name, column_name, type, options = {}) #:nodoc:
|
178
187
|
unless options_include_default?(options)
|
179
188
|
if column = columns(table_name).find { |c| c.name == column_name.to_s }
|
@@ -193,7 +202,7 @@ module ::JdbcSpec
|
|
193
202
|
current_type = cols["Type"] || cols["COLUMN_TYPE"]
|
194
203
|
execute "ALTER TABLE #{quote_table_name(table_name)} CHANGE #{quote_table_name(column_name)} #{quote_column_name(new_column_name)} #{current_type}"
|
195
204
|
end
|
196
|
-
|
205
|
+
|
197
206
|
def add_limit_offset!(sql, options) #:nodoc:
|
198
207
|
if limit = options[:limit]
|
199
208
|
unless offset = options[:offset]
|
@@ -65,12 +65,7 @@ module ::JdbcSpec
|
|
65
65
|
else value
|
66
66
|
end
|
67
67
|
end
|
68
|
-
|
69
|
-
def type_cast_code(var_name)
|
70
|
-
return "JdbcSpec::Oracle::Column.cast_to_date_or_time(#{var_name})" if type == :datetime
|
71
|
-
super
|
72
|
-
end
|
73
|
-
|
68
|
+
|
74
69
|
private
|
75
70
|
def simplified_type(field_type)
|
76
71
|
case field_type
|
@@ -317,7 +312,12 @@ module ::JdbcSpec
|
|
317
312
|
return value.to_s
|
318
313
|
end
|
319
314
|
case value
|
320
|
-
when String, ActiveSupport::Multibyte::Chars
|
315
|
+
when String, ActiveSupport::Multibyte::Chars
|
316
|
+
if column.type == :datetime
|
317
|
+
%Q{TIMESTAMP'#{value}'}
|
318
|
+
else
|
319
|
+
%Q{'#{quote_string(value)}'}
|
320
|
+
end
|
321
321
|
when NilClass : 'null'
|
322
322
|
when TrueClass : '1'
|
323
323
|
when FalseClass : '0'
|
@@ -165,7 +165,7 @@ module ::JdbcSpec
|
|
165
165
|
def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) #:nodoc:
|
166
166
|
execute(sql, name)
|
167
167
|
table = sql.split(" ", 4)[2]
|
168
|
-
id_value || last_insert_id(table, sequence_name || default_sequence_name(table, pk))
|
168
|
+
id_value || pk && last_insert_id(table, sequence_name || default_sequence_name(table, pk))
|
169
169
|
end
|
170
170
|
|
171
171
|
def columns(table_name, name=nil)
|
@@ -0,0 +1,188 @@
|
|
1
|
+
module ::JdbcSpec
|
2
|
+
module ActiveRecordExtensions
|
3
|
+
def sqlite3_connection(config)
|
4
|
+
config[:url] ||= "jdbc:sqlite:#{config[:database]}"
|
5
|
+
config[:driver] ||= "org.sqlite.JDBC"
|
6
|
+
jdbc_connection(config)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
module SQLite3
|
11
|
+
def self.column_selector
|
12
|
+
[/sqlite/i, lambda {|cfg,col| col.extend(::JdbcSpec::SQLite3::Column)}]
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.adapter_selector
|
16
|
+
[/sqlite/i, lambda {|cfg,adapt| adapt.extend(::JdbcSpec::SQLite3)}]
|
17
|
+
end
|
18
|
+
|
19
|
+
module Column
|
20
|
+
|
21
|
+
private
|
22
|
+
def simplified_type(field_type)
|
23
|
+
case field_type
|
24
|
+
when /^integer\(1\)$/i then :boolean
|
25
|
+
when /text/i then :string
|
26
|
+
when /int/i then :integer
|
27
|
+
when /real/i then @scale == 0 ? :integer : :decimal
|
28
|
+
when /date|time/i then :datetime
|
29
|
+
when /blob/i then :binary
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.cast_to_date_or_time(value)
|
34
|
+
return value if value.is_a? Date
|
35
|
+
return nil if value.blank?
|
36
|
+
guess_date_or_time((value.is_a? Time) ? value : cast_to_time(value))
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.cast_to_time(value)
|
40
|
+
return value if value.is_a? Time
|
41
|
+
Time.at(value) rescue nil
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.guess_date_or_time(value)
|
45
|
+
(value.hour == 0 and value.min == 0 and value.sec == 0) ?
|
46
|
+
Date.new(value.year, value.month, value.day) : value
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def type_cast(value)
|
51
|
+
return nil if value.nil?
|
52
|
+
case type
|
53
|
+
when :string then value
|
54
|
+
when :integer then defined?(value.to_i) ? value.to_i : (value ? 1 : 0)
|
55
|
+
when :primary_key then defined?(value.to_i) ? value.to_i : (value ? 1 : 0)
|
56
|
+
when :float then value.to_f
|
57
|
+
when :datetime then JdbcSpec::SQLite3::Column.cast_to_date_or_time(value)
|
58
|
+
when :time then JdbcSpec::SQLite3::Column.cast_to_time(value)
|
59
|
+
when :decimal then self.class.value_to_decimal(value)
|
60
|
+
when :boolean then self.class.value_to_boolean(value)
|
61
|
+
else value
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def modify_types(tp)
|
66
|
+
tp[:primary_key] = "INTEGER PRIMARY KEY AUTOINCREMENT"
|
67
|
+
tp[:float] = { :name => "REAL" }
|
68
|
+
tp[:decimal] = { :name => "REAL" }
|
69
|
+
tp[:datetime] = { :name => "INTEGER" }
|
70
|
+
tp[:timestamp] = { :name => "INTEGER" }
|
71
|
+
tp[:time] = { :name => "INTEGER" }
|
72
|
+
tp[:date] = { :name => "INTEGER" }
|
73
|
+
tp[:boolean] = { :name => "INTEGER", :limit => 1}
|
74
|
+
tp
|
75
|
+
end
|
76
|
+
|
77
|
+
def quote(value, column = nil) # :nodoc:
|
78
|
+
return value.quoted_id if value.respond_to?(:quoted_id)
|
79
|
+
|
80
|
+
case value
|
81
|
+
when String
|
82
|
+
if column && column.type == :binary
|
83
|
+
"'#{quote_string(value).unpack("C*").collect {|v| v.to_s(16)}.join}'"
|
84
|
+
else
|
85
|
+
"'#{quote_string(value)}'"
|
86
|
+
end
|
87
|
+
else super
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def quote_string(str)
|
92
|
+
str.gsub(/'/, "''")
|
93
|
+
end
|
94
|
+
|
95
|
+
def quoted_true
|
96
|
+
'1'
|
97
|
+
end
|
98
|
+
|
99
|
+
def quoted_false
|
100
|
+
'0'
|
101
|
+
end
|
102
|
+
|
103
|
+
def add_column(table_name, column_name, type, options = {})
|
104
|
+
if option_not_null = options[:null] == false
|
105
|
+
option_not_null = options.delete(:null)
|
106
|
+
end
|
107
|
+
add_column_sql = "ALTER TABLE #{quote_table_name(table_name)} ADD #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
|
108
|
+
add_column_options!(add_column_sql, options)
|
109
|
+
execute(add_column_sql)
|
110
|
+
if option_not_null
|
111
|
+
alter_column_sql = "ALTER TABLE #{quote_table_name(table_name)} ALTER #{quote_column_name(column_name)} NOT NULL"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def remove_column(table_name, column_name) #:nodoc:
|
116
|
+
cols = columns(table_name).collect {|col| col.name}
|
117
|
+
cols.delete(column_name)
|
118
|
+
cols = cols.join(', ')
|
119
|
+
table_backup = table_name + "_backup"
|
120
|
+
|
121
|
+
@connection.begin
|
122
|
+
|
123
|
+
execute "CREATE TEMPORARY TABLE #{table_backup}(#{cols})"
|
124
|
+
insert "INSERT INTO #{table_backup} SELECT #{cols} FROM #{table_name}"
|
125
|
+
execute "DROP TABLE #{table_name}"
|
126
|
+
execute "CREATE TABLE #{table_name}(#{cols})"
|
127
|
+
insert "INSERT INTO #{table_name} SELECT #{cols} FROM #{table_backup}"
|
128
|
+
execute "DROP TABLE #{table_backup}"
|
129
|
+
|
130
|
+
@connection.commit
|
131
|
+
end
|
132
|
+
|
133
|
+
def change_column(table_name, column_name, type, options = {}) #:nodoc:
|
134
|
+
execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} #{type_to_sql(type, options[:limit])}"
|
135
|
+
end
|
136
|
+
|
137
|
+
def change_column_default(table_name, column_name, default) #:nodoc:
|
138
|
+
execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} SET DEFAULT #{quote(default)}"
|
139
|
+
end
|
140
|
+
|
141
|
+
def rename_column(table_name, column_name, new_column_name) #:nodoc:
|
142
|
+
execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} RENAME TO #{new_column_name}"
|
143
|
+
end
|
144
|
+
|
145
|
+
def rename_table(name, new_name)
|
146
|
+
execute "ALTER TABLE #{name} RENAME TO #{new_name}"
|
147
|
+
end
|
148
|
+
|
149
|
+
def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) #:nodoc:
|
150
|
+
log(sql,name) do
|
151
|
+
@connection.execute_update(sql)
|
152
|
+
end
|
153
|
+
table = sql.split(" ", 4)[2]
|
154
|
+
id_value || last_insert_id(table, nil)
|
155
|
+
end
|
156
|
+
|
157
|
+
def last_insert_id(table, sequence_name)
|
158
|
+
Integer(select_value("SELECT SEQ FROM SQLITE_SEQUENCE WHERE NAME = '#{table}'"))
|
159
|
+
end
|
160
|
+
|
161
|
+
def add_limit_offset!(sql, options) #:nodoc:
|
162
|
+
if options[:limit]
|
163
|
+
sql << " LIMIT #{options[:limit]}"
|
164
|
+
sql << " OFFSET #{options[:offset]}" if options[:offset]
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def tables
|
169
|
+
@connection.tables.select {|row| row.to_s !~ /^sqlite_/i }
|
170
|
+
end
|
171
|
+
|
172
|
+
def remove_index(table_name, options = {})
|
173
|
+
execute "DROP INDEX #{quote_column_name(index_name(table_name, options))}"
|
174
|
+
end
|
175
|
+
|
176
|
+
def indexes(table_name, name = nil)
|
177
|
+
result = select_rows("SELECT name, sql FROM sqlite_master WHERE tbl_name = '#{table_name}' AND type = 'index'", name)
|
178
|
+
|
179
|
+
result.collect do |row|
|
180
|
+
name = row[0]
|
181
|
+
index_sql = row[1]
|
182
|
+
unique = (index_sql =~ /unique/i)
|
183
|
+
cols = index_sql.match(/\((.*)\)/)[1].gsub(/,/,' ').split
|
184
|
+
::ActiveRecord::ConnectionAdapters::IndexDefinition.new(table_name, name, unique, cols)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module JdbcSpec
|
2
|
+
module Sybase
|
3
|
+
def self.adapter_selector
|
4
|
+
[/sybase/i, lambda{|cfg,adapt| adapt.extend(JdbcSpec::Sybase)}]
|
5
|
+
end
|
6
|
+
|
7
|
+
def add_limit_offset!(sql, options) # :nodoc:
|
8
|
+
@limit = options[:limit]
|
9
|
+
@offset = options[:offset]
|
10
|
+
if use_temp_table?
|
11
|
+
# Use temp table to hack offset with Sybase
|
12
|
+
sql.sub!(/ FROM /i, ' INTO #artemp FROM ')
|
13
|
+
elsif zero_limit?
|
14
|
+
# "SET ROWCOUNT 0" turns off limits, so we havesy
|
15
|
+
# to use a cheap trick.
|
16
|
+
if sql =~ /WHERE/i
|
17
|
+
sql.sub!(/WHERE/i, 'WHERE 1 = 2 AND ')
|
18
|
+
elsif sql =~ /ORDER\s+BY/i
|
19
|
+
sql.sub!(/ORDER\s+BY/i, 'WHERE 1 = 2 ORDER BY')
|
20
|
+
else
|
21
|
+
sql << 'WHERE 1 = 2'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# If limit is not set at all, we can ignore offset;
|
27
|
+
# if limit *is* set but offset is zero, use normal select
|
28
|
+
# with simple SET ROWCOUNT. Thus, only use the temp table
|
29
|
+
# if limit is set and offset > 0.
|
30
|
+
def use_temp_table?
|
31
|
+
!@limit.nil? && !@offset.nil? && @offset > 0
|
32
|
+
end
|
33
|
+
|
34
|
+
def zero_limit?
|
35
|
+
!@limit.nil? && @limit == 0
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# Common methods for handling TSQL databases.
|
2
|
+
module TSqlMethods
|
3
|
+
|
4
|
+
def modify_types(tp) #:nodoc:
|
5
|
+
tp[:primary_key] = "int NOT NULL IDENTITY(1, 1) PRIMARY KEY"
|
6
|
+
tp[:integer][:limit] = nil
|
7
|
+
tp[:boolean] = {:name => "bit"}
|
8
|
+
tp[:binary] = { :name => "image"}
|
9
|
+
tp
|
10
|
+
end
|
11
|
+
|
12
|
+
def type_to_sql(type, limit = nil, precision = nil, scale = nil) #:nodoc:
|
13
|
+
return super unless type.to_s == 'integer'
|
14
|
+
|
15
|
+
if limit.nil? || limit == 4
|
16
|
+
'int'
|
17
|
+
elsif limit == 2
|
18
|
+
'smallint'
|
19
|
+
elsif limit == 1
|
20
|
+
'tinyint'
|
21
|
+
else
|
22
|
+
'bigint'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def add_limit_offset!(sql, options)
|
27
|
+
if options[:limit] and options[:offset]
|
28
|
+
total_rows = select_all("SELECT count(*) as TotalRows from (#{sql.gsub(/\bSELECT(\s+DISTINCT)?\b/i, "SELECT\\1 TOP 1000000000")}) tally")[0]["TotalRows"].to_i
|
29
|
+
if (options[:limit] + options[:offset]) >= total_rows
|
30
|
+
options[:limit] = (total_rows - options[:offset] >= 0) ? (total_rows - options[:offset]) : 0
|
31
|
+
end
|
32
|
+
sql.sub!(/^\s*SELECT(\s+DISTINCT)?/i, "SELECT * FROM (SELECT TOP #{options[:limit]} * FROM (SELECT\\1 TOP #{options[:limit] + options[:offset]} ")
|
33
|
+
sql << ") AS tmp1"
|
34
|
+
if options[:order]
|
35
|
+
options[:order] = options[:order].split(',').map do |field|
|
36
|
+
parts = field.split(" ")
|
37
|
+
tc = parts[0]
|
38
|
+
if sql =~ /\.\[/ and tc =~ /\./ # if column quoting used in query
|
39
|
+
tc.gsub!(/\./, '\\.\\[')
|
40
|
+
tc << '\\]'
|
41
|
+
end
|
42
|
+
if sql =~ /#{tc} AS (t\d_r\d\d?)/
|
43
|
+
parts[0] = $1
|
44
|
+
elsif parts[0] =~ /\w+\.(\w+)/
|
45
|
+
parts[0] = $1
|
46
|
+
end
|
47
|
+
parts.join(' ')
|
48
|
+
end.join(', ')
|
49
|
+
sql << " ORDER BY #{change_order_direction(options[:order])}) AS tmp2 ORDER BY #{options[:order]}"
|
50
|
+
else
|
51
|
+
sql << " ) AS tmp2"
|
52
|
+
end
|
53
|
+
elsif sql !~ /^\s*SELECT (@@|COUNT\()/i
|
54
|
+
sql.sub!(/^\s*SELECT(\s+DISTINCT)?/i) do
|
55
|
+
"SELECT#{$1} TOP #{options[:limit]}"
|
56
|
+
end unless options[:limit].nil?
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|