adapter_extensions 0.9.5 → 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. data/.travis.yml +14 -0
  2. data/CHANGELOG +5 -0
  3. data/HOW_TO_RELEASE +4 -4
  4. data/LICENSE +1 -1
  5. data/README.md +121 -14
  6. data/Rakefile +38 -53
  7. data/adapter_extensions.gemspec +4 -2
  8. data/lib/adapter_extensions/active_record/adapters/abstract_adapter.rb +9 -0
  9. data/lib/adapter_extensions/active_record/adapters/mysql2_adapter.rb +6 -0
  10. data/lib/adapter_extensions/active_record/adapters/mysql_adapter.rb +6 -0
  11. data/lib/adapter_extensions/active_record/adapters/postgresql_adapter.rb +6 -0
  12. data/lib/adapter_extensions/active_record/adapters/sqlserver_adapter.rb +6 -0
  13. data/lib/adapter_extensions/adapters/abstract_adapter.rb +44 -0
  14. data/lib/adapter_extensions/adapters/mysql_adapter.rb +73 -0
  15. data/lib/adapter_extensions/adapters/postgresql_adapter.rb +47 -0
  16. data/lib/adapter_extensions/adapters/sqlserver_adapter.rb +63 -0
  17. data/lib/adapter_extensions/base.rb +19 -0
  18. data/lib/adapter_extensions/version.rb +1 -1
  19. data/lib/adapter_extensions.rb +17 -8
  20. data/test/abstract_adapter_test.rb +10 -4
  21. data/test/config/database.yml +15 -0
  22. data/test/{connection/mysql/setup.sql → config/databases/mysql_setup.sql} +0 -0
  23. data/test/{connection/postgresql/setup.sql → config/databases/postgresql_setup.sql} +0 -0
  24. data/test/config/gemfiles/.gitignore +1 -0
  25. data/test/config/gemfiles/Gemfile.rails-3.0.x +3 -0
  26. data/test/config/gemfiles/Gemfile.rails-3.1.x +3 -0
  27. data/test/config/gemfiles/Gemfile.rails-3.2.x +3 -0
  28. data/test/config/gemfiles/common.rb +22 -0
  29. data/test/integration/adapter_test.rb +23 -7
  30. data/test/test_helper.rb +3 -4
  31. data/test/unit/sqlserver_test_ignored.rb +89 -0
  32. metadata +86 -88
  33. data/lib/adapter_extensions/connection_adapters/abstract_adapter.rb +0 -50
  34. data/lib/adapter_extensions/connection_adapters/mysql_adapter.rb +0 -90
  35. data/lib/adapter_extensions/connection_adapters/postgresql_adapter.rb +0 -52
  36. data/lib/adapter_extensions/connection_adapters/sqlserver_adapter.rb +0 -44
  37. data/test/connection/mysql/connection.rb +0 -27
  38. data/test/connection/postgresql/connection.rb +0 -27
@@ -1,18 +1,24 @@
1
1
  require File.dirname(__FILE__) + '/test_helper'
2
2
 
3
+ require 'adapter_extensions/base'
4
+ require 'adapter_extensions/adapters/abstract_adapter'
5
+
3
6
  class AbstractAdapterTest < Test::Unit::TestCase
4
7
  include ActiveRecord::ConnectionAdapters
5
- class MyAdapter < AbstractAdapter
8
+
9
+ class MyAdapter
10
+ include AdapterExtensions::AbstractAdapter
11
+
6
12
  attr_accessor :query
7
- def initialize
8
- super(nil)
9
- end
13
+
10
14
  def tables
11
15
  ['people']
12
16
  end
17
+
13
18
  def execute(query)
14
19
  @query = query
15
20
  end
21
+
16
22
  end
17
23
 
18
24
  attr_accessor :adapter
