activerecord-jdbc-adapter 1.3.0.beta2 → 1.3.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (282) hide show
  1. data/.gitignore +14 -8
  2. data/.travis.yml +40 -31
  3. data/.yardopts +4 -0
  4. data/Appraisals +2 -5
  5. data/CONTRIBUTING.md +46 -0
  6. data/Gemfile +21 -4
  7. data/Gemfile.lock +42 -17
  8. data/{History.txt → History.md} +142 -75
  9. data/README.md +102 -104
  10. data/RUNNING_TESTS.md +76 -0
  11. data/Rakefile.jdbc +20 -0
  12. data/activerecord-jdbc-adapter.gemspec +35 -18
  13. data/gemfiles/rails23.gemfile +4 -3
  14. data/gemfiles/rails23.gemfile.lock +9 -6
  15. data/gemfiles/rails30.gemfile +4 -3
  16. data/gemfiles/rails30.gemfile.lock +9 -6
  17. data/gemfiles/rails31.gemfile +4 -3
  18. data/gemfiles/rails31.gemfile.lock +9 -6
  19. data/gemfiles/rails32.gemfile +4 -3
  20. data/gemfiles/rails32.gemfile.lock +17 -14
  21. data/gemfiles/rails40.gemfile +5 -5
  22. data/gemfiles/rails40.gemfile.lock +17 -69
  23. data/lib/active_record/connection_adapters/firebird_adapter.rb +1 -0
  24. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +1 -0
  25. data/lib/arel/visitors/compat.rb +22 -3
  26. data/lib/arel/visitors/db2.rb +8 -4
  27. data/lib/arel/visitors/derby.rb +14 -13
  28. data/lib/arel/visitors/firebird.rb +5 -4
  29. data/lib/arel/visitors/hsqldb.rb +11 -9
  30. data/lib/arel/visitors/sql_server.rb +89 -61
  31. data/lib/arjdbc.rb +1 -1
  32. data/lib/arjdbc/db2/adapter.rb +181 -212
  33. data/lib/arjdbc/db2/as400.rb +31 -18
  34. data/lib/arjdbc/db2/column.rb +167 -0
  35. data/lib/arjdbc/db2/connection_methods.rb +2 -0
  36. data/lib/arjdbc/derby/adapter.rb +206 -107
  37. data/lib/arjdbc/derby/connection_methods.rb +4 -9
  38. data/lib/arjdbc/firebird.rb +1 -0
  39. data/lib/arjdbc/firebird/adapter.rb +202 -64
  40. data/lib/arjdbc/firebird/connection_methods.rb +20 -0
  41. data/lib/arjdbc/h2/adapter.rb +56 -36
  42. data/lib/arjdbc/hsqldb/adapter.rb +99 -68
  43. data/lib/arjdbc/jdbc/adapter.rb +474 -265
  44. data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
  45. data/lib/arjdbc/jdbc/adapter_require.rb +8 -7
  46. data/lib/arjdbc/jdbc/arel_support.rb +132 -0
  47. data/lib/arjdbc/jdbc/base_ext.rb +8 -7
  48. data/lib/arjdbc/jdbc/callbacks.rb +16 -10
  49. data/lib/arjdbc/jdbc/column.rb +25 -3
  50. data/lib/arjdbc/jdbc/connection.rb +28 -55
  51. data/lib/arjdbc/jdbc/extension.rb +14 -14
  52. data/lib/arjdbc/jdbc/java.rb +6 -3
  53. data/lib/arjdbc/jdbc/jdbc.rake +1 -1
  54. data/lib/arjdbc/jdbc/quoted_primary_key.rb +2 -2
  55. data/lib/arjdbc/jdbc/rake_tasks.rb +1 -1
  56. data/lib/arjdbc/jdbc/type_converter.rb +5 -2
  57. data/lib/arjdbc/mssql/adapter.rb +160 -280
  58. data/lib/arjdbc/mssql/column.rb +182 -0
  59. data/lib/arjdbc/mssql/connection_methods.rb +37 -4
  60. data/lib/arjdbc/mssql/explain_support.rb +13 -21
  61. data/lib/arjdbc/mssql/limit_helpers.rb +79 -42
  62. data/lib/arjdbc/mssql/lock_methods.rb +77 -0
  63. data/lib/arjdbc/mssql/utils.rb +11 -11
  64. data/lib/arjdbc/mysql/adapter.rb +165 -247
  65. data/lib/arjdbc/mysql/column.rb +123 -0
  66. data/lib/arjdbc/mysql/connection_methods.rb +3 -6
  67. data/lib/arjdbc/oracle/adapter.rb +282 -288
  68. data/lib/arjdbc/oracle/column.rb +122 -0
  69. data/lib/arjdbc/oracle/connection_methods.rb +3 -0
  70. data/lib/arjdbc/postgresql/adapter.rb +336 -574
  71. data/lib/arjdbc/postgresql/column.rb +458 -0
  72. data/lib/arjdbc/postgresql/connection_methods.rb +1 -2
  73. data/lib/arjdbc/postgresql/schema_creation.rb +38 -0
  74. data/lib/arjdbc/sqlite3/adapter.rb +189 -145
  75. data/lib/arjdbc/sqlite3/explain_support.rb +1 -1
  76. data/lib/arjdbc/tasks/oracle/enhanced_structure_dump.rb +8 -8
  77. data/lib/arjdbc/util/quoted_cache.rb +60 -0
  78. data/lib/arjdbc/util/table_copier.rb +110 -0
  79. data/lib/arjdbc/version.rb +6 -7
  80. data/pom.xml +56 -2
  81. data/rakelib/02-test.rake +72 -83
  82. data/rakelib/db.rake +29 -17
  83. data/src/java/arjdbc/ArJdbcModule.java +21 -18
  84. data/src/java/arjdbc/db2/DB2RubyJdbcConnection.java +84 -12
  85. data/src/java/arjdbc/derby/DerbyModule.java +140 -143
  86. data/src/java/arjdbc/derby/DerbyRubyJdbcConnection.java +58 -7
  87. data/src/java/arjdbc/h2/H2Module.java +43 -0
  88. data/src/java/arjdbc/informix/InformixRubyJdbcConnection.java +7 -6
  89. data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +1223 -648
  90. data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +24 -23
  91. data/src/java/arjdbc/mysql/MySQLModule.java +33 -32
  92. data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +147 -30
  93. data/src/java/arjdbc/oracle/OracleModule.java +13 -13
  94. data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +114 -6
  95. data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +166 -36
  96. data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +101 -19
  97. data/src/java/arjdbc/util/QuotingUtils.java +19 -19
  98. metadata +240 -394
  99. data/bench/bench_attributes.rb +0 -13
  100. data/bench/bench_attributes_new.rb +0 -14
  101. data/bench/bench_create.rb +0 -12
  102. data/bench/bench_find_all.rb +0 -12
  103. data/bench/bench_find_all_mt.rb +0 -25
  104. data/bench/bench_model.rb +0 -85
  105. data/bench/bench_new.rb +0 -12
  106. data/bench/bench_new_valid.rb +0 -12
  107. data/bench/bench_valid.rb +0 -13
  108. data/lib/arel/engines/sql/compilers/db2_compiler.rb +0 -9
  109. data/lib/arel/engines/sql/compilers/derby_compiler.rb +0 -6
  110. data/lib/arel/engines/sql/compilers/h2_compiler.rb +0 -6
  111. data/lib/arel/engines/sql/compilers/hsqldb_compiler.rb +0 -15
  112. data/lib/arel/engines/sql/compilers/jdbc_compiler.rb +0 -6
  113. data/lib/arel/engines/sql/compilers/mssql_compiler.rb +0 -46
  114. data/lib/arjdbc/jdbc/missing_functionality_helper.rb +0 -98
  115. data/lib/arjdbc/mssql/lock_helpers.rb +0 -76
  116. data/lib/arjdbc/mssql/tsql_methods.rb +0 -58
  117. data/lib/arjdbc/postgresql/column_cast.rb +0 -134
  118. data/test/activerecord/connections/native_jdbc_mysql/connection.rb +0 -25
  119. data/test/activerecord/jall.sh +0 -7
  120. data/test/activerecord/jtest.sh +0 -3
  121. data/test/assets/flowers.jpg +0 -0
  122. data/test/binary.rb +0 -67
  123. data/test/db/db2.rb +0 -43
  124. data/test/db/db2/binary_test.rb +0 -6
  125. data/test/db/db2/has_many_through_test.rb +0 -6
  126. data/test/db/db2/rake_test.rb +0 -82
  127. data/test/db/db2/rake_test_data.sql +0 -35
  128. data/test/db/db2/reset_column_information_test.rb +0 -5
  129. data/test/db/db2/serialize_test.rb +0 -6
  130. data/test/db/db2/simple_test.rb +0 -81
  131. data/test/db/db2/test_helper.rb +0 -6
  132. data/test/db/db2/unit_test.rb +0 -73
  133. data/test/db/derby.rb +0 -12
  134. data/test/db/derby/binary_test.rb +0 -6
  135. data/test/db/derby/migration_test.rb +0 -74
  136. data/test/db/derby/rake_test.rb +0 -96
  137. data/test/db/derby/reset_column_information_test.rb +0 -6
  138. data/test/db/derby/row_locking_test.rb +0 -20
  139. data/test/db/derby/schema_dump_test.rb +0 -5
  140. data/test/db/derby/serialize_test.rb +0 -6
  141. data/test/db/derby/simple_test.rb +0 -173
  142. data/test/db/derby/test_helper.rb +0 -6
  143. data/test/db/derby/unit_test.rb +0 -32
  144. data/test/db/derby/xml_column_test.rb +0 -17
  145. data/test/db/h2.rb +0 -11
  146. data/test/db/h2/binary_test.rb +0 -6
  147. data/test/db/h2/change_column_test.rb +0 -68
  148. data/test/db/h2/identity_column_test.rb +0 -35
  149. data/test/db/h2/offset_test.rb +0 -49
  150. data/test/db/h2/rake_test.rb +0 -98
  151. data/test/db/h2/schema_dump_test.rb +0 -29
  152. data/test/db/h2/serialize_test.rb +0 -6
  153. data/test/db/h2/simple_test.rb +0 -56
  154. data/test/db/hsqldb.rb +0 -11
  155. data/test/db/hsqldb/binary_test.rb +0 -6
  156. data/test/db/hsqldb/rake_test.rb +0 -101
  157. data/test/db/hsqldb/schema_dump_test.rb +0 -19
  158. data/test/db/hsqldb/serialize_test.rb +0 -6
  159. data/test/db/hsqldb/simple_test.rb +0 -17
  160. data/test/db/informix.rb +0 -13
  161. data/test/db/jdbc.rb +0 -16
  162. data/test/db/jdbc_derby.rb +0 -14
  163. data/test/db/jdbc_h2.rb +0 -17
  164. data/test/db/jdbc_mysql.rb +0 -13
  165. data/test/db/jdbc_postgres.rb +0 -23
  166. data/test/db/jndi_config.rb +0 -32
  167. data/test/db/jndi_pooled_config.rb +0 -32
  168. data/test/db/mssql.rb +0 -11
  169. data/test/db/mssql/binary_test.rb +0 -6
  170. data/test/db/mssql/exec_proc_test.rb +0 -46
  171. data/test/db/mssql/identity_insert_test.rb +0 -18
  172. data/test/db/mssql/ignore_system_views_test.rb +0 -40
  173. data/test/db/mssql/limit_offset_test.rb +0 -190
  174. data/test/db/mssql/multibyte_test.rb +0 -16
  175. data/test/db/mssql/multiple_connections_test.rb +0 -71
  176. data/test/db/mssql/rake_test.rb +0 -143
  177. data/test/db/mssql/reset_column_information_test.rb +0 -6
  178. data/test/db/mssql/row_locking_test.rb +0 -7
  179. data/test/db/mssql/serialize_test.rb +0 -6
  180. data/test/db/mssql/simple_test.rb +0 -140
  181. data/test/db/mssql/transaction_test.rb +0 -6
  182. data/test/db/mssql/types_test.rb +0 -205
  183. data/test/db/mssql/unit_test.rb +0 -249
  184. data/test/db/mysql.rb +0 -4
  185. data/test/db/mysql/_rails_test_mysql.32.out +0 -6585
  186. data/test/db/mysql/binary_test.rb +0 -6
  187. data/test/db/mysql/connection_test.rb +0 -51
  188. data/test/db/mysql/index_length_test.rb +0 -58
  189. data/test/db/mysql/multibyte_test.rb +0 -10
  190. data/test/db/mysql/nonstandard_primary_key_test.rb +0 -39
  191. data/test/db/mysql/rake_test.rb +0 -97
  192. data/test/db/mysql/reset_column_information_test.rb +0 -6
  193. data/test/db/mysql/schema_dump_test.rb +0 -228
  194. data/test/db/mysql/serialize_test.rb +0 -6
  195. data/test/db/mysql/simple_test.rb +0 -187
  196. data/test/db/mysql/statement_escaping_test.rb +0 -46
  197. data/test/db/mysql/transaction_test.rb +0 -6
  198. data/test/db/mysql/types_test.rb +0 -30
  199. data/test/db/mysql/unit_test.rb +0 -93
  200. data/test/db/mysql_config.rb +0 -7
  201. data/test/db/oracle.rb +0 -27
  202. data/test/db/oracle/binary_test.rb +0 -6
  203. data/test/db/oracle/limit_test.rb +0 -24
  204. data/test/db/oracle/multibyte_test.rb +0 -22
  205. data/test/db/oracle/rake_test.rb +0 -100
  206. data/test/db/oracle/reset_column_information_test.rb +0 -6
  207. data/test/db/oracle/serialize_test.rb +0 -6
  208. data/test/db/oracle/simple_test.rb +0 -140
  209. data/test/db/oracle/specific_test.rb +0 -180
  210. data/test/db/oracle/transaction_test.rb +0 -31
  211. data/test/db/oracle/unit_test.rb +0 -31
  212. data/test/db/postgres.rb +0 -11
  213. data/test/db/postgres/_rails_test_postgres.32.out +0 -6405
  214. data/test/db/postgres/a_custom_primary_key_test.rb +0 -50
  215. data/test/db/postgres/active_schema_unit_test.rb +0 -68
  216. data/test/db/postgres/array_type_test.rb +0 -101
  217. data/test/db/postgres/binary_test.rb +0 -6
  218. data/test/db/postgres/connection_test.rb +0 -63
  219. data/test/db/postgres/data_types_test.rb +0 -703
  220. data/test/db/postgres/hstore_test.rb +0 -200
  221. data/test/db/postgres/information_schema_leak_test.rb +0 -30
  222. data/test/db/postgres/json_test.rb +0 -86
  223. data/test/db/postgres/ltree_test.rb +0 -51
  224. data/test/db/postgres/mixed_case_test.rb +0 -29
  225. data/test/db/postgres/native_types_test.rb +0 -124
  226. data/test/db/postgres/rake_test.rb +0 -117
  227. data/test/db/postgres/reserved_test.rb +0 -22
  228. data/test/db/postgres/reset_column_information_test.rb +0 -6
  229. data/test/db/postgres/row_locking_test.rb +0 -21
  230. data/test/db/postgres/schema_dump_test.rb +0 -95
  231. data/test/db/postgres/schema_test.rb +0 -115
  232. data/test/db/postgres/simple_test.rb +0 -260
  233. data/test/db/postgres/table_alias_length_test.rb +0 -16
  234. data/test/db/postgres/transaction_test.rb +0 -6
  235. data/test/db/postgres/unit_test.rb +0 -31
  236. data/test/db/postgres_config.rb +0 -10
  237. data/test/db/sqlite3.rb +0 -6
  238. data/test/db/sqlite3/_rails_test_sqlite3.32.out +0 -6274
  239. data/test/db/sqlite3/has_many_though_test.rb +0 -6
  240. data/test/db/sqlite3/rake_test.rb +0 -71
  241. data/test/db/sqlite3/reset_column_information_test.rb +0 -6
  242. data/test/db/sqlite3/schema_dump_test.rb +0 -6
  243. data/test/db/sqlite3/serialize_test.rb +0 -6
  244. data/test/db/sqlite3/simple_test.rb +0 -268
  245. data/test/db/sqlite3/transaction_test.rb +0 -32
  246. data/test/db/sqlite3/type_conversion_test.rb +0 -104
  247. data/test/has_many_through.rb +0 -61
  248. data/test/informix_simple_test.rb +0 -48
  249. data/test/jdbc/db2.rb +0 -36
  250. data/test/jdbc/oracle.rb +0 -34
  251. data/test/jdbc_column_test.rb +0 -23
  252. data/test/jdbc_common.rb +0 -16
  253. data/test/jdbc_connection_test.rb +0 -196
  254. data/test/jndi_callbacks_test.rb +0 -33
  255. data/test/jndi_test.rb +0 -55
  256. data/test/manualTestDatabase.rb +0 -191
  257. data/test/models/add_not_null_column_to_table.rb +0 -9
  258. data/test/models/auto_id.rb +0 -15
  259. data/test/models/binary.rb +0 -18
  260. data/test/models/custom_pk_name.rb +0 -15
  261. data/test/models/data_types.rb +0 -40
  262. data/test/models/entry.rb +0 -41
  263. data/test/models/mixed_case.rb +0 -22
  264. data/test/models/reserved_word.rb +0 -15
  265. data/test/models/rights_and_roles.rb +0 -57
  266. data/test/models/string_id.rb +0 -17
  267. data/test/models/thing.rb +0 -17
  268. data/test/models/topic.rb +0 -32
  269. data/test/models/validates_uniqueness_of_string.rb +0 -19
  270. data/test/rails/mysql.rb +0 -13
  271. data/test/rails/sqlite3/version.rb +0 -6
  272. data/test/rails_stub.rb +0 -31
  273. data/test/rake_test_support.rb +0 -298
  274. data/test/row_locking.rb +0 -102
  275. data/test/schema_dump.rb +0 -182
  276. data/test/serialize.rb +0 -275
  277. data/test/shared_helper.rb +0 -35
  278. data/test/simple.rb +0 -1317
  279. data/test/sybase_jtds_simple_test.rb +0 -28
  280. data/test/sybase_reset_column_information_test.rb +0 -6
  281. data/test/test_helper.rb +0 -304
  282. data/test/transaction.rb +0 -109
