adapter_extensions 0.9.5 → 1.0.0.rc1

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 (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