@@ -0,0 +1,15 @@
1
+ mysql2:
2
+ adapter: mysql2
3
+ database: adapter_extensions_test
4
+ username: root
5
+ encoding: utf8
6
+ local_infile: true
7
+ mysql:
8
+ adapter: mysql
9
+ database: adapter_extensions_test
10
+ username: root
11
+ encoding: utf8
12
+ postgresql:
13
+ adapter: postgresql
14
+ database: adapter_extensions_test
15
+ username: postgres
@@ -0,0 +1 @@
1
+ *.lock
@@ -0,0 +1,3 @@
1
+ require File.dirname(__FILE__) + '/common'
2
+
3
+ declare_gems '3.0.11'
@@ -0,0 +1,3 @@
1
+ require File.dirname(__FILE__) + '/common'
2
+
3
+ declare_gems '3.1.3'
@@ -0,0 +1,3 @@
1
+ require File.dirname(__FILE__) + '/common'
2
+
3
+ declare_gems '3.2.1'
@@ -0,0 +1,22 @@
1
+ def declare_gems(activerecord_version)
2
+ source :rubygems
3
+
4
+ gem 'activerecord', activerecord_version
5
+
6
+ if activerecord_version < '3.1'
7
+ gem 'mysql2', '< 0.3'
8
+ else
9
+ # use our own fork for bulk load support until issue fixed:
10
+ # https://github.com/brianmario/mysql2/pull/242
11
+ gem 'mysql2', :git => 'https://github.com/activewarehouse/mysql2.git'
12
+ end
13
+
14
+ gem 'mysql'
15
+
16
+ gem 'pg'
17
+ gem 'activerecord-sqlserver-adapter'
18
+
19
+ gem 'awesome_print'
20
+ gem 'rake'
21
+ gem 'flexmock'
22
+ end
@@ -2,14 +2,27 @@ require File.dirname(__FILE__) + '/../test_helper'
2
2
 
3
3
  # Integration tests
4
4
  class AdapterTest < Test::Unit::TestCase
5
-
6
- require File.dirname(__FILE__) + "/#{ENV['DB']}_tests"
7
- include "#{ENV['DB'].capitalize}Tests".constantize
5
+
6
+ # quick hack to load adapter-specific tests - TODO: refactor
7
+ # this also allows to run the same tests for mysql and mysql2
8
+ adapter_tests = ENV['DB']
9
+ raise "Missing DB environment variable" unless adapter_tests
10
+ adapter_tests = 'mysql' if adapter_tests == 'mysql2'
11
+ require File.dirname(__FILE__) + "/#{adapter_tests}_tests"
12
+ include "#{adapter_tests.capitalize}Tests".constantize
13
+ # end of hack
14
+
15
+ def setup
16
+ raise "Missing required DB environment variable" unless ENV['DB']
17
+ configs = YAML.load_file(File.dirname(__FILE__)+ '/../config/database.yml')
18
+ raise "Configuration #{ENV['DB']} not in database.yml!" unless configs[ENV['DB']]
19
+ ActiveRecord::Base.configurations = configs
20
+ ActiveRecord::Base.establish_connection(ENV['DB'])
21
+ end
8
22
 
9
23
  def select_value(query)
10
- value = connection.select_value(query)
11
- value = Integer(value) if ENV['DB'] =~ /postgresql/
12
- value
24
+ # mysql and postgresql will return a string, while mysql2 will return an integer here - smooth things out
25
+ Integer(connection.select_value(query))
13
26
  end
14
27
 
15
28
  def test_add_select_into_table
@@ -74,6 +87,9 @@ class AdapterTest < Test::Unit::TestCase
74
87
  end
75
88
 
76
89
  def test_bulk_load_interprets_empty_strings_as_nulls
90
+ # known issue with mysql - test only on other dbs
91
+ return if ENV['DB'] =~ /mysql/
92
+
77
93
  connection.truncate('people')
78
94
  options = {:fields => {:delimited_by => ',', :null_string => ''}}
79
95
  connection.bulk_load(File.join(File.dirname(__FILE__), 'people_with_empties.csv'), 'people', options)
@@ -96,7 +112,7 @@ class AdapterTest < Test::Unit::TestCase
96
112
  when 'sqlserver', 'postgresql'
97
113
  assert_equal 'SELECT foo INTO new_table FROM bar',
98
114
  connection.add_select_into_table(new_table_name, sql_query)
