sequel 3.21.0 → 3.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (225) hide show
  1. data/CHANGELOG +485 -3
  2. data/README.rdoc +20 -6
  3. data/Rakefile +37 -19
  4. data/bin/sequel +1 -5
  5. data/doc/association_basics.rdoc +249 -43
  6. data/doc/dataset_basics.rdoc +4 -4
  7. data/doc/dataset_filtering.rdoc +8 -0
  8. data/doc/mass_assignment.rdoc +54 -0
  9. data/doc/migration.rdoc +15 -538
  10. data/doc/model_hooks.rdoc +72 -27
  11. data/doc/opening_databases.rdoc +89 -50
  12. data/doc/prepared_statements.rdoc +40 -13
  13. data/doc/reflection.rdoc +8 -2
  14. data/doc/release_notes/3.22.0.txt +39 -0
  15. data/doc/release_notes/3.23.0.txt +172 -0
  16. data/doc/release_notes/3.24.0.txt +420 -0
  17. data/doc/release_notes/3.25.0.txt +88 -0
  18. data/doc/release_notes/3.26.0.txt +88 -0
  19. data/doc/release_notes/3.27.0.txt +82 -0
  20. data/doc/release_notes/3.28.0.txt +304 -0
  21. data/doc/release_notes/3.29.0.txt +459 -0
  22. data/doc/release_notes/3.30.0.txt +135 -0
  23. data/doc/release_notes/3.31.0.txt +146 -0
  24. data/doc/schema_modification.rdoc +547 -0
  25. data/doc/sharding.rdoc +7 -1
  26. data/doc/testing.rdoc +129 -0
  27. data/doc/transactions.rdoc +137 -0
  28. data/doc/virtual_rows.rdoc +2 -2
  29. data/lib/sequel/adapters/ado/mssql.rb +18 -6
  30. data/lib/sequel/adapters/ado.rb +40 -18
  31. data/lib/sequel/adapters/amalgalite.rb +17 -9
  32. data/lib/sequel/adapters/db2.rb +175 -86
  33. data/lib/sequel/adapters/dbi.rb +15 -15
  34. data/lib/sequel/adapters/do/mysql.rb +5 -7
  35. data/lib/sequel/adapters/do/postgres.rb +0 -5
  36. data/lib/sequel/adapters/do/sqlite.rb +0 -5
  37. data/lib/sequel/adapters/do.rb +17 -36
  38. data/lib/sequel/adapters/firebird.rb +27 -208
  39. data/lib/sequel/adapters/ibmdb.rb +448 -0
  40. data/lib/sequel/adapters/informix.rb +6 -23
  41. data/lib/sequel/adapters/jdbc/as400.rb +16 -34
  42. data/lib/sequel/adapters/jdbc/db2.rb +45 -0
  43. data/lib/sequel/adapters/jdbc/derby.rb +247 -0
  44. data/lib/sequel/adapters/jdbc/firebird.rb +29 -0
  45. data/lib/sequel/adapters/jdbc/h2.rb +56 -29
  46. data/lib/sequel/adapters/jdbc/hsqldb.rb +170 -0
  47. data/lib/sequel/adapters/jdbc/informix.rb +26 -0
  48. data/lib/sequel/adapters/jdbc/jtds.rb +34 -0
  49. data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
  50. data/lib/sequel/adapters/jdbc/mysql.rb +11 -11
  51. data/lib/sequel/adapters/jdbc/oracle.rb +81 -25
  52. data/lib/sequel/adapters/jdbc/postgresql.rb +9 -13
  53. data/lib/sequel/adapters/jdbc/sqlite.rb +2 -6
  54. data/lib/sequel/adapters/jdbc/sqlserver.rb +71 -0
  55. data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
  56. data/lib/sequel/adapters/jdbc.rb +231 -78
  57. data/lib/sequel/adapters/mock.rb +335 -0
  58. data/lib/sequel/adapters/mysql.rb +82 -184
  59. data/lib/sequel/adapters/mysql2.rb +26 -25
  60. data/lib/sequel/adapters/odbc/db2.rb +17 -0
  61. data/lib/sequel/adapters/odbc/mssql.rb +1 -6
  62. data/lib/sequel/adapters/odbc.rb +28 -9
  63. data/lib/sequel/adapters/openbase.rb +3 -5
  64. data/lib/sequel/adapters/oracle.rb +351 -53
  65. data/lib/sequel/adapters/postgres.rb +194 -33
  66. data/lib/sequel/adapters/shared/access.rb +32 -9
  67. data/lib/sequel/adapters/shared/db2.rb +321 -0
  68. data/lib/sequel/adapters/shared/firebird.rb +221 -0
  69. data/lib/sequel/adapters/shared/informix.rb +53 -0
  70. data/lib/sequel/adapters/shared/mssql.rb +231 -106
  71. data/lib/sequel/adapters/shared/mysql.rb +181 -63
  72. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +149 -0
  73. data/lib/sequel/adapters/shared/oracle.rb +231 -41
  74. data/lib/sequel/adapters/shared/postgres.rb +214 -82
  75. data/lib/sequel/adapters/shared/progress.rb +4 -7
  76. data/lib/sequel/adapters/shared/sqlite.rb +201 -57
  77. data/lib/sequel/adapters/sqlite.rb +29 -21
  78. data/lib/sequel/adapters/swift/mysql.rb +12 -7
  79. data/lib/sequel/adapters/swift/postgres.rb +0 -5
  80. data/lib/sequel/adapters/swift/sqlite.rb +8 -6
  81. data/lib/sequel/adapters/swift.rb +5 -5
  82. data/lib/sequel/adapters/tinytds.rb +160 -19
  83. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +66 -0
  84. data/lib/sequel/adapters/utils/stored_procedures.rb +1 -11
  85. data/lib/sequel/ast_transformer.rb +190 -0
  86. data/lib/sequel/connection_pool/threaded.rb +3 -2
  87. data/lib/sequel/connection_pool.rb +1 -1
  88. data/lib/sequel/core.rb +46 -5
  89. data/lib/sequel/database/connecting.rb +5 -6
  90. data/lib/sequel/database/dataset.rb +4 -4
  91. data/lib/sequel/database/dataset_defaults.rb +59 -1
  92. data/lib/sequel/database/logging.rb +1 -1
  93. data/lib/sequel/database/misc.rb +104 -19
  94. data/lib/sequel/database/query.rb +153 -58
  95. data/lib/sequel/database/schema_generator.rb +17 -7
  96. data/lib/sequel/database/schema_methods.rb +59 -29
  97. data/lib/sequel/dataset/actions.rb +231 -76
  98. data/lib/sequel/dataset/features.rb +91 -8
  99. data/lib/sequel/dataset/graph.rb +38 -11
  100. data/lib/sequel/dataset/misc.rb +50 -23
  101. data/lib/sequel/dataset/mutation.rb +5 -6
  102. data/lib/sequel/dataset/prepared_statements.rb +48 -27
  103. data/lib/sequel/dataset/query.rb +236 -43
  104. data/lib/sequel/dataset/sql.rb +665 -253
  105. data/lib/sequel/dataset.rb +8 -0
  106. data/lib/sequel/exceptions.rb +4 -0
  107. data/lib/sequel/extensions/columns_introspection.rb +61 -0
  108. data/lib/sequel/extensions/migration.rb +6 -4
  109. data/lib/sequel/extensions/named_timezones.rb +5 -0
  110. data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
  111. data/lib/sequel/extensions/to_dot.rb +95 -83
  112. data/lib/sequel/model/associations.rb +1020 -337
  113. data/lib/sequel/model/base.rb +414 -132
  114. data/lib/sequel/model/errors.rb +1 -1
  115. data/lib/sequel/model/exceptions.rb +5 -1
  116. data/lib/sequel/model.rb +15 -8
  117. data/lib/sequel/plugins/association_pks.rb +22 -4
  118. data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
  119. data/lib/sequel/plugins/dataset_associations.rb +100 -0
  120. data/lib/sequel/plugins/defaults_setter.rb +58 -0
  121. data/lib/sequel/plugins/force_encoding.rb +6 -6
  122. data/lib/sequel/plugins/identity_map.rb +114 -7
  123. data/lib/sequel/plugins/many_through_many.rb +65 -7
  124. data/lib/sequel/plugins/prepared_statements.rb +151 -0
  125. data/lib/sequel/plugins/prepared_statements_associations.rb +84 -0
  126. data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
  127. data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
  128. data/lib/sequel/plugins/rcte_tree.rb +29 -15
  129. data/lib/sequel/plugins/serialization.rb +88 -44
  130. data/lib/sequel/plugins/serialization_modification_detection.rb +51 -0
  131. data/lib/sequel/plugins/sharding.rb +21 -54
  132. data/lib/sequel/plugins/single_table_inheritance.rb +3 -1
  133. data/lib/sequel/plugins/typecast_on_load.rb +9 -12
  134. data/lib/sequel/plugins/update_primary_key.rb +2 -2
  135. data/lib/sequel/plugins/xml_serializer.rb +3 -3
  136. data/lib/sequel/sql.rb +109 -52
  137. data/lib/sequel/timezones.rb +57 -38
  138. data/lib/sequel/version.rb +1 -1
  139. data/spec/adapters/db2_spec.rb +146 -0
  140. data/spec/adapters/mssql_spec.rb +111 -29
  141. data/spec/adapters/mysql_spec.rb +135 -123
  142. data/spec/adapters/oracle_spec.rb +49 -77
  143. data/spec/adapters/postgres_spec.rb +267 -78
  144. data/spec/adapters/spec_helper.rb +6 -5
  145. data/spec/adapters/sqlite_spec.rb +35 -21
  146. data/spec/core/connection_pool_spec.rb +71 -92
  147. data/spec/core/core_sql_spec.rb +21 -30
  148. data/spec/core/database_spec.rb +788 -512
  149. data/spec/core/dataset_spec.rb +1073 -1053
  150. data/spec/core/expression_filters_spec.rb +159 -42
  151. data/spec/core/mock_adapter_spec.rb +419 -0
  152. data/spec/core/object_graph_spec.rb +86 -114
  153. data/spec/core/schema_generator_spec.rb +3 -3
  154. data/spec/core/schema_spec.rb +298 -38
  155. data/spec/core/spec_helper.rb +6 -48
  156. data/spec/extensions/association_autoreloading_spec.rb +1 -10
  157. data/spec/extensions/association_dependencies_spec.rb +2 -12
  158. data/spec/extensions/association_pks_spec.rb +66 -32
  159. data/spec/extensions/caching_spec.rb +23 -50
  160. data/spec/extensions/class_table_inheritance_spec.rb +31 -83
  161. data/spec/extensions/columns_introspection_spec.rb +91 -0
  162. data/spec/extensions/composition_spec.rb +18 -13
  163. data/spec/extensions/dataset_associations_spec.rb +199 -0
  164. data/spec/extensions/defaults_setter_spec.rb +64 -0
  165. data/spec/extensions/hook_class_methods_spec.rb +65 -91
  166. data/spec/extensions/identity_map_spec.rb +114 -22
  167. data/spec/extensions/instance_filters_spec.rb +11 -21
  168. data/spec/extensions/instance_hooks_spec.rb +53 -0
  169. data/spec/extensions/json_serializer_spec.rb +4 -5
  170. data/spec/extensions/lazy_attributes_spec.rb +16 -20
  171. data/spec/extensions/list_spec.rb +17 -39
  172. data/spec/extensions/many_through_many_spec.rb +283 -250
  173. data/spec/extensions/migration_spec.rb +35 -32
  174. data/spec/extensions/named_timezones_spec.rb +23 -3
  175. data/spec/extensions/nested_attributes_spec.rb +97 -88
  176. data/spec/extensions/optimistic_locking_spec.rb +9 -20
  177. data/spec/extensions/prepared_statements_associations_spec.rb +111 -0
  178. data/spec/extensions/prepared_statements_safe_spec.rb +61 -0
  179. data/spec/extensions/prepared_statements_spec.rb +53 -0
  180. data/spec/extensions/prepared_statements_with_pk_spec.rb +31 -0
  181. data/spec/extensions/pretty_table_spec.rb +1 -6
  182. data/spec/extensions/rcte_tree_spec.rb +41 -43
  183. data/spec/extensions/schema_dumper_spec.rb +5 -8
  184. data/spec/extensions/schema_spec.rb +13 -21
  185. data/spec/extensions/serialization_modification_detection_spec.rb +37 -0
  186. data/spec/extensions/serialization_spec.rb +72 -43
  187. data/spec/extensions/sharding_spec.rb +66 -140
  188. data/spec/extensions/single_table_inheritance_spec.rb +18 -29
  189. data/spec/extensions/spec_helper.rb +13 -61
  190. data/spec/extensions/sql_expr_spec.rb +20 -60
  191. data/spec/extensions/tactical_eager_loading_spec.rb +9 -19
  192. data/spec/extensions/thread_local_timezones_spec.rb +22 -2
  193. data/spec/extensions/timestamps_spec.rb +6 -6
  194. data/spec/extensions/to_dot_spec.rb +4 -7
  195. data/spec/extensions/touch_spec.rb +13 -14
  196. data/spec/extensions/tree_spec.rb +11 -26
  197. data/spec/extensions/typecast_on_load_spec.rb +1 -6
  198. data/spec/extensions/update_primary_key_spec.rb +30 -24
  199. data/spec/extensions/validation_class_methods_spec.rb +30 -51
  200. data/spec/extensions/validation_helpers_spec.rb +16 -35
  201. data/spec/extensions/xml_serializer_spec.rb +16 -4
  202. data/spec/integration/associations_test.rb +537 -21
  203. data/spec/integration/database_test.rb +4 -2
  204. data/spec/integration/dataset_test.rb +461 -65
  205. data/spec/integration/eager_loader_test.rb +19 -21
  206. data/spec/integration/model_test.rb +80 -1
  207. data/spec/integration/plugin_test.rb +304 -116
  208. data/spec/integration/prepared_statement_test.rb +212 -122
  209. data/spec/integration/schema_test.rb +161 -30
  210. data/spec/integration/spec_helper.rb +39 -30
  211. data/spec/integration/timezone_test.rb +38 -12
  212. data/spec/integration/transaction_test.rb +172 -5
  213. data/spec/integration/type_test.rb +17 -3
  214. data/spec/model/association_reflection_spec.rb +201 -7
  215. data/spec/model/associations_spec.rb +865 -662
  216. data/spec/model/base_spec.rb +275 -95
  217. data/spec/model/dataset_methods_spec.rb +7 -27
  218. data/spec/model/eager_loading_spec.rb +677 -676
  219. data/spec/model/hooks_spec.rb +309 -67
  220. data/spec/model/model_spec.rb +222 -168
  221. data/spec/model/plugins_spec.rb +24 -13
  222. data/spec/model/record_spec.rb +381 -218
  223. data/spec/model/spec_helper.rb +13 -71
  224. data/spec/model/validations_spec.rb +11 -0
  225. metadata +115 -73
