activerecord-jdbc-adapter-ficoh 1.3.21-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +35 -0
  3. data/.travis.yml +462 -0
  4. data/.yardopts +4 -0
  5. data/Appraisals +36 -0
  6. data/CONTRIBUTING.md +49 -0
  7. data/Gemfile +68 -0
  8. data/History.md +1191 -0
  9. data/LICENSE.txt +25 -0
  10. data/README.md +277 -0
  11. data/RUNNING_TESTS.md +88 -0
  12. data/Rakefile +298 -0
  13. data/Rakefile.jdbc +20 -0
  14. data/activerecord-jdbc-adapter.gemspec +63 -0
  15. data/lib/active_record/connection_adapters/as400_adapter.rb +2 -0
  16. data/lib/active_record/connection_adapters/db2_adapter.rb +1 -0
  17. data/lib/active_record/connection_adapters/derby_adapter.rb +1 -0
  18. data/lib/active_record/connection_adapters/firebird_adapter.rb +1 -0
  19. data/lib/active_record/connection_adapters/h2_adapter.rb +1 -0
  20. data/lib/active_record/connection_adapters/hsqldb_adapter.rb +1 -0
  21. data/lib/active_record/connection_adapters/informix_adapter.rb +1 -0
  22. data/lib/active_record/connection_adapters/jdbc_adapter.rb +1 -0
  23. data/lib/active_record/connection_adapters/jndi_adapter.rb +1 -0
  24. data/lib/active_record/connection_adapters/mariadb_adapter.rb +1 -0
  25. data/lib/active_record/connection_adapters/mssql_adapter.rb +1 -0
  26. data/lib/active_record/connection_adapters/mysql2_adapter.rb +1 -0
  27. data/lib/active_record/connection_adapters/mysql_adapter.rb +1 -0
  28. data/lib/active_record/connection_adapters/oracle_adapter.rb +1 -0
  29. data/lib/active_record/connection_adapters/postgresql_adapter.rb +1 -0
  30. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +1 -0
  31. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +1 -0
  32. data/lib/activerecord-jdbc-adapter.rb +1 -0
  33. data/lib/arel/visitors/compat.rb +64 -0
  34. data/lib/arel/visitors/db2.rb +137 -0
  35. data/lib/arel/visitors/derby.rb +112 -0
  36. data/lib/arel/visitors/firebird.rb +79 -0
  37. data/lib/arel/visitors/h2.rb +25 -0
  38. data/lib/arel/visitors/hsqldb.rb +32 -0
  39. data/lib/arel/visitors/postgresql_jdbc.rb +6 -0
  40. data/lib/arel/visitors/sql_server.rb +225 -0
  41. data/lib/arel/visitors/sql_server/ng42.rb +293 -0
  42. data/lib/arjdbc.rb +22 -0
  43. data/lib/arjdbc/db2.rb +4 -0
  44. data/lib/arjdbc/db2/adapter.rb +802 -0
  45. data/lib/arjdbc/db2/as400.rb +137 -0
  46. data/lib/arjdbc/db2/column.rb +177 -0
  47. data/lib/arjdbc/db2/connection_methods.rb +45 -0
  48. data/lib/arjdbc/derby.rb +3 -0
  49. data/lib/arjdbc/derby/active_record_patch.rb +13 -0
  50. data/lib/arjdbc/derby/adapter.rb +567 -0
  51. data/lib/arjdbc/derby/connection_methods.rb +16 -0
  52. data/lib/arjdbc/derby/schema_creation.rb +15 -0
  53. data/lib/arjdbc/discover.rb +104 -0
  54. data/lib/arjdbc/firebird.rb +4 -0
  55. data/lib/arjdbc/firebird/adapter.rb +468 -0
  56. data/lib/arjdbc/firebird/connection_methods.rb +20 -0
  57. data/lib/arjdbc/h2.rb +3 -0
  58. data/lib/arjdbc/h2/adapter.rb +335 -0
  59. data/lib/arjdbc/h2/connection_methods.rb +22 -0
  60. data/lib/arjdbc/hsqldb.rb +3 -0
  61. data/lib/arjdbc/hsqldb/adapter.rb +304 -0
  62. data/lib/arjdbc/hsqldb/connection_methods.rb +23 -0
  63. data/lib/arjdbc/hsqldb/explain_support.rb +35 -0
  64. data/lib/arjdbc/hsqldb/schema_creation.rb +11 -0
  65. data/lib/arjdbc/informix.rb +5 -0
  66. data/lib/arjdbc/informix/adapter.rb +160 -0
  67. data/lib/arjdbc/informix/connection_methods.rb +9 -0
  68. data/lib/arjdbc/jdbc.rb +62 -0
  69. data/lib/arjdbc/jdbc/adapter.rb +997 -0
  70. data/lib/arjdbc/jdbc/adapter_require.rb +46 -0
  71. data/lib/arjdbc/jdbc/arel_support.rb +149 -0
  72. data/lib/arjdbc/jdbc/base_ext.rb +34 -0
  73. data/lib/arjdbc/jdbc/callbacks.rb +52 -0
  74. data/lib/arjdbc/jdbc/column.rb +83 -0
  75. data/lib/arjdbc/jdbc/connection.rb +26 -0
  76. data/lib/arjdbc/jdbc/connection_methods.rb +59 -0
  77. data/lib/arjdbc/jdbc/driver.rb +44 -0
  78. data/lib/arjdbc/jdbc/error.rb +75 -0
  79. data/lib/arjdbc/jdbc/extension.rb +69 -0
  80. data/lib/arjdbc/jdbc/java.rb +13 -0
  81. data/lib/arjdbc/jdbc/type_cast.rb +154 -0
  82. data/lib/arjdbc/jdbc/type_converter.rb +142 -0
  83. data/lib/arjdbc/mssql.rb +7 -0
  84. data/lib/arjdbc/mssql/adapter.rb +822 -0
  85. data/lib/arjdbc/mssql/column.rb +207 -0
  86. data/lib/arjdbc/mssql/connection_methods.rb +72 -0
  87. data/lib/arjdbc/mssql/explain_support.rb +99 -0
  88. data/lib/arjdbc/mssql/limit_helpers.rb +231 -0
  89. data/lib/arjdbc/mssql/lock_methods.rb +77 -0
  90. data/lib/arjdbc/mssql/types.rb +343 -0
  91. data/lib/arjdbc/mssql/utils.rb +82 -0
  92. data/lib/arjdbc/mysql.rb +3 -0
  93. data/lib/arjdbc/mysql/adapter.rb +998 -0
  94. data/lib/arjdbc/mysql/bulk_change_table.rb +150 -0
  95. data/lib/arjdbc/mysql/column.rb +167 -0
  96. data/lib/arjdbc/mysql/connection_methods.rb +137 -0
  97. data/lib/arjdbc/mysql/explain_support.rb +82 -0
  98. data/lib/arjdbc/mysql/schema_creation.rb +58 -0
  99. data/lib/arjdbc/oracle.rb +4 -0
  100. data/lib/arjdbc/oracle/adapter.rb +968 -0
  101. data/lib/arjdbc/oracle/column.rb +136 -0
  102. data/lib/arjdbc/oracle/connection_methods.rb +21 -0
  103. data/lib/arjdbc/postgresql.rb +3 -0
  104. data/lib/arjdbc/postgresql/_bc_time_cast_patch.rb +21 -0
  105. data/lib/arjdbc/postgresql/adapter.rb +1498 -0
  106. data/lib/arjdbc/postgresql/base/array_parser.rb +95 -0
  107. data/lib/arjdbc/postgresql/base/oid.rb +412 -0
  108. data/lib/arjdbc/postgresql/base/pgconn.rb +8 -0
  109. data/lib/arjdbc/postgresql/base/schema_definitions.rb +132 -0
  110. data/lib/arjdbc/postgresql/column.rb +640 -0
  111. data/lib/arjdbc/postgresql/connection_methods.rb +44 -0
  112. data/lib/arjdbc/postgresql/explain_support.rb +53 -0
  113. data/lib/arjdbc/postgresql/oid/bytea.rb +3 -0
  114. data/lib/arjdbc/postgresql/oid_types.rb +265 -0
  115. data/lib/arjdbc/postgresql/schema_creation.rb +60 -0
  116. data/lib/arjdbc/railtie.rb +11 -0
  117. data/lib/arjdbc/sqlite3.rb +3 -0
  118. data/lib/arjdbc/sqlite3/adapter.rb +654 -0
  119. data/lib/arjdbc/sqlite3/connection_methods.rb +36 -0
  120. data/lib/arjdbc/sqlite3/explain_support.rb +29 -0
  121. data/lib/arjdbc/sybase.rb +2 -0
  122. data/lib/arjdbc/sybase/adapter.rb +47 -0
  123. data/lib/arjdbc/tasks.rb +13 -0
  124. data/lib/arjdbc/tasks/database_tasks.rb +66 -0
  125. data/lib/arjdbc/tasks/databases.rake +91 -0
  126. data/lib/arjdbc/tasks/databases3.rake +239 -0
  127. data/lib/arjdbc/tasks/databases4.rake +39 -0
  128. data/lib/arjdbc/tasks/db2_database_tasks.rb +104 -0
  129. data/lib/arjdbc/tasks/derby_database_tasks.rb +95 -0
  130. data/lib/arjdbc/tasks/h2_database_tasks.rb +31 -0
  131. data/lib/arjdbc/tasks/hsqldb_database_tasks.rb +70 -0
  132. data/lib/arjdbc/tasks/jdbc_database_tasks.rb +169 -0
  133. data/lib/arjdbc/tasks/mssql_database_tasks.rb +46 -0
  134. data/lib/arjdbc/tasks/oracle/enhanced_structure_dump.rb +297 -0
  135. data/lib/arjdbc/tasks/oracle_database_tasks.rb +65 -0
  136. data/lib/arjdbc/util/quoted_cache.rb +60 -0
  137. data/lib/arjdbc/util/serialized_attributes.rb +98 -0
  138. data/lib/arjdbc/util/table_copier.rb +108 -0
  139. data/lib/arjdbc/version.rb +8 -0
  140. data/lib/generators/jdbc/USAGE +9 -0
  141. data/lib/generators/jdbc/jdbc_generator.rb +17 -0
  142. data/pom.xml +285 -0
  143. data/rails_generators/jdbc_generator.rb +15 -0
  144. data/rails_generators/templates/config/initializers/jdbc.rb +10 -0
  145. data/rails_generators/templates/lib/tasks/jdbc.rake +11 -0
  146. data/rakelib/01-tomcat.rake +51 -0
  147. data/rakelib/02-test.rake +151 -0
  148. data/rakelib/bundler_ext.rb +11 -0
  149. data/rakelib/db.rake +58 -0
  150. data/rakelib/rails.rake +77 -0
  151. data/src/java/arjdbc/ArJdbcModule.java +288 -0
  152. data/src/java/arjdbc/db2/DB2Module.java +77 -0
  153. data/src/java/arjdbc/db2/DB2RubyJdbcConnection.java +128 -0
  154. data/src/java/arjdbc/derby/DerbyModule.java +180 -0
  155. data/src/java/arjdbc/derby/DerbyRubyJdbcConnection.java +153 -0
  156. data/src/java/arjdbc/firebird/FirebirdRubyJdbcConnection.java +190 -0
  157. data/src/java/arjdbc/h2/H2Module.java +50 -0
  158. data/src/java/arjdbc/h2/H2RubyJdbcConnection.java +86 -0
  159. data/src/java/arjdbc/hsqldb/HSQLDBModule.java +74 -0
  160. data/src/java/arjdbc/informix/InformixRubyJdbcConnection.java +76 -0
  161. data/src/java/arjdbc/jdbc/AdapterJavaService.java +43 -0
  162. data/src/java/arjdbc/jdbc/Callable.java +44 -0
  163. data/src/java/arjdbc/jdbc/ConnectionFactory.java +77 -0
  164. data/src/java/arjdbc/jdbc/DataSourceConnectionFactory.java +156 -0
  165. data/src/java/arjdbc/jdbc/DriverConnectionFactory.java +63 -0
  166. data/src/java/arjdbc/jdbc/DriverWrapper.java +128 -0
  167. data/src/java/arjdbc/jdbc/JdbcConnectionFactory.java +32 -0
  168. data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +4541 -0
  169. data/src/java/arjdbc/jdbc/SQLBlock.java +54 -0
  170. data/src/java/arjdbc/jdbc/WithResultSet.java +37 -0
  171. data/src/java/arjdbc/mssql/MSSQLModule.java +91 -0
  172. data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +193 -0
  173. data/src/java/arjdbc/mysql/MySQLModule.java +140 -0
  174. data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +456 -0
  175. data/src/java/arjdbc/oracle/OracleModule.java +81 -0
  176. data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +477 -0
  177. data/src/java/arjdbc/postgresql/ByteaUtils.java +171 -0
  178. data/src/java/arjdbc/postgresql/DriverImplementation.java +78 -0
  179. data/src/java/arjdbc/postgresql/PGDriverImplementation.java +535 -0
  180. data/src/java/arjdbc/postgresql/PostgreSQLModule.java +189 -0
  181. data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +489 -0
  182. data/src/java/arjdbc/sqlite3/SQLite3Module.java +93 -0
  183. data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +405 -0
  184. data/src/java/arjdbc/util/CallResultSet.java +826 -0
  185. data/src/java/arjdbc/util/DateTimeUtils.java +517 -0
  186. data/src/java/arjdbc/util/NumberUtils.java +50 -0
  187. data/src/java/arjdbc/util/ObjectSupport.java +65 -0
  188. data/src/java/arjdbc/util/QuotingUtils.java +139 -0
  189. data/src/java/arjdbc/util/StringCache.java +60 -0
  190. data/src/java/arjdbc/util/StringHelper.java +155 -0
  191. metadata +288 -0
