sequel 3.21.0 → 3.32.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 +539 -3
- data/MIT-LICENSE +1 -1
- data/README.rdoc +20 -6
- data/Rakefile +37 -19
- data/bin/sequel +1 -5
- data/doc/advanced_associations.rdoc +17 -0
- data/doc/association_basics.rdoc +293 -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/release_notes/3.32.0.txt +202 -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 +52 -0
- data/lib/sequel/adapters/jdbc/derby.rb +260 -0
- data/lib/sequel/adapters/jdbc/firebird.rb +29 -0
- data/lib/sequel/adapters/jdbc/h2.rb +66 -30
- data/lib/sequel/adapters/jdbc/hsqldb.rb +177 -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 +88 -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 +339 -0
- data/lib/sequel/adapters/mysql.rb +85 -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 +355 -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 +328 -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 +278 -107
- data/lib/sequel/adapters/shared/mysql.rb +203 -65
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +149 -0
- data/lib/sequel/adapters/shared/oracle.rb +237 -46
- data/lib/sequel/adapters/shared/postgres.rb +214 -82
- data/lib/sequel/adapters/shared/progress.rb +5 -8
- data/lib/sequel/adapters/shared/sqlite.rb +200 -50
- 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 +68 -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 +163 -59
- data/lib/sequel/database/schema_generator.rb +17 -7
- data/lib/sequel/database/schema_methods.rb +59 -29
- data/lib/sequel/dataset/actions.rb +240 -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 +12 -7
- data/lib/sequel/dataset/prepared_statements.rb +59 -27
- data/lib/sequel/dataset/query.rb +236 -43
- data/lib/sequel/dataset/sql.rb +676 -267
- 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/query.rb +1 -1
- 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 +1081 -344
- data/lib/sequel/model/base.rb +420 -133
- data/lib/sequel/model/errors.rb +1 -1
- data/lib/sequel/model/exceptions.rb +5 -1
- data/lib/sequel/model.rb +20 -10
- data/lib/sequel/plugins/active_model.rb +13 -1
- data/lib/sequel/plugins/association_pks.rb +22 -4
- data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
- data/lib/sequel/plugins/composition.rb +43 -10
- 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 +68 -7
- data/lib/sequel/plugins/nested_attributes.rb +65 -10
- 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 +98 -49
- data/lib/sequel/plugins/serialization_modification_detection.rb +63 -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 +135 -30
- data/spec/adapters/mysql_spec.rb +244 -212
- data/spec/adapters/oracle_spec.rb +67 -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 +789 -512
- data/spec/core/dataset_spec.rb +1176 -1061
- 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/active_model_spec.rb +13 -0
- 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/query_spec.rb +6 -0
- 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 +72 -0
- data/spec/extensions/serialization_spec.rb +81 -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 +661 -21
- data/spec/integration/database_test.rb +4 -2
- data/spec/integration/dataset_test.rb +500 -67
- data/spec/integration/eager_loader_test.rb +19 -21
- data/spec/integration/model_test.rb +80 -1
- data/spec/integration/plugin_test.rb +367 -119
- data/spec/integration/prepared_statement_test.rb +222 -125
- data/spec/integration/schema_test.rb +217 -39
- data/spec/integration/spec_helper.rb +39 -30
- data/spec/integration/timezone_test.rb +38 -12
- data/spec/integration/transaction_test.rb +182 -5
- data/spec/integration/type_test.rb +17 -3
- data/spec/model/association_reflection_spec.rb +201 -7
- data/spec/model/associations_spec.rb +955 -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 +349 -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 +117 -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,35 @@ 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
|
+
fks = foreign_keys
|
|
174
|
+
self.foreign_keys = false if fks
|
|
175
|
+
transaction do
|
|
176
|
+
if ops.length > 1 && ops.all?{|op| op[:op] == :add_constraint}
|
|
177
|
+
# If you are just doing constraints, apply all of them at the same time,
|
|
178
|
+
# as otherwise all but the last one get lost.
|
|
179
|
+
alter_table_sql_list(table, [{:op=>:add_constraints, :ops=>ops}]).flatten.each{|sql| execute_ddl(sql)}
|
|
180
|
+
else
|
|
181
|
+
# Run each operation separately, as later operations may depend on the
|
|
182
|
+
# results of earlier operations.
|
|
183
|
+
ops.each{|op| alter_table_sql_list(table, [op]).flatten.each{|sql| execute_ddl(sql)}}
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
self.foreign_keys = true if fks
|
|
187
|
+
end
|
|
188
|
+
|
|
139
189
|
# SQLite supports limited table modification. You can add a column
|
|
140
190
|
# or an index. Dropping columns is supported by copying the table into
|
|
141
191
|
# a temporary table, dropping the table, and creating a new table without
|
|
@@ -161,12 +211,27 @@ module Sequel
|
|
|
161
211
|
when :set_column_null
|
|
162
212
|
duplicate_table(table){|columns| columns.each{|s| s[:null] = op[:null] if s[:name].to_s == op[:name].to_s}}
|
|
163
213
|
when :set_column_type
|
|
164
|
-
duplicate_table(table){|columns| columns.each{|s| s
|
|
214
|
+
duplicate_table(table){|columns| columns.each{|s| s.merge!(op) if s[:name].to_s == op[:name].to_s}}
|
|
215
|
+
when :drop_constraint
|
|
216
|
+
case op[:type]
|
|
217
|
+
when :primary_key
|
|
218
|
+
duplicate_table(table){|columns| columns.each{|s| s[:primary_key] = nil}}
|
|
219
|
+
when :foreign_key
|
|
220
|
+
duplicate_table(table){|columns| columns.each{|s| s[:table] = nil}}
|
|
221
|
+
when :unique
|
|
222
|
+
duplicate_table(table)
|
|
223
|
+
else
|
|
224
|
+
raise Error, "Unsupported :type option for drop_constraint: #{op[:type].inspect}"
|
|
225
|
+
end
|
|
226
|
+
when :add_constraint
|
|
227
|
+
duplicate_table(table, :constraints=>[op])
|
|
228
|
+
when :add_constraints
|
|
229
|
+
duplicate_table(table, :constraints=>op[:ops])
|
|
165
230
|
else
|
|
166
|
-
raise Error, "Unsupported ALTER TABLE operation"
|
|
231
|
+
raise Error, "Unsupported ALTER TABLE operation: #{op[:op].inspect}"
|
|
167
232
|
end
|
|
168
233
|
end
|
|
169
|
-
|
|
234
|
+
|
|
170
235
|
# The array of column symbols in the table, except for ones given in opts[:except]
|
|
171
236
|
def backup_table_name(table, opts={})
|
|
172
237
|
table = table.gsub('`', '')
|
|
@@ -176,17 +241,19 @@ module Sequel
|
|
|
176
241
|
end
|
|
177
242
|
end
|
|
178
243
|
|
|
179
|
-
#
|
|
180
|
-
def
|
|
181
|
-
|
|
244
|
+
# Surround default with parens to appease SQLite
|
|
245
|
+
def column_definition_default_sql(sql, column)
|
|
246
|
+
sql << " DEFAULT (#{literal(column[:default])})" if column.include?(:default)
|
|
182
247
|
end
|
|
183
|
-
|
|
248
|
+
|
|
184
249
|
# Array of PRAGMA SQL statements based on the Database options that should be applied to
|
|
185
250
|
# new connections.
|
|
186
251
|
def connection_pragmas
|
|
187
252
|
ps = []
|
|
188
253
|
v = typecast_value_boolean(opts.fetch(:foreign_keys, 1))
|
|
189
254
|
ps << "PRAGMA foreign_keys = #{v ? 1 : 0}"
|
|
255
|
+
v = typecast_value_boolean(opts.fetch(:case_sensitive_like, 1))
|
|
256
|
+
ps << "PRAGMA case_sensitive_like = #{v ? 1 : 0}"
|
|
190
257
|
[[:auto_vacuum, AUTO_VACUUM], [:synchronous, SYNCHRONOUS], [:temp_store, TEMP_STORE]].each do |prag, con|
|
|
191
258
|
if v = opts[prag]
|
|
192
259
|
raise(Error, "Value for PRAGMA #{prag} not supported, should be one of #{con.join(', ')}") unless v = con.index(v.to_sym)
|
|
@@ -208,7 +275,7 @@ module Sequel
|
|
|
208
275
|
cols.reject!{|c| nono.include? c[:name] }
|
|
209
276
|
end
|
|
210
277
|
|
|
211
|
-
|
|
278
|
+
begin
|
|
212
279
|
metadata_dataset.with_sql("PRAGMA foreign_key_list(?)", input_identifier_meth.call(table)).each do |row|
|
|
213
280
|
c = cols.find {|co| co[:name] == row[:from] } or next
|
|
214
281
|
c[:table] = row[:table]
|
|
@@ -217,6 +284,9 @@ module Sequel
|
|
|
217
284
|
c[:on_delete] = on_delete_sql_to_sym(row[:on_delete])
|
|
218
285
|
# is there any way to get deferrable status?
|
|
219
286
|
end
|
|
287
|
+
rescue Sequel::DatabaseError
|
|
288
|
+
# Doesn't work correctly on some versions of JDBC SQLite,
|
|
289
|
+
# giving a "query does not return ResultSet" error.
|
|
220
290
|
end
|
|
221
291
|
cols
|
|
222
292
|
end
|
|
@@ -231,17 +301,26 @@ module Sequel
|
|
|
231
301
|
opts[:old_columns_proc].call(old_columns) if opts[:old_columns_proc]
|
|
232
302
|
|
|
233
303
|
yield def_columns if block_given?
|
|
234
|
-
|
|
304
|
+
|
|
305
|
+
constraints = (opts[:constraints] || []).dup
|
|
306
|
+
pks = []
|
|
307
|
+
def_columns.each{|c| pks << c[:name] if c[:primary_key]}
|
|
308
|
+
if pks.length > 1
|
|
309
|
+
constraints << {:type=>:primary_key, :columns=>pks}
|
|
310
|
+
def_columns.each{|c| c[:primary_key] = false if c[:primary_key]}
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
def_columns_str = (def_columns.map{|c| column_definition_sql(c)} + constraints.map{|c| constraint_definition_sql(c)}).join(', ')
|
|
235
314
|
new_columns = old_columns.dup
|
|
236
315
|
opts[:new_columns_proc].call(new_columns) if opts[:new_columns_proc]
|
|
237
316
|
|
|
238
317
|
qt = quote_schema_table(table)
|
|
239
318
|
bt = quote_identifier(backup_table_name(qt))
|
|
240
319
|
a = [
|
|
241
|
-
"
|
|
242
|
-
"
|
|
243
|
-
"
|
|
244
|
-
"
|
|
320
|
+
"ALTER TABLE #{qt} RENAME TO #{bt}",
|
|
321
|
+
"CREATE TABLE #{qt}(#{def_columns_str})",
|
|
322
|
+
"INSERT INTO #{qt}(#{dataset.send(:identifier_list, new_columns)}) SELECT #{dataset.send(:identifier_list, old_columns)} FROM #{bt}",
|
|
323
|
+
"DROP TABLE #{bt}"
|
|
245
324
|
]
|
|
246
325
|
indexes(table).each do |name, h|
|
|
247
326
|
if (h[:columns].map{|x| x.to_s} - new_columns).empty?
|
|
@@ -280,7 +359,7 @@ module Sequel
|
|
|
280
359
|
|
|
281
360
|
# Parse the output of the table_info pragma
|
|
282
361
|
def parse_pragma(table_name, opts)
|
|
283
|
-
metadata_dataset.with_sql("PRAGMA table_info(?)", input_identifier_meth.call(table_name)).map do |row|
|
|
362
|
+
metadata_dataset.with_sql("PRAGMA table_info(?)", input_identifier_meth(opts[:dataset]).call(table_name)).map do |row|
|
|
284
363
|
row.delete(:cid)
|
|
285
364
|
row[:allow_null] = row.delete(:notnull).to_i == 0
|
|
286
365
|
row[:default] = row.delete(:dflt_value)
|
|
@@ -300,12 +379,18 @@ module Sequel
|
|
|
300
379
|
# SQLite supports schema parsing using the table_info PRAGMA, so
|
|
301
380
|
# parse the output of that into the format Sequel expects.
|
|
302
381
|
def schema_parse_table(table_name, opts)
|
|
303
|
-
m = output_identifier_meth
|
|
382
|
+
m = output_identifier_meth(opts[:dataset])
|
|
304
383
|
parse_pragma(table_name, opts).map do |row|
|
|
305
384
|
[m.call(row.delete(:name)), row]
|
|
306
385
|
end
|
|
307
386
|
end
|
|
308
387
|
|
|
388
|
+
# Backbone of the tables and views support.
|
|
389
|
+
def tables_and_views(filter, opts)
|
|
390
|
+
m = output_identifier_meth
|
|
391
|
+
metadata_dataset.from(:sqlite_master).server(opts[:server]).filter(filter).map{|r| m.call(r[:name])}
|
|
392
|
+
end
|
|
393
|
+
|
|
309
394
|
# SQLite uses the integer data type even for bignums. This is because they
|
|
310
395
|
# are both stored internally as text, and converted when returned from
|
|
311
396
|
# the database. Using an integer type instead of bigint makes it more likely
|
|
@@ -317,28 +402,59 @@ module Sequel
|
|
|
317
402
|
|
|
318
403
|
# Instance methods for datasets that connect to an SQLite database
|
|
319
404
|
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
|
|
405
|
+
SELECT_CLAUSE_METHODS = Dataset.clause_methods(:select, %w'select distinct columns from join where group having compounds order limit')
|
|
322
406
|
CONSTANT_MAP = {:CURRENT_DATE=>"date(CURRENT_TIMESTAMP, 'localtime')".freeze, :CURRENT_TIMESTAMP=>"datetime(CURRENT_TIMESTAMP, 'localtime')".freeze, :CURRENT_TIME=>"time(CURRENT_TIMESTAMP, 'localtime')".freeze}
|
|
323
|
-
|
|
407
|
+
EXTRACT_MAP = {:year=>"'%Y'", :month=>"'%m'", :day=>"'%d'", :hour=>"'%H'", :minute=>"'%M'", :second=>"'%f'"}
|
|
408
|
+
NOT_SPACE = Dataset::NOT_SPACE
|
|
409
|
+
COMMA = Dataset::COMMA
|
|
410
|
+
PAREN_CLOSE = Dataset::PAREN_CLOSE
|
|
411
|
+
AS = Dataset::AS
|
|
412
|
+
APOS = Dataset::APOS
|
|
413
|
+
EXTRACT_OPEN = "CAST(strftime(".freeze
|
|
414
|
+
EXTRACT_CLOSE = ') AS '.freeze
|
|
415
|
+
NUMERIC = 'NUMERIC'.freeze
|
|
416
|
+
INTEGER = 'INTEGER'.freeze
|
|
417
|
+
BACKTICK = '`'.freeze
|
|
418
|
+
BLOB_START = "X'".freeze
|
|
419
|
+
HSTAR = "H*".freeze
|
|
420
|
+
|
|
324
421
|
# SQLite does not support pattern matching via regular expressions.
|
|
325
422
|
# SQLite is case insensitive (depending on pragma), so use LIKE for
|
|
326
423
|
# ILIKE.
|
|
327
|
-
def
|
|
424
|
+
def complex_expression_sql_append(sql, op, args)
|
|
328
425
|
case op
|
|
329
426
|
when :~, :'!~', :'~*', :'!~*'
|
|
330
427
|
raise Error, "SQLite does not support pattern matching via regular expressions"
|
|
331
|
-
when :
|
|
332
|
-
|
|
333
|
-
|
|
428
|
+
when :ILIKE
|
|
429
|
+
super(sql, :LIKE, args.map{|a| SQL::Function.new(:upper, a)})
|
|
430
|
+
when :"NOT LIKE", :"NOT ILIKE"
|
|
431
|
+
sql << NOT_SPACE
|
|
432
|
+
complex_expression_sql_append(sql, (op == :"NOT ILIKE" ? :ILIKE : :LIKE), args)
|
|
433
|
+
when :^
|
|
434
|
+
sql << complex_expression_arg_pairs(args) do |a, b|
|
|
435
|
+
a = literal(a)
|
|
436
|
+
b = literal(b)
|
|
437
|
+
"((~(#{a} & #{b})) & (#{a} | #{b}))"
|
|
438
|
+
end
|
|
439
|
+
when :extract
|
|
440
|
+
part = args.at(0)
|
|
441
|
+
raise(Sequel::Error, "unsupported extract argument: #{part.inspect}") unless format = EXTRACT_MAP[part]
|
|
442
|
+
sql << EXTRACT_OPEN << format << COMMA
|
|
443
|
+
literal_append(sql, args.at(1))
|
|
444
|
+
sql << EXTRACT_CLOSE << (part == :second ? NUMERIC : INTEGER) << PAREN_CLOSE
|
|
334
445
|
else
|
|
335
|
-
super
|
|
446
|
+
super
|
|
336
447
|
end
|
|
337
448
|
end
|
|
338
449
|
|
|
339
|
-
#
|
|
340
|
-
|
|
341
|
-
|
|
450
|
+
# SQLite has CURRENT_TIMESTAMP and related constants in UTC instead
|
|
451
|
+
# of in localtime, so convert those constants to local time.
|
|
452
|
+
def constant_sql_append(sql, constant)
|
|
453
|
+
if c = CONSTANT_MAP[constant]
|
|
454
|
+
sql << c
|
|
455
|
+
else
|
|
456
|
+
super
|
|
457
|
+
end
|
|
342
458
|
end
|
|
343
459
|
|
|
344
460
|
# SQLite performs a TRUNCATE style DELETE if no filter is specified.
|
|
@@ -362,8 +478,20 @@ module Sequel
|
|
|
362
478
|
end
|
|
363
479
|
|
|
364
480
|
# SQLite uses the nonstandard ` (backtick) for quoting identifiers.
|
|
365
|
-
def
|
|
366
|
-
|
|
481
|
+
def quoted_identifier_append(sql, c)
|
|
482
|
+
sql << BACKTICK << c.to_s << BACKTICK
|
|
483
|
+
end
|
|
484
|
+
|
|
485
|
+
# When a qualified column is selected on SQLite and the qualifier
|
|
486
|
+
# is a subselect, the column name used is the full qualified name
|
|
487
|
+
# (including the qualifier) instead of just the column name. To
|
|
488
|
+
# get correct column names, you must use an alias.
|
|
489
|
+
def select(*cols)
|
|
490
|
+
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)})
|
|
491
|
+
super(*cols.map{|c| alias_qualified_column(c)})
|
|
492
|
+
else
|
|
493
|
+
super
|
|
494
|
+
end
|
|
367
495
|
end
|
|
368
496
|
|
|
369
497
|
# SQLite does not support INTERSECT ALL or EXCEPT ALL
|
|
@@ -382,31 +510,53 @@ module Sequel
|
|
|
382
510
|
end
|
|
383
511
|
|
|
384
512
|
# SQLite supports timezones in literal timestamps, since it stores them
|
|
385
|
-
# as text.
|
|
513
|
+
# as text. But using timezones in timestamps breaks SQLite datetime
|
|
514
|
+
# functions, so we allow the user to override the default per database.
|
|
386
515
|
def supports_timestamp_timezones?
|
|
387
|
-
|
|
516
|
+
db.use_timestamp_timezones?
|
|
388
517
|
end
|
|
389
518
|
|
|
519
|
+
# SQLite cannot use WHERE 't'.
|
|
520
|
+
def supports_where_true?
|
|
521
|
+
false
|
|
522
|
+
end
|
|
523
|
+
|
|
390
524
|
private
|
|
391
525
|
|
|
392
526
|
# SQLite uses string literals instead of identifiers in AS clauses.
|
|
393
|
-
def
|
|
527
|
+
def as_sql_append(sql, aliaz)
|
|
394
528
|
aliaz = aliaz.value if aliaz.is_a?(SQL::Identifier)
|
|
395
|
-
|
|
529
|
+
sql << AS
|
|
530
|
+
literal_append(sql, aliaz.to_s)
|
|
531
|
+
end
|
|
532
|
+
|
|
533
|
+
# If col is a qualified column, alias it to the same as the column name
|
|
534
|
+
def alias_qualified_column(col)
|
|
535
|
+
case col
|
|
536
|
+
when Symbol
|
|
537
|
+
t, c, a = split_symbol(col)
|
|
538
|
+
if t && !a
|
|
539
|
+
alias_qualified_column(SQL::QualifiedIdentifier.new(t, c))
|
|
540
|
+
else
|
|
541
|
+
col
|
|
542
|
+
end
|
|
543
|
+
when SQL::QualifiedIdentifier
|
|
544
|
+
SQL::AliasedExpression.new(col, col.column)
|
|
545
|
+
else
|
|
546
|
+
col
|
|
547
|
+
end
|
|
396
548
|
end
|
|
397
549
|
|
|
398
550
|
# SQL fragment specifying a list of identifiers
|
|
399
551
|
def identifier_list(columns)
|
|
400
|
-
columns.map{|i| quote_identifier(i)}.join(
|
|
552
|
+
columns.map{|i| quote_identifier(i)}.join(COMMA)
|
|
401
553
|
end
|
|
402
554
|
|
|
403
555
|
# SQLite uses a preceding X for hex escaping strings
|
|
404
|
-
def
|
|
405
|
-
|
|
406
|
-
v.each_byte{|x| blob << sprintf('%02x', x)}
|
|
407
|
-
"X'#{blob}'"
|
|
556
|
+
def literal_blob_append(sql, v)
|
|
557
|
+
sql << BLOB_START << v.unpack(HSTAR).first << APOS
|
|
408
558
|
end
|
|
409
|
-
|
|
559
|
+
|
|
410
560
|
# SQLite does not support the SQL WITH clause
|
|
411
561
|
def select_clause_methods
|
|
412
562
|
SELECT_CLAUSE_METHODS
|
|
@@ -416,7 +566,7 @@ module Sequel
|
|
|
416
566
|
def select_lock_sql(sql)
|
|
417
567
|
super unless @opts[:lock] == :update
|
|
418
568
|
end
|
|
419
|
-
|
|
569
|
+
|
|
420
570
|
# SQLite treats a DELETE with no WHERE clause as a TRUNCATE
|
|
421
571
|
def _truncate_sql(table)
|
|
422
572
|
"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|
|