@@ -1,7 +1,7 @@
1
1
  module Sequel
2
2
  class Dataset
3
3
  # ---------------------
4
- # :section: Methods related to dataset graphing
4
+ # :section: 5 - Methods related to dataset graphing
5
5
  # Dataset graphing changes the dataset to yield hashes where keys are table
6
6
  # name symbols and values are hashes representing the columns related to
7
7
  # that table. All of these methods return modified copies of the receiver.
@@ -115,7 +115,11 @@ module Sequel
115
115
  add_columns = !ds.opts.include?(:graph_aliases)
116
116
 
117
117
  # Setup the initial graph data structure if it doesn't exist
118
- unless graph = opts[:graph]
118
+ if graph = opts[:graph]
119
+ opts[:graph] = graph = graph.dup
120
+ select = opts[:select].dup
121
+ [:column_aliases, :table_aliases, :column_alias_num].each{|k| graph[k] = graph[k].dup}
122
+ else
119
123
  master = alias_symbol(ds.first_source_alias)
120
124
  raise_alias_error.call if master == table_alias
121
125
  # Master hash storing all .graph related information
@@ -130,10 +134,33 @@ module Sequel
130
134
  # aliased, but are not included if set_graph_aliases
131
135
  # has been used.
132
136
  if add_columns