@@ -0,0 +1,44 @@
1
+ ArJdbc::ConnectionMethods.module_eval do
2
+ def postgresql_connection(config)
3
+ config[:adapter_spec] ||= ::ArJdbc::PostgreSQL
4
+ config[:adapter_class] = ActiveRecord::ConnectionAdapters::PostgreSQLAdapter unless config.key?(:adapter_class)
5
+
6
+ return jndi_connection(config) if jndi_config?(config)
7
+
8
+ driver = config[:driver] ||= 'org.postgresql.Driver'
9
+ ArJdbc.load_driver(:Postgres) if driver.start_with?('org.postgresql.') && config[:load_driver] != false
10
+
11
+ host = config[:host] ||= ( config[:hostaddr] || ENV['PGHOST'] || 'localhost' )
12
+ port = config[:port] ||= ( ENV['PGPORT'] || 5432 )
13
+ database = config[:database] || config[:dbname] || ENV['PGDATABASE']
14
+
15
+ config[:url] ||= "jdbc:postgresql://#{host}:#{port}/#{database}"
16
+ config[:url] << config[:pg_params] if config[:pg_params]
17
+
18
+ config[:username] ||= ( config[:user] || ENV['PGUSER'] || ENV_JAVA['user.name'] )
19
+ config[:password] ||= ENV['PGPASSWORD'] unless config.key?(:password)
20
+ properties = ( config[:properties] ||= {} )
21
+ # PG :connect_timeout - maximum time to wait for connection to succeed
22
+ if connect_timeout = ( config[:connect_timeout] || ENV['PGCONNECT_TIMEOUT'] )
23
+ properties['socketTimeout'] ||= connect_timeout
24
+ end
25
+ if login_timeout = config[:login_timeout]
26
+ properties['loginTimeout'] ||= login_timeout
27
+ end
28
+ sslmode = config.key?(:sslmode) ? config[:sslmode] : config[:requiressl]
29
+ # NOTE: makes not much sense since this needs some JVM options :
30
+ # sslmode = ENV['PGSSLMODE'] || ENV['PGREQUIRESSL'] if sslmode.nil?
31
+ unless sslmode.nil? # PG :sslmode - disable|allow|prefer|require
32
+ # JRuby/JVM needs to be started with :
33
+ # -Djavax.net.ssl.trustStore=mystore -Djavax.net.ssl.trustStorePassword=...
34
+ # or a non-validating connection might be used (for testing) :
35
+ # :sslfactory = 'org.postgresql.ssl.NonValidatingFactory'
36
+ properties['ssl'] ||= 'true' if sslmode == true || sslmode.to_s == 'require'
37
+ end
38
+ properties['tcpKeepAlive'] ||= config[:keepalives] if config.key?(:keepalives)
39
+ properties['kerberosServerName'] ||= config[:krbsrvname] if config[:krbsrvname]
40
+
41
+ jdbc_connection(config)
42
+ end
43
+ alias_method :jdbcpostgresql_connection, :postgresql_connection
44
+ end
@@ -0,0 +1,53 @@
1
+ module ArJdbc
2
+ module PostgreSQL
3
+ # @private
4
+ module ExplainSupport
5
+ def supports_explain?
6
+ true
7
+ end
8
+
9
+ def explain(arel, binds = [])
10
+ sql = "EXPLAIN #{to_sql(arel, binds)}"
11
+ result = exec_query(sql, "EXPLAIN", binds)
12
+ ExplainPrettyPrinter.new.pp result # we can assume AR >= 3.1
13
+ end
14
+ # @private
15
+ class ExplainPrettyPrinter
16
+ # Pretty prints the result of a EXPLAIN in a way that resembles the output of the
17
+ # PostgreSQL shell:
18
+ #
19
+ # QUERY PLAN
20
+ # ------------------------------------------------------------------------------
21
+ # Nested Loop Left Join (cost=0.00..37.24 rows=8 width=0)
22
+ # Join Filter: (posts.user_id = users.id)
23
+ # -> Index Scan using users_pkey on users (cost=0.00..8.27 rows=1 width=4)
24
+ # Index Cond: (id = 1)
25
+ # -> Seq Scan on posts (cost=0.00..28.88 rows=8 width=4)
26
+ # Filter: (posts.user_id = 1)
27
+ # (6 rows)
28
+ #
29
+ def pp(result)
30
+ header = result.columns.first
31
+ lines = result.rows.map(&:first)
32
+
33
+ # We add 2 because there's one char of padding at both sides, note
34
+ # the extra hyphens in the example above.
35
+ width = [header, *lines].map(&:length).max + 2
36
+
37
+ pp = []
38
+
39
+ pp << header.center(width).rstrip
40
+ pp << '-' * width
41
+
42
+ pp += lines.map {|line| " #{line}"}
43
+
44
+ nrows = result.rows.length
45
+ rows_label = nrows == 1 ? 'row' : 'rows'
46
+ pp << "(#{nrows} #{rows_label})"
47
+
48
+ pp.join("\n") + "\n"
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,3 @@
1
+ class ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Bytea
2
+ remove_method :type_cast_from_database
3
+ end
@@ -0,0 +1,265 @@
1
+ require 'thread'
2
+
3
+ module ArJdbc
4
+ module PostgreSQL
5
+
6
+ if AR42
7
+ require 'active_record/connection_adapters/postgresql/oid'
8
+ require 'arjdbc/postgresql/base/pgconn'
9
+ require 'arjdbc/postgresql/oid/bytea.rb'
10
+ else
11
+ require 'arjdbc/postgresql/base/oid'
12
+ end
13
+
14
+ require 'arjdbc/postgresql/base/pgconn'
15
+
16
+ # @private
17
+ OID = ::ActiveRecord::ConnectionAdapters::PostgreSQL::OID
18
+
19
+ # @private
20
+ module OIDTypes
21
+
22
+ # @override
23
+ def enable_extension(name)
24
+ result = super(name)
25
+ @extensions = nil
26
+ reload_type_map
27
+ result
28
+ end
29
+
30
+ # @override
31
+ def disable_extension(name)
32
+ result = super(name)
33
+ @extensions = nil
34
+ reload_type_map
35
+ result
36
+ end
37
+
38
+ # @override
39
+ def extensions
40
+ @extensions ||= super
41
+ end
42
+
43
+ # @override
44
+ def lookup_cast_type(sql_type)
45
+ oid = execute("SELECT #{quote(sql_type)}::regtype::oid", "SCHEMA")
46
+ super oid.first['oid'].to_i
47
+ end if AR42
48
+
49
+ def get_oid_type(oid, fmod, column_name)
50
+ type_map.fetch(oid, fmod) {
51
+ warn "unknown OID #{oid}: failed to recognize type of '#{column_name}'. It will be treated as String."
52
+ type_map[oid] = OID::Identity.new
53
+ }
54
+ end unless AR42
55
+
56
+ def get_oid_type(oid, fmod, column_name, sql_type = '')
57
+ if !type_map.key?(oid)
58
+ load_additional_types(type_map, [oid])
59
+ end
60
+
61
+ type_map.fetch(oid, fmod, sql_type) {
62
+ warn "unknown OID #{oid}: failed to recognize type of '#{column_name}'. It will be treated as String."
63
+ Type::Value.new.tap do |cast_type|
64
+ type_map.register_type(oid, cast_type)
65
+ end
66
+ }
67
+ end if AR42
68
+
69
+ @@type_map_cache = {}
70
+ @@type_map_cache_lock = Mutex.new
71
+
72
+ if AR42
73
+ TypeMap = ActiveRecord::Type::HashLookupTypeMap
74
+ else
75
+ TypeMap = OID::TypeMap
76
+ end
77
+
78
+ # @see #type_map
79
+ # @private
80
+ TypeMap.class_eval do
81
+ def dup
82
+ dup = super # make sure @mapping is not shared
83
+ dup.instance_variable_set(:@mapping, @mapping.dup)
84
+ dup
85
+ end
86
+ end
87
+
88
+ def type_map
89
+ # NOTE: our type_map is lazy (on AR < 4.2)
90
+ # ... since it's only used for `adapter.accessor`
91
+ @type_map ||= begin
92
+ if type_map = @@type_map_cache[ type_cache_key ]
93
+ type_map.dup
94
+ else
95
+ type_map = TypeMap.new
96
+ initialize_type_map(type_map)
97
+ cache_type_map(type_map)
98
+ type_map
99
+ end
100
+ end
101
+ end
102
+
103
+ def reload_type_map
104
+ if ( @type_map ||= nil )
105
+ @type_map.clear
106
+ initialize_type_map(@type_map)
107
+ end
108
+ end
109
+
110
+ private
111
+
112
+ def cache_type_map(type_map)
113
+ @@type_map_cache_lock.synchronize do
114
+ @@type_map_cache[ type_cache_key ] = type_map
115
+ end
116
+ end
117
+
118
+ def type_cache_key
119
+ config.hash + ( 7 * extensions.hash )
120
+ end
121
+
122
+ def add_oid(row, records_by_oid, type_map)
123
+ return type_map if type_map.key? row['type_elem'].to_i
124
+
125
+ if OID.registered_type? typname = row['typname']
126
+ # this composite type is explicitly registered
127
+ vector = OID::NAMES[ typname ]
128
+ else
129
+ # use the default for composite types
130
+ unless type_map.key? typelem = row['typelem'].to_i
131
+ add_oid records_by_oid[ row['typelem'] ], records_by_oid, type_map
132
+ end
133
+
134
+ vector = OID::Vector.new row['typdelim'], type_map[typelem]
135
+ end
136
+
137
+ type_map[ row['oid'].to_i ] = vector
138
+ type_map
139
+ end
140
+
141
+ def initialize_type_map(type_map)
142
+ result = execute('SELECT oid, typname, typelem, typdelim, typinput FROM pg_type', 'SCHEMA')
143
+ leaves, nodes = result.partition { |row| row['typelem'].to_s == '0' }
144
+ # populate the leaf nodes
145
+ leaves.find_all { |row| OID.registered_type? row['typname'] }.each do |row|
146
+ type_map[ row['oid'].to_i ] = OID::NAMES[ row['typname'] ]
147
+ end
148
+
149
+ records_by_oid = result.group_by { |row| row['oid'] }
150
+
151
+ arrays, nodes = nodes.partition { |row| row['typinput'] == 'array_in' }
152
+
153
+ # populate composite types
154
+ nodes.each { |row| add_oid row, records_by_oid, type_map }
155
+
156
+ # populate array types
157
+ arrays.find_all { |row| type_map.key? row['typelem'].to_i }.each do |row|
158
+ array = OID::Array.new type_map[ row['typelem'].to_i ]
159
+ type_map[ row['oid'].to_i ] = array
160
+ end
161
+ end unless AR42
162
+
163
+ def initialize_type_map(m)
164
+ register_class_with_limit m, 'int2', OID::Integer
165
+ register_class_with_limit m, 'int4', OID::Integer
166
+ register_class_with_limit m, 'int8', OID::Integer
167
+ m.alias_type 'oid', 'int2'
168
+ m.register_type 'float4', OID::Float.new
169
+ m.alias_type 'float8', 'float4'
170
+ m.register_type 'text', Type::Text.new
171
+ register_class_with_limit m, 'varchar', Type::String
172
+ m.alias_type 'char', 'varchar'
173
+ m.alias_type 'name', 'varchar'
174
+ m.alias_type 'bpchar', 'varchar'
175
+ m.register_type 'bool', Type::Boolean.new
176
+ register_class_with_limit m, 'bit', OID::Bit
177
+ register_class_with_limit m, 'varbit', OID::BitVarying
178
+ m.alias_type 'timestamptz', 'timestamp'
179
+ m.register_type 'date', OID::Date.new
180
+ m.register_type 'time', OID::Time.new
181
+
182
+ m.register_type 'money', OID::Money.new
183
+ m.register_type 'bytea', OID::Bytea.new
184
+ m.register_type 'point', OID::Point.new
185
+ m.register_type 'hstore', OID::Hstore.new
186
+ m.register_type 'json', OID::Json.new
187
+ m.register_type 'jsonb', OID::Jsonb.new
188
+ m.register_type 'cidr', OID::Cidr.new
189
+ m.register_type 'inet', OID::Inet.new
190
+ m.register_type 'uuid', OID::Uuid.new
191
+ m.register_type 'xml', OID::Xml.new
192
+ m.register_type 'tsvector', OID::SpecializedString.new(:tsvector)
193
+ m.register_type 'macaddr', OID::SpecializedString.new(:macaddr)
194
+ m.register_type 'citext', OID::SpecializedString.new(:citext)
195
+ m.register_type 'ltree', OID::SpecializedString.new(:ltree)
196
+
197
+ # FIXME: why are we keeping these types as strings?
198
+ m.alias_type 'interval', 'varchar'
199
+ m.alias_type 'path', 'varchar'
200
+ m.alias_type 'line', 'varchar'
201
+ m.alias_type 'polygon', 'varchar'
202
+ m.alias_type 'circle', 'varchar'
203
+ m.alias_type 'lseg', 'varchar'
204
+ m.alias_type 'box', 'varchar'
205
+
206
+ m.register_type 'timestamp' do |_, _, sql_type|
207
+ precision = extract_precision(sql_type)
208
+ OID::DateTime.new(precision: precision)
209
+ end
210
+
211
+ m.register_type 'numeric' do |_, fmod, sql_type|
212
+ precision = extract_precision(sql_type)
213
+ scale = extract_scale(sql_type)
214
+
215
+ # The type for the numeric depends on the width of the field,
216
+ # so we'll do something special here.
217
+ #
218
+ # When dealing with decimal columns:
219
+ #
220
+ # places after decimal = fmod - 4 & 0xffff
221
+ # places before decimal = (fmod - 4) >> 16 & 0xffff
222
+ if fmod && (fmod - 4 & 0xffff).zero?
223
+ # FIXME: Remove this class, and the second argument to
224
+ # lookups on PG
225
+ Type::DecimalWithoutScale.new(precision: precision)
226
+ else
227
+ OID::Decimal.new(precision: precision, scale: scale)
228
+ end
229
+ end
230
+
231
+ load_additional_types(m)
232
+ end if AR42
233
+
234
+ def load_additional_types(type_map, oids = nil)
235
+ if supports_ranges?
236
+ query = <<-SQL
237
+ SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, r.rngsubtype, t.typtype, t.typbasetype
238
+ FROM pg_type as t
239
+ LEFT JOIN pg_range as r ON oid = rngtypid
240
+ SQL
241
+ else
242
+ query = <<-SQL
243
+ SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, t.typtype, t.typbasetype
244
+ FROM pg_type as t
245
+ SQL
246
+ end
247
+
248
+ initializer = OID::TypeMapInitializer.new(type_map)
249
+
250
+ if oids
251
+ query << ( "WHERE t.oid::integer IN (%s)" % oids.join(", ") )
252
+ else
253
+ # query_conditions_for_initial_load only available since AR > 4.2.1
254
+ if initializer.respond_to?(:query_conditions_for_initial_load)
255
+ query << initializer.query_conditions_for_initial_load(type_map)
256
+ end
257
+ end
258
+
259
+ records = execute(query, 'SCHEMA')
260
+ initializer.run(records)
261
+ end if AR42
262
+
263
+ end
264
+ end
265
+ end
@@ -0,0 +1,60 @@
1
+ module ArJdbc
2
+ module PostgreSQL
3
+ # @private copied (and adjusted) from native adapter 4.0/4.1/4.2
4
+ class SchemaCreation < ::ActiveRecord::ConnectionAdapters::AbstractAdapter::SchemaCreation
5
+
6
+ private
7
+
8
+ def visit_AddColumn(o)
9
+ sql_type = type_to_sql(o.type.to_sym, o.limit, o.precision, o.scale)
10
+ sql = "ADD COLUMN #{quote_column_name(o.name)} #{sql_type}"
11
+ add_column_options!(sql, column_options(o))
12
+ end unless AR42
13
+
14
+ def visit_ColumnDefinition(o)
15
+ sql = super
16
+ if o.primary_key? && o.type == :uuid
17
+ sql << " PRIMARY KEY "
18
+ add_column_options!(sql, column_options(o))
19
+ end
20
+ sql
21
+ end unless AR42
22
+
23
+ def visit_ColumnDefinition(o)
24
+ sql = super
25
+ if o.primary_key? && o.type != :primary_key
26
+ sql << " PRIMARY KEY "
27
+ add_column_options!(sql, column_options(o))
28
+ end
29
+ sql
30
+ end if AR42
31
+
32
+ def add_column_options!(sql, options)
33
+ if options[:array] || options[:column].try(:array)
34
+ sql << '[]'
35
+ end
36
+
37
+ column = options.fetch(:column) { return super }
38
+ if column.type == :uuid && options[:default] =~ /\(\)/
39
+ sql << " DEFAULT #{options[:default]}"
40
+ else
41
+ super
42
+ end
43
+ end
44
+
45
+ def type_for_column(column)
46
+ if column.array
47
+ @conn.lookup_cast_type("#{column.sql_type}[]")
48
+ else
49
+ super
50
+ end
51
+ end if AR42
52
+
53
+ end
54
+
55
+ def schema_creation
56
+ SchemaCreation.new self
57
+ end
58
+
59
+ end
60
+ end if ::ActiveRecord::ConnectionAdapters::AbstractAdapter.const_defined? :SchemaCreation
@@ -0,0 +1,11 @@
1
+ require 'rails/railtie'
2
+
3
+ module ArJdbc
4
+ class Railtie < ::Rails::Railtie
5
+ rake_tasks do
6
+ if defined? ActiveRecord::Railtie # only if AR being used
7
+ load File.expand_path('tasks.rb', File.dirname(__FILE__))
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ require 'arjdbc'
2
+ require 'arjdbc/sqlite3/adapter'
3
+ require 'arjdbc/sqlite3/connection_methods'
@@ -0,0 +1,654 @@
1
+ ArJdbc.load_java_part :SQLite3
2
+
3
+ require 'arjdbc/sqlite3/explain_support'
4
+ require 'arjdbc/util/table_copier'
5
+
6
+ module ArJdbc
7
+ module SQLite3
8
+ include Util::TableCopier
9
+
10
+ JdbcConnection = ::ActiveRecord::ConnectionAdapters::SQLite3JdbcConnection
11
+
12
+ # @deprecated
13
+ # @see ActiveRecord::ConnectionAdapters::JdbcAdapter#jdbc_connection_class
14
+ def self.jdbc_connection_class; JdbcConnection end
15
+
16
+ # @see ActiveRecord::ConnectionAdapters::JdbcColumn#column_types
17
+ def self.column_selector
18
+ [ /sqlite/i, lambda { |config, column| column.extend(ColumnMethods) } ]
19
+ end
20
+
21
+ # @private
22
+ # @see ActiveRecord::ConnectionAdapters::JdbcColumn
23
+ module ColumnMethods
24
+
25
+ # @override {ActiveRecord::ConnectionAdapters::JdbcColumn#init_column}
26
+ def init_column(name, default, *args)
27
+ if default =~ /NULL/
28
+ @default = nil
29
+ else
30
+ super
31
+ end
32
+ end
33
+
34
+ # @override {ActiveRecord::ConnectionAdapters::JdbcColumn#default_value}
35
+ def default_value(value)
36
+ # JDBC returns column default strings with actual single quotes :
37
+ return $1 if value =~ /^'(.*)'$/
38
+
39
+ value
40
+ end
41
+
42
+ # @override {ActiveRecord::ConnectionAdapters::Column#type_cast}
43
+ def type_cast(value)
44
+ return nil if value.nil?
45
+ case type
46
+ when :string then value
47
+ when :primary_key
48
+ value.respond_to?(:to_i) ? value.to_i : ( value ? 1 : 0 )
49
+ when :float then value.to_f
50
+ when :decimal then self.class.value_to_decimal(value)
51
+ when :boolean then self.class.value_to_boolean(value)
52
+ else super
53
+ end
54
+ end
55
+
56
+ private
57
+
58
+ # @override {ActiveRecord::ConnectionAdapters::Column#simplified_type}
59
+ def simplified_type(field_type)
60
+ case field_type
61
+ when /boolean/i then :boolean
62
+ when /text/i then :text
63
+ when /varchar/i then :string
64
+ when /int/i then :integer
65
+ when /float/i then :float
66
+ when /real|decimal/i then
67
+ extract_scale(field_type) == 0 ? :integer : :decimal
68
+ when /datetime/i then :datetime
69
+ when /date/i then :date
70
+ when /time/i then :time
71
+ when /blob/i then :binary
72
+ else super
73
+ end
74
+ end
75
+
76
+ # @override {ActiveRecord::ConnectionAdapters::Column#extract_limit}
77
+ def extract_limit(sql_type)
78
+ return nil if sql_type =~ /^(real)\(\d+/i
79
+ super
80
+ end
81
+
82
+ def extract_precision(sql_type)
83
+ case sql_type
84
+ when /^(real)\((\d+)(,\d+)?\)/i then $2.to_i
85
+ else super
86
+ end
87
+ end
88
+
89
+ def extract_scale(sql_type)
90
+ case sql_type
91
+ when /^(real)\((\d+)\)/i then 0
92
+ when /^(real)\((\d+)(,(\d+))\)/i then $4.to_i
93
+ else super
94
+ end
95
+ end
96
+
97
+ end
98
+
99
+ # @see ActiveRecord::ConnectionAdapters::Jdbc::ArelSupport
100
+ def self.arel_visitor_type(config = nil)
101
+ ::Arel::Visitors::SQLite
102
+ end
103
+
104
+ # @see ActiveRecord::ConnectionAdapters::JdbcAdapter#bind_substitution
105
+ # @private
106
+ class BindSubstitution < ::Arel::Visitors::SQLite
107
+ include ::Arel::Visitors::BindVisitor
108
+ end if defined? ::Arel::Visitors::BindVisitor
109
+
110
+ ADAPTER_NAME = 'SQLite'.freeze
111
+
112
+ def adapter_name
113
+ ADAPTER_NAME
114
+ end
115
+
116
+ NATIVE_DATABASE_TYPES = {
117
+ :primary_key => nil,
118
+ :string => { :name => "varchar", :limit => 255 },
119
+ :text => { :name => "text" },
120
+ :integer => { :name => "integer" },
121
+ :float => { :name => "float" },
122
+ # :real => { :name=>"real" },
123
+ :decimal => { :name => "decimal" },
124
+ :datetime => { :name => "datetime" },
125
+ :timestamp => { :name => "datetime" },
126
+ :time => { :name => "time" },
127
+ :date => { :name => "date" },
128
+ :binary => { :name => "blob" },
129
+ :boolean => { :name => "boolean" }
130
+ }
131
+ NATIVE_DATABASE_TYPES.update(
132
+ :string => { :name => "varchar" }
133
+ ) if AR42
134
+
135
+ # @override
136
+ def native_database_types
137
+ types = NATIVE_DATABASE_TYPES.dup
138
+ types[:primary_key] = default_primary_key_type
139
+ types
140
+ end
141
+
142
+ def default_primary_key_type
143
+ if supports_autoincrement?
144
+ 'integer PRIMARY KEY AUTOINCREMENT NOT NULL'
145
+ else
146
+ 'integer PRIMARY KEY NOT NULL'
147
+ end
148
+ end
149
+
150
+ # @override
151
+ def supports_ddl_transactions?
152
+ true
153
+ end
154
+
155
+ # @override
156
+ def supports_savepoints?
157
+ sqlite_version >= '3.6.8'
158
+ end
159
+
160
+ # @override
161
+ def supports_partial_index?
162
+ sqlite_version >= '3.8.0'
163
+ end
164
+
165
+ # @override
166
+ def supports_add_column?
167
+ true
168
+ end
169
+
170
+ # @override
171
+ def supports_count_distinct?
172
+ true
173
+ end
174
+
175
+ # @override
176
+ def supports_autoincrement?
177
+ true
178
+ end
179
+
180
+ # @override
181
+ def supports_migrations?
182
+ true
183
+ end
184
+
185
+ # @override
186
+ def supports_primary_key?
187
+ true
188
+ end
189
+
190
+ # @override
191
+ def supports_add_column?
192
+ true
193
+ end
194
+
195
+ # @override
196
+ def supports_count_distinct?
197
+ true
198
+ end
199
+
200
+ # @override
201
+ def supports_autoincrement?
202
+ true
203
+ end
204
+
205
+ # @override
206
+ def supports_index_sort_order?
207
+ true
208
+ end
209
+
210
+ # @override
211
+ def supports_views?
212
+ true
213
+ end
214
+
215
+ def sqlite_version
216
+ @sqlite_version ||= Version.new(select_value('SELECT sqlite_version(*)'))
217
+ end
218
+ private :sqlite_version
219
+
220
+ # @override
221
+ def quote(value, column = nil)
222
+ return value if sql_literal?(value)
223
+
224
+ if value.kind_of?(String)
225
+ column_type = column && column.type
226
+ if column_type == :binary
227
+ "x'#{value.unpack("H*")[0]}'"
228
+ else
229
+ super
230
+ end
231
+ else
232
+ super
233
+ end
234
+ end
235
+
236
+ def quote_table_name_for_assignment(table, attr)
237
+ quote_column_name(attr)
238
+ end if ::ActiveRecord::VERSION::MAJOR >= 4
239
+
240
+ def type_cast(value, column)
241
+ return value.to_f if BigDecimal === value
242
+ return super unless String === value
243
+ return super unless column && value
244
+
245
+ value = super
246
+ if column.type == :string &&
247
+ value.respond_to?(:encoding) && value.encoding == Encoding::ASCII_8BIT
248
+ logger.error "Binary data inserted for `string` type on column `#{column.name}`" if logger
249
+ value = value.encode Encoding::UTF_8
250
+ end
251
+ value
252
+ end
253
+
254
+ # Quote date/time values for use in SQL input.
255
+ # Includes microseconds if the value is a Time responding to usec.
256
+ # @override
257
+ def quoted_date(value)
258
+ if value.acts_like?(:time) && value.respond_to?(:usec)
259
+ "#{super}.#{sprintf("%06d", value.usec)}"
260
+ else
261
+ super
262
+ end
263
+ end if ::ActiveRecord::VERSION::MAJOR >= 3
264
+
265
+ # @override
266
+ def tables(name = nil, table_name = nil)
267
+ sql = "SELECT name FROM sqlite_master WHERE type = 'table'"
268
+ if table_name
269
+ sql << " AND name = #{quote_table_name(table_name)}"
270
+ else
271
+ sql << " AND NOT name = 'sqlite_sequence'"
272
+ end
273
+
274
+ select_rows(sql, name).map! { |row| row[0] }
275
+ end
276
+
277
+ # @override
278
+ def table_exists?(table_name)
279
+ table_name && tables(nil, table_name).any?
280
+ end
281
+
282
+ def truncate_fake(table_name, name = nil)
283
+ execute "DELETE FROM #{quote_table_name(table_name)}; VACUUM", name
284
+ end
285
+ # NOTE: not part of official AR (4.2) alias truncate truncate_fake
286
+
287
+ # Returns 62. SQLite supports index names up to 64 characters.
288
+ # The rest is used by Rails internally to perform temporary rename operations.
289
+ # @return [Fixnum]
290
+ def allowed_index_name_length
291
+ index_name_length - 2
292
+ end
293
+
294
+ # NOTE: handled by JdbcAdapter only to have statements in logs :
295
+
296
+ # @override
297
+ def begin_db_transaction
298
+ # NOTE: based on TX mode SQLite-JDBC does "begin;"
299
+ # "begin immediate;" or "begin exclusive;" on setAutoCommit(false)
300
+ log('BEGIN') { @connection.begin }
301
+ end
302
+
303
+ # @override
304
+ def commit_db_transaction
305
+ log('COMMIT') { @connection.commit }
306
+ end
307
+
308
+ # @override
309
+ def rollback_db_transaction
310
+ log('ROLLBACK') { @connection.rollback }
311
+ end
312
+
313
+ # @override on **AR-4.0**
314
+ def begin_isolated_db_transaction(isolation)
315
+ log("/* TRANSACTION_#{isolation.to_s.upcase} */; BEGIN") do
316
+ @connection.begin(isolation)
317
+ end
318
+ end
319
+
320
+ # @override
321
+ def create_savepoint(name = current_savepoint_name(true))
322
+ log("SAVEPOINT #{name}") { @connection.create_savepoint(name) }
323
+ end
324
+
325
+ # @override
326
+ def rollback_to_savepoint(name = current_savepoint_name(true))
327
+ log("ROLLBACK TO SAVEPOINT #{name}") { @connection.rollback_savepoint(name) }
328
+ end
329
+
330
+ # @override
331
+ def release_savepoint(name = current_savepoint_name(false))
332
+ log("RELEASE SAVEPOINT #{name}") { @connection.release_savepoint(name) }
333
+ end
334
+
335
+ # @private
336
+ def recreate_database(name = nil, options = {})
337
+ drop_database(name)
338
+ create_database(name, options)
339
+ end
340
+
341
+ # @private
342
+ def create_database(name = nil, options = {})
343
+ end
344
+
345
+ # @private
346
+ def drop_database(name = nil)
347
+ tables.each { |table| drop_table(table) }
348
+ end
349
+
350
+ def select(sql, name = nil, binds = [])
351
+ result = super # AR::Result (4.0) or Array (<= 3.2)
352
+ if result.respond_to?(:columns) # 4.0
353
+ result.columns.map! do |key| # [ [ 'id', ... ]
354
+ key.is_a?(String) ? key.sub(/^"?\w+"?\./, '') : key
355
+ end
356
+ else
357
+ result.map! do |row| # [ { 'id' => ... }, {...} ]
358
+ record = {}
359
+ row.each_key do |key|
360
+ if key.is_a?(String)
361
+ record[key.sub(/^"?\w+"?\./, '')] = row[key]
362
+ end
363
+ end
364
+ record
365
+ end
366
+ end
367
+ result
368
+ end
369
+
370
+ # @note We have an extra binds argument at the end due AR-2.3 support.
371
+ # @override
372
+ def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
373
+ result = execute(sql, name, binds)
374
+ id_value || last_inserted_id(result)
375
+ end
376
+
377
+ # @note Does not support prepared statements for INSERT statements.
378
+ # @override
379
+ def exec_insert(sql, name, binds, pk = nil, sequence_name = nil)
380
+ # NOTE: since SQLite JDBC does not support executeUpdate but only
381
+ # statement.execute we can not support prepared statements here :
382
+ execute(sql, name, binds)
383
+ end
384
+
385
+ def table_structure(table_name)
386
+ sql = "PRAGMA table_info(#{quote_table_name(table_name)})"
387
+ log(sql, 'SCHEMA') { @connection.execute_query_raw(sql) }
388
+ rescue ActiveRecord::JDBCError => error
389
+ e = ActiveRecord::StatementInvalid.new("Could not find table '#{table_name}'")
390
+ e.set_backtrace error.backtrace
391
+ raise e
392
+ end
393
+
394
+ # @override
395
+ def columns(table_name, name = nil)
396
+ pass_cast_type = respond_to?(:lookup_cast_type)
397
+ table_structure(table_name).map do |field|
398
+ sql_type = field['type']
399
+ if pass_cast_type
400
+ cast_type = lookup_cast_type(sql_type)
401
+ Column.new(field['name'], field['dflt_value'], cast_type, sql_type, field['notnull'] == 0)
402
+ else
403
+ Column.new(field['name'], field['dflt_value'], sql_type, field['notnull'] == 0)
404
+ end
405
+ end
406
+ end
407
+
408
+ # @override
409
+ def primary_key(table_name)
410
+ column = table_structure(table_name).find { |field| field['pk'].to_i == 1 }
411
+ column && column['name']
412
+ end
413
+
414
+ # NOTE: do not override indexes without testing support for 3.7.2 & 3.8.7 !
415
+ # @override
416
+ def indexes(table_name, name = nil)
417
+ # on JDBC 3.7 we'll simply do super since it can not handle "PRAGMA index_info"
418
+ return @connection.indexes(table_name, name) if sqlite_version < '3.8' # super
419
+
420
+ name ||= 'SCHEMA'
421
+ exec_query_raw("PRAGMA index_list(#{quote_table_name(table_name)})", name).map do |row|
422
+ index_name = row['name']
423
+ sql = "SELECT sql FROM sqlite_master"
424
+ sql << " WHERE name=#{quote(index_name)} AND type='index'"
425
+ sql << " UNION ALL "
426
+ sql << "SELECT sql FROM sqlite_temp_master"
427
+ sql << " WHERE name=#{quote(index_name)} AND type='index'"
428
+ where = nil
429
+ exec_query_raw(sql, name) do |index_sql|
430
+ match = /\sWHERE\s+(.+)$/i.match(index_sql)
431
+ where = match[1] if match
432
+ end
433
+ begin
434
+ columns = exec_query_raw("PRAGMA index_info('#{index_name}')", name).map { |col| col['name'] }
435
+ rescue => e
436
+ # NOTE: JDBC <= 3.8.7 bug work-around :
437
+ if e.message && e.message.index('[SQLITE_ERROR] SQL error or missing database')
438
+ columns = []
439
+ end
440
+ raise e
441
+ end
442
+ new_index_definition(table_name, index_name, row['unique'] != 0, columns, nil, nil, where)
443
+ end
444
+ end
445
+
446
+ # @override
447
+ def remove_index!(table_name, index_name)
448
+ execute "DROP INDEX #{quote_column_name(index_name)}"
449
+ end
450
+
451
+ # @override
452
+ def rename_table(table_name, new_name)
453
+ execute "ALTER TABLE #{quote_table_name(table_name)} RENAME TO #{quote_table_name(new_name)}"
454
+ rename_table_indexes(table_name, new_name) if respond_to?(:rename_table_indexes) # AR-4.0 SchemaStatements
455
+ end
456
+
457
+ # SQLite has an additional restriction on the ALTER TABLE statement.
458
+ # @see http://www.sqlite.org/lang_altertable.html
459
+ def valid_alter_table_options( type, options)
460
+ type.to_sym != :primary_key
461
+ end
462
+
463
+ def add_column(table_name, column_name, type, options = {})
464
+ if supports_add_column? && valid_alter_table_options( type, options )
465
+ super(table_name, column_name, type, options)
466
+ else
467
+ alter_table(table_name) do |definition|
468
+ definition.column(column_name, type, options)
469
+ end
470
+ end
471
+ end
472
+
473
+ if ActiveRecord::VERSION::MAJOR >= 4
474
+
475
+ # @private
476
+ def remove_column(table_name, column_name, type = nil, options = {})
477
+ alter_table(table_name) do |definition|
478
+ definition.remove_column column_name
479
+ end
480
+ end
481
+
482
+ else
483
+
484
+ # @private
485
+ def remove_column(table_name, *column_names)
486
+ if column_names.empty?
487
+ raise ArgumentError.new(
488
+ "You must specify at least one column name." +
489
+ " Example: remove_column(:people, :first_name)"
490
+ )
491
+ end
492
+ column_names.flatten.each do |column_name|
493
+ alter_table(table_name) do |definition|
494
+ definition.columns.delete(definition[column_name])
495
+ end
496
+ end
497
+ end
498
+ alias :remove_columns :remove_column
499
+
500
+ end
501
+
502
+ def change_column_default(table_name, column_name, default) #:nodoc:
503
+ alter_table(table_name) do |definition|
504
+ definition[column_name].default = default
505
+ end
506
+ end
507
+
508
+ def change_column_null(table_name, column_name, null, default = nil)
509
+ unless null || default.nil?
510
+ execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
511
+ end
512
+ alter_table(table_name) do |definition|
513
+ definition[column_name].null = null
514
+ end
515
+ end
516
+
517
+ def change_column(table_name, column_name, type, options = {})
518
+ alter_table(table_name) do |definition|
519
+ include_default = options_include_default?(options)
520
+ definition[column_name].instance_eval do
521
+ self.type = type
522
+ self.limit = options[:limit] if options.include?(:limit)
523
+ self.default = options[:default] if include_default
524
+ self.null = options[:null] if options.include?(:null)
525
+ self.precision = options[:precision] if options.include?(:precision)
526
+ self.scale = options[:scale] if options.include?(:scale)
527
+ end
528
+ end
529
+ end
530
+
531
+ def rename_column(table_name, column_name, new_column_name)
532
+ unless columns(table_name).detect{|c| c.name == column_name.to_s }
533
+ raise ActiveRecord::ActiveRecordError, "Missing column #{table_name}.#{column_name}"
534
+ end
535
+ alter_table(table_name, :rename => {column_name.to_s => new_column_name.to_s})
536
+ rename_column_indexes(table_name, column_name, new_column_name) if respond_to?(:rename_column_indexes) # AR-4.0 SchemaStatements
537
+ end
538
+
539
+ # @private
540
+ def add_lock!(sql, options)
541
+ sql # SELECT ... FOR UPDATE is redundant since the table is locked
542
+ end if ::ActiveRecord::VERSION::MAJOR < 3
543
+
544
+ def empty_insert_statement_value
545
+ # inherited (default) on 3.2 : "VALUES(DEFAULT)"
546
+ # inherited (default) on 4.0 : "DEFAULT VALUES"
547
+ # re-defined in native adapter on 3.2 "VALUES(NULL)"
548
+ # on 4.0 no longer re-defined (thus inherits default)
549
+ "DEFAULT VALUES"
550
+ end
551
+
552
+ def encoding
553
+ select_value 'PRAGMA encoding'
554
+ end
555
+
556
+ def last_insert_id
557
+ @connection.last_insert_rowid
558
+ end
559
+
560
+ protected
561
+
562
+ def last_inserted_id(result)
563
+ super || last_insert_id # NOTE: #last_insert_id call should not be needed
564
+ end
565
+
566
+ def translate_exception(exception, message)
567
+ if msg = exception.message
568
+ # SQLite 3.8.2 returns a newly formatted error message:
569
+ # UNIQUE constraint failed: *table_name*.*column_name*
570
+ # Older versions of SQLite return:
571
+ # column *column_name* is not unique
572
+ if msg.index('UNIQUE constraint failed: ') ||
573
+ msg =~ /column(s)? .* (is|are) not unique/
574
+ return ::ActiveRecord::RecordNotUnique.new(message, exception)
575
+ end
576
+ end
577
+ super
578
+ end
579
+
580
+ # @private available in native adapter way back to AR-2.3
581
+ class Version
582
+ include Comparable
583
+
584
+ def initialize(version_string)
585
+ @version = version_string.split('.').map!(&:to_i)
586
+ end
587
+
588
+ def <=>(version_string)
589
+ @version <=> version_string.split('.').map!(&:to_i)
590
+ end
591
+
592
+ def to_s
593
+ @version.join('.')
594
+ end
595
+
596
+ end
597
+
598
+ end
599
+ end
600
+
601
+ module ActiveRecord::ConnectionAdapters
602
+
603
+ remove_const(:SQLite3Adapter) if const_defined?(:SQLite3Adapter)
604
+ class SQLite3Adapter < JdbcAdapter
605
+ include ::ArJdbc::SQLite3
606
+ include ::ArJdbc::SQLite3::ExplainSupport
607
+
608
+ # @private
609
+ Version = ArJdbc::SQLite3::Version
610
+
611
+ class Column < JdbcColumn
612
+ include ::ArJdbc::SQLite3::ColumnMethods
613
+
614
+ def initialize(name, *args)
615
+ if Hash === name
616
+ super
617
+ else
618
+ super(nil, name, *args)
619
+ end
620
+ end
621
+
622
+ def self.string_to_binary(value)
623
+ value
624
+ end
625
+
626
+ def self.binary_to_string(value)
627
+ if value.respond_to?(:encoding) && value.encoding != Encoding::ASCII_8BIT
628
+ value = value.force_encoding(Encoding::ASCII_8BIT)
629
+ end
630
+ value
631
+ end
632
+ end
633
+
634
+ end
635
+
636
+ # NOTE: SQLite3Column exists in native adapter since AR 4.0
637
+ remove_const(:SQLite3Column) if const_defined?(:SQLite3Column)
638
+ SQLite3Column = SQLite3Adapter::Column
639
+
640
+ if ActiveRecord::VERSION::MAJOR <= 3
641
+ remove_const(:SQLiteColumn) if const_defined?(:SQLiteColumn)
642
+ SQLiteColumn = SQLite3Column
643
+
644
+ remove_const(:SQLiteAdapter) if const_defined?(:SQLiteAdapter)
645
+
646
+ SQLiteAdapter = SQLite3Adapter
647
+ end
648
+ end
649
+
650
+ module ArJdbc
651
+ module SQLite3
652
+ Column = ::ActiveRecord::ConnectionAdapters::SQLite3Adapter::Column
653
+ end
654
+ end