sequel 3.21.0 → 3.36.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 +855 -3
- data/MIT-LICENSE +1 -1
- data/README.rdoc +23 -7
- data/Rakefile +42 -24
- data/bin/sequel +26 -8
- data/doc/active_record.rdoc +1 -0
- data/doc/advanced_associations.rdoc +171 -11
- data/doc/association_basics.rdoc +293 -43
- data/doc/dataset_basics.rdoc +5 -5
- data/doc/dataset_filtering.rdoc +8 -0
- data/doc/mass_assignment.rdoc +56 -0
- data/doc/migration.rdoc +85 -552
- data/doc/model_hooks.rdoc +78 -27
- data/doc/object_model.rdoc +541 -0
- data/doc/opening_databases.rdoc +97 -50
- data/doc/prepared_statements.rdoc +40 -14
- data/doc/querying.rdoc +28 -4
- data/doc/reflection.rdoc +30 -4
- 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/release_notes/3.33.0.txt +157 -0
- data/doc/release_notes/3.34.0.txt +671 -0
- data/doc/release_notes/3.35.0.txt +144 -0
- data/doc/release_notes/3.36.0.txt +245 -0
- data/doc/schema_modification.rdoc +572 -0
- data/doc/sharding.rdoc +95 -3
- data/doc/testing.rdoc +129 -0
- data/doc/thread_safety.rdoc +17 -0
- data/doc/transactions.rdoc +137 -0
- data/doc/virtual_rows.rdoc +51 -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 +17 -11
- data/lib/sequel/adapters/do/postgres.rb +1 -57
- data/lib/sequel/adapters/do/sqlite.rb +0 -10
- data/lib/sequel/adapters/do.rb +18 -36
- data/lib/sequel/adapters/firebird.rb +27 -208
- data/lib/sequel/adapters/ibmdb.rb +453 -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 +47 -0
- data/lib/sequel/adapters/jdbc/derby.rb +287 -0
- data/lib/sequel/adapters/jdbc/firebird.rb +24 -0
- data/lib/sequel/adapters/jdbc/h2.rb +73 -31
- data/lib/sequel/adapters/jdbc/hsqldb.rb +184 -0
- data/lib/sequel/adapters/jdbc/informix.rb +21 -0
- data/lib/sequel/adapters/jdbc/jtds.rb +29 -0
- data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
- data/lib/sequel/adapters/jdbc/mysql.rb +7 -24
- data/lib/sequel/adapters/jdbc/oracle.rb +88 -25
- data/lib/sequel/adapters/jdbc/postgresql.rb +58 -48
- data/lib/sequel/adapters/jdbc/progress.rb +21 -0
- data/lib/sequel/adapters/jdbc/sqlite.rb +20 -10
- data/lib/sequel/adapters/jdbc/sqlserver.rb +66 -0
- data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
- data/lib/sequel/adapters/jdbc.rb +265 -94
- data/lib/sequel/adapters/mock.rb +361 -0
- data/lib/sequel/adapters/mysql.rb +118 -222
- data/lib/sequel/adapters/mysql2.rb +58 -57
- data/lib/sequel/adapters/odbc/mssql.rb +15 -7
- data/lib/sequel/adapters/odbc.rb +28 -9
- data/lib/sequel/adapters/openbase.rb +3 -5
- data/lib/sequel/adapters/oracle.rb +349 -53
- data/lib/sequel/adapters/postgres.rb +356 -107
- data/lib/sequel/adapters/shared/access.rb +32 -9
- data/lib/sequel/adapters/shared/db2.rb +342 -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 +335 -118
- data/lib/sequel/adapters/shared/mysql.rb +340 -76
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +155 -0
- data/lib/sequel/adapters/shared/oracle.rb +243 -45
- data/lib/sequel/adapters/shared/postgres.rb +524 -279
- data/lib/sequel/adapters/shared/progress.rb +5 -8
- data/lib/sequel/adapters/shared/sqlite.rb +265 -89
- data/lib/sequel/adapters/sqlite.rb +101 -39
- data/lib/sequel/adapters/swift/mysql.rb +9 -12
- data/lib/sequel/adapters/swift/postgres.rb +9 -74
- data/lib/sequel/adapters/swift/sqlite.rb +8 -6
- data/lib/sequel/adapters/swift.rb +8 -7
- data/lib/sequel/adapters/tinytds.rb +161 -21
- 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 +194 -0
- data/lib/sequel/connection_pool/sharded_single.rb +11 -1
- data/lib/sequel/connection_pool/sharded_threaded.rb +28 -2
- data/lib/sequel/connection_pool/single.rb +5 -0
- data/lib/sequel/connection_pool/threaded.rb +38 -14
- data/lib/sequel/connection_pool.rb +10 -2
- data/lib/sequel/core.rb +118 -11
- data/lib/sequel/database/connecting.rb +38 -28
- data/lib/sequel/database/dataset.rb +4 -4
- data/lib/sequel/database/dataset_defaults.rb +63 -2
- data/lib/sequel/database/logging.rb +7 -2
- data/lib/sequel/database/misc.rb +150 -46
- data/lib/sequel/database/query.rb +215 -65
- data/lib/sequel/database/schema_generator.rb +64 -20
- data/lib/sequel/database/schema_methods.rb +212 -54
- data/lib/sequel/dataset/actions.rb +322 -85
- data/lib/sequel/dataset/features.rb +96 -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 +68 -30
- data/lib/sequel/dataset/query.rb +237 -44
- data/lib/sequel/dataset/sql.rb +698 -278
- data/lib/sequel/dataset.rb +8 -0
- data/lib/sequel/exceptions.rb +4 -0
- data/lib/sequel/extensions/_pretty_table.rb +79 -0
- data/lib/sequel/extensions/arbitrary_servers.rb +108 -0
- data/lib/sequel/extensions/columns_introspection.rb +61 -0
- data/lib/sequel/{core_sql.rb → extensions/core_extensions.rb} +16 -34
- data/lib/sequel/extensions/migration.rb +97 -11
- data/lib/sequel/extensions/named_timezones.rb +5 -0
- data/lib/sequel/extensions/null_dataset.rb +90 -0
- data/lib/sequel/extensions/pg_array.rb +460 -0
- data/lib/sequel/extensions/pg_array_ops.rb +220 -0
- data/lib/sequel/extensions/pg_auto_parameterize.rb +169 -0
- data/lib/sequel/extensions/pg_hstore.rb +296 -0
- data/lib/sequel/extensions/pg_hstore_ops.rb +259 -0
- data/lib/sequel/extensions/pg_inet.rb +89 -0
- data/lib/sequel/extensions/pg_json.rb +178 -0
- data/lib/sequel/extensions/pg_statement_cache.rb +316 -0
- data/lib/sequel/extensions/pretty_table.rb +5 -71
- data/lib/sequel/extensions/query.rb +1 -1
- data/lib/sequel/extensions/query_literals.rb +79 -0
- data/lib/sequel/extensions/schema_caching.rb +76 -0
- data/lib/sequel/extensions/schema_dumper.rb +251 -37
- data/lib/sequel/extensions/select_remove.rb +35 -0
- data/lib/sequel/extensions/server_block.rb +139 -0
- data/lib/sequel/extensions/sql_expr.rb +4 -110
- 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 +1187 -393
- data/lib/sequel/model/base.rb +578 -170
- data/lib/sequel/model/errors.rb +1 -1
- data/lib/sequel/model/exceptions.rb +5 -1
- data/lib/sequel/model/inflections.rb +1 -1
- data/lib/sequel/model.rb +30 -11
- data/lib/sequel/no_core_ext.rb +2 -0
- data/lib/sequel/plugins/active_model.rb +13 -1
- data/lib/sequel/plugins/association_pks.rb +22 -4
- data/lib/sequel/plugins/caching.rb +25 -18
- data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
- data/lib/sequel/plugins/composition.rb +44 -12
- data/lib/sequel/plugins/dataset_associations.rb +100 -0
- data/lib/sequel/plugins/defaults_setter.rb +58 -0
- data/lib/sequel/plugins/dirty.rb +214 -0
- data/lib/sequel/plugins/eager_each.rb +59 -0
- data/lib/sequel/plugins/force_encoding.rb +6 -6
- data/lib/sequel/plugins/hook_class_methods.rb +1 -1
- data/lib/sequel/plugins/identity_map.rb +123 -8
- data/lib/sequel/plugins/instance_filters.rb +10 -0
- data/lib/sequel/plugins/instance_hooks.rb +1 -1
- data/lib/sequel/plugins/json_serializer.rb +58 -6
- data/lib/sequel/plugins/list.rb +12 -2
- data/lib/sequel/plugins/many_through_many.rb +79 -28
- data/lib/sequel/plugins/many_to_one_pk_lookup.rb +71 -0
- data/lib/sequel/plugins/nested_attributes.rb +139 -63
- data/lib/sequel/plugins/optimistic_locking.rb +8 -0
- data/lib/sequel/plugins/prepared_statements.rb +167 -0
- data/lib/sequel/plugins/prepared_statements_associations.rb +87 -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/schema.rb +7 -2
- 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 +5 -3
- data/lib/sequel/plugins/static_cache.rb +99 -0
- data/lib/sequel/plugins/subclasses.rb +10 -2
- data/lib/sequel/plugins/tactical_eager_loading.rb +7 -7
- data/lib/sequel/plugins/timestamps.rb +1 -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/validation_class_methods.rb +1 -1
- data/lib/sequel/plugins/xml_serializer.rb +15 -4
- data/lib/sequel/sql.rb +526 -59
- 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/firebird_spec.rb +1 -1
- data/spec/adapters/mssql_spec.rb +142 -40
- data/spec/adapters/mysql_spec.rb +380 -234
- data/spec/adapters/oracle_spec.rb +67 -77
- data/spec/adapters/postgres_spec.rb +1050 -212
- data/spec/adapters/spec_helper.rb +8 -5
- data/spec/adapters/sqlite_spec.rb +139 -27
- data/spec/core/connection_pool_spec.rb +196 -93
- data/spec/core/database_spec.rb +879 -510
- data/spec/core/dataset_spec.rb +1415 -1086
- data/spec/core/expression_filters_spec.rb +554 -109
- data/spec/core/mock_adapter_spec.rb +449 -0
- data/spec/core/object_graph_spec.rb +86 -114
- data/spec/core/schema_generator_spec.rb +4 -4
- data/spec/core/schema_spec.rb +482 -38
- data/spec/core/spec_helper.rb +6 -48
- data/spec/extensions/active_model_spec.rb +13 -0
- data/spec/extensions/arbitrary_servers_spec.rb +110 -0
- data/spec/extensions/association_autoreloading_spec.rb +18 -10
- data/spec/extensions/association_dependencies_spec.rb +15 -25
- data/spec/extensions/association_pks_spec.rb +66 -32
- data/spec/extensions/association_proxies_spec.rb +4 -4
- data/spec/extensions/caching_spec.rb +47 -51
- 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/{core/core_sql_spec.rb → extensions/core_extensions_spec.rb} +119 -139
- data/spec/extensions/dataset_associations_spec.rb +199 -0
- data/spec/extensions/defaults_setter_spec.rb +64 -0
- data/spec/extensions/dirty_spec.rb +155 -0
- data/spec/extensions/eager_each_spec.rb +34 -0
- data/spec/extensions/force_encoding_spec.rb +4 -2
- data/spec/extensions/hook_class_methods_spec.rb +69 -92
- data/spec/extensions/identity_map_spec.rb +131 -22
- data/spec/extensions/inflector_spec.rb +0 -4
- data/spec/extensions/instance_filters_spec.rb +11 -21
- data/spec/extensions/instance_hooks_spec.rb +72 -0
- data/spec/extensions/json_serializer_spec.rb +49 -6
- data/spec/extensions/lazy_attributes_spec.rb +16 -20
- data/spec/extensions/list_spec.rb +48 -39
- data/spec/extensions/many_through_many_spec.rb +283 -250
- data/spec/extensions/many_to_one_pk_lookup_spec.rb +140 -0
- data/spec/extensions/migration_spec.rb +140 -35
- data/spec/extensions/named_timezones_spec.rb +29 -11
- data/spec/extensions/nested_attributes_spec.rb +251 -89
- data/spec/extensions/null_dataset_spec.rb +85 -0
- data/spec/extensions/optimistic_locking_spec.rb +24 -21
- data/spec/extensions/pg_array_ops_spec.rb +105 -0
- data/spec/extensions/pg_array_spec.rb +196 -0
- data/spec/extensions/pg_auto_parameterize_spec.rb +65 -0
- data/spec/extensions/pg_hstore_ops_spec.rb +136 -0
- data/spec/extensions/pg_hstore_spec.rb +195 -0
- data/spec/extensions/pg_inet_spec.rb +44 -0
- data/spec/extensions/pg_json_spec.rb +101 -0
- data/spec/extensions/pg_statement_cache_spec.rb +209 -0
- 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 +87 -0
- data/spec/extensions/prepared_statements_with_pk_spec.rb +31 -0
- data/spec/extensions/pretty_table_spec.rb +7 -6
- data/spec/extensions/query_literals_spec.rb +168 -0
- data/spec/extensions/query_spec.rb +6 -0
- data/spec/extensions/rcte_tree_spec.rb +50 -43
- data/spec/extensions/schema_caching_spec.rb +41 -0
- data/spec/extensions/schema_dumper_spec.rb +429 -22
- data/spec/extensions/schema_spec.rb +25 -21
- data/spec/extensions/select_remove_spec.rb +38 -0
- data/spec/extensions/serialization_modification_detection_spec.rb +72 -0
- data/spec/extensions/serialization_spec.rb +85 -43
- data/spec/extensions/server_block_spec.rb +90 -0
- data/spec/extensions/sharding_spec.rb +69 -143
- data/spec/extensions/single_table_inheritance_spec.rb +23 -29
- data/spec/extensions/skip_create_refresh_spec.rb +1 -1
- data/spec/extensions/spec_helper.rb +22 -61
- data/spec/extensions/sql_expr_spec.rb +29 -60
- data/spec/extensions/static_cache_spec.rb +145 -0
- data/spec/extensions/tactical_eager_loading_spec.rb +17 -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 +9 -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 +29 -4
- data/spec/files/transaction_specified_migrations/001_create_alt_basic.rb +4 -0
- data/spec/files/transaction_specified_migrations/002_create_basic.rb +4 -0
- data/spec/files/transaction_unspecified_migrations/001_create_alt_basic.rb +3 -0
- data/spec/files/transaction_unspecified_migrations/002_create_basic.rb +3 -0
- data/spec/integration/associations_test.rb +659 -21
- data/spec/integration/database_test.rb +9 -3
- data/spec/integration/dataset_test.rb +605 -91
- data/spec/integration/eager_loader_test.rb +19 -21
- data/spec/integration/migrator_test.rb +2 -3
- data/spec/integration/model_test.rb +81 -2
- data/spec/integration/plugin_test.rb +454 -143
- data/spec/integration/prepared_statement_test.rb +263 -128
- data/spec/integration/schema_test.rb +309 -43
- data/spec/integration/spec_helper.rb +40 -30
- data/spec/integration/timezone_test.rb +38 -12
- data/spec/integration/transaction_test.rb +183 -8
- data/spec/integration/type_test.rb +18 -4
- data/spec/model/association_reflection_spec.rb +201 -7
- data/spec/model/associations_spec.rb +1067 -661
- data/spec/model/base_spec.rb +329 -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 +240 -168
- data/spec/model/plugins_spec.rb +24 -13
- data/spec/model/record_spec.rb +490 -232
- data/spec/model/spec_helper.rb +14 -71
- data/spec/model/validations_spec.rb +11 -0
- data/spec/rcov.opts +2 -0
- metadata +178 -80
|
@@ -6,16 +6,10 @@ module Sequel
|
|
|
6
6
|
def database_type
|
|
7
7
|
:progress
|
|
8
8
|
end
|
|
9
|
-
|
|
10
|
-
def dataset(opts = nil)
|
|
11
|
-
ds = super
|
|
12
|
-
ds.extend(DatasetMethods)
|
|
13
|
-
ds
|
|
14
|
-
end
|
|
15
9
|
end
|
|
16
10
|
|
|
17
11
|
module DatasetMethods
|
|
18
|
-
SELECT_CLAUSE_METHODS = Dataset.clause_methods(:select, %w'limit distinct columns from join where group order having compounds')
|
|
12
|
+
SELECT_CLAUSE_METHODS = Dataset.clause_methods(:select, %w'select limit distinct columns from join where group order having compounds')
|
|
19
13
|
|
|
20
14
|
# Progress requires SQL standard datetimes
|
|
21
15
|
def requires_sql_standard_datetimes?
|
|
@@ -37,7 +31,10 @@ module Sequel
|
|
|
37
31
|
# The Progress adapter targets Progress 9, so it silently ignores the option.
|
|
38
32
|
def select_limit_sql(sql)
|
|
39
33
|
raise(Error, "OFFSET not supported") if @opts[:offset]
|
|
40
|
-
#
|
|
34
|
+
# if l = @opts[:limit]
|
|
35
|
+
# sql << " TOP "
|
|
36
|
+
# literal_append(sql, l)
|
|
37
|
+
# end
|
|
41
38
|
end
|
|
42
39
|
end
|
|
43
40
|
end
|
|
@@ -7,16 +7,13 @@ 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
|
-
|
|
14
|
-
#
|
|
15
|
-
|
|
16
|
-
|
|
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
|
|
13
|
+
|
|
14
|
+
# Whether to use integers for booleans in the database. SQLite recommends
|
|
15
|
+
# booleans be stored as integers, but historically Sequel has used 't'/'f'.
|
|
16
|
+
attr_accessor :integer_booleans
|
|
20
17
|
|
|
21
18
|
# A symbol signifying the value of the auto_vacuum PRAGMA.
|
|
22
19
|
def auto_vacuum
|
|
@@ -30,7 +27,14 @@ module Sequel
|
|
|
30
27
|
value = AUTO_VACUUM.index(value) || (raise Error, "Invalid value for auto_vacuum option. Please specify one of :none, :full, :incremental.")
|
|
31
28
|
pragma_set(:auto_vacuum, value)
|
|
32
29
|
end
|
|
33
|
-
|
|
30
|
+
|
|
31
|
+
# Set the case_sensitive_like PRAGMA using the given boolean value, if using
|
|
32
|
+
# SQLite 3.2.3+. If not using 3.2.3+, no error is raised. See pragma_set.
|
|
33
|
+
# Consider using the :case_sensitive_like Database option instead.
|
|
34
|
+
def case_sensitive_like=(value)
|
|
35
|
+
pragma_set(:case_sensitive_like, !!value ? 'on' : 'off') if sqlite_version >= 30203
|
|
36
|
+
end
|
|
37
|
+
|
|
34
38
|
# SQLite uses the :sqlite database type.
|
|
35
39
|
def database_type
|
|
36
40
|
:sqlite
|
|
@@ -49,22 +53,33 @@ module Sequel
|
|
|
49
53
|
pragma_set(:foreign_keys, !!value ? 'on' : 'off') if sqlite_version >= 30619
|
|
50
54
|
end
|
|
51
55
|
|
|
56
|
+
# Return the array of foreign key info hashes using the foreign_key_list PRAGMA,
|
|
57
|
+
# including information for the :on_update and :on_delete entries.
|
|
58
|
+
def foreign_key_list(table, opts={})
|
|
59
|
+
m = output_identifier_meth
|
|
60
|
+
h = {}
|
|
61
|
+
metadata_dataset.with_sql("PRAGMA foreign_key_list(?)", input_identifier_meth.call(table)).each do |row|
|
|
62
|
+
if r = h[row[:id]]
|
|
63
|
+
r[:columns] << m.call(row[:from])
|
|
64
|
+
r[:key] << m.call(row[:to]) if r[:key]
|
|
65
|
+
else
|
|
66
|
+
h[row[:id]] = {:columns=>[m.call(row[:from])], :table=>m.call(row[:table]), :key=>([m.call(row[:to])] if row[:to]), :on_update=>on_delete_sql_to_sym(row[:on_update]), :on_delete=>on_delete_sql_to_sym(row[:on_delete])}
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
h.values
|
|
70
|
+
end
|
|
71
|
+
|
|
52
72
|
# Use the index_list and index_info PRAGMAs to determine the indexes on the table.
|
|
53
73
|
def indexes(table, opts={})
|
|
54
74
|
m = output_identifier_meth
|
|
55
75
|
im = input_identifier_meth
|
|
56
76
|
indexes = {}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
nil
|
|
64
|
-
else
|
|
65
|
-
indexes.each do |k, v|
|
|
66
|
-
v[:columns] = metadata_dataset.with_sql("PRAGMA index_info(?)", im.call(k)).map(:name).map{|x| m.call(x)}
|
|
67
|
-
end
|
|
77
|
+
metadata_dataset.with_sql("PRAGMA index_list(?)", im.call(table)).each do |r|
|
|
78
|
+
next if r[:name] =~ PRIMARY_KEY_INDEX_RE
|
|
79
|
+
indexes[m.call(r[:name])] = {:unique=>r[:unique].to_i==1}
|
|
80
|
+
end
|
|
81
|
+
indexes.each do |k, v|
|
|
82
|
+
v[:columns] = metadata_dataset.with_sql("PRAGMA index_info(?)", im.call(k)).map(:name).map{|x| m.call(x)}
|
|
68
83
|
end
|
|
69
84
|
indexes
|
|
70
85
|
end
|
|
@@ -83,6 +98,11 @@ module Sequel
|
|
|
83
98
|
def pragma_set(name, value)
|
|
84
99
|
execute_ddl("PRAGMA #{name} = #{value}")
|
|
85
100
|
end
|
|
101
|
+
|
|
102
|
+
# Set the integer_booleans option using the passed in :integer_boolean option.
|
|
103
|
+
def set_integer_booleans
|
|
104
|
+
@integer_booleans = typecast_value_boolean(@opts[:integer_booleans])
|
|
105
|
+
end
|
|
86
106
|
|
|
87
107
|
# The version of the server as an integer, where 3.6.19 = 30619.
|
|
88
108
|
# If the server version can't be determined, 0 is used.
|
|
@@ -96,11 +116,29 @@ module Sequel
|
|
|
96
116
|
end
|
|
97
117
|
end
|
|
98
118
|
|
|
119
|
+
# SQLite supports CREATE TABLE IF NOT EXISTS syntax since 3.3.0.
|
|
120
|
+
def supports_create_table_if_not_exists?
|
|
121
|
+
sqlite_version >= 30300
|
|
122
|
+
end
|
|
123
|
+
|
|
99
124
|
# SQLite 3.6.8+ supports savepoints.
|
|
100
125
|
def supports_savepoints?
|
|
101
126
|
sqlite_version >= 30608
|
|
102
127
|
end
|
|
103
128
|
|
|
129
|
+
# Override the default setting for whether to use timezones in timestamps.
|
|
130
|
+
# For backwards compatibility, it is set to +true+ by default.
|
|
131
|
+
# Anyone wanting to use SQLite's datetime functions should set it to +false+
|
|
132
|
+
# using this method. It's possible that the default will change in a future version,
|
|
133
|
+
# so anyone relying on timezones in timestamps should set this to +true+.
|
|
134
|
+
attr_writer :use_timestamp_timezones
|
|
135
|
+
|
|
136
|
+
# SQLite supports timezones in timestamps, since it just stores them as strings,
|
|
137
|
+
# but it breaks the usage of SQLite's datetime functions.
|
|
138
|
+
def use_timestamp_timezones?
|
|
139
|
+
defined?(@use_timestamp_timezones) ? @use_timestamp_timezones : (@use_timestamp_timezones = true)
|
|
140
|
+
end
|
|
141
|
+
|
|
104
142
|
# A symbol signifying the value of the synchronous PRAGMA.
|
|
105
143
|
def synchronous
|
|
106
144
|
SYNCHRONOUS[pragma_get(:synchronous).to_i]
|
|
@@ -118,8 +156,7 @@ module Sequel
|
|
|
118
156
|
# Options:
|
|
119
157
|
# * :server - Set the server to use.
|
|
120
158
|
def tables(opts={})
|
|
121
|
-
|
|
122
|
-
metadata_dataset.from(:sqlite_master).server(opts[:server]).filter(TABLES_FILTER).map{|r| m.call(r[:name])}
|
|
159
|
+
tables_and_views(TABLES_FILTER, opts)
|
|
123
160
|
end
|
|
124
161
|
|
|
125
162
|
# A symbol signifying the value of the temp_store PRAGMA.
|
|
@@ -134,8 +171,35 @@ module Sequel
|
|
|
134
171
|
pragma_set(:temp_store, value)
|
|
135
172
|
end
|
|
136
173
|
|
|
174
|
+
# Array of symbols specifying the view names in the current database.
|
|
175
|
+
#
|
|
176
|
+
# Options:
|
|
177
|
+
# * :server - Set the server to use.
|
|
178
|
+
def views(opts={})
|
|
179
|
+
tables_and_views(VIEWS_FILTER, opts)
|
|
180
|
+
end
|
|
181
|
+
|
|
137
182
|
private
|
|
138
183
|
|
|
184
|
+
# Run all alter_table commands in a transaction. This is technically only
|
|
185
|
+
# needed for drop column.
|
|
186
|
+
def apply_alter_table(table, ops)
|
|
187
|
+
fks = foreign_keys
|
|
188
|
+
self.foreign_keys = false if fks
|
|
189
|
+
transaction do
|
|
190
|
+
if ops.length > 1 && ops.all?{|op| op[:op] == :add_constraint}
|
|
191
|
+
# If you are just doing constraints, apply all of them at the same time,
|
|
192
|
+
# as otherwise all but the last one get lost.
|
|
193
|
+
alter_table_sql_list(table, [{:op=>:add_constraints, :ops=>ops}]).flatten.each{|sql| execute_ddl(sql)}
|
|
194
|
+
else
|
|
195
|
+
# Run each operation separately, as later operations may depend on the
|
|
196
|
+
# results of earlier operations.
|
|
197
|
+
ops.each{|op| alter_table_sql_list(table, [op]).flatten.each{|sql| execute_ddl(sql)}}
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
self.foreign_keys = true if fks
|
|
201
|
+
end
|
|
202
|
+
|
|
139
203
|
# SQLite supports limited table modification. You can add a column
|
|
140
204
|
# or an index. Dropping columns is supported by copying the table into
|
|
141
205
|
# a temporary table, dropping the table, and creating a new table without
|
|
@@ -161,13 +225,28 @@ module Sequel
|
|
|
161
225
|
when :set_column_null
|
|
162
226
|
duplicate_table(table){|columns| columns.each{|s| s[:null] = op[:null] if s[:name].to_s == op[:name].to_s}}
|
|
163
227
|
when :set_column_type
|
|
164
|
-
duplicate_table(table){|columns| columns.each{|s| s
|
|
228
|
+
duplicate_table(table){|columns| columns.each{|s| s.merge!(op) if s[:name].to_s == op[:name].to_s}}
|
|
229
|
+
when :drop_constraint
|
|
230
|
+
case op[:type]
|
|
231
|
+
when :primary_key
|
|
232
|
+
duplicate_table(table){|columns| columns.each{|s| s[:primary_key] = nil}}
|
|
233
|
+
when :foreign_key
|
|
234
|
+
duplicate_table(table, :no_foreign_keys=>true)
|
|
235
|
+
when :unique
|
|
236
|
+
duplicate_table(table)
|
|
237
|
+
else
|
|
238
|
+
raise Error, "Unsupported :type option for drop_constraint: #{op[:type].inspect}"
|
|
239
|
+
end
|
|
240
|
+
when :add_constraint
|
|
241
|
+
duplicate_table(table, :constraints=>[op])
|
|
242
|
+
when :add_constraints
|
|
243
|
+
duplicate_table(table, :constraints=>op[:ops])
|
|
165
244
|
else
|
|
166
|
-
raise Error, "Unsupported ALTER TABLE operation"
|
|
245
|
+
raise Error, "Unsupported ALTER TABLE operation: #{op[:op].inspect}"
|
|
167
246
|
end
|
|
168
247
|
end
|
|
169
|
-
|
|
170
|
-
#
|
|
248
|
+
|
|
249
|
+
# A name to use for the backup table
|
|
171
250
|
def backup_table_name(table, opts={})
|
|
172
251
|
table = table.gsub('`', '')
|
|
173
252
|
(opts[:times]||1000).times do |i|
|
|
@@ -176,17 +255,19 @@ module Sequel
|
|
|
176
255
|
end
|
|
177
256
|
end
|
|
178
257
|
|
|
179
|
-
#
|
|
180
|
-
def
|
|
181
|
-
|
|
258
|
+
# Surround default with parens to appease SQLite
|
|
259
|
+
def column_definition_default_sql(sql, column)
|
|
260
|
+
sql << " DEFAULT (#{literal(column[:default])})" if column.include?(:default)
|
|
182
261
|
end
|
|
183
|
-
|
|
262
|
+
|
|
184
263
|
# Array of PRAGMA SQL statements based on the Database options that should be applied to
|
|
185
264
|
# new connections.
|
|
186
265
|
def connection_pragmas
|
|
187
266
|
ps = []
|
|
188
267
|
v = typecast_value_boolean(opts.fetch(:foreign_keys, 1))
|
|
189
268
|
ps << "PRAGMA foreign_keys = #{v ? 1 : 0}"
|
|
269
|
+
v = typecast_value_boolean(opts.fetch(:case_sensitive_like, 1))
|
|
270
|
+
ps << "PRAGMA case_sensitive_like = #{v ? 1 : 0}"
|
|
190
271
|
[[:auto_vacuum, AUTO_VACUUM], [:synchronous, SYNCHRONOUS], [:temp_store, TEMP_STORE]].each do |prag, con|
|
|
191
272
|
if v = opts[prag]
|
|
192
273
|
raise(Error, "Value for PRAGMA #{prag} not supported, should be one of #{con.join(', ')}") unless v = con.index(v.to_sym)
|
|
@@ -196,28 +277,13 @@ module Sequel
|
|
|
196
277
|
ps
|
|
197
278
|
end
|
|
198
279
|
|
|
199
|
-
# The array of column schema hashes
|
|
200
|
-
def defined_columns_for(table
|
|
280
|
+
# The array of column schema hashes for the current columns in the table
|
|
281
|
+
def defined_columns_for(table)
|
|
201
282
|
cols = parse_pragma(table, {})
|
|
202
283
|
cols.each do |c|
|
|
203
284
|
c[:default] = LiteralString.new(c[:default]) if c[:default]
|
|
204
285
|
c[:type] = c[:db_type]
|
|
205
286
|
end
|
|
206
|
-
if opts[:except]
|
|
207
|
-
nono= Array(opts[:except]).compact.map{|n| n.to_s}
|
|
208
|
-
cols.reject!{|c| nono.include? c[:name] }
|
|
209
|
-
end
|
|
210
|
-
|
|
211
|
-
if foreign_keys
|
|
212
|
-
metadata_dataset.with_sql("PRAGMA foreign_key_list(?)", input_identifier_meth.call(table)).each do |row|
|
|
213
|
-
c = cols.find {|co| co[:name] == row[:from] } or next
|
|
214
|
-
c[:table] = row[:table]
|
|
215
|
-
c[:key] = row[:to]
|
|
216
|
-
c[:on_update] = on_delete_sql_to_sym(row[:on_update])
|
|
217
|
-
c[:on_delete] = on_delete_sql_to_sym(row[:on_delete])
|
|
218
|
-
# is there any way to get deferrable status?
|
|
219
|
-
end
|
|
220
|
-
end
|
|
221
287
|
cols
|
|
222
288
|
end
|
|
223
289
|
|
|
@@ -231,17 +297,40 @@ module Sequel
|
|
|
231
297
|
opts[:old_columns_proc].call(old_columns) if opts[:old_columns_proc]
|
|
232
298
|
|
|
233
299
|
yield def_columns if block_given?
|
|
234
|
-
|
|
300
|
+
|
|
301
|
+
constraints = (opts[:constraints] || []).dup
|
|
302
|
+
pks = []
|
|
303
|
+
def_columns.each{|c| pks << c[:name] if c[:primary_key]}
|
|
304
|
+
if pks.length > 1
|
|
305
|
+
constraints << {:type=>:primary_key, :columns=>pks}
|
|
306
|
+
def_columns.each{|c| c[:primary_key] = false if c[:primary_key]}
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
# If dropping a foreign key constraint, drop all foreign key constraints,
|
|
310
|
+
# as there is no way to determine which one to drop.
|
|
311
|
+
unless opts[:no_foreign_keys]
|
|
312
|
+
fks = foreign_key_list(table)
|
|
313
|
+
|
|
314
|
+
# If dropping a column, if there is a foreign key with that
|
|
315
|
+
# column, don't include it when building a copy of the table.
|
|
316
|
+
if ocp = opts[:old_columns_proc]
|
|
317
|
+
fks.delete_if{|c| ocp.call(c[:columns].dup) != c[:columns]}
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
constraints.concat(fks.each{|h| h[:type] = :foreign_key})
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
def_columns_str = (def_columns.map{|c| column_definition_sql(c)} + constraints.map{|c| constraint_definition_sql(c)}).join(', ')
|
|
235
324
|
new_columns = old_columns.dup
|
|
236
325
|
opts[:new_columns_proc].call(new_columns) if opts[:new_columns_proc]
|
|
237
326
|
|
|
238
327
|
qt = quote_schema_table(table)
|
|
239
328
|
bt = quote_identifier(backup_table_name(qt))
|
|
240
329
|
a = [
|
|
241
|
-
"
|
|
242
|
-
"
|
|
243
|
-
"
|
|
244
|
-
"
|
|
330
|
+
"ALTER TABLE #{qt} RENAME TO #{bt}",
|
|
331
|
+
"CREATE TABLE #{qt}(#{def_columns_str})",
|
|
332
|
+
"INSERT INTO #{qt}(#{dataset.send(:identifier_list, new_columns)}) SELECT #{dataset.send(:identifier_list, old_columns)} FROM #{bt}",
|
|
333
|
+
"DROP TABLE #{bt}"
|
|
245
334
|
]
|
|
246
335
|
indexes(table).each do |name, h|
|
|
247
336
|
if (h[:columns].map{|x| x.to_s} - new_columns).empty?
|
|
@@ -280,7 +369,7 @@ module Sequel
|
|
|
280
369
|
|
|
281
370
|
# Parse the output of the table_info pragma
|
|
282
371
|
def parse_pragma(table_name, opts)
|
|
283
|
-
metadata_dataset.with_sql("PRAGMA table_info(?)", input_identifier_meth.call(table_name)).map do |row|
|
|
372
|
+
metadata_dataset.with_sql("PRAGMA table_info(?)", input_identifier_meth(opts[:dataset]).call(table_name)).map do |row|
|
|
284
373
|
row.delete(:cid)
|
|
285
374
|
row[:allow_null] = row.delete(:notnull).to_i == 0
|
|
286
375
|
row[:default] = row.delete(:dflt_value)
|
|
@@ -300,59 +389,102 @@ module Sequel
|
|
|
300
389
|
# SQLite supports schema parsing using the table_info PRAGMA, so
|
|
301
390
|
# parse the output of that into the format Sequel expects.
|
|
302
391
|
def schema_parse_table(table_name, opts)
|
|
303
|
-
m = output_identifier_meth
|
|
392
|
+
m = output_identifier_meth(opts[:dataset])
|
|
304
393
|
parse_pragma(table_name, opts).map do |row|
|
|
305
394
|
[m.call(row.delete(:name)), row]
|
|
306
395
|
end
|
|
307
396
|
end
|
|
308
397
|
|
|
309
|
-
#
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
398
|
+
# Backbone of the tables and views support.
|
|
399
|
+
def tables_and_views(filter, opts)
|
|
400
|
+
m = output_identifier_meth
|
|
401
|
+
metadata_dataset.from(:sqlite_master).server(opts[:server]).filter(filter).map{|r| m.call(r[:name])}
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
# SQLite only supports AUTOINCREMENT on integer columns, not
|
|
405
|
+
# bigint columns, so use integer instead of bigint for those
|
|
406
|
+
# columns.
|
|
313
407
|
def type_literal_generic_bignum(column)
|
|
314
|
-
:integer
|
|
408
|
+
column[:auto_increment] ? :integer : super
|
|
315
409
|
end
|
|
316
410
|
end
|
|
317
411
|
|
|
318
412
|
# Instance methods for datasets that connect to an SQLite database
|
|
319
413
|
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
|
|
414
|
+
SELECT_CLAUSE_METHODS = Dataset.clause_methods(:select, %w'select distinct columns from join where group having compounds order limit')
|
|
322
415
|
CONSTANT_MAP = {:CURRENT_DATE=>"date(CURRENT_TIMESTAMP, 'localtime')".freeze, :CURRENT_TIMESTAMP=>"datetime(CURRENT_TIMESTAMP, 'localtime')".freeze, :CURRENT_TIME=>"time(CURRENT_TIMESTAMP, 'localtime')".freeze}
|
|
323
|
-
|
|
416
|
+
EXTRACT_MAP = {:year=>"'%Y'", :month=>"'%m'", :day=>"'%d'", :hour=>"'%H'", :minute=>"'%M'", :second=>"'%f'"}
|
|
417
|
+
NOT_SPACE = Dataset::NOT_SPACE
|
|
418
|
+
COMMA = Dataset::COMMA
|
|
419
|
+
PAREN_CLOSE = Dataset::PAREN_CLOSE
|
|
420
|
+
AS = Dataset::AS
|
|
421
|
+
APOS = Dataset::APOS
|
|
422
|
+
EXTRACT_OPEN = "CAST(strftime(".freeze
|
|
423
|
+
EXTRACT_CLOSE = ') AS '.freeze
|
|
424
|
+
NUMERIC = 'NUMERIC'.freeze
|
|
425
|
+
INTEGER = 'INTEGER'.freeze
|
|
426
|
+
BACKTICK = '`'.freeze
|
|
427
|
+
BACKTICK_RE = /`/.freeze
|
|
428
|
+
DOUBLE_BACKTICK = '``'.freeze
|
|
429
|
+
BLOB_START = "X'".freeze
|
|
430
|
+
HSTAR = "H*".freeze
|
|
431
|
+
|
|
324
432
|
# SQLite does not support pattern matching via regular expressions.
|
|
325
433
|
# SQLite is case insensitive (depending on pragma), so use LIKE for
|
|
326
434
|
# ILIKE.
|
|
327
|
-
def
|
|
435
|
+
def complex_expression_sql_append(sql, op, args)
|
|
328
436
|
case op
|
|
329
437
|
when :~, :'!~', :'~*', :'!~*'
|
|
330
438
|
raise Error, "SQLite does not support pattern matching via regular expressions"
|
|
331
|
-
when :
|
|
332
|
-
|
|
333
|
-
|
|
439
|
+
when :ILIKE
|
|
440
|
+
super(sql, :LIKE, args.map{|a| SQL::Function.new(:upper, a)})
|
|
441
|
+
when :"NOT LIKE", :"NOT ILIKE"
|
|
442
|
+
sql << NOT_SPACE
|
|
443
|
+
complex_expression_sql_append(sql, (op == :"NOT ILIKE" ? :ILIKE : :LIKE), args)
|
|
444
|
+
when :^
|
|
445
|
+
sql << complex_expression_arg_pairs(args) do |a, b|
|
|
446
|
+
a = literal(a)
|
|
447
|
+
b = literal(b)
|
|
448
|
+
"((~(#{a} & #{b})) & (#{a} | #{b}))"
|
|
449
|
+
end
|
|
450
|
+
when :extract
|
|
451
|
+
part = args.at(0)
|
|
452
|
+
raise(Sequel::Error, "unsupported extract argument: #{part.inspect}") unless format = EXTRACT_MAP[part]
|
|
453
|
+
sql << EXTRACT_OPEN << format << COMMA
|
|
454
|
+
literal_append(sql, args.at(1))
|
|
455
|
+
sql << EXTRACT_CLOSE << (part == :second ? NUMERIC : INTEGER) << PAREN_CLOSE
|
|
334
456
|
else
|
|
335
|
-
super
|
|
457
|
+
super
|
|
336
458
|
end
|
|
337
459
|
end
|
|
338
460
|
|
|
339
|
-
#
|
|
340
|
-
|
|
341
|
-
|
|
461
|
+
# SQLite has CURRENT_TIMESTAMP and related constants in UTC instead
|
|
462
|
+
# of in localtime, so convert those constants to local time.
|
|
463
|
+
def constant_sql_append(sql, constant)
|
|
464
|
+
if c = CONSTANT_MAP[constant]
|
|
465
|
+
sql << c
|
|
466
|
+
else
|
|
467
|
+
super
|
|
468
|
+
end
|
|
342
469
|
end
|
|
343
470
|
|
|
344
471
|
# SQLite performs a TRUNCATE style DELETE if no filter is specified.
|
|
345
472
|
# Since we want to always return the count of records, add a condition
|
|
346
473
|
# that is always true and then delete.
|
|
347
474
|
def delete
|
|
348
|
-
@opts[:where] ? super :
|
|
475
|
+
@opts[:where] ? super : where(1=>1).delete
|
|
349
476
|
end
|
|
350
477
|
|
|
351
478
|
# Return an array of strings specifying a query explanation for a SELECT of the
|
|
352
|
-
# current dataset.
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
479
|
+
# current dataset. Currently, the options are ignore, but it accepts options
|
|
480
|
+
# to be compatible with other adapters.
|
|
481
|
+
def explain(opts=nil)
|
|
482
|
+
# Load the PrettyTable class, needed for explain output
|
|
483
|
+
Sequel.extension(:_pretty_table) unless defined?(Sequel::PrettyTable)
|
|
484
|
+
|
|
485
|
+
ds = db.send(:metadata_dataset).clone(:sql=>"EXPLAIN #{select_sql}")
|
|
486
|
+
rows = ds.all
|
|
487
|
+
Sequel::PrettyTable.string(rows, ds.columns)
|
|
356
488
|
end
|
|
357
489
|
|
|
358
490
|
# HAVING requires GROUP BY on SQLite
|
|
@@ -362,8 +494,20 @@ module Sequel
|
|
|
362
494
|
end
|
|
363
495
|
|
|
364
496
|
# SQLite uses the nonstandard ` (backtick) for quoting identifiers.
|
|
365
|
-
def
|
|
366
|
-
|
|
497
|
+
def quoted_identifier_append(sql, c)
|
|
498
|
+
sql << BACKTICK << c.to_s.gsub(BACKTICK_RE, DOUBLE_BACKTICK) << BACKTICK
|
|
499
|
+
end
|
|
500
|
+
|
|
501
|
+
# When a qualified column is selected on SQLite and the qualifier
|
|
502
|
+
# is a subselect, the column name used is the full qualified name
|
|
503
|
+
# (including the qualifier) instead of just the column name. To
|
|
504
|
+
# get correct column names, you must use an alias.
|
|
505
|
+
def select(*cols)
|
|
506
|
+
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)})
|
|
507
|
+
super(*cols.map{|c| alias_qualified_column(c)})
|
|
508
|
+
else
|
|
509
|
+
super
|
|
510
|
+
end
|
|
367
511
|
end
|
|
368
512
|
|
|
369
513
|
# SQLite does not support INTERSECT ALL or EXCEPT ALL
|
|
@@ -382,31 +526,63 @@ module Sequel
|
|
|
382
526
|
end
|
|
383
527
|
|
|
384
528
|
# SQLite supports timezones in literal timestamps, since it stores them
|
|
385
|
-
# as text.
|
|
529
|
+
# as text. But using timezones in timestamps breaks SQLite datetime
|
|
530
|
+
# functions, so we allow the user to override the default per database.
|
|
386
531
|
def supports_timestamp_timezones?
|
|
387
|
-
|
|
532
|
+
db.use_timestamp_timezones?
|
|
388
533
|
end
|
|
389
534
|
|
|
535
|
+
# SQLite cannot use WHERE 't'.
|
|
536
|
+
def supports_where_true?
|
|
537
|
+
false
|
|
538
|
+
end
|
|
539
|
+
|
|
390
540
|
private
|
|
391
541
|
|
|
392
542
|
# SQLite uses string literals instead of identifiers in AS clauses.
|
|
393
|
-
def
|
|
543
|
+
def as_sql_append(sql, aliaz)
|
|
394
544
|
aliaz = aliaz.value if aliaz.is_a?(SQL::Identifier)
|
|
395
|
-
|
|
545
|
+
sql << AS
|
|
546
|
+
literal_append(sql, aliaz.to_s)
|
|
547
|
+
end
|
|
548
|
+
|
|
549
|
+
# If col is a qualified column, alias it to the same as the column name
|
|
550
|
+
def alias_qualified_column(col)
|
|
551
|
+
case col
|
|
552
|
+
when Symbol
|
|
553
|
+
t, c, a = split_symbol(col)
|
|
554
|
+
if t && !a
|
|
555
|
+
alias_qualified_column(SQL::QualifiedIdentifier.new(t, c))
|
|
556
|
+
else
|
|
557
|
+
col
|
|
558
|
+
end
|
|
559
|
+
when SQL::QualifiedIdentifier
|
|
560
|
+
SQL::AliasedExpression.new(col, col.column)
|
|
561
|
+
else
|
|
562
|
+
col
|
|
563
|
+
end
|
|
396
564
|
end
|
|
397
565
|
|
|
398
566
|
# SQL fragment specifying a list of identifiers
|
|
399
567
|
def identifier_list(columns)
|
|
400
|
-
columns.map{|i| quote_identifier(i)}.join(
|
|
568
|
+
columns.map{|i| quote_identifier(i)}.join(COMMA)
|
|
401
569
|
end
|
|
402
570
|
|
|
403
571
|
# SQLite uses a preceding X for hex escaping strings
|
|
404
|
-
def
|
|
405
|
-
|
|
406
|
-
v.each_byte{|x| blob << sprintf('%02x', x)}
|
|
407
|
-
"X'#{blob}'"
|
|
572
|
+
def literal_blob_append(sql, v)
|
|
573
|
+
sql << BLOB_START << v.unpack(HSTAR).first << APOS
|
|
408
574
|
end
|
|
409
|
-
|
|
575
|
+
|
|
576
|
+
# Respect the database integer_booleans setting, using 0 or 'f'.
|
|
577
|
+
def literal_false
|
|
578
|
+
@db.integer_booleans ? '0' : "'f'"
|
|
579
|
+
end
|
|
580
|
+
|
|
581
|
+
# Respect the database integer_booleans setting, using 1 or 't'.
|
|
582
|
+
def literal_true
|
|
583
|
+
@db.integer_booleans ? '1' : "'t'"
|
|
584
|
+
end
|
|
585
|
+
|
|
410
586
|
# SQLite does not support the SQL WITH clause
|
|
411
587
|
def select_clause_methods
|
|
412
588
|
SELECT_CLAUSE_METHODS
|
|
@@ -416,7 +592,7 @@ module Sequel
|
|
|
416
592
|
def select_lock_sql(sql)
|
|
417
593
|
super unless @opts[:lock] == :update
|
|
418
594
|
end
|
|
419
|
-
|
|
595
|
+
|
|
420
596
|
# SQLite treats a DELETE with no WHERE clause as a TRUNCATE
|
|
421
597
|
def _truncate_sql(table)
|
|
422
598
|
"DELETE FROM #{table}"
|