Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions lib/active_record/connection_adapters/fb/quoting.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ def quote_string(string) # :nodoc:
string.gsub(/'/, "''")
end

def quoted_date(time)
if time.is_a?(Time)
time.strftime("%m-%d-%Y %H:%M:%S")
else
time.strftime("%m-%d-%Y")
end
end

def quote_column_name(column_name) # :nodoc:
name = ar_to_fb_case(column_name.to_s).gsub('"', '')
@connection.dialect == 1 ? %Q(#{name}) : %Q("#{name}")
Expand Down Expand Up @@ -67,10 +75,12 @@ def _quote(value)
case value
when Type::Binary::Data
"@BINDBINARY#{Base64.encode64(value.to_s)}BINDBINARY@"
when Date, Time
"@BINDDATE#{quoted_date(value)}BINDDATE@"
when Time
"'#{value.strftime("%m-%d-%Y %H:%M")}'"
when Date
"'#{value.strftime("%m-%d-%Y")}'"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the BINDDATE craziness is there for a good reason. In one of my previous PRs, I learned why this is here and explained it in the comments.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain it here, why binddate is better solution?

else
super
super #TODO fix date that present in string
end
end

Expand Down
51 changes: 45 additions & 6 deletions lib/active_record/connection_adapters/fb/schema_statements.rb
Original file line number Diff line number Diff line change
Expand Up @@ -79,33 +79,54 @@ def create_table(name, options = {}) # :nodoc:

return if options[:sequence] == false || !needs_sequence
create_sequence(options[:sequence] || default_sequence_name(name))
trg_sql = <<-END_SQL
CREATE TRIGGER N$#{name.upcase} FOR #{name.upcase}
ACTIVE BEFORE INSERT
AS
declare variable gen_val bigint;
BEGIN
if (new.ID is null) then
new.ID = next value for #{options[:sequence] || default_sequence_name(name)};
else begin
gen_val = gen_id(#{options[:sequence] || default_sequence_name(name)}, 0);
if (new.ID > gen_val) then
gen_val = gen_id(#{options[:sequence] || default_sequence_name(name)}, new.ID - gen_val);
end
END
END_SQL
execute(trg_sql)
commit_db_transaction
end

def rename_table(name, new_name)
fail ActiveRecordError, 'Firebird does not support renaming tables.'
end

def drop_table(name, options = {}) # :nodoc:
super
Copy link
Contributor

@rzane rzane Oct 17, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the table has a sequence, you can't drop it. You need to drop the sequence first.

Unless I'm missing something, the super should come after the sequence is dropped.


unless options[:sequence] == false
sequence_name = options[:sequence] || default_sequence_name(name)
drop_sequence(sequence_name) if sequence_exists?(sequence_name)
end

super
commit_db_transaction
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason for all of the commit_db_transaction invocations? execute should commit.

end

# Creates a sequence
# ===== Examples
# create_sequence('DOGS_SEQ')
def create_sequence(sequence_name)
execute("CREATE SEQUENCE #{sequence_name}") rescue nil
commit_db_transaction
end

# Drops a sequence
# ===== Examples
# drop_sequence('DOGS_SEQ')
def drop_sequence(sequence_name)
execute("DROP SEQUENCE #{sequence_name}") rescue nil
commit_db_transaction
end

# Adds a new column to the named table.
Expand All @@ -117,13 +138,15 @@ def add_column(table_name, column_name, type, options = {})
create_sequence(options[:sequence] || default_sequence_name(table_name))
end

commit_db_transaction
return unless options[:position]
# position is 1-based but add 1 to skip id column
execute(squish_sql(<<-end_sql))
ALTER TABLE #{quote_table_name(table_name)}
ALTER COLUMN #{quote_column_name(column_name)}
POSITION #{options[:position] + 1}
end_sql
commit_db_transaction
end

def remove_column(table_name, column_name, type = nil, options = {})
Expand All @@ -134,6 +157,7 @@ def remove_column(table_name, column_name, type = nil, options = {})
end

super
commit_db_transaction
end

# Changes the column's definition according to the new options.
Expand All @@ -144,13 +168,19 @@ def remove_column(table_name, column_name, type = nil, options = {})
def change_column(table_name, column_name, type, options = {})
type_sql = type_to_sql(type, *options.values_at(:limit, :precision, :scale))

execute(squish_sql(<<-end_sql))
if type == :text
remove_column table_name, column_name
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change column is supposed to be a "safe" operation, meaning it won't delete your data. I would say dropping a column without warning would be very unsafe.

add_column table_name, column_name, type, options
else
execute(squish_sql(<<-end_sql))
ALTER TABLE #{quote_table_name(table_name)}
ALTER COLUMN #{quote_column_name(column_name)} TYPE #{type_sql}
end_sql
end_sql
change_column_null(table_name, column_name, !!options[:null]) if options.key?(:null)
change_column_default(table_name, column_name, options[:default]) if options.key?(:default)
end

change_column_null(table_name, column_name, !!options[:null]) if options.key?(:null)
change_column_default(table_name, column_name, options[:default]) if options.key?(:default)
commit_db_transaction
end

# Sets a new default value for a column. If you want to set the default
Expand All @@ -165,6 +195,7 @@ def change_column_default(table_name, column_name, default)
ALTER #{quote_column_name(column_name)}
SET DEFAULT #{quote(default)}
end_sql
commit_db_transaction
end

def change_column_null(table_name, column_name, null, default = nil)
Expand All @@ -176,6 +207,7 @@ def change_column_null(table_name, column_name, null, default = nil)
WHERE RDB$FIELD_NAME='#{ar_to_fb_case(column_name)}'
AND RDB$RELATION_NAME='#{ar_to_fb_case(table_name)}'
end_sql
commit_db_transaction
end

# Renames a column.
Expand All @@ -189,16 +221,23 @@ def rename_column(table_name, column_name, new_column_name)
end_sql

rename_column_indexes(table_name, column_name, new_column_name)
commit_db_transaction
end

def remove_index!(_table_name, index_name) #:nodoc:
execute "DROP INDEX #{quote_column_name(index_name)}"
commit_db_transaction
end

def index_name(table_name, options) #:nodoc:
if options.respond_to?(:keys) # legacy support
if options[:column]
"#{table_name}_#{Array.wrap(options[:column]) * '_'}"
index_name = "#{table_name}_#{Array.wrap(options[:column]) * '_'}"
if index_name.length > 31
"IDX_#{Digest::SHA256.hexdigest(index_name)[0..22]}"
else
index_name
end
elsif options[:name]
options[:name]
else
Expand Down