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