133
- select = opts[:select] = []
134
- columns.each do |column|
135
- column_aliases[column] = [master, column]
136
- select.push(SQL::QualifiedIdentifier.new(master, column))
137
+ if (select = @opts[:select]) && !select.empty? && !(select.length == 1 && (select.first.is_a?(SQL::ColumnAll)))
138
+ select = select.each do |sel|
139
+ column = case sel
140
+ when Symbol
141
+ _, c, a = split_symbol(sel)
142
+ (a || c).to_sym
143
+ when SQL::Identifier
144
+ sel.value.to_sym
145
+ when SQL::QualifiedIdentifier
146
+ column = sel.column
147
+ column = column.value if column.is_a?(SQL::Identifier)
148
+ column.to_sym
149
+ when SQL::AliasedExpression
150
+ column = sel.aliaz
151
+ column = column.value if column.is_a?(SQL::Identifier)
152
+ column.to_sym
153
+ else
154
+ raise Error, "can't figure out alias to use for graphing for #{sel.inspect}"
155
+ end
156
+ column_aliases[column] = [master, column]
157
+ end
158
+ select = qualified_expression(select, master)
159
+ else
160
+ select = columns.map do |column|
161
+ column_aliases[column] = [master, column]
162
+ SQL::QualifiedIdentifier.new(master, column)
163
+ end
137
164
  end
