module RailsSqlViews4
module ConnectionAdapters # :nodoc:
module SchemaStatements
def self.included(base)
base.alias_method_chain :drop_table, :cascade
end
# Create a view.
# The +options+ hash can include the following keys:
# [:check_option]
# Specify restrictions for inserts or updates in updatable views. ANSI SQL 92 defines two check option
# values: CASCADED and LOCAL. See your database documentation for allowed values.
#
#
# we have a problem with the force option in postgres
# rescue nil will rescue the ruby program, but we still have an error for postgres
# and unfortunatly for postgress, the first error will stop the interpretor :
# ActiveRecord::StatementInvalid Exception: PG::InFailedSqlTransaction: ERROR:
# current transaction is aborted, commands ignored until end of transaction block
#
def create_view(name, select_query, options={})
create_or_create_view_base(name, select_query, options, "CREATE VIEW ")
end
def create_or_replace_view(name, select_query, options={})
create_or_create_view_base(name, select_query, options, "CREATE OR REPLACE VIEW ")
end
def create_or_create_view_base(name, select_query, options, init_create_sql)
if supports_views?
view_definition = ViewDefinition.new(self, select_query)
if block_given?
yield view_definition
end
if options[:force]
puts" TOTO : Please, force option is not correctly implemented in postgres"
drop_view(name) rescue nil
end
# create_sql = "CREATE VIEW "
create_sql = init_create_sql
create_sql << "#{quote_table_name(name)} "
if supports_view_columns_definition? && !view_definition.to_sql.blank?
create_sql << "("
create_sql << view_definition.to_sql
create_sql << ") "
end
create_sql << "AS #{view_definition.select_query}"
create_sql << " WITH #{options[:check_option]} CHECK OPTION" if options[:check_option]
execute create_sql
end
end
# Also creates a view, with the specific purpose of remapping column names
# to make non-ActiveRecord tables friendly with the naming
# conventions, while maintaining legacy app compatibility.
def create_mapping_view(old_name, new_name, options = {})
return unless supports_views?
col_names = columns(old_name).collect { |col| col.name.to_sym }
mapper = MappingDefinition.new(col_names)
yield mapper
if options[:force]
drop_view(new_name) rescue nil
end
view_sql = "CREATE VIEW #{new_name} "
if supports_view_columns_definition?
view_sql << "(#{mapper.view_cols.collect { |c| quote_column_name(c) }.join(', ')}) "
end
view_sql << "AS SELECT #{mapper.select_cols.collect { |c| quote_column_name(c) }.join(', ')} FROM #{old_name}"
execute view_sql
end
# TODO : est appelé avec SQLITE, alors que c'est pas ok
def drop_table_with_cascade(table_name, options = {})
# execute "DROP TABLE #{quote_table_name(table_name)} CASCADE"
if supports_drop_table_cascade?
execute "DROP TABLE #{quote_table_name(table_name)} CASCADE"
else
execute "DROP TABLE #{quote_table_name(table_name)}"
end
end
# Drop a view.
# The +options+ hash can include the following keys:
# [:drop_behavior]
# Specify the drop behavior. ANSI SQL 92 defines two drop behaviors, CASCADE and RESTRICT. See your
# database documentation to determine what drop behaviors are available.
def drop_view(name, options={})
# if supports_views? # because of postgres (see create_view with force option)
if supports_views? & table_exists?(name)
drop_sql = "DROP VIEW #{quote_table_name(name)}"
drop_sql << " #{options[:drop_behavior]}" if options[:drop_behavior]
execute drop_sql
end
end
end
end
end