From f09bb33bb534fe2e729e292c8ac6b0e2ffdcea2a Mon Sep 17 00:00:00 2001 From: Doug Cole Date: Sat, 31 Mar 2012 13:38:11 -0700 Subject: add use_returning as a postgresql connection config --- .../abstract/database_statements.rb | 4 +- .../connection_adapters/postgresql_adapter.rb | 50 ++++++++++++++++++++-- 2 files changed, 48 insertions(+), 6 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb index 174450eb00..f08040a1a7 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb @@ -59,7 +59,7 @@ module ActiveRecord # Executes insert +sql+ statement in the context of this connection using # +binds+ as the bind substitutes. +name+ is the logged along with # the executed +sql+ statement. - def exec_insert(sql, name, binds) + def exec_insert(sql, name, binds, pk = nil, sequence_name = nil) exec_query(sql, name, binds) end @@ -87,7 +87,7 @@ module ActiveRecord # passed in as +id_value+. def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = []) sql, binds = sql_for_insert(to_sql(arel, binds), pk, id_value, sequence_name, binds) - value = exec_insert(sql, name, binds) + value = exec_insert(sql, name, binds, pk, sequence_name) id_value || last_inserted_id(value) end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 10a178e369..2509fe0490 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -406,6 +406,7 @@ module ActiveRecord initialize_type_map @local_tz = execute('SHOW TIME ZONE', 'SCHEMA').first["TimeZone"] + self.use_returning = true end # Clears the prepared statements cache. @@ -667,8 +668,11 @@ module ActiveRecord pk = primary_key(table_ref) if table_ref end - if pk + if pk && use_returning? select_value("#{sql} RETURNING #{quote_column_name(pk)}") + elsif pk + super + last_insert_id_value(sequence_name || default_sequence_name(table_ref, pk)) else super end @@ -783,11 +787,35 @@ module ActiveRecord pk = primary_key(table_ref) if table_ref end - sql = "#{sql} RETURNING #{quote_column_name(pk)}" if pk + if pk && use_returning? + sql = "#{sql} RETURNING #{quote_column_name(pk)}" + end [sql, binds] end + def exec_insert(sql, name, binds, pk = nil, sequence_name = nil) + val = exec_query(sql, name, binds) + if !use_returning? && pk + if sequence_name + last_insert_id_value(sequence_name) + else + table_ref = extract_table_ref_from_insert_sql(sql) + sequence_name = default_sequence_name(table_ref, pk) + return val unless sequence_name + last_insert_id(sequence_name) + end + else + val + end + end + + def last_inserted_id(result) + return result if result.kind_of?(Integer) + row = result.rows.first + row && row.first + end + # Executes an UPDATE query and returns the number of affected tuples. def update_sql(sql, name = nil) super.cmd_tuples @@ -1028,7 +1056,9 @@ module ActiveRecord # 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 + result = serial_sequence(table_name, pk || 'id') + return nil unless result + result.split('.').last rescue ActiveRecord::StatementInvalid "#{table_name}_#{pk || 'id'}_seq" end @@ -1236,6 +1266,14 @@ module ActiveRecord end end + def use_returning=(val) + @use_returning = val + end + + def use_returning? + @use_returning + end + protected # Returns the version of the connected PostgreSQL server. def postgresql_version @@ -1365,8 +1403,12 @@ module ActiveRecord # Returns the current ID of a table's sequence. def last_insert_id(sequence_name) #:nodoc: + Integer(last_insert_id_value(sequence_name)) + end + + def last_insert_id_value(sequence_name) #:nodoc: r = exec_query("SELECT currval($1)", 'SQL', [[nil, sequence_name]]) - Integer(r.rows.first.first) + r.rows.first.first end # Executes a SELECT query and returns the results, performing any data type -- cgit v1.2.3 From 3475051f7ff8d29eb779618c8f06e725b3889698 Mon Sep 17 00:00:00 2001 From: Doug Cole Date: Sat, 31 Mar 2012 18:13:40 -0700 Subject: update mysql for new exec_insert signature --- activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb index 3f45f23de8..92908d9599 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb @@ -226,7 +226,7 @@ module ActiveRecord end alias :create :insert_sql - def exec_insert(sql, name, binds) + def exec_insert(sql, name, binds, pk = nil, sequence_name = nil) execute to_sql(sql, binds), name end -- cgit v1.2.3 From 20615e74cb9153436f1a2f9f858bf55e093b424b Mon Sep 17 00:00:00 2001 From: Doug Cole Date: Sat, 31 Mar 2012 18:13:55 -0700 Subject: refactor --- .../connection_adapters/postgresql_adapter.rb | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 2509fe0490..5e166defea 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -797,25 +797,17 @@ module ActiveRecord def exec_insert(sql, name, binds, pk = nil, sequence_name = nil) val = exec_query(sql, name, binds) if !use_returning? && pk - if sequence_name - last_insert_id_value(sequence_name) - else + unless sequence_name table_ref = extract_table_ref_from_insert_sql(sql) sequence_name = default_sequence_name(table_ref, pk) return val unless sequence_name - last_insert_id(sequence_name) end + last_insert_id_result(sequence_name) else val end end - def last_inserted_id(result) - return result if result.kind_of?(Integer) - row = result.rows.first - row && row.first - end - # Executes an UPDATE query and returns the number of affected tuples. def update_sql(sql, name = nil) super.cmd_tuples @@ -1406,9 +1398,12 @@ module ActiveRecord Integer(last_insert_id_value(sequence_name)) end - def last_insert_id_value(sequence_name) #:nodoc: - r = exec_query("SELECT currval($1)", 'SQL', [[nil, sequence_name]]) - r.rows.first.first + def last_insert_id_value(sequence_name) + last_insert_id_result(sequence_name).rows.first.first + end + + def last_insert_id_result(sequence_name) #:nodoc: + exec_query("SELECT currval($1)", 'SQL', [[nil, sequence_name]]) end # Executes a SELECT query and returns the results, performing any data type -- cgit v1.2.3 From 3a0d08163a76427611df0c109a5159daaf5b51bf Mon Sep 17 00:00:00 2001 From: Doug Cole Date: Sun, 1 Apr 2012 15:23:06 -0700 Subject: pick better names and add a little documentation --- .../connection_adapters/postgresql_adapter.rb | 24 ++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 5e166defea..c39e8c8577 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -406,7 +406,7 @@ module ActiveRecord initialize_type_map @local_tz = execute('SHOW TIME ZONE', 'SCHEMA').first["TimeZone"] - self.use_returning = true + self.enable_insert_returning! end # Clears the prepared statements cache. @@ -668,7 +668,7 @@ module ActiveRecord pk = primary_key(table_ref) if table_ref end - if pk && use_returning? + if pk && use_insert_returning? select_value("#{sql} RETURNING #{quote_column_name(pk)}") elsif pk super @@ -787,7 +787,7 @@ module ActiveRecord pk = primary_key(table_ref) if table_ref end - if pk && use_returning? + if pk && use_insert_returning? sql = "#{sql} RETURNING #{quote_column_name(pk)}" end @@ -796,7 +796,7 @@ module ActiveRecord def exec_insert(sql, name, binds, pk = nil, sequence_name = nil) val = exec_query(sql, name, binds) - if !use_returning? && pk + if !use_insert_returning? && pk unless sequence_name table_ref = extract_table_ref_from_insert_sql(sql) sequence_name = default_sequence_name(table_ref, pk) @@ -1258,12 +1258,20 @@ module ActiveRecord end end - def use_returning=(val) - @use_returning = val + # Enable insert statements to use INSERT ... RETURNING ... statements. On by default. + def enable_insert_returning! + @use_insert_returning = true end - def use_returning? - @use_returning + # Disable INSERT ... RETURNING ... statements, using currval() instead. + # Useful for trigger based insertions where INSERT RETURNING does the wrong thing. + def disable_insert_returning! + @use_insert_returning = false + end + + + def use_insert_returning? + @use_insert_returning end protected -- cgit v1.2.3 From cd6ddc865a68d126a845d03337e1c7f775588db2 Mon Sep 17 00:00:00 2001 From: Doug Cole Date: Sat, 7 Apr 2012 18:23:26 -0700 Subject: refactor configuration of insert_returning --- .../connection_adapters/postgresql_adapter.rb | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) (limited to 'activerecord/lib/active_record') diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index c39e8c8577..78c00d9341 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -17,7 +17,7 @@ module ActiveRecord # Forward any unused config params to PGconn.connect. [:statement_limit, :encoding, :min_messages, :schema_search_path, :schema_order, :adapter, :pool, :wait_timeout, :template, - :reaping_frequency].each do |key| + :reaping_frequency, :insert_returning].each do |key| conn_params.delete key end conn_params.delete_if { |k,v| v.nil? } @@ -259,6 +259,8 @@ module ActiveRecord # call on the connection. # * :min_messages - An optional client min messages that is used in a # SET client_min_messages TO call on the connection. + # * :insert_returning - An optional boolean to control the use or RETURNING for INSERT statements + # defaults to true. # # Any further options are used as connection parameters to libpq. See # http://www.postgresql.org/docs/9.1/static/libpq-connect.html for the @@ -406,7 +408,7 @@ module ActiveRecord initialize_type_map @local_tz = execute('SHOW TIME ZONE', 'SCHEMA').first["TimeZone"] - self.enable_insert_returning! + @use_insert_returning = @config.key?(:insert_returning) ? @config[:insert_returning] : true end # Clears the prepared statements cache. @@ -1258,18 +1260,6 @@ module ActiveRecord end end - # Enable insert statements to use INSERT ... RETURNING ... statements. On by default. - def enable_insert_returning! - @use_insert_returning = true - end - - # Disable INSERT ... RETURNING ... statements, using currval() instead. - # Useful for trigger based insertions where INSERT RETURNING does the wrong thing. - def disable_insert_returning! - @use_insert_returning = false - end - - def use_insert_returning? @use_insert_returning end -- cgit v1.2.3