138
165
  end
139
166
  end
@@ -147,7 +174,6 @@ module Sequel
147
174
 
148
175
  # Add the columns to the selection unless we are ignoring them
149
176
  if add_table && add_columns
150
- select = opts[:select]
151
177
  column_aliases = graph[:column_aliases]
152
178
  ca_num = graph[:column_alias_num]
153
179
  # Which columns to add to the result set
@@ -165,15 +191,16 @@ module Sequel
165
191
  column_alias = :"#{column_alias}_#{column_alias_num}"
166
192
  ca_num[column_alias] += 1
167
193
  end
168
- [column_alias, SQL::QualifiedIdentifier.new(table_alias, column).as(column_alias)]
194
+ [column_alias, SQL::AliasedExpression.new(SQL::QualifiedIdentifier.new(table_alias, column), column_alias)]
169
195
  else
170
- [column, SQL::QualifiedIdentifier.new(table_alias, column)]
196
+ ident = SQL::QualifiedIdentifier.new(table_alias, column)
197
+ [column, ident]
171
198
  end
172
199
  column_aliases[col_alias] = [table_alias, column]
173
200
  select.push(identifier)
174
201
  end
175
202
  end
176
- ds
203
+ add_columns ? ds.select(*select) : ds
177
204
  end
178
205
 
