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.
- data/.travis.yml +14 -0
- data/CHANGELOG +5 -0
- data/HOW_TO_RELEASE +4 -4
- data/LICENSE +1 -1
- data/README.md +121 -14
- data/Rakefile +38 -53
- data/adapter_extensions.gemspec +4 -2
- data/lib/adapter_extensions/active_record/adapters/abstract_adapter.rb +9 -0
- data/lib/adapter_extensions/active_record/adapters/mysql2_adapter.rb +6 -0
- data/lib/adapter_extensions/active_record/adapters/mysql_adapter.rb +6 -0
- data/lib/adapter_extensions/active_record/adapters/postgresql_adapter.rb +6 -0
- data/lib/adapter_extensions/active_record/adapters/sqlserver_adapter.rb +6 -0
- data/lib/adapter_extensions/adapters/abstract_adapter.rb +44 -0
- data/lib/adapter_extensions/adapters/mysql_adapter.rb +73 -0
- data/lib/adapter_extensions/adapters/postgresql_adapter.rb +47 -0
- data/lib/adapter_extensions/adapters/sqlserver_adapter.rb +63 -0
- data/lib/adapter_extensions/base.rb +19 -0
- data/lib/adapter_extensions/version.rb +1 -1
- data/lib/adapter_extensions.rb +17 -8
- data/test/abstract_adapter_test.rb +10 -4
- data/test/config/database.yml +15 -0
- data/test/{connection/mysql/setup.sql → config/databases/mysql_setup.sql} +0 -0
- data/test/{connection/postgresql/setup.sql → config/databases/postgresql_setup.sql} +0 -0
- data/test/config/gemfiles/.gitignore +1 -0
- data/test/config/gemfiles/Gemfile.rails-3.0.x +3 -0
- data/test/config/gemfiles/Gemfile.rails-3.1.x +3 -0
- data/test/config/gemfiles/Gemfile.rails-3.2.x +3 -0
- data/test/config/gemfiles/common.rb +22 -0
- data/test/integration/adapter_test.rb +23 -7
- data/test/test_helper.rb +3 -4
- data/test/unit/sqlserver_test_ignored.rb +89 -0
- metadata +86 -88
- data/lib/adapter_extensions/connection_adapters/abstract_adapter.rb +0 -50
- data/lib/adapter_extensions/connection_adapters/mysql_adapter.rb +0 -90
- data/lib/adapter_extensions/connection_adapters/postgresql_adapter.rb +0 -52
- data/lib/adapter_extensions/connection_adapters/sqlserver_adapter.rb +0 -44
- data/test/connection/mysql/connection.rb +0 -27
- 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
|
-
|
8
|
+
|
9
|
+
class MyAdapter
|
10
|
+
include AdapterExtensions::AbstractAdapter
|
11
|
+
|
6
12
|
attr_accessor :query
|
7
|
-
|
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
|
File without changes
|
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
*.lock
|
@@ -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
|
-
|
7
|
-
|
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
|
-
|
11
|
-
|
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
|
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
|
-
|
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
|
-
-
|
9
|
+
- Thibaut Barrère
|
15
10
|
autorequire:
|
16
11
|
bindir: bin
|
17
12
|
cert_chain: []
|
18
|
-
|
19
|
-
|
20
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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/
|
89
|
-
- lib/adapter_extensions/
|
90
|
-
- lib/adapter_extensions/
|
91
|
-
- lib/adapter_extensions/
|
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/
|
95
|
-
- test/
|
96
|
-
- test/
|
97
|
-
- test/
|
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
|
-
|
120
|
-
|
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.
|
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
|