activerecord-jdbcvertica-adapter 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d8318f964be5c0fda875c96fe3c5136e02d0ff73
4
- data.tar.gz: a9ab0afc7b2d5b5e67d6f9a80362949128c21994
3
+ metadata.gz: 2411f766a5415371744b5ae088f649a194bca87d
4
+ data.tar.gz: 75538ba4703aa40da5ce94bda56da15da8adc8b2
5
5
  SHA512:
6
- metadata.gz: 190ff0e13bbb386942cac0d7d1f20ab723c6554de401da9f8f7677a12195a8f5b05446de9973a222aa002ab571e464e1389e410e1f01da0d61fecff010300c73
7
- data.tar.gz: cf0b1dacef7b49c9894c51ca33e7237df99c8cbcac3ad9c3ab7e88f74d00f0f032530c9d8d8a25042d449469d5ebf668327e50c774e6a9949045b31b217d11d7
6
+ metadata.gz: 9eeefd2cacc1262b89b2ea25d71bc5b28fd5501ef9410ec9742a025bb8f4b7e405ee6bfb83db397aa8c850b073f945deee2ae6b2b15f6f8bdd5f5b4f321f31df
7
+ data.tar.gz: ddb252641d5a599d17ba58209a0106316b9d90da5d8e77c3caaf04a07d415bc4ca1cea58feaff12b954beb3614abd219433dfd712651343bed0d8bb8add7e0ee
@@ -1,7 +1,7 @@
1
1
  module Activerecord
2
2
  module Jdbcvertica
3
3
  module Adapter
4
- VERSION = "0.0.7"
4
+ VERSION = "0.0.8"
5
5
  end
6
6
  end
7
7
  end
@@ -1,4 +1,5 @@
1
1
  require 'arjdbc/vertica/column'
2
+ require 'securerandom'
2
3
 
3
4
  # Load a mapping for the "text" type that will actually work
4
5
  ::ActiveRecord::ConnectionAdapters::JdbcTypeConverter::AR_TO_JDBC_TYPES[:text] << lambda { |r| r['type_name'] =~ /varchar$/i }
@@ -9,6 +10,26 @@ module ::ActiveRecord
9
10
  def self.sequence_name
10
11
  "#{self.table_name}_#{self.primary_key || 'id'}_seq"
11
12
  end
13
+
14
+ def self.bulk_insert(columns, data)
15
+ connection.bulk_insert(self.table_name, self.primary_key, self.sequence_name, columns, data)
16
+ end
17
+
18
+ def self.bulk_insert_records(*records)
19
+ records.flatten!
20
+ data = []
21
+ column_names_without_id = column_names.reject { |name| name == self.primary_key }
22
+
23
+ records.each do |record|
24
+ values = []
25
+ column_names_without_id.each do |column_name|
26
+ values << record.__send__("#{column_name}")
27
+ end
28
+ data << values
29
+ end
30
+
31
+ bulk_insert(column_names_without_id, data)
32
+ end
12
33
  end
13
34
  end
14
35
 