@@ -0,0 +1,122 @@
1
+ module ArJdbc
2
+ module Oracle
3
+
4
+ # @see ActiveRecord::ConnectionAdapters::JdbcColumn#column_types
5
+ def self.column_selector
6
+ [ /oracle/i, lambda { |config, column| column.extend(Column) } ]
7
+ end
8
+
9
+ # @see ActiveRecord::ConnectionAdapters::JdbcColumn
10
+ module Column
11
+
12
+ def self.included(base)
13
+ # NOTE: assumes a standalone OracleColumn class
14
+ class << base; include Cast; end
15
+ end
16
+
17
+ def primary=(value)
18
+ super
19
+ @type = :integer if value && @sql_type =~ /^NUMBER$/i
20
+ end
21
+
22
+ def type_cast(value)
23
+ return nil if value.nil?
24
+ case type
25
+ when :datetime then self.class.string_to_time(value)
26
+ when :timestamp then self.class.string_to_time(value)
27
+ when :boolean then self.class.value_to_boolean(value)
28
+ else
29
+ super
30
+ end
31
+ end
32
+
33
+ def type_cast_code(var_name)
34
+ case type
35
+ when :datetime then "#{self.class.name}.string_to_time(#{var_name})"
36
+ when :timestamp then "#{self.class.name}.string_to_time(#{var_name})"
37
+ when :boolean then "#{self.class.name}.value_to_boolean(#{var_name})"
38
+ else
39
+ super
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ def extract_limit(sql_type)
46
+ case sql_type
47
+ when /^(clob|date)/i then nil
48
+ when /^xml/i then @sql_type = 'XMLTYPE'; nil
49
+ else super
50
+ end
51
+ end
52
+
53
+ def simplified_type(field_type)
54
+ case field_type
55
+ when /char/i then :string
56
+ when /float|double/i then :float
57
+ when /int/i then :integer
58
+ when /^number\(1\)$/i then Oracle.emulate_booleans ? :boolean : :integer
59
+ when /^num|dec|real/i then extract_scale(field_type) == 0 ? :integer : :decimal
60
+ # Oracle TIMESTAMP stores the date and time to up to 9 digits of sub-second precision
61
+ when /TIMESTAMP/i then :timestamp
62
+ # Oracle DATE stores the date and time to the second
63
+ when /DATE|TIME/i then :datetime
64
+ when /CLOB/i then :text
65
+ when /BLOB/i then :binary
66
+ when /XML/i then :xml
67
+ else
68
+ super
69
+ end
70
+ end
71
+
72
+ # Post process default value from JDBC into a Rails-friendly format (columns{-internal})
73
+ def default_value(value)
74
+ return nil unless value
75
+ value = value.strip # Not sure why we need this for Oracle?
76
+ upcase = value.upcase
77
+
78
+ return nil if upcase == "NULL"
79
+ # SYSDATE default should be treated like a NULL value
80
+ return nil if upcase == "SYSDATE"
81
+ # jdbc returns column default strings with actual single quotes around the value.
82
+ return $1 if value =~ /^'(.*)'$/
83
+
84
+ value
85
+ end
86
+
87
+ module Cast
88
+
89
+ # Convert a value to a boolean.
90
+ def value_to_boolean(value)
91
+ # NOTE: Oracle JDBC meta-data gets us DECIMAL for NUMBER(1) values
92
+ # thus we're likely to get a column back as BigDecimal (e.g. 1.0)
93
+ if value.is_a?(String)
94
+ value.blank? ? nil : value == '1'
95
+ elsif value.is_a?(Numeric)
96
+ value.to_i == 1 # <BigDecimal:7b5bfe,'0.1E1',1(4)>
97
+ else
98
+ !! value
99
+ end
100
+ end
101
+
102
+ # @override
103
+ def string_to_time(string)
104
+ return string unless string.is_a?(String)
105
+ return nil if string.empty?
106
+ return Time.now if string.index('CURRENT') == 0 # TODO seems very wrong
107
+
108
+ super(string)
109
+ end
110
+
111
+ # @private
112
+ def guess_date_or_time(value)
113
+ return value if value.is_a? Date
114
+ ( value && value.hour == 0 && value.min == 0 && value.sec == 0 ) ?
115
+ Date.new(value.year, value.month, value.day) : value
116
+ end
117
+
118
+ end
119
+
120
+ end
121
+ end
122
+ end
@@ -1,4 +1,7 @@
1
1
  ArJdbc::ConnectionMethods.module_eval do
