diff --git a/lib/odbc_adapter/adapters/mysql_odbc_adapter.rb b/lib/odbc_adapter/adapters/mysql_odbc_adapter.rb index 0358c348..df57e79b 100644 --- a/lib/odbc_adapter/adapters/mysql_odbc_adapter.rb +++ b/lib/odbc_adapter/adapters/mysql_odbc_adapter.rb @@ -27,26 +27,6 @@ def truncate(table_name, name = nil) execute("TRUNCATE TABLE #{quote_table_name(table_name)}", name) end - def limited_update_conditions(where_sql, _quoted_table_name, _quoted_primary_key) - where_sql - end - - def join_to_update(update, select) #:nodoc: - if select.limit || select.offset || select.orders.any? - subsubselect = select.clone - subsubselect.projections = [update.key] - - subselect = Arel::SelectManager.new(select.engine) - subselect.project Arel.sql(update.key.name) - subselect.from subsubselect.as('__active_record_temp') - - update.where update.key.in(subselect) - else - update.table select.source - update.wheres = select.constraints - end - end - # Quotes a string, escaping any ' (single quote) and \ (backslash) # characters. def quote_string(string) @@ -113,9 +93,8 @@ def rename_table(name, new_name) end def change_column(table_name, column_name, type, options = {}) - # column_name.to_s used in case column_name is a symbol unless options_include_default?(options) - options[:default] = columns(table_name).find { |c| c.name == column_name.to_s }.default + options[:default] = column_for(table_name, column_name).default end change_column_sql = "ALTER TABLE #{table_name} CHANGE #{column_name} #{column_name} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}" @@ -139,34 +118,15 @@ def change_column_null(table_name, column_name, null, default = nil) end def rename_column(table_name, column_name, new_column_name) - col = columns(table_name).detect { |c| c.name == column_name.to_s } - current_type = col.native_type - current_type << "(#{col.limit})" if col.limit + column = column_for(table_name, column_name) + current_type = column.native_type + current_type << "(#{column.limit})" if column.limit execute("ALTER TABLE #{table_name} CHANGE #{column_name} #{new_column_name} #{current_type}") end # Skip primary key indexes def indexes(table_name, name = nil) - super(table_name, name).delete_if { |i| i.unique && i.name =~ /^PRIMARY$/ } - end - - # MySQL 5.x doesn't allow DEFAULT NULL for first timestamp column in a - # table - def options_include_default?(options) - if options.include?(:default) && options[:default].nil? - if options.include?(:column) && options[:column].native_type =~ /timestamp/i - options.delete(:default) - end - end - super(options) - end - - def structure_dump - select_all("SHOW FULL TABLES WHERE Table_type = 'BASE TABLE'").map do |table| - table.delete('Table_type') - sql = "SHOW CREATE TABLE #{quote_table_name(table.to_a.first.last)}" - exec_query(sql).first['Create Table'] + ";\n\n" - end.join + super(table_name, name).reject { |i| i.unique && i.name =~ /^PRIMARY$/ } end protected @@ -179,6 +139,19 @@ def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) def last_inserted_id(_result) select_value('SELECT LAST_INSERT_ID()').to_i end + + private + + # MySQL 5.x doesn't allow DEFAULT NULL for first timestamp column in a + # table + def options_include_default?(options) + if options.include?(:default) && options[:default].nil? + if options.include?(:column) && options[:column].native_type =~ /timestamp/i + options.delete(:default) + end + end + super(options) + end end end end diff --git a/lib/odbc_adapter/adapters/postgresql_odbc_adapter.rb b/lib/odbc_adapter/adapters/postgresql_odbc_adapter.rb index 981f02c4..f6721e02 100644 --- a/lib/odbc_adapter/adapters/postgresql_odbc_adapter.rb +++ b/lib/odbc_adapter/adapters/postgresql_odbc_adapter.rb @@ -6,6 +6,8 @@ class PostgreSQLODBCAdapter < ActiveRecord::ConnectionAdapters::ODBCAdapter BOOLEAN_TYPE = 'bool'.freeze PRIMARY_KEY = 'SERIAL PRIMARY KEY'.freeze + alias :create :insert + # Override to handle booleans appropriately def native_database_types @native_database_types ||= super.merge(boolean: { name: 'bool' }) @@ -25,34 +27,14 @@ def truncate(table_name, name = nil) exec_query("TRUNCATE TABLE #{quote_table_name(table_name)}", name) end - # Returns the sequence name for a table's primary key or some other specified key. + # Returns the sequence name for a table's primary key or some other + # specified key. def default_sequence_name(table_name, pk = nil) #:nodoc: serial_sequence(table_name, pk || 'id').split('.').last rescue ActiveRecord::StatementInvalid "#{table_name}_#{pk || 'id'}_seq" end - # Returns the current ID of a table's sequence. - def last_insert_id(sequence_name) - r = exec_query("SELECT currval('#{sequence_name}')", 'SQL') - Integer(r.rows.first.first) - end - - # Executes an INSERT query and returns the new record's ID - def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) - unless pk - table_ref = extract_table_ref_from_insert_sql(sql) - pk = primary_key(table_ref) if table_ref - end - - if pk - select_value("#{sql} RETURNING #{quote_column_name(pk)}") - else - super - end - end - alias :create :insert - def sql_for_insert(sql, pk, id_value, sequence_name, binds) unless pk table_ref = extract_table_ref_from_insert_sql(sql) @@ -88,13 +70,14 @@ def disable_referential_integrity #:nodoc: execute(tables.map { |name| "ALTER TABLE #{quote_table_name(name)} ENABLE TRIGGER ALL" }.join(';')) end - # Create a new PostgreSQL database. Options include :owner, :template, - # :encoding, :tablespace, and :connection_limit (note that MySQL - # uses :charset while PostgreSQL uses :encoding). + # Create a new PostgreSQL database. Options include :owner, + # :template, :encoding, :tablespace, and + # :connection_limit (note that MySQL uses :charset + # while PostgreSQL uses :encoding). # # Example: # create_database config[:database], config - # create_database 'foo_development', :encoding => 'unicode' + # create_database 'foo_development', encoding: 'unicode' def create_database(name, options = {}) options = options.reverse_merge(encoding: 'utf8') @@ -121,7 +104,7 @@ def create_database(name, options = {}) # Drops a PostgreSQL database. # # Example: - # drop_database 'matt_development' + # drop_database 'rails_development' def drop_database(name) #:nodoc: execute "DROP DATABASE IF EXISTS #{quote_table_name(name)}" end @@ -152,17 +135,19 @@ def rename_index(table_name, old_name, new_name) execute("ALTER INDEX #{quote_column_name(old_name)} RENAME TO #{quote_table_name(new_name)}") end - # Returns a SELECT DISTINCT clause for a given set of columns and a given ORDER BY clause. + # Returns a SELECT DISTINCT clause for a given set of columns and a given + # ORDER BY clause. # - # PostgreSQL requires the ORDER BY columns in the select list for distinct queries, and - # requires that the ORDER BY include the distinct column. + # PostgreSQL requires the ORDER BY columns in the select list for + # distinct queries, and requires that the ORDER BY include the distinct + # column. # # distinct("posts.id", "posts.created_at desc") def distinct(columns, orders) return "DISTINCT #{columns}" if orders.empty? - # Construct a clean list of column names from the ORDER BY clause, removing - # any ASC/DESC modifiers + # Construct a clean list of column names from the ORDER BY clause, + # removing any ASC/DESC modifiers order_columns = orders.map { |s| s.gsub(/\s+(ASC|DESC)\s*(NULLS\s+(FIRST|LAST)\s*)?/i, '') } order_columns.reject! { |c| c.blank? } order_columns = order_columns.zip((0...order_columns.size).to_a).map { |s,i| "#{s} AS alias_#{i}" } @@ -170,6 +155,28 @@ def distinct(columns, orders) "DISTINCT #{columns}, #{order_columns * ', '}" end + protected + + # Executes an INSERT query and returns the new record's ID + def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) + unless pk + table_ref = extract_table_ref_from_insert_sql(sql) + pk = primary_key(table_ref) if table_ref + end + + if pk + select_value("#{sql} RETURNING #{quote_column_name(pk)}") + else + super + end + end + + # Returns the current ID of a table's sequence. + def last_insert_id(sequence_name) + r = exec_query("SELECT currval('#{sequence_name}')", 'SQL') + Integer(r.rows.first.first) + end + private def serial_sequence(table, column)