tgbyte-activerecord-jdbc-adapter 1.2.2.2

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.
Files changed (218) hide show
  1. data/.gitignore +22 -0
  2. data/.travis.yml +8 -0
  3. data/Gemfile +14 -0
  4. data/Gemfile.lock +40 -0
  5. data/History.txt +488 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.rdoc +199 -0
  8. data/Rakefile +60 -0
  9. data/activerecord-jdbc-adapter.gemspec +23 -0
  10. data/bench/bench_attributes.rb +13 -0
  11. data/bench/bench_attributes_new.rb +14 -0
  12. data/bench/bench_create.rb +12 -0
  13. data/bench/bench_find_all.rb +12 -0
  14. data/bench/bench_find_all_mt.rb +25 -0
  15. data/bench/bench_model.rb +85 -0
  16. data/bench/bench_new.rb +12 -0
  17. data/bench/bench_new_valid.rb +12 -0
  18. data/bench/bench_valid.rb +13 -0
  19. data/lib/active_record/connection_adapters/derby_adapter.rb +1 -0
  20. data/lib/active_record/connection_adapters/h2_adapter.rb +1 -0
  21. data/lib/active_record/connection_adapters/hsqldb_adapter.rb +1 -0
  22. data/lib/active_record/connection_adapters/informix_adapter.rb +1 -0
  23. data/lib/active_record/connection_adapters/jdbc_adapter.rb +1 -0
  24. data/lib/active_record/connection_adapters/jndi_adapter.rb +1 -0
  25. data/lib/active_record/connection_adapters/mssql_adapter.rb +1 -0
  26. data/lib/active_record/connection_adapters/mysql2_adapter.rb +1 -0
  27. data/lib/active_record/connection_adapters/mysql_adapter.rb +1 -0
  28. data/lib/active_record/connection_adapters/oracle_adapter.rb +1 -0
  29. data/lib/active_record/connection_adapters/postgresql_adapter.rb +1 -0
  30. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +1 -0
  31. data/lib/activerecord-jdbc-adapter.rb +8 -0
  32. data/lib/arel/engines/sql/compilers/db2_compiler.rb +9 -0
  33. data/lib/arel/engines/sql/compilers/derby_compiler.rb +6 -0
  34. data/lib/arel/engines/sql/compilers/h2_compiler.rb +6 -0
  35. data/lib/arel/engines/sql/compilers/hsqldb_compiler.rb +15 -0
  36. data/lib/arel/engines/sql/compilers/jdbc_compiler.rb +6 -0
  37. data/lib/arel/engines/sql/compilers/mssql_compiler.rb +46 -0
  38. data/lib/arel/visitors/compat.rb +13 -0
  39. data/lib/arel/visitors/db2.rb +17 -0
  40. data/lib/arel/visitors/derby.rb +32 -0
  41. data/lib/arel/visitors/firebird.rb +24 -0
  42. data/lib/arel/visitors/hsqldb.rb +26 -0
  43. data/lib/arel/visitors/sql_server.rb +46 -0
  44. data/lib/arjdbc.rb +24 -0
  45. data/lib/arjdbc/db2.rb +2 -0
  46. data/lib/arjdbc/db2/adapter.rb +510 -0
  47. data/lib/arjdbc/derby.rb +7 -0
  48. data/lib/arjdbc/derby/adapter.rb +358 -0
  49. data/lib/arjdbc/derby/connection_methods.rb +19 -0
  50. data/lib/arjdbc/discover.rb +92 -0
  51. data/lib/arjdbc/firebird.rb +2 -0
  52. data/lib/arjdbc/firebird/adapter.rb +136 -0
  53. data/lib/arjdbc/h2.rb +4 -0
  54. data/lib/arjdbc/h2/adapter.rb +54 -0
  55. data/lib/arjdbc/h2/connection_methods.rb +13 -0
  56. data/lib/arjdbc/hsqldb.rb +4 -0
  57. data/lib/arjdbc/hsqldb/adapter.rb +184 -0
  58. data/lib/arjdbc/hsqldb/connection_methods.rb +15 -0
  59. data/lib/arjdbc/informix.rb +3 -0
  60. data/lib/arjdbc/informix/adapter.rb +138 -0
  61. data/lib/arjdbc/informix/connection_methods.rb +11 -0
  62. data/lib/arjdbc/jdbc.rb +2 -0
  63. data/lib/arjdbc/jdbc/adapter.rb +356 -0
  64. data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
  65. data/lib/arjdbc/jdbc/base_ext.rb +15 -0
  66. data/lib/arjdbc/jdbc/callbacks.rb +44 -0
  67. data/lib/arjdbc/jdbc/column.rb +47 -0
  68. data/lib/arjdbc/jdbc/compatibility.rb +51 -0
  69. data/lib/arjdbc/jdbc/connection.rb +134 -0
  70. data/lib/arjdbc/jdbc/connection_methods.rb +16 -0
  71. data/lib/arjdbc/jdbc/core_ext.rb +24 -0
  72. data/lib/arjdbc/jdbc/discover.rb +18 -0
  73. data/lib/arjdbc/jdbc/driver.rb +35 -0
  74. data/lib/arjdbc/jdbc/extension.rb +47 -0
  75. data/lib/arjdbc/jdbc/java.rb +14 -0
  76. data/lib/arjdbc/jdbc/jdbc.rake +131 -0
  77. data/lib/arjdbc/jdbc/missing_functionality_helper.rb +88 -0
  78. data/lib/arjdbc/jdbc/quoted_primary_key.rb +28 -0
  79. data/lib/arjdbc/jdbc/railtie.rb +9 -0
  80. data/lib/arjdbc/jdbc/rake_tasks.rb +10 -0
  81. data/lib/arjdbc/jdbc/require_driver.rb +16 -0
  82. data/lib/arjdbc/jdbc/type_converter.rb +126 -0
  83. data/lib/arjdbc/mimer.rb +2 -0
  84. data/lib/arjdbc/mimer/adapter.rb +142 -0
  85. data/lib/arjdbc/mssql.rb +4 -0
  86. data/lib/arjdbc/mssql/adapter.rb +477 -0
  87. data/lib/arjdbc/mssql/connection_methods.rb +31 -0
  88. data/lib/arjdbc/mssql/limit_helpers.rb +101 -0
  89. data/lib/arjdbc/mssql/lock_helpers.rb +72 -0
  90. data/lib/arjdbc/mssql/tsql_helper.rb +61 -0
  91. data/lib/arjdbc/mysql.rb +4 -0
  92. data/lib/arjdbc/mysql/adapter.rb +505 -0
  93. data/lib/arjdbc/mysql/connection_methods.rb +28 -0
  94. data/lib/arjdbc/oracle.rb +3 -0
  95. data/lib/arjdbc/oracle/adapter.rb +428 -0
  96. data/lib/arjdbc/oracle/connection_methods.rb +12 -0
  97. data/lib/arjdbc/postgresql.rb +4 -0
  98. data/lib/arjdbc/postgresql/adapter.rb +825 -0
  99. data/lib/arjdbc/postgresql/connection_methods.rb +23 -0
  100. data/lib/arjdbc/sqlite3.rb +4 -0
  101. data/lib/arjdbc/sqlite3/adapter.rb +389 -0
  102. data/lib/arjdbc/sqlite3/connection_methods.rb +35 -0
  103. data/lib/arjdbc/sybase.rb +2 -0
  104. data/lib/arjdbc/sybase/adapter.rb +46 -0
  105. data/lib/arjdbc/version.rb +8 -0
  106. data/lib/generators/jdbc/USAGE +10 -0
  107. data/lib/generators/jdbc/jdbc_generator.rb +9 -0
  108. data/lib/jdbc_adapter.rb +2 -0
  109. data/lib/jdbc_adapter/rake_tasks.rb +3 -0
  110. data/lib/jdbc_adapter/version.rb +3 -0
  111. data/lib/pg.rb +26 -0
  112. data/pom.xml +57 -0
  113. data/rails_generators/jdbc_generator.rb +15 -0
  114. data/rails_generators/templates/config/initializers/jdbc.rb +7 -0
  115. data/rails_generators/templates/lib/tasks/jdbc.rake +8 -0
  116. data/rakelib/bundler_ext.rb +11 -0
  117. data/rakelib/compile.rake +23 -0
  118. data/rakelib/db.rake +39 -0
  119. data/rakelib/rails.rake +41 -0
  120. data/src/java/arjdbc/db2/DB2RubyJdbcConnection.java +62 -0
  121. data/src/java/arjdbc/derby/DerbyModule.java +324 -0
  122. data/src/java/arjdbc/h2/H2RubyJdbcConnection.java +70 -0
  123. data/src/java/arjdbc/informix/InformixRubyJdbcConnection.java +74 -0
  124. data/src/java/arjdbc/jdbc/AdapterJavaService.java +68 -0
  125. data/src/java/arjdbc/jdbc/JdbcConnectionFactory.java +36 -0
  126. data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +1326 -0
  127. data/src/java/arjdbc/jdbc/SQLBlock.java +48 -0
  128. data/src/java/arjdbc/mssql/MssqlRubyJdbcConnection.java +127 -0
  129. data/src/java/arjdbc/mysql/MySQLModule.java +134 -0
  130. data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +161 -0
  131. data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +85 -0
  132. data/src/java/arjdbc/postgresql/PostgresqlRubyJdbcConnection.java +82 -0
  133. data/src/java/arjdbc/sqlite3/Sqlite3RubyJdbcConnection.java +126 -0
  134. data/test/abstract_db_create.rb +135 -0
  135. data/test/activerecord/connection_adapters/type_conversion_test.rb +31 -0
  136. data/test/activerecord/connections/native_jdbc_mysql/connection.rb +25 -0
  137. data/test/activerecord/jall.sh +7 -0
  138. data/test/activerecord/jtest.sh +3 -0
  139. data/test/db/db2.rb +11 -0
  140. data/test/db/derby.rb +12 -0
  141. data/test/db/h2.rb +11 -0
  142. data/test/db/hsqldb.rb +13 -0
  143. data/test/db/informix.rb +11 -0
  144. data/test/db/jdbc.rb +12 -0
  145. data/test/db/jndi_config.rb +40 -0
  146. data/test/db/logger.rb +3 -0
  147. data/test/db/mssql.rb +9 -0
  148. data/test/db/mysql.rb +10 -0
  149. data/test/db/oracle.rb +34 -0
  150. data/test/db/postgres.rb +9 -0
  151. data/test/db/sqlite3.rb +11 -0
  152. data/test/db2_reset_column_information_test.rb +8 -0
  153. data/test/db2_simple_test.rb +66 -0
  154. data/test/derby_migration_test.rb +68 -0
  155. data/test/derby_multibyte_test.rb +12 -0
  156. data/test/derby_reset_column_information_test.rb +8 -0
  157. data/test/derby_row_locking_test.rb +9 -0
  158. data/test/derby_simple_test.rb +139 -0
  159. data/test/generic_jdbc_connection_test.rb +29 -0
  160. data/test/h2_change_column_test.rb +68 -0
  161. data/test/h2_simple_test.rb +41 -0
  162. data/test/has_many_through.rb +79 -0
  163. data/test/helper.rb +87 -0
  164. data/test/hsqldb_simple_test.rb +6 -0
  165. data/test/informix_simple_test.rb +48 -0
  166. data/test/jdbc_common.rb +28 -0
  167. data/test/jndi_callbacks_test.rb +36 -0
  168. data/test/jndi_test.rb +25 -0
  169. data/test/manualTestDatabase.rb +191 -0
  170. data/test/models/add_not_null_column_to_table.rb +9 -0
  171. data/test/models/auto_id.rb +15 -0
  172. data/test/models/data_types.rb +30 -0
  173. data/test/models/entry.rb +40 -0
  174. data/test/models/mixed_case.rb +22 -0
  175. data/test/models/reserved_word.rb +15 -0
  176. data/test/models/string_id.rb +17 -0
  177. data/test/models/thing.rb +16 -0
  178. data/test/models/validates_uniqueness_of_string.rb +19 -0
  179. data/test/mssql_db_create_test.rb +26 -0
  180. data/test/mssql_identity_insert_test.rb +19 -0
  181. data/test/mssql_ignore_system_views_test.rb +27 -0
  182. data/test/mssql_legacy_types_test.rb +58 -0
  183. data/test/mssql_limit_offset_test.rb +136 -0
  184. data/test/mssql_multibyte_test.rb +18 -0
  185. data/test/mssql_null_test.rb +14 -0
  186. data/test/mssql_reset_column_information_test.rb +8 -0
  187. data/test/mssql_row_locking_sql_test.rb +159 -0
  188. data/test/mssql_row_locking_test.rb +9 -0
  189. data/test/mssql_simple_test.rb +55 -0
  190. data/test/mysql_db_create_test.rb +27 -0
  191. data/test/mysql_index_length_test.rb +58 -0
  192. data/test/mysql_info_test.rb +123 -0
  193. data/test/mysql_multibyte_test.rb +10 -0
  194. data/test/mysql_nonstandard_primary_key_test.rb +42 -0
  195. data/test/mysql_reset_column_information_test.rb +8 -0
  196. data/test/mysql_simple_test.rb +125 -0
  197. data/test/oracle_reset_column_information_test.rb +8 -0
  198. data/test/oracle_simple_test.rb +18 -0
  199. data/test/oracle_specific_test.rb +83 -0
  200. data/test/postgres_db_create_test.rb +32 -0
  201. data/test/postgres_drop_db_test.rb +16 -0
  202. data/test/postgres_information_schema_leak_test.rb +29 -0
  203. data/test/postgres_mixed_case_test.rb +29 -0
  204. data/test/postgres_native_type_mapping_test.rb +89 -0
  205. data/test/postgres_nonseq_pkey_test.rb +38 -0
  206. data/test/postgres_reserved_test.rb +22 -0
  207. data/test/postgres_reset_column_information_test.rb +8 -0
  208. data/test/postgres_schema_search_path_test.rb +48 -0
  209. data/test/postgres_simple_test.rb +167 -0
  210. data/test/postgres_table_alias_length_test.rb +15 -0
  211. data/test/postgres_type_conversion_test.rb +34 -0
  212. data/test/row_locking.rb +90 -0
  213. data/test/simple.rb +717 -0
  214. data/test/sqlite3_reset_column_information_test.rb +8 -0
  215. data/test/sqlite3_simple_test.rb +316 -0
  216. data/test/sybase_jtds_simple_test.rb +28 -0
  217. data/test/sybase_reset_column_information_test.rb +8 -0
  218. metadata +275 -0