179
206
  # This allows you to manually specify the graph aliases to use
@@ -225,7 +252,7 @@ module Sequel
225
252
  column ||= col_alias
226
253
  gas[col_alias] = [table, column]
227
254
  identifier = value || SQL::QualifiedIdentifier.new(table, column)
228
- identifier = SQL::AliasedExpression.new(identifier, col_alias) if value or column != col_alias
255
+ identifier = SQL::AliasedExpression.new(identifier, col_alias) if value || column != col_alias
229
256
  identifier
230
257
  end
231
258
  [identifiers, gas]
@@ -1,7 +1,7 @@
1
1
  module Sequel
2
2
  class Dataset
3
3
  # ---------------------
4
- # :section: Miscellaneous methods
4
+ # :section: 6 - Miscellaneous methods
5
5
  # These methods don't fit cleanly into another section.
6
6
  # ---------------------
7
7
 
@@ -23,17 +23,13 @@ module Sequel
23
23
  # DB[:posts]
24
24
  #
25
25
  # Sequel::Dataset is an abstract class that is not useful by itself. Each
26
- # database adaptor provides a subclass of Sequel::Dataset, and has
26
+ # database adapter provides a subclass of Sequel::Dataset, and has
27
27
  # the Database#dataset method return an instance of that subclass.
28
28
  def initialize(db, opts = nil)
29
29
  @db = db
30
- @quote_identifiers = db.quote_identifiers? if db.respond_to?(:quote_identifiers?)
31
- @identifier_input_method = db.identifier_input_method if db.respond_to?(:identifier_input_method)
32
- @identifier_output_method = db.identifier_output_method if db.respond_to?(:identifier_output_method)
33
30
  @opts = opts || {}
34
- @row_proc = nil
35
31
  end
36
-
32
+
37
33
  # Define a hash value such that datasets with the same DB, opts, and SQL
38
34
  # will be consider equal.
39
35
  def ==(o)
@@ -45,15 +41,6 @@ module Sequel
45
41
  self == o
46
42
  end
47
43
 
48
- # Return the dataset as an aliased expression with the given alias. You can
49
- # use this as a FROM or JOIN dataset, or as a column if this dataset
50
- # returns a single row and column.
51
- #
52
- # DB.from(DB[:table].as(:b)) # SELECT * FROM (SELECT * FROM table) AS b
53
- def as(aliaz)
54
- ::Sequel::SQL::AliasedExpression.new(self, aliaz)
55
- end
56
-
57
44
  # Yield a dataset for each server in the connection pool that is tied to that server.
58
45
  # Intended for use in sharded environments where all servers need to be modified
59
46
  # with the same data:
@@ -96,10 +83,10 @@ module Sequel
96
83
  # have a table, raises an error. If the table is aliased, returns the original
97
84
  # table, not the alias
