sequel 4.31.0 → 4.32.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +24 -0
- data/Rakefile +17 -15
- data/doc/association_basics.rdoc +7 -3
- data/doc/opening_databases.rdoc +7 -0
- data/doc/release_notes/4.32.0.txt +132 -0
- data/doc/schema_modification.rdoc +1 -1
- data/doc/security.rdoc +70 -26
- data/doc/testing.rdoc +1 -0
- data/lib/sequel/adapters/jdbc.rb +2 -1
- data/lib/sequel/adapters/postgres.rb +3 -4
- data/lib/sequel/adapters/shared/mysql.rb +14 -1
- data/lib/sequel/adapters/shared/sqlite.rb +2 -2
- data/lib/sequel/extensions/_pretty_table.rb +2 -0
- data/lib/sequel/extensions/arbitrary_servers.rb +2 -0
- data/lib/sequel/extensions/columns_introspection.rb +2 -0
- data/lib/sequel/extensions/connection_validator.rb +2 -0
- data/lib/sequel/extensions/constraint_validations.rb +2 -0
- data/lib/sequel/extensions/core_extensions.rb +1 -5
- data/lib/sequel/extensions/current_datetime_timestamp.rb +2 -0
- data/lib/sequel/extensions/dataset_source_alias.rb +2 -0
- data/lib/sequel/extensions/date_arithmetic.rb +2 -0
- data/lib/sequel/extensions/empty_array_consider_nulls.rb +3 -1
- data/lib/sequel/extensions/error_sql.rb +2 -0
- data/lib/sequel/extensions/eval_inspect.rb +2 -0
- data/lib/sequel/extensions/filter_having.rb +2 -0
- data/lib/sequel/extensions/from_block.rb +2 -0
- data/lib/sequel/extensions/graph_each.rb +2 -0
- data/lib/sequel/extensions/hash_aliases.rb +2 -0
- data/lib/sequel/extensions/inflector.rb +2 -0
- data/lib/sequel/extensions/looser_typecasting.rb +3 -1
- data/lib/sequel/extensions/meta_def.rb +2 -0
- data/lib/sequel/extensions/migration.rb +4 -0
- data/lib/sequel/extensions/mssql_emulate_lateral_with_apply.rb +2 -0
- data/lib/sequel/extensions/named_timezones.rb +2 -0
- data/lib/sequel/extensions/no_auto_literal_strings.rb +84 -0
- data/lib/sequel/extensions/null_dataset.rb +2 -0
- data/lib/sequel/extensions/pagination.rb +2 -0
- data/lib/sequel/extensions/pg_array.rb +2 -4
- data/lib/sequel/extensions/pg_array_ops.rb +2 -0
- data/lib/sequel/extensions/pg_enum.rb +2 -0
- data/lib/sequel/extensions/pg_hstore.rb +2 -4
- data/lib/sequel/extensions/pg_hstore_ops.rb +2 -0
- data/lib/sequel/extensions/pg_inet.rb +2 -4
- data/lib/sequel/extensions/pg_inet_ops.rb +2 -0
- data/lib/sequel/extensions/pg_interval.rb +2 -4
- data/lib/sequel/extensions/pg_json.rb +4 -4
- data/lib/sequel/extensions/pg_json_ops.rb +3 -0
- data/lib/sequel/extensions/pg_loose_count.rb +2 -0
- data/lib/sequel/extensions/pg_range.rb +2 -4
- data/lib/sequel/extensions/pg_range_ops.rb +2 -0
- data/lib/sequel/extensions/pg_row.rb +2 -4
- data/lib/sequel/extensions/pg_row_ops.rb +2 -0
- data/lib/sequel/extensions/pg_static_cache_updater.rb +2 -0
- data/lib/sequel/extensions/pretty_table.rb +2 -0
- data/lib/sequel/extensions/query.rb +3 -0
- data/lib/sequel/extensions/query_literals.rb +7 -5
- data/lib/sequel/extensions/round_timestamps.rb +4 -3
- data/lib/sequel/extensions/schema_caching.rb +2 -0
- data/lib/sequel/extensions/schema_dumper.rb +2 -0
- data/lib/sequel/extensions/select_remove.rb +2 -0
- data/lib/sequel/extensions/sequel_3_dataset_methods.rb +2 -0
- data/lib/sequel/extensions/server_block.rb +3 -0
- data/lib/sequel/extensions/set_overrides.rb +2 -0
- data/lib/sequel/extensions/split_array_nil.rb +2 -0
- data/lib/sequel/extensions/thread_local_timezones.rb +2 -0
- data/lib/sequel/extensions/to_dot.rb +2 -0
- data/lib/sequel/model/associations.rb +95 -55
- data/lib/sequel/plugins/association_pks.rb +58 -33
- data/lib/sequel/plugins/eager_each.rb +22 -0
- data/lib/sequel/plugins/pg_typecast_on_load.rb +3 -2
- data/lib/sequel/plugins/tactical_eager_loading.rb +44 -3
- data/lib/sequel/version.rb +2 -2
- data/spec/adapters/mysql_spec.rb +34 -6
- data/spec/adapters/oracle_spec.rb +1 -1
- data/spec/bin_spec.rb +2 -2
- data/spec/core/dataset_spec.rb +7 -0
- data/spec/extensions/association_pks_spec.rb +38 -0
- data/spec/extensions/class_table_inheritance_spec.rb +24 -0
- data/spec/extensions/eager_each_spec.rb +25 -1
- data/spec/extensions/no_auto_literal_strings_spec.rb +65 -0
- data/spec/extensions/pg_range_spec.rb +1 -0
- data/spec/extensions/spec_helper.rb +5 -5
- data/spec/extensions/tactical_eager_loading_spec.rb +71 -17
- data/spec/integration/associations_test.rb +77 -62
- data/spec/integration/dataset_test.rb +3 -3
- data/spec/integration/plugin_test.rb +22 -0
- data/spec/integration/prepared_statement_test.rb +8 -8
- data/spec/integration/spec_helper.rb +4 -0
- data/spec/model/association_reflection_spec.rb +30 -0
- data/spec/model/associations_spec.rb +177 -16
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d56404078cfe75cf79b2fe4b804e205d8a2e48d3
|
4
|
+
data.tar.gz: 587618022698a1b6f7076571e01361b080f3ea77
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 97590c69f6bef7d22b856c9e331256357cdb4bc5804a65747242c14e3e9c40149f134503f303ce410941181e7574253205e73482f5fe5501ce2d6bebaa94c6cc
|
7
|
+
data.tar.gz: cb19067f82ec892008af6e1064bfb107edce01df096e377606adade354dbfa59dad90aa55dd2a33dc1d7ede4b9c42f16e5f5850c864979e85dfbb63adbfceca6
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,27 @@
|
|
1
|
+
=== 4.32.0 (2016-03-01)
|
2
|
+
|
3
|
+
* Use mutex for synchronizing access to association reflection cache on MRI (jeremyevans)
|
4
|
+
|
5
|
+
* Add Dataset#delete_from on MySQL, allowing deletions from multiple tables in a single query (jeremyevans) (#1146)
|
6
|
+
|
7
|
+
* Add no_auto_literal_strings extension, which makes SQL injection vulnerabilities less likely (jeremyevans)
|
8
|
+
|
9
|
+
* Add Model.default_association_options, for setting option defaults for all future associations (jeremyevans)
|
10
|
+
|
11
|
+
* Support :association_pks_nil association option in association_pks setter for determining how to handle nil (jeremyevans)
|
12
|
+
|
13
|
+
* Make association_pks setter handle empty array correctly when :delay_pks is set (jeremyevans)
|
14
|
+
|
15
|
+
* Add a setter method for one_through_one associations (jeremyevans)
|
16
|
+
|
17
|
+
* Include :remarks entry in JDBC schema parsing output, containing comments on the column (olleolleolle) (#1143)
|
18
|
+
|
19
|
+
* Support :eager_reload and :eager options to associations in tactical_eager_loading plugin (jeremyevans)
|
20
|
+
|
21
|
+
* Make tactical_eager_loading not eager load if passing proc or block to association method (jeremyevans)
|
22
|
+
|
23
|
+
* Make eager_each plugin handle eager loading for Dataset#first and similar methods (jeremyevans)
|
24
|
+
|
1
25
|
=== 4.31.0 (2016-02-01)
|
2
26
|
|
3
27
|
* Convert types in association_pks setters before saving them, instead of just before running queries (jeremyevans)
|
data/Rakefile
CHANGED
@@ -93,7 +93,7 @@ run_spec = proc do |patterns|
|
|
93
93
|
ENV['RUBYLIB'] = rubylib
|
94
94
|
end
|
95
95
|
|
96
|
-
spec_task = proc do |description, name, files|
|
96
|
+
spec_task = proc do |description, name, files, coverage|
|
97
97
|
desc description
|
98
98
|
task name do
|
99
99
|
run_spec.call(files)
|
@@ -106,11 +106,13 @@ spec_task = proc do |description, name, files|
|
|
106
106
|
sh "#{rake} #{name} 2>&1 | egrep -v \"(: warning: instance variable @.* not initialized|: warning: method redefined; discarding old|: warning: previous definition of)\""
|
107
107
|
end
|
108
108
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
109
|
+
if coverage
|
110
|
+
desc "#{description} with coverage"
|
111
|
+
task :"#{name}_cov" do
|
112
|
+
ENV['COVERAGE'] = '1'
|
113
|
+
run_spec.call(files)
|
114
|
+
ENV.delete('COVERAGE')
|
115
|
+
end
|
114
116
|
end
|
115
117
|
end
|
116
118
|
|
@@ -119,19 +121,19 @@ task :default => :spec
|
|
119
121
|
desc "Run the core, model, and extension/plugin specs"
|
120
122
|
task :spec => [:spec_core, :spec_model, :spec_plugin]
|
121
123
|
|
122
|
-
spec_task.call("Run core and model specs together", :spec_core_model, './spec/core/*_spec.rb ./spec/model/*_spec.rb')
|
123
|
-
spec_task.call("Run core specs", :spec_core, './spec/core/*_spec.rb')
|
124
|
-
spec_task.call("Run model specs", :spec_model, './spec/model/*_spec.rb')
|
125
|
-
spec_task.call("Run plugin/extension specs", :spec_plugin, './spec/extensions/*_spec.rb')
|
126
|
-
spec_task.call("Run bin/sequel specs", :spec_bin, './spec/bin_spec.rb')
|
127
|
-
spec_task.call("Run core extensions specs", :spec_core_ext, './spec/core_extensions_spec.rb')
|
128
|
-
spec_task.call("Run integration tests", :spec_integration, './spec/integration/*_test.rb')
|
124
|
+
spec_task.call("Run core and model specs together", :spec_core_model, './spec/core/*_spec.rb ./spec/model/*_spec.rb', true)
|
125
|
+
spec_task.call("Run core specs", :spec_core, './spec/core/*_spec.rb', false)
|
126
|
+
spec_task.call("Run model specs", :spec_model, './spec/model/*_spec.rb', false)
|
127
|
+
spec_task.call("Run plugin/extension specs", :spec_plugin, './spec/extensions/*_spec.rb', true)
|
128
|
+
spec_task.call("Run bin/sequel specs", :spec_bin, './spec/bin_spec.rb', false)
|
129
|
+
spec_task.call("Run core extensions specs", :spec_core_ext, './spec/core_extensions_spec.rb', true)
|
130
|
+
spec_task.call("Run integration tests", :spec_integration, './spec/integration/*_test.rb', true)
|
129
131
|
|
130
132
|
%w'postgres sqlite mysql informix oracle firebird mssql db2 sqlanywhere'.each do |adapter|
|
131
|
-
spec_task.call("Run #{adapter} tests", :"spec_#{adapter}", "./spec/adapters/#{adapter}_spec.rb ./spec/integration/*_test.rb")
|
133
|
+
spec_task.call("Run #{adapter} tests", :"spec_#{adapter}", "./spec/adapters/#{adapter}_spec.rb ./spec/integration/*_test.rb", true)
|
132
134
|
end
|
133
135
|
|
134
|
-
spec_task.call("Run model specs without the associations code", :_spec_model_no_assoc, Dir["./spec/model/*_spec.rb"].delete_if{|f| f =~ /association|eager_loading/}.join(' '))
|
136
|
+
spec_task.call("Run model specs without the associations code", :_spec_model_no_assoc, Dir["./spec/model/*_spec.rb"].delete_if{|f| f =~ /association|eager_loading/}.join(' '), false)
|
135
137
|
desc "Run model specs without the associations code"
|
136
138
|
task :spec_model_no_assoc do
|
137
139
|
ENV['SEQUEL_NO_ASSOCIATIONS'] = '1'
|
data/doc/association_basics.rdoc
CHANGED
@@ -302,8 +302,6 @@ Examples:
|
|
302
302
|
@artist.remove_album(@album)
|
303
303
|
@artist.remove_all_albums
|
304
304
|
|
305
|
-
one_through_one associations do not have any modification methods added.
|
306
|
-
|
307
305
|
Note that the remove_all_* method does not call remove hooks defined on
|
308
306
|
the association, it just issues a single query to the database. If you
|
309
307
|
want to remove all associated objects and call remove hooks, iterate
|
@@ -867,7 +865,13 @@ you also wanted to handle the Artist#remove_all_albums method:
|
|
867
865
|
== Association Options
|
868
866
|
|
869
867
|
Sequel's associations mostly share the same options. For ease of understanding,
|
870
|
-
they are grouped here by section
|
868
|
+
they are grouped here by section.
|
869
|
+
|
870
|
+
The defaults for any of these options can be set at the class level using
|
871
|
+
<tt>Sequel::Model.default_association_options</tt>. Many of these options
|
872
|
+
are specific to particular associations and probably should not be set as
|
873
|
+
defaults, but there certainly are options where a class level default makes
|
874
|
+
sense.
|
871
875
|
|
872
876
|
=== Association Dataset Modification Options
|
873
877
|
|
data/doc/opening_databases.rdoc
CHANGED
@@ -62,6 +62,13 @@ For example:
|
|
62
62
|
|
63
63
|
Sequel.connect('sqlite://blog.db'){|db| puts db[:users].count}
|
64
64
|
|
65
|
+
Note that if you do not pass a block to Sequel.connect, Sequel will automatically retain a
|
66
|
+
reference to the object in the <tt>Sequel::DATABASES</tt> array. So calling +Sequel.connect+
|
67
|
+
multiple times (say once per request), can result in a memory leak. For any application where
|
68
|
+
database access is needed for a long period of time, it's best to store the result of
|
69
|
+
Sequel.connection in a constant, as recommended above.
|
70
|
+
|
71
|
+
== Using the Sequel.connect method
|
65
72
|
== General connection options
|
66
73
|
|
67
74
|
These options are shared by all adapters unless otherwise noted.
|
@@ -0,0 +1,132 @@
|
|
1
|
+
= New Features
|
2
|
+
|
3
|
+
* A no_auto_string_literals plugin has been added, which removes the
|
4
|
+
automatic usage of strings in filter arguments as literal SQL code.
|
5
|
+
By default, if you do:
|
6
|
+
|
7
|
+
DB[:albums].where("name > 'N'")
|
8
|
+
|
9
|
+
By default Sequel will treat "name > 'N'" as SQL code. However,
|
10
|
+
this makes it much easier to introduce SQL injection:
|
11
|
+
|
12
|
+
# SQL Injection vulnerability in default Sequel
|
13
|
+
DB[:albums].where("name > 'params[:letter]'")
|
14
|
+
|
15
|
+
Sequel does support using placeholders when using literal strings:
|
16
|
+
|
17
|
+
# Safe in default Sequel
|
18
|
+
DB[:albums].where("name > ?", params[:letter])
|
19
|
+
|
20
|
+
However, if you forget to use placeholders, you can end up with SQL
|
21
|
+
injection. Accidental usage of filter strings derived from user
|
22
|
+
input as literal SQL code is probably the most common SQL injection
|
23
|
+
vector in applications using Sequel.
|
24
|
+
|
25
|
+
With the no_auto_string_literals extension, passing a plain string
|
26
|
+
as the first or only argument to a filter method raises an
|
27
|
+
exception. If you want to use literal SQL code, you have to do so
|
28
|
+
explicitly:
|
29
|
+
|
30
|
+
DB[:albums].where(Sequel.lit("name > 'N'"))
|
31
|
+
|
32
|
+
You can also specify placeholders when using Sequel.lit:
|
33
|
+
|
34
|
+
DB[:albums].where(Sequel.lit("name > ?", params[:letter]))
|
35
|
+
|
36
|
+
Note that in many cases, you can avoid using literal SQL strings
|
37
|
+
completely:
|
38
|
+
|
39
|
+
DB[:albums].where{|v| v.name > params[:letter]}
|
40
|
+
|
41
|
+
* one_through_one associations now support a setter method:
|
42
|
+
|
43
|
+
Foo.one_through_one :bar
|
44
|
+
|
45
|
+
foo = Foo[1]
|
46
|
+
foo.bar = Bar[2]
|
47
|
+
foo.bar = nil
|
48
|
+
|
49
|
+
This will check the current entry in the join table, and based on
|
50
|
+
the argument and the current entry, run a DELETE, INSERT, or UPDATE
|
51
|
+
query, or take no action if the join table is already in the
|
52
|
+
correct state.
|
53
|
+
|
54
|
+
* Model.default_association_options has been added, which supports
|
55
|
+
default options for all future associations. You can use this to
|
56
|
+
do:
|
57
|
+
|
58
|
+
Model.default_association_options = {:read_only=>true}
|
59
|
+
|
60
|
+
Which makes associations not create modification methods by default.
|
61
|
+
You could still create the modification methods by passing
|
62
|
+
:read_only=>true when creating association.
|
63
|
+
|
64
|
+
* The tactical_eager_loading plugin now supports two additional
|
65
|
+
options when calling an association method: :eager and
|
66
|
+
:eager_reload. Example:
|
67
|
+
|
68
|
+
artist = Artist.all.first
|
69
|
+
|
70
|
+
# Loads all albums for all of the artists,
|
71
|
+
# and all tracks for all of those albums
|
72
|
+
artist.albums(:eager=>:tracks)
|
73
|
+
|
74
|
+
# Reload the artists association for all artists
|
75
|
+
artist.albums(:eager_reload=>true)
|
76
|
+
|
77
|
+
You can also use the :eager option for an eager loading callback:
|
78
|
+
|
79
|
+
# Eagerly load the albums with names starting with A-M
|
80
|
+
artist.albums(:eager=>proc{|ds| ds.where(:name > 'N')})
|
81
|
+
|
82
|
+
* The association_pks plugin now supports an :association_pks_nil
|
83
|
+
association option in the association_pks setter, for determining
|
84
|
+
how nil values should be handled.
|
85
|
+
|
86
|
+
In Sequel <4.31.0, if you provided nil, it would either raise an
|
87
|
+
exception immediately if :delay_pks was not set, or on saving if
|
88
|
+
:delay_pks was set.
|
89
|
+
|
90
|
+
In Sequel 4.31.0, if :delay_pks was not set, it would remove all
|
91
|
+
associated rows. If :delay_pks was set, it would do nothing.
|
92
|
+
|
93
|
+
You can now set :association_pks_nil=>:remove to remove all
|
94
|
+
associated values on nil, or :association_pks_nil=>:ignore to ignore
|
95
|
+
a nil value passed to the method. Without :association_pks_nil set,
|
96
|
+
an exception will be raised.
|
97
|
+
|
98
|
+
* Dataset#delete_from has been added on MySQL, allowing deletions from
|
99
|
+
multiple tables in a single query:
|
100
|
+
|
101
|
+
DB[:a].join(:b, :a_id=>:id).delete_from(:a, :b).delete
|
102
|
+
# DELETE a, b FROM a INNER JOIN b ON (b.a_id = a.id)
|
103
|
+
|
104
|
+
* The JDBC schema parser now includes a :remarks entry for each
|
105
|
+
column, which contains comments on the column.
|
106
|
+
|
107
|
+
= Other Improvements
|
108
|
+
|
109
|
+
* The setter method added by the association_pks plugin now handles
|
110
|
+
the empty array correctly when :delay_pks is set. Previously, if
|
111
|
+
the empty array was passed, Sequel made no modifications in this
|
112
|
+
case. Sequel now correctly removes all associated values if an
|
113
|
+
empty array is passed.
|
114
|
+
|
115
|
+
* The eager_each plugin now handles eager loading when using
|
116
|
+
Dataset#first and related methods. Previously, the behavior was
|
117
|
+
unspecified. In Sequel <4.27.0 Dataset#first did eager loading
|
118
|
+
correctly in the eager case, but incorrectly in the eager_graph
|
119
|
+
case. In Sequel 4.27.0-4.31.0, it did not do eager loading in
|
120
|
+
either case.
|
121
|
+
|
122
|
+
* The tactical_eager_loading plugin will not automatically eager load
|
123
|
+
if passing a proc or block to an association method, since the proc
|
124
|
+
or block could be specific to the receiver.
|
125
|
+
|
126
|
+
* Sequel now uses a mutex to synchronize access to the association
|
127
|
+
cache on MRI, as it does on other ruby implementations.
|
128
|
+
|
129
|
+
= Backwards Compatibility
|
130
|
+
|
131
|
+
* See above for changes in eager_each and association_pks plugin
|
132
|
+
behavior.
|
@@ -132,7 +132,7 @@ If provided with an array, +primary_key+ does not create a column, it just sets
|
|
132
132
|
|
133
133
|
+foreign_key+ is used to create a foreign key column that references a column in another table (or the same table).
|
134
134
|
It takes the column name as the first argument, the table it references as the second argument, and an options hash
|
135
|
-
as
|
135
|
+
as its third argument. A simple example is:
|
136
136
|
|
137
137
|
create_table(:albums) do
|
138
138
|
primary_key :id
|
data/doc/security.rdoc
CHANGED
@@ -44,34 +44,56 @@ There are basically two kinds of possible SQL injections in Sequel:
|
|
44
44
|
|
45
45
|
==== Full SQL Strings
|
46
46
|
|
47
|
-
Some Sequel methods are designed to execute raw SQL, including:
|
47
|
+
Some Sequel methods are designed to execute raw SQL strings, including:
|
48
48
|
|
49
49
|
* Sequel::Database#execute
|
50
50
|
* Sequel::Database#run
|
51
51
|
* Sequel::Database#<<
|
52
|
-
* Sequel::
|
53
|
-
* Sequel::
|
54
|
-
* Sequel::Dataset#
|
52
|
+
* Sequel::Dataset#fetch_rows
|
53
|
+
* Sequel::Dataset#with_sql_all
|
54
|
+
* Sequel::Dataset#with_sql_delete
|
55
|
+
* Sequel::Dataset#with_sql_each
|
56
|
+
* Sequel::Dataset#with_sql_first
|
57
|
+
* Sequel::Dataset#with_sql_insert
|
58
|
+
* Sequel::Dataset#with_sql_single_value
|
59
|
+
* Sequel::Dataset#with_sql_update
|
55
60
|
|
56
61
|
Here are some examples of use:
|
57
62
|
|
58
63
|
DB.run 'SQL'
|
59
64
|
DB << 'SQL'
|
60
65
|
DB.execute 'SQL'
|
61
|
-
DB
|
62
|
-
DB.
|
63
|
-
DB.dataset.
|
66
|
+
DB.fetch_rows('SQL'){|row| }
|
67
|
+
DB.dataset.with_sql_all('SQL')
|
68
|
+
DB.dataset.with_sql_delete('SQL')
|
69
|
+
DB.dataset.with_sql_each('SQL'){|row| }
|
70
|
+
DB.dataset.with_sql_first('SQL')
|
71
|
+
DB.dataset.with_sql_insert('SQL')
|
72
|
+
DB.dataset.with_sql_single_value('SQL')
|
73
|
+
DB.dataset.with_sql_update('SQL')
|
64
74
|
|
65
75
|
If you pass a string to these methods that is derived from user input, you open
|
66
|
-
yourself up to SQL injection.
|
67
|
-
|
68
|
-
|
69
|
-
via Sequel::Database#literal. Example:
|
76
|
+
yourself up to SQL injection. These methods are not designed to work at all
|
77
|
+
with user input. If you must call them with user input, you should escape the
|
78
|
+
user input manually via Sequel::Database#literal. Example:
|
70
79
|
|
71
80
|
DB.run "SOME SQL #{DB.literal(params[:user].to_s)}"
|
72
81
|
|
73
|
-
|
74
|
-
|
82
|
+
==== Full SQL Strings, With Possible Placeholders
|
83
|
+
|
84
|
+
Other Sequel methods are designed to support execution of raw SQL strings that may contain placeholders:
|
85
|
+
|
86
|
+
* Sequel::Database#[]
|
87
|
+
* Sequel::Database#fetch
|
88
|
+
* Sequel::Dataset#with_sql
|
89
|
+
|
90
|
+
Here are some examples of use:
|
91
|
+
|
92
|
+
DB['SQL'].all
|
93
|
+
DB.fetch('SQL').all
|
94
|
+
DB.dataset.with_sql('SQL').all
|
95
|
+
|
96
|
+
With these methods you should use placeholders, in which case Sequel automatically escapes the input:
|
75
97
|
|
76
98
|
DB['SELECT * FROM foo WHERE bar = ?', params[:user].to_s]
|
77
99
|
|
@@ -144,11 +166,13 @@ following methods pass their arguments to a filter method:
|
|
144
166
|
* Sequel::Dataset#first
|
145
167
|
* Sequel::Dataset#last
|
146
168
|
* Sequel::Dataset#[]
|
147
|
-
* Sequel::Dataset#[]=
|
148
169
|
|
149
170
|
The Model.find[rdoc-ref:Sequel::Model::ClassMethods#find] and Model.find_or_create[rdoc-ref:Sequel::Model::ClassMethods#find_or_create]
|
150
171
|
class methods also call down to the filter methods.
|
151
172
|
|
173
|
+
The no_auto_string_literals extension can be used to remove the default support
|
174
|
+
for plain strings as literal strings in filter methods.
|
175
|
+
|
152
176
|
==== SQL Fragment passed to Dataset#update
|
153
177
|
|
154
178
|
Similar to the filter methods, Sequel::Dataset#update also treats a
|
@@ -164,6 +188,9 @@ Instead, you should do:
|
|
164
188
|
|
165
189
|
DB[:table].update(:column => params[:value].to_s) # Safe
|
166
190
|
|
191
|
+
The no_auto_string_literals extension can also be used to remove the default support
|
192
|
+
for plain strings as literal strings in update methods.
|
193
|
+
|
167
194
|
==== SQL Fragment passed to Dataset#lock_style
|
168
195
|
|
169
196
|
The Sequel::Dataset#lock_style method also treats an input string
|
@@ -222,12 +249,12 @@ pass any of those values derived from user input, you are dealing with the same
|
|
222
249
|
Note that the issues with SQL identifiers do not just apply to places where
|
223
250
|
strings are used as identifiers, they also apply to all places where Sequel
|
224
251
|
uses symbols as identifiers. However, if you are creating symbols from user input,
|
225
|
-
you at least have a denial of service vulnerability, and possibly a
|
226
|
-
vulnerability.
|
252
|
+
you at least have a denial of service vulnerability in ruby <2.2, and possibly a
|
253
|
+
more serious vulnerability.
|
227
254
|
|
228
255
|
== Denial of Service
|
229
256
|
|
230
|
-
Sequel converts some strings to symbols. Because symbols in ruby are not
|
257
|
+
Sequel converts some strings to symbols. Because symbols in ruby <2.2 are not
|
231
258
|
garbage collected, if the strings that are converted to symbols are
|
232
259
|
derived from user input, you have a denial of service vulnerability due to
|
233
260
|
memory exhaustion.
|
@@ -302,17 +329,34 @@ they also allow mass assignment:
|
|
302
329
|
Album.new(params[:album]) # Mass Assignment
|
303
330
|
Album.create(params[:album]) # Mass Assignment
|
304
331
|
|
305
|
-
|
306
|
-
Model#
|
332
|
+
When the argument is derived from user input, instead of these methods, it is encouraged to either use
|
333
|
+
Model#set_fields[rdoc-ref:Sequel::Model::InstanceMethods#set_fields] or
|
334
|
+
Model#update_fields[rdoc-ref:Sequel::Model::InstanceMethods#update_fields],
|
335
|
+
which allow you to specify which fields to allow on a per-call basis. This
|
336
|
+
pretty much eliminates the chance that the user will be able to set a column
|
337
|
+
you did not intend to allow:
|
338
|
+
|
339
|
+
album.set_fields(params[:album], [:name, :copies_sold])
|
340
|
+
album.update_fields(params[:album], [:name, :copies_sold])
|
341
|
+
|
342
|
+
These two methods iterate over the second argument (+:name+ and +:copies_sold+ in
|
343
|
+
this example) instead of iterating over the entries in the first argument
|
344
|
+
(<tt>params[:album]</tt> in this example).
|
345
|
+
|
346
|
+
In addition to these two methods, you can also use
|
347
|
+
Model#set_only[rdoc-ref:Sequel::Model::InstanceMethods#set_only] or
|
307
348
|
Model#update_only[rdoc-ref:Sequel::Model::InstanceMethods#update_only],
|
308
|
-
|
309
|
-
|
310
|
-
methods, which allow you to specify which fields
|
311
|
-
to allow on a per-call basis. This pretty much eliminates the chance that the
|
312
|
-
user will be able to set a column you did not intend to allow:
|
349
|
+
which are similar but iterate over the entries in the first argument, checking
|
350
|
+
the second argument to see if setting the entries is allowed.
|
313
351
|
|
314
352
|
album.set_only(params[:album], [:name, :copies_sold])
|
315
|
-
album.
|
353
|
+
album.update_only(params[:album], [:name, :copies_sold])
|
354
|
+
|
355
|
+
If you expect all entries in the second argument to be present in the first
|
356
|
+
argument, use +set_fields+ or +update_fields+. If you are not sure if all
|
357
|
+
arguments in the second argument will be present in the first argument, but
|
358
|
+
do not want to allow setting any column other than the ones listed in the
|
359
|
+
second argument, use +set_only+ or +update_only+.
|
316
360
|
|
317
361
|
You can override the columns to allow by default during mass assignment via
|
318
362
|
the Model.set_allowed_columns[rdoc-ref:Sequel::Model::ClassMethods#set_allowed_columns] class method. This is a good
|
@@ -331,7 +375,7 @@ their type. For example:
|
|
331
375
|
|
332
376
|
Album.where(:id=>params[:id])
|
333
377
|
|
334
|
-
is probably a bad idea. Assuming you are using a web framework, params
|
378
|
+
is probably a bad idea. Assuming you are using a web framework, <tt>params[:id]</tt> could
|
335
379
|
be a string, an array, a hash, or nil.
|
336
380
|
|
337
381
|
Assuming that +id+ is an integer field, you probably want to do:
|
data/doc/testing.rdoc
CHANGED
@@ -155,6 +155,7 @@ The SEQUEL_INTEGRATION_URL environment variable specifies the Database connectio
|
|
155
155
|
SEQUEL_COLUMNS_INTROSPECTION :: Use the columns_introspection extension when running the specs
|
156
156
|
SEQUEL_CONNECTION_VALIDATOR :: Use the connection validator extension when running the specs
|
157
157
|
SEQUEL_ERROR_SQL :: Use the error_sql extension when running the specs
|
158
|
+
SEQUEL_NO_AUTO_LITERAL_STRINGS :: Use the no_auto_string_literals extension when running the specs
|
158
159
|
SEQUEL_NO_CACHE_ASSOCIATIONS :: Don't cache association metadata when running the specs
|
159
160
|
SEQUEL_NO_CHECK_SQLS :: Don't check for specific SQL syntax when running the specs
|
160
161
|
SEQUEL_NO_PENDING :: Don't skip any specs, try running all specs (note, can cause lockups for some adapters)
|