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,458 @@
1
+ module ArJdbc
2
+ module PostgreSQL
3
+
4
+ # @see ActiveRecord::ConnectionAdapters::JdbcColumn#column_types
5
+ def self.column_selector
6
+ [ /postgre/i, lambda { |cfg, column| column.extend(Column) } ]
7
+ end
8
+
9
+ # Column behavior based on PostgreSQL adapter in Rails.
10
+ # @see ActiveRecord::ConnectionAdapters::JdbcColumn
11
+ module Column
12
+
13
+ def self.included(base)
14
+ # NOTE: assumes a standalone PostgreSQLColumn class
15
+ class << base
16
+ include Cast
17
+ attr_accessor :money_precision
18
+ end
19
+ end
20
+
21
+ attr_accessor :array
22
+ def array?; array; end # in case we remove the array reader
23
+
24
+ # Extracts the value from a PostgreSQL column default definition.
25
+ #
26
+ # @override JdbcColumn#default_value
27
+ # NOTE: based on `self.extract_value_from_default(default)` code
28
+ def default_value(default)
29
+ # This is a performance optimization for Ruby 1.9.2 in development.
30
+ # If the value is nil, we return nil straight away without checking
31
+ # the regular expressions. If we check each regular expression,
32
+ # Regexp#=== will call NilClass#to_str, which will trigger
33
+ # method_missing (defined by whiny nil in ActiveSupport) which
34
+ # makes this method very very slow.
35
+ return default unless default
36
+
37
+ case default
38
+ when /\A'(.*)'::(num|date|tstz|ts|int4|int8)range\z/m
39
+ $1
40
+ # Numeric types
41
+ when /\A\(?(-?\d+(\.\d*)?\)?)\z/
42
+ $1
43
+ # Character types
44
+ when /\A\(?'(.*)'::.*\b(?:character varying|bpchar|text)\z/m
45
+ $1
46
+ # Binary data types
47
+ when /\A'(.*)'::bytea\z/m
48
+ $1
49
+ # Date/time types
50
+ when /\A'(.+)'::(?:time(?:stamp)? with(?:out)? time zone|date)\z/
51
+ $1
52
+ when /\A'(.*)'::interval\z/
53
+ $1
54
+ # Boolean type
55
+ when 'true'
56
+ true
57
+ when 'false'
58
+ false
59
+ # Geometric types
60
+ when /\A'(.*)'::(?:point|line|lseg|box|"?path"?|polygon|circle)\z/
61
+ $1
62
+ # Network address types
63
+ when /\A'(.*)'::(?:cidr|inet|macaddr)\z/
64
+ $1
65
+ # Bit string types
66
+ when /\AB'(.*)'::"?bit(?: varying)?"?\z/
67
+ $1
68
+ # XML type
69
+ when /\A'(.*)'::xml\z/m
70
+ $1
71
+ # Arrays
72
+ when /\A'(.*)'::"?\D+"?\[\]\z/
73
+ $1
74
+ when /\AARRAY\[(.*)\](::\D+)?\z/
75
+ "{#{$1.gsub(/'(.*?)'::[a-z]+(,)?\s?/, '\1\2')}}"
76
+ # Hstore
77
+ when /\A'(.*)'::hstore\z/
78
+ $1
79
+ # JSON
80
+ when /\A'(.*)'::json\z/
81
+ $1
82
+ # Object identifier types
83
+ when /\A-?\d+\z/
84
+ $1
85
+ else
86
+ # Anything else is blank, some user type, or some function
87
+ # and we can't know the value of that, so return nil.
88
+ nil
89
+ end
90
+ end
91
+
92
+ # Casts value (which is a String) to an appropriate instance.
93
+ def type_cast(value)
94
+ return if value.nil?
95
+ return super if encoded? # respond_to?(:encoded?) only since AR-3.2
96
+
97
+ # NOTE: we do not use OID::Type
98
+ # @oid_type.type_cast value
99
+
100
+ return value if array? # handled on the connection (JDBC) side
101
+
102
+ case type
103
+ when :hstore then self.class.string_to_hstore value
104
+ when :json then self.class.string_to_json value
105
+ when :cidr, :inet then self.class.string_to_cidr value
106
+ when :macaddr then value
107
+ when :tsvector then value
108
+ when :datetime, :timestamp then self.class.string_to_time value
109
+ else
110
+ case sql_type
111
+ when 'money'
112
+ # Because money output is formatted according to the locale, there
113
+ # are two cases to consider (note the decimal separators) :
114
+ # (1) $12,345,678.12
115
+ # (2) $12.345.678,12
116
+ case value
117
+ when /^-?\D+[\d,]+\.\d{2}$/ # (1)
118
+ value.gsub!(/[^-\d.]/, '')
119
+ when /^-?\D+[\d.]+,\d{2}$/ # (2)
120
+ value.gsub!(/[^-\d,]/, '')
121
+ value.sub!(/,/, '.')
122
+ end
123
+ self.class.value_to_decimal value
124
+ when /^point/
125
+ value.is_a?(String) ? self.class.string_to_point(value) : value
126
+ when /^(bit|varbit)/
127
+ value.is_a?(String) ? self.class.string_to_bit(value) : value
128
+ when /(.*?)range$/
129
+ return if value.nil? || value == 'empty'
130
+ return value if value.is_a?(::Range)
131
+
132
+ extracted = extract_bounds(value)
133
+
134
+ case $1 # subtype
135
+ when 'date' # :date
136
+ from = self.class.value_to_date(extracted[:from])
137
+ from -= 1.day if extracted[:exclude_start]
138
+ to = self.class.value_to_date(extracted[:to])
139
+ when 'num' # :decimal
140
+ from = BigDecimal.new(extracted[:from].to_s)
141
+ # FIXME: add exclude start for ::Range, same for timestamp ranges
142
+ to = BigDecimal.new(extracted[:to].to_s)
143
+ when 'ts', 'tstz' # :time
144
+ from = self.class.string_to_time(extracted[:from])
145
+ to = self.class.string_to_time(extracted[:to])
146
+ when 'int4', 'int8' # :integer
147
+ from = to_integer(extracted[:from]) rescue value ? 1 : 0
148
+ from -= 1 if extracted[:exclude_start]
149
+ to = to_integer(extracted[:to]) rescue value ? 1 : 0
150
+ else
151
+ return value
152
+ end
153
+
154
+ ::Range.new(from, to, extracted[:exclude_end])
155
+ else super
156
+ end
157
+ end
158
+ end if AR4_COMPAT
159
+
160
+ private
161
+
162
+ def extract_limit(sql_type)
163
+ case sql_type
164
+ when /^bigint/i; 8
165
+ when /^smallint/i; 2
166
+ when /^timestamp/i; nil
167
+ else super
168
+ end
169
+ end
170
+
171
+ # Extracts the scale from PostgreSQL-specific data types.
172
+ def extract_scale(sql_type)
173
+ # Money type has a fixed scale of 2.
174
+ sql_type =~ /^money/ ? 2 : super
175
+ end
176
+
177
+ # Extracts the precision from PostgreSQL-specific data types.
178
+ def extract_precision(sql_type)
179
+ if sql_type == 'money'
180
+ self.class.money_precision
181
+ elsif sql_type =~ /timestamp/i
182
+ $1.to_i if sql_type =~ /\((\d+)\)/
183
+ else
184
+ super
185
+ end
186
+ end
187
+
188
+ # Maps PostgreSQL-specific data types to logical Rails types.
189
+ def simplified_type(field_type)
190
+ case field_type
191
+ # Numeric and monetary types
192
+ when /^(?:real|double precision)$/ then :float
193
+ # Monetary types
194
+ when 'money' then :decimal
195
+ # Character types
196
+ when /^(?:character varying|bpchar)(?:\(\d+\))?$/ then :string
197
+ # Binary data types
198
+ when 'bytea' then :binary
199
+ # Date/time types
200
+ when /^timestamp with(?:out)? time zone$/ then :datetime
201
+ when 'interval' then :string
202
+ # Geometric types
203
+ when /^(?:point|line|lseg|box|"?path"?|polygon|circle)$/ then :string
204
+ # Network address types
205
+ when /^(?:cidr|inet|macaddr)$/ then :string
206
+ # Bit strings
207
+ when /^bit(?: varying)?(?:\(\d+\))?$/ then :string
208
+ # XML type
209
+ when 'xml' then :xml
210
+ # tsvector type
211
+ when 'tsvector' then :tsvector
212
+ # Arrays
213
+ when /^\D+\[\]$/ then :string
214
+ # Object identifier types
215
+ when 'oid' then :integer
216
+ # UUID type
217
+ when 'uuid' then :string
218
+ # Small and big integer types
219
+ when /^(?:small|big)int$/ then :integer
220
+ # AR-JDBC added :
221
+ when 'bool' then :boolean
222
+ when 'char' then :string
223
+ when 'serial' then :integer
224
+ # Pass through all types that are not specific to PostgreSQL.
225
+ else
226
+ super
227
+ end
228
+ end
229
+
230
+ # @private
231
+ def simplified_type(field_type)
232
+ case field_type
233
+ # Numeric and monetary types
234
+ when /^(?:real|double precision)$/ then :float
235
+ # Monetary types
236
+ when 'money' then :decimal
237
+ when 'hstore' then :hstore
238
+ when 'ltree' then :ltree
239
+ # Network address types
240
+ when 'inet' then :inet
241
+ when 'cidr' then :cidr
242
+ when 'macaddr' then :macaddr
243
+ # Character types
244
+ when /^(?:character varying|bpchar)(?:\(\d+\))?$/ then :string
245
+ # Binary data types
246
+ when 'bytea' then :binary
247
+ # Date/time types
248
+ when /^timestamp with(?:out)? time zone$/ then :datetime
249
+ when /^interval(?:|\(\d+\))$/ then :string
250
+ # Geometric types
251
+ when /^(?:point|line|lseg|box|"?path"?|polygon|circle)$/ then :string
252
+ # Bit strings
253
+ when /^bit(?: varying)?(?:\(\d+\))?$/ then :string
254
+ # XML type
255
+ when 'xml' then :xml
256
+ # tsvector type
257
+ when 'tsvector' then :tsvector
258
+ # Arrays
259
+ when /^\D+\[\]$/ then :string
260
+ # Object identifier types
261
+ when 'oid' then :integer
262
+ # UUID type
263
+ when 'uuid' then :uuid
264
+ # JSON type
265
+ when 'json' then :json
266
+ # Small and big integer types
267
+ when /^(?:small|big)int$/ then :integer
268
+ when /(num|date|tstz|ts|int4|int8)range$/
269
+ field_type.to_sym
270
+ # AR-JDBC added :
271
+ when 'bool' then :boolean
272
+ when 'char' then :string
273
+ when 'serial' then :integer
274
+ # Pass through all types that are not specific to PostgreSQL.
275
+ else
276
+ super
277
+ end
278
+ end if AR4_COMPAT
279
+
280
+ # OID Type::Range helpers :
281
+
282
+ def extract_bounds(value)
283
+ f, t = value[1..-2].split(',')
284
+ {
285
+ :from => (value[1] == ',' || f == '-infinity') ? infinity(:negative => true) : f,
286
+ :to => (value[-2] == ',' || t == 'infinity') ? infinity : t,
287
+ :exclude_start => (value[0] == '('), :exclude_end => (value[-1] == ')')
288
+ }
289
+ end if AR4_COMPAT
290
+
291
+ def infinity(options = {})
292
+ ::Float::INFINITY * (options[:negative] ? -1 : 1)
293
+ end if AR4_COMPAT
294
+
295
+ def to_integer(value)
296
+ (value.respond_to?(:infinite?) && value.infinite?) ? value : value.to_i
297
+ end if AR4_COMPAT
298
+
299
+ # @note Based on *active_record/connection_adapters/postgresql/cast.rb* (4.0).
300
+ module Cast
301
+
302
+ def point_to_string(point)
303
+ "(#{point[0]},#{point[1]})"
304
+ end
305
+
306
+ def string_to_point(string)
307
+ if string[0] == '(' && string[-1] == ')'
308
+ string = string[1...-1]
309
+ end
310
+ string.split(',').map { |v| Float(v) }
311
+ end
312
+
313
+ def string_to_time(string)
314
+ return string unless String === string
315
+
316
+ case string
317
+ when 'infinity' then 1.0 / 0.0
318
+ when '-infinity' then -1.0 / 0.0
319
+ when / BC$/
320
+ super("-" + string.sub(/ BC$/, ""))
321
+ else
322
+ super
323
+ end
324
+ end
325
+
326
+ def string_to_bit(value)
327
+ case value
328
+ when /^[01]*$/ then value # Bit-string notation
329
+ when /^[0-9A-F]*$/i then value.hex.to_s(2) # Hexadecimal notation
330
+ end
331
+ end
332
+
333
+ def string_to_bit(value)
334
+ case value
335
+ when /^0x/i
336
+ value[2..-1].hex.to_s(2) # Hexadecimal notation
337
+ else
338
+ value # Bit-string notation
339
+ end
340
+ end if AR4_COMPAT
341
+
342
+ def hstore_to_string(object)
343
+ if Hash === object
344
+ object.map { |k,v| "#{escape_hstore(k)}=>#{escape_hstore(v)}" }.join(',')
345
+ else
346
+ object
347
+ end
348
+ end
349
+
350
+ def string_to_hstore(string)
351
+ if string.nil?
352
+ nil
353
+ elsif String === string
354
+ Hash[string.scan(HstorePair).map { |k,v|
355
+ v = v.upcase == 'NULL' ? nil : v.gsub(/^"(.*)"$/,'\1').gsub(/\\(.)/, '\1')
356
+ k = k.gsub(/^"(.*)"$/,'\1').gsub(/\\(.)/, '\1')
357
+ [k,v]
358
+ }]
359
+ else
360
+ string
361
+ end
362
+ end
363
+
364
+ def json_to_string(object)
365
+ if Hash === object
366
+ ActiveSupport::JSON.encode(object)
367
+ else
368
+ object
369
+ end
370
+ end
371
+
372
+ def array_to_string(value, column, adapter, should_be_quoted = false)
373
+ casted_values = value.map do |val|
374
+ if String === val
375
+ if val == "NULL"
376
+ "\"#{val}\""
377
+ else
378
+ quote_and_escape(adapter.type_cast(val, column, true))
379
+ end
380
+ else
381
+ adapter.type_cast(val, column, true)
382
+ end
383
+ end
384
+ "{#{casted_values.join(',')}}"
385
+ end
386
+
387
+ def range_to_string(object)
388
+ from = object.begin.respond_to?(:infinite?) && object.begin.infinite? ? '' : object.begin
389
+ to = object.end.respond_to?(:infinite?) && object.end.infinite? ? '' : object.end
390
+ "[#{from},#{to}#{object.exclude_end? ? ')' : ']'}"
391
+ end
392
+
393
+ def string_to_json(string)
394
+ if String === string
395
+ ActiveSupport::JSON.decode(string)
396
+ else
397
+ string
398
+ end
399
+ end
400
+
401
+ def string_to_cidr(string)
402
+ if string.nil?
403
+ nil
404
+ elsif String === string
405
+ IPAddr.new(string)
406
+ else
407
+ string
408
+ end
409
+ end
410
+
411
+ def cidr_to_string(object)
412
+ if IPAddr === object
413
+ "#{object.to_s}/#{object.instance_variable_get(:@mask_addr).to_s(2).count('1')}"
414
+ else
415
+ object
416
+ end
417
+ end
418
+
419
+ # NOTE: not used - we get "parsed" array value from connection
420
+ #def string_to_array(string, oid)
421
+ # parse_pg_array(string).map { |val| oid.type_cast val }
422
+ #end
423
+
424
+ private
425
+
426
+ # @private
427
+ HstorePair = begin
428
+ quoted_string = /"[^"\\]*(?:\\.[^"\\]*)*"/
429
+ unquoted_string = /(?:\\.|[^\s,])[^\s=,\\]*(?:\\.[^\s=,\\]*|=[^,>])*/
430
+ /(#{quoted_string}|#{unquoted_string})\s*=>\s*(#{quoted_string}|#{unquoted_string})/
431
+ end
432
+
433
+ def escape_hstore(value)
434
+ if value.nil?
435
+ 'NULL'
436
+ else
437
+ if value == ""
438
+ '""'
439
+ else
440
+ '"%s"' % value.to_s.gsub(/(["\\])/, '\\\\\1')
441
+ end
442
+ end
443
+ end
444
+
445
+ def quote_and_escape(value)
446
+ case value
447
+ when "NULL"
448
+ value
449
+ else
450
+ "\"#{value.gsub(/(["\\])/, '\\\\\1')}\""
451
+ end
452
+ end
453
+
454
+ end
455
+
456
+ end
457
+ end
458
+ end