@@ -21,7 +42,7 @@ module ::ArJdbc
21
42
  INSERT_TABLE_EXTRACTION = /into\s+(?<table_name>[^\(]*).*values\s*\(/im
22
43
 
23
44
  NATIVE_DATABASE_TYPES = {
24
- :primary_key => "integer primary key",
45
+ :primary_key => "INTEGER NOT NULL PRIMARY KEY",
25
46
  :string => { :name => "varchar", :limit => 255 },
26
47
  :text => { :name => "varchar", :limit => 15000 },
27
48
  :integer => { :name => "integer" },
@@ -44,9 +65,30 @@ module ::ArJdbc
44
65
  # no op
45
66
  end
46
67
 
68
+ def bulk_insert(table_name, primary_key, sequence_name, column_names, data)
69
+ sql = "INSERT INTO #{table_name} (#{column_names.join(',')},#{primary_key || 'id'}) #{$/}"
70
+ row_count = data.size
71
+ last_index = row_count - 1
72
+ temp_table_name = vertica_random_temp_table_name
73
+ column_types = vertica_column_types_for(table_name, column_names)
74
+
75
+ sql << "SELECT #{temp_table_name}.*, #{sequence_name}.nextval FROM ("
76
+ data.each_with_index do |data_row, index|
77
+ sql << "SELECT #{vertica_bulk_insert_select_for(column_types, data_row)} "
78
+
79
+ unless index == last_index
80
+ sql << "#{$/} UNION ALL #{$/}"
81
+ end
82
+ end
83
+ sql << ") #{temp_table_name};"
84
+
85
+ execute(sql)
86
+ end
87
+
47
88
  def columns(table_name, name = nil)
48
89
  sql = "SELECT * from V_CATALOG.COLUMNS WHERE table_name = '#{table_name}';"
49
90
  raw_columns = execute(sql, name || "SCHEMA")
91
+
50
92
  columns = raw_columns.map do |raw_column|
51
93
  ::ActiveRecord::ConnectionAdapters::VerticaColumn.new(
52
94
  raw_column['column_name'],
@@ -174,6 +216,44 @@ module ::ArJdbc
174
216
  "#{table_name}_#{primary_key_name || 'id'}_seq"
175
217
  end
176
218
 
219
+ ##
220
+ # Custom Vertica methods to allow
221
+ # bulk insert operations on a db engine
222
+ # that does not support multi-insert
223
+ def vertica_bulk_insert_select_for(column_types, data_row)
224
+ insert_values = data_row.each_with_index.map do |value, index|
225
+ "#{quote(value)}::#{column_types[index]}"
226
+ end
227
+
228
+ return insert_values.join(",")
229
+ end
230
+
231
+ def vertica_column_types_for(table_name, column_names)
232
+ column_names.map { |column_name| vertica_column_type_for(table_name, column_name) }
233
+ end
234
+
235
+ def vertica_column_type_for(table_name, column_name)
236
+ column = vertica_memoized_columns(table_name).find { |column| column.name == "#{column_name}" }
237
+ return column.sql_type if column
238
+ return nil
239
+ end
240
+
241
+ def vertica_memoized_columns(table_name, name = nil)
242
+ @vertica_memoized_columns ||= {}
243
+ normalized_table_name = "#{table_name}"
244
+
245
+ unless @vertica_memoized_columns.has_key?(normalized_table_name)
246
+ @vertica_memoized_columns[normalized_table_name] = columns(table_name, name)
247
+ end
248
+
249
+ return @vertica_memoized_columns[normalized_table_name]
250
+ end
251
+
252
+ def vertica_random_temp_table_name
253
+ # Generate a Random "table_name" to prevent collisions (not sure if needed)
254
+ "temporary_table_#{::SecureRandom.hex}"
255
+ end
256
+
177
257
  end
178
258
  end
179
259
 
@@ -0,0 +1,65 @@
1
+ require 'spec_helper'
2
+
3
+ class CreateFullObject < ::ActiveRecord::Migration
4
+ def self.up
5
+ create_table :full_objects do |t|
6
+ t.string :string
7
+ t.text :text
8
+ t.integer :integer
9
+ t.float :float
10
+ t.decimal :decimal
11
+ t.datetime :datetime
12
+ t.time :time
13
+ t.date :date
14
+ t.boolean :boolean
15
+ end
16
+ end
17
+
18
+ def self.down
19
+ if table_exists?(:full_objects)
20
+ drop_table :full_objects
21
+ end
22
+ end
23
+ end
24
+
25
+ class FullObject < ::ActiveRecord::Base
26
+ end
27
+
28
+ describe ::FullObject do
29
+ before do
30
+ CreateFullObject.down
31
+ CreateFullObject.up
32
+ end
33
+
34
+ it "bulk inserts" do
35
+ ::FullObject.count.must_equal(0)
36
+ a = []
37
+ 100.times { a << ["derp"] }
38
+ ::FullObject.bulk_insert([:string], a)
39
+ ::FullObject.count.must_equal(100)
40
+ end
41
+
42
+ it "records with string" do
43
+ ::FullObject.count.must_equal(0)
44
+ a = []
45
+ 100.times { a << FullObject.new(:string => "derp") }
46
+ ::FullObject.bulk_insert_records(a)
47
+ ::FullObject.count.must_equal(100)
48
+ end
49
+
50
+ it "records with integer" do
51
+ ::FullObject.count.must_equal(0)
52
+ a = []
53
+ 100.times { a << FullObject.new(:integer => 1) }
54
+ ::FullObject.bulk_insert_records(a)
55
+ ::FullObject.count.must_equal(100)
56
+ end
57
+
58
+ it "records with DateTime" do
59
+ ::FullObject.count.must_equal(0)
60
+ a = []
61
+ 100.times { a << FullObject.new(:datetime => Time.current) }
62
+ ::FullObject.bulk_insert_records(a)
63
+ ::FullObject.count.must_equal(100)
64
+ end
65
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord-jdbcvertica-adapter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brandon Dewitt
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-01-10 00:00:00.000000000 Z
11
+ date: 2014-01-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -120,6 +120,7 @@ files:
120
120
  - lib/arjdbc/vertica/column.rb
121
121
  - lib/arjdbc/vertica/connection_methods.rb
122
122
  - lib/tasks/vertica_database_tasks.rake
123
+ - spec/bulk_insert_spec.rb
123
124
  - spec/full_object_spec.rb
124
125
  - spec/migrations/column_spec.rb
125
126
  - spec/migrations/index_spec.rb
@@ -150,6 +151,7 @@ signing_key:
150
151
  specification_version: 4
151
152
  summary: An ActiveRecord adapter JDBC
152
153
  test_files:
154
+ - spec/bulk_insert_spec.rb
153
155
  - spec/full_object_spec.rb
154
156
  - spec/migrations/column_spec.rb
155
157
  - spec/migrations/index_spec.rb