-
Notifications
You must be signed in to change notification settings - Fork 100
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow to do a change_table to change partition key #64
base: master
Are you sure you want to change the base?
Changes from 2 commits
987337a
99c6fbd
f35c0a4
855a382
8cf51b0
0b01179
f5f2f42
876f95c
0e5db11
6e7d33e
0159335
419f234
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -43,12 +43,45 @@ module ActiveRecord | |
module ConnectionAdapters # :nodoc: | ||
module SchemaStatements | ||
alias :orig_create_table :create_table | ||
alias :orig_change_table :change_table | ||
|
||
def change_primary_key(table_name, options) | ||
if !options[:partition_key] || options[:partition_key].to_s == 'id' | ||
return | ||
end | ||
|
||
pkey_columns = ['id', options[:partition_key]] | ||
|
||
# we are here comparing the columns in the primary key on the database and the one in the migration file | ||
columns_result = execute("select kcu.column_name as key_column " \ | ||
"from information_schema.table_constraints tco "\ | ||
"join information_schema.key_column_usage kcu " \ | ||
"ON kcu.constraint_name = tco.constraint_name " \ | ||
"AND kcu.constraint_schema = tco.constraint_schema "\ | ||
"WHERE tco.constraint_type = 'PRIMARY KEY' " \ | ||
"AND tco.constraint_name = '#{table_name}_pkey'") | ||
|
||
if columns_result.present? | ||
columns = [] | ||
columns_result.values.each do |c| columns.push(c[0]) end | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For one liners usually in Ruby you'd use the columns_result.values.each { |c| columns.push(c[0]) } There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is there anyway to do this without initializing a constant? in python you can do There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, you could do it like this: columns = columns_result.values.map { |c| c[0] } or without the block, utilizing the fact that there is a columns = columns_result.values.map(&:first) |
||
|
||
if columns.length != pkey_columns.length | ||
execute "ALTER TABLE #{table_name} DROP CONSTRAINT IF EXISTS #{table_name}_pkey" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here regarding SQL injection - I think there are methods to escape identifier names in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually, I tried looking into it, the method to sanitize raw sql is
And this triggers errors because SQL doesn't suppose that format If you have an idea how to do change the queries, let me know |
||
execute "ALTER TABLE #{table_name} ADD PRIMARY KEY(\"#{options[:partition_key]}\", id)" | ||
end | ||
end | ||
|
||
end | ||
|
||
def create_table(table_name, options = {}, &block) | ||
ret = orig_create_table(table_name, options.except(:partition_key), &block) | ||
if options[:partition_key] && options[:partition_key].to_s != 'id' | ||
execute "ALTER TABLE #{table_name} DROP CONSTRAINT #{table_name}_pkey" | ||
execute "ALTER TABLE #{table_name} ADD PRIMARY KEY(id, \"#{options[:partition_key]}\")" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Of course, to be fair my own code was not up to my comments :-) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. haha, noted, I'll work on avoiding SQL injection ;) |
||
end | ||
change_primary_key(table_name, options) | ||
ret | ||
end | ||
|
||
def change_table(table_name, options, &block) | ||
ret = orig_change_table(table_name, options.except(:partition_key), &block) | ||
change_primary_key(table_name, options) | ||
ret | ||
end | ||
end | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -82,7 +82,7 @@ | |
t.column :name, :string | ||
end | ||
|
||
create_table :project_categories, force: true, partition_key: :account_id do |t| | ||
create_table :project_categories, force: true do |t| | ||
t.column :name, :string | ||
t.column :account_id, :integer | ||
t.column :project_id, :integer | ||
|
@@ -106,9 +106,20 @@ | |
create_distributed_table :partition_key_not_model_tasks, :non_model_id | ||
create_distributed_table :subclass_tasks, :non_model_id | ||
create_distributed_table :uuid_records, :organization_id | ||
create_distributed_table :project_categories, :account_id | ||
create_distributed_table :allowed_places, :account_id | ||
create_reference_table :categories | ||
|
||
change_table :project_categories, partition_key: :account_id do |t| | ||
end | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we can not pass the block at all, unless that throws an error: change_table :project_categories, partition_key: :account_id |
||
|
||
|
||
# primary key shoud not be recreated | ||
change_table :project_categories, partition_key: :account_id do |t| | ||
t.column :subtitle, :string | ||
end | ||
|
||
|
||
create_distributed_table :project_categories, :account_id | ||
end | ||
|
||
class Account < ActiveRecord::Base | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we use a bind parameter here, instead of string substitution?
Whilst its unlikely that someone will do SQL injection here, it seems better to avoid problems with table_name called
'; DROP TABLE xyz; SELECT '