98
85
  #
99
- # DB[:table].first_source_alias
86
+ # DB[:table].first_source_table
100
87
  # # => :table
101
88
  #
102
- # DB[:table___t].first_source_alias
89
+ # DB[:table___t].first_source_table
103
90
  # # => :table
104
91
  def first_source_table
105
92
  source = @opts[:from]
@@ -120,16 +107,48 @@ module Sequel
120
107
  # Define a hash value such that datasets with the same DB, opts, and SQL
121
108
  # will have the same hash value
122
109
  def hash
123
- [db, opts.sort_by{|k| k.to_s}, sql].hash
110
+ [db, opts.sort_by{|k, v| k.to_s}, sql].hash
111
+ end
112
+
113
+ # The String instance method to call on identifiers before sending them to
114
+ # the database.
115
+ def identifier_input_method
116
+ if defined?(@identifier_input_method)
117
+ @identifier_input_method
118
+ elsif db.respond_to?(:identifier_input_method)
119
+ @identifier_input_method = db.identifier_input_method
120
+ else
121
+ @identifier_input_method = nil
122
+ end
123
+ end
124
+
125
+ # The String instance method to call on identifiers before sending them to
126
+ # the database.
127
+ def identifier_output_method
128
+ if defined?(@identifier_output_method)
129
+ @identifier_output_method
130
+ elsif db.respond_to?(:identifier_output_method)
131
+ @identifier_output_method = db.identifier_output_method
132
+ else
133
+ @identifier_output_method = nil
134
+ end
124
135
  end
125
136
 
126
137
  # Returns a string representation of the dataset including the class name
127
138
  # and the corresponding SQL select statement.
128
139
  def inspect
129
- "#<#{self.class}: #{sql.inspect}>"
140
+ c = self.class
141
+ c = c.superclass while c.name.nil? || c.name == ''
142
+ "#<#{c.name}: #{sql.inspect}>"
130
143
  end
131
144
 
132
- # Splits a possible implicit alias in C, handling both SQL::AliasedExpressions
145
+ # The alias to use for the row_number column, used when emulating OFFSET
146
+ # support and for eager limit strategies
147
+ def row_number_column
148
+ :x_sequel_row_number_x
149
+ end
150
+
151
+ # Splits a possible implicit alias in +c+, handling both SQL::AliasedExpressions
133
152
  # and Symbols. Returns an array of two elements, with the first being the
134
153
  # main expression, and the second being the alias.
135
154
  def split_alias(c)
@@ -139,6 +158,8 @@ module Sequel
139
158
  [c_table ? SQL::QualifiedIdentifier.new(c_table, column.to_sym) : column.to_sym, aliaz]
140
159
  when SQL::AliasedExpression
141
160
  [c.expression, c.aliaz]
161
+ when SQL::JoinClause
162
+ [c.table, c.table_alias]
142
163
  else
143
164
  [c, nil]
144
165
  end
@@ -151,6 +172,10 @@ module Sequel
151
172
  # used, where N is an integer starting at 0 and increasing until an
152
173
  # unused one is found.
153
174
  #
175
+ # You can provide a second addition array argument containing symbols
176
+ # that should not be considered valid table aliases. The current aliases
177
+ # for the FROM and JOIN tables are automatically included in this array.
178
+ #
154
179
  # DB[:table].unused_table_alias(:t)
155
180
  # # => :t
156
181
  #
@@ -159,9 +184,11 @@ module Sequel
159
184
  #
160
185
  # DB[:table, :table_0].unused_table_alias(:table)
161
186
  # # => :table_1
162
- def unused_table_alias(table_alias)
187
+ #
188
+ # DB[:table, :table_0].unused_table_alias(:table, [:table_1, :table_2])
189
+ # # => :table_3
190
+ def unused_table_alias(table_alias, used_aliases = [])
163
191
  table_alias = alias_symbol(table_alias)
164
- used_aliases = []
165
192
  used_aliases += opts[:from].map{|t| alias_symbol(t)} if opts[:from]
166
193
  used_aliases += opts[:join].map{|j| j.table_alias ? alias_alias_symbol(j.table_alias) : alias_symbol(j.table)} if opts[:join]
167
194
  if used_aliases.include?(table_alias)
@@ -1,7 +1,7 @@
1
1
  module Sequel
2
2
  class Dataset
3
3
  # ---------------------