@@ -0,0 +1,28 @@
1
+ # Don't need to load native mysql adapter
2
+ $LOADED_FEATURES << "active_record/connection_adapters/mysql_adapter.rb"
3
+ $LOADED_FEATURES << "active_record/connection_adapters/mysql2_adapter.rb"
4
+
5
+ class ActiveRecord::Base
6
+ class << self
7
+ def mysql_connection(config)
8
+ require "arjdbc/mysql"
9
+ config[:port] ||= 3306
10
+ options = (config[:options] ||= {})
11
+ options['zeroDateTimeBehavior'] ||= 'convertToNull'
12
+ options['jdbcCompliantTruncation'] ||= 'false'
13
+ options['useUnicode'] ||= 'true'
14
+ options['characterEncoding'] = config[:encoding] || 'utf8'
15
+ config[:url] ||= "jdbc:mysql://#{config[:host]}:#{config[:port]}/#{config[:database]}"
16
+ config[:driver] ||= "com.mysql.jdbc.Driver"
17
+ config[:adapter_class] = ActiveRecord::ConnectionAdapters::MysqlAdapter
18
+ config[:adapter_spec] = ::ArJdbc::MySQL
19
+ connection = jdbc_connection(config)
20
+ ::ArJdbc::MySQL.kill_cancel_timer(connection.raw_connection)
21
+ connection
22
+ end
23
+ alias_method :jdbcmysql_connection, :mysql_connection
24
+ alias_method :mysql2_connection, :mysql_connection
25
+ end
26
+ end
27
+
28
+
@@ -0,0 +1,3 @@
1
+ require 'arjdbc/jdbc'
2
+ require 'arjdbc/oracle/connection_methods'
3
+ require 'arjdbc/oracle/adapter'
@@ -0,0 +1,428 @@
1
+ module ActiveRecord::ConnectionAdapters
2
+ OracleAdapter = Class.new(AbstractAdapter) unless const_defined?(:OracleAdapter)
3
+ end
4
+
5
+ module ::ArJdbc
6
+ module Oracle
7
+ def self.extended(mod)
8
+ unless defined?(@lob_callback_added)
9
+ ActiveRecord::Base.class_eval do
10
+ def after_save_with_oracle_lob
11
+ self.class.columns.select { |c| c.sql_type =~ /LOB\(|LOB$/i }.each do |c|
12
+ value = self[c.name]
13
+ value = value.to_yaml if unserializable_attribute?(c.name, c)
14
+ next if value.nil? || (value == '')
15
+
16
+ connection.write_large_object(c.type == :binary, c.name, self.class.table_name, self.class.primary_key, quote_value(id), value)
17
+ end
18
+ end
19
+ end
20
+
21
+ ActiveRecord::Base.after_save :after_save_with_oracle_lob
22
+ @lob_callback_added = true
23
+ end
24
+
25
+ unless ActiveRecord::ConnectionAdapters::AbstractAdapter.instance_methods(false).detect {|m| m.to_s == "prefetch_primary_key?"}
26
+ require 'arjdbc/jdbc/quoted_primary_key'
27
+ ActiveRecord::Base.extend ArJdbc::QuotedPrimaryKeyExtension
28
+ end
29
+
30
+ (class << mod; self; end).class_eval do
31
+ alias_chained_method :insert, :query_dirty, :ora_insert
32
+ alias_chained_method :columns, :query_cache, :ora_columns
33
+ end
34
+ end
35
+
36
+ def self.column_selector
37
+ [/oracle/i, lambda {|cfg,col| col.extend(::ArJdbc::Oracle::Column)}]
38
+ end
39
+
40
+ def self.jdbc_connection_class
41
+ ::ActiveRecord::ConnectionAdapters::OracleJdbcConnection
42
+ end
43
+
44
+ module Column
45
+ def primary=(val)
46
+ super
47
+ if val && @sql_type =~ /^NUMBER$/i
48
+ @type = :integer
49
+ end
50
+ end
51
+
52
+ def type_cast(value)
53
+ return nil if value.nil?
54
+ case type
55
+ when :datetime then ArJdbc::Oracle::Column.string_to_time(value, self.class)
56
+ else
57
+ super
58
+ end
59
+ end
60
+
61
+ def extract_limit(sql_type)
62
+ case sql_type
63
+ when /^(clob|date)/i; nil
64
+ else super
65
+ end
66
+ end
67
+
68
+ def type_cast_code(var_name)
69
+ case type
70
+ when :datetime then "ArJdbc::Oracle::Column.string_to_time(#{var_name}, self.class)"
71
+ else
72
+ super
73
+ end
74
+ end
75
+
76
+ def self.string_to_time(string, klass)
77
+ time = klass.string_to_time(string)
78
+ guess_date_or_time(time)
79
+ end
80
+
81
+ def self.guess_date_or_time(value)
82
+ return value if Date === value
83
+ (value && value.hour == 0 && value.min == 0 && value.sec == 0) ?
84
+ Date.new(value.year, value.month, value.day) : value
85
+ end
86
+
87
+ private
88
+ def simplified_type(field_type)
89
+ case field_type
90
+ when /^number\(1\)$/i then :boolean
91
+ when /char/i then :string
92
+ when /float|double/i then :float
93
+ when /int/i then :integer
94
+ when /num|dec|real/i then extract_scale(field_type) == 0 ? :integer : :decimal
95
+ when /date|time/i then :datetime
96
+ when /clob/i then :text
97
+ when /blob/i then :binary
98
+ end
99
+ end
100
+
101
+ # Post process default value from JDBC into a Rails-friendly format (columns{-internal})
102
+ def default_value(value)
103
+ return nil unless value
104
+
105
+ # Not sure why we need this for Oracle?
106
+ value = value.strip
107
+
108
+ return nil if value == "null"
109
+
110
+ # sysdate default should be treated like a null value
111
+ return nil if value.downcase == "sysdate"
112
+
113
+ # jdbc returns column default strings with actual single quotes around the value.
114
+ return $1 if value =~ /^'(.*)'$/
115
+
116
+ value
117
+ end
118
+ end
119
+
120
+ def adapter_name
121
+ 'Oracle'
122
+ end
123
+
124
+ def self.arel2_visitors(config)
125
+ { 'oracle' => Arel::Visitors::Oracle }
126
+ end
127
+
128
+ def prefetch_primary_key?(table_name = nil)
129
+ columns(table_name).detect {|c| c.primary } if table_name
130
+ end
131
+
132
+ def table_alias_length
133
+ 30
134
+ end
135
+
136
+ def default_sequence_name(table, column = nil) #:nodoc:
137
+ "#{table}_seq"
138
+ end
139
+
140
+ def create_table(name, options = {}) #:nodoc:
141
+ super(name, options)
142
+ seq_name = options[:sequence_name] || default_sequence_name(name)
143
+ start_value = options[:sequence_start_value] || 10000
144
+ raise ActiveRecord::StatementInvalid.new("name #{seq_name} too long") if seq_name.length > table_alias_length
145
+ execute "CREATE SEQUENCE #{seq_name} START WITH #{start_value}" unless options[:id] == false
146
+ end
147
+
148
+ def rename_table(name, new_name) #:nodoc:
149
+ execute "RENAME #{name} TO #{new_name}"
150
+ execute "RENAME #{name}_seq TO #{new_name}_seq" rescue nil
151
+ end
152
+
153
+ def drop_table(name, options = {}) #:nodoc:
154
+ super(name) rescue nil
155
+ seq_name = options[:sequence_name] || default_sequence_name(name)
156
+ execute "DROP SEQUENCE #{seq_name}" rescue nil
157
+ end
158
+
159
+ def recreate_database(name)
160
+ tables.each{ |table| drop_table(table) }
161
+ end
162
+
163
+ def drop_database(name)
164
+ recreate_database(name)
165
+ end
166
+
167
+ def next_sequence_value(sequence_name)
168
+ # avoid #select or #select_one so that the sequence values aren't cached
169
+ execute("select #{sequence_name}.nextval id from dual").first['id'].to_i
170
+ end
171
+
172
+ def sql_literal?(value)
173
+ defined?(::Arel::SqlLiteral) && ::Arel::SqlLiteral === value
174
+ end
175
+
176
+ def ora_insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = []) #:nodoc:
177
+ if (id_value && !sql_literal?(id_value)) || pk.nil?
178
+ # Pre-assigned id or table without a primary key
179
+ # Presence of #to_sql means an Arel literal bind variable
180
+ # that should use #execute_id_insert below
181
+ execute sql, name, binds
182
+ else
183
+ # Assume the sql contains a bind-variable for the id
184
+ # Extract the table from the insert sql. Yuck.
185
+ table = sql.split(" ", 4)[2].gsub('"', '')
186
+ sequence_name ||= default_sequence_name(table)
187
+ id_value = next_sequence_value(sequence_name)
188
+ log(sql, name) do
189
+ @connection.execute_id_insert(sql,id_value)
190
+ end
191
+ end
192
+ id_value
193
+ end
194
+
195
+ def indexes(table, name = nil)
196
+ @connection.indexes(table, name, @connection.connection.meta_data.user_name)
197
+ end
198
+
199
+ def _execute(sql, name = nil)
200
+ case sql.strip
201
+ when /\A\(?\s*(select|show)/i then
202
+ @connection.execute_query(sql)
203
+ else
204
+ @connection.execute_update(sql)
205
+ end
206
+ end
207
+
208
+ def modify_types(tp)
209
+ tp[:primary_key] = "NUMBER(38) NOT NULL PRIMARY KEY"
210
+ tp[:integer] = { :name => "NUMBER", :limit => 38 }
211
+ tp[:datetime] = { :name => "DATE" }
212
+ tp[:timestamp] = { :name => "DATE" }
213
+ tp[:time] = { :name => "DATE" }
214
+ tp[:date] = { :name => "DATE" }
215
+ tp
216
+ end
217
+
218
+ def add_limit_offset!(sql, options) #:nodoc:
219
+ offset = options[:offset] || 0
220
+
221
+ if limit = options[:limit]
222
+ sql.replace "select * from (select raw_sql_.*, rownum raw_rnum_ from (#{sql}) raw_sql_ where rownum <= #{offset+limit}) where raw_rnum_ > #{offset}"
223
+ elsif offset > 0
224
+ sql.replace "select * from (select raw_sql_.*, rownum raw_rnum_ from (#{sql}) raw_sql_) where raw_rnum_ > #{offset}"
225
+ end
226
+ end
227
+
228
+ def current_database #:nodoc:
229
+ select_one("select sys_context('userenv','db_name') db from dual")["db"]
230
+ end
231
+
232
+ def remove_index(table_name, options = {}) #:nodoc:
233
+ execute "DROP INDEX #{index_name(table_name, options)}"
234
+ end
235
+
236
+ def change_column_default(table_name, column_name, default) #:nodoc:
237
+ execute "ALTER TABLE #{table_name} MODIFY #{column_name} DEFAULT #{quote(default)}"
238
+ end
239
+
240
+ def add_column_options!(sql, options) #:nodoc:
241
+ # handle case of defaults for CLOB columns, which would otherwise get "quoted" incorrectly
242
+ if options_include_default?(options) && (column = options[:column]) && column.type == :text
243
+ sql << " DEFAULT #{quote(options.delete(:default))}"
244
+ end
245
+ super
246
+ end
247
+
248
+ def change_column(table_name, column_name, type, options = {}) #:nodoc:
249
+ change_column_sql = "ALTER TABLE #{table_name} MODIFY #{column_name} #{type_to_sql(type, options[:limit])}"
250
+ add_column_options!(change_column_sql, options)
251
+ execute(change_column_sql)
252
+ end
253
+
254
+ def rename_column(table_name, column_name, new_column_name) #:nodoc:
255
+ execute "ALTER TABLE #{table_name} RENAME COLUMN #{column_name} to #{new_column_name}"
256
+ end
257
+
258
+ def remove_column(table_name, column_name) #:nodoc:
259
+ execute "ALTER TABLE #{table_name} DROP COLUMN #{column_name}"
260
+ end
261
+
262
+ def structure_dump #:nodoc:
263
+ s = select_all("select sequence_name from user_sequences").inject("") do |structure, seq|
264
+ structure << "create sequence #{seq.to_a.first.last};\n\n"
265
+ end
266
+
267
+ select_all("select table_name from user_tables").inject(s) do |structure, table|
268
+ ddl = "create table #{table.to_a.first.last} (\n "
269
+ cols = select_all(%Q{
270
+ select column_name, data_type, data_length, data_precision, data_scale, data_default, nullable
271
+ from user_tab_columns
272
+ where table_name = '#{table.to_a.first.last}'
273
+ order by column_id
274
+ }).map do |row|
275
+ row = row.inject({}) do |h,args|
276
+ h[args[0].downcase] = args[1]
277
+ h
278
+ end
279
+ col = "#{row['column_name'].downcase} #{row['data_type'].downcase}"
280
+ if row['data_type'] =='NUMBER' and !row['data_precision'].nil?
281
+ col << "(#{row['data_precision'].to_i}"
282
+ col << ",#{row['data_scale'].to_i}" if !row['data_scale'].nil?
283
+ col << ')'
284
+ elsif row['data_type'].include?('CHAR')
285
+ col << "(#{row['data_length'].to_i})"
286
+ end
287
+ col << " default #{row['data_default']}" if !row['data_default'].nil?
288
+ col << ' not null' if row['nullable'] == 'N'
289
+ col
290
+ end
291
+ ddl << cols.join(",\n ")
292
+ ddl << ");\n\n"
293
+ structure << ddl
294
+ end
295
+ end
296
+
297
+ def structure_drop #:nodoc:
298
+ s = select_all("select sequence_name from user_sequences").inject("") do |drop, seq|
299
+ drop << "drop sequence #{seq.to_a.first.last};\n\n"
300
+ end
301
+
302
+ select_all("select table_name from user_tables").inject(s) do |drop, table|
303
+ drop << "drop table #{table.to_a.first.last} cascade constraints;\n\n"
304
+ end
305
+ end
306
+
307
+ # SELECT DISTINCT clause for a given set of columns and a given ORDER BY clause.
308
+ #
309
+ # Oracle requires the ORDER BY columns to be in the SELECT list for DISTINCT
310
+ # queries. However, with those columns included in the SELECT DISTINCT list, you
311
+ # won't actually get a distinct list of the column you want (presuming the column
312
+ # has duplicates with multiple values for the ordered-by columns. So we use the
313
+ # FIRST_VALUE function to get a single (first) value for each column, effectively
314
+ # making every row the same.
315
+ #
316
+ # distinct("posts.id", "posts.created_at desc")
317
+ def distinct(columns, order_by)
318
+ return "DISTINCT #{columns}" if order_by.blank?
319
+
320
+ # construct a valid DISTINCT clause, ie. one that includes the ORDER BY columns, using
321
+ # FIRST_VALUE such that the inclusion of these columns doesn't invalidate the DISTINCT
322
+ order_columns = order_by.split(',').map { |s| s.strip }.reject(&:blank?)
323
+ order_columns = order_columns.zip((0...order_columns.size).to_a).map do |c, i|
324
+ "FIRST_VALUE(#{c.split.first}) OVER (PARTITION BY #{columns} ORDER BY #{c}) AS alias_#{i}__"
325
+ end
326
+ sql = "DISTINCT #{columns}, "
327
+ sql << order_columns * ", "
328
+ end
329
+
330
+ # ORDER BY clause for the passed order option.
331
+ #
332
+ # Uses column aliases as defined by #distinct.
333
+ def add_order_by_for_association_limiting!(sql, options)
334
+ return sql if options[:order].blank?
335
+
336
+ order = options[:order].split(',').collect { |s| s.strip }.reject(&:blank?)
337
+ order.map! {|s| $1 if s =~ / (.*)/}
338
+ order = order.zip((0...order.size).to_a).map { |s,i| "alias_#{i}__ #{s}" }.join(', ')
339
+
340
+ sql << "ORDER BY #{order}"
341
+ end
342
+
343
+ def tables
344
+ @connection.tables(nil, oracle_schema)
345
+ end
346
+
347
+ def ora_columns(table_name, name=nil)
348
+ @connection.columns_internal(table_name, name, oracle_schema)
349
+ end
350
+
351
+ # QUOTING ==================================================
352
+ #
353
+ # see: abstract/quoting.rb
354
+
355
+ # See ACTIVERECORD_JDBC-33 for details -- better to not quote
356
+ # table names, esp. if they have schemas.
357
+ def quote_table_name(name) #:nodoc:
358
+ name.to_s
359
+ end
360
+
361
+ # Camelcase column names need to be quoted.
362
+ # Nonquoted identifiers can contain only alphanumeric characters from your
363
+ # database character set and the underscore (_), dollar sign ($), and pound sign (#).
364
+ # Database links can also contain periods (.) and "at" signs (@).
365
+ # Oracle strongly discourages you from using $ and # in nonquoted identifiers.
366
+ # Source: http://download.oracle.com/docs/cd/B28359_01/server.111/b28286/sql_elements008.htm
367
+ def quote_column_name(name) #:nodoc:
368
+ name.to_s =~ /^[a-z0-9_$#]+$/ ? name.to_s : "\"#{name}\""
369
+ end
370
+
371
+ def quote_string(string) #:nodoc:
372
+ string.gsub(/'/, "''")
373
+ end
374
+
375
+ def quote(value, column = nil) #:nodoc:
376
+ # Arel 2 passes SqlLiterals through
377
+ return value if sql_literal?(value)
378
+
379
+ if column && [:text, :binary].include?(column.type)
380
+ if /(.*?)\([0-9]+\)/ =~ column.sql_type
381
+ %Q{empty_#{ $1.downcase }()}
382
+ else
383
+ %Q{empty_#{ column.sql_type.downcase rescue 'blob' }()}
384
+ end
385
+ else
386
+ if column.respond_to?(:primary) && column.primary && column.klass != String
387
+ return value.to_i.to_s
388
+ end
389
+ quoted = super
390
+ if value.acts_like?(:date)
391
+ quoted = %Q{DATE'#{quoted_date(value)}'}
392
+ elsif value.acts_like?(:time)
393
+ quoted = %Q{TIMESTAMP'#{quoted_date(value)}'}
394
+ end
395
+ quoted
396
+ end
397
+ end
398
+
399
+ def quoted_true #:nodoc:
400
+ '1'
401
+ end
402
+
403
+ def quoted_false #:nodoc:
404
+ '0'
405
+ end
406
+
407
+ private
408
+ # In Oracle, schemas are usually created under your username:
409
+ # http://www.oracle.com/technology/obe/2day_dba/schema/schema.htm
410
+ # But allow separate configuration as "schema:" anyway (GH #53)
411
+ def oracle_schema
412
+ if @config[:schema]
413
+ @config[:schema].to_s
414
+ elsif @config[:username]
415
+ @config[:username].to_s
416
+ end
417
+ end
418
+
419
+ def select(sql, name = nil, binds = [])
420
+ records = execute(sql, name, binds)
421
+ records.each do |col|
422
+ col.delete('raw_rnum_')
423
+ end
424
+ records
425
+ end
426
+ end
427
+ end
428
+