2
+ # Unless a connection URL (`url: jdbc:oracle:...`) is specified we'll use the
3
+ # *thin* method to connect to the Oracle DB.
4
+ # @note Oracle's JDBC driver should be on the class-path.
2
5
  def oracle_connection(config)
3
6
  config[:port] ||= 1521
4
7
  config[:url] ||= "jdbc:oracle:thin:@#{config[:host]}:#{config[:port]}:#{config[:database]}"
@@ -1,29 +1,75 @@
1
1
  ArJdbc.load_java_part :PostgreSQL
2
2
 
3
3
  require 'ipaddr'
4
- require 'arjdbc/postgresql/column_cast'
5
- require 'arjdbc/postgresql/explain_support'
6
4
 
7
5
  module ArJdbc
6
+ # Strives to provide Rails built-in PostgreSQL adapter (API) compatibility.
8
7
  module PostgreSQL
9
-
10
- AR4_COMPAT = ::ActiveRecord::VERSION::MAJOR > 3 unless const_defined?(:AR4_COMPAT) # :nodoc:
11
8
 
12
- def self.column_selector
13
- [ /postgre/i, lambda { |cfg, column| column.extend(::ArJdbc::PostgreSQL::Column) } ]
14
- end
9
+ # @private
10
+ AR4_COMPAT = ::ActiveRecord::VERSION::MAJOR > 3 unless const_defined?(:AR4_COMPAT)
11
+
12
+ require 'arjdbc/postgresql/column'
13
+ require 'arjdbc/postgresql/explain_support'
15
14
 
15
+ # @see ActiveRecord::ConnectionAdapters::JdbcAdapter#jdbc_connection_class
16
16
  def self.jdbc_connection_class
17
17
  ::ActiveRecord::ConnectionAdapters::PostgreSQLJdbcConnection
18
18
  end
19
19
 
20
+ # @private
21
+ def init_connection(jdbc_connection)
22
+ meta = jdbc_connection.meta_data
23
+ if meta.driver_version.index('JDBC3') # e.g. 'PostgreSQL 9.2 JDBC4 (build 1002)'
24
+ config[:connection_alive_sql] ||= 'SELECT 1'
25
+ else
26
+ # NOTE: since the loaded Java driver class can't change :
27
+ PostgreSQL.send(:remove_method, :init_connection) rescue nil
28
+ end
29
+ end
30
+
31
+ def self.arel_visitor_type(config = nil)
32
+ ::Arel::Visitors::PostgreSQL
33
+ end
34
+
35
+ # @see ActiveRecord::ConnectionAdapters::JdbcAdapter#bind_substitution
36
+ # @private
37
+ class BindSubstitution < ::Arel::Visitors::PostgreSQL
38
+ include ::Arel::Visitors::BindVisitor
39
+ end if defined? ::Arel::Visitors::BindVisitor
40
+
41
+ ADAPTER_NAME = 'PostgreSQL'.freeze
42
+
43
+ def adapter_name
44
+ ADAPTER_NAME
45
+ end
46
+
47
+ def postgresql_version
48
+ @postgresql_version ||=
49
+ begin
50
+ value = select_value('SELECT version()')
51
+ if value =~ /PostgreSQL (\d+)\.(\d+)\.(\d+)/
52
+ ($1.to_i * 10000) + ($2.to_i * 100) + $3.to_i
53
+ else
54
+ 0
55
+ end
56
+ end
57
+ end
58
+
59
+ def use_insert_returning?
60
+ if ( @use_insert_returning ||= nil ).nil?
61
+ @use_insert_returning = supports_insert_with_returning?
62
+ end
63
+ @use_insert_returning
64
+ end
65
+
20
66
  def set_client_encoding(encoding)
21
67
  ActiveRecord::Base.logger.warn "client_encoding is set by the driver and should not be altered, ('#{encoding}' ignored)"
22
68
  ActiveRecord::Base.logger.debug "Set the 'allowEncodingChanges' driver property (e.g. using config[:properties]) if you need to override the client encoding when doing a copy."
23
69
  end
24
70
 
25
71
  # Configures the encoding, verbosity, schema search path, and time zone of the connection.
26
- # This is called by #connect and should not be called manually.
72
+ # This is called on `connection.connect` and should not be called manually.
27
73
  def configure_connection
28
74
  #if encoding = config[:encoding]
29
75
  # The client_encoding setting is set by the driver and should not be altered.
@@ -42,8 +88,8 @@ module ArJdbc
42
88
  # (SET TIME ZONE does not use an equals sign like other SET variables)
43
89
  if ActiveRecord::Base.default_timezone == :utc
44
90
  execute("SET time zone 'UTC'", 'SCHEMA')
45
- elsif defined?(@local_tz) && @local_tz
46
- execute("SET time zone '#{@local_tz}'", 'SCHEMA')
91
+ elsif tz = local_tz
92
+ execute("SET time zone '#{tz}'", 'SCHEMA')
47
93
  end # if defined? ActiveRecord::Base.default_timezone
48
94
 
49
95
  # SET statements from :variables config hash
@@ -58,334 +104,9 @@ module ArJdbc
58
104
  end
59
105
  end
60
106
 
61
- # constants taken from postgresql_adapter in rails project
62
- ADAPTER_NAME = 'PostgreSQL'.freeze
63
-
64
- def adapter_name # :nodoc:
65
- ADAPTER_NAME
66
- end
67
-
68
- def self.arel2_visitors(config)
69
- {
70
- 'postgresql' => ::Arel::Visitors::PostgreSQL,
71
- 'jdbcpostgresql' => ::Arel::Visitors::PostgreSQL,
72
- 'pg' => ::Arel::Visitors::PostgreSQL
73
- }
74
- end
75
-
76
- def new_visitor(config = nil)
77
- visitor = ::Arel::Visitors::PostgreSQL
78
- ( prepared_statements? ? visitor : bind_substitution(visitor) ).new(self)
79
- end if defined? ::Arel::Visitors::PostgreSQL
80
-
81
- # @see #bind_substitution
82
- class BindSubstitution < Arel::Visitors::PostgreSQL # :nodoc:
83
- include Arel::Visitors::BindVisitor
84
- end if defined? Arel::Visitors::BindVisitor
107
+ # @private
108
+ ActiveRecordError = ::ActiveRecord::ActiveRecordError
85
109
 
