sequel 4.31.0 → 4.32.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +24 -0
  3. data/Rakefile +17 -15
  4. data/doc/association_basics.rdoc +7 -3
  5. data/doc/opening_databases.rdoc +7 -0
  6. data/doc/release_notes/4.32.0.txt +132 -0
  7. data/doc/schema_modification.rdoc +1 -1
  8. data/doc/security.rdoc +70 -26
  9. data/doc/testing.rdoc +1 -0
  10. data/lib/sequel/adapters/jdbc.rb +2 -1
  11. data/lib/sequel/adapters/postgres.rb +3 -4
  12. data/lib/sequel/adapters/shared/mysql.rb +14 -1
  13. data/lib/sequel/adapters/shared/sqlite.rb +2 -2
  14. data/lib/sequel/extensions/_pretty_table.rb +2 -0
  15. data/lib/sequel/extensions/arbitrary_servers.rb +2 -0
  16. data/lib/sequel/extensions/columns_introspection.rb +2 -0
  17. data/lib/sequel/extensions/connection_validator.rb +2 -0
  18. data/lib/sequel/extensions/constraint_validations.rb +2 -0
  19. data/lib/sequel/extensions/core_extensions.rb +1 -5
  20. data/lib/sequel/extensions/current_datetime_timestamp.rb +2 -0
  21. data/lib/sequel/extensions/dataset_source_alias.rb +2 -0
  22. data/lib/sequel/extensions/date_arithmetic.rb +2 -0
  23. data/lib/sequel/extensions/empty_array_consider_nulls.rb +3 -1
  24. data/lib/sequel/extensions/error_sql.rb +2 -0
  25. data/lib/sequel/extensions/eval_inspect.rb +2 -0
  26. data/lib/sequel/extensions/filter_having.rb +2 -0
  27. data/lib/sequel/extensions/from_block.rb +2 -0
  28. data/lib/sequel/extensions/graph_each.rb +2 -0
  29. data/lib/sequel/extensions/hash_aliases.rb +2 -0
  30. data/lib/sequel/extensions/inflector.rb +2 -0
  31. data/lib/sequel/extensions/looser_typecasting.rb +3 -1
  32. data/lib/sequel/extensions/meta_def.rb +2 -0
  33. data/lib/sequel/extensions/migration.rb +4 -0
  34. data/lib/sequel/extensions/mssql_emulate_lateral_with_apply.rb +2 -0
  35. data/lib/sequel/extensions/named_timezones.rb +2 -0
  36. data/lib/sequel/extensions/no_auto_literal_strings.rb +84 -0
  37. data/lib/sequel/extensions/null_dataset.rb +2 -0
  38. data/lib/sequel/extensions/pagination.rb +2 -0
  39. data/lib/sequel/extensions/pg_array.rb +2 -4
  40. data/lib/sequel/extensions/pg_array_ops.rb +2 -0
  41. data/lib/sequel/extensions/pg_enum.rb +2 -0
  42. data/lib/sequel/extensions/pg_hstore.rb +2 -4
  43. data/lib/sequel/extensions/pg_hstore_ops.rb +2 -0
  44. data/lib/sequel/extensions/pg_inet.rb +2 -4
  45. data/lib/sequel/extensions/pg_inet_ops.rb +2 -0
  46. data/lib/sequel/extensions/pg_interval.rb +2 -4
  47. data/lib/sequel/extensions/pg_json.rb +4 -4
  48. data/lib/sequel/extensions/pg_json_ops.rb +3 -0
  49. data/lib/sequel/extensions/pg_loose_count.rb +2 -0
  50. data/lib/sequel/extensions/pg_range.rb +2 -4
  51. data/lib/sequel/extensions/pg_range_ops.rb +2 -0
  52. data/lib/sequel/extensions/pg_row.rb +2 -4
  53. data/lib/sequel/extensions/pg_row_ops.rb +2 -0
  54. data/lib/sequel/extensions/pg_static_cache_updater.rb +2 -0
  55. data/lib/sequel/extensions/pretty_table.rb +2 -0
  56. data/lib/sequel/extensions/query.rb +3 -0
  57. data/lib/sequel/extensions/query_literals.rb +7 -5
  58. data/lib/sequel/extensions/round_timestamps.rb +4 -3
  59. data/lib/sequel/extensions/schema_caching.rb +2 -0
  60. data/lib/sequel/extensions/schema_dumper.rb +2 -0
  61. data/lib/sequel/extensions/select_remove.rb +2 -0
  62. data/lib/sequel/extensions/sequel_3_dataset_methods.rb +2 -0
  63. data/lib/sequel/extensions/server_block.rb +3 -0
  64. data/lib/sequel/extensions/set_overrides.rb +2 -0
  65. data/lib/sequel/extensions/split_array_nil.rb +2 -0
  66. data/lib/sequel/extensions/thread_local_timezones.rb +2 -0
  67. data/lib/sequel/extensions/to_dot.rb +2 -0
  68. data/lib/sequel/model/associations.rb +95 -55
  69. data/lib/sequel/plugins/association_pks.rb +58 -33
  70. data/lib/sequel/plugins/eager_each.rb +22 -0
  71. data/lib/sequel/plugins/pg_typecast_on_load.rb +3 -2
  72. data/lib/sequel/plugins/tactical_eager_loading.rb +44 -3
  73. data/lib/sequel/version.rb +2 -2
  74. data/spec/adapters/mysql_spec.rb +34 -6
  75. data/spec/adapters/oracle_spec.rb +1 -1
  76. data/spec/bin_spec.rb +2 -2
  77. data/spec/core/dataset_spec.rb +7 -0
  78. data/spec/extensions/association_pks_spec.rb +38 -0
  79. data/spec/extensions/class_table_inheritance_spec.rb +24 -0
  80. data/spec/extensions/eager_each_spec.rb +25 -1
  81. data/spec/extensions/no_auto_literal_strings_spec.rb +65 -0
  82. data/spec/extensions/pg_range_spec.rb +1 -0
  83. data/spec/extensions/spec_helper.rb +5 -5
  84. data/spec/extensions/tactical_eager_loading_spec.rb +71 -17
  85. data/spec/integration/associations_test.rb +77 -62
  86. data/spec/integration/dataset_test.rb +3 -3
  87. data/spec/integration/plugin_test.rb +22 -0
  88. data/spec/integration/prepared_statement_test.rb +8 -8
  89. data/spec/integration/spec_helper.rb +4 -0
  90. data/spec/model/association_reflection_spec.rb +30 -0
  91. data/spec/model/associations_spec.rb +177 -16
  92. metadata +6 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7388e21a31fdf29fda8d3687cdf96011514b32f3
