aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
authorAaron Patterson <aaron.patterson@gmail.com>2011-04-13 10:41:12 -0700
committerAaron Patterson <aaron.patterson@gmail.com>2011-04-14 13:37:39 -0700
commit8571facea3b51717b3c57c50b2deae5dbf997c6e (patch)
tree7641f3559c3f5add085c7574f58a4ecc070b0f94 /activerecord
parent4893170da20eee28c016408a0f72f1996343a048 (diff)
downloadrails-8571facea3b51717b3c57c50b2deae5dbf997c6e.tar.gz
rails-8571facea3b51717b3c57c50b2deae5dbf997c6e.tar.bz2
rails-8571facea3b51717b3c57c50b2deae5dbf997c6e.zip
insert statements are prepared, but values are not escaped properly
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb22
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql_adapter.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb12
-rw-r--r--activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb4
-rw-r--r--activerecord/lib/active_record/relation.rb30
5 files changed, 64 insertions, 8 deletions
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 a3082b8f01..6d9b5c7b32 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
@@ -56,8 +56,17 @@ module ActiveRecord
end
# Returns the last auto-generated ID from the affected table.
- def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
- insert_sql(sql, name, pk, id_value, sequence_name)
+ #
+ # +id_value+ will be returned unless the value is nil, in
+ # which case the database will attempt to calculate the last inserted
+ # id and return that value.
+ #
+ # If the next id was calculated in advance (as in Oracle), it should be
+ # passed in as +id_value+.
+ def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
+ sql, binds = sql_for_insert(sql, pk, id_value, sequence_name, binds)
+ value = exec_insert(sql, name, binds)
+ id_value || last_inserted_id(value)
end
# Executes the update statement and returns the number of rows affected.
@@ -364,6 +373,15 @@ module ActiveRecord
end
end
end
+
+ def sql_for_insert(sql, pk, id_value, sequence_name, binds)
+ [sql, binds]
+ end
+
+ def last_inserted_id(result)
+ row = result.rows.first
+ row && row.first
+ end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
index d88075fdea..f461162dde 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
@@ -425,6 +425,10 @@ module ActiveRecord
exec_query(sql, name, binds)
end
+ def last_inserted_id(result)
+ @connection.insert_id
+ end
+
def exec_without_stmt(sql, name = 'SQL') # :nodoc:
# Some queries, like SHOW CREATE TABLE don't work through the prepared
# statement API. For those queries, we need to use this method. :'(
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index 05f0e5ebe1..0884968363 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -544,6 +544,18 @@ module ActiveRecord
exec_query(sql, name, binds)
end
+ def sql_for_insert(sql, pk, id_value, sequence_name, binds)
+ unless pk
+ _, table = extract_schema_and_table(sql.split(" ", 4)[2])
+
+ pk = primary_key(table)
+ end
+
+ sql = "#{sql} RETURNING #{quote_column_name(pk)}" if pk
+
+ [sql, binds]
+ end
+
# Executes an UPDATE query and returns the number of affected tuples.
def update_sql(sql, name = nil)
super.cmd_tuples
diff --git a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
index 14c4fd689b..9e7f874f4b 100644
--- a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
@@ -177,6 +177,10 @@ module ActiveRecord
exec_query(sql, name, binds)
end
+ def last_inserted_id(result)
+ @connection.last_insert_row_id
+ end
+
def execute(sql, name = nil) #:nodoc:
log(sql, name) { @connection.execute(sql) }
end
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index 490360ccb5..2f9970dec1 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -48,17 +48,35 @@ module ActiveRecord
im = arel.create_insert
im.into @table
+ conn = @klass.connection
+
if values.empty? # empty insert
im.values = im.create_values [connection.null_insert_value], []
+ @klass.connection.insert(
+ im.to_sql,
+ 'SQL',
+ primary_key,
+ primary_key_value)
else
- im.insert values
+ substitutes = values.to_a
+ binds = substitutes.map do |arel_attr, value|
+ [@klass.columns_hash[arel_attr.name], value]
+ end
+ substitutes.each_with_index do |tuple, i|
+ tuple[1] = conn.substitute_at(tuple.first, i)
+ end
+
+ im.insert substitutes
+
+ conn.insert(
+ im.to_sql,
+ 'SQL',
+ primary_key,
+ primary_key_value,
+ nil,
+ binds)
end
- @klass.connection.insert(
- im.to_sql,
- 'SQL',
- primary_key,
- primary_key_value)
end
def new(*args, &block)