86
- def postgresql_version
87
- @postgresql_version ||=
88
- begin
89
- value = select_value('SELECT version()')
90
- if value =~ /PostgreSQL (\d+)\.(\d+)\.(\d+)/
91
- ($1.to_i * 10000) + ($2.to_i * 100) + $3.to_i
92
- else
93
- 0
94
- end
95
- end
96
- end
97
-
98
- def use_insert_returning?
99
- if ( @use_insert_returning ||= nil ).nil?
100
- @use_insert_returning = supports_insert_with_returning?
101
- end
102
- @use_insert_returning
103
- end
104
-
105
- # column behavior based on postgresql_adapter in rails
106
- module Column
107
-
108
- def self.included(base)
109
- class << base
110
- include ArJdbc::PostgreSQL::Column::Cast
111
- # include ArJdbc::PostgreSQL::Column::ArrayParser
112
- attr_accessor :money_precision
113
- end
114
- end
115
-
116
- attr_accessor :array
117
- def array?; array; end # in case we remove the array reader
118
-
119
- # Extracts the value from a PostgreSQL column default definition.
120
- #
121
- # @override JdbcColumn#default_value
122
- # NOTE: based on `self.extract_value_from_default(default)` code
123
- def default_value(default)
124
- # This is a performance optimization for Ruby 1.9.2 in development.
125
- # If the value is nil, we return nil straight away without checking
126
- # the regular expressions. If we check each regular expression,
127
- # Regexp#=== will call NilClass#to_str, which will trigger
128
- # method_missing (defined by whiny nil in ActiveSupport) which
129
- # makes this method very very slow.
130
- return default unless default
131
-
132
- case default
133
- when /\A'(.*)'::(num|date|tstz|ts|int4|int8)range\z/m
134
- $1
135
- # Numeric types
136
- when /\A\(?(-?\d+(\.\d*)?\)?)\z/
137
- $1
138
- # Character types
139
- when /\A\(?'(.*)'::.*\b(?:character varying|bpchar|text)\z/m
140
- $1
141
- # Binary data types
142
- when /\A'(.*)'::bytea\z/m
143
- $1
144
- # Date/time types
145
- when /\A'(.+)'::(?:time(?:stamp)? with(?:out)? time zone|date)\z/
146
- $1
147
- when /\A'(.*)'::interval\z/
148
- $1
149
- # Boolean type
150
- when 'true'
151
- true
152
- when 'false'
153
- false
154
- # Geometric types
155
- when /\A'(.*)'::(?:point|line|lseg|box|"?path"?|polygon|circle)\z/
156
- $1
157
- # Network address types
158
- when /\A'(.*)'::(?:cidr|inet|macaddr)\z/
159
- $1
160
- # Bit string types
161
- when /\AB'(.*)'::"?bit(?: varying)?"?\z/
162
- $1
163
- # XML type
164
- when /\A'(.*)'::xml\z/m
165
- $1
166
- # Arrays
167
- when /\A'(.*)'::"?\D+"?\[\]\z/
168
- $1
169
- # Hstore
170
- when /\A'(.*)'::hstore\z/
171
- $1
172
- # JSON
173
- when /\A'(.*)'::json\z/
174
- $1
175
- # Object identifier types
176
- when /\A-?\d+\z/
177
- $1
178
- else
179
- # Anything else is blank, some user type, or some function
180
- # and we can't know the value of that, so return nil.
181
- nil
182
- end
183
- end
184
-
185
- # Casts value (which is a String) to an appropriate instance.
186
- def type_cast(value)
187
- return if value.nil?
188
- return super if encoded? # respond_to?(:encoded?) only since AR-3.2
189
-
190
- # NOTE: we do not use OID::Type
191
- # @oid_type.type_cast value
192
-
193
- return value if array? # handled on the connection (JDBC) side
194
-
195
- case type
196
- when :hstore then self.class.string_to_hstore value
197
- when :json then self.class.string_to_json value
198
- when :cidr, :inet then self.class.string_to_cidr value
199
- when :macaddr then value
200
- when :tsvector then value
201
- when :datetime, :timestamp then self.class.string_to_time value
202
- else
203
- case sql_type
204
- when 'money'
205
- # Because money output is formatted according to the locale, there
206
- # are two cases to consider (note the decimal separators) :
207
- # (1) $12,345,678.12
208
- # (2) $12.345.678,12
209
- case value
210
- when /^-?\D+[\d,]+\.\d{2}$/ # (1)
211
- value.gsub!(/[^-\d.]/, '')
212
- when /^-?\D+[\d.]+,\d{2}$/ # (2)
213
- value.gsub!(/[^-\d,]/, '')
214
- value.sub!(/,/, '.')
215
- end
216
- self.class.value_to_decimal value
217
- when /^point/
218
- if value.is_a?(String)
219
- self.class.string_to_point value
220
- else
221
- value
222
- end
223
- when /(.*?)range$/
224
- return if value.nil? || value == 'empty'
225
- return value if value.is_a?(::Range)
226
-
227
- extracted = extract_bounds(value)
228
-
229
- case $1 # subtype
230
- when 'date' # :date
231
- from = self.class.value_to_date(extracted[:from])
232
- from -= 1.day if extracted[:exclude_start]
233
- to = self.class.value_to_date(extracted[:to])
234
- when 'num' # :decimal
235
- from = BigDecimal.new(extracted[:from].to_s)
236
- # FIXME: add exclude start for ::Range, same for timestamp ranges
237
- to = BigDecimal.new(extracted[:to].to_s)
238
- when 'ts', 'tstz' # :time
239
- from = self.class.string_to_time(extracted[:from])
240
- to = self.class.string_to_time(extracted[:to])
241
- when 'int4', 'int8' # :integer
242
- from = to_integer(extracted[:from]) rescue value ? 1 : 0
243
- from -= 1 if extracted[:exclude_start]
244
- to = to_integer(extracted[:to]) rescue value ? 1 : 0
245
- else
246
- return value
247
- end
248
-
249
- ::Range.new(from, to, extracted[:exclude_end])
250
- else super
251
- end
252
- end
253
- end if AR4_COMPAT
254
-
255
- private
256
-
257
- def extract_limit(sql_type)
258
- case sql_type
259
- when /^bigint/i; 8
260
- when /^smallint/i; 2
261
- when /^timestamp/i; nil
262
- else super
263
- end
264
- end
265
-
266
- # Extracts the scale from PostgreSQL-specific data types.
267
- def extract_scale(sql_type)
268
- # Money type has a fixed scale of 2.
269
- sql_type =~ /^money/ ? 2 : super
270
- end
271
-
272
- # Extracts the precision from PostgreSQL-specific data types.
273
- def extract_precision(sql_type)
274
- if sql_type == 'money'
275
- self.class.money_precision
276
- elsif sql_type =~ /timestamp/i
277
- $1.to_i if sql_type =~ /\((\d+)\)/
278
- else
279
- super
280
- end
281
- end
282
-
283
- # Maps PostgreSQL-specific data types to logical Rails types.
284
- def simplified_type(field_type)
285
- case field_type
286
- # Numeric and monetary types
287
- when /^(?:real|double precision)$/ then :float
288
- # Monetary types
289
- when 'money' then :decimal
290
- # Character types
291
- when /^(?:character varying|bpchar)(?:\(\d+\))?$/ then :string
292
- # Binary data types
293
- when 'bytea' then :binary
294
- # Date/time types
295
- when /^timestamp with(?:out)? time zone$/ then :datetime
296
- when 'interval' then :string
297
- # Geometric types
298
- when /^(?:point|line|lseg|box|"?path"?|polygon|circle)$/ then :string
299
- # Network address types
300
- when /^(?:cidr|inet|macaddr)$/ then :string
301
- # Bit strings
302
- when /^bit(?: varying)?(?:\(\d+\))?$/ then :string
303
- # XML type
304
- when 'xml' then :xml
305
- # tsvector type
306
- when 'tsvector' then :tsvector
307
- # Arrays
308
- when /^\D+\[\]$/ then :string
309
- # Object identifier types
310
- when 'oid' then :integer
311
- # UUID type
312
- when 'uuid' then :string
313
- # Small and big integer types
314
- when /^(?:small|big)int$/ then :integer
315
- # Pass through all types that are not specific to PostgreSQL.
316
- else
317
- super
318
- end
319
- end
320
-
321
- def simplified_type(field_type) # :nodoc:
322
- case field_type
323
- # Numeric and monetary types
324
- when /^(?:real|double precision)$/ then :float
325
- # Monetary types
326
- when 'money' then :decimal
327
- when 'hstore' then :hstore
328
- when 'ltree' then :ltree
329
- # Network address types
330
- when 'inet' then :inet
331
- when 'cidr' then :cidr
332
- when 'macaddr' then :macaddr
333
- # Character types
334
- when /^(?:character varying|bpchar)(?:\(\d+\))?$/ then :string
335
- # Binary data types
336
- when 'bytea' then :binary
337
- # Date/time types
338
- when /^timestamp with(?:out)? time zone$/ then :datetime
339
- when /^interval(?:|\(\d+\))$/ then :string
340
- # Geometric types
341
- when /^(?:point|line|lseg|box|"?path"?|polygon|circle)$/ then :string
342
- # Bit strings
343
- when /^bit(?: varying)?(?:\(\d+\))?$/ then :string
344
- # XML type
345
- when 'xml' then :xml
346
- # tsvector type
347
- when 'tsvector' then :tsvector
348
- # Arrays
349
- when /^\D+\[\]$/ then :string
350
- # Object identifier types
351
- when 'oid' then :integer
352
- # UUID type
353
- when 'uuid' then :uuid
354
- # JSON type
355
- when 'json' then :json
356
- # Small and big integer types
357
- when /^(?:small|big)int$/ then :integer
358
- when /(num|date|tstz|ts|int4|int8)range$/
359
- field_type.to_sym
360
- # Pass through all types that are not specific to PostgreSQL.
361
- else
362
- super
363
- end
364
- end if AR4_COMPAT
365
-
366
- # OID Type::Range helpers :
367
-
368
- def extract_bounds(value)
369
- f, t = value[1..-2].split(',')
370
- {
371
- :from => (value[1] == ',' || f == '-infinity') ? infinity(:negative => true) : f,
372
- :to => (value[-2] == ',' || t == 'infinity') ? infinity : t,
373
- :exclude_start => (value[0] == '('), :exclude_end => (value[-1] == ')')
374
- }
375
- end if AR4_COMPAT
376
-
377
- def infinity(options = {})
378
- ::Float::INFINITY * (options[:negative] ? -1 : 1)
379
- end if AR4_COMPAT
380
-
381
- def to_integer(value)
382
- (value.respond_to?(:infinite?) && value.infinite?) ? value : value.to_i
383
- end if AR4_COMPAT
384
-
385
- end # Column
386
-
387
- ActiveRecordError = ::ActiveRecord::ActiveRecordError # :nodoc:
388
-
389
110
  # Maps logical Rails types to PostgreSQL-specific data types.
390
111
  def type_to_sql(type, limit = nil, precision = nil, scale = nil)
391
112
  case type.to_sym
@@ -432,9 +153,15 @@ module ArJdbc
432
153
  return super(value, column) unless 'bytea' == column.sql_type
433
154
  value # { :value => value, :format => 1 }
434
155
  when Array
435
- return super(value, column) unless column.array?
436
- column_class = ::ActiveRecord::ConnectionAdapters::PostgreSQLColumn
437
- column_class.array_to_string(value, column, self)
156
+ case column.sql_type
157
+ when 'point'
158
+ column_class = ::ActiveRecord::ConnectionAdapters::PostgreSQLColumn
159
+ column_class.point_to_string(value)
160
+ else
161
+ return super(value, column) unless column.array?
162
+ column_class = ::ActiveRecord::ConnectionAdapters::PostgreSQLColumn
163
+ column_class.array_to_string(value, column, self)
164
+ end
438
165
  when NilClass
439
166
  if column.array? && array_member
440
167
  'NULL'
@@ -457,18 +184,23 @@ module ArJdbc
457
184
  return super unless column.sql_type == 'inet' || column.sql_type == 'cidr'
458
185
  column_class = ::ActiveRecord::ConnectionAdapters::PostgreSQLColumn
459
186
  column_class.cidr_to_string(value)
187
+ when Range
188
+ return super(value, column) unless /range$/ =~ column.sql_type
189
+ column_class = ::ActiveRecord::ConnectionAdapters::PostgreSQLColumn
190
+ column_class.range_to_string(value)
460
191
  else
461
192
  super(value, column)
462
193
  end
463
194
  end if AR4_COMPAT
464
-
195
+
465
196
  NATIVE_DATABASE_TYPES = {
466
197
  :primary_key => "serial primary key",
467
198
  :string => { :name => "character varying", :limit => 255 },
468
199
  :text => { :name => "text" },
469
200
  :integer => { :name => "integer" },
470
201
  :float => { :name => "float" },
471
- :decimal => { :name => "decimal" },
202
+ :numeric => { :name => "numeric" },
203
+ :decimal => { :name => "decimal" }, # :limit => 1000
472
204
  :datetime => { :name => "timestamp" },
473
205
  :timestamp => { :name => "timestamp" },
474
206
  :time => { :name => "time" },
@@ -476,8 +208,14 @@ module ArJdbc
476
208
  :binary => { :name => "bytea" },
477
209
  :boolean => { :name => "boolean" },
478
210
  :xml => { :name => "xml" },
211
+ # AR-JDBC added :
212
+ #:timestamptz => { :name => "timestamptz" },
213
+ #:timetz => { :name => "timetz" },
214
+ :money => { :name=>"money" },
215
+ :char => { :name => "char" },
216
+ :serial => { :name => "serial" }, # auto-inc integer, bigserial, smallserial
479
217
  }
480
-
218
+
481
219
  NATIVE_DATABASE_TYPES.update({
482
220
  :tsvector => { :name => "tsvector" },
483
221
  :hstore => { :name => "hstore" },
@@ -495,41 +233,35 @@ module ArJdbc
495
233
  :int4range => { :name => "int4range" },
496
234
  :int8range => { :name => "int8range" },
497
235
  }) if AR4_COMPAT
498
-
236
+
499
237
  def native_database_types
500
238
  NATIVE_DATABASE_TYPES
501
239
  end
502
-
503
- # Adds `:array` option to the default set provided by the AbstractAdapter
240
+
241
+ # Adds `:array` option to the default set provided by the `AbstractAdapter`.
504
242
  def prepare_column_options(column, types)
505
243
  spec = super
506
244
  spec[:array] = 'true' if column.respond_to?(:array) && column.array
507
245
  spec
508
246
  end if AR4_COMPAT
509
247
 
510
- # Adds `:array` as a valid migration key
248
+ # Adds `:array` as a valid migration key.
511
249
  def migration_keys
512
250
  super + [:array]
513
251
  end if AR4_COMPAT
514
-
515
- def add_column_options!(sql, options)
516
- if options[:array] || options[:column].try(:array)
517
- sql << '[]'
518
- end
519
252
 
520
- column = options.fetch(:column) { return super }
521
- if column.type == :uuid && options[:default] =~ /\(\)/
522
- sql << " DEFAULT #{options[:default]}"
523
- else
524
- super
525
- end
526
- end if AR4_COMPAT
527
-
253
+ if ActiveRecord::VERSION::MAJOR > 3
254
+
255
+ require 'arjdbc/postgresql/schema_creation'
256
+ def schema_creation; SchemaCreation.new(self); end
257
+
258
+ end
259
+
528
260
  # Enable standard-conforming strings if available.
529
- def set_standard_conforming_strings # native adapter API compatibility
261
+ def set_standard_conforming_strings
530
262
  self.standard_conforming_strings=(true)
531
263
  end
532
-
264
+
533
265
  # Enable standard-conforming strings if available.
534
266
  def standard_conforming_strings=(enable)
535
267
  client_min_messages = self.client_min_messages
@@ -545,7 +277,7 @@ module ArJdbc
545
277
  end
546
278
  end
547
279
 
548
- def standard_conforming_strings? # :nodoc:
280
+ def standard_conforming_strings?
549
281
  if @standard_conforming_strings.nil?
550
282
  client_min_messages = self.client_min_messages
551
283
  begin
@@ -562,38 +294,38 @@ module ArJdbc
562
294
  end
563
295
 
564
296
  # Does PostgreSQL support migrations?
565
- def supports_migrations? # :nodoc:
297
+ def supports_migrations?
566
298
  true
567
299
  end
568
300
 
569
301
  # Does PostgreSQL support finding primary key on non-Active Record tables?
570
- def supports_primary_key? # :nodoc:
302
+ def supports_primary_key?
571
303
  true
572
304
  end
573
-
305
+
574
306
  # Does PostgreSQL support standard conforming strings?
575
- def supports_standard_conforming_strings? # :nodoc:
307
+ def supports_standard_conforming_strings?
576
308
  standard_conforming_strings?
577
309
  @standard_conforming_strings != :unsupported
578
310
  end
579
311
 
580
- def supports_hex_escaped_bytea? # :nodoc:
312
+ def supports_hex_escaped_bytea?
581
313
  postgresql_version >= 90000
582
314
  end
583
315
 
584
- def supports_insert_with_returning? # :nodoc:
316
+ def supports_insert_with_returning?
585
317
  postgresql_version >= 80200
586
318
  end
587
319
 
588
- def supports_ddl_transactions? # :nodoc:
320
+ def supports_ddl_transactions?
589
321
  true
590
322
  end
591
323
 
592
- def supports_transaction_isolation? # :nodoc:
324
+ def supports_transaction_isolation?
593
325
  true
594
326
  end
595
-
596
- def supports_index_sort_order? # :nodoc:
327
+
328
+ def supports_index_sort_order?
597
329
  true
598
330
  end
599
331
 
@@ -601,39 +333,41 @@ module ArJdbc
601
333
  true
602
334
  end if AR4_COMPAT
603
335
 
604
- # Range datatypes weren't introduced until PostgreSQL 9.2
605
- def supports_ranges? # :nodoc:
336
+ # Range data-types weren't introduced until PostgreSQL 9.2.
337
+ def supports_ranges?
606
338
  postgresql_version >= 90200
607
339
  end if AR4_COMPAT
608
-
609
- def supports_savepoints? # :nodoc:
610
- true
611
- end
612
-
340
+
613
341
  def supports_transaction_isolation?(level = nil)
614
342
  true
615
343
  end
616
344
 
617
- def index_algorithms
618
- { :concurrently => 'CONCURRENTLY' }
345
+ # NOTE: handled by JdbcAdapter we override only to have save-point in logs :
346
+
347
+ # @override
348
+ def supports_savepoints?
349
+ true
619
350
  end
620
351
 
621
- def create_savepoint
622
- execute("SAVEPOINT #{current_savepoint_name}")
352
+ # @override
353
+ def create_savepoint(name = current_savepoint_name(true))
354
+ log("SAVEPOINT #{name}", 'Savepoint') { super }
623
355
  end
624
356
 
625
- def rollback_to_savepoint
626
- execute("ROLLBACK TO SAVEPOINT #{current_savepoint_name}")
357
+ # @override
358
+ def rollback_to_savepoint(name = current_savepoint_name)
359
+ log("ROLLBACK TO SAVEPOINT #{name}", 'Savepoint') { super }
627
360
  end
628
361
 
629
- def release_savepoint
630
- execute("RELEASE SAVEPOINT #{current_savepoint_name}")
362
+ # @override
363
+ def release_savepoint(name = current_savepoint_name)
364
+ log("RELEASE SAVEPOINT #{name}", 'Savepoint') { super }
631
365
  end
632
-
633
- def supports_extensions? # :nodoc:
366
+
367
+ def supports_extensions?
634
368
  postgresql_version >= 90200
635
369
  end # NOTE: only since AR-4.0 but should not hurt on other versions
636
-
370
+
637
371
  def enable_extension(name)
638
372
  execute("CREATE EXTENSION IF NOT EXISTS \"#{name}\"")
639
373
  end
@@ -657,18 +391,22 @@ module ArJdbc
657
391
  []
658
392
  end
659
393
  end
660
-
661
- # Set the authorized user for this session
394
+
395
+ def index_algorithms
396
+ { :concurrently => 'CONCURRENTLY' }
397
+ end
398
+
399
+ # Set the authorized user for this session.
662
400
  def session_auth=(user)
663
401
  execute "SET SESSION AUTHORIZATION #{user}"
664
402
  end
665
-
403
+
666
404
  # Returns the configured supported identifier length supported by PostgreSQL,
667
405
  # or report the default of 63 on PostgreSQL 7.x.
668
406
  def table_alias_length
669
407
  @table_alias_length ||= (
670
- postgresql_version >= 80000 ?
671
- select_one('SHOW max_identifier_length')['max_identifier_length'].to_i :
408
+ postgresql_version >= 80000 ?
409
+ select_one('SHOW max_identifier_length')['max_identifier_length'].to_i :
672
410
  63
673
411
  )
674
412
  end
@@ -678,8 +416,8 @@ module ArJdbc
678
416
  default_seq || "#{table_name}_#{pk || default_pk || 'id'}_seq"
679
417
  end
680
418
 
681
- # Resets sequence to the max value of the table's pk if present.
682
- def reset_pk_sequence!(table, pk = nil, sequence = nil) #:nodoc:
419
+ # Resets sequence to the max value of the table's primary key if present.
420
+ def reset_pk_sequence!(table, pk = nil, sequence = nil)
683
421
  if ! pk || ! sequence
684
422
  default_pk, default_sequence = pk_and_sequence_for(table)
685
423
  pk ||= default_pk; sequence ||= default_sequence
@@ -694,15 +432,13 @@ module ArJdbc
694
432
  end
695
433
 
696
434
  # Find a table's primary key and sequence.
697
- def pk_and_sequence_for(table) #:nodoc:
698
- # First try looking for a sequence with a dependency on the
699
- # given table's primary key.
435
+ def pk_and_sequence_for(table)
436
+ # try looking for a seq with a dependency on the table's primary key :
700
437
  result = select(<<-end_sql, 'PK and Serial Sequence')[0]
701
438
  SELECT attr.attname, seq.relname
702
439
  FROM pg_class seq,
703
440
  pg_attribute attr,
704
441
  pg_depend dep,
705
- pg_namespace name,
706
442
  pg_constraint cons
707
443
  WHERE seq.oid = dep.objid
708
444
  AND seq.relkind = 'S'
@@ -715,16 +451,15 @@ module ArJdbc
715
451
  end_sql
716
452
 
717
453
  if result.nil? || result.empty?
718
- # If that fails, try parsing the primary key's default value.
719
- # Support the 7.x and 8.0 nextval('foo'::text) as well as
720
- # the 8.1+ nextval('foo'::regclass).
454
+ # if that fails, try parsing the primary key's default value :
721
455
  result = select(<<-end_sql, 'PK and Custom Sequence')[0]
722
456
  SELECT attr.attname,
723
457
  CASE
724
- WHEN split_part(def.adsrc, '''', 2) ~ '.' THEN
725
- substr(split_part(def.adsrc, '''', 2),
726
- strpos(split_part(def.adsrc, '''', 2), '.')+1)
727
- ELSE split_part(def.adsrc, '''', 2)
458
+ WHEN pg_get_expr(def.adbin, def.adrelid) !~* 'nextval' THEN NULL
459
+ WHEN split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2) ~ '.' THEN
460
+ substr(split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2),
461
+ strpos(split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2), '.')+1)
462
+ ELSE split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2)
728
463
  END as relname
