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
data/lib/sequel/dataset/sql.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
module Sequel
|
|
2
2
|
class Dataset
|
|
3
3
|
# ---------------------
|
|
4
|
-
# :section: User Methods relating to SQL Creation
|
|
4
|
+
# :section: 3 - User Methods relating to SQL Creation
|
|
5
5
|
# These are methods you can call to see what SQL will be generated by the dataset.
|
|
6
6
|
# ---------------------
|
|
7
7
|
|
|
@@ -20,7 +20,7 @@ module Sequel
|
|
|
20
20
|
# DB.select(1).where(DB[:items].exists)
|
|
21
21
|
# # SELECT 1 WHERE (EXISTS (SELECT * FROM items))
|
|
22
22
|
def exists
|
|
23
|
-
|
|
23
|
+
SQL::PlaceholderLiteralString.new(EXISTS, [self], true)
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
# Returns an INSERT SQL query string. See +insert+.
|
|
@@ -61,7 +61,10 @@ module Sequel
|
|
|
61
61
|
end
|
|
62
62
|
end
|
|
63
63
|
|
|
64
|
-
|
|
64
|
+
if values.is_a?(Array) && values.empty? && !insert_supports_empty_values?
|
|
65
|
+
columns = [columns().last]
|
|
66
|
+
values = [DEFAULT]
|
|
67
|
+
end
|
|
65
68
|
clone(:columns=>columns, :values=>values)._insert_sql
|
|
66
69
|
end
|
|
67
70
|
|
|
@@ -75,41 +78,47 @@ module Sequel
|
|
|
75
78
|
# DB[:items].literal(:x + 1 > :y) => "((x + 1) > y)"
|
|
76
79
|
#
|
|
77
80
|
# If an unsupported object is given, an +Error+ is raised.
|
|
78
|
-
def
|
|
81
|
+
def literal_append(sql, v)
|
|
79
82
|
case v
|
|
80
|
-
when String
|
|
81
|
-
return v if v.is_a?(LiteralString)
|
|
82
|
-
v.is_a?(SQL::Blob) ? literal_blob(v) : literal_string(v)
|
|
83
83
|
when Symbol
|
|
84
|
-
|
|
84
|
+
literal_symbol_append(sql, v)
|
|
85
|
+
when String
|
|
86
|
+
case v
|
|
87
|
+
when LiteralString
|
|
88
|
+
sql << v
|
|
89
|
+
when SQL::Blob
|
|
90
|
+
literal_blob_append(sql, v)
|
|
91
|
+
else
|
|
92
|
+
literal_string_append(sql, v)
|
|
93
|
+
end
|
|
85
94
|
when Integer
|
|
86
|
-
literal_integer(v)
|
|
95
|
+
sql << literal_integer(v)
|
|
87
96
|
when Hash
|
|
88
|
-
|
|
97
|
+
literal_hash_append(sql, v)
|
|
89
98
|
when SQL::Expression
|
|
90
|
-
|
|
99
|
+
literal_expression_append(sql, v)
|
|
91
100
|
when Float
|
|
92
|
-
literal_float(v)
|
|
101
|
+
sql << literal_float(v)
|
|
93
102
|
when BigDecimal
|
|
94
|
-
literal_big_decimal(v)
|
|
103
|
+
sql << literal_big_decimal(v)
|
|
95
104
|
when NilClass
|
|
96
|
-
literal_nil
|
|
105
|
+
sql << literal_nil
|
|
97
106
|
when TrueClass
|
|
98
|
-
literal_true
|
|
107
|
+
sql << literal_true
|
|
99
108
|
when FalseClass
|
|
100
|
-
literal_false
|
|
109
|
+
sql << literal_false
|
|
101
110
|
when Array
|
|
102
|
-
|
|
111
|
+
literal_array_append(sql, v)
|
|
103
112
|
when Time
|
|
104
|
-
literal_time(v)
|
|
113
|
+
sql << (v.is_a?(SQLTime) ? literal_sqltime(v) : literal_time(v))
|
|
105
114
|
when DateTime
|
|
106
|
-
literal_datetime(v)
|
|
115
|
+
sql << literal_datetime(v)
|
|
107
116
|
when Date
|
|
108
|
-
literal_date(v)
|
|
117
|
+
sql << literal_date(v)
|
|
109
118
|
when Dataset
|
|
110
|
-
|
|
119
|
+
literal_dataset_append(sql, v)
|
|
111
120
|
else
|
|
112
|
-
|
|
121
|
+
literal_other_append(sql, v)
|
|
113
122
|
end
|
|
114
123
|
end
|
|
115
124
|
|
|
@@ -143,8 +152,8 @@ module Sequel
|
|
|
143
152
|
if opts[:sql]
|
|
144
153
|
static_sql(opts[:sql])
|
|
145
154
|
else
|
|
146
|
-
|
|
147
|
-
raise(InvalidOperation, "Can't truncate filtered datasets") if opts[:where]
|
|
155
|
+
check_truncation_allowed!
|
|
156
|
+
raise(InvalidOperation, "Can't truncate filtered datasets") if opts[:where] || opts[:having]
|
|
148
157
|
_truncate_sql(source_list(opts[:from]))
|
|
149
158
|
end
|
|
150
159
|
end
|
|
@@ -163,7 +172,7 @@ module Sequel
|
|
|
163
172
|
end
|
|
164
173
|
|
|
165
174
|
# ---------------------
|
|
166
|
-
# :section: Internal Methods relating to SQL Creation
|
|
175
|
+
# :section: 9 - Internal Methods relating to SQL Creation
|
|
167
176
|
# These methods, while public, are not designed to be used directly by the end user.
|
|
168
177
|
# ---------------------
|
|
169
178
|
|
|
@@ -173,80 +182,235 @@ module Sequel
|
|
|
173
182
|
clauses.map{|clause| :"#{type}_#{clause}_sql"}.freeze
|
|
174
183
|
end
|
|
175
184
|
|
|
185
|
+
WILDCARD = LiteralString.new('*').freeze
|
|
186
|
+
ALL = ' ALL'.freeze
|
|
176
187
|
AND_SEPARATOR = " AND ".freeze
|
|
188
|
+
APOS = "'".freeze
|
|
189
|
+
APOS_RE = /'/.freeze
|
|
190
|
+
ARRAY_EMPTY = '(NULL)'.freeze
|
|
191
|
+
AS = ' AS '.freeze
|
|
192
|
+
ASC = ' ASC'.freeze
|
|
177
193
|
BOOL_FALSE = "'f'".freeze
|
|
178
194
|
BOOL_TRUE = "'t'".freeze
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
195
|
+
BRACKET_CLOSE = ']'.freeze
|
|
196
|
+
BRACKET_OPEN = '['.freeze
|
|
197
|
+
CASE_ELSE = " ELSE ".freeze
|
|
198
|
+
CASE_END = " END)".freeze
|
|
199
|
+
CASE_OPEN = '(CASE'.freeze
|
|
200
|
+
CASE_THEN = " THEN ".freeze
|
|
201
|
+
CASE_WHEN = " WHEN ".freeze
|
|
202
|
+
CAST_OPEN = 'CAST('.freeze
|
|
203
|
+
COLUMN_REF_RE1 = /\A((?:(?!__).)+)__((?:(?!___).)+)___(.+)\z/.freeze
|
|
204
|
+
COLUMN_REF_RE2 = /\A((?:(?!___).)+)___(.+)\z/.freeze
|
|
205
|
+
COLUMN_REF_RE3 = /\A((?:(?!__).)+)__(.+)\z/.freeze
|
|
206
|
+
COMMA = ', '.freeze
|
|
207
|
+
COMMA_SEPARATOR = COMMA
|
|
208
|
+
CONDITION_FALSE = '(1 = 0)'.freeze
|
|
209
|
+
CONDITION_TRUE = '(1 = 1)'.freeze
|
|
183
210
|
COUNT_FROM_SELF_OPTS = [:distinct, :group, :sql, :limit, :compounds]
|
|
184
|
-
COUNT_OF_ALL_AS_COUNT = SQL::Function.new(:count,
|
|
211
|
+
COUNT_OF_ALL_AS_COUNT = SQL::Function.new(:count, WILDCARD).as(:count)
|
|
185
212
|
DATASET_ALIAS_BASE_NAME = 't'.freeze
|
|
213
|
+
DEFAULT = LiteralString.new('DEFAULT').freeze
|
|
214
|
+
DEFAULT_VALUES = " DEFAULT VALUES".freeze
|
|
215
|
+
DELETE = 'DELETE'.freeze
|
|
216
|
+
DELETE_CLAUSE_METHODS = clause_methods(:delete, %w'delete from where')
|
|
217
|
+
DESC = ' DESC'.freeze
|
|
218
|
+
DISTINCT = " DISTINCT".freeze
|
|
219
|
+
DOT = '.'.freeze
|
|
220
|
+
DOUBLE_APOS = "''".freeze
|
|
221
|
+
DOUBLE_QUOTE = '""'.freeze
|
|
222
|
+
EQUAL = ' = '.freeze
|
|
223
|
+
EXTRACT = 'extract('.freeze
|
|
224
|
+
EXISTS = ['EXISTS '.freeze].freeze
|
|
186
225
|
FOR_UPDATE = ' FOR UPDATE'.freeze
|
|
226
|
+
FORMAT_DATE = "'%Y-%m-%d'".freeze
|
|
227
|
+
FORMAT_DATE_STANDARD = "DATE '%Y-%m-%d'".freeze
|
|
228
|
+
FORMAT_OFFSET = "%+03i%02i".freeze
|
|
229
|
+
FORMAT_TIMESTAMP_RE = /%[Nz]/.freeze
|
|
230
|
+
FORMAT_TIMESTAMP_USEC = ".%06d".freeze
|
|
231
|
+
FORMAT_USEC = '%N'.freeze
|
|
232
|
+
FRAME_ALL = "ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING".freeze
|
|
233
|
+
FRAME_ROWS = "ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW".freeze
|
|
234
|
+
FROM = ' FROM '.freeze
|
|
235
|
+
FUNCTION_EMPTY = '()'.freeze
|
|
236
|
+
GROUP_BY = " GROUP BY ".freeze
|
|
237
|
+
HAVING = " HAVING ".freeze
|
|
238
|
+
INSERT = "INSERT".freeze
|
|
239
|
+
INSERT_CLAUSE_METHODS = clause_methods(:insert, %w'insert into columns values')
|
|
240
|
+
INTO = " INTO ".freeze
|
|
187
241
|
IS_LITERALS = {nil=>'NULL'.freeze, true=>'TRUE'.freeze, false=>'FALSE'.freeze}.freeze
|
|
188
242
|
IS_OPERATORS = ::Sequel::SQL::ComplexExpression::IS_OPERATORS
|
|
243
|
+
LIMIT = " LIMIT ".freeze
|
|
189
244
|
N_ARITY_OPERATORS = ::Sequel::SQL::ComplexExpression::N_ARITY_OPERATORS
|
|
245
|
+
NOT_SPACE = 'NOT '.freeze
|
|
190
246
|
NULL = "NULL".freeze
|
|
247
|
+
NULLS_FIRST = " NULLS FIRST".freeze
|
|
248
|
+
NULLS_LAST = " NULLS LAST".freeze
|
|
249
|
+
OFFSET = " OFFSET ".freeze
|
|
250
|
+
ON = ' ON '.freeze
|
|
251
|
+
ON_PAREN = " ON (".freeze
|
|
252
|
+
ORDER_BY = " ORDER BY ".freeze
|
|
253
|
+
ORDER_BY_NS = "ORDER BY ".freeze
|
|
254
|
+
OVER = ' OVER '.freeze
|
|
255
|
+
PAREN_CLOSE = ')'.freeze
|
|
256
|
+
PAREN_OPEN = '('.freeze
|
|
257
|
+
PAREN_SPACE_OPEN = ' ('.freeze
|
|
258
|
+
PARTITION_BY = "PARTITION BY ".freeze
|
|
191
259
|
QUALIFY_KEYS = [:select, :where, :having, :order, :group]
|
|
192
260
|
QUESTION_MARK = '?'.freeze
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
261
|
+
QUESTION_MARK_RE = /\?/.freeze
|
|
262
|
+
QUOTE = '"'.freeze
|
|
263
|
+
QUOTE_RE = /"/.freeze
|
|
264
|
+
RETURNING = " RETURNING ".freeze
|
|
265
|
+
SELECT = 'SELECT'.freeze
|
|
266
|
+
SELECT_CLAUSE_METHODS = clause_methods(:select, %w'with select distinct columns from join where group having compounds order limit lock')
|
|
267
|
+
SET = ' SET '.freeze
|
|
268
|
+
SPACE = ' '.freeze
|
|
269
|
+
SQL_WITH = "WITH ".freeze
|
|
270
|
+
SPACE_WITH = " WITH ".freeze
|
|
271
|
+
TILDE = '~'.freeze
|
|
197
272
|
TIMESTAMP_FORMAT = "'%Y-%m-%d %H:%M:%S%N%z'".freeze
|
|
198
273
|
STANDARD_TIMESTAMP_FORMAT = "TIMESTAMP #{TIMESTAMP_FORMAT}".freeze
|
|
199
274
|
TWO_ARITY_OPERATORS = ::Sequel::SQL::ComplexExpression::TWO_ARITY_OPERATORS
|
|
200
|
-
|
|
201
|
-
|
|
275
|
+
UNDERSCORE = '_'.freeze
|
|
276
|
+
UPDATE = 'UPDATE'.freeze
|
|
277
|
+
UPDATE_CLAUSE_METHODS = clause_methods(:update, %w'update table set where')
|
|
278
|
+
USING = ' USING ('.freeze
|
|
279
|
+
VALUES = " VALUES ".freeze
|
|
280
|
+
V190 = '1.9.0'.freeze
|
|
281
|
+
WHERE = " WHERE ".freeze
|
|
282
|
+
|
|
283
|
+
PUBLIC_APPEND_METHODS = (<<-END).split.map{|x| x.to_sym}
|
|
284
|
+
literal
|
|
285
|
+
aliased_expression_sql
|
|
286
|
+
array_sql
|
|
287
|
+
boolean_constant_sql
|
|
288
|
+
case_expression_sql
|
|
289
|
+
cast_sql
|
|
290
|
+
column_all_sql
|
|
291
|
+
complex_expression_sql
|
|
292
|
+
constant_sql
|
|
293
|
+
function_sql
|
|
294
|
+
join_clause_sql
|
|
295
|
+
join_on_clause_sql
|
|
296
|
+
join_using_clause_sql
|
|
297
|
+
negative_boolean_constant_sql
|
|
298
|
+
ordered_expression_sql
|
|
299
|
+
placeholder_literal_string_sql
|
|
300
|
+
qualified_identifier_sql
|
|
301
|
+
quote_identifier
|
|
302
|
+
quote_schema_table
|
|
303
|
+
quoted_identifier
|
|
304
|
+
subscript_sql
|
|
305
|
+
window_sql
|
|
306
|
+
window_function_sql
|
|
307
|
+
END
|
|
308
|
+
PRIVATE_APPEND_METHODS = (<<-END).split.map{|x| x.to_sym}
|
|
309
|
+
argument_list
|
|
310
|
+
as_sql
|
|
311
|
+
column_list
|
|
312
|
+
compound_dataset_sql
|
|
313
|
+
expression_list
|
|
314
|
+
literal_array
|
|
315
|
+
literal_blob
|
|
316
|
+
literal_dataset
|
|
317
|
+
literal_expression
|
|
318
|
+
literal_hash
|
|
319
|
+
literal_other
|
|
320
|
+
literal_string
|
|
321
|
+
literal_symbol
|
|
322
|
+
source_list
|
|
323
|
+
subselect_sql
|
|
324
|
+
table_ref
|
|
325
|
+
END
|
|
326
|
+
def self.def_append_methods(meths)
|
|
327
|
+
meths.each do |meth|
|
|
328
|
+
class_eval(<<-END, __FILE__, __LINE__ + 1)
|
|
329
|
+
def #{meth}(*args, &block)
|
|
330
|
+
s = ''
|
|
331
|
+
#{meth}_append(s, *args, &block)
|
|
332
|
+
s
|
|
333
|
+
end
|
|
334
|
+
END
|
|
335
|
+
end
|
|
336
|
+
end
|
|
337
|
+
def_append_methods(PUBLIC_APPEND_METHODS + PRIVATE_APPEND_METHODS)
|
|
338
|
+
private *PRIVATE_APPEND_METHODS
|
|
202
339
|
|
|
203
340
|
# SQL fragment for AliasedExpression
|
|
204
|
-
def
|
|
205
|
-
|
|
341
|
+
def aliased_expression_sql_append(sql, ae)
|
|
342
|
+
literal_append(sql, ae.expression)
|
|
343
|
+
as_sql_append(sql, ae.aliaz)
|
|
206
344
|
end
|
|
207
345
|
|
|
208
346
|
# SQL fragment for Array
|
|
209
|
-
def
|
|
210
|
-
a.empty?
|
|
347
|
+
def array_sql_append(sql, a)
|
|
348
|
+
if a.empty?
|
|
349
|
+
sql << ARRAY_EMPTY
|
|
350
|
+
else
|
|
351
|
+
sql << PAREN_OPEN
|
|
352
|
+
expression_list_append(sql, a)
|
|
353
|
+
sql << PAREN_CLOSE
|
|
354
|
+
end
|
|
211
355
|
end
|
|
212
356
|
|
|
213
357
|
# SQL fragment for BooleanConstants
|
|
214
|
-
def
|
|
215
|
-
|
|
358
|
+
def boolean_constant_sql_append(sql, constant)
|
|
359
|
+
if (constant == true || constant == false) && !supports_where_true?
|
|
360
|
+
sql << (constant == true ? CONDITION_TRUE : CONDITION_FALSE)
|
|
361
|
+
else
|
|
362
|
+
literal_append(sql, constant)
|
|
363
|
+
end
|
|
216
364
|
end
|
|
217
365
|
|
|
218
366
|
# SQL fragment for CaseExpression
|
|
219
|
-
def
|
|
220
|
-
sql
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
sql
|
|
224
|
-
|
|
225
|
-
|
|
367
|
+
def case_expression_sql_append(sql, ce)
|
|
368
|
+
sql << CASE_OPEN
|
|
369
|
+
if ce.expression?
|
|
370
|
+
sql << SPACE
|
|
371
|
+
literal_append(sql, ce.expression)
|
|
372
|
+
end
|
|
373
|
+
w = CASE_WHEN
|
|
374
|
+
t = CASE_THEN
|
|
375
|
+
ce.conditions.each do |c,r|
|
|
376
|
+
sql << w
|
|
377
|
+
literal_append(sql, c)
|
|
378
|
+
sql << t
|
|
379
|
+
literal_append(sql, r)
|
|
380
|
+
end
|
|
381
|
+
sql << CASE_ELSE
|
|
382
|
+
literal_append(sql, ce.default)
|
|
383
|
+
sql << CASE_END
|
|
226
384
|
end
|
|
227
385
|
|
|
228
386
|
# SQL fragment for the SQL CAST expression
|
|
229
|
-
def
|
|
230
|
-
|
|
387
|
+
def cast_sql_append(sql, expr, type)
|
|
388
|
+
sql << CAST_OPEN
|
|
389
|
+
literal_append(sql, expr)
|
|
390
|
+
sql << AS << db.cast_type_literal(type).to_s
|
|
391
|
+
sql << PAREN_CLOSE
|
|
231
392
|
end
|
|
232
393
|
|
|
233
394
|
# SQL fragment for specifying all columns in a given table
|
|
234
|
-
def
|
|
235
|
-
|
|
395
|
+
def column_all_sql_append(sql, ca)
|
|
396
|
+
qualified_identifier_sql_append(sql, ca.table, WILDCARD)
|
|
236
397
|
end
|
|
237
398
|
|
|
238
|
-
# SQL fragment for complex
|
|
239
|
-
def
|
|
399
|
+
# SQL fragment for the complex expression.
|
|
400
|
+
def complex_expression_sql_append(sql, op, args)
|
|
240
401
|
case op
|
|
241
402
|
when *IS_OPERATORS
|
|
242
403
|
r = args.at(1)
|
|
243
404
|
if r.nil? || supports_is_true?
|
|
244
405
|
raise(InvalidOperation, 'Invalid argument used for IS operator') unless v = IS_LITERALS[r]
|
|
245
|
-
|
|
406
|
+
sql << PAREN_OPEN
|
|
407
|
+
literal_append(sql, args.at(0))
|
|
408
|
+
sql << SPACE << op.to_s << SPACE
|
|
409
|
+
sql << v << PAREN_CLOSE
|
|
246
410
|
elsif op == :IS
|
|
247
|
-
|
|
411
|
+
complex_expression_sql_append(sql, :"=", args)
|
|
248
412
|
else
|
|
249
|
-
|
|
413
|
+
complex_expression_sql_append(sql, :OR, [SQL::BooleanExpression.new(:"!=", *args), SQL::BooleanExpression.new(:IS, args.at(0), nil)])
|
|
250
414
|
end
|
|
251
415
|
when :IN, :"NOT IN"
|
|
252
416
|
cols = args.at(0)
|
|
@@ -256,147 +420,208 @@ module Sequel
|
|
|
256
420
|
val_array = true
|
|
257
421
|
empty_val_array = vals == []
|
|
258
422
|
end
|
|
259
|
-
if
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
else
|
|
264
|
-
literal(1=>1)
|
|
265
|
-
end
|
|
266
|
-
elsif !supports_multiple_column_in?
|
|
423
|
+
if empty_val_array
|
|
424
|
+
literal_append(sql, empty_array_value(op, cols))
|
|
425
|
+
elsif col_array
|
|
426
|
+
if !supports_multiple_column_in?
|
|
267
427
|
if val_array
|
|
268
428
|
expr = SQL::BooleanExpression.new(:OR, *vals.to_a.map{|vs| SQL::BooleanExpression.from_value_pairs(cols.to_a.zip(vs).map{|c, v| [c, v]})})
|
|
269
|
-
|
|
429
|
+
literal_append(sql, op == :IN ? expr : ~expr)
|
|
270
430
|
else
|
|
271
431
|
old_vals = vals
|
|
432
|
+
vals = vals.naked if vals.is_a?(Sequel::Dataset)
|
|
272
433
|
vals = vals.to_a
|
|
273
434
|
val_cols = old_vals.columns
|
|
274
|
-
|
|
435
|
+
complex_expression_sql_append(sql, op, [cols, vals.map!{|x| x.values_at(*val_cols)}])
|
|
275
436
|
end
|
|
276
437
|
else
|
|
277
438
|
# If the columns and values are both arrays, use array_sql instead of
|
|
278
439
|
# literal so that if values is an array of two element arrays, it
|
|
279
440
|
# will be treated as a value list instead of a condition specifier.
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
literal(SQL::BooleanExpression.from_value_pairs([[cols, cols]], :AND, true))
|
|
441
|
+
sql << PAREN_OPEN
|
|
442
|
+
literal_append(sql, cols)
|
|
443
|
+
sql << SPACE << op.to_s << SPACE
|
|
444
|
+
if val_array
|
|
445
|
+
array_sql_append(sql, vals)
|
|
286
446
|
else
|
|
287
|
-
|
|
447
|
+
literal_append(sql, vals)
|
|
288
448
|
end
|
|
289
|
-
|
|
290
|
-
"(#{literal(cols)} #{op} #{literal(vals)})"
|
|
449
|
+
sql << PAREN_CLOSE
|
|
291
450
|
end
|
|
451
|
+
else
|
|
452
|
+
sql << PAREN_OPEN
|
|
453
|
+
literal_append(sql, cols)
|
|
454
|
+
sql << SPACE << op.to_s << SPACE
|
|
455
|
+
literal_append(sql, vals)
|
|
456
|
+
sql << PAREN_CLOSE
|
|
292
457
|
end
|
|
293
458
|
when *TWO_ARITY_OPERATORS
|
|
294
|
-
|
|
459
|
+
sql << PAREN_OPEN
|
|
460
|
+
literal_append(sql, args.at(0))
|
|
461
|
+
sql << SPACE << op.to_s << SPACE
|
|
462
|
+
literal_append(sql, args.at(1))
|
|
463
|
+
sql << PAREN_CLOSE
|
|
295
464
|
when *N_ARITY_OPERATORS
|
|
296
|
-
|
|
465
|
+
sql << PAREN_OPEN
|
|
466
|
+
c = false
|
|
467
|
+
op_str = " #{op} "
|
|
468
|
+
args.each do |a|
|
|
469
|
+
sql << op_str if c
|
|
470
|
+
literal_append(sql, a)
|
|
471
|
+
c ||= true
|
|
472
|
+
end
|
|
473
|
+
sql << PAREN_CLOSE
|
|
297
474
|
when :NOT
|
|
298
|
-
|
|
475
|
+
sql << NOT_SPACE
|
|
476
|
+
literal_append(sql, args.at(0))
|
|
299
477
|
when :NOOP
|
|
300
|
-
|
|
478
|
+
literal_append(sql, args.at(0))
|
|
301
479
|
when :'B~'
|
|
302
|
-
|
|
480
|
+
sql << TILDE
|
|
481
|
+
literal_append(sql, args.at(0))
|
|
482
|
+
when :extract
|
|
483
|
+
sql << EXTRACT << args.at(0).to_s << FROM
|
|
484
|
+
literal_append(sql, args.at(1))
|
|
485
|
+
sql << PAREN_CLOSE
|
|
303
486
|
else
|
|
304
487
|
raise(InvalidOperation, "invalid operator #{op}")
|
|
305
488
|
end
|
|
306
489
|
end
|
|
307
490
|
|
|
308
491
|
# SQL fragment for constants
|
|
309
|
-
def
|
|
310
|
-
constant.to_s
|
|
492
|
+
def constant_sql_append(sql, constant)
|
|
493
|
+
sql << constant.to_s
|
|
311
494
|
end
|
|
312
495
|
|
|
313
496
|
# SQL fragment specifying an SQL function call
|
|
314
|
-
def
|
|
497
|
+
def function_sql_append(sql, f)
|
|
498
|
+
sql << f.f.to_s
|
|
315
499
|
args = f.args
|
|
316
|
-
|
|
500
|
+
if args.empty?
|
|
501
|
+
sql << FUNCTION_EMPTY
|
|
502
|
+
else
|
|
503
|
+
literal_append(sql, args)
|
|
504
|
+
end
|
|
317
505
|
end
|
|
318
506
|
|
|
319
507
|
# SQL fragment specifying a JOIN clause without ON or USING.
|
|
320
|
-
def
|
|
508
|
+
def join_clause_sql_append(sql, jc)
|
|
321
509
|
table = jc.table
|
|
322
510
|
table_alias = jc.table_alias
|
|
323
511
|
table_alias = nil if table == table_alias
|
|
324
|
-
|
|
325
|
-
|
|
512
|
+
sql << SPACE << join_type_sql(jc.join_type) << SPACE
|
|
513
|
+
identifier_append(sql, table)
|
|
514
|
+
as_sql_append(sql, table_alias) if table_alias
|
|
326
515
|
end
|
|
327
516
|
|
|
328
517
|
# SQL fragment specifying a JOIN clause with ON.
|
|
329
|
-
def
|
|
330
|
-
|
|
518
|
+
def join_on_clause_sql_append(sql, jc)
|
|
519
|
+
join_clause_sql_append(sql, jc)
|
|
520
|
+
sql << ON
|
|
521
|
+
literal_append(sql, filter_expr(jc.on))
|
|
331
522
|
end
|
|
332
523
|
|
|
333
524
|
# SQL fragment specifying a JOIN clause with USING.
|
|
334
|
-
def
|
|
335
|
-
|
|
525
|
+
def join_using_clause_sql_append(sql, jc)
|
|
526
|
+
join_clause_sql_append(sql, jc)
|
|
527
|
+
sql << USING
|
|
528
|
+
column_list_append(sql, jc.using)
|
|
529
|
+
sql << PAREN_CLOSE
|
|
336
530
|
end
|
|
337
531
|
|
|
338
532
|
# SQL fragment for NegativeBooleanConstants
|
|
339
|
-
def
|
|
340
|
-
|
|
533
|
+
def negative_boolean_constant_sql_append(sql, constant)
|
|
534
|
+
sql << NOT_SPACE
|
|
535
|
+
boolean_constant_sql_append(sql, constant)
|
|
341
536
|
end
|
|
342
537
|
|
|
343
538
|
# SQL fragment for the ordered expression, used in the ORDER BY
|
|
344
539
|
# clause.
|
|
345
|
-
def
|
|
346
|
-
|
|
540
|
+
def ordered_expression_sql_append(sql, oe)
|
|
541
|
+
literal_append(sql, oe.expression)
|
|
542
|
+
sql << (oe.descending ? DESC : ASC)
|
|
347
543
|
case oe.nulls
|
|
348
544
|
when :first
|
|
349
|
-
|
|
545
|
+
sql << NULLS_FIRST
|
|
350
546
|
when :last
|
|
351
|
-
|
|
352
|
-
else
|
|
353
|
-
s
|
|
547
|
+
sql << NULLS_LAST
|
|
354
548
|
end
|
|
355
549
|
end
|
|
356
550
|
|
|
357
551
|
# SQL fragment for a literal string with placeholders
|
|
358
|
-
def
|
|
552
|
+
def placeholder_literal_string_sql_append(sql, pls)
|
|
359
553
|
args = pls.args
|
|
360
|
-
|
|
554
|
+
str = pls.str
|
|
555
|
+
sql << PAREN_OPEN if pls.parens
|
|
556
|
+
if args.is_a?(Hash)
|
|
361
557
|
re = /:(#{args.keys.map{|k| Regexp.escape(k.to_s)}.join('|')})\b/
|
|
362
|
-
|
|
558
|
+
loop do
|
|
559
|
+
previous, q, str = str.partition(re)
|
|
560
|
+
sql << previous
|
|
561
|
+
literal_append(sql, args[($1||q[1..-1].to_s).to_sym]) unless q.empty?
|
|
562
|
+
break if str.empty?
|
|
563
|
+
end
|
|
564
|
+
elsif str.is_a?(Array)
|
|
565
|
+
len = args.length
|
|
566
|
+
str.each_with_index do |s, i|
|
|
567
|
+
sql << s
|
|
568
|
+
literal_append(sql, args[i]) unless i == len
|
|
569
|
+
end
|
|
363
570
|
else
|
|
364
571
|
i = -1
|
|
365
|
-
|
|
572
|
+
loop do
|
|
573
|
+
previous, q, str = str.partition(QUESTION_MARK)
|
|
574
|
+
sql << previous
|
|
575
|
+
literal_append(sql, args.at(i+=1)) unless q.empty?
|
|
576
|
+
break if str.empty?
|
|
577
|
+
end
|
|
366
578
|
end
|
|
367
|
-
|
|
368
|
-
s
|
|
579
|
+
sql << PAREN_CLOSE if pls.parens
|
|
369
580
|
end
|
|
370
581
|
|
|
371
582
|
# SQL fragment for the qualifed identifier, specifying
|
|
372
583
|
# a table and a column (or schema and table).
|
|
373
|
-
|
|
374
|
-
|
|
584
|
+
# If 3 arguments are given, the 2nd should be the table/qualifier and the third should be
|
|
585
|
+
# column/qualified. If 2 arguments are given, the 2nd should be an SQL::QualifiedIdentifier.
|
|
586
|
+
def qualified_identifier_sql_append(sql, table, column=(c = table.column; table = table.table; c))
|
|
587
|
+
identifier_append(sql, table)
|
|
588
|
+
sql << DOT
|
|
589
|
+
identifier_append(sql, column)
|
|
375
590
|
end
|
|
376
591
|
|
|
377
592
|
# Adds quoting to identifiers (columns and tables). If identifiers are not
|
|
378
593
|
# being quoted, returns name as a string. If identifiers are being quoted
|
|
379
594
|
# quote the name with quoted_identifier.
|
|
380
|
-
def
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
595
|
+
def quote_identifier_append(sql, name)
|
|
596
|
+
if name.is_a?(LiteralString)
|
|
597
|
+
sql << name
|
|
598
|
+
else
|
|
599
|
+
name = name.value if name.is_a?(SQL::Identifier)
|
|
600
|
+
name = input_identifier(name)
|
|
601
|
+
if quote_identifiers?
|
|
602
|
+
quoted_identifier_append(sql, name)
|
|
603
|
+
else
|
|
604
|
+
sql << name
|
|
605
|
+
end
|
|
606
|
+
end
|
|
386
607
|
end
|
|
387
608
|
|
|
388
609
|
# Separates the schema from the table and returns a string with them
|
|
389
610
|
# quoted (if quoting identifiers)
|
|
390
|
-
def
|
|
611
|
+
def quote_schema_table_append(sql, table)
|
|
391
612
|
schema, table = schema_and_table(table)
|
|
392
|
-
|
|
613
|
+
if schema
|
|
614
|
+
quote_identifier_append(sql, schema)
|
|
615
|
+
sql << DOT
|
|
616
|
+
end
|
|
617
|
+
quote_identifier_append(sql, table)
|
|
393
618
|
end
|
|
394
619
|
|
|
395
620
|
# This method quotes the given name with the SQL standard double quote.
|
|
396
621
|
# should be overridden by subclasses to provide quoting not matching the
|
|
397
622
|
# SQL standard, such as backtick (used by MySQL and SQLite).
|
|
398
|
-
def
|
|
399
|
-
|
|
623
|
+
def quoted_identifier_append(sql, name)
|
|
624
|
+
sql << QUOTE << name.to_s.gsub(QUOTE_RE, DOUBLE_QUOTE) << QUOTE
|
|
400
625
|
end
|
|
401
626
|
|
|
402
627
|
# Split the schema information from the table
|
|
@@ -418,34 +643,59 @@ module Sequel
|
|
|
418
643
|
end
|
|
419
644
|
|
|
420
645
|
# SQL fragment for specifying subscripts (SQL array accesses)
|
|
421
|
-
def
|
|
422
|
-
|
|
646
|
+
def subscript_sql_append(sql, s)
|
|
647
|
+
literal_append(sql, s.f)
|
|
648
|
+
sql << BRACKET_OPEN
|
|
649
|
+
expression_list_append(sql, s.sub)
|
|
650
|
+
sql << BRACKET_CLOSE
|
|
423
651
|
end
|
|
424
652
|
|
|
425
653
|
# The SQL fragment for the given window's options.
|
|
426
|
-
def
|
|
654
|
+
def window_sql_append(sql, opts)
|
|
427
655
|
raise(Error, 'This dataset does not support window functions') unless supports_window_functions?
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
656
|
+
sql << PAREN_OPEN
|
|
657
|
+
window, part, order, frame = opts.values_at(:window, :partition, :order, :frame)
|
|
658
|
+
space = false
|
|
659
|
+
space_s = SPACE
|
|
660
|
+
if window
|
|
661
|
+
literal_append(sql, window)
|
|
662
|
+
space = true
|
|
663
|
+
end
|
|
664
|
+
if part
|
|
665
|
+
sql << space_s if space
|
|
666
|
+
sql << PARTITION_BY
|
|
667
|
+
expression_list_append(sql, Array(part))
|
|
668
|
+
space = true
|
|
669
|
+
end
|
|
670
|
+
if order
|
|
671
|
+
sql << space_s if space
|
|
672
|
+
sql << ORDER_BY_NS
|
|
673
|
+
expression_list_append(sql, Array(order))
|
|
674
|
+
space = true
|
|
675
|
+
end
|
|
676
|
+
case frame
|
|
432
677
|
when nil
|
|
433
|
-
|
|
678
|
+
# nothing
|
|
434
679
|
when :all
|
|
435
|
-
|
|
680
|
+
sql << space_s if space
|
|
681
|
+
sql << FRAME_ALL
|
|
436
682
|
when :rows
|
|
437
|
-
|
|
683
|
+
sql << space_s if space
|
|
684
|
+
sql << FRAME_ROWS
|
|
438
685
|
when String
|
|
439
|
-
|
|
686
|
+
sql << space_s if space
|
|
687
|
+
sql << frame
|
|
440
688
|
else
|
|
441
689
|
raise Error, "invalid window frame clause, should be :all, :rows, a string, or nil"
|
|
442
690
|
end
|
|
443
|
-
|
|
691
|
+
sql << PAREN_CLOSE
|
|
444
692
|
end
|
|
445
693
|
|
|
446
694
|
# The SQL fragment for the given window function's function and window.
|
|
447
|
-
def
|
|
448
|
-
|
|
695
|
+
def window_function_sql_append(sql, function, window)
|
|
696
|
+
literal_append(sql, function)
|
|
697
|
+
sql << OVER
|
|
698
|
+
literal_append(sql, window)
|
|
449
699
|
end
|
|
450
700
|
|
|
451
701
|
protected
|
|
@@ -517,14 +767,20 @@ module Sequel
|
|
|
517
767
|
options_overlap(COUNT_FROM_SELF_OPTS) ? from_self : unordered
|
|
518
768
|
end
|
|
519
769
|
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
770
|
+
def argument_list_append(sql, args)
|
|
771
|
+
c = false
|
|
772
|
+
comma = COMMA
|
|
773
|
+
args.each do |a|
|
|
774
|
+
sql << comma if c
|
|
775
|
+
sql << a.to_s
|
|
776
|
+
c ||= true
|
|
777
|
+
end
|
|
523
778
|
end
|
|
524
779
|
|
|
525
780
|
# SQL fragment for specifying an alias. expression should already be literalized.
|
|
526
|
-
def
|
|
527
|
-
|
|
781
|
+
def as_sql_append(sql, aliaz)
|
|
782
|
+
sql << AS
|
|
783
|
+
quote_identifier_append(sql, aliaz)
|
|
528
784
|
end
|
|
529
785
|
|
|
530
786
|
# Raise an InvalidOperation exception if deletion is not allowed
|
|
@@ -534,38 +790,88 @@ module Sequel
|
|
|
534
790
|
raise(InvalidOperation, "Joined datasets cannot be modified") if !supports_modifying_joins? && joined_dataset?
|
|
535
791
|
end
|
|
536
792
|
|
|
793
|
+
# Alias of check_modification_allowed!
|
|
794
|
+
def check_truncation_allowed!
|
|
795
|
+
check_modification_allowed!
|
|
796
|
+
end
|
|
797
|
+
|
|
537
798
|
# Prepare an SQL statement by calling all clause methods for the given statement type.
|
|
538
799
|
def clause_sql(type)
|
|
539
|
-
sql =
|
|
800
|
+
sql = @opts[:append_sql] || sql_string_origin
|
|
540
801
|
send("#{type}_clause_methods").each{|x| send(x, sql)}
|
|
541
802
|
sql
|
|
542
803
|
end
|
|
543
804
|
|
|
544
805
|
# Converts an array of column names into a comma seperated string of
|
|
545
806
|
# column names. If the array is empty, a wildcard (*) is returned.
|
|
546
|
-
def
|
|
547
|
-
(columns.nil? || columns.empty?)
|
|
807
|
+
def column_list_append(sql, columns)
|
|
808
|
+
if (columns.nil? || columns.empty?)
|
|
809
|
+
sql << WILDCARD
|
|
810
|
+
else
|
|
811
|
+
expression_list_append(sql, columns)
|
|
812
|
+
end
|
|
548
813
|
end
|
|
549
|
-
|
|
814
|
+
|
|
815
|
+
# Yield each two pair of arguments to the block, which should
|
|
816
|
+
# return a string representing the SQL code for those
|
|
817
|
+
# two arguments. If more than 2 arguments are provided, all
|
|
818
|
+
# calls to the block # after the first will have a LiteralString
|
|
819
|
+
# as the first argument, representing the application of the block to
|
|
820
|
+
# the previous arguments.
|
|
821
|
+
def complex_expression_arg_pairs(args)
|
|
822
|
+
case args.length
|
|
823
|
+
when 1
|
|
824
|
+
literal(args.at(0))
|
|
825
|
+
when 2
|
|
826
|
+
yield args.at(0), args.at(1)
|
|
827
|
+
else
|
|
828
|
+
args.inject{|m, a| LiteralString.new(yield(m, a))}
|
|
829
|
+
end
|
|
830
|
+
end
|
|
831
|
+
|
|
832
|
+
# The SQL to use for the dataset used in a UNION/INTERSECT/EXCEPT clause.
|
|
833
|
+
def compound_dataset_sql_append(sql, ds)
|
|
834
|
+
subselect_sql_append(sql, ds)
|
|
835
|
+
end
|
|
836
|
+
|
|
550
837
|
# The alias to use for datasets, takes a number to make sure the name is unique.
|
|
551
838
|
def dataset_alias(number)
|
|
552
839
|
:"#{DATASET_ALIAS_BASE_NAME}#{number}"
|
|
553
840
|
end
|
|
554
841
|
|
|
842
|
+
# The strftime format to use when literalizing the time.
|
|
843
|
+
def default_timestamp_format
|
|
844
|
+
requires_sql_standard_datetimes? ? STANDARD_TIMESTAMP_FORMAT : TIMESTAMP_FORMAT
|
|
845
|
+
end
|
|
846
|
+
|
|
555
847
|
# The order of methods to call to build the DELETE SQL statement
|
|
556
848
|
def delete_clause_methods
|
|
557
849
|
DELETE_CLAUSE_METHODS
|
|
558
850
|
end
|
|
559
851
|
|
|
852
|
+
def delete_delete_sql(sql)
|
|
853
|
+
sql << DELETE
|
|
854
|
+
end
|
|
855
|
+
|
|
560
856
|
# Converts an array of expressions into a comma separated string of
|
|
561
857
|
# expressions.
|
|
562
|
-
def
|
|
563
|
-
|
|
858
|
+
def expression_list_append(sql, columns)
|
|
859
|
+
c = false
|
|
860
|
+
co = COMMA
|
|
861
|
+
columns.each do |col|
|
|
862
|
+
sql << co if c
|
|
863
|
+
literal_append(sql, col)
|
|
864
|
+
c ||= true
|
|
865
|
+
end
|
|
564
866
|
end
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
867
|
+
|
|
868
|
+
def empty_array_value(op, cols)
|
|
869
|
+
if Sequel.empty_array_handle_nulls
|
|
870
|
+
c = Array(cols)
|
|
871
|
+
SQL::BooleanExpression.from_value_pairs(c.zip(c), :AND, op == :IN)
|
|
872
|
+
else
|
|
873
|
+
{1 => ((op == :IN) ? 0 : 1)}
|
|
874
|
+
end
|
|
569
875
|
end
|
|
570
876
|
|
|
571
877
|
# Format the timestamp based on the default_timestamp_format, with a couple
|
|
@@ -573,10 +879,10 @@ module Sequel
|
|
|
573
879
|
# database supports them), and override %z to always use a numeric offset
|
|
574
880
|
# of hours and minutes.
|
|
575
881
|
def format_timestamp(v)
|
|
576
|
-
v2 =
|
|
577
|
-
fmt = default_timestamp_format.gsub(
|
|
578
|
-
if m ==
|
|
579
|
-
format_timestamp_usec(v.is_a?(DateTime) ? v.sec_fraction*(RUBY_VERSION <
|
|
882
|
+
v2 = db.from_application_timestamp(v)
|
|
883
|
+
fmt = default_timestamp_format.gsub(FORMAT_TIMESTAMP_RE) do |m|
|
|
884
|
+
if m == FORMAT_USEC
|
|
885
|
+
format_timestamp_usec(v.is_a?(DateTime) ? v.sec_fraction*(RUBY_VERSION < V190 ? 86400000000 : 1000000) : v.usec) if supports_timestamp_usecs?
|
|
580
886
|
else
|
|
581
887
|
if supports_timestamp_timezones?
|
|
582
888
|
# Would like to just use %z format, but it doesn't appear to work on Windows
|
|
@@ -591,15 +897,33 @@ module Sequel
|
|
|
591
897
|
|
|
592
898
|
# Return the SQL timestamp fragment to use for the timezone offset.
|
|
593
899
|
def format_timestamp_offset(hour, minute)
|
|
594
|
-
sprintf(
|
|
900
|
+
sprintf(FORMAT_OFFSET, hour, minute)
|
|
595
901
|
end
|
|
596
902
|
|
|
597
903
|
# Return the SQL timestamp fragment to use for the fractional time part.
|
|
598
904
|
# Should start with the decimal point. Uses 6 decimal places by default.
|
|
599
905
|
def format_timestamp_usec(usec)
|
|
600
|
-
sprintf(
|
|
906
|
+
sprintf(FORMAT_TIMESTAMP_USEC, usec)
|
|
907
|
+
end
|
|
908
|
+
|
|
909
|
+
# Append the value, but special case regular (non-literal, non-blob) strings
|
|
910
|
+
# so that they are considered as identifiers and not SQL strings.
|
|
911
|
+
def identifier_append(sql, v)
|
|
912
|
+
if v.is_a?(String)
|
|
913
|
+
case v
|
|
914
|
+
when LiteralString
|
|
915
|
+
sql << v
|
|
916
|
+
when SQL::Blob
|
|
917
|
+
literal_append(sql, v)
|
|
918
|
+
else
|
|
919
|
+
quote_identifier_append(sql, v)
|
|
920
|
+
end
|
|
921
|
+
else
|
|
922
|
+
literal_append(sql, v)
|
|
923
|
+
end
|
|
601
924
|
end
|
|
602
|
-
|
|
925
|
+
alias table_ref_append identifier_append
|
|
926
|
+
|
|
603
927
|
# Modify the identifier returned from the database based on the
|
|
604
928
|
# identifier_output_method.
|
|
605
929
|
def input_identifier(v)
|
|
@@ -608,7 +932,8 @@ module Sequel
|
|
|
608
932
|
|
|
609
933
|
# SQL fragment specifying the table to insert INTO
|
|
610
934
|
def insert_into_sql(sql)
|
|
611
|
-
sql <<
|
|
935
|
+
sql << INTO
|
|
936
|
+
source_list_append(sql, @opts[:from])
|
|
612
937
|
end
|
|
613
938
|
|
|
614
939
|
# The order of methods to call to build the INSERT SQL statement
|
|
@@ -619,27 +944,57 @@ module Sequel
|
|
|
619
944
|
# SQL fragment specifying the columns to insert into
|
|
620
945
|
def insert_columns_sql(sql)
|
|
621
946
|
columns = opts[:columns]
|
|
622
|
-
|
|
947
|
+
if columns && !columns.empty?
|
|
948
|
+
sql << PAREN_SPACE_OPEN
|
|
949
|
+
c = false
|
|
950
|
+
co = COMMA
|
|
951
|
+
columns.each do |col|
|
|
952
|
+
sql << co if c
|
|
953
|
+
identifier_append(sql, col)
|
|
954
|
+
c ||= true
|
|
955
|
+
end
|
|
956
|
+
sql << PAREN_CLOSE
|
|
957
|
+
end
|
|
958
|
+
end
|
|
959
|
+
|
|
960
|
+
def insert_insert_sql(sql)
|
|
961
|
+
sql << INSERT
|
|
623
962
|
end
|
|
624
963
|
|
|
625
964
|
# SQL fragment specifying the values to insert.
|
|
626
965
|
def insert_values_sql(sql)
|
|
627
966
|
case values = opts[:values]
|
|
628
967
|
when Array
|
|
629
|
-
|
|
968
|
+
if values.empty?
|
|
969
|
+
sql << DEFAULT_VALUES
|
|
970
|
+
else
|
|
971
|
+
sql << VALUES
|
|
972
|
+
literal_append(sql, values)
|
|
973
|
+
end
|
|
630
974
|
when Dataset
|
|
631
|
-
sql <<
|
|
975
|
+
sql << SPACE
|
|
976
|
+
subselect_sql_append(sql, values)
|
|
632
977
|
when LiteralString
|
|
633
|
-
sql <<
|
|
978
|
+
sql << SPACE << values
|
|
634
979
|
else
|
|
635
980
|
raise Error, "Unsupported INSERT values type, should be an Array or Dataset: #{values.inspect}"
|
|
636
981
|
end
|
|
637
982
|
end
|
|
638
983
|
|
|
984
|
+
# SQL fragment specifying the values to return.
|
|
985
|
+
def insert_returning_sql(sql)
|
|
986
|
+
if opts.has_key?(:returning)
|
|
987
|
+
sql << RETURNING
|
|
988
|
+
column_list_append(sql, Array(opts[:returning]))
|
|
989
|
+
end
|
|
990
|
+
end
|
|
991
|
+
alias delete_returning_sql insert_returning_sql
|
|
992
|
+
alias update_returning_sql insert_returning_sql
|
|
993
|
+
|
|
639
994
|
# SQL fragment specifying a JOIN type, converts underscores to
|
|
640
995
|
# spaces and upcases.
|
|
641
996
|
def join_type_sql(join_type)
|
|
642
|
-
"#{join_type.to_s.gsub(
|
|
997
|
+
"#{join_type.to_s.gsub(UNDERSCORE, SPACE).upcase} JOIN"
|
|
643
998
|
end
|
|
644
999
|
|
|
645
1000
|
# Whether this dataset is a joined dataset
|
|
@@ -648,8 +1003,12 @@ module Sequel
|
|
|
648
1003
|
end
|
|
649
1004
|
|
|
650
1005
|
# SQL fragment for Array. Treats as an expression if an array of all two pairs, or as a SQL array otherwise.
|
|
651
|
-
def
|
|
652
|
-
Sequel.condition_specifier?(v)
|
|
1006
|
+
def literal_array_append(sql, v)
|
|
1007
|
+
if Sequel.condition_specifier?(v)
|
|
1008
|
+
literal_expression_append(sql, SQL::BooleanExpression.from_value_pairs(v))
|
|
1009
|
+
else
|
|
1010
|
+
array_sql_append(sql, v)
|
|
1011
|
+
end
|
|
653
1012
|
end
|
|
654
1013
|
|
|
655
1014
|
# SQL fragment for BigDecimal
|
|
@@ -659,18 +1018,24 @@ module Sequel
|
|
|
659
1018
|
end
|
|
660
1019
|
|
|
661
1020
|
# SQL fragment for SQL::Blob
|
|
662
|
-
def
|
|
663
|
-
|
|
1021
|
+
def literal_blob_append(sql, v)
|
|
1022
|
+
literal_string_append(sql, v)
|
|
664
1023
|
end
|
|
665
1024
|
|
|
666
1025
|
# SQL fragment for Dataset. Does a subselect inside parantheses.
|
|
667
|
-
def
|
|
668
|
-
|
|
1026
|
+
def literal_dataset_append(sql, v)
|
|
1027
|
+
sql << PAREN_OPEN
|
|
1028
|
+
subselect_sql_append(sql, v)
|
|
1029
|
+
sql << PAREN_CLOSE
|
|
669
1030
|
end
|
|
670
1031
|
|
|
671
1032
|
# SQL fragment for Date, using the ISO8601 format.
|
|
672
1033
|
def literal_date(v)
|
|
673
|
-
|
|
1034
|
+
if requires_sql_standard_datetimes?
|
|
1035
|
+
v.strftime(FORMAT_DATE_STANDARD)
|
|
1036
|
+
else
|
|
1037
|
+
v.strftime(FORMAT_DATE)
|
|
1038
|
+
end
|
|
674
1039
|
end
|
|
675
1040
|
|
|
676
1041
|
# SQL fragment for DateTime
|
|
@@ -679,8 +1044,8 @@ module Sequel
|
|
|
679
1044
|
end
|
|
680
1045
|
|
|
681
1046
|
# SQL fragment for SQL::Expression, result depends on the specific type of expression.
|
|
682
|
-
def
|
|
683
|
-
v.
|
|
1047
|
+
def literal_expression_append(sql, v)
|
|
1048
|
+
v.to_s_append(self, sql)
|
|
684
1049
|
end
|
|
685
1050
|
|
|
686
1051
|
# SQL fragment for false
|
|
@@ -694,15 +1059,15 @@ module Sequel
|
|
|
694
1059
|
end
|
|
695
1060
|
|
|
696
1061
|
# SQL fragment for Hash, treated as an expression
|
|
697
|
-
def
|
|
698
|
-
|
|
1062
|
+
def literal_hash_append(sql, v)
|
|
1063
|
+
literal_expression_append(sql, SQL::BooleanExpression.from_value_pairs(v))
|
|
699
1064
|
end
|
|
700
1065
|
|
|
701
1066
|
# SQL fragment for Integer
|
|
702
1067
|
def literal_integer(v)
|
|
703
1068
|
v.to_s
|
|
704
1069
|
end
|
|
705
|
-
|
|
1070
|
+
|
|
706
1071
|
# SQL fragment for nil
|
|
707
1072
|
def literal_nil
|
|
708
1073
|
NULL
|
|
@@ -714,17 +1079,24 @@ module Sequel
|
|
|
714
1079
|
# provided and should add that method to Sequel::Dataset, allowing for adapters
|
|
715
1080
|
# to provide customized literalizations.
|
|
716
1081
|
# If a database specific type is allowed, this should be overriden in a subclass.
|
|
717
|
-
def
|
|
718
|
-
if v.respond_to?(:
|
|
719
|
-
v.
|
|
1082
|
+
def literal_other_append(sql, v)
|
|
1083
|
+
if v.respond_to?(:sql_literal_append)
|
|
1084
|
+
v.sql_literal_append(self, sql)
|
|
1085
|
+
elsif v.respond_to?(:sql_literal)
|
|
1086
|
+
sql << v.sql_literal(self)
|
|
720
1087
|
else
|
|
721
1088
|
raise Error, "can't express #{v.inspect} as a SQL literal"
|
|
722
1089
|
end
|
|
723
1090
|
end
|
|
724
1091
|
|
|
1092
|
+
# SQL fragment for Sequel::SQLTime, containing just the time part
|
|
1093
|
+
def literal_sqltime(v)
|
|
1094
|
+
v.strftime("'%H:%M:%S#{format_timestamp_usec(v.usec) if supports_timestamp_usecs?}'")
|
|
1095
|
+
end
|
|
1096
|
+
|
|
725
1097
|
# SQL fragment for String. Doubles \ and ' by default.
|
|
726
|
-
def
|
|
727
|
-
|
|
1098
|
+
def literal_string_append(sql, v)
|
|
1099
|
+
sql << APOS << v.gsub(APOS_RE, DOUBLE_APOS) << APOS
|
|
728
1100
|
end
|
|
729
1101
|
|
|
730
1102
|
# Converts a symbol into a column name. This method supports underscore
|
|
@@ -735,10 +1107,14 @@ module Sequel
|
|
|
735
1107
|
# dataset.literal(:abc___a) #=> "abc AS a"
|
|
736
1108
|
# dataset.literal(:items__abc) #=> "items.abc"
|
|
737
1109
|
# dataset.literal(:items__abc___a) #=> "items.abc AS a"
|
|
738
|
-
def
|
|
1110
|
+
def literal_symbol_append(sql, v)
|
|
739
1111
|
c_table, column, c_alias = split_symbol(v)
|
|
740
|
-
|
|
741
|
-
|
|
1112
|
+
if c_table
|
|
1113
|
+
quote_identifier_append(sql, c_table)
|
|
1114
|
+
sql << DOT
|
|
1115
|
+
end
|
|
1116
|
+
quote_identifier_append(sql, column)
|
|
1117
|
+
as_sql_append(sql, c_alias) if c_alias
|
|
742
1118
|
end
|
|
743
1119
|
|
|
744
1120
|
# SQL fragment for Time
|
|
@@ -774,59 +1150,7 @@ module Sequel
|
|
|
774
1150
|
|
|
775
1151
|
# Qualify the given expression e to the given table.
|
|
776
1152
|
def qualified_expression(e, table)
|
|
777
|
-
|
|
778
|
-
when Symbol
|
|
779
|
-
t, column, aliaz = split_symbol(e)
|
|
780
|
-
if t
|
|
781
|
-
e
|
|
782
|
-
elsif aliaz
|
|
783
|
-
SQL::AliasedExpression.new(SQL::QualifiedIdentifier.new(table, SQL::Identifier.new(column)), aliaz)
|
|
784
|
-
else
|
|
785
|
-
SQL::QualifiedIdentifier.new(table, e)
|
|
786
|
-
end
|
|
787
|
-
when Array
|
|
788
|
-
e.map{|a| qualified_expression(a, table)}
|
|
789
|
-
when Hash
|
|
790
|
-
h = {}
|
|
791
|
-
e.each{|k,v| h[qualified_expression(k, table)] = qualified_expression(v, table)}
|
|
792
|
-
h
|
|
793
|
-
when SQL::Identifier
|
|
794
|
-
SQL::QualifiedIdentifier.new(table, e)
|
|
795
|
-
when SQL::OrderedExpression
|
|
796
|
-
SQL::OrderedExpression.new(qualified_expression(e.expression, table), e.descending, :nulls=>e.nulls)
|
|
797
|
-
when SQL::AliasedExpression
|
|
798
|
-
SQL::AliasedExpression.new(qualified_expression(e.expression, table), e.aliaz)
|
|
799
|
-
when SQL::CaseExpression
|
|
800
|
-
args = [qualified_expression(e.conditions, table), qualified_expression(e.default, table)]
|
|
801
|
-
args << qualified_expression(e.expression, table) if e.expression?
|
|
802
|
-
SQL::CaseExpression.new(*args)
|
|
803
|
-
when SQL::Cast
|
|
804
|
-
SQL::Cast.new(qualified_expression(e.expr, table), e.type)
|
|
805
|
-
when SQL::Function
|
|
806
|
-
SQL::Function.new(e.f, *qualified_expression(e.args, table))
|
|
807
|
-
when SQL::ComplexExpression
|
|
808
|
-
SQL::ComplexExpression.new(e.op, *qualified_expression(e.args, table))
|
|
809
|
-
when SQL::Subscript
|
|
810
|
-
SQL::Subscript.new(qualified_expression(e.f, table), qualified_expression(e.sub, table))
|
|
811
|
-
when SQL::WindowFunction
|
|
812
|
-
SQL::WindowFunction.new(qualified_expression(e.function, table), qualified_expression(e.window, table))
|
|
813
|
-
when SQL::Window
|
|
814
|
-
o = e.opts.dup
|
|
815
|
-
o[:partition] = qualified_expression(o[:partition], table) if o[:partition]
|
|
816
|
-
o[:order] = qualified_expression(o[:order], table) if o[:order]
|
|
817
|
-
SQL::Window.new(o)
|
|
818
|
-
when SQL::PlaceholderLiteralString
|
|
819
|
-
args = if e.args.is_a?(Hash)
|
|
820
|
-
h = {}
|
|
821
|
-
e.args.each{|k,v| h[k] = qualified_expression(v, table)}
|
|
822
|
-
h
|
|
823
|
-
else
|
|
824
|
-
qualified_expression(e.args, table)
|
|
825
|
-
end
|
|
826
|
-
SQL::PlaceholderLiteralString.new(e.str, args, e.parens)
|
|
827
|
-
else
|
|
828
|
-
e
|
|
829
|
-
end
|
|
1153
|
+
Qualifier.new(self, table).transform(e)
|
|
830
1154
|
end
|
|
831
1155
|
|
|
832
1156
|
# The order of methods to call to build the SELECT SQL statement
|
|
@@ -836,13 +1160,19 @@ module Sequel
|
|
|
836
1160
|
|
|
837
1161
|
# Modify the sql to add the columns selected
|
|
838
1162
|
def select_columns_sql(sql)
|
|
839
|
-
sql <<
|
|
1163
|
+
sql << SPACE
|
|
1164
|
+
column_list_append(sql, @opts[:select])
|
|
840
1165
|
end
|
|
841
1166
|
|
|
842
1167
|
# Modify the sql to add the DISTINCT modifier
|
|
843
1168
|
def select_distinct_sql(sql)
|
|
844
1169
|
if distinct = @opts[:distinct]
|
|
845
|
-
sql <<
|
|
1170
|
+
sql << DISTINCT
|
|
1171
|
+
unless distinct.empty?
|
|
1172
|
+
sql << ON_PAREN
|
|
1173
|
+
expression_list_append(sql, distinct)
|
|
1174
|
+
sql << PAREN_CLOSE
|
|
1175
|
+
end
|
|
846
1176
|
end
|
|
847
1177
|
end
|
|
848
1178
|
|
|
@@ -850,60 +1180,100 @@ module Sequel
|
|
|
850
1180
|
# This uses a subselect for the compound datasets used, because using parantheses doesn't
|
|
851
1181
|
# work on all databases. I consider this an ugly hack, but can't I think of a better default.
|
|
852
1182
|
def select_compounds_sql(sql)
|
|
853
|
-
return unless @opts[:compounds]
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
sql <<
|
|
1183
|
+
return unless c = @opts[:compounds]
|
|
1184
|
+
c.each do |type, dataset, all|
|
|
1185
|
+
sql << SPACE << type.to_s.upcase
|
|
1186
|
+
sql << ALL if all
|
|
1187
|
+
sql << SPACE
|
|
1188
|
+
compound_dataset_sql_append(sql, dataset)
|
|
857
1189
|
end
|
|
858
1190
|
end
|
|
859
1191
|
|
|
860
1192
|
# Modify the sql to add the list of tables to select FROM
|
|
861
1193
|
def select_from_sql(sql)
|
|
862
|
-
|
|
1194
|
+
if f = @opts[:from]
|
|
1195
|
+
sql << FROM
|
|
1196
|
+
source_list_append(sql, f)
|
|
1197
|
+
end
|
|
863
1198
|
end
|
|
864
1199
|
alias delete_from_sql select_from_sql
|
|
865
1200
|
|
|
866
1201
|
# Modify the sql to add the expressions to GROUP BY
|
|
867
1202
|
def select_group_sql(sql)
|
|
868
|
-
|
|
1203
|
+
if group = @opts[:group]
|
|
1204
|
+
sql << GROUP_BY
|
|
1205
|
+
if go = @opts[:group_options]
|
|
1206
|
+
if uses_with_rollup?
|
|
1207
|
+
expression_list_append(sql, group)
|
|
1208
|
+
sql << SPACE_WITH << go.to_s.upcase
|
|
1209
|
+
else
|
|
1210
|
+
sql << go.to_s.upcase << PAREN_OPEN
|
|
1211
|
+
expression_list_append(sql, group)
|
|
1212
|
+
sql << PAREN_CLOSE
|
|
1213
|
+
end
|
|
1214
|
+
else
|
|
1215
|
+
expression_list_append(sql, group)
|
|
1216
|
+
end
|
|
1217
|
+
end
|
|
869
1218
|
end
|
|
870
1219
|
|
|
871
1220
|
# Modify the sql to add the filter criteria in the HAVING clause
|
|
872
1221
|
def select_having_sql(sql)
|
|
873
|
-
|
|
1222
|
+
if having = @opts[:having]
|
|
1223
|
+
sql << HAVING
|
|
1224
|
+
literal_append(sql, having)
|
|
1225
|
+
end
|
|
874
1226
|
end
|
|
875
1227
|
|
|
876
1228
|
# Modify the sql to add the list of tables to JOIN to
|
|
877
1229
|
def select_join_sql(sql)
|
|
878
|
-
|
|
1230
|
+
if js = @opts[:join]
|
|
1231
|
+
js.each{|j| literal_append(sql, j)}
|
|
1232
|
+
end
|
|
879
1233
|
end
|
|
880
1234
|
|
|
881
1235
|
# Modify the sql to limit the number of rows returned and offset
|
|
882
1236
|
def select_limit_sql(sql)
|
|
883
|
-
|
|
884
|
-
|
|
1237
|
+
if l = @opts[:limit]
|
|
1238
|
+
sql << LIMIT
|
|
1239
|
+
literal_append(sql, l)
|
|
1240
|
+
end
|
|
1241
|
+
if o = @opts[:offset]
|
|
1242
|
+
sql << OFFSET
|
|
1243
|
+
literal_append(sql, o)
|
|
1244
|
+
end
|
|
885
1245
|
end
|
|
886
1246
|
|
|
887
1247
|
# Modify the sql to support the different types of locking modes.
|
|
888
1248
|
def select_lock_sql(sql)
|
|
889
|
-
case @opts[:lock]
|
|
1249
|
+
case l = @opts[:lock]
|
|
890
1250
|
when :update
|
|
891
1251
|
sql << FOR_UPDATE
|
|
892
1252
|
when String
|
|
893
|
-
sql <<
|
|
1253
|
+
sql << SPACE << l
|
|
894
1254
|
end
|
|
895
1255
|
end
|
|
896
1256
|
|
|
897
1257
|
# Modify the sql to add the expressions to ORDER BY
|
|
898
1258
|
def select_order_sql(sql)
|
|
899
|
-
|
|
1259
|
+
if o = @opts[:order]
|
|
1260
|
+
sql << ORDER_BY
|
|
1261
|
+
expression_list_append(sql, o)
|
|
1262
|
+
end
|
|
900
1263
|
end
|
|
901
1264
|
alias delete_order_sql select_order_sql
|
|
902
1265
|
alias update_order_sql select_order_sql
|
|
903
1266
|
|
|
1267
|
+
def select_select_sql(sql)
|
|
1268
|
+
sql << SELECT
|
|
1269
|
+
end
|
|
1270
|
+
|
|
904
1271
|
# Modify the sql to add the filter criteria in the WHERE clause
|
|
905
1272
|
def select_where_sql(sql)
|
|
906
|
-
|
|
1273
|
+
if w = @opts[:where]
|
|
1274
|
+
sql << WHERE
|
|
1275
|
+
literal_append(sql, w)
|
|
1276
|
+
end
|
|
907
1277
|
end
|
|
908
1278
|
alias delete_where_sql select_where_sql
|
|
909
1279
|
alias update_where_sql select_where_sql
|
|
@@ -912,8 +1282,26 @@ module Sequel
|
|
|
912
1282
|
def select_with_sql(sql)
|
|
913
1283
|
ws = opts[:with]
|
|
914
1284
|
return if !ws || ws.empty?
|
|
915
|
-
sql
|
|
1285
|
+
sql << select_with_sql_base
|
|
1286
|
+
c = false
|
|
1287
|
+
comma = COMMA
|
|
1288
|
+
ws.each do |w|
|
|
1289
|
+
sql << comma if c
|
|
1290
|
+
quote_identifier_append(sql, w[:name])
|
|
1291
|
+
if args = w[:args]
|
|
1292
|
+
sql << PAREN_OPEN
|
|
1293
|
+
argument_list_append(sql, args)
|
|
1294
|
+
sql << PAREN_CLOSE
|
|
1295
|
+
end
|
|
1296
|
+
sql << AS
|
|
1297
|
+
literal_dataset_append(sql, w[:dataset])
|
|
1298
|
+
c ||= true
|
|
1299
|
+
end
|
|
1300
|
+
sql << SPACE
|
|
916
1301
|
end
|
|
1302
|
+
alias delete_with_sql select_with_sql
|
|
1303
|
+
alias insert_with_sql select_with_sql
|
|
1304
|
+
alias update_with_sql select_with_sql
|
|
917
1305
|
|
|
918
1306
|
# The base keyword to use for the SQL WITH clause
|
|
919
1307
|
def select_with_sql_base
|
|
@@ -921,9 +1309,15 @@ module Sequel
|
|
|
921
1309
|
end
|
|
922
1310
|
|
|
923
1311
|
# Converts an array of source names into into a comma separated list.
|
|
924
|
-
def
|
|
925
|
-
raise(Error, 'No source specified for query') if
|
|
926
|
-
|
|
1312
|
+
def source_list_append(sql, sources)
|
|
1313
|
+
raise(Error, 'No source specified for query') if sources.nil? || sources == []
|
|
1314
|
+
c = false
|
|
1315
|
+
co = COMMA
|
|
1316
|
+
sources.each do |s|
|
|
1317
|
+
sql << co if c
|
|
1318
|
+
identifier_append(sql, s)
|
|
1319
|
+
c ||= true
|
|
1320
|
+
end
|
|
927
1321
|
end
|
|
928
1322
|
|
|
929
1323
|
# Splits the symbol into three parts. Each part will
|
|
@@ -932,35 +1326,48 @@ module Sequel
|
|
|
932
1326
|
# For columns, these parts are the table, column, and alias.
|
|
933
1327
|
# For tables, these parts are the schema, table, and alias.
|
|
934
1328
|
def split_symbol(sym)
|
|
935
|
-
s = sym.to_s
|
|
936
|
-
|
|
937
|
-
[
|
|
938
|
-
|
|
939
|
-
[nil,
|
|
940
|
-
|
|
941
|
-
[
|
|
1329
|
+
case s = sym.to_s
|
|
1330
|
+
when COLUMN_REF_RE1
|
|
1331
|
+
[$1, $2, $3]
|
|
1332
|
+
when COLUMN_REF_RE2
|
|
1333
|
+
[nil, $1, $2]
|
|
1334
|
+
when COLUMN_REF_RE3
|
|
1335
|
+
[$1, $2, nil]
|
|
942
1336
|
else
|
|
943
1337
|
[nil, s, nil]
|
|
944
1338
|
end
|
|
945
1339
|
end
|
|
946
1340
|
|
|
1341
|
+
# The string that is appended to to create the SQL query, the empty
|
|
1342
|
+
# string by default
|
|
1343
|
+
def sql_string_origin
|
|
1344
|
+
''
|
|
1345
|
+
end
|
|
1346
|
+
|
|
947
1347
|
# SQL to use if this dataset uses static SQL. Since static SQL
|
|
948
1348
|
# can be a PlaceholderLiteralString in addition to a String,
|
|
949
1349
|
# we literalize nonstrings.
|
|
950
1350
|
def static_sql(sql)
|
|
951
|
-
|
|
1351
|
+
if append_sql = @opts[:append_sql]
|
|
1352
|
+
if sql.is_a?(String)
|
|
1353
|
+
append_sql << sql
|
|
1354
|
+
else
|
|
1355
|
+
literal_append(append_sql, sql)
|
|
1356
|
+
end
|
|
1357
|
+
else
|
|
1358
|
+
if sql.is_a?(String)
|
|
1359
|
+
sql
|
|
1360
|
+
else
|
|
1361
|
+
literal(sql)
|
|
1362
|
+
end
|
|
1363
|
+
end
|
|
952
1364
|
end
|
|
953
1365
|
|
|
954
1366
|
# SQL fragment for a subselect using the given database's SQL.
|
|
955
|
-
def
|
|
956
|
-
ds.sql
|
|
1367
|
+
def subselect_sql_append(sql, ds)
|
|
1368
|
+
ds.clone(:append_sql=>sql).sql
|
|
957
1369
|
end
|
|
958
1370
|
|
|
959
|
-
# SQL fragment specifying a table name.
|
|
960
|
-
def table_ref(t)
|
|
961
|
-
t.is_a?(String) ? quote_identifier(t) : literal(t)
|
|
962
|
-
end
|
|
963
|
-
|
|
964
1371
|
# The order of methods to call to build the UPDATE SQL statement
|
|
965
1372
|
def update_clause_methods
|
|
966
1373
|
UPDATE_CLAUSE_METHODS
|
|
@@ -969,25 +1376,38 @@ module Sequel
|
|
|
969
1376
|
# SQL fragment specifying the tables from with to delete.
|
|
970
1377
|
# Includes join table if modifying joins is allowed.
|
|
971
1378
|
def update_table_sql(sql)
|
|
972
|
-
sql <<
|
|
1379
|
+
sql << SPACE
|
|
1380
|
+
source_list_append(sql, @opts[:from])
|
|
973
1381
|
select_join_sql(sql) if supports_modifying_joins?
|
|
974
1382
|
end
|
|
975
1383
|
|
|
976
1384
|
# The SQL fragment specifying the columns and values to SET.
|
|
977
1385
|
def update_set_sql(sql)
|
|
978
1386
|
values = opts[:values]
|
|
979
|
-
|
|
1387
|
+
sql << SET
|
|
1388
|
+
if values.is_a?(Hash)
|
|
980
1389
|
values = opts[:defaults].merge(values) if opts[:defaults]
|
|
981
1390
|
values = values.merge(opts[:overrides]) if opts[:overrides]
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
1391
|
+
c = false
|
|
1392
|
+
eq = EQUAL
|
|
1393
|
+
values.each do |k, v|
|
|
1394
|
+
sql << COMMA if c
|
|
1395
|
+
if k.is_a?(String) && !k.is_a?(LiteralString)
|
|
1396
|
+
quote_identifier_append(sql, k)
|
|
1397
|
+
else
|
|
1398
|
+
literal_append(sql, k)
|
|
1399
|
+
end
|
|
1400
|
+
sql << eq
|
|
1401
|
+
literal_append(sql, v)
|
|
1402
|
+
c ||= true
|
|
1403
|
+
end
|
|
986
1404
|
else
|
|
987
|
-
|
|
988
|
-
values
|
|
1405
|
+
sql << values
|
|
989
1406
|
end
|
|
990
|
-
|
|
1407
|
+
end
|
|
1408
|
+
|
|
1409
|
+
def update_update_sql(sql)
|
|
1410
|
+
sql << UPDATE
|
|
991
1411
|
end
|
|
992
1412
|
end
|
|
993
1413
|
end
|