4
- # :section: Mutation methods
4
+ # :section: 7 - Mutation methods
5
5
  # These methods modify the receiving dataset and should be used with care.
6
6
  # ---------------------
7
7
 
@@ -21,17 +21,16 @@ module Sequel
21
21
  def_mutation_method(*MUTATION_METHODS)
22
22
 
23
23
  # Set the method to call on identifiers going into the database for this dataset
24
- attr_accessor :identifier_input_method
24
+ attr_writer :identifier_input_method
25
25
 
26
26
  # Set the method to call on identifiers coming the database for this dataset
27
- attr_accessor :identifier_output_method
27
+ attr_writer :identifier_output_method
28
28
 
29
29
  # Whether to quote identifiers for this dataset
30
30
  attr_writer :quote_identifiers
31
31
 
32
- # The row_proc for this database, should be a Proc that takes
33
- # a single hash argument and returns the object you want
34
- # each to return.
32
+ # The row_proc for this database, should be any object that responds to +call+ with
33
+ # a single hash argument and returns the object you want #each to return.
35
34
  attr_accessor :row_proc
36
35
 
37
36
  # Add a mutation method to this dataset instance.
@@ -1,7 +1,7 @@
1
1
  module Sequel
2
2
  class Dataset
3
3
  # ---------------------
4
- # :section: Methods related to prepared statements or bound variables
4
+ # :section: 8 - Methods related to prepared statements or bound variables
5
5
  # On some adapters, these use native prepared statements and bound variables, on others
6
6
  # support is emulated. For details, see the {"Prepared Statements/Bound Variables" guide}[link:files/doc/prepared_statements_rdoc.html].
7
7
  # ---------------------
@@ -12,9 +12,6 @@ module Sequel
12
12
  # native database support for bind variables and prepared
13
13
  # statements (as opposed to the emulated ones used by default).
14
14
  module ArgumentMapper
15
- SQL_QUERY_TYPE = Hash.new{|h,k| h[k] = k}
16
- SQL_QUERY_TYPE[:first] = SQL_QUERY_TYPE[:all] = :select
17
-
18
15
  # The name of the prepared statement, if any.
19
16
  attr_accessor :prepared_statement_name
20
17
 
@@ -35,16 +32,9 @@ module Sequel
35
32
  return @prepared_sql if @prepared_sql
36
33
  @prepared_args ||= []
37
34
  @prepared_sql = super
38
- meta_def("#{sql_query_type}_sql"){|*args| prepared_sql}
35
+ @opts[:sql] = @prepared_sql
39
36
  @prepared_sql
40
37
  end
41
-
42
- private
43
-
44
- # The type of query (:select, :insert, :delete, :update).
45
- def sql_query_type
46
- SQL_QUERY_TYPE[@prepared_type]
47
- end
48
38
  end
49
39
 
50
40
  # Backbone of the prepared statement support. Grafts bind variable
@@ -63,6 +53,9 @@ module Sequel
63
53
  # The array/hash of bound variable placeholder names.
64
54
  attr_accessor :prepared_args
65
55
 
56
+ # The dataset that created this prepared statement.
57
+ attr_accessor :orig_dataset
58
+
66
59
  # The argument to supply to insert and update, which may use
67
60
  # placeholders specified by prepared_args
68
61
  attr_accessor :prepared_modify_values
@@ -72,6 +65,12 @@ module Sequel
72
65
  def call(bind_vars={}, &block)
73
66
  bind(bind_vars).run(&block)
74
67
  end
68
+
69
+ # Send the columns to the original dataset, as calling it
70
+ # on the prepared statement can cause problems.
71
+ def columns
72
+ orig_dataset.columns
73
+ end
75
74
 
76
75
  # Returns the SQL for the prepared statement, depending on
77
76
  # the type of the statement and the prepared_modify_values.
@@ -81,6 +80,8 @@ module Sequel
81
80
  select_sql
82
81
  when :first
83
82
  clone(:limit=>1).select_sql
83
+ when :insert_select
84
+ returning.insert_sql(*@prepared_modify_values)
84
85
  when :insert
85
86
  insert_sql(*@prepared_modify_values)
86
87
  when :update
@@ -93,10 +94,14 @@ module Sequel
93
94
  # Changes the values of symbols if they start with $ and
94
95
  # prepared_args is present. If so, they are considered placeholders,
95
96
  # and they are substituted using prepared_arg.