729
464
  FROM pg_class t
730
465
  JOIN pg_attribute attr ON (t.oid = attrelid)
@@ -732,7 +467,7 @@ module ArJdbc
732
467
  JOIN pg_constraint cons ON (conrelid = adrelid AND adnum = conkey[1])
733
468
  WHERE t.oid = '#{quote_table_name(table)}'::regclass
734
469
  AND cons.contype = 'p'
735
- AND def.adsrc ~* 'nextval'
470
+ AND pg_get_expr(def.adbin, def.adrelid) ~* 'nextval|uuid_generate'
736
471
  end_sql
737
472
  end
738
473
 
@@ -740,7 +475,21 @@ module ArJdbc
740
475
  rescue
741
476
  nil
742
477
  end
743
-
478
+
479
+ def primary_key(table)
480
+ result = select(<<-end_sql, 'SCHEMA').first
481
+ SELECT attr.attname
482
+ FROM pg_attribute attr
483
+ INNER JOIN pg_constraint cons ON attr.attrelid = cons.conrelid AND attr.attnum = cons.conkey[1]
484
+ WHERE cons.contype = 'p'
485
+ AND cons.conrelid = '#{quote_table_name(table)}'::regclass
486
+ end_sql
487
+
488
+ result && result['attname']
489
+ # pk_and_sequence = pk_and_sequence_for(table)
490
+ # pk_and_sequence && pk_and_sequence.first
491
+ end
492
+
744
493
  def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
