pg_partitioning 0.0.1
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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +97 -0
- data/Rakefile +23 -0
- data/config/locales/en.yml +28 -0
- data/lib/generators/partitioning_generator.rb +18 -0
- data/lib/pg_partitioning/input_master.rb +83 -0
- data/lib/pg_partitioning/partitioning_master.rb +78 -0
- data/lib/pg_partitioning/printer.rb +28 -0
- data/lib/pg_partitioning/strategies/base.rb +72 -0
- data/lib/pg_partitioning/strategies/date.rb +73 -0
- data/lib/pg_partitioning/strategies/equal.rb +43 -0
- data/lib/pg_partitioning/strategies/step.rb +57 -0
- data/lib/pg_partitioning/version.rb +3 -0
- data/lib/pg_partitioning.rb +4 -0
- data/lib/tasks/pg_partitioning_tasks.rake +4 -0
- data/spec/db_helpers.rb +36 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/models/bandit.rb +4 -0
- data/spec/dummy/app/models/crime.rb +3 -0
- data/spec/dummy/app/models/gang.rb +3 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/bin/setup +29 -0
- data/spec/dummy/config/application.rb +32 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +28 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +41 -0
- data/spec/dummy/config/environments/production.rb +79 -0
- data/spec/dummy/config/environments/test.rb +42 -0
- data/spec/dummy/config/initializers/assets.rb +11 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +56 -0
- data/spec/dummy/config/secrets.yml +22 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/db/migrate/20160306173540_create_gangs.rb +9 -0
- data/spec/dummy/db/migrate/20160306174017_create_bandits.rb +12 -0
- data/spec/dummy/db/migrate/20160306174042_create_crimes.rb +10 -0
- data/spec/dummy/db/schema.rb +47 -0
- data/spec/dummy/log/development.log +3421 -0
- data/spec/dummy/log/production.log +0 -0
- data/spec/dummy/log/test.log +154834 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/factories/bandits.rb +23 -0
- data/spec/factories/crimes.rb +6 -0
- data/spec/factories/gangs.rb +5 -0
- data/spec/input_master_spec.rb +74 -0
- data/spec/models/bandit_spec.rb +13 -0
- data/spec/models/crime_spec.rb +10 -0
- data/spec/models/gang_spec.rb +10 -0
- data/spec/partitioning_master_spec.rb +156 -0
- data/spec/rails_helper.rb +67 -0
- data/spec/shared_examples.rb +28 -0
- data/spec/spec_helper.rb +92 -0
- metadata +213 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 3218f90c14f4626030e7eee68580ba3e8ab6beec
|
4
|
+
data.tar.gz: 6f71ac05ee7bb5fdf82f65335aeba6ab7cc1073a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 2051b32762a47edc84ce1cf597282dc4700280dd7bb32f747497b6d143a7eefe32f712cb44937dd968bddadfc32e2aec5999d14a05b55c3cf22d1177fa820231
|
7
|
+
data.tar.gz: 0b3f91c0c0f69906e733ac45ce794ddacb773bde5bd0e595f2da720d71168a360f9c8711ff96f28044b11d31e333c8595f0dcd4851052633bf97e2fe66748a73
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2016 Victor M.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
= PgPartitioning
|
2
|
+
|
3
|
+
{<img src="https://codeclimate.com/github/victor-magarlamov/pg_partitioning/badges/gpa.svg" />}[https://codeclimate.com/github/victor-magarlamov/pg_partitioning]
|
4
|
+
{<img src="https://codeclimate.com/github/victor-magarlamov/pg_partitioning/badges/coverage.svg" />}[https://codeclimate.com/github/victor-magarlamov/pg_partitioning/coverage]
|
5
|
+
|
6
|
+
This project rocks and uses MIT-LICENSE.
|
7
|
+
|
8
|
+
== Install
|
9
|
+
|
10
|
+
Put this line in your Gemfile:
|
11
|
+
gem 'pg_partitioning'
|
12
|
+
|
13
|
+
Then bundle:
|
14
|
+
% bundle install
|
15
|
+
|
16
|
+
== Usage
|
17
|
+
|
18
|
+
% RAILS_ENV=production rails g partitioning
|
19
|
+
|
20
|
+
1) Select the partitioning mode:
|
21
|
+
* by single column +value+
|
22
|
+
* by dates +template+
|
23
|
+
* by +range+
|
24
|
+
|
25
|
+
2) Enter +table+ name.
|
26
|
+
|
27
|
+
3) Enter +column+ name.
|
28
|
+
|
29
|
+
4) Enter condition depending on the selected mode - template +pattern+ or range +step+.
|
30
|
+
|
31
|
+
What will happen then...
|
32
|
+
|
33
|
+
1) The generator will create two triggers: before insert and after insert. The before insert trigger executes the procedure that created nested table and inserts a new record into it. The after trigger clears the master table.
|
34
|
+
|
35
|
+
2) Foreign keys which reference to the master table will delete.
|
36
|
+
|
37
|
+
3) Old data will be migrated from master table to child tables.
|
38
|
+
|
39
|
+
For more details, see ...
|
40
|
+
|
41
|
+
== Examples
|
42
|
+
|
43
|
+
Given we have table 'bandits':
|
44
|
+
|
45
|
+
| id | name | specialization | born_at
|
46
|
+
|
47
|
+
=== Example 1: Partitioning by single column value
|
48
|
+
|
49
|
+
Enter mode: 0
|
50
|
+
Enter table: bandits
|
51
|
+
Enter column: specialization
|
52
|
+
|
53
|
+
Create two bandits:
|
54
|
+
|
55
|
+
Bandit.create([{name: 'Al Capone', specialization: 'bootlegger'},
|
56
|
+
{name: 'Black Bart', specialization: 'robber'}])
|
57
|
+
|
58
|
+
Now we have three tables:
|
59
|
+
|
60
|
+
* bandits - master - not contains real data
|
61
|
+
* bandits_bootlegger - nested - contains only the bootleggers
|
62
|
+
* bandits_robber - nested - contains only the robbers
|
63
|
+
|
64
|
+
Check this...
|
65
|
+
|
66
|
+
SELECT COUNT(*) FROM bandits; (2)
|
67
|
+
SELECT COUNT(*) FROM ONLY bandits; (0)
|
68
|
+
SELECT COUNT(*) FROM ONLY bandits_bootlegger; (1)
|
69
|
+
SELECT COUNT(*) FROM ONLY bandits_robber; (1)
|
70
|
+
|
71
|
+
=== Example 2: Partitioning by range
|
72
|
+
|
73
|
+
Enter mode: 1
|
74
|
+
Enter table: bandits
|
75
|
+
Enter column: id
|
76
|
+
Enter step: 10
|
77
|
+
|
78
|
+
All bandits with ID from 0 to 9 will be recorded to table 'bandits_0'.
|
79
|
+
All bandits with ID from 10 to 19 will be recorded to table 'bandits_1'.
|
80
|
+
All bandits with ID from 20 to 29 will be recorded to table 'bandits_2' etc.
|
81
|
+
|
82
|
+
=== Example 3: Partitioning by date template
|
83
|
+
|
84
|
+
Enter mode: 2
|
85
|
+
Enter table: bandits
|
86
|
+
Enter column: born_at
|
87
|
+
Enter pattern: YYYYMM
|
88
|
+
|
89
|
+
Create two bandits:
|
90
|
+
|
91
|
+
Bandit.create([{name: 'Al Capone', born_at: '1899-01-17'},
|
92
|
+
{name: 'Charles Luciano', born_at: '1897-11-24'}])
|
93
|
+
|
94
|
+
And now we have two child tables:
|
95
|
+
|
96
|
+
* bandits_1899_01
|
97
|
+
* bandits_1897_11
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'PgPartitioning'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.rdoc')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
Bundler::GemHelper.install_tasks
|
23
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
en:
|
2
|
+
pg_partitioning:
|
3
|
+
enter: "Enter the %{quest}"
|
4
|
+
quests:
|
5
|
+
mode: "type of the partitioning - equal(0), step(1), date(2): "
|
6
|
+
table_name: "name of the table: "
|
7
|
+
column_name: "name of the column: "
|
8
|
+
cond_step: "step (e.g. 1000): "
|
9
|
+
cond_date: "pattern (e.g. YYYY_MM or MM): "
|
10
|
+
failure:
|
11
|
+
answer: "I cannot accept your answer!"
|
12
|
+
mode: "Invalid value."
|
13
|
+
step: "Invalid value. Should be eat then 0"
|
14
|
+
pattern: "Invalid value."
|
15
|
+
no_table: "Table with some column is not exists!"
|
16
|
+
column_type: "Invalid column type."
|
17
|
+
blank_cond: "Value is not set."
|
18
|
+
other: "An error has occurred."
|
19
|
+
progress:
|
20
|
+
insert_master: "Insert master func: %{state}"
|
21
|
+
before_insert_trigger: "Before Insert trigger: %{state}"
|
22
|
+
drop_master: "Drop master func: %{state}"
|
23
|
+
after_insert_trigger: "After Insert trigger: %{state}"
|
24
|
+
drop_fk: "Delete foreign keys: %{state}"
|
25
|
+
migration: "Migrate old data: %{state}"
|
26
|
+
finish: "Done!"
|
27
|
+
messages:
|
28
|
+
partition_mode: "Recommend to set constraint_exclusion in 'partition' state for best perfomance (your current state is %{current})."
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'pg_partitioning/input_master'
|
2
|
+
require 'pg_partitioning/partitioning_master'
|
3
|
+
|
4
|
+
class PartitioningGenerator < Rails::Generators::Base
|
5
|
+
|
6
|
+
def partitioning
|
7
|
+
input_master = PgPartitioning::InputMaster.new
|
8
|
+
input_master.intro
|
9
|
+
|
10
|
+
mode = input_master.ask_mode.to_i
|
11
|
+
table_name = input_master.ask_table_name
|
12
|
+
column_name = input_master.ask_column_name
|
13
|
+
cond = input_master.ask_cond(PgPartitioning::PartitioningMaster::MODES[mode])
|
14
|
+
|
15
|
+
master = PgPartitioning::PartitioningMaster.new(table_name, column_name, mode, cond)
|
16
|
+
master.partitioning
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'pg_partitioning/printer'
|
2
|
+
|
3
|
+
module PgPartitioning
|
4
|
+
class InputMaster
|
5
|
+
include Printer
|
6
|
+
|
7
|
+
%w(mode table_name column_name cond).each do |act|
|
8
|
+
define_method "ask_#{act}" do |argument = nil|
|
9
|
+
begin
|
10
|
+
quest_key = argument.blank? ? act : "#{act}_#{argument}"
|
11
|
+
quest_val = I18n.t "pg_partitioning.quests.#{quest_key}", raise: true
|
12
|
+
res = ask quest_val
|
13
|
+
if send "#{quest_key}_valid?", res
|
14
|
+
return res
|
15
|
+
else
|
16
|
+
alert @error_message
|
17
|
+
send "ask_#{act}", argument unless ENV['RAILS_ENV'] == 'test'
|
18
|
+
end
|
19
|
+
rescue I18n::MissingTranslationData
|
20
|
+
return nil
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def method_missing(name, *args)
|
26
|
+
valid?(*args) if name.to_s.include?('_valid?')
|
27
|
+
end
|
28
|
+
|
29
|
+
def intro
|
30
|
+
info <<-INTRO
|
31
|
+
Hi! It's time to do partitioning)
|
32
|
+
I can do it in different ways:
|
33
|
+
|
34
|
+
by EQUALity
|
35
|
+
- partition will be created by value of column,
|
36
|
+
- in this case you should only set column name;
|
37
|
+
|
38
|
+
by STEP
|
39
|
+
- partition will be created by value of column divided by the step and rounded,
|
40
|
+
- in this case you should else set number of the step,
|
41
|
+
- a type of the column should be a numeric;
|
42
|
+
|
43
|
+
by DATE
|
44
|
+
- partition will be created by pattern from date,
|
45
|
+
- in this case you should else set pattern for parsing the date,
|
46
|
+
- acceptable (itself or in combination): Y, YY, YYY, YYYY, MM, D, DD, DDD, W, WW, HH24
|
47
|
+
- a type of the column should be a date/timestamp.
|
48
|
+
INTRO
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
def ask(text)
|
53
|
+
text_color WHITE
|
54
|
+
print I18n.t('pg_partitioning.enter', quest: text)
|
55
|
+
gets.chomp
|
56
|
+
end
|
57
|
+
|
58
|
+
def valid?(text)
|
59
|
+
res = !text.blank?
|
60
|
+
@error_message = I18n.t 'pg_partitioning.failure.answer' unless res
|
61
|
+
res
|
62
|
+
end
|
63
|
+
|
64
|
+
def mode_valid?(text)
|
65
|
+
res = %w(0 1 2).include? text
|
66
|
+
@error_message = I18n.t 'pg_partitioning.failure.mode' unless res
|
67
|
+
res
|
68
|
+
end
|
69
|
+
|
70
|
+
def cond_step_valid?(text)
|
71
|
+
res = text.to_i > 0
|
72
|
+
@error_message = I18n.t "pg_partitioning.failure.step" unless res
|
73
|
+
res
|
74
|
+
end
|
75
|
+
|
76
|
+
def cond_date_valid?(text)
|
77
|
+
res = /Y{1,4}|M{2}|D{1,3}|W{1,2}|HH24/ =~ text
|
78
|
+
@error_message = I18n.t "pg_partitioning.failure.pattern" unless res
|
79
|
+
res
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'pg_partitioning/printer'
|
2
|
+
require 'pg_partitioning/strategies/equal'
|
3
|
+
require 'pg_partitioning/strategies/date'
|
4
|
+
require 'pg_partitioning/strategies/step'
|
5
|
+
|
6
|
+
module PgPartitioning
|
7
|
+
class PartitioningMaster
|
8
|
+
include Printer
|
9
|
+
|
10
|
+
MODES = %w(equal step date).freeze
|
11
|
+
|
12
|
+
def initialize(table_name, column_name, mode, cond=nil)
|
13
|
+
@table_name = table_name
|
14
|
+
@column_name = column_name
|
15
|
+
@cond = cond
|
16
|
+
@sql = ActiveRecord::Base.connection()
|
17
|
+
|
18
|
+
klass = "PgPartitioning::Strategies::#{MODES[mode].classify}"
|
19
|
+
@strategy = klass.constantize.new(@table_name, @column_name, @cond, @sql)
|
20
|
+
end
|
21
|
+
|
22
|
+
def partitioning
|
23
|
+
@strategy.partitioning!
|
24
|
+
|
25
|
+
drop_foreign_keys
|
26
|
+
migration
|
27
|
+
|
28
|
+
mode = show_value_of('constraint_exclusion')
|
29
|
+
if mode != 'partition'
|
30
|
+
alert I18n.t('pg_partitioning.messages.partition_mode', current: mode)
|
31
|
+
end
|
32
|
+
|
33
|
+
info I18n.t 'pg_partitioning.progress.finish'
|
34
|
+
rescue => e
|
35
|
+
alert e.message || I18n.t('pg_partitioning.failure.other')
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
def drop_foreign_keys
|
40
|
+
fk_info = []
|
41
|
+
query = ActiveRecord::Base.send(
|
42
|
+
:sanitize_sql_array,
|
43
|
+
["SELECT tc.constraint_name, tc.table_name, kcu.column_name,
|
44
|
+
ccu.table_name AS foreign_table_name,
|
45
|
+
ccu.column_name AS foreign_column_name
|
46
|
+
FROM information_schema.table_constraints AS tc
|
47
|
+
JOIN information_schema.key_column_usage AS kcu ON tc.constraint_name = kcu.constraint_name
|
48
|
+
JOIN information_schema.constraint_column_usage AS ccu ON ccu.constraint_name = tc.constraint_name
|
49
|
+
WHERE constraint_type = 'FOREIGN KEY' AND ccu.table_name=?;", @table_name])
|
50
|
+
|
51
|
+
@sql.execute(query).each do |r|
|
52
|
+
fk_info << r
|
53
|
+
end
|
54
|
+
|
55
|
+
fk_info.each do |r|
|
56
|
+
@sql.execute "ALTER TABLE #{r['table_name']} DROP CONSTRAINT #{r['constraint_name']};"
|
57
|
+
end
|
58
|
+
|
59
|
+
info I18n.t('pg_partitioning.progress.drop_fk', state: 'OK')
|
60
|
+
end
|
61
|
+
|
62
|
+
def migration
|
63
|
+
@sql.execute <<-SQL
|
64
|
+
CREATE MATERIALIZED VIEW temp_table AS SELECT * FROM #{@table_name};
|
65
|
+
DELETE FROM #{@table_name};
|
66
|
+
INSERT INTO #{@table_name} (SELECT * FROM temp_table);
|
67
|
+
DROP MATERIALIZED VIEW temp_table;
|
68
|
+
SQL
|
69
|
+
info I18n.t('pg_partitioning.progress.migration', state: 'OK')
|
70
|
+
end
|
71
|
+
|
72
|
+
def show_value_of(param)
|
73
|
+
res = ''
|
74
|
+
@sql.execute("SHOW #{param};").each{ |r| res = r[param] }
|
75
|
+
res
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module PgPartitioning
|
2
|
+
module Printer
|
3
|
+
COLORS = [GREEN="\e[32m", WHITE="\e[0m", RED="\e[31m"]
|
4
|
+
|
5
|
+
def text_color(color)
|
6
|
+
print color
|
7
|
+
end
|
8
|
+
|
9
|
+
def print_row(mes, color = WHITE)
|
10
|
+
text_color color
|
11
|
+
print mes + "\n"
|
12
|
+
text_color WHITE
|
13
|
+
end
|
14
|
+
|
15
|
+
def info(mes)
|
16
|
+
print_row mes, GREEN
|
17
|
+
end
|
18
|
+
|
19
|
+
def alert(mes)
|
20
|
+
print_row mes, RED
|
21
|
+
end
|
22
|
+
|
23
|
+
def message(mes)
|
24
|
+
print_row mes
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'pg_partitioning/printer'
|
2
|
+
|
3
|
+
module PgPartitioning
|
4
|
+
module Strategies
|
5
|
+
class Base
|
6
|
+
include Printer
|
7
|
+
|
8
|
+
def initialize(table, column, cond, sql_conn)
|
9
|
+
@table_name = table
|
10
|
+
@column_name = column
|
11
|
+
@cond = cond
|
12
|
+
@sql = sql_conn
|
13
|
+
end
|
14
|
+
|
15
|
+
def partitioning!
|
16
|
+
raise error_message unless valid?
|
17
|
+
create_insert_master_function
|
18
|
+
create_trigger('insert_master', 'before')
|
19
|
+
create_drop_function
|
20
|
+
create_trigger('delete_master', 'after')
|
21
|
+
end
|
22
|
+
|
23
|
+
protected
|
24
|
+
|
25
|
+
def valid?
|
26
|
+
@data_type = column_data_type
|
27
|
+
@error_message = I18n.t "pg_partitioning.failure.no_table" if @data_type.blank?
|
28
|
+
@error_message.blank?
|
29
|
+
end
|
30
|
+
|
31
|
+
def error_message
|
32
|
+
@error_message || I18n.t("pg_partitioning.failure.other")
|
33
|
+
end
|
34
|
+
|
35
|
+
def column_data_type
|
36
|
+
res = nil
|
37
|
+
query = ActiveRecord::Base.send(:sanitize_sql_array,
|
38
|
+
["SELECT data_type FROM information_schema.columns
|
39
|
+
WHERE table_name = ? AND column_name = ?;",
|
40
|
+
@table_name, @column_name])
|
41
|
+
@sql.execute(query).each do |r|
|
42
|
+
res = r['data_type']
|
43
|
+
end
|
44
|
+
res
|
45
|
+
end
|
46
|
+
|
47
|
+
def create_trigger(master, mode)
|
48
|
+
drop_trigger(mode)
|
49
|
+
@sql.execute "CREATE TRIGGER #{@table_name}_#{mode}_insert_trigger
|
50
|
+
#{mode} INSERT ON #{@table_name}
|
51
|
+
FOR EACH ROW EXECUTE PROCEDURE #{@table_name}_#{master}();"
|
52
|
+
info I18n.t("pg_partitioning.progress.#{mode}_insert_trigger", state: "OK")
|
53
|
+
end
|
54
|
+
|
55
|
+
def drop_trigger(mode)
|
56
|
+
@sql.execute "DROP TRIGGER IF EXISTS #{@table_name}_#{mode}_insert_trigger ON #{@table_name};"
|
57
|
+
end
|
58
|
+
|
59
|
+
def create_drop_function
|
60
|
+
@sql.execute "CREATE OR REPLACE FUNCTION #{@table_name}_delete_master() RETURNS TRIGGER AS $$
|
61
|
+
DECLARE
|
62
|
+
row #{@table_name.to_sym}%rowtype;
|
63
|
+
BEGIN
|
64
|
+
DELETE FROM ONLY #{@table_name} WHERE id = NEW.id RETURNING * INTO row;
|
65
|
+
RETURN row;
|
66
|
+
END;
|
67
|
+
$$ LANGUAGE plpgsql;"
|
68
|
+
info I18n.t("pg_partitioning.progress.drop_master", state: "OK")
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|