99
- when 'mysql'
115
+ when /mysql/
100
116
  assert_equal 'CREATE TABLE new_table SELECT foo FROM bar',
101
117
  connection.add_select_into_table(new_table_name, sql_query)
102
118
  else
data/test/test_helper.rb CHANGED
@@ -1,11 +1,10 @@
1
1
  $:.unshift(File.dirname(__FILE__))
2
2
 
3
3
  require 'test/unit'
4
- require 'rubygems'
5
4
  require 'flexmock/test_unit'
6
5
  require 'pp'
6
+ require 'ap'
7
7
 
8
+ require 'active_record'
8
9
  require File.dirname(__FILE__) + '/../lib/adapter_extensions'
9
-
10
- db = ENV['DB'] ||= 'mysql'
11
- require "connection/#{db}/connection"
10
+ require 'adapter_extensions'
@@ -0,0 +1,89 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class SqlServerTest < Test::Unit::TestCase
4
+
5
+ def adapter
6
+ @adapter ||= begin
7
+ adapter = Object.new
8
+ adapter.extend(AdapterExtensions::AbstractAdapter)
9
+ adapter.extend(AdapterExtensions::SQLServerAdapter)
10
+ adapter
11
+ end
12
+ end
13
+
14
+ def prepare_mocks
15
+ flexmock(File).should_receive(:exist?).with("the_file").and_return(true).once
16
+ flexmock(adapter).should_receive(:tables).and_return(['the_table']).once
17
+ flexmock(ActiveRecord::Base).should_receive(:configurations).and_return(
18
+ 'fake_env' => {
19
+ 'database' => 'the_database',
20
+ 'host' => 'the_host',
21
+ 'username' => 'the_username',
22
+ 'password' => 'the_password'
23
+ }
24
+ )
25
+ end
26
+
27
+ def bulk_load(options)
28
+ options = {:env => 'fake_env'}.merge(options)
29
+ adapter.bulk_load("the_file", "the_table", options)
30
+ end
31
+
32
+ def assert_bulk_command(pattern, options = {})
33
+ prepare_mocks
34
+ command_result = options.delete(:command_successful)
35
+ command_result = true if command_result.nil?
36
+ flexmock(Kernel).should_receive(:system).with(pattern).and_return(command_result)
37
+ bulk_load(options)
38
+ end
39
+
40
+ def test_freebcp_by_default
41
+ assert_bulk_command(/^freebcp/)
42
+ end
43
+
44
+ def test_custom_bin_can_be_specified
45
+ assert_bulk_command(/^bcp /, :bin => 'bcp')
46
+ end
47
+
48
+ def test_command
49
+ assert_bulk_command(/ "the_database\.dbo\.the_table" in "the_file" /)
50
+ end
51
+
52
+ def test_host
53
+ assert_bulk_command(/ \-S "the_host" /)
54
+ end
55
+
56
+ def test_user
57
+ assert_bulk_command(/ \-U "the_username" /)
58
+ end
59
+
60
+ def test_password
61
+ assert_bulk_command(/ \-P "the_password" /)
62
+ end
63
+
64
+ def test_character_format
65
+ assert_bulk_command(/ \-c /)
66
+ end
67
+
68
+ def test_delimited_by
69
+ assert_bulk_command(/ \-t "," /, :fields => { :delimited_by => ',' })
70
+ end
71
+
72
+ def test_max_errors
73
+ assert_bulk_command(/ \-m 1/, :max_errors => 1)
74
+ end
75
+
76
+ def test_failed_command_must_raise
77
+ exception = assert_raise(RuntimeError) do
78
+ assert_bulk_command(//, :command_successful => false)
79
+ end
80
+ assert_equal "bulk load failed!", exception.message
81
+ end
82
+
83
+ def test_unsupported_columns_option
84
+ assert_raise(NotImplementedError) do
85
+ assert_bulk_command(//, :columns => %w(id first_name last_name))
86
+ end
87
+ end
88
+
89
+ end
metadata CHANGED
@@ -1,82 +1,81 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: adapter_extensions
3
- version: !ruby/object:Gem::Version
4
- hash: 49
5
- prerelease:
6
- segments:
7
- - 0
8
- - 9
9
- - 5
10
- version: 0.9.5
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0.rc1
5
+ prerelease: 6
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Anthony Eden
14
- - "Thibaut Barr\xC3\xA8re"
9
+ - Thibaut Barrère
15
10
  autorequire:
16
11
  bindir: bin
17
12
  cert_chain: []
18
-
19
- date: 2011-12-18 00:00:00 Z
20
- dependencies:
21
- - !ruby/object:Gem::Dependency
13
+ date: 2012-03-03 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
22
16
  name: rake
23
- prerelease: false
24
- requirement: &id001 !ruby/object:Gem::Requirement
17
+ requirement: &70258975563120 !ruby/object:Gem::Requirement
25
18
  none: false
26
- requirements:
27
- - - ">="
28
- - !ruby/object:Gem::Version
29
- hash: 57
30
- segments:
31
- - 0
32
- - 8
33
- - 3
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
34
22
  version: 0.8.3
35
23
  type: :runtime
36
- version_requirements: *id001
37
- - !ruby/object:Gem::Dependency
38
- name: activesupport
39
24
  prerelease: false
40
- requirement: &id002 !ruby/object:Gem::Requirement
25
+ version_requirements: *70258975563120
26
+ - !ruby/object:Gem::Dependency
27
+ name: activesupport
28
+ requirement: &70258975562380 !ruby/object:Gem::Requirement
41
29
  none: false
42
- requirements:
43
- - - ">="
44
- - !ruby/object:Gem::Version
45
- hash: 11
46
- segments:
47
- - 2
48
- - 1
49
- - 0
50
- version: 2.1.0
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: 3.0.0
51
34
  type: :runtime
52
- version_requirements: *id002
53
- - !ruby/object:Gem::Dependency
54
- name: activerecord
55
35
  prerelease: false
56
- requirement: &id003 !ruby/object:Gem::Requirement
36
+ version_requirements: *70258975562380
37
+ - !ruby/object:Gem::Dependency
38
+ name: activerecord
39
+ requirement: &70258975561480 !ruby/object:Gem::Requirement
57
40
  none: false
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- hash: 11
62
- segments:
63
- - 2
64
- - 1
65
- - 0
66
- version: 2.1.0
41
+ requirements:
42
+ - - ! '>='
43
+ - !ruby/object:Gem::Version
44
+ version: 3.0.0
67
45
  type: :runtime
68
- version_requirements: *id003
46
+ prerelease: false
47
+ version_requirements: *70258975561480
48
+ - !ruby/object:Gem::Dependency
49
+ name: flexmock
50
+ requirement: &70258975560780 !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ! '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ type: :development
57
+ prerelease: false
58
+ version_requirements: *70258975560780
59
+ - !ruby/object:Gem::Dependency
60
+ name: cartesian
61
+ requirement: &70258975559900 !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ! '>='
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ type: :development
68
+ prerelease: false
69
+ version_requirements: *70258975559900
69
70
  description: Provides various extensions to the Rails ActiveRecord adapters.
70
- email:
71
+ email:
71
72
  - thibaut.barrere@gmail.com
72
73
  executables: []
73
-
74
74
  extensions: []
75
-
76
75
  extra_rdoc_files: []
77
-
78
- files:
76
+ files:
79
77
  - .gitignore
78
+ - .travis.yml
80
79
  - CHANGELOG
81
80
  - Gemfile
82
81
  - HOW_TO_RELEASE
@@ -85,16 +84,26 @@ files:
85
84
  - Rakefile
86
85
  - adapter_extensions.gemspec
87
86
  - lib/adapter_extensions.rb
88
- - lib/adapter_extensions/connection_adapters/abstract_adapter.rb
89
- - lib/adapter_extensions/connection_adapters/mysql_adapter.rb
90
- - lib/adapter_extensions/connection_adapters/postgresql_adapter.rb
91
- - lib/adapter_extensions/connection_adapters/sqlserver_adapter.rb
87
+ - lib/adapter_extensions/active_record/adapters/abstract_adapter.rb
88
+ - lib/adapter_extensions/active_record/adapters/mysql2_adapter.rb
89
+ - lib/adapter_extensions/active_record/adapters/mysql_adapter.rb
90
+ - lib/adapter_extensions/active_record/adapters/postgresql_adapter.rb
91
+ - lib/adapter_extensions/active_record/adapters/sqlserver_adapter.rb
92
+ - lib/adapter_extensions/adapters/abstract_adapter.rb
93
+ - lib/adapter_extensions/adapters/mysql_adapter.rb
94
+ - lib/adapter_extensions/adapters/postgresql_adapter.rb
95
+ - lib/adapter_extensions/adapters/sqlserver_adapter.rb
96
+ - lib/adapter_extensions/base.rb
92
97
  - lib/adapter_extensions/version.rb
93
98
  - test/abstract_adapter_test.rb
94
- - test/connection/mysql/connection.rb
95
- - test/connection/mysql/setup.sql
96
- - test/connection/postgresql/connection.rb
97
- - test/connection/postgresql/setup.sql
99
+ - test/config/database.yml
100
+ - test/config/databases/mysql_setup.sql
101
+ - test/config/databases/postgresql_setup.sql
102
+ - test/config/gemfiles/.gitignore
103
+ - test/config/gemfiles/Gemfile.rails-3.0.x
104
+ - test/config/gemfiles/Gemfile.rails-3.1.x
105
+ - test/config/gemfiles/Gemfile.rails-3.2.x
106
+ - test/config/gemfiles/common.rb
98
107
  - test/integration/adapter_test.rb
99
108
  - test/integration/empty.csv
100
109
  - test/integration/mysql_tests.rb
@@ -103,40 +112,29 @@ files:
103
112
  - test/integration/people_with_empties.csv
104
113
  - test/integration/postgresql_tests.rb
105
114
  - test/test_helper.rb
115
+ - test/unit/sqlserver_test_ignored.rb
106
116
  homepage: https://github.com/activewarehouse/adapter_extensions
107
117
  licenses: []
108
-
109
118
  post_install_message:
110
119
  rdoc_options: []
111
-
112
- require_paths:
120
+ require_paths:
113
121
  - lib
114
- required_ruby_version: !ruby/object:Gem::Requirement
122
+ required_ruby_version: !ruby/object:Gem::Requirement
115
123
  none: false
116
- requirements:
117
- - - ">="
118
- - !ruby/object:Gem::Version
119
- hash: 3
120
- segments:
121
- - 0
122
- version: "0"
123
- required_rubygems_version: !ruby/object:Gem::Requirement
124
+ requirements:
125
+ - - ! '>='
126
+ - !ruby/object:Gem::Version
127
+ version: '0'
128
+ required_rubygems_version: !ruby/object:Gem::Requirement
124
129
  none: false
125
- requirements:
126
- - - ">="
127
- - !ruby/object:Gem::Version
128
- hash: 23
129
- segments:
130
- - 1
131
- - 3
132
- - 6
130
+ requirements:
131
+ - - ! '>='
132
+ - !ruby/object:Gem::Version
133
133
  version: 1.3.6
134
134
  requirements: []
135
-
136
135
  rubyforge_project: activewarehouse
137
- rubygems_version: 1.8.10
136
+ rubygems_version: 1.8.15
138
137
  signing_key:
139
138
  specification_version: 3
140
139
  summary: Extensions to Rails ActiveRecord adapters.
141
140
  test_files: []
142
-
@@ -1,50 +0,0 @@
1
- # This source file contains extensions to the abstract adapter.
2
- module ActiveRecord #:nodoc:
3
- module ConnectionAdapters #:nodoc:
4
- # Extensions to the AbstractAdapter. In some cases a default implementation
5
- # is provided, in others it is adapter-dependent and the method will
6
- # raise a NotImplementedError if the adapter does not implement that method
7
- class AbstractAdapter
8
- # Truncate the specified table - allow to pass an optional string
9
- # to let the called add extra parameters like RESET IDENTITY for pg
10
- def truncate(table_name, options=nil)
11
- statement = [
12
- 'TRUNCATE TABLE',
13
- table_name,
14
- options
15
- ].compact.join(' ')
16
- execute(statement)
17
- end
18
-
19
- # Bulk loading interface. Load the data from the specified file into the
20
- # given table. Note that options will be adapter-dependent.
21
- def bulk_load(file, table_name, options={})
22
- raise ArgumentError, "#{file} does not exist" unless File.exist?(file)
23
- raise ArgumentError, "#{table_name} does not exist" unless tables.include?(table_name)
24
- do_bulk_load(file, table_name, options)
25
- end
26
-
27
- # SQL select into statement constructs a new table from the results
28
- # of a select. It is used to select data from a table and create a new
29
- # table with its result set at the same time. Note that this method
30
- # name does not necessarily match the implementation. E.g. MySQL's
31
- # version of this is 'CREATE TABLE ... AS SELECT ...'
32
- def support_select_into_table?
33
- false
34
- end
35
-
36
- # Add a chunk of SQL to the given query that will create a new table and
37
- # execute the select into that table.
38
- def add_select_into_table(new_table_name, sql_query)
39
- raise NotImplementedError, "add_select_into_table is an abstract method"
40
- end
41
-
42
- protected
43
-
44
- # for subclasses to implement
45
- def do_bulk_load(file, table_name, options={})
46
- raise NotImplementedError, "do_bulk_load is an abstract method"
47
- end
48
- end
49
- end
50
- end
@@ -1,90 +0,0 @@
1
- # lots of folks doing something like this now - take a look for other good ideas
2
- # https://github.com/jsuchal/activerecord-fast-import/blob/master/lib/activerecord-fast-import.rb
3
- # https://github.com/EmmanuelOga/load_data_infile/blob/master/lib/load_data_infile.rb
4
-
5
- # Source code for the MysqlAdapter extensions.
6
- module ActiveRecord #:nodoc:
7
- module ConnectionAdapters #:nodoc:
8
- # Adds new functionality to ActiveRecord MysqlAdapter.
9
- class MysqlAdapter < AbstractAdapter
10
-
11
- def support_select_into_table?
12
- true
13
- end
14
-
15
- # Inserts an INTO table_name clause to the sql_query.
16
- def add_select_into_table(new_table_name, sql_query)
17
- "CREATE TABLE #{new_table_name} " + sql_query
18
- end
19
-
20
- # Copy the specified table.
21
- def copy_table(old_table_name, new_table_name)
22
- transaction do
23
- execute "CREATE TABLE #{new_table_name} LIKE #{old_table_name}"
24
- execute "INSERT INTO #{new_table_name} SELECT * FROM #{old_table_name}"
25
- end
26
- end
27
-
28
- def disable_keys(table)
29
- execute("ALTER TABLE #{table} DISABLE KEYS")
30
- end
31
-
32
- def enable_keys(table)
33
- execute("ALTER TABLE #{table} ENABLE KEYS")
34
- end
35
-
36
- def with_keys_disabled(table)
37
- disable_keys(table)
38
- yield
39
- ensure
40
- enable_keys(table)
41
- end
42
-
43
- protected
44
- # Call +bulk_load+, as that method wraps this method.
45
- #
46
- # Bulk load the data in the specified file. This implementation always uses the LOCAL keyword
47
- # so the file must be found locally, not on the remote server, to be loaded.
48
- #
49
- # Options:
50
- # * <tt>:ignore</tt> -- Ignore the specified number of lines from the source file
51
- # * <tt>:columns</tt> -- Array of column names defining the source file column order
52
- # * <tt>:fields</tt> -- Hash of options for fields:
53
- # * <tt>:delimited_by</tt> -- The field delimiter
54
- # * <tt>:enclosed_by</tt> -- The field enclosure
55
- # * <tt>:replace</tt> -- Add in REPLACE to LOAD DATA INFILE command
56
- # * <tt>:disable_keys</tt> -- if set to true, disable keys, loads, then enables again
57
- def do_bulk_load(file, table_name, options={})
58
- return if File.size(file) == 0
59
-
60
- # an unfortunate hack - setting the bulk load option after the connection has been
61
- # established does not seem to have any effect, and since the connection is made when
62
- # active-record is loaded, there's no chance for us to sneak it in earlier. So we
63
- # disconnect, set the option, then reconnect - fortunately, this only needs to happen once.
64
- unless @bulk_load_enabled
65
- disconnect!
66
- @connection.options(Mysql::OPT_LOCAL_INFILE, true)
67
- connect
68
- @bulk_load_enabled = true
69
- end
70
-
71
- q = "LOAD DATA LOCAL INFILE '#{file}' #{options[:replace] ? 'REPLACE' : ''} INTO TABLE #{table_name}"
72
- if options[:fields]
73
- q << " FIELDS"
74
- q << " TERMINATED BY '#{options[:fields][:delimited_by]}'" if options[:fields][:delimited_by]
75
- q << " ENCLOSED BY '#{options[:fields][:enclosed_by]}'" if options[:fields][:enclosed_by]
76
- end
77
- q << " IGNORE #{options[:ignore]} LINES" if options[:ignore]
78
- q << " (#{options[:columns].map { |c| quote_column_name(c.to_s) }.join(',')})" if options[:columns]
79
-
80
- if options[:disable_keys]
81
- with_keys_disabled(table_name) { execute(q) }
82
- else
83
- execute(q)
84
- end
85
-
86
- end
87
-
88
- end
89
- end
90
- end
@@ -1,52 +0,0 @@
1
- # Source code for the PostgreSQLAdapter extensions.
2
- module ActiveRecord #:nodoc:
3
- module ConnectionAdapters #:nodoc:
4
- # Adds new functionality to ActiveRecord PostgreSQLAdapter.
5
- class PostgreSQLAdapter < AbstractAdapter
6
- def support_select_into_table?
7
- true
8
- end
9
-
10
- # Inserts an INTO table_name clause to the sql_query.
11
- def add_select_into_table(new_table_name, sql_query)
12
- sql_query.sub(/FROM/i, "INTO #{new_table_name} FROM")
13
- end
14
-
15
- # Copy the specified table.
16
- def copy_table(old_table_name, new_table_name)
17
- execute add_select_into_table(new_table_name, "SELECT * FROM #{old_table_name}")
18
- end
19
-
20
- protected
21
- # Call +bulk_load+, as that method wraps this method.
22
- #
23
- # Bulk load the data in the specified file.
24
- #
25
- # Options:
26
- # * <tt>:ignore</tt> -- Ignore the specified number of lines from the source file. In the case of PostgreSQL
27
- # only the first line will be ignored from the source file regardless of the number of lines specified.
28
- # * <tt>:columns</tt> -- Array of column names defining the source file column order
29
- # * <tt>:fields</tt> -- Hash of options for fields:
30
- # * <tt>:delimited_by</tt> -- The field delimiter
31
- # * <tt>:null_string</tt> -- The string that should be interpreted as NULL (in addition to \N)
32
- # * <tt>:enclosed_by</tt> -- The field enclosure
33
- def do_bulk_load(file, table_name, options={})
34
- q = "COPY #{table_name} "
35
- q << "(#{options[:columns].join(',')}) " if options[:columns]
36
- q << "FROM '#{File.expand_path(file)}' "
37
- if options[:fields]
38
- q << "WITH "
39
- q << "DELIMITER '#{options[:fields][:delimited_by]}' " if options[:fields][:delimited_by]
40
- q << "NULL '#{options[:fields][:null_string]}'" if options[:fields][:null_string]
41
- if options[:fields][:enclosed_by] || options[:ignore] && options[:ignore] > 0
42
- q << "CSV "
43
- q << "HEADER " if options[:ignore] && options[:ignore] > 0
44
- q << "QUOTE '#{options[:fields][:enclosed_by]}' " if options[:fields][:enclosed_by]
45
- end
46
- end
47
-
48
- execute(q)
49
- end
50
- end
51
- end
52
- end