745
494
  unless pk
746
495
  # Extract the table from the insert sql. Yuck.
@@ -767,52 +516,66 @@ module ArJdbc
767
516
  id_value
768
517
  end
769
518
  end
770
-
771
- # taken from rails postgresql_adapter.rb
519
+
520
+ # @override
772
521
  def sql_for_insert(sql, pk, id_value, sequence_name, binds)
773
522
  unless pk
523
+ # Extract the table from the insert sql. Yuck.
774
524
  table_ref = extract_table_ref_from_insert_sql(sql)
775
525
  pk = primary_key(table_ref) if table_ref
776
526
  end
777
527
 
778
- sql = "#{sql} RETURNING #{quote_column_name(pk)}" if pk
528
+ if pk && use_insert_returning?
529
+ sql = "#{sql} RETURNING #{quote_column_name(pk)}"
530
+ end
779
531
 
780
532
  [ sql, binds ]
781
533
  end
782
-
783
- def primary_key(table)
784
- result = select(<<-end_sql, 'SCHEMA').first
785
- SELECT attr.attname
786
- FROM pg_attribute attr
787
- INNER JOIN pg_constraint cons ON attr.attrelid = cons.conrelid AND attr.attnum = cons.conkey[1]
788
- WHERE cons.contype = 'p'
789
- AND cons.conrelid = '#{quote_table_name(table)}'::regclass
790
- end_sql
791
-
792
- result && result["attname"]
793
- # pk_and_sequence = pk_and_sequence_for(table)
794
- # pk_and_sequence && pk_and_sequence.first
534
+
535
+ # @override due RETURNING clause
536
+ def exec_insert(sql, name, binds, pk = nil, sequence_name = nil)
537
+ # NOTE: 3.2 does not pass the PK on #insert (passed only into #sql_for_insert) :
538
+ # sql, binds = sql_for_insert(to_sql(arel, binds), pk, id_value, sequence_name, binds)
539
+ # 3.2 :
540
+ # value = exec_insert(sql, name, binds)
541
+ # 4.x :
542
+ # value = exec_insert(sql, name, binds, pk, sequence_name)
543
+ if use_insert_returning? && ( pk || (sql.is_a?(String) && sql =~ /RETURNING "?\S+"?$/) )
544
+ exec_query(sql, name, binds) # due RETURNING clause returns a result set
545
+ else
546
+ result = super
547
+ if pk
548
+ unless sequence_name
549
+ table_ref = extract_table_ref_from_insert_sql(sql)
550
+ sequence_name = default_sequence_name(table_ref, pk)
551
+ return result unless sequence_name
552
+ end
553
+ last_insert_id_result(sequence_name)
554
+ else
555
+ result
556
+ end
557
+ end
795
558
  end
796
-
559
+
797
560
  # Returns an array of schema names.
798
561
  def schema_names
799
562
  select_values(
800
563
  "SELECT nspname FROM pg_namespace" <<
801
564
  " WHERE nspname !~ '^pg_.*' AND nspname NOT IN ('information_schema')" <<
802
- " ORDER by nspname;",
565
+ " ORDER by nspname;",
803
566
  'SCHEMA')
804
567
  end
805
-
568
+
806
569
  # Returns true if schema exists.
807
570
  def schema_exists?(name)
808
571
  select_value("SELECT COUNT(*) FROM pg_namespace WHERE nspname = '#{name}'", 'SCHEMA').to_i > 0
809
572
  end
810
-
573
+
811
574
  # Returns the current schema name.
812
575
  def current_schema
813
576
  select_value('SELECT current_schema', 'SCHEMA')
814
577
  end
815
-
578
+
816
579
  # current database name
817
580
  def current_database
818
581
  select_value('SELECT current_database()', 'SCHEMA')
@@ -821,21 +584,21 @@ module ArJdbc
821
584
  # Returns the current database encoding format.
822
585
  def encoding
823
586
  select_value(
824
- "SELECT pg_encoding_to_char(pg_database.encoding)" <<
825
- " FROM pg_database" <<
826
- " WHERE pg_database.datname LIKE '#{current_database}'",
587
+ "SELECT pg_encoding_to_char(pg_database.encoding)" <<
588
+ " FROM pg_database" <<
589
+ " WHERE pg_database.datname LIKE '#{current_database}'",
827
590
  'SCHEMA')
828
591
  end
829
592
 
830
593
  # Returns the current database collation.
831
594
  def collation
832
595
  select_value(
833
- "SELECT pg_database.datcollate" <<
834
- " FROM pg_database" <<
596
+ "SELECT pg_database.datcollate" <<
597
+ " FROM pg_database" <<
835
598
  " WHERE pg_database.datname LIKE '#{current_database}'",
836
599
  'SCHEMA')
837
600
  end
838
-
601
+
839
602
  # Returns the current database ctype.
840
603
  def ctype
841
604
  select_value(
@@ -847,7 +610,7 @@ module ArJdbc
847
610
  def schema_search_path
848
611
  @schema_search_path ||= select_value('SHOW search_path', 'SCHEMA')
849
612
  end
850
-
613
+
851
614
  # Sets the schema search path to a string of comma-separated schema names.
852
615
  # Names beginning with $ have to be quoted (e.g. $user => '$user').
853
616
  # See: http://www.postgresql.org/docs/current/static/ddl-schemas.html
@@ -860,25 +623,26 @@ module ArJdbc
860
623
  end
861
624
  end
862
625
 
863
- # take id from result of insert query
626
+ # Take an id from the result of an INSERT query.
627
+ # @return [Integer, NilClass]
864
628
  def last_inserted_id(result)
865
- if result.is_a? Integer
866
- result
867
- else
868
- result.first.first[1]
869
- end
629
+ return nil if result.nil?
630
+ return result if result.is_a? Integer
631
+ # <ActiveRecord::Result @hash_rows=nil, @columns=["id"], @rows=[[3]]>
632
+ # but it will work with [{ 'id' => 1 }] Hash wrapped results as well
633
+ result.first.first[1] # .first = { "id"=>1 } .first = [ "id", 1 ]
870
634
  end
871
635
 
872
636
  def last_insert_id(table, sequence_name = nil)
873
637
  sequence_name = table if sequence_name.nil? # AR-4.0 1 argument
874
638
  Integer(select_value("SELECT currval('#{sequence_name}')", 'SQL'))
875
639
  end
876
-
640
+
877
641
  def recreate_database(name, options = {})
878
642
  drop_database(name)
879
643
  create_database(name, options)
880
644
  end
881
-
645
+
882
646
  # Create a new PostgreSQL database. Options include <tt>:owner</tt>, <tt>:template</tt>,
883
647
  # <tt>:encoding</tt>, <tt>:collation</tt>, <tt>:ctype</tt>,
884
648
  # <tt>:tablespace</tt>, and <tt>:connection_limit</tt> (note that MySQL uses
@@ -936,6 +700,7 @@ module ArJdbc
936
700
  select('SELECT nspname FROM pg_namespace').map { |row| row["nspname"] }
937
701
  end
938
702
 
703
+ # @deprecated no longer used - handled with (AR built-in) Rake tasks
939
704
  def structure_dump
940
705
  database = @config[:database]
941
706
  if database.nil?
@@ -977,35 +742,42 @@ module ArJdbc
977
742
  def multi_column_index_limit
978
743
  defined?(@multi_column_index_limit) && @multi_column_index_limit || 32
979
744
  end
980
-
745
+
981
746
  # Sets the maximum number columns postgres has, default 32
982
747
  def multi_column_index_limit=(limit)
983
748
  @multi_column_index_limit = limit
984
749
  end
985
-
986
- # SELECT DISTINCT clause for a given set of columns and a given ORDER BY clause.
750
+
751
+ # Returns a SELECT DISTINCT clause for a given set of columns and a given
752
+ # ORDER BY clause.
987
753
  #
988
- # PostgreSQL requires the ORDER BY columns in the select list for distinct queries, and
989
- # requires that the ORDER BY include the distinct column.
754
+ # PostgreSQL requires the ORDER BY columns in the select list for distinct
755
+ # queries, and requires that the ORDER BY include the distinct column.
990
756
  #
991
- # distinct("posts.id", "posts.created_at desc")
992
- def distinct(columns, orders) #:nodoc:
993
- return "DISTINCT #{columns}" if orders.empty?
757
+ # distinct("posts.id", ["posts.created_at desc"])
758
+ # # => "DISTINCT posts.id, posts.created_at AS alias_0"
759
+ def distinct(columns, orders)
760
+ if orders.is_a?(String)
761
+ orders = orders.split(','); orders.each(&:strip!)
762
+ end
763
+
764
+ order_columns = orders.map do |column|
765
+ column = column.to_sql unless column.is_a?(String) # handle AREL node
766
+ column.gsub(/\s+(ASC|DESC)\s*(NULLS\s+(FIRST|LAST)\s*)?/i, '') # remove ASC/DESC
767
+ end.reject(&:blank?)
994
768
 
995
- # Construct a clean list of column names from the ORDER BY clause, removing
996
- # any ASC/DESC modifiers
997
- order_columns = orders.collect { |s| s.gsub(/\s+(ASC|DESC)\s*/i, '') }.
998
- reject(&:blank?)
999
- order_columns = order_columns.
1000
- zip((0...order_columns.size).to_a).map { |s,i| "#{s} AS alias_#{i}" }
769
+ return "DISTINCT #{columns}" if order_columns.empty?
1001
770
 
1002
- "DISTINCT #{columns}, #{order_columns * ', '}"
771
+ i = -1; order_columns.map! { |c| "#{c} AS alias_#{i += 1}" }
772
+
773
+ "DISTINCT #{columns}, #{order_columns.join(', ')}"
1003
774
  end
1004
775
 
1005
776
  # ORDER BY clause for the passed order option.
1006
777
  #
1007
- # PostgreSQL does not allow arbitrary ordering when using DISTINCT ON, so we work around this
1008
- # by wrapping the sql as a sub-select and ordering in that query.
778
+ # PostgreSQL does not allow arbitrary ordering when using DISTINCT ON,
779
+ # so we work around this by wrapping the SQL as a sub-select and ordering
780
+ # in that query.
1009
781
  def add_order_by_for_association_limiting!(sql, options)
1010
782
  return sql if options[:order].blank?
1011
783
 
@@ -1016,9 +788,11 @@ module ArJdbc
1016
788
  sql.replace "SELECT * FROM (#{sql}) AS id_list ORDER BY #{order}"
1017
789
  end
1018
790
 
1019
- def quote(value, column = nil) # :nodoc:
791
+ # @return [String]
792
+ # @override
793
+ def quote(value, column = nil)
1020
794
  return super unless column
1021
-
795
+
1022
796
  case value
1023
797
  when Float
1024
798
  if value.infinite? && ( column.type == :datetime || column.type == :timestamp )
@@ -1037,22 +811,13 @@ module ArJdbc
1037
811
  return "E'#{escape_bytea(value)}'::bytea" if column.type == :binary
1038
812
  return "xml '#{quote_string(value)}'" if column.type == :xml
1039
813
  if column.respond_to?(:sql_type) && column.sql_type[0, 3] == 'bit'
1040
- case value
1041
- # NOTE: as reported with #60 this is not quite "right" :
1042
- # "0103" will be treated as hexadecimal string
1043
- # "0102" will be treated as hexadecimal string
1044
- # "0101" will be treated as binary string
1045
- # "0100" will be treated as binary string
1046
- # ... but is kept due Rails compatibility
1047
- when /^[01]*$/ then "B'#{value}'" # Bit-string notation
1048
- when /^[0-9A-F]*$/i then "X'#{value}'" # Hexadecimal notation
1049
- end
814
+ quote_bit(value)
1050
815
  else super
1051
816
  end
1052
817
  when Array
1053
818
  if AR4_COMPAT && column.array? # will be always falsy in AR < 4.0
1054
819
  column_class = ::ActiveRecord::ConnectionAdapters::PostgreSQLColumn
1055
- "'#{column_class.array_to_string(value, column, self)}'"
820
+ "'#{column_class.array_to_string(value, column, self).gsub(/'/, "''")}'"
1056
821
  else super
1057
822
  end
1058
823
  when Hash
@@ -1081,8 +846,9 @@ module ArJdbc
1081
846
  end
1082
847
  end
1083
848
 
1084
- # Quotes a string, escaping any ' (single quote) and \ (backslash)
1085
- # characters.
849
+ # Quotes a string, escaping any ' (single quote) and \ (backslash) chars.
850
+ # @return [String]
851
+ # @override
1086
852
  def quote_string(string)
1087
853
  quoted = string.gsub("'", "''")
1088
854
  unless standard_conforming_strings?
@@ -1091,6 +857,24 @@ module ArJdbc
1091
857
  quoted
1092
858
  end
1093
859
 
860
+ # @return [String]
861
+ def quote_bit(value)
862
+ case value
863
+ # NOTE: as reported with #60 this is not quite "right" :
864
+ # "0103" will be treated as hexadecimal string
865
+ # "0102" will be treated as hexadecimal string
866
+ # "0101" will be treated as binary string
867
+ # "0100" will be treated as binary string
868
+ # ... but is kept due Rails compatibility
869
+ when /^[01]*$/ then "B'#{value}'" # Bit-string notation
870
+ when /^[0-9A-F]*$/i then "X'#{value}'" # Hexadecimal notation
871
+ end
872
+ end
873
+
874
+ def quote_bit(value)
875
+ "B'#{value}'"
876
+ end if PostgreSQL::AR4_COMPAT
877
+
1094
878
  def escape_bytea(string)
1095
879
  if string
1096
880
  if supports_hex_escaped_bytea?
@@ -1102,10 +886,11 @@ module ArJdbc
1102
886
  end
1103
887
  end
1104
888
  end
1105
-
889
+
890
+ # @override
1106
891
  def quote_table_name(name)
1107
892
  schema, name_part = extract_pg_identifier_from_name(name.to_s)
1108
-
893
+
1109
894
  unless name_part
1110
895
  quote_column_name(schema)
1111
896
  else
@@ -1114,30 +899,34 @@ module ArJdbc
1114
899
  end
1115
900
  end
1116
901
 
902
+ # @override
1117
903
  def quote_table_name_for_assignment(table, attr)
1118
904
  quote_column_name(attr)
1119
905
  end if ::ActiveRecord::VERSION::MAJOR > 3
1120
906
 
907
+ # @override
1121
908
  def quote_column_name(name)
1122
909
  %("#{name.to_s.gsub("\"", "\"\"")}")