4
- data.tar.gz: ea540316de1e370e88ad2c15bc2b53860f34f353
3
+ metadata.gz: d56404078cfe75cf79b2fe4b804e205d8a2e48d3
4
+ data.tar.gz: 587618022698a1b6f7076571e01361b080f3ea77
5
5
  SHA512:
6
- metadata.gz: a674f18f2fe56030b484cddbd66e10fa221256609a6314d3f95f606dcd3092d39b96b41368eff9943f95094c7ef8702e1094fcf4d059a7fd3fee2cda8e1eb0de
7
- data.tar.gz: 2ba7e438b33bf0601ac63eceaaf1858a91437bf4c35f4c95bd16c9a04e7fe990f975ed395b49d1ec4a42b56fe8a90506e74964421027aa3973105cccc3aa32e6
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
- desc "#{description} with coverage"
110
- task :"#{name}_cov" do
111
- ENV['COVERAGE'] = '1'
112
- run_spec.call(files)
113
- ENV.delete('COVERAGE')
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'
@@ -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
 
@@ -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 it's third argument. A simple example is:
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::Database#[]
53
- * Sequel::Database#fetch
54
- * Sequel::Dataset#with_sql
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['SQL'].all
62
- DB.fetch('SQL').all
63
- DB.dataset.with_sql('SQL').all
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. The Sequel::Database#run, Sequel::Database#<<, and
67
- Sequel::Database#execute methods are not designed to work at all with user input.
68
- If you must use them with user input, you should escape the user input manually
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
- With Sequel::Database#[], Sequel::Database#fetch and Sequel::Dataset#with_sql, you should use placeholders,
74
- in which case Sequel automatically literalizes the input:
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 more serious
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
- Instead of these methods, it is encouraged to either use the
306
- Model#set_only[rdoc-ref:Sequel::Model::InstanceMethods#set_only],
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
- Model#set_fields[rdoc-ref:Sequel::Model::InstanceMethods#set_fields], or
309
- Model#update_fields[rdoc-ref:Sequel::Model::InstanceMethods#update_fields]
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.set_fields(params[:album], [:name, :copies_sold])
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\[:id\] could
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)