96
- def literal_symbol(v)
97
+ def literal_symbol_append(sql, v)
97
98
  if @opts[:bind_vars] and match = PLACEHOLDER_RE.match(v.to_s)
98
- v2 = prepared_arg(match[1].to_sym)
99
- v2 ? literal(v2) : v
99
+ s = match[1].to_sym
100
+ if prepared_arg?(s)
101
+ literal_append(sql, prepared_arg(s))
102
+ else
103
+ sql << v.to_s
104
+ end
100
105
  else
101
106
  super
102
107
  end
@@ -118,6 +123,8 @@ module Sequel
118
123
  case @prepared_type
119
124
  when :select, :all
120
125
  all(&block)
126
+ when :insert_select
127
+ with_sql(prepared_sql).first
121
128
  when :first
122
129
  first
123
130
  when :insert
@@ -136,11 +143,16 @@ module Sequel
136
143
  @opts[:bind_vars][k]
137
144
  end
138
145
 
146
+ # Whether there is a bound value for the given key.
147
+ def prepared_arg?(k)
148
+ @opts[:bind_vars].has_key?(k)
149
+ end
150
+
139
151
  # Use a clone of the dataset extended with prepared statement
140
152
  # support and using the same argument hash so that you can use
141
153
  # bind variables/prepared arguments in subselects.
142
- def subselect_sql(ds)
143
- ps = ds.prepare(:select)
154
+ def subselect_sql_append(sql, ds)
155
+ ps = ds.clone(:append_sql=>sql).prepare(:select)
144
156
  ps = ps.bind(@opts[:bind_vars]) if @opts[:bind_vars]
145
157
  ps.prepared_args = prepared_args
146
158
  ps.prepared_sql
@@ -171,6 +183,11 @@ module Sequel
171
183
  prepared_args << k
172
184
  prepared_arg_placeholder
173
185
  end
186
+
187
+ # Always assume there is a prepared arg in the argument mapper.
188
+ def prepared_arg?(k)
189
+ true
190
+ end
174
191
  end
175
192
 
176
193
  # Set the bind variables to use for the call. If bind variables have
@@ -184,11 +201,9 @@ module Sequel
184
201
  clone(:bind_vars=>@opts[:bind_vars] ? @opts[:bind_vars].merge(bind_vars) : bind_vars)
185
202
  end
186
203
 
187
- # For the given type (:select, :insert, :update, or :delete),
188
- # run the sql with the bind variables
189
- # specified in the hash. values is a hash of passed to
190
- # insert or update (if one of those types is used),
191
- # which may contain placeholders.
204
+ # For the given type (:select, :first, :insert, :insert_select, :update, or :delete),
205
+ # run the sql with the bind variables specified in the hash. +values+ is a hash passed to
206
+ # insert or update (if one of those types is used), which may contain placeholders.
192
207
  #
193
208
  # DB[:table].filter(:id=>:$id).call(:first, :id=>1)
194
209
  # # SELECT * FROM table WHERE id = ? LIMIT 1 -- (1)
@@ -197,11 +212,16 @@ module Sequel
197
212
  prepare(type, nil, *values).call(bind_variables, &block)
198
213
  end
199
214
 
200
- # Prepare an SQL statement for later execution. This returns
201
- # a clone of the dataset extended with PreparedStatementMethods,
202
- # on which you can call call with the hash of bind variables to
203
- # do substitution. The prepared statement is also stored in
204
- # the associated database. The following usage is identical:
215
+ # Prepare an SQL statement for later execution. Takes a type similar to #call,
216
+ # and the +name+ symbol of the prepared statement. While +name+ defaults to +nil+,
217
+ # it should always be provided as a symbol for the name of the prepared statement,
218
+ # as some databases require that prepared statements have names.
219
+ #
220
+ # This returns a clone of the dataset extended with PreparedStatementMethods,
221
+ # which you can +call+ with the hash of bind variables to use.
222
+ # The prepared statement is also stored in
223
+ # the associated database, where it can be called by name.
224
+ # The following usage is identical:
205
225
  #
206
226
  # ps = DB[:table].filter(:name=>:$name).prepare(:first, :select_by_name)
207
227
  #
@@ -223,6 +243,7 @@ module Sequel
223
243
  def to_prepared_statement(type, values=nil)
224
244
  ps = bind
225
245
  ps.extend(PreparedStatementMethods)
246
+ ps.orig_dataset = self
226
247
  ps.prepared_type = type
227
248
  ps.prepared_modify_values = values
228
249
  ps