sequel 4.41.0 → 4.42.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +98 -0
- data/README.rdoc +23 -10
- data/doc/active_record.rdoc +4 -4
- data/doc/advanced_associations.rdoc +2 -2
- data/doc/association_basics.rdoc +5 -2
- data/doc/cheat_sheet.rdoc +3 -3
- data/doc/core_extensions.rdoc +2 -2
- data/doc/dataset_basics.rdoc +4 -4
- data/doc/dataset_filtering.rdoc +1 -1
- data/doc/migration.rdoc +19 -1
- data/doc/prepared_statements.rdoc +2 -2
- data/doc/release_notes/4.42.0.txt +221 -0
- data/doc/testing.rdoc +3 -1
- data/lib/sequel/adapters/ado/access.rb +0 -1
- data/lib/sequel/adapters/ado/mssql.rb +0 -1
- data/lib/sequel/adapters/do/mysql.rb +0 -1
- data/lib/sequel/adapters/do/postgres.rb +0 -1
- data/lib/sequel/adapters/do/sqlite3.rb +0 -1
- data/lib/sequel/adapters/ibmdb.rb +21 -25
- data/lib/sequel/adapters/jdbc.rb +8 -16
- data/lib/sequel/adapters/jdbc/as400.rb +0 -1
- data/lib/sequel/adapters/jdbc/cubrid.rb +0 -1
- data/lib/sequel/adapters/jdbc/db2.rb +0 -1
- data/lib/sequel/adapters/jdbc/derby.rb +0 -1
- data/lib/sequel/adapters/jdbc/firebirdsql.rb +0 -1
- data/lib/sequel/adapters/jdbc/h2.rb +0 -1
- data/lib/sequel/adapters/jdbc/hsqldb.rb +0 -1
- data/lib/sequel/adapters/jdbc/informix-sqli.rb +0 -1
- data/lib/sequel/adapters/jdbc/jdbcprogress.rb +0 -1
- data/lib/sequel/adapters/jdbc/jtds.rb +0 -1
- data/lib/sequel/adapters/jdbc/mssql.rb +0 -1
- data/lib/sequel/adapters/jdbc/mysql.rb +0 -1
- data/lib/sequel/adapters/jdbc/oracle.rb +0 -1
- data/lib/sequel/adapters/jdbc/postgresql.rb +0 -13
- data/lib/sequel/adapters/jdbc/sqlanywhere.rb +0 -1
- data/lib/sequel/adapters/jdbc/sqlite.rb +0 -1
- data/lib/sequel/adapters/jdbc/sqlserver.rb +3 -4
- data/lib/sequel/adapters/mock.rb +54 -12
- data/lib/sequel/adapters/mysql.rb +1 -1
- data/lib/sequel/adapters/mysql2.rb +11 -17
- data/lib/sequel/adapters/odbc/mssql.rb +0 -1
- data/lib/sequel/adapters/oracle.rb +8 -20
- data/lib/sequel/adapters/postgres.rb +11 -29
- data/lib/sequel/adapters/shared/access.rb +5 -12
- data/lib/sequel/adapters/shared/cubrid.rb +4 -13
- data/lib/sequel/adapters/shared/db2.rb +4 -2
- data/lib/sequel/adapters/shared/firebird.rb +2 -4
- data/lib/sequel/adapters/shared/informix.rb +4 -2
- data/lib/sequel/adapters/shared/mssql.rb +3 -5
- data/lib/sequel/adapters/shared/mysql.rb +4 -14
- data/lib/sequel/adapters/shared/oracle.rb +1 -3
- data/lib/sequel/adapters/shared/postgres.rb +16 -38
- data/lib/sequel/adapters/shared/progress.rb +0 -2
- data/lib/sequel/adapters/shared/sqlanywhere.rb +0 -2
- data/lib/sequel/adapters/shared/sqlite.rb +20 -16
- data/lib/sequel/adapters/sqlite.rb +8 -20
- data/lib/sequel/adapters/swift/mysql.rb +0 -1
- data/lib/sequel/adapters/swift/postgres.rb +0 -1
- data/lib/sequel/adapters/swift/sqlite.rb +0 -1
- data/lib/sequel/adapters/tinytds.rb +4 -12
- data/lib/sequel/adapters/utils/emulate_offset_with_reverse_and_count.rb +1 -1
- data/lib/sequel/adapters/utils/mysql_mysql2.rb +2 -2
- data/lib/sequel/adapters/utils/mysql_prepared_statements.rb +11 -34
- data/lib/sequel/adapters/utils/stored_procedures.rb +9 -22
- data/lib/sequel/adapters/utils/unmodified_identifiers.rb +26 -0
- data/lib/sequel/ast_transformer.rb +2 -2
- data/lib/sequel/database/dataset.rb +1 -1
- data/lib/sequel/database/dataset_defaults.rb +0 -66
- data/lib/sequel/database/features.rb +6 -0
- data/lib/sequel/database/misc.rb +31 -17
- data/lib/sequel/database/query.rb +7 -4
- data/lib/sequel/database/schema_methods.rb +1 -1
- data/lib/sequel/dataset.rb +8 -8
- data/lib/sequel/dataset/actions.rb +140 -46
- data/lib/sequel/dataset/features.rb +1 -5
- data/lib/sequel/dataset/graph.rb +7 -8
- data/lib/sequel/dataset/misc.rb +127 -56
- data/lib/sequel/dataset/mutation.rb +9 -20
- data/lib/sequel/dataset/placeholder_literalizer.rb +10 -1
- data/lib/sequel/dataset/prepared_statements.rb +102 -46
- data/lib/sequel/dataset/query.rb +155 -72
- data/lib/sequel/dataset/sql.rb +26 -9
- data/lib/sequel/extensions/columns_introspection.rb +3 -1
- data/lib/sequel/extensions/core_extensions.rb +5 -5
- data/lib/sequel/extensions/core_refinements.rb +5 -5
- data/lib/sequel/extensions/duplicate_columns_handler.rb +4 -2
- data/lib/sequel/extensions/freeze_datasets.rb +69 -0
- data/lib/sequel/extensions/identifier_mangling.rb +196 -0
- data/lib/sequel/extensions/looser_typecasting.rb +11 -7
- data/lib/sequel/extensions/migration.rb +1 -1
- data/lib/sequel/extensions/null_dataset.rb +5 -2
- data/lib/sequel/extensions/pagination.rb +42 -23
- data/lib/sequel/extensions/pg_enum.rb +3 -3
- data/lib/sequel/extensions/query.rb +3 -3
- data/lib/sequel/extensions/sequel_3_dataset_methods.rb +15 -8
- data/lib/sequel/model/associations.rb +25 -8
- data/lib/sequel/model/base.rb +88 -29
- data/lib/sequel/model/dataset_module.rb +37 -0
- data/lib/sequel/plugins/association_pks.rb +4 -4
- data/lib/sequel/plugins/class_table_inheritance.rb +2 -2
- data/lib/sequel/plugins/constraint_validations.rb +1 -2
- data/lib/sequel/plugins/csv_serializer.rb +2 -2
- data/lib/sequel/plugins/dataset_associations.rb +8 -8
- data/lib/sequel/plugins/eager_each.rb +2 -2
- data/lib/sequel/plugins/instance_filters.rb +1 -1
- data/lib/sequel/plugins/json_serializer.rb +2 -2
- data/lib/sequel/plugins/lazy_attributes.rb +1 -1
- data/lib/sequel/plugins/list.rb +4 -4
- data/lib/sequel/plugins/prepared_statements.rb +2 -4
- data/lib/sequel/plugins/prepared_statements_associations.rb +1 -3
- data/lib/sequel/plugins/prepared_statements_with_pk.rb +1 -1
- data/lib/sequel/plugins/rcte_tree.rb +13 -13
- data/lib/sequel/plugins/sharding.rb +1 -1
- data/lib/sequel/plugins/single_table_inheritance.rb +9 -4
- data/lib/sequel/plugins/tactical_eager_loading.rb +4 -4
- data/lib/sequel/plugins/validation_class_methods.rb +1 -1
- data/lib/sequel/plugins/validation_helpers.rb +1 -1
- data/lib/sequel/plugins/xml_serializer.rb +2 -2
- data/lib/sequel/sql.rb +69 -36
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/db2_spec.rb +10 -0
- data/spec/adapters/firebird_spec.rb +1 -1
- data/spec/adapters/mssql_spec.rb +4 -5
- data/spec/adapters/mysql_spec.rb +9 -9
- data/spec/adapters/postgres_spec.rb +67 -68
- data/spec/adapters/spec_helper.rb +6 -1
- data/spec/adapters/sqlite_spec.rb +29 -15
- data/spec/core/connection_pool_spec.rb +14 -14
- data/spec/core/database_spec.rb +38 -180
- data/spec/core/dataset_mutation_spec.rb +253 -0
- data/spec/core/dataset_spec.rb +394 -537
- data/spec/core/expression_filters_spec.rb +34 -32
- data/spec/core/mock_adapter_spec.rb +27 -35
- data/spec/core/placeholder_literalizer_spec.rb +2 -4
- data/spec/core/schema_generator_spec.rb +4 -4
- data/spec/core/schema_spec.rb +1 -2
- data/spec/core_extensions_spec.rb +22 -29
- data/spec/extensions/active_model_spec.rb +6 -6
- data/spec/extensions/association_dependencies_spec.rb +2 -2
- data/spec/extensions/blacklist_security_spec.rb +3 -3
- data/spec/extensions/boolean_readers_spec.rb +12 -12
- data/spec/extensions/caching_spec.rb +13 -10
- data/spec/extensions/class_table_inheritance_spec.rb +38 -43
- data/spec/extensions/column_conflicts_spec.rb +1 -3
- data/spec/extensions/columns_introspection_spec.rb +2 -3
- data/spec/extensions/composition_spec.rb +5 -3
- data/spec/extensions/constraint_validations_plugin_spec.rb +5 -5
- data/spec/extensions/constraint_validations_spec.rb +14 -8
- data/spec/extensions/core_refinements_spec.rb +22 -29
- data/spec/extensions/csv_serializer_spec.rb +7 -6
- data/spec/extensions/date_arithmetic_spec.rb +15 -15
- data/spec/extensions/defaults_setter_spec.rb +2 -2
- data/spec/extensions/delay_add_association_spec.rb +1 -1
- data/spec/extensions/dirty_spec.rb +19 -10
- data/spec/extensions/duplicate_columns_handler_spec.rb +12 -18
- data/spec/extensions/eager_each_spec.rb +12 -16
- data/spec/extensions/empty_array_consider_nulls_spec.rb +1 -1
- data/spec/extensions/eval_inspect_spec.rb +4 -3
- data/spec/extensions/force_encoding_spec.rb +12 -12
- data/spec/extensions/freeze_datasets_spec.rb +31 -0
- data/spec/extensions/graph_each_spec.rb +6 -18
- data/spec/extensions/hook_class_methods_spec.rb +7 -7
- data/spec/extensions/identifier_mangling_spec.rb +307 -0
- data/spec/extensions/instance_filters_spec.rb +5 -6
- data/spec/extensions/instance_hooks_spec.rb +12 -12
- data/spec/extensions/json_serializer_spec.rb +12 -15
- data/spec/extensions/lazy_attributes_spec.rb +4 -4
- data/spec/extensions/list_spec.rb +19 -21
- data/spec/extensions/many_through_many_spec.rb +108 -163
- data/spec/extensions/meta_def_spec.rb +7 -2
- data/spec/extensions/migration_spec.rb +10 -12
- data/spec/extensions/mssql_optimistic_locking_spec.rb +4 -3
- data/spec/extensions/named_timezones_spec.rb +4 -3
- data/spec/extensions/nested_attributes_spec.rb +2 -2
- data/spec/extensions/null_dataset_spec.rb +17 -12
- data/spec/extensions/optimistic_locking_spec.rb +4 -5
- data/spec/extensions/pagination_spec.rb +8 -10
- data/spec/extensions/pg_array_associations_spec.rb +28 -27
- data/spec/extensions/pg_array_ops_spec.rb +2 -1
- data/spec/extensions/pg_array_spec.rb +6 -2
- data/spec/extensions/pg_enum_spec.rb +5 -3
- data/spec/extensions/pg_hstore_ops_spec.rb +3 -1
- data/spec/extensions/pg_hstore_spec.rb +7 -6
- data/spec/extensions/pg_inet_ops_spec.rb +2 -1
- data/spec/extensions/pg_inet_spec.rb +2 -1
- data/spec/extensions/pg_interval_spec.rb +2 -1
- data/spec/extensions/pg_json_ops_spec.rb +2 -1
- data/spec/extensions/pg_json_spec.rb +6 -3
- data/spec/extensions/pg_loose_count_spec.rb +1 -0
- data/spec/extensions/pg_range_ops_spec.rb +3 -1
- data/spec/extensions/pg_range_spec.rb +9 -5
- data/spec/extensions/pg_row_ops_spec.rb +2 -1
- data/spec/extensions/pg_row_plugin_spec.rb +4 -6
- data/spec/extensions/pg_row_spec.rb +5 -3
- data/spec/extensions/pg_static_cache_updater_spec.rb +2 -1
- data/spec/extensions/pg_typecast_on_load_spec.rb +1 -1
- data/spec/extensions/prepared_statements_associations_spec.rb +1 -1
- data/spec/extensions/prepared_statements_spec.rb +12 -11
- data/spec/extensions/pretty_table_spec.rb +1 -1
- data/spec/extensions/query_spec.rb +8 -5
- data/spec/extensions/rcte_tree_spec.rb +39 -39
- data/spec/extensions/round_timestamps_spec.rb +2 -2
- data/spec/extensions/schema_dumper_spec.rb +3 -2
- data/spec/extensions/schema_spec.rb +2 -2
- data/spec/extensions/scissors_spec.rb +1 -2
- data/spec/extensions/sequel_3_dataset_methods_spec.rb +30 -17
- data/spec/extensions/serialization_modification_detection_spec.rb +2 -2
- data/spec/extensions/serialization_spec.rb +15 -13
- data/spec/extensions/set_overrides_spec.rb +14 -8
- data/spec/extensions/sharding_spec.rb +9 -18
- data/spec/extensions/shared_caching_spec.rb +3 -4
- data/spec/extensions/single_table_inheritance_spec.rb +11 -11
- data/spec/extensions/skip_create_refresh_spec.rb +2 -1
- data/spec/extensions/spec_helper.rb +1 -1
- data/spec/extensions/split_values_spec.rb +2 -2
- data/spec/extensions/sql_comments_spec.rb +6 -0
- data/spec/extensions/static_cache_spec.rb +7 -9
- data/spec/extensions/string_agg_spec.rb +30 -29
- data/spec/extensions/tactical_eager_loading_spec.rb +4 -5
- data/spec/extensions/thread_local_timezones_spec.rb +2 -2
- data/spec/extensions/timestamps_spec.rb +28 -3
- data/spec/extensions/to_dot_spec.rb +1 -2
- data/spec/extensions/tree_spec.rb +33 -29
- data/spec/extensions/typecast_on_load_spec.rb +1 -1
- data/spec/extensions/unlimited_update_spec.rb +1 -0
- data/spec/extensions/update_primary_key_spec.rb +11 -7
- data/spec/extensions/update_refresh_spec.rb +1 -1
- data/spec/extensions/uuid_spec.rb +0 -1
- data/spec/extensions/validate_associated_spec.rb +1 -1
- data/spec/extensions/validation_class_methods_spec.rb +10 -10
- data/spec/extensions/validation_helpers_spec.rb +10 -10
- data/spec/extensions/xml_serializer_spec.rb +7 -3
- data/spec/integration/associations_test.rb +31 -31
- data/spec/integration/dataset_test.rb +17 -19
- data/spec/integration/eager_loader_test.rb +24 -24
- data/spec/integration/model_test.rb +6 -6
- data/spec/integration/plugin_test.rb +43 -43
- data/spec/integration/prepared_statement_test.rb +6 -6
- data/spec/integration/schema_test.rb +63 -52
- data/spec/integration/spec_helper.rb +6 -1
- data/spec/integration/transaction_test.rb +13 -13
- data/spec/model/association_reflection_spec.rb +17 -17
- data/spec/model/associations_spec.rb +101 -96
- data/spec/model/base_spec.rb +175 -49
- data/spec/model/class_dataset_methods_spec.rb +5 -9
- data/spec/model/dataset_methods_spec.rb +5 -5
- data/spec/model/eager_loading_spec.rb +209 -235
- data/spec/model/hooks_spec.rb +15 -15
- data/spec/model/model_spec.rb +28 -21
- data/spec/model/plugins_spec.rb +4 -5
- data/spec/model/record_spec.rb +59 -57
- data/spec/model/spec_helper.rb +1 -1
- data/spec/model/validations_spec.rb +6 -6
- data/spec/spec_config.rb +1 -1
- metadata +10 -2
@@ -10,11 +10,7 @@ module Sequel
|
|
10
10
|
|
11
11
|
# Whether this dataset quotes identifiers.
|
12
12
|
def quote_identifiers?
|
13
|
-
|
14
|
-
@quote_identifiers
|
15
|
-
else
|
16
|
-
@quote_identifiers = db.quote_identifiers?
|
17
|
-
end
|
13
|
+
@opts.fetch(:quote_identifiers, true)
|
18
14
|
end
|
19
15
|
|
20
16
|
# Whether this dataset will provide accurate number of rows matched for
|
data/lib/sequel/dataset/graph.rb
CHANGED
@@ -11,7 +11,7 @@ module Sequel
|
|
11
11
|
|
12
12
|
# Adds the given graph aliases to the list of graph aliases to use,
|
13
13
|
# unlike +set_graph_aliases+, which replaces the list (the equivalent
|
14
|
-
# of +
|
14
|
+
# of +select_append+ when graphing). See +set_graph_aliases+.
|
15
15
|
#
|
16
16
|
# DB[:table].add_graph_aliases(:some_alias=>[:table, :column])
|
17
17
|
# # SELECT ..., table.column AS some_alias
|
@@ -20,7 +20,7 @@ module Sequel
|
|
20
20
|
raise Error, "cannot call add_graph_aliases on a dataset that has not been called with graph or set_graph_aliases"
|
21
21
|
end
|
22
22
|
columns, graph_aliases = graph_alias_columns(graph_aliases)
|
23
|
-
|
23
|
+
select_append(*columns).clone(:graph_aliases => Hash[ga].merge!(graph_aliases).freeze)
|
24
24
|
end
|
25
25
|
|
26
26
|
# Similar to Dataset#join_table, but uses unambiguous aliases for selected
|
@@ -196,11 +196,12 @@ module Sequel
|
|
196
196
|
ident = SQL::QualifiedIdentifier.new(table_alias_qualifier, column)
|
197
197
|
[column, ident]
|
198
198
|
end
|
199
|
-
column_aliases[col_alias] = [table_alias, column]
|
199
|
+
column_aliases[col_alias] = [table_alias, column].freeze
|
200
200
|
select.push(identifier)
|
201
201
|
end
|
202
202
|
end
|
203
|
-
|
203
|
+
[:column_aliases, :table_aliases, :column_alias_num].each{|k| graph[k].freeze}
|
204
|
+
ds = ds.clone(:graph=>graph.freeze)
|
204
205
|
add_columns ? ds.select(*select) : ds
|
205
206
|
end
|
206
207
|
|
@@ -229,9 +230,7 @@ module Sequel
|
|
229
230
|
# # SELECT artists.name, albums.name AS album_name, 42 AS forty_two ...
|
230
231
|
def set_graph_aliases(graph_aliases)
|
231
232
|
columns, graph_aliases = graph_alias_columns(graph_aliases)
|
232
|
-
|
233
|
-
ds.opts[:graph_aliases] = graph_aliases
|
234
|
-
ds
|
233
|
+
select(*columns).clone(:graph_aliases=>graph_aliases.freeze)
|
235
234
|
end
|
236
235
|
|
237
236
|
# Remove the splitting of results into subhashes, and all metadata
|
@@ -269,7 +268,7 @@ module Sequel
|
|
269
268
|
identifiers = graph_aliases.collect do |col_alias, tc|
|
270
269
|
table, column, value = Array(tc)
|
271
270
|
column ||= col_alias
|
272
|
-
gas[col_alias] = [table, column]
|
271
|
+
gas[col_alias] = [table, column].freeze
|
273
272
|
identifier = value || SQL::QualifiedIdentifier.new(table, column)
|
274
273
|
identifier = SQL::AliasedExpression.new(identifier, col_alias) if value || column != col_alias
|
275
274
|
identifier
|
data/lib/sequel/dataset/misc.rb
CHANGED
@@ -29,13 +29,14 @@ module Sequel
|
|
29
29
|
# the Database#dataset method return an instance of that subclass.
|
30
30
|
def initialize(db)
|
31
31
|
@db = db
|
32
|
-
@opts =
|
32
|
+
@opts = {}
|
33
|
+
@cache = {}
|
33
34
|
end
|
34
35
|
|
35
|
-
# Define a hash value such that datasets with the same
|
36
|
+
# Define a hash value such that datasets with the same class, DB, and opts
|
36
37
|
# will be considered equal.
|
37
38
|
def ==(o)
|
38
|
-
o.is_a?(self.class) && db == o.db && opts == o.opts
|
39
|
+
o.is_a?(self.class) && db == o.db && opts == o.opts
|
39
40
|
end
|
40
41
|
|
41
42
|
# An object representing the current date or time, should be an instance
|
@@ -49,11 +50,19 @@ module Sequel
|
|
49
50
|
self == o
|
50
51
|
end
|
51
52
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
53
|
+
if TRUE_FREEZE
|
54
|
+
# Similar to #clone, but returns an unfrozen clone if the receiver is frozen.
|
55
|
+
def dup
|
56
|
+
_clone(:freeze=>false)
|
57
|
+
end
|
58
|
+
else
|
59
|
+
# :nocov:
|
60
|
+
def dup
|
61
|
+
c = clone
|
62
|
+
c.instance_variable_set(:@opts, Hash[c.opts])
|
63
|
+
c
|
64
|
+
end
|
65
|
+
# :nocov:
|
57
66
|
end
|
58
67
|
|
59
68
|
# Yield a dataset for each server in the connection pool that is tied to that server.
|
@@ -74,15 +83,25 @@ module Sequel
|
|
74
83
|
string.gsub(/[\\%_]/){|m| "\\#{m}"}
|
75
84
|
end
|
76
85
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
86
|
+
if TRUE_FREEZE
|
87
|
+
# Freeze the opts when freezing the dataset.
|
88
|
+
def freeze
|
89
|
+
@opts.freeze
|
90
|
+
super
|
91
|
+
end
|
92
|
+
else
|
93
|
+
# :nocov:
|
94
|
+
# :nodoc:
|
95
|
+
def freeze
|
96
|
+
@opts.freeze
|
97
|
+
self
|
98
|
+
end
|
82
99
|
|
83
|
-
|
84
|
-
|
85
|
-
|
100
|
+
# :nodoc:
|
101
|
+
def frozen?
|
102
|
+
@opts.frozen?
|
103
|
+
end
|
104
|
+
# :nocov:
|
86
105
|
end
|
87
106
|
|
88
107
|
# Alias of +first_source_alias+
|
@@ -139,30 +158,10 @@ module Sequel
|
|
139
158
|
end
|
140
159
|
end
|
141
160
|
|
142
|
-
# Define a hash value such that datasets with the same
|
143
|
-
# will have the same hash value
|
161
|
+
# Define a hash value such that datasets with the same class, DB, and opts,
|
162
|
+
# will have the same hash value.
|
144
163
|
def hash
|
145
|
-
[db, opts
|
146
|
-
end
|
147
|
-
|
148
|
-
# The String instance method to call on identifiers before sending them to
|
149
|
-
# the database.
|
150
|
-
def identifier_input_method
|
151
|
-
if defined?(@identifier_input_method)
|
152
|
-
@identifier_input_method
|
153
|
-
else
|
154
|
-
@identifier_input_method = db.identifier_input_method
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
# The String instance method to call on identifiers before sending them to
|
159
|
-
# the database.
|
160
|
-
def identifier_output_method
|
161
|
-
if defined?(@identifier_output_method)
|
162
|
-
@identifier_output_method
|
163
|
-
else
|
164
|
-
@identifier_output_method = db.identifier_output_method
|
165
|
-
end
|
164
|
+
[self.class, db, opts].hash
|
166
165
|
end
|
167
166
|
|
168
167
|
# Returns a string representation of the dataset including the class name
|
@@ -182,6 +181,12 @@ module Sequel
|
|
182
181
|
:x_sequel_row_number_x
|
183
182
|
end
|
184
183
|
|
184
|
+
# The row_proc for this database, should be any object that responds to +call+ with
|
185
|
+
# a single hash argument and returns the object you want #each to return.
|
186
|
+
def row_proc
|
187
|
+
@opts[:row_proc]
|
188
|
+
end
|
189
|
+
|
185
190
|
# Splits a possible implicit alias in +c+, handling both SQL::AliasedExpressions
|
186
191
|
# and Symbols. Returns an array of two elements, with the first being the
|
187
192
|
# main expression, and the second being the alias.
|
@@ -250,29 +255,95 @@ module Sequel
|
|
250
255
|
|
251
256
|
# Return a modified dataset with quote_identifiers set.
|
252
257
|
def with_quote_identifiers(v)
|
253
|
-
|
254
|
-
c.send(:skip_symbol_cache!)
|
255
|
-
c.instance_variable_set(:@quote_identifiers, v)
|
256
|
-
c
|
258
|
+
clone(:quote_identifiers=>v, :skip_symbol_cache=>true)
|
257
259
|
end
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
260
|
+
|
261
|
+
protected
|
262
|
+
|
263
|
+
# Access the cache for the current dataset. Should be used with caution,
|
264
|
+
# as access to the cache is not thread safe without a mutex if other
|
265
|
+
# threads can reference the dataset. Symbol keys prefixed with an
|
266
|
+
# underscore are reserved for internal use.
|
267
|
+
attr_reader :cache
|
268
|
+
|
269
|
+
# Retreive a value from the dataset's cache in a thread safe manner.
|
270
|
+
def cache_get(k)
|
271
|
+
Sequel.synchronize{@cache[k]}
|
265
272
|
end
|
266
|
-
|
267
|
-
#
|
268
|
-
def
|
269
|
-
|
270
|
-
|
271
|
-
|
273
|
+
|
274
|
+
# Set a value in the dataset's cache in a thread safe manner.
|
275
|
+
def cache_set(k, v)
|
276
|
+
Sequel.synchronize{@cache[k] = v}
|
277
|
+
end
|
278
|
+
|
279
|
+
# Clear the columns hash for the current dataset. This is not a
|
280
|
+
# thread safe operation, so it should only be used if the dataset
|
281
|
+
# could not be used by another thread (such as one that was just
|
282
|
+
# created via clone).
|
283
|
+
def clear_columns_cache
|
284
|
+
@cache.delete(:_columns)
|
285
|
+
end
|
286
|
+
|
287
|
+
# The cached columns for the current dataset.
|
288
|
+
def _columns
|
289
|
+
cache_get(:_columns)
|
272
290
|
end
|
273
291
|
|
274
292
|
private
|
275
293
|
|
294
|
+
# Check the cache for the given key, returning the value.
|
295
|
+
# Otherwise, yield to get the dataset, and if the current dataset
|
296
|
+
# is frozen, cache the dataset under the given key.
|
297
|
+
def cached_dataset(key)
|
298
|
+
unless ds = cache_get(key)
|
299
|
+
ds = yield
|
300
|
+
cache_set(key, ds) if frozen?
|
301
|
+
end
|
302
|
+
|
303
|
+
ds
|
304
|
+
end
|
305
|
+
|
306
|
+
# Return a cached placeholder literalizer for the given key if there
|
307
|
+
# is one for this dataset. If there isn't one, increment the counter
|
308
|
+
# for the number of calls for the key, and if the counter is at least
|
309
|
+
# three, then create a placeholder literalizer by yielding to the block,
|
310
|
+
# and cache it.
|
311
|
+
def cached_placeholder_literalizer(key)
|
312
|
+
if loader = cache_get(key)
|
313
|
+
return loader unless loader.is_a?(Integer)
|
314
|
+
loader += 1
|
315
|
+
|
316
|
+
if loader >= 3
|
317
|
+
loader = Sequel::Dataset::PlaceholderLiteralizer.loader(self){|pl, _| yield pl}
|
318
|
+
cache_set(key, loader)
|
319
|
+
else
|
320
|
+
cache_set(key, loader + 1)
|
321
|
+
loader = nil
|
322
|
+
end
|
323
|
+
elsif cache_sql?
|
324
|
+
cache_set(key, 1)
|
325
|
+
end
|
326
|
+
|
327
|
+
loader
|
328
|
+
end
|
329
|
+
|
330
|
+
# Set the columns for the current dataset.
|
331
|
+
def columns=(v)
|
332
|
+
cache_set(:_columns, v)
|
333
|
+
end
|
334
|
+
|
335
|
+
# Set the db, opts, and cache for the copy of the dataset.
|
336
|
+
def initialize_copy(c)
|
337
|
+
@db = c.db
|
338
|
+
@opts = Hash[c.opts]
|
339
|
+
if cols = c.cache_get(:_columns)
|
340
|
+
@cache = {:_columns=>cols}
|
341
|
+
else
|
342
|
+
@cache = {}
|
343
|
+
end
|
344
|
+
end
|
345
|
+
alias initialize_clone initialize_copy
|
346
|
+
|
276
347
|
# Internal recursive version of unqualified_column_for, handling Strings inside
|
277
348
|
# of other objects.
|
278
349
|
def _unqualified_column_for(v)
|
@@ -28,10 +28,6 @@ module Sequel
|
|
28
28
|
# Add the mutation methods via metaprogramming
|
29
29
|
def_mutation_method(*MUTATION_METHODS)
|
30
30
|
|
31
|
-
# The row_proc for this database, should be any object that responds to +call+ with
|
32
|
-
# a single hash argument and returns the object you want #each to return.
|
33
|
-
attr_reader :row_proc
|
34
|
-
|
35
31
|
# Like #extension, but modifies and returns the receiver instead of returning a modified clone.
|
36
32
|
def extension!(*exts)
|
37
33
|
raise_if_frozen!
|
@@ -45,23 +41,10 @@ module Sequel
|
|
45
41
|
self
|
46
42
|
end
|
47
43
|
|
48
|
-
# Set the method to call on identifiers going into the database for this dataset
|
49
|
-
def identifier_input_method=(v)
|
50
|
-
raise_if_frozen!
|
51
|
-
skip_symbol_cache!
|
52
|
-
@identifier_input_method = v
|
53
|
-
end
|
54
|
-
|
55
|
-
# Set the method to call on identifiers coming the database for this dataset
|
56
|
-
def identifier_output_method=(v)
|
57
|
-
raise_if_frozen!
|
58
|
-
@identifier_output_method = v
|
59
|
-
end
|
60
|
-
|
61
44
|
# Remove the row_proc from the current dataset.
|
62
45
|
def naked!
|
63
46
|
raise_if_frozen!
|
64
|
-
|
47
|
+
@opts[:row_proc] = nil
|
65
48
|
self
|
66
49
|
end
|
67
50
|
|
@@ -69,13 +52,13 @@ module Sequel
|
|
69
52
|
def quote_identifiers=(v)
|
70
53
|
raise_if_frozen!
|
71
54
|
skip_symbol_cache!
|
72
|
-
@quote_identifiers = v
|
55
|
+
@opts[:quote_identifiers] = v
|
73
56
|
end
|
74
57
|
|
75
58
|
# Override the row_proc for this dataset
|
76
59
|
def row_proc=(v)
|
77
60
|
raise_if_frozen!
|
78
|
-
@row_proc = v
|
61
|
+
@opts[:row_proc] = v
|
79
62
|
end
|
80
63
|
|
81
64
|
private
|
@@ -99,6 +82,7 @@ module Sequel
|
|
99
82
|
def mutation_method(meth, *args, &block)
|
100
83
|
raise_if_frozen!
|
101
84
|
@opts = send(meth, *args, &block).opts
|
85
|
+
@cache = {}
|
102
86
|
self
|
103
87
|
end
|
104
88
|
|
@@ -108,5 +92,10 @@ module Sequel
|
|
108
92
|
raise RuntimeError, "can't modify frozen #{visible_class_name}"
|
109
93
|
end
|
110
94
|
end
|
95
|
+
|
96
|
+
# Set the dataset to skip the symbol cache
|
97
|
+
def skip_symbol_cache!
|
98
|
+
@opts[:skip_symbol_cache] = true
|
99
|
+
end
|
111
100
|
end
|
112
101
|
end
|
@@ -51,6 +51,7 @@ module Sequel
|
|
51
51
|
@recorder = recorder
|
52
52
|
@pos = pos
|
53
53
|
@transformer = transformer
|
54
|
+
freeze
|
54
55
|
end
|
55
56
|
|
56
57
|
# Record the SQL query offset, argument position, and transforming block where the
|
@@ -125,13 +126,21 @@ module Sequel
|
|
125
126
|
@fragments = fragments
|
126
127
|
@final_sql = final_sql
|
127
128
|
@arity = arity
|
129
|
+
freeze
|
130
|
+
end
|
131
|
+
|
132
|
+
# Freeze the fragments and final SQL when freezing the literalizer.
|
133
|
+
def freeze
|
134
|
+
@fragments.freeze
|
135
|
+
@final_sql.freeze
|
136
|
+
super
|
128
137
|
end
|
129
138
|
|
130
139
|
# Return a new PlaceholderLiteralizer with a modified dataset. This yields the
|
131
140
|
# receiver's dataset to the block, and the block should return the new dataset
|
132
141
|
# to use.
|
133
142
|
def with_dataset
|
134
|
-
dup.instance_exec{@dataset = yield @dataset; self}
|
143
|
+
dup.instance_exec{@dataset = yield @dataset; self}.freeze
|
135
144
|
end
|
136
145
|
|
137
146
|
# Return an array of all objects by running the SQL query for the given arguments.
|
@@ -36,33 +36,49 @@ module Sequel
|
|
36
36
|
end
|
37
37
|
end
|
38
38
|
private_class_method :prepared_statements_module
|
39
|
+
|
40
|
+
def self.def_deprecated_opts_setter(mod, *meths)
|
41
|
+
meths.each do |meth|
|
42
|
+
mod.send(:define_method, :"#{meth}=") do |v|
|
43
|
+
# :nocov:
|
44
|
+
Sequel::Deprecation.deprecate("Dataset##{meth}=", "The API has changed, and this value should now be passed in as an option via Dataset#clone.")
|
45
|
+
@opts[meth] = v
|
46
|
+
# :nocov:
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
39
50
|
|
40
51
|
# Default implementation of the argument mapper to allow
|
41
52
|
# native database support for bind variables and prepared
|
42
53
|
# statements (as opposed to the emulated ones used by default).
|
43
54
|
module ArgumentMapper
|
44
|
-
|
45
|
-
attr_accessor :prepared_statement_name
|
55
|
+
Dataset.def_deprecated_opts_setter(self, :prepared_statement_name, :bind_arguments)
|
46
56
|
|
57
|
+
# The name of the prepared statement, if any.
|
58
|
+
def prepared_statement_name
|
59
|
+
@opts[:prepared_statement_name]
|
60
|
+
end
|
61
|
+
|
47
62
|
# The bind arguments to use for running this prepared statement
|
48
|
-
|
63
|
+
def bind_arguments
|
64
|
+
@opts[:bind_arguments]
|
65
|
+
end
|
49
66
|
|
50
67
|
# Set the bind arguments based on the hash and call super.
|
51
68
|
def call(bind_vars={}, &block)
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
69
|
+
sql = prepared_sql
|
70
|
+
prepared_args.freeze
|
71
|
+
ps = bind(bind_vars)
|
72
|
+
ps.clone(:bind_arguments=>ps.map_to_prepared_args(ps.opts[:bind_vars]), :sql=>sql, :prepared_sql=>sql).run(&block)
|
56
73
|
end
|
57
74
|
|
58
75
|
# Override the given *_sql method based on the type, and
|
59
76
|
# cache the result of the sql.
|
60
77
|
def prepared_sql
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
@prepared_sql
|
78
|
+
if sql = @opts[:prepared_sql] || cache_get(:_prepared_sql)
|
79
|
+
return sql
|
80
|
+
end
|
81
|
+
cache_set(:_prepared_sql, super)
|
66
82
|
end
|
67
83
|
end
|
68
84
|
|
@@ -73,25 +89,37 @@ module Sequel
|
|
73
89
|
# into the query, which works on all databases, as it is no different
|
74
90
|
# from using the dataset without bind variables.
|
75
91
|
module PreparedStatementMethods
|
92
|
+
Dataset.def_deprecated_opts_setter(self, :log_sql, :prepared_type, :prepared_args, :orig_dataset, :prepared_modify_values)
|
93
|
+
|
76
94
|
PLACEHOLDER_RE = /\A\$(.*)\z/
|
77
95
|
|
78
96
|
# Whether to log the full SQL query. By default, just the prepared statement
|
79
97
|
# name is generally logged on adapters that support native prepared statements.
|
80
|
-
|
98
|
+
def log_sql
|
99
|
+
@opts[:log_sql]
|
100
|
+
end
|
81
101
|
|
82
102
|
# The type of prepared statement, should be one of :select, :first,
|
83
103
|
# :insert, :update, or :delete
|
84
|
-
|
104
|
+
def prepared_type
|
105
|
+
@opts[:prepared_type]
|
106
|
+
end
|
85
107
|
|
86
108
|
# The array/hash of bound variable placeholder names.
|
87
|
-
|
109
|
+
def prepared_args
|
110
|
+
@opts[:prepared_args]
|
111
|
+
end
|
88
112
|
|
89
113
|
# The dataset that created this prepared statement.
|
90
|
-
|
114
|
+
def orig_dataset
|
115
|
+
@opts[:orig_dataset]
|
116
|
+
end
|
91
117
|
|
92
118
|
# The argument to supply to insert and update, which may use
|
93
119
|
# placeholders specified by prepared_args
|
94
|
-
|
120
|
+
def prepared_modify_values
|
121
|
+
@opts[:prepared_modify_values]
|
122
|
+
end
|
95
123
|
|
96
124
|
# Sets the prepared_args to the given hash and runs the
|
97
125
|
# prepared statement.
|
@@ -115,18 +143,18 @@ module Sequel
|
|
115
143
|
# Returns the SQL for the prepared statement, depending on
|
116
144
|
# the type of the statement and the prepared_modify_values.
|
117
145
|
def prepared_sql
|
118
|
-
case
|
146
|
+
case prepared_type
|
119
147
|
when :select, :all, :each
|
120
148
|
# Most common scenario, so listed first.
|
121
149
|
select_sql
|
122
150
|
when :first
|
123
151
|
clone(:limit=>1).select_sql
|
124
152
|
when :insert_select
|
125
|
-
insert_select_sql(
|
126
|
-
when :insert
|
127
|
-
insert_sql(
|
153
|
+
insert_select_sql(*prepared_modify_values)
|
154
|
+
when :insert, :insert_pk
|
155
|
+
insert_sql(*prepared_modify_values)
|
128
156
|
when :update
|
129
|
-
update_sql(
|
157
|
+
update_sql(*prepared_modify_values)
|
130
158
|
when :delete
|
131
159
|
delete_sql
|
132
160
|
else
|
@@ -163,7 +191,7 @@ module Sequel
|
|
163
191
|
# :select running #all to get all of the rows, and the other
|
164
192
|
# types running the method with the same name as the type.
|
165
193
|
def run(&block)
|
166
|
-
case
|
194
|
+
case prepared_type
|
167
195
|
when :select, :all
|
168
196
|
# Most common scenario, so listed first
|
169
197
|
all(&block)
|
@@ -174,17 +202,19 @@ module Sequel
|
|
174
202
|
when :first
|
175
203
|
first
|
176
204
|
when :insert, :update, :delete
|
177
|
-
if opts[:returning] && supports_returning?(
|
205
|
+
if opts[:returning] && supports_returning?(prepared_type)
|
178
206
|
returning_fetch_rows(prepared_sql)
|
179
|
-
elsif
|
207
|
+
elsif prepared_type == :delete
|
180
208
|
delete
|
181
209
|
else
|
182
|
-
send(
|
210
|
+
send(prepared_type, *prepared_modify_values)
|
183
211
|
end
|
212
|
+
when :insert_pk
|
213
|
+
fetch_rows(prepared_sql){|r| return r.values.first}
|
184
214
|
when Array
|
185
|
-
case
|
215
|
+
case prepared_type.at(0)
|
186
216
|
when :map, :to_hash, :to_hash_groups
|
187
|
-
send(
|
217
|
+
send(*prepared_type, &block)
|
188
218
|
end
|
189
219
|
else
|
190
220
|
all(&block)
|
@@ -213,10 +243,9 @@ module Sequel
|
|
213
243
|
# support and using the same argument hash so that you can use
|
214
244
|
# bind variables/prepared arguments in subselects.
|
215
245
|
def subselect_sql_append(sql, ds)
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
ps.prepared_sql
|
246
|
+
ds.clone(:append_sql=>sql, :prepared_args=>prepared_args, :bind_vars=>@opts[:bind_vars]).
|
247
|
+
send(:to_prepared_statement, :select, nil, :extend=>prepared_statement_modules).
|
248
|
+
prepared_sql
|
220
249
|
end
|
221
250
|
end
|
222
251
|
|
@@ -255,22 +284,32 @@ module Sequel
|
|
255
284
|
# already been set for this dataset, they are updated with the contents
|
256
285
|
# of bind_vars.
|
257
286
|
#
|
258
|
-
# DB[:table].
|
287
|
+
# DB[:table].where(:id=>:$id).bind(:id=>1).call(:first)
|
259
288
|
# # SELECT * FROM table WHERE id = ? LIMIT 1 -- (1)
|
260
289
|
# # => {:id=>1}
|
261
290
|
def bind(bind_vars={})
|
262
|
-
|
291
|
+
bind_vars = if bv = @opts[:bind_vars]
|
292
|
+
Hash[bv].merge!(bind_vars).freeze
|
293
|
+
else
|
294
|
+
if bind_vars.frozen?
|
295
|
+
bind_vars
|
296
|
+
else
|
297
|
+
Hash[bind_vars]
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
clone(:bind_vars=>bind_vars)
|
263
302
|
end
|
264
303
|
|
265
304
|
# For the given type (:select, :first, :insert, :insert_select, :update, or :delete),
|
266
305
|
# run the sql with the bind variables specified in the hash. +values+ is a hash passed to
|
267
306
|
# insert or update (if one of those types is used), which may contain placeholders.
|
268
307
|
#
|
269
|
-
# DB[:table].
|
308
|
+
# DB[:table].where(:id=>:$id).call(:first, :id=>1)
|
270
309
|
# # SELECT * FROM table WHERE id = ? LIMIT 1 -- (1)
|
271
310
|
# # => {:id=>1}
|
272
311
|
def call(type, bind_variables={}, *values, &block)
|
273
|
-
|
312
|
+
to_prepared_statement(type, values, :extend=>bound_variable_modules).call(bind_variables, &block)
|
274
313
|
end
|
275
314
|
|
276
315
|
# Prepare an SQL statement for later execution. Takes a type similar to #call,
|
@@ -284,7 +323,7 @@ module Sequel
|
|
284
323
|
# the associated database, where it can be called by name.
|
285
324
|
# The following usage is identical:
|
286
325
|
#
|
287
|
-
# ps = DB[:table].
|
326
|
+
# ps = DB[:table].where(:name=>:$name).prepare(:first, :select_by_name)
|
288
327
|
#
|
289
328
|
# ps.call(:name=>'Blah')
|
290
329
|
# # SELECT * FROM table WHERE name = ? -- ('Blah')
|
@@ -292,8 +331,17 @@ module Sequel
|
|
292
331
|
#
|
293
332
|
# DB.call(:select_by_name, :name=>'Blah') # Same thing
|
294
333
|
def prepare(type, name=nil, *values)
|
295
|
-
ps = to_prepared_statement(type, values)
|
296
|
-
|
334
|
+
ps = to_prepared_statement(type, values, :name=>name, :extend=>prepared_statement_modules)
|
335
|
+
|
336
|
+
if name
|
337
|
+
ps.prepared_sql
|
338
|
+
db.set_prepared_statement(name, ps)
|
339
|
+
else
|
340
|
+
# :nocov:
|
341
|
+
Sequel::Deprecation.deprecate("Dataset#prepare will change to requiring a name argument in Sequel 5, please update your code.") unless name
|
342
|
+
# :nocov:
|
343
|
+
end
|
344
|
+
|
297
345
|
ps
|
298
346
|
end
|
299
347
|
|
@@ -301,13 +349,13 @@ module Sequel
|
|
301
349
|
|
302
350
|
# Return a cloned copy of the current dataset extended with
|
303
351
|
# PreparedStatementMethods, setting the type and modify values.
|
304
|
-
def to_prepared_statement(type, values=nil)
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
352
|
+
def to_prepared_statement(type, values=nil, opts=OPTS)
|
353
|
+
mods = opts[:extend] || []
|
354
|
+
mods += [PreparedStatementMethods]
|
355
|
+
|
356
|
+
bind.
|
357
|
+
clone(:prepared_statement_name=>opts[:name], :prepared_type=>type, :prepared_modify_values=>values, :orig_dataset=>self, :no_cache_sql=>true, :prepared_args=>@opts[:prepared_args]||[]).
|
358
|
+
with_extend(*mods)
|
311
359
|
end
|
312
360
|
|
313
361
|
private
|
@@ -317,6 +365,14 @@ module Sequel
|
|
317
365
|
false
|
318
366
|
end
|
319
367
|
|
368
|
+
def bound_variable_modules
|
369
|
+
prepared_statement_modules
|
370
|
+
end
|
371
|
+
|
372
|
+
def prepared_statement_modules
|
373
|
+
[]
|
374
|
+
end
|
375
|
+
|
320
376
|
# The argument placeholder. Most databases used unnumbered
|
321
377
|
# arguments with question marks, so that is the default.
|
322
378
|
def prepared_arg_placeholder
|