1123
910
  end
1124
-
1125
- # Quote date/time values for use in SQL input.
1126
- # Includes microseconds if the value is a Time responding to usec.
1127
- def quoted_date(value) #:nodoc:
911
+
912
+ # Quote date/time values for use in SQL input.
913
+ # Includes microseconds if the value is a Time responding to `usec`.
914
+ # @override
915
+ def quoted_date(value)
1128
916
  result = super
1129
917
  if value.acts_like?(:time) && value.respond_to?(:usec)
1130
- "#{result}.#{sprintf("%06d", value.usec)}"
918
+ result = "#{result}.#{sprintf("%06d", value.usec)}"
1131
919
  end
1132
920
  result = "#{result.sub(/^-/, '')} BC" if value.year < 0
1133
921
  result
1134
- end
1135
-
1136
- def supports_disable_referential_integrity? # :nodoc:
922
+ end if ::ActiveRecord::VERSION::MAJOR >= 3
923
+
924
+ # @override
925
+ def supports_disable_referential_integrity?
1137
926
  true
1138
927
  end
1139
928
 
1140
- def disable_referential_integrity # :nodoc:
929
+ def disable_referential_integrity
1141
930
  if supports_disable_referential_integrity?
1142
931
  begin
1143
932
  execute(tables.collect { |name| "ALTER TABLE #{quote_table_name(name)} DISABLE TRIGGER ALL" }.join(";"))
@@ -1165,15 +954,18 @@ module ArJdbc
1165
954
  end
1166
955
  rename_table_indexes(table_name, new_name) if respond_to?(:rename_table_indexes) # AR-4.0 SchemaStatements
1167
956
  end
1168
-
957
+
1169
958
  # Adds a new column to the named table.
1170
959
  # See TableDefinition#column for details of the options you can use.
1171
960
  def add_column(table_name, column_name, type, options = {})
1172
961
  default = options[:default]
1173
962
  notnull = options[:null] == false
1174
963
 
964
+ sql_type = type_to_sql(type, options[:limit], options[:precision], options[:scale])
965
+ sql_type << "[]" if options[:array]
966
+
1175
967
  # Add the column.
1176
- execute("ALTER TABLE #{quote_table_name(table_name)} ADD COLUMN #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}")
968
+ execute("ALTER TABLE #{quote_table_name(table_name)} ADD COLUMN #{quote_column_name(column_name)} #{sql_type}")
1177
969
 
1178
970
  change_column_default(table_name, column_name, default) if options_include_default?(options)
1179
971
  change_column_null(table_name, column_name, false, default) if notnull
@@ -1183,8 +975,11 @@ module ArJdbc
1183
975
  def change_column(table_name, column_name, type, options = {})
1184
976
  quoted_table_name = quote_table_name(table_name)
1185
977
 
978
+ sql_type = type_to_sql(type, options[:limit], options[:precision], options[:scale])
979
+ sql_type << "[]" if options[:array]
980
+
1186
981
  begin
1187
- execute "ALTER TABLE #{quoted_table_name} ALTER COLUMN #{quote_column_name(column_name)} TYPE #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
982
+ execute "ALTER TABLE #{quoted_table_name} ALTER COLUMN #{quote_column_name(column_name)} TYPE #{sql_type}"
1188
983
  rescue ActiveRecord::StatementInvalid => e
1189
984
  raise e if postgresql_version > 80000
1190
985
  # This is PostgreSQL 7.x, so we have to use a more arcane way of doing it.
@@ -1192,7 +987,7 @@ module ArJdbc
1192
987
  begin_db_transaction
1193
988
  tmp_column_name = "#{column_name}_ar_tmp"
1194
989
  add_column(table_name, tmp_column_name, type, options)
1195
- execute "UPDATE #{quoted_table_name} SET #{quote_column_name(tmp_column_name)} = CAST(#{quote_column_name(column_name)} AS #{type_to_sql(type, options[:limit], options[:precision], options[:scale])})"
990
+ execute "UPDATE #{quoted_table_name} SET #{quote_column_name(tmp_column_name)} = CAST(#{quote_column_name(column_name)} AS #{sql_type})"
1196
991
  remove_column(table_name, column_name)
1197
992
  rename_column(table_name, tmp_column_name, column_name)
1198
993
  commit_db_transaction
@@ -1217,17 +1012,17 @@ module ArJdbc
1217
1012
  execute("ALTER TABLE #{quote_table_name(table_name)} ALTER #{quote_column_name(column_name)} #{null ? 'DROP' : 'SET'} NOT NULL")
1218
1013
  end
1219
1014
 
1220
- def rename_column(table_name, column_name, new_column_name) # :nodoc:
1015
+ def rename_column(table_name, column_name, new_column_name)
1221
1016
  execute "ALTER TABLE #{quote_table_name(table_name)} RENAME COLUMN #{quote_column_name(column_name)} TO #{quote_column_name(new_column_name)}"
1222
1017
  rename_column_indexes(table_name, column_name, new_column_name) if respond_to?(:rename_column_indexes) # AR-4.0 SchemaStatements
1223
1018
  end
1224
1019
 
1225
- def add_index(table_name, column_name, options = {}) # :nodoc:
1020
+ def add_index(table_name, column_name, options = {})
1226
1021
  index_name, index_type, index_columns, index_options, index_algorithm, index_using = add_index_options(table_name, column_name, options)
1227
1022
  execute "CREATE #{index_type} INDEX #{index_algorithm} #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} #{index_using} (#{index_columns})#{index_options}"
1228
1023
  end if AR4_COMPAT
1229
1024
 
1230
- def remove_index!(table_name, index_name) # :nodoc:
1025
+ def remove_index!(table_name, index_name)
1231
1026
  execute "DROP INDEX #{quote_table_name(index_name)}"
1232
1027
  end
1233
1028
 
@@ -1254,7 +1049,7 @@ module ArJdbc
1254
1049
  klass.new(name, default, oid, type, ! notnull)
1255
1050
  end
1256
1051
  end
1257
-
1052
+
1258
1053
  # Returns the list of a table's column names, data types, and default values.
1259
1054
  #
1260
1055
  # If the table name is not prefixed with a schema, the database will
@@ -1263,7 +1058,7 @@ module ArJdbc
1263
1058
  # Query implementation notes:
