activerecord-jdbc-adapter 0.8 → 0.8.1
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/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
|