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.
- data/CHANGELOG +485 -3
- data/README.rdoc +20 -6
- data/Rakefile +37 -19
- data/bin/sequel +1 -5
- data/doc/association_basics.rdoc +249 -43
- data/doc/dataset_basics.rdoc +4 -4
- data/doc/dataset_filtering.rdoc +8 -0
- data/doc/mass_assignment.rdoc +54 -0
- data/doc/migration.rdoc +15 -538
- data/doc/model_hooks.rdoc +72 -27
- data/doc/opening_databases.rdoc +89 -50
- data/doc/prepared_statements.rdoc +40 -13
- data/doc/reflection.rdoc +8 -2
- data/doc/release_notes/3.22.0.txt +39 -0
- data/doc/release_notes/3.23.0.txt +172 -0
- data/doc/release_notes/3.24.0.txt +420 -0
- data/doc/release_notes/3.25.0.txt +88 -0
- data/doc/release_notes/3.26.0.txt +88 -0
- data/doc/release_notes/3.27.0.txt +82 -0
- data/doc/release_notes/3.28.0.txt +304 -0
- data/doc/release_notes/3.29.0.txt +459 -0
- data/doc/release_notes/3.30.0.txt +135 -0
- data/doc/release_notes/3.31.0.txt +146 -0
- data/doc/schema_modification.rdoc +547 -0
- data/doc/sharding.rdoc +7 -1
- data/doc/testing.rdoc +129 -0
- data/doc/transactions.rdoc +137 -0
- data/doc/virtual_rows.rdoc +2 -2
- data/lib/sequel/adapters/ado/mssql.rb +18 -6
- data/lib/sequel/adapters/ado.rb +40 -18
- data/lib/sequel/adapters/amalgalite.rb +17 -9
- data/lib/sequel/adapters/db2.rb +175 -86
- data/lib/sequel/adapters/dbi.rb +15 -15
- data/lib/sequel/adapters/do/mysql.rb +5 -7
- data/lib/sequel/adapters/do/postgres.rb +0 -5
- data/lib/sequel/adapters/do/sqlite.rb +0 -5
- data/lib/sequel/adapters/do.rb +17 -36
- data/lib/sequel/adapters/firebird.rb +27 -208
- data/lib/sequel/adapters/ibmdb.rb +448 -0
- data/lib/sequel/adapters/informix.rb +6 -23
- data/lib/sequel/adapters/jdbc/as400.rb +16 -34
- data/lib/sequel/adapters/jdbc/db2.rb +45 -0
- data/lib/sequel/adapters/jdbc/derby.rb +247 -0
- data/lib/sequel/adapters/jdbc/firebird.rb +29 -0
- data/lib/sequel/adapters/jdbc/h2.rb +56 -29
- data/lib/sequel/adapters/jdbc/hsqldb.rb +170 -0
- data/lib/sequel/adapters/jdbc/informix.rb +26 -0
- data/lib/sequel/adapters/jdbc/jtds.rb +34 -0
- data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
- data/lib/sequel/adapters/jdbc/mysql.rb +11 -11
- data/lib/sequel/adapters/jdbc/oracle.rb +81 -25
- data/lib/sequel/adapters/jdbc/postgresql.rb +9 -13
- data/lib/sequel/adapters/jdbc/sqlite.rb +2 -6
- data/lib/sequel/adapters/jdbc/sqlserver.rb +71 -0
- data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
- data/lib/sequel/adapters/jdbc.rb +231 -78
- data/lib/sequel/adapters/mock.rb +335 -0
- data/lib/sequel/adapters/mysql.rb +82 -184
- data/lib/sequel/adapters/mysql2.rb +26 -25
- data/lib/sequel/adapters/odbc/db2.rb +17 -0
- data/lib/sequel/adapters/odbc/mssql.rb +1 -6
- data/lib/sequel/adapters/odbc.rb +28 -9
- data/lib/sequel/adapters/openbase.rb +3 -5
- data/lib/sequel/adapters/oracle.rb +351 -53
- data/lib/sequel/adapters/postgres.rb +194 -33
- data/lib/sequel/adapters/shared/access.rb +32 -9
- data/lib/sequel/adapters/shared/db2.rb +321 -0
- data/lib/sequel/adapters/shared/firebird.rb +221 -0
- data/lib/sequel/adapters/shared/informix.rb +53 -0
- data/lib/sequel/adapters/shared/mssql.rb +231 -106
- data/lib/sequel/adapters/shared/mysql.rb +181 -63
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +149 -0
- data/lib/sequel/adapters/shared/oracle.rb +231 -41
- data/lib/sequel/adapters/shared/postgres.rb +214 -82
- data/lib/sequel/adapters/shared/progress.rb +4 -7
- data/lib/sequel/adapters/shared/sqlite.rb +201 -57
- data/lib/sequel/adapters/sqlite.rb +29 -21
- data/lib/sequel/adapters/swift/mysql.rb +12 -7
- data/lib/sequel/adapters/swift/postgres.rb +0 -5
- data/lib/sequel/adapters/swift/sqlite.rb +8 -6
- data/lib/sequel/adapters/swift.rb +5 -5
- data/lib/sequel/adapters/tinytds.rb +160 -19
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +66 -0
- data/lib/sequel/adapters/utils/stored_procedures.rb +1 -11
- data/lib/sequel/ast_transformer.rb +190 -0
- data/lib/sequel/connection_pool/threaded.rb +3 -2
- data/lib/sequel/connection_pool.rb +1 -1
- data/lib/sequel/core.rb +46 -5
- data/lib/sequel/database/connecting.rb +5 -6
- data/lib/sequel/database/dataset.rb +4 -4
- data/lib/sequel/database/dataset_defaults.rb +59 -1
- data/lib/sequel/database/logging.rb +1 -1
- data/lib/sequel/database/misc.rb +104 -19
- data/lib/sequel/database/query.rb +153 -58
- data/lib/sequel/database/schema_generator.rb +17 -7
- data/lib/sequel/database/schema_methods.rb +59 -29
- data/lib/sequel/dataset/actions.rb +231 -76
- data/lib/sequel/dataset/features.rb +91 -8
- data/lib/sequel/dataset/graph.rb +38 -11
- data/lib/sequel/dataset/misc.rb +50 -23
- data/lib/sequel/dataset/mutation.rb +5 -6
- data/lib/sequel/dataset/prepared_statements.rb +48 -27
- data/lib/sequel/dataset/query.rb +236 -43
- data/lib/sequel/dataset/sql.rb +665 -253
- data/lib/sequel/dataset.rb +8 -0
- data/lib/sequel/exceptions.rb +4 -0
- data/lib/sequel/extensions/columns_introspection.rb +61 -0
- data/lib/sequel/extensions/migration.rb +6 -4
- data/lib/sequel/extensions/named_timezones.rb +5 -0
- data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
- data/lib/sequel/extensions/to_dot.rb +95 -83
- data/lib/sequel/model/associations.rb +1020 -337
- data/lib/sequel/model/base.rb +414 -132
- data/lib/sequel/model/errors.rb +1 -1
- data/lib/sequel/model/exceptions.rb +5 -1
- data/lib/sequel/model.rb +15 -8
- data/lib/sequel/plugins/association_pks.rb +22 -4
- data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
- data/lib/sequel/plugins/dataset_associations.rb +100 -0
- data/lib/sequel/plugins/defaults_setter.rb +58 -0
- data/lib/sequel/plugins/force_encoding.rb +6 -6
- data/lib/sequel/plugins/identity_map.rb +114 -7
- data/lib/sequel/plugins/many_through_many.rb +65 -7
- data/lib/sequel/plugins/prepared_statements.rb +151 -0
- data/lib/sequel/plugins/prepared_statements_associations.rb +84 -0
- data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
- data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
- data/lib/sequel/plugins/rcte_tree.rb +29 -15
- data/lib/sequel/plugins/serialization.rb +88 -44
- data/lib/sequel/plugins/serialization_modification_detection.rb +51 -0
- data/lib/sequel/plugins/sharding.rb +21 -54
- data/lib/sequel/plugins/single_table_inheritance.rb +3 -1
- data/lib/sequel/plugins/typecast_on_load.rb +9 -12
- data/lib/sequel/plugins/update_primary_key.rb +2 -2
- data/lib/sequel/plugins/xml_serializer.rb +3 -3
- data/lib/sequel/sql.rb +109 -52
- data/lib/sequel/timezones.rb +57 -38
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/db2_spec.rb +146 -0
- data/spec/adapters/mssql_spec.rb +111 -29
- data/spec/adapters/mysql_spec.rb +135 -123
- data/spec/adapters/oracle_spec.rb +49 -77
- data/spec/adapters/postgres_spec.rb +267 -78
- data/spec/adapters/spec_helper.rb +6 -5
- data/spec/adapters/sqlite_spec.rb +35 -21
- data/spec/core/connection_pool_spec.rb +71 -92
- data/spec/core/core_sql_spec.rb +21 -30
- data/spec/core/database_spec.rb +788 -512
- data/spec/core/dataset_spec.rb +1073 -1053
- data/spec/core/expression_filters_spec.rb +159 -42
- data/spec/core/mock_adapter_spec.rb +419 -0
- data/spec/core/object_graph_spec.rb +86 -114
- data/spec/core/schema_generator_spec.rb +3 -3
- data/spec/core/schema_spec.rb +298 -38
- data/spec/core/spec_helper.rb +6 -48
- data/spec/extensions/association_autoreloading_spec.rb +1 -10
- data/spec/extensions/association_dependencies_spec.rb +2 -12
- data/spec/extensions/association_pks_spec.rb +66 -32
- data/spec/extensions/caching_spec.rb +23 -50
- data/spec/extensions/class_table_inheritance_spec.rb +31 -83
- data/spec/extensions/columns_introspection_spec.rb +91 -0
- data/spec/extensions/composition_spec.rb +18 -13
- data/spec/extensions/dataset_associations_spec.rb +199 -0
- data/spec/extensions/defaults_setter_spec.rb +64 -0
- data/spec/extensions/hook_class_methods_spec.rb +65 -91
- data/spec/extensions/identity_map_spec.rb +114 -22
- data/spec/extensions/instance_filters_spec.rb +11 -21
- data/spec/extensions/instance_hooks_spec.rb +53 -0
- data/spec/extensions/json_serializer_spec.rb +4 -5
- data/spec/extensions/lazy_attributes_spec.rb +16 -20
- data/spec/extensions/list_spec.rb +17 -39
- data/spec/extensions/many_through_many_spec.rb +283 -250
- data/spec/extensions/migration_spec.rb +35 -32
- data/spec/extensions/named_timezones_spec.rb +23 -3
- data/spec/extensions/nested_attributes_spec.rb +97 -88
- data/spec/extensions/optimistic_locking_spec.rb +9 -20
- data/spec/extensions/prepared_statements_associations_spec.rb +111 -0
- data/spec/extensions/prepared_statements_safe_spec.rb +61 -0
- data/spec/extensions/prepared_statements_spec.rb +53 -0
- data/spec/extensions/prepared_statements_with_pk_spec.rb +31 -0
- data/spec/extensions/pretty_table_spec.rb +1 -6
- data/spec/extensions/rcte_tree_spec.rb +41 -43
- data/spec/extensions/schema_dumper_spec.rb +5 -8
- data/spec/extensions/schema_spec.rb +13 -21
- data/spec/extensions/serialization_modification_detection_spec.rb +37 -0
- data/spec/extensions/serialization_spec.rb +72 -43
- data/spec/extensions/sharding_spec.rb +66 -140
- data/spec/extensions/single_table_inheritance_spec.rb +18 -29
- data/spec/extensions/spec_helper.rb +13 -61
- data/spec/extensions/sql_expr_spec.rb +20 -60
- data/spec/extensions/tactical_eager_loading_spec.rb +9 -19
- data/spec/extensions/thread_local_timezones_spec.rb +22 -2
- data/spec/extensions/timestamps_spec.rb +6 -6
- data/spec/extensions/to_dot_spec.rb +4 -7
- data/spec/extensions/touch_spec.rb +13 -14
- data/spec/extensions/tree_spec.rb +11 -26
- data/spec/extensions/typecast_on_load_spec.rb +1 -6
- data/spec/extensions/update_primary_key_spec.rb +30 -24
- data/spec/extensions/validation_class_methods_spec.rb +30 -51
- data/spec/extensions/validation_helpers_spec.rb +16 -35
- data/spec/extensions/xml_serializer_spec.rb +16 -4
- data/spec/integration/associations_test.rb +537 -21
- data/spec/integration/database_test.rb +4 -2
- data/spec/integration/dataset_test.rb +461 -65
- data/spec/integration/eager_loader_test.rb +19 -21
- data/spec/integration/model_test.rb +80 -1
- data/spec/integration/plugin_test.rb +304 -116
- data/spec/integration/prepared_statement_test.rb +212 -122
- data/spec/integration/schema_test.rb +161 -30
- data/spec/integration/spec_helper.rb +39 -30
- data/spec/integration/timezone_test.rb +38 -12
- data/spec/integration/transaction_test.rb +172 -5
- data/spec/integration/type_test.rb +17 -3
- data/spec/model/association_reflection_spec.rb +201 -7
- data/spec/model/associations_spec.rb +865 -662
- data/spec/model/base_spec.rb +275 -95
- data/spec/model/dataset_methods_spec.rb +7 -27
- data/spec/model/eager_loading_spec.rb +677 -676
- data/spec/model/hooks_spec.rb +309 -67
- data/spec/model/model_spec.rb +222 -168
- data/spec/model/plugins_spec.rb +24 -13
- data/spec/model/record_spec.rb +381 -218
- data/spec/model/spec_helper.rb +13 -71
- data/spec/model/validations_spec.rb +11 -0
- metadata +115 -73
|
@@ -7,16 +7,9 @@ module Sequel
|
|
|
7
7
|
AUTO_VACUUM = [:none, :full, :incremental].freeze
|
|
8
8
|
PRIMARY_KEY_INDEX_RE = /\Asqlite_autoindex_/.freeze
|
|
9
9
|
SYNCHRONOUS = [:off, :normal, :full].freeze
|
|
10
|
-
TABLES_FILTER = "type = 'table' AND NOT name = 'sqlite_sequence'"
|
|
10
|
+
TABLES_FILTER = "type = 'table' AND NOT name = 'sqlite_sequence'".freeze
|
|
11
11
|
TEMP_STORE = [:default, :file, :memory].freeze
|
|
12
|
-
|
|
13
|
-
# Run all alter_table commands in a transaction. This is technically only
|
|
14
|
-
# needed for drop column.
|
|
15
|
-
def alter_table(name, generator=nil, &block)
|
|
16
|
-
remove_cached_schema(name)
|
|
17
|
-
generator ||= Schema::AlterTableGenerator.new(self, &block)
|
|
18
|
-
transaction{generator.operations.each{|op| alter_table_sql_list(name, [op]).flatten.each{|sql| execute_ddl(sql)}}}
|
|
19
|
-
end
|
|
12
|
+
VIEWS_FILTER = "type = 'view'".freeze
|
|
20
13
|
|
|
21
14
|
# A symbol signifying the value of the auto_vacuum PRAGMA.
|
|
22
15
|
def auto_vacuum
|
|
@@ -30,7 +23,20 @@ module Sequel
|
|
|
30
23
|
value = AUTO_VACUUM.index(value) || (raise Error, "Invalid value for auto_vacuum option. Please specify one of :none, :full, :incremental.")
|
|
31
24
|
pragma_set(:auto_vacuum, value)
|
|
32
25
|
end
|
|
26
|
+
|
|
27
|
+
# Boolean signifying the value of the case_sensitive_likePRAGMA, or nil
|
|
28
|
+
# if not using SQLite 3.2.3+.
|
|
29
|
+
def case_sensitive_like
|
|
30
|
+
pragma_get(:case_sensitive_like).to_i == 1 if sqlite_version >= 30203
|
|
31
|
+
end
|
|
33
32
|
|
|
33
|
+
# Set the case_sensitive_like PRAGMA using the given boolean value, if using
|
|
34
|
+
# SQLite 3.2.3+. If not using 3.2.3+, no error is raised. See pragma_set.
|
|
35
|
+
# Consider using the :case_sensitive_like Database option instead.
|
|
36
|
+
def case_sensitive_like=(value)
|
|
37
|
+
pragma_set(:case_sensitive_like, !!value ? 'on' : 'off') if sqlite_version >= 30203
|
|
38
|
+
end
|
|
39
|
+
|
|
34
40
|
# SQLite uses the :sqlite database type.
|
|
35
41
|
def database_type
|
|
36
42
|
:sqlite
|
|
@@ -96,11 +102,29 @@ module Sequel
|
|
|
96
102
|
end
|
|
97
103
|
end
|
|
98
104
|
|
|
105
|
+
# SQLite supports CREATE TABLE IF NOT EXISTS syntax since 3.3.0.
|
|
106
|
+
def supports_create_table_if_not_exists?
|
|
107
|
+
sqlite_version >= 30300
|
|
108
|
+
end
|
|
109
|
+
|
|
99
110
|
# SQLite 3.6.8+ supports savepoints.
|
|
100
111
|
def supports_savepoints?
|
|
101
112
|
sqlite_version >= 30608
|
|
102
113
|
end
|
|
103
114
|
|
|
115
|
+
# Override the default setting for whether to use timezones in timestamps.
|
|
116
|
+
# For backwards compatibility, it is set to +true+ by default.
|
|
117
|
+
# Anyone wanting to use SQLite's datetime functions should set it to +false+
|
|
118
|
+
# using this method. It's possible that the default will change in a future version,
|
|
119
|
+
# so anyone relying on timezones in timestamps should set this to +true+.
|
|
120
|
+
attr_writer :use_timestamp_timezones
|
|
121
|
+
|
|
122
|
+
# SQLite supports timezones in timestamps, since it just stores them as strings,
|
|
123
|
+
# but it breaks the usage of SQLite's datetime functions.
|
|
124
|
+
def use_timestamp_timezones?
|
|
125
|
+
defined?(@use_timestamp_timezones) ? @use_timestamp_timezones : (@use_timestamp_timezones = true)
|
|
126
|
+
end
|
|
127
|
+
|
|
104
128
|
# A symbol signifying the value of the synchronous PRAGMA.
|
|
105
129
|
def synchronous
|
|
106
130
|
SYNCHRONOUS[pragma_get(:synchronous).to_i]
|
|
@@ -118,8 +142,7 @@ module Sequel
|
|
|
118
142
|
# Options:
|
|
119
143
|
# * :server - Set the server to use.
|
|
120
144
|
def tables(opts={})
|
|
121
|
-
|
|
122
|
-
metadata_dataset.from(:sqlite_master).server(opts[:server]).filter(TABLES_FILTER).map{|r| m.call(r[:name])}
|
|
145
|
+
tables_and_views(TABLES_FILTER, opts)
|
|
123
146
|
end
|
|
124
147
|
|
|
125
148
|
# A symbol signifying the value of the temp_store PRAGMA.
|
|
@@ -134,8 +157,32 @@ module Sequel
|
|
|
134
157
|
pragma_set(:temp_store, value)
|
|
135
158
|
end
|
|
136
159
|
|
|
160
|
+
# Array of symbols specifying the view names in the current database.
|
|
161
|
+
#
|
|
162
|
+
# Options:
|
|
163
|
+
# * :server - Set the server to use.
|
|
164
|
+
def views(opts={})
|
|
165
|
+
tables_and_views(VIEWS_FILTER, opts)
|
|
166
|
+
end
|
|
167
|
+
|
|
137
168
|
private
|
|
138
169
|
|
|
170
|
+
# Run all alter_table commands in a transaction. This is technically only
|
|
171
|
+
# needed for drop column.
|
|
172
|
+
def apply_alter_table(table, ops)
|
|
173
|
+
transaction do
|
|
174
|
+
if ops.length > 1 && ops.all?{|op| op[:op] == :add_constraint}
|
|
175
|
+
# If you are just doing constraints, apply all of them at the same time,
|
|
176
|
+
# as otherwise all but the last one get lost.
|
|
177
|
+
alter_table_sql_list(table, [{:op=>:add_constraints, :ops=>ops}]).flatten.each{|sql| execute_ddl(sql)}
|
|
178
|
+
else
|
|
179
|
+
# Run each operation separately, as later operations may depend on the
|
|
180
|
+
# results of earlier operations.
|
|
181
|
+
ops.each{|op| alter_table_sql_list(table, [op]).flatten.each{|sql| execute_ddl(sql)}}
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
139
186
|
# SQLite supports limited table modification. You can add a column
|
|
140
187
|
# or an index. Dropping columns is supported by copying the table into
|
|
141
188
|
# a temporary table, dropping the table, and creating a new table without
|
|
@@ -162,11 +209,26 @@ module Sequel
|
|
|
162
209
|
duplicate_table(table){|columns| columns.each{|s| s[:null] = op[:null] if s[:name].to_s == op[:name].to_s}}
|
|
163
210
|
when :set_column_type
|
|
164
211
|
duplicate_table(table){|columns| columns.each{|s| s[:type] = op[:type] if s[:name].to_s == op[:name].to_s}}
|
|
212
|
+
when :drop_constraint
|
|
213
|
+
case op[:type]
|
|
214
|
+
when :primary_key
|
|
215
|
+
duplicate_table(table){|columns| columns.each{|s| s[:primary_key] = nil}}
|
|
216
|
+
when :foreign_key
|
|
217
|
+
duplicate_table(table){|columns| columns.each{|s| s[:table] = nil}}
|
|
218
|
+
when :unique
|
|
219
|
+
duplicate_table(table)
|
|
220
|
+
else
|
|
221
|
+
raise Error, "Unsupported :type option for drop_constraint: #{op[:type].inspect}"
|
|
222
|
+
end
|
|
223
|
+
when :add_constraint
|
|
224
|
+
duplicate_table(table, :constraints=>[op])
|
|
225
|
+
when :add_constraints
|
|
226
|
+
duplicate_table(table, :constraints=>op[:ops])
|
|
165
227
|
else
|
|
166
|
-
raise Error, "Unsupported ALTER TABLE operation"
|
|
228
|
+
raise Error, "Unsupported ALTER TABLE operation: #{op[:op].inspect}"
|
|
167
229
|
end
|
|
168
230
|
end
|
|
169
|
-
|
|
231
|
+
|
|
170
232
|
# The array of column symbols in the table, except for ones given in opts[:except]
|
|
171
233
|
def backup_table_name(table, opts={})
|
|
172
234
|
table = table.gsub('`', '')
|
|
@@ -176,17 +238,14 @@ module Sequel
|
|
|
176
238
|
end
|
|
177
239
|
end
|
|
178
240
|
|
|
179
|
-
# Allow use without a generator, needed for the alter table hackery that Sequel allows.
|
|
180
|
-
def column_list_sql(generator)
|
|
181
|
-
generator.is_a?(Schema::Generator) ? super : generator.map{|c| column_definition_sql(c)}.join(', ')
|
|
182
|
-
end
|
|
183
|
-
|
|
184
241
|
# Array of PRAGMA SQL statements based on the Database options that should be applied to
|
|
185
242
|
# new connections.
|
|
186
243
|
def connection_pragmas
|
|
187
244
|
ps = []
|
|
188
245
|
v = typecast_value_boolean(opts.fetch(:foreign_keys, 1))
|
|
189
246
|
ps << "PRAGMA foreign_keys = #{v ? 1 : 0}"
|
|
247
|
+
v = typecast_value_boolean(opts.fetch(:case_sensitive_like, 1))
|
|
248
|
+
ps << "PRAGMA case_sensitive_like = #{v ? 1 : 0}"
|
|
190
249
|
[[:auto_vacuum, AUTO_VACUUM], [:synchronous, SYNCHRONOUS], [:temp_store, TEMP_STORE]].each do |prag, con|
|
|
191
250
|
if v = opts[prag]
|
|
192
251
|
raise(Error, "Value for PRAGMA #{prag} not supported, should be one of #{con.join(', ')}") unless v = con.index(v.to_sym)
|
|
@@ -208,15 +267,20 @@ module Sequel
|
|
|
208
267
|
cols.reject!{|c| nono.include? c[:name] }
|
|
209
268
|
end
|
|
210
269
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
270
|
+
begin
|
|
271
|
+
if foreign_keys
|
|
272
|
+
metadata_dataset.with_sql("PRAGMA foreign_key_list(?)", input_identifier_meth.call(table)).each do |row|
|
|
273
|
+
c = cols.find {|co| co[:name] == row[:from] } or next
|
|
274
|
+
c[:table] = row[:table]
|
|
275
|
+
c[:key] = row[:to]
|
|
276
|
+
c[:on_update] = on_delete_sql_to_sym(row[:on_update])
|
|
277
|
+
c[:on_delete] = on_delete_sql_to_sym(row[:on_delete])
|
|
278
|
+
# is there any way to get deferrable status?
|
|
279
|
+
end
|
|
219
280
|
end
|
|
281
|
+
rescue Sequel::DatabaseError
|
|
282
|
+
# Doesn't work correctly on some versions of JDBC SQLite,
|
|
283
|
+
# giving a "query does not return ResultSet" error.
|
|
220
284
|
end
|
|
221
285
|
cols
|
|
222
286
|
end
|
|
@@ -231,17 +295,26 @@ module Sequel
|
|
|
231
295
|
opts[:old_columns_proc].call(old_columns) if opts[:old_columns_proc]
|
|
232
296
|
|
|
233
297
|
yield def_columns if block_given?
|
|
234
|
-
|
|
298
|
+
|
|
299
|
+
constraints = (opts[:constraints] || []).dup
|
|
300
|
+
pks = []
|
|
301
|
+
def_columns.each{|c| pks << c[:name] if c[:primary_key]}
|
|
302
|
+
if pks.length > 1
|
|
303
|
+
constraints << {:type=>:primary_key, :columns=>pks}
|
|
304
|
+
def_columns.each{|c| c[:primary_key] = false if c[:primary_key]}
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
def_columns_str = (def_columns.map{|c| column_definition_sql(c)} + constraints.map{|c| constraint_definition_sql(c)}).join(', ')
|
|
235
308
|
new_columns = old_columns.dup
|
|
236
309
|
opts[:new_columns_proc].call(new_columns) if opts[:new_columns_proc]
|
|
237
310
|
|
|
238
311
|
qt = quote_schema_table(table)
|
|
239
312
|
bt = quote_identifier(backup_table_name(qt))
|
|
240
313
|
a = [
|
|
241
|
-
"
|
|
242
|
-
"
|
|
243
|
-
"
|
|
244
|
-
"
|
|
314
|
+
"ALTER TABLE #{qt} RENAME TO #{bt}",
|
|
315
|
+
"CREATE TABLE #{qt}(#{def_columns_str})",
|
|
316
|
+
"INSERT INTO #{qt}(#{dataset.send(:identifier_list, new_columns)}) SELECT #{dataset.send(:identifier_list, old_columns)} FROM #{bt}",
|
|
317
|
+
"DROP TABLE #{bt}"
|
|
245
318
|
]
|
|
246
319
|
indexes(table).each do |name, h|
|
|
247
320
|
if (h[:columns].map{|x| x.to_s} - new_columns).empty?
|
|
@@ -280,7 +353,7 @@ module Sequel
|
|
|
280
353
|
|
|
281
354
|
# Parse the output of the table_info pragma
|
|
282
355
|
def parse_pragma(table_name, opts)
|
|
283
|
-
metadata_dataset.with_sql("PRAGMA table_info(?)", input_identifier_meth.call(table_name)).map do |row|
|
|
356
|
+
metadata_dataset.with_sql("PRAGMA table_info(?)", input_identifier_meth(opts[:dataset]).call(table_name)).map do |row|
|
|
284
357
|
row.delete(:cid)
|
|
285
358
|
row[:allow_null] = row.delete(:notnull).to_i == 0
|
|
286
359
|
row[:default] = row.delete(:dflt_value)
|
|
@@ -300,12 +373,18 @@ module Sequel
|
|
|
300
373
|
# SQLite supports schema parsing using the table_info PRAGMA, so
|
|
301
374
|
# parse the output of that into the format Sequel expects.
|
|
302
375
|
def schema_parse_table(table_name, opts)
|
|
303
|
-
m = output_identifier_meth
|
|
376
|
+
m = output_identifier_meth(opts[:dataset])
|
|
304
377
|
parse_pragma(table_name, opts).map do |row|
|
|
305
378
|
[m.call(row.delete(:name)), row]
|
|
306
379
|
end
|
|
307
380
|
end
|
|
308
381
|
|
|
382
|
+
# Backbone of the tables and views support.
|
|
383
|
+
def tables_and_views(filter, opts)
|
|
384
|
+
m = output_identifier_meth
|
|
385
|
+
metadata_dataset.from(:sqlite_master).server(opts[:server]).filter(filter).map{|r| m.call(r[:name])}
|
|
386
|
+
end
|
|
387
|
+
|
|
309
388
|
# SQLite uses the integer data type even for bignums. This is because they
|
|
310
389
|
# are both stored internally as text, and converted when returned from
|
|
311
390
|
# the database. Using an integer type instead of bigint makes it more likely
|
|
@@ -317,28 +396,59 @@ module Sequel
|
|
|
317
396
|
|
|
318
397
|
# Instance methods for datasets that connect to an SQLite database
|
|
319
398
|
module DatasetMethods
|
|
320
|
-
SELECT_CLAUSE_METHODS = Dataset.clause_methods(:select, %w'distinct columns from join where group having compounds order limit')
|
|
321
|
-
COMMA_SEPARATOR = ', '.freeze
|
|
399
|
+
SELECT_CLAUSE_METHODS = Dataset.clause_methods(:select, %w'select distinct columns from join where group having compounds order limit')
|
|
322
400
|
CONSTANT_MAP = {:CURRENT_DATE=>"date(CURRENT_TIMESTAMP, 'localtime')".freeze, :CURRENT_TIMESTAMP=>"datetime(CURRENT_TIMESTAMP, 'localtime')".freeze, :CURRENT_TIME=>"time(CURRENT_TIMESTAMP, 'localtime')".freeze}
|
|
323
|
-
|
|
401
|
+
EXTRACT_MAP = {:year=>"'%Y'", :month=>"'%m'", :day=>"'%d'", :hour=>"'%H'", :minute=>"'%M'", :second=>"'%f'"}
|
|
402
|
+
NOT_SPACE = Dataset::NOT_SPACE
|
|
403
|
+
COMMA = Dataset::COMMA
|
|
404
|
+
PAREN_CLOSE = Dataset::PAREN_CLOSE
|
|
405
|
+
AS = Dataset::AS
|
|
406
|
+
APOS = Dataset::APOS
|
|
407
|
+
EXTRACT_OPEN = "CAST(strftime(".freeze
|
|
408
|
+
EXTRACT_CLOSE = ') AS '.freeze
|
|
409
|
+
NUMERIC = 'NUMERIC'.freeze
|
|
410
|
+
INTEGER = 'INTEGER'.freeze
|
|
411
|
+
BACKTICK = '`'.freeze
|
|
412
|
+
BLOB_START = "X'".freeze
|
|
413
|
+
HSTAR = "H*".freeze
|
|
414
|
+
|
|
324
415
|
# SQLite does not support pattern matching via regular expressions.
|
|
325
416
|
# SQLite is case insensitive (depending on pragma), so use LIKE for
|
|
326
417
|
# ILIKE.
|
|
327
|
-
def
|
|
418
|
+
def complex_expression_sql_append(sql, op, args)
|
|
328
419
|
case op
|
|
329
420
|
when :~, :'!~', :'~*', :'!~*'
|
|
330
421
|
raise Error, "SQLite does not support pattern matching via regular expressions"
|
|
331
|
-
when :
|
|
332
|
-
|
|
333
|
-
|
|
422
|
+
when :ILIKE
|
|
423
|
+
super(sql, :LIKE, args.map{|a| SQL::Function.new(:upper, a)})
|
|
424
|
+
when :"NOT LIKE", :"NOT ILIKE"
|
|
425
|
+
sql << NOT_SPACE
|
|
426
|
+
complex_expression_sql_append(sql, (op == :"NOT ILIKE" ? :ILIKE : :LIKE), args)
|
|
427
|
+
when :^
|
|
428
|
+
sql << complex_expression_arg_pairs(args) do |a, b|
|
|
429
|
+
a = literal(a)
|
|
430
|
+
b = literal(b)
|
|
431
|
+
"((~(#{a} & #{b})) & (#{a} | #{b}))"
|
|
432
|
+
end
|
|
433
|
+
when :extract
|
|
434
|
+
part = args.at(0)
|
|
435
|
+
raise(Sequel::Error, "unsupported extract argument: #{part.inspect}") unless format = EXTRACT_MAP[part]
|
|
436
|
+
sql << EXTRACT_OPEN << format << COMMA
|
|
437
|
+
literal_append(sql, args.at(1))
|
|
438
|
+
sql << EXTRACT_CLOSE << (part == :second ? NUMERIC : INTEGER) << PAREN_CLOSE
|
|
334
439
|
else
|
|
335
|
-
super
|
|
440
|
+
super
|
|
336
441
|
end
|
|
337
442
|
end
|
|
338
443
|
|
|
339
|
-
#
|
|
340
|
-
|
|
341
|
-
|
|
444
|
+
# SQLite has CURRENT_TIMESTAMP and related constants in UTC instead
|
|
445
|
+
# of in localtime, so convert those constants to local time.
|
|
446
|
+
def constant_sql_append(sql, constant)
|
|
447
|
+
if c = CONSTANT_MAP[constant]
|
|
448
|
+
sql << c
|
|
449
|
+
else
|
|
450
|
+
super
|
|
451
|
+
end
|
|
342
452
|
end
|
|
343
453
|
|
|
344
454
|
# SQLite performs a TRUNCATE style DELETE if no filter is specified.
|
|
@@ -362,8 +472,20 @@ module Sequel
|
|
|
362
472
|
end
|
|
363
473
|
|
|
364
474
|
# SQLite uses the nonstandard ` (backtick) for quoting identifiers.
|
|
365
|
-
def
|
|
366
|
-
|
|
475
|
+
def quoted_identifier_append(sql, c)
|
|
476
|
+
sql << BACKTICK << c.to_s << BACKTICK
|
|
477
|
+
end
|
|
478
|
+
|
|
479
|
+
# When a qualified column is selected on SQLite and the qualifier
|
|
480
|
+
# is a subselect, the column name used is the full qualified name
|
|
481
|
+
# (including the qualifier) instead of just the column name. To
|
|
482
|
+
# get correct column names, you must use an alias.
|
|
483
|
+
def select(*cols)
|
|
484
|
+
if ((f = @opts[:from]) && f.any?{|t| t.is_a?(Dataset) || (t.is_a?(SQL::AliasedExpression) && t.expression.is_a?(Dataset))}) || ((j = @opts[:join]) && j.any?{|t| t.table.is_a?(Dataset)})
|
|
485
|
+
super(*cols.map{|c| alias_qualified_column(c)})
|
|
486
|
+
else
|
|
487
|
+
super
|
|
488
|
+
end
|
|
367
489
|
end
|
|
368
490
|
|
|
369
491
|
# SQLite does not support INTERSECT ALL or EXCEPT ALL
|
|
@@ -382,31 +504,53 @@ module Sequel
|
|
|
382
504
|
end
|
|
383
505
|
|
|
384
506
|
# SQLite supports timezones in literal timestamps, since it stores them
|
|
385
|
-
# as text.
|
|
507
|
+
# as text. But using timezones in timestamps breaks SQLite datetime
|
|
508
|
+
# functions, so we allow the user to override the default per database.
|
|
386
509
|
def supports_timestamp_timezones?
|
|
387
|
-
|
|
510
|
+
db.use_timestamp_timezones?
|
|
388
511
|
end
|
|
389
512
|
|
|
513
|
+
# SQLite cannot use WHERE 't'.
|
|
514
|
+
def supports_where_true?
|
|
515
|
+
false
|
|
516
|
+
end
|
|
517
|
+
|
|
390
518
|
private
|
|
391
519
|
|
|
392
520
|
# SQLite uses string literals instead of identifiers in AS clauses.
|
|
393
|
-
def
|
|
521
|
+
def as_sql_append(sql, aliaz)
|
|
394
522
|
aliaz = aliaz.value if aliaz.is_a?(SQL::Identifier)
|
|
395
|
-
|
|
523
|
+
sql << AS
|
|
524
|
+
literal_append(sql, aliaz.to_s)
|
|
525
|
+
end
|
|
526
|
+
|
|
527
|
+
# If col is a qualified column, alias it to the same as the column name
|
|
528
|
+
def alias_qualified_column(col)
|
|
529
|
+
case col
|
|
530
|
+
when Symbol
|
|
531
|
+
t, c, a = split_symbol(col)
|
|
532
|
+
if t && !a
|
|
533
|
+
alias_qualified_column(SQL::QualifiedIdentifier.new(t, c))
|
|
534
|
+
else
|
|
535
|
+
col
|
|
536
|
+
end
|
|
537
|
+
when SQL::QualifiedIdentifier
|
|
538
|
+
SQL::AliasedExpression.new(col, col.column)
|
|
539
|
+
else
|
|
540
|
+
col
|
|
541
|
+
end
|
|
396
542
|
end
|
|
397
543
|
|
|
398
544
|
# SQL fragment specifying a list of identifiers
|
|
399
545
|
def identifier_list(columns)
|
|
400
|
-
columns.map{|i| quote_identifier(i)}.join(
|
|
546
|
+
columns.map{|i| quote_identifier(i)}.join(COMMA)
|
|
401
547
|
end
|
|
402
548
|
|
|
403
549
|
# SQLite uses a preceding X for hex escaping strings
|
|
404
|
-
def
|
|
405
|
-
|
|
406
|
-
v.each_byte{|x| blob << sprintf('%02x', x)}
|
|
407
|
-
"X'#{blob}'"
|
|
550
|
+
def literal_blob_append(sql, v)
|
|
551
|
+
sql << BLOB_START << v.unpack(HSTAR).first << APOS
|
|
408
552
|
end
|
|
409
|
-
|
|
553
|
+
|
|
410
554
|
# SQLite does not support the SQL WITH clause
|
|
411
555
|
def select_clause_methods
|
|
412
556
|
SELECT_CLAUSE_METHODS
|
|
@@ -416,7 +560,7 @@ module Sequel
|
|
|
416
560
|
def select_lock_sql(sql)
|
|
417
561
|
super unless @opts[:lock] == :update
|
|
418
562
|
end
|
|
419
|
-
|
|
563
|
+
|
|
420
564
|
# SQLite treats a DELETE with no WHERE clause as a TRUNCATE
|
|
421
565
|
def _truncate_sql(table)
|
|
422
566
|
"DELETE FROM #{table}"
|
|
@@ -13,26 +13,21 @@ module Sequel
|
|
|
13
13
|
TYPE_TRANSLATOR = tt = Class.new do
|
|
14
14
|
FALSE_VALUES = %w'0 false f no n'.freeze
|
|
15
15
|
def boolean(s) !FALSE_VALUES.include?(s.downcase) end
|
|
16
|
-
def blob(s) ::Sequel::SQL::Blob.new(s) end
|
|
17
16
|
def integer(s) s.to_i end
|
|
18
17
|
def float(s) s.to_f end
|
|
19
18
|
def numeric(s) ::BigDecimal.new(s) rescue s end
|
|
20
|
-
def date(s) ::Sequel.string_to_date(s) end
|
|
21
|
-
def time(s) ::Sequel.string_to_time(s) end
|
|
22
|
-
def timestamp(s) ::Sequel.database_to_application_timestamp(s) end
|
|
23
19
|
end.new
|
|
24
20
|
|
|
25
21
|
# Hash with string keys and callable values for converting SQLite types.
|
|
26
22
|
SQLITE_TYPES = {}
|
|
27
23
|
{
|
|
28
|
-
%w'
|
|
29
|
-
%w'
|
|
30
|
-
%w'time' => tt.method(:time),
|
|
24
|
+
%w'date' => ::Sequel.method(:string_to_date),
|
|
25
|
+
%w'time' => ::Sequel.method(:string_to_time),
|
|
31
26
|
%w'bit bool boolean' => tt.method(:boolean),
|
|
32
27
|
%w'integer smallint mediumint int bigint' => tt.method(:integer),
|
|
33
28
|
%w'numeric decimal money' => tt.method(:numeric),
|
|
34
29
|
%w'float double real dec fixed' + ['double precision'] => tt.method(:float),
|
|
35
|
-
%w'blob' =>
|
|
30
|
+
%w'blob' => ::Sequel::SQL::Blob.method(:new)
|
|
36
31
|
}.each do |k,v|
|
|
37
32
|
k.each{|n| SQLITE_TYPES[n] = v}
|
|
38
33
|
end
|
|
@@ -51,6 +46,16 @@ module Sequel
|
|
|
51
46
|
end
|
|
52
47
|
|
|
53
48
|
private_class_method :uri_to_options
|
|
49
|
+
|
|
50
|
+
# The conversion procs to use for this database
|
|
51
|
+
attr_reader :conversion_procs
|
|
52
|
+
|
|
53
|
+
def initialize(opts={})
|
|
54
|
+
super
|
|
55
|
+
@conversion_procs = SQLITE_TYPES.dup
|
|
56
|
+
@conversion_procs['timestamp'] = method(:to_application_timestamp)
|
|
57
|
+
@conversion_procs['datetime'] = method(:to_application_timestamp)
|
|
58
|
+
end
|
|
54
59
|
|
|
55
60
|
# Connect to the database. Since SQLite is a file based database,
|
|
56
61
|
# the only options available are :database (to specify the database
|
|
@@ -72,11 +77,6 @@ module Sequel
|
|
|
72
77
|
db
|
|
73
78
|
end
|
|
74
79
|
|
|
75
|
-
# Return instance of Sequel::SQLite::Dataset with the given options.
|
|
76
|
-
def dataset(opts = nil)
|
|
77
|
-
SQLite::Dataset.new(self, opts)
|
|
78
|
-
end
|
|
79
|
-
|
|
80
80
|
# Run the given SQL with the given arguments and yield each row.
|
|
81
81
|
def execute(sql, opts={}, &block)
|
|
82
82
|
_execute(:select, sql, opts, &block)
|
|
@@ -117,7 +117,8 @@ module Sequel
|
|
|
117
117
|
synchronize(opts[:server]) do |conn|
|
|
118
118
|
return execute_prepared_statement(conn, type, sql, opts, &block) if sql.is_a?(Symbol)
|
|
119
119
|
log_args = opts[:arguments]
|
|
120
|
-
args =
|
|
120
|
+
args = {}
|
|
121
|
+
opts.fetch(:arguments, {}).each{|k, v| args[k] = prepared_statement_argument(v)}
|
|
121
122
|
case type
|
|
122
123
|
when :select
|
|
123
124
|
log_yield(sql, log_args){conn.query(sql, args, &block)}
|
|
@@ -173,7 +174,7 @@ module Sequel
|
|
|
173
174
|
end
|
|
174
175
|
end
|
|
175
176
|
unless cps
|
|
176
|
-
cps = conn.prepare(sql)
|
|
177
|
+
cps = log_yield("Preparing #{name}: #{sql}"){conn.prepare(sql)}
|
|
177
178
|
conn.prepared_statements[name] = [cps, sql]
|
|
178
179
|
end
|
|
179
180
|
if block
|
|
@@ -204,6 +205,8 @@ module Sequel
|
|
|
204
205
|
# Dataset class for SQLite datasets that use the ruby-sqlite3 driver.
|
|
205
206
|
class Dataset < Sequel::Dataset
|
|
206
207
|
include ::Sequel::SQLite::DatasetMethods
|
|
208
|
+
|
|
209
|
+
Database::DatasetClass = self
|
|
207
210
|
|
|
208
211
|
PREPARED_ARG_PLACEHOLDER = ':'.freeze
|
|
209
212
|
|
|
@@ -217,7 +220,7 @@ module Sequel
|
|
|
217
220
|
# but with the keys converted to strings.
|
|
218
221
|
def map_to_prepared_args(hash)
|
|
219
222
|
args = {}
|
|
220
|
-
hash.each{|k,v| args[k.to_s] = v}
|
|
223
|
+
hash.each{|k,v| args[k.to_s.gsub('.', '__')] = v}
|
|
221
224
|
args
|
|
222
225
|
end
|
|
223
226
|
|
|
@@ -226,7 +229,12 @@ module Sequel
|
|
|
226
229
|
# SQLite uses a : before the name of the argument for named
|
|
227
230
|
# arguments.
|
|
228
231
|
def prepared_arg(k)
|
|
229
|
-
LiteralString.new("#{prepared_arg_placeholder}#{k}")
|
|
232
|
+
LiteralString.new("#{prepared_arg_placeholder}#{k.to_s.gsub('.', '__')}")
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
# Always assume a prepared argument.
|
|
236
|
+
def prepared_arg?(k)
|
|
237
|
+
true
|
|
230
238
|
end
|
|
231
239
|
end
|
|
232
240
|
|
|
@@ -287,7 +295,8 @@ module Sequel
|
|
|
287
295
|
def fetch_rows(sql)
|
|
288
296
|
execute(sql) do |result|
|
|
289
297
|
i = -1
|
|
290
|
-
|
|
298
|
+
cps = db.conversion_procs
|
|
299
|
+
type_procs = result.types.map{|t| cps[base_type_name(t)]}
|
|
291
300
|
cols = result.columns.map{|c| i+=1; [output_identifier(c), i, type_procs[i]]}
|
|
292
301
|
@columns = cols.map{|c| c.first}
|
|
293
302
|
result.each do |values|
|
|
@@ -314,7 +323,6 @@ module Sequel
|
|
|
314
323
|
ps.prepared_statement_name = name
|
|
315
324
|
db.prepared_statements[name] = ps
|
|
316
325
|
end
|
|
317
|
-
ps.prepared_sql
|
|
318
326
|
ps
|
|
319
327
|
end
|
|
320
328
|
|
|
@@ -326,8 +334,8 @@ module Sequel
|
|
|
326
334
|
end
|
|
327
335
|
|
|
328
336
|
# Quote the string using the adapter class method.
|
|
329
|
-
def
|
|
330
|
-
"'
|
|
337
|
+
def literal_string_append(sql, v)
|
|
338
|
+
sql << "'" << ::SQLite3::Database.quote(v) << "'"
|
|
331
339
|
end
|
|
332
340
|
|
|
333
341
|
# SQLite uses a : before the name of the argument as a placeholder.
|
|
@@ -9,11 +9,6 @@ module Sequel
|
|
|
9
9
|
module DatabaseMethods
|
|
10
10
|
include Sequel::MySQL::DatabaseMethods
|
|
11
11
|
|
|
12
|
-
# Return instance of Sequel::Swift::MySQL::Dataset with the given opts.
|
|
13
|
-
def dataset(opts=nil)
|
|
14
|
-
Sequel::Swift::MySQL::Dataset.new(self, opts)
|
|
15
|
-
end
|
|
16
|
-
|
|
17
12
|
private
|
|
18
13
|
|
|
19
14
|
# The database name for the given database.
|
|
@@ -25,11 +20,21 @@ module Sequel
|
|
|
25
20
|
def schema_column_type(db_type)
|
|
26
21
|
db_type == 'tinyint(1)' ? :boolean : super
|
|
27
22
|
end
|
|
23
|
+
|
|
24
|
+
# By default, MySQL 'where id is null' selects the last inserted id.
|
|
25
|
+
# Turn that off unless explicitly enabled.
|
|
26
|
+
def setup_connection(conn)
|
|
27
|
+
super
|
|
28
|
+
sql = "SET SQL_AUTO_IS_NULL=0"
|
|
29
|
+
log_yield(sql){conn.execute(sql)} unless opts[:auto_is_null]
|
|
30
|
+
conn
|
|
31
|
+
end
|
|
28
32
|
end
|
|
29
33
|
|
|
30
34
|
# Dataset class for MySQL datasets accessed via Swift.
|
|
31
35
|
class Dataset < Swift::Dataset
|
|
32
36
|
include Sequel::MySQL::DatasetMethods
|
|
37
|
+
APOS = Dataset::APOS
|
|
33
38
|
|
|
34
39
|
# Use execute_insert to execute the replace_sql.
|
|
35
40
|
def replace(*args)
|
|
@@ -39,8 +44,8 @@ module Sequel
|
|
|
39
44
|
private
|
|
40
45
|
|
|
41
46
|
# Use Swift's escape method for quoting.
|
|
42
|
-
def
|
|
43
|
-
db.synchronize{|c|
|
|
47
|
+
def literal_string_append(sql, s)
|
|
48
|
+
sql << APOS << db.synchronize{|c| c.escape(s)} << APOS
|
|
44
49
|
end
|
|
45
50
|
end
|
|
46
51
|
end
|
|
@@ -41,11 +41,6 @@ module Sequel
|
|
|
41
41
|
end
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
-
# Return instance of Sequel::Swift::Postgres::Dataset with the given opts.
|
|
45
|
-
def dataset(opts=nil)
|
|
46
|
-
Sequel::Swift::Postgres::Dataset.new(self, opts)
|
|
47
|
-
end
|
|
48
|
-
|
|
49
44
|
# Run the SELECT SQL on the database and yield the rows
|
|
50
45
|
def execute(sql, opts={})
|
|
51
46
|
synchronize(opts[:server]) do |conn|
|
|
@@ -8,10 +8,12 @@ module Sequel
|
|
|
8
8
|
# Database instance methods for SQLite databases accessed via Swift.
|
|
9
9
|
module DatabaseMethods
|
|
10
10
|
include Sequel::SQLite::DatabaseMethods
|
|
11
|
-
|
|
12
|
-
#
|
|
13
|
-
def
|
|
14
|
-
|
|
11
|
+
|
|
12
|
+
# Set the correct pragmas on the connection.
|
|
13
|
+
def connect(opts)
|
|
14
|
+
c = super
|
|
15
|
+
connection_pragmas.each{|s| log_yield(s){c.execute(s)}}
|
|
16
|
+
c
|
|
15
17
|
end
|
|
16
18
|
end
|
|
17
19
|
|
|
@@ -22,8 +24,8 @@ module Sequel
|
|
|
22
24
|
private
|
|
23
25
|
|
|
24
26
|
# Use Swift's escape method for quoting.
|
|
25
|
-
def
|
|
26
|
-
db.synchronize{|c|
|
|
27
|
+
def literal_string_append(sql, s)
|
|
28
|
+
sql << db.synchronize{|c| c.escape(s)}
|
|
27
29
|
end
|
|
28
30
|
end
|
|
29
31
|
end
|
|
@@ -15,16 +15,19 @@ module Sequel
|
|
|
15
15
|
DATABASE_SETUP = {:postgres=>proc do |db|
|
|
16
16
|
Sequel.ts_require 'adapters/swift/postgres'
|
|
17
17
|
db.extend(Sequel::Swift::Postgres::DatabaseMethods)
|
|
18
|
+
db.dataset_class = Sequel::Swift::Postgres::Dataset
|
|
18
19
|
db.swift_class = ::Swift::DB::Postgres
|
|
19
20
|
end,
|
|
20
21
|
:mysql=>proc do |db|
|
|
21
22
|
Sequel.ts_require 'adapters/swift/mysql'
|
|
22
23
|
db.extend(Sequel::Swift::MySQL::DatabaseMethods)
|
|
24
|
+
db.dataset_class = Sequel::Swift::MySQL::Dataset
|
|
23
25
|
db.swift_class = ::Swift::DB::Mysql
|
|
24
26
|
end,
|
|
25
27
|
:sqlite=>proc do |db|
|
|
26
28
|
Sequel.ts_require 'adapters/swift/sqlite'
|
|
27
29
|
db.extend(Sequel::Swift::SQLite::DatabaseMethods)
|
|
30
|
+
db.dataset_class = Sequel::Swift::SQLite::Dataset
|
|
28
31
|
db.swift_class = ::Swift::DB::Sqlite3
|
|
29
32
|
end,
|
|
30
33
|
}
|
|
@@ -59,11 +62,6 @@ module Sequel
|
|
|
59
62
|
setup_connection(swift_class.new(server_opts(server)))
|
|
60
63
|
end
|
|
61
64
|
|
|
62
|
-
# Return a Sequel::Swift::Dataset object for this database.
|
|
63
|
-
def dataset(opts = nil)
|
|
64
|
-
Swift::Dataset.new(self, opts)
|
|
65
|
-
end
|
|
66
|
-
|
|
67
65
|
# Execute the given SQL, yielding a Swift::Result if a block is given.
|
|
68
66
|
def execute(sql, opts={})
|
|
69
67
|
synchronize(opts[:server]) do |conn|
|
|
@@ -134,6 +132,8 @@ module Sequel
|
|
|
134
132
|
end
|
|
135
133
|
|
|
136
134
|
class Dataset < Sequel::Dataset
|
|
135
|
+
Database::DatasetClass = self
|
|
136
|
+
|
|
137
137
|
# Set the columns and yield the hashes to the block.
|
|
138
138
|
def fetch_rows(sql, &block)
|
|
139
139
|
execute(sql) do |res|
|