1264
1059
  # - format_type includes the column size constraint, e.g. varchar(50)
1265
1060
  # - ::regclass is a function that gives the id for a table name
1266
- def column_definitions(table_name) #:nodoc:
1061
+ def column_definitions(table_name)
1267
1062
  select_rows(<<-end_sql, 'SCHEMA')
1268
1063
  SELECT a.attname, format_type(a.atttypid, a.atttypmod),
1269
1064
  pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod
@@ -1275,7 +1070,7 @@ module ArJdbc
1275
1070
  end_sql
1276
1071
  end
1277
1072
  private :column_definitions
1278
-
1073
+
1279
1074
  def tables(name = nil)
1280
1075
  select_values(<<-SQL, 'SCHEMA')
1281
1076
  SELECT tablename
@@ -1290,7 +1085,7 @@ module ArJdbc
1290
1085
 
1291
1086
  binds = [[ nil, table.gsub(/(^"|"$)/,'') ]]
1292
1087
  binds << [ nil, schema ] if schema
1293
-
1088
+
1294
1089
  exec_query_raw(<<-SQL, 'SCHEMA', binds).first["table_count"] > 0
1295
1090
  SELECT COUNT(*) as table_count
1296
1091
  FROM pg_tables
@@ -1298,9 +1093,10 @@ module ArJdbc
1298
1093
  AND schemaname = #{schema ? "?" : "ANY (current_schemas(false))"}
1299
1094
  SQL
1300
1095
  end
1301
-
1302
- IndexDefinition = ::ActiveRecord::ConnectionAdapters::IndexDefinition # :nodoc:
1303
- if ActiveRecord::VERSION::MAJOR < 3 ||
1096
+
1097
+ # @private
1098
+ IndexDefinition = ::ActiveRecord::ConnectionAdapters::IndexDefinition
1099
+ if ActiveRecord::VERSION::MAJOR < 3 ||
1304
1100
  ( ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR <= 1 )
1305
1101
  # NOTE: make sure we accept 6 arguments (>= 3.2) as well as 5 (<= 3.1) :
1306
1102
  # allow 6 on 3.1 : Struct.new(:table, :name, :unique, :columns, :lengths)
@@ -1310,7 +1106,7 @@ module ArJdbc
1310
1106
  end
1311
1107
  end
1312
1108
  end
1313
-
1109
+
1314
1110
  # Returns an array of indexes for the given table.
1315
1111
  def indexes(table_name, name = nil)
1316
1112
  # NOTE: maybe it's better to leave things of to the JDBC API ?!
@@ -1325,7 +1121,7 @@ module ArJdbc
1325
1121
  AND i.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname = ANY (current_schemas(false)) )
1326
1122
  ORDER BY i.relname
1327
1123
  SQL
1328
-
1124
+
1329
1125
  result.map! do |row|
1330
1126
  index_name = row[0]
1331
1127
  unique = row[1].is_a?(String) ? row[1] == 't' : row[1] # JDBC gets us a boolean
@@ -1363,13 +1159,8 @@ module ArJdbc
1363
1159
  result
1364
1160
  end
1365
1161
 
1366
- # #override due RETURNING clause - can't do an {#execute_insert}
1367
- def exec_insert(sql, name, binds, pk = nil, sequence_name = nil) # :nodoc:
1368
- execute(sql, name, binds)
1369
- end
1370
-
1371
1162
  private
1372
-
1163
+
1373
1164
  def translate_exception(exception, message)
1374
1165
  case exception.message
1375
1166
  when /duplicate key value violates unique constraint/
@@ -1380,7 +1171,7 @@ module ArJdbc
1380
1171
  super
1381
1172
  end
1382
1173
  end
1383
-
1174
+
1384
1175
  # Extracts the table and schema name from +name+
1385
1176
  def extract_schema_and_table(name)
1386
1177
  schema, table = name.split('.', 2)
@@ -1407,34 +1198,27 @@ module ArJdbc
1407
1198
  end
1408
1199
  end
1409
1200
 
1410
- # taken from rails postgresql_adapter.rb
1411
- def extract_table_ref_from_insert_sql(sql) # :nodoc:
1201
+ def extract_table_ref_from_insert_sql(sql)
1412
1202
  sql[/into\s+([^\(]*).*values\s*\(/i]
1413
1203
  $1.strip if $1
1414
- # sql.split(" ", 4)[2].gsub('"', '')
1415
1204
  end
1416
-
1205
+
1206
+ def local_tz
1207
+ @local_tz ||= execute('SHOW TIME ZONE', 'SCHEMA').first["TimeZone"]
1208
+ end
1209
+
1417
1210
  end
1418
1211
  end
1419
1212
 
1213
+ require 'arjdbc/util/quoted_cache'
1214
+
1420
1215
  module ActiveRecord::ConnectionAdapters
1421
-
1422
- PostgreSQLJdbcConnection.class_eval do
1423
-
1424
- # alias :java_native_database_types :set_native_database_types
1425
-
1426
- # @override to prevent connection from loading hash from JDBC meta-data,
1427
- # which can be expensive. We can do this since {#native_database_types} is
1428
- # defined in the adapter to use a hash not relying on driver's meta-data
1429
- def set_native_database_types; @native_types = {}; end
1430
-
1431
- end
1432
-
1216
+
1433
1217
  remove_const(:PostgreSQLColumn) if const_defined?(:PostgreSQLColumn)
1434
1218
 
1435
1219
  class PostgreSQLColumn < JdbcColumn
1436
- include ArJdbc::PostgreSQL::Column
1437
-
1220
+ include ::ArJdbc::PostgreSQL::Column
1221
+
1438
1222
  def initialize(name, default, oid_type = nil, sql_type = nil, null = true)
1439
1223
  # NOTE: we support AR <= 3.2 : (name, default, sql_type = nil, null = true)
1440
1224
  null, sql_type, oid_type = !! sql_type, oid_type, nil unless oid_type.is_a?(Integer)
@@ -1447,26 +1231,25 @@ module ActiveRecord::ConnectionAdapters
1447
1231
  super(name, default, sql_type, null)
1448
1232
  end
1449
1233
  end
1450
-
1234
+
1451
1235
  end
1452
1236
 
1453
1237
  remove_const(:PostgreSQLAdapter) if const_defined?(:PostgreSQLAdapter)
1454
-
1238
+
1455
1239
  class PostgreSQLAdapter < JdbcAdapter
1456
- include ArJdbc::PostgreSQL
1457
- include ArJdbc::PostgreSQL::ExplainSupport
1458
-
1240
+ include ::ArJdbc::PostgreSQL
1241
+ include ::ArJdbc::PostgreSQL::ExplainSupport
1242
+ include ::ArJdbc::Util::QuotedCache
1243
+
1459
1244
  def initialize(*args)
1460
- super
1461
-
1462
1245
  # @local_tz is initialized as nil to avoid warnings when connect tries to use it
1463
1246
  @local_tz = nil
1247
+
1248
+ super # configure_connection happens in super
1249
+
1464
1250
  @table_alias_length = nil
1465
-
1466
- # configure_connection happens in super
1467
1251
 
1468
- @local_tz = execute('SHOW TIME ZONE', 'SCHEMA').first["TimeZone"]
1469
- @use_insert_returning = config.key?(:insert_returning) ?
1252
+ @use_insert_returning = config.key?(:insert_returning) ?
1470
1253
  self.class.type_cast_config_to_boolean(config[:insert_returning]) : nil
1471
1254
  end
1472
1255
 
@@ -1540,14 +1323,14 @@ module ActiveRecord::ConnectionAdapters
1540
1323
 
1541
1324
  class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
1542
1325
  include ColumnMethods
1543
-
1326
+
1544
1327
  def primary_key(name, type = :primary_key, options = {})
1545
1328
  return super unless type == :uuid
1546
1329
  options[:default] ||= 'uuid_generate_v4()'
1547
1330
  options[:primary_key] = true
1548
1331
  column name, type, options
1549
1332
  end if ActiveRecord::VERSION::MAJOR > 3 # 3.2 super expects (name)
1550
-
1333
+
1551
1334
  def column(name, type = nil, options = {})
1552
1335
  super
1553
1336
  column = self[name]
@@ -1561,28 +1344,28 @@ module ActiveRecord::ConnectionAdapters
1561
1344
  private
1562
1345
 
1563
1346
  if ActiveRecord::VERSION::MAJOR > 3
1564
-
1347
+
1565
1348
  def create_column_definition(name, type)
1566
1349
  ColumnDefinition.new name, type
1567
1350
  end
1568
-
1351
+
1569
1352
  else # no #create_column_definition on 3.2
1570
-
1353
+
1571
1354
  def new_column_definition(base, name, type)
1572
1355
  definition = ColumnDefinition.new base, name, type
1573
1356
  @columns << definition
1574
1357
  @columns_hash[name] = definition
1575
1358
  definition
1576
1359
  end
1577
-
1360
+
1578
1361
  end
1579
-
1362
+
1580
1363
  end
1581
1364
 
1582
1365
  def table_definition(*args)
1583
1366
  new_table_definition(TableDefinition, *args)
1584
1367
  end
1585
-
1368
+
1586
1369
  class Table < ActiveRecord::ConnectionAdapters::Table
1587
1370
  include ColumnMethods
1588
1371
  end
@@ -1590,36 +1373,15 @@ module ActiveRecord::ConnectionAdapters
1590
1373
  def update_table_definition(table_name, base)
1591
1374
  Table.new(table_name, base)
1592
1375
  end if ActiveRecord::VERSION::MAJOR > 3
1593
-
1376
+
1594
1377
  def jdbc_connection_class(spec)
1595
1378
  ::ArJdbc::PostgreSQL.jdbc_connection_class
1596
1379
  end
1597
1380
 
1381
+ # @see ActiveRecord::ConnectionAdapters::JdbcAdapter#jdbc_column_class
1598
1382
  def jdbc_column_class
1599
1383
  ::ActiveRecord::ConnectionAdapters::PostgreSQLColumn
1600
1384
  end
1601
-
1602
- # some QUOTING caching :
1603
-
1604
- @@quoted_table_names = {}
1605
-
1606
- def quote_table_name(name)
1607
- unless quoted = @@quoted_table_names[name]
1608
- quoted = super
1609
- @@quoted_table_names[name] = quoted.freeze
1610
- end
1611
- quoted
1612
- end
1613
-
1614
- @@quoted_column_names = {}
1615
-
1616
- def quote_column_name(name)
1617
- unless quoted = @@quoted_column_names[name]
1618
- quoted = super
1619
- @@quoted_column_names[name] = quoted.freeze
1620
- end
1621
- quoted
1622
- end
1623
-
1385
+
1624
1386
  end
1625
1387
  end