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
|
@@ -7,12 +7,7 @@ module Sequel
|
|
|
7
7
|
module MSSQL
|
|
8
8
|
module DatabaseMethods
|
|
9
9
|
include Sequel::MSSQL::DatabaseMethods
|
|
10
|
-
LAST_INSERT_ID_SQL='SELECT SCOPE_IDENTITY()'
|
|
11
|
-
|
|
12
|
-
# Return an instance of Sequel::ODBC::MSSQL::Dataset with the given opts.
|
|
13
|
-
def dataset(opts=nil)
|
|
14
|
-
Sequel::ODBC::MSSQL::Dataset.new(self, opts)
|
|
15
|
-
end
|
|
10
|
+
LAST_INSERT_ID_SQL='SELECT SCOPE_IDENTITY()'.freeze
|
|
16
11
|
|
|
17
12
|
# Return the last inserted identity value.
|
|
18
13
|
def execute_insert(sql, opts={})
|
|
@@ -33,9 +28,22 @@ module Sequel
|
|
|
33
28
|
end
|
|
34
29
|
end
|
|
35
30
|
end
|
|
36
|
-
|
|
37
31
|
class Dataset < ODBC::Dataset
|
|
38
32
|
include Sequel::MSSQL::DatasetMethods
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
# Use ODBC format, not Microsoft format, as the ODBC layer does
|
|
37
|
+
# some translation.
|
|
38
|
+
def default_timestamp_format
|
|
39
|
+
TIMESTAMP_FORMAT
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Use ODBC format, not Microsoft format, as the ODBC layer does
|
|
43
|
+
# some translation.
|
|
44
|
+
def literal_date(v)
|
|
45
|
+
v.strftime(ODBC_DATE_FORMAT)
|
|
46
|
+
end
|
|
39
47
|
end
|
|
40
48
|
end
|
|
41
49
|
end
|
data/lib/sequel/adapters/odbc.rb
CHANGED
|
@@ -15,9 +15,16 @@ module Sequel
|
|
|
15
15
|
when 'mssql'
|
|
16
16
|
Sequel.ts_require 'adapters/odbc/mssql'
|
|
17
17
|
extend Sequel::ODBC::MSSQL::DatabaseMethods
|
|
18
|
+
@dataset_class = Sequel::ODBC::MSSQL::Dataset
|
|
19
|
+
set_mssql_unicode_strings
|
|
18
20
|
when 'progress'
|
|
19
21
|
Sequel.ts_require 'adapters/shared/progress'
|
|
20
22
|
extend Sequel::Progress::DatabaseMethods
|
|
23
|
+
extend_datasets(Sequel::Progress::DatasetMethods)
|
|
24
|
+
when 'db2'
|
|
25
|
+
Sequel.ts_require 'adapters/shared/db2'
|
|
26
|
+
extend ::Sequel::DB2::DatabaseMethods
|
|
27
|
+
extend_datasets ::Sequel::DB2::DatasetMethods
|
|
21
28
|
end
|
|
22
29
|
end
|
|
23
30
|
|
|
@@ -41,17 +48,13 @@ module Sequel
|
|
|
41
48
|
conn
|
|
42
49
|
end
|
|
43
50
|
|
|
44
|
-
def dataset(opts = nil)
|
|
45
|
-
ODBC::Dataset.new(self, opts)
|
|
46
|
-
end
|
|
47
|
-
|
|
48
51
|
def execute(sql, opts={})
|
|
49
52
|
synchronize(opts[:server]) do |conn|
|
|
50
53
|
begin
|
|
51
54
|
r = log_yield(sql){conn.run(sql)}
|
|
52
55
|
yield(r) if block_given?
|
|
53
56
|
rescue ::ODBC::Error, ArgumentError => e
|
|
54
|
-
raise_error(e
|
|
57
|
+
raise_error(e)
|
|
55
58
|
ensure
|
|
56
59
|
r.drop if r
|
|
57
60
|
end
|
|
@@ -64,7 +67,7 @@ module Sequel
|
|
|
64
67
|
begin
|
|
65
68
|
log_yield(sql){conn.do(sql)}
|
|
66
69
|
rescue ::ODBC::Error, ArgumentError => e
|
|
67
|
-
raise_error(e
|
|
70
|
+
raise_error(e)
|
|
68
71
|
end
|
|
69
72
|
end
|
|
70
73
|
end
|
|
@@ -76,9 +79,17 @@ module Sequel
|
|
|
76
79
|
:do
|
|
77
80
|
end
|
|
78
81
|
|
|
82
|
+
def database_error_classes
|
|
83
|
+
[::ODBC::Error]
|
|
84
|
+
end
|
|
85
|
+
|
|
79
86
|
def disconnect_connection(c)
|
|
80
87
|
c.disconnect
|
|
81
88
|
end
|
|
89
|
+
|
|
90
|
+
def disconnect_error?(e, opts)
|
|
91
|
+
super || (e.is_a?(::ODBC::Error) && DISCONNECT_ERRORS.match(e.message))
|
|
92
|
+
end
|
|
82
93
|
end
|
|
83
94
|
|
|
84
95
|
class Dataset < Sequel::Dataset
|
|
@@ -87,15 +98,23 @@ module Sequel
|
|
|
87
98
|
ODBC_DATE_FORMAT = "{d '%Y-%m-%d'}".freeze
|
|
88
99
|
TIMESTAMP_FORMAT="{ts '%Y-%m-%d %H:%M:%S'}".freeze
|
|
89
100
|
|
|
101
|
+
Database::DatasetClass = self
|
|
102
|
+
|
|
90
103
|
def fetch_rows(sql)
|
|
91
104
|
execute(sql) do |s|
|
|
92
105
|
i = -1
|
|
93
106
|
cols = s.columns(true).map{|c| [output_identifier(c.name), i+=1]}
|
|
94
|
-
|
|
107
|
+
columns = cols.map{|c| c.at(0)}
|
|
108
|
+
if opts[:offset] && offset_returns_row_number_column?
|
|
109
|
+
rn = row_number_column
|
|
110
|
+
columns.delete(rn)
|
|
111
|
+
end
|
|
112
|
+
@columns = columns
|
|
95
113
|
if rows = s.fetch_all
|
|
96
114
|
rows.each do |row|
|
|
97
115
|
hash = {}
|
|
98
116
|
cols.each{|n,i| hash[n] = convert_odbc_value(row[i])}
|
|
117
|
+
hash.delete(rn) if rn
|
|
99
118
|
yield hash
|
|
100
119
|
end
|
|
101
120
|
end
|
|
@@ -114,9 +133,9 @@ module Sequel
|
|
|
114
133
|
# ODBCColumn#mapSqlTypeToGenericType and Column#klass.
|
|
115
134
|
case v
|
|
116
135
|
when ::ODBC::TimeStamp
|
|
117
|
-
|
|
136
|
+
db.to_application_timestamp([v.year, v.month, v.day, v.hour, v.minute, v.second])
|
|
118
137
|
when ::ODBC::Time
|
|
119
|
-
Sequel.
|
|
138
|
+
Sequel::SQLTime.create(v.hour, v.minute, v.second)
|
|
120
139
|
when ::ODBC::Date
|
|
121
140
|
Date.new(v.year, v.month, v.day)
|
|
122
141
|
else
|
|
@@ -15,10 +15,6 @@ module Sequel
|
|
|
15
15
|
)
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
-
def dataset(opts = nil)
|
|
19
|
-
OpenBase::Dataset.new(self, opts)
|
|
20
|
-
end
|
|
21
|
-
|
|
22
18
|
def execute(sql, opts={})
|
|
23
19
|
synchronize(opts[:server]) do |conn|
|
|
24
20
|
r = log_yield(sql){conn.execute(sql)}
|
|
@@ -36,7 +32,9 @@ module Sequel
|
|
|
36
32
|
end
|
|
37
33
|
|
|
38
34
|
class Dataset < Sequel::Dataset
|
|
39
|
-
SELECT_CLAUSE_METHODS = clause_methods(:select, %w'distinct columns from join where group having compounds order limit')
|
|
35
|
+
SELECT_CLAUSE_METHODS = clause_methods(:select, %w'select distinct columns from join where group having compounds order limit')
|
|
36
|
+
|
|
37
|
+
Database::DatasetClass = self
|
|
40
38
|
|
|
41
39
|
def fetch_rows(sql)
|
|
42
40
|
execute(sql) do |result|
|
|
@@ -13,6 +13,18 @@ module Sequel
|
|
|
13
13
|
# ORA-03114: not connected to ORACLE
|
|
14
14
|
CONNECTION_ERROR_CODES = [ 28, 1012, 3113, 3114 ]
|
|
15
15
|
|
|
16
|
+
ORACLE_TYPES = {:blob=>lambda{|b| Sequel::SQL::Blob.new(b.read)}}
|
|
17
|
+
|
|
18
|
+
# Hash of conversion procs for this database.
|
|
19
|
+
attr_reader :conversion_procs
|
|
20
|
+
|
|
21
|
+
def initialize(opts={})
|
|
22
|
+
super
|
|
23
|
+
@autosequence = opts[:autosequence]
|
|
24
|
+
@primary_key_sequences = {}
|
|
25
|
+
@conversion_procs = ORACLE_TYPES.dup
|
|
26
|
+
end
|
|
27
|
+
|
|
16
28
|
def connect(server)
|
|
17
29
|
opts = server_opts(server)
|
|
18
30
|
if opts[:database]
|
|
@@ -22,61 +34,150 @@ module Sequel
|
|
|
22
34
|
dbname = opts[:host]
|
|
23
35
|
end
|
|
24
36
|
conn = OCI8.new(opts[:user], opts[:password], dbname, opts[:privilege])
|
|
37
|
+
conn.prefetch_rows = typecast_value_integer(opts[:prefetch_rows]) if opts[:prefetch_rows]
|
|
25
38
|
conn.autocommit = true
|
|
26
39
|
conn.non_blocking = true
|
|
40
|
+
|
|
41
|
+
# The ruby-oci8 gem which retrieves oracle columns with a type of
|
|
42
|
+
# DATE, TIMESTAMP, TIMESTAMP WITH TIME ZONE is complex based on the
|
|
43
|
+
# ruby version (1.9.2 or later) and Oracle version (9 or later)
|
|
44
|
+
# In the now standard case of 1.9.2 and Oracle 9 or later, the timezone
|
|
45
|
+
# is determined by the Oracle session timezone. Thus if the user
|
|
46
|
+
# requests Sequel provide UTC timezone to the application,
|
|
47
|
+
# we need to alter the session timezone to be UTC
|
|
48
|
+
if Sequel.application_timezone == :utc
|
|
49
|
+
conn.exec("ALTER SESSION SET TIME_ZONE='-00:00'")
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
class << conn
|
|
53
|
+
attr_reader :prepared_statements
|
|
54
|
+
end
|
|
55
|
+
conn.instance_variable_set(:@prepared_statements, {})
|
|
56
|
+
|
|
27
57
|
conn
|
|
28
58
|
end
|
|
29
|
-
|
|
30
|
-
def
|
|
31
|
-
|
|
59
|
+
|
|
60
|
+
def execute(sql, opts={}, &block)
|
|
61
|
+
_execute(nil, sql, opts, &block)
|
|
32
62
|
end
|
|
63
|
+
alias do execute
|
|
33
64
|
|
|
34
|
-
def
|
|
35
|
-
|
|
36
|
-
ds.identifier_output_method = :downcase
|
|
37
|
-
schema_and_table = "#{"#{quote_identifier(opts[:schema])}." if opts[:schema]}#{quote_identifier(table)}"
|
|
38
|
-
table_schema = []
|
|
39
|
-
metadata = transaction(opts){|conn| conn.describe_table(schema_and_table)}
|
|
40
|
-
metadata.columns.each do |column|
|
|
41
|
-
table_schema << [
|
|
42
|
-
column.name.downcase.to_sym,
|
|
43
|
-
{
|
|
44
|
-
:type => column.data_type,
|
|
45
|
-
:db_type => column.type_string.split(' ')[0],
|
|
46
|
-
:type_string => column.type_string,
|
|
47
|
-
:charset_form => column.charset_form,
|
|
48
|
-
:char_used => column.char_used?,
|
|
49
|
-
:char_size => column.char_size,
|
|
50
|
-
:data_size => column.data_size,
|
|
51
|
-
:precision => column.precision,
|
|
52
|
-
:scale => column.scale,
|
|
53
|
-
:fsprecision => column.fsprecision,
|
|
54
|
-
:lfprecision => column.lfprecision,
|
|
55
|
-
:allow_null => column.nullable?
|
|
56
|
-
}
|
|
57
|
-
]
|
|
58
|
-
end
|
|
59
|
-
table_schema
|
|
65
|
+
def execute_insert(sql, opts={})
|
|
66
|
+
_execute(:insert, sql, opts)
|
|
60
67
|
end
|
|
61
68
|
|
|
62
|
-
|
|
69
|
+
private
|
|
70
|
+
|
|
71
|
+
def _execute(type, sql, opts={}, &block)
|
|
63
72
|
synchronize(opts[:server]) do |conn|
|
|
64
73
|
begin
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
74
|
+
return execute_prepared_statement(conn, type, sql, opts, &block) if sql.is_a?(Symbol)
|
|
75
|
+
if args = opts[:arguments]
|
|
76
|
+
r = conn.parse(sql)
|
|
77
|
+
args = cursor_bind_params(conn, r, args)
|
|
78
|
+
nr = log_yield(sql, args){r.exec}
|
|
79
|
+
r = nr unless block_given?
|
|
80
|
+
else
|
|
81
|
+
r = log_yield(sql){conn.exec(sql)}
|
|
82
|
+
end
|
|
83
|
+
if block_given?
|
|
84
|
+
begin
|
|
85
|
+
yield(r)
|
|
86
|
+
ensure
|
|
87
|
+
r.close
|
|
88
|
+
end
|
|
89
|
+
elsif type == :insert
|
|
90
|
+
last_insert_id(conn, opts)
|
|
91
|
+
else
|
|
92
|
+
r
|
|
93
|
+
end
|
|
94
|
+
rescue OCIException, RuntimeError => e
|
|
95
|
+
# ruby-oci8 is naughty and raises strings in some places
|
|
96
|
+
raise_error(e)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
PS_TYPES = {'string'.freeze=>String, 'integer'.freeze=>Integer, 'float'.freeze=>Float,
|
|
102
|
+
'decimal'.freeze=>Float, 'date'.freeze=>Time, 'datetime'.freeze=>Time,
|
|
103
|
+
'time'.freeze=>Time, 'boolean'.freeze=>String, 'blob'.freeze=>OCI8::BLOB}
|
|
104
|
+
def cursor_bind_params(conn, cursor, args)
|
|
105
|
+
cursor
|
|
106
|
+
i = 0
|
|
107
|
+
args.map do |arg, type|
|
|
108
|
+
i += 1
|
|
109
|
+
case arg
|
|
110
|
+
when true
|
|
111
|
+
arg = 'Y'
|
|
112
|
+
when false
|
|
113
|
+
arg = 'N'
|
|
114
|
+
when BigDecimal
|
|
115
|
+
arg = arg.to_f
|
|
116
|
+
when ::Sequel::SQL::Blob
|
|
117
|
+
raise Error, "Sequel's oracle adapter does not currently support using a blob in a bound variable"
|
|
118
|
+
end
|
|
119
|
+
if t = PS_TYPES[type]
|
|
120
|
+
cursor.bind_param(i, arg, t)
|
|
121
|
+
else
|
|
122
|
+
cursor.bind_param(i, arg, arg.class)
|
|
123
|
+
end
|
|
124
|
+
arg
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def execute_prepared_statement(conn, type, name, opts)
|
|
129
|
+
ps = prepared_statement(name)
|
|
130
|
+
sql = ps.prepared_sql
|
|
131
|
+
if cursora = conn.prepared_statements[name]
|
|
132
|
+
cursor, cursor_sql = cursora
|
|
133
|
+
if cursor_sql != sql
|
|
134
|
+
cursor.close
|
|
135
|
+
cursor = nil
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
unless cursor
|
|
139
|
+
cursor = log_yield("PREPARE #{name}: #{sql}"){conn.parse(sql)}
|
|
140
|
+
conn.prepared_statements[name] = [cursor, sql]
|
|
141
|
+
end
|
|
142
|
+
args = cursor_bind_params(conn, cursor, opts[:arguments])
|
|
143
|
+
log_sql = "EXECUTE #{name}"
|
|
144
|
+
if ps.log_sql
|
|
145
|
+
log_sql << " ("
|
|
146
|
+
log_sql << sql
|
|
147
|
+
log_sql << ")"
|
|
148
|
+
end
|
|
149
|
+
r = log_yield(log_sql, args){cursor.exec}
|
|
150
|
+
if block_given?
|
|
151
|
+
yield(cursor)
|
|
152
|
+
elsif type == :insert
|
|
153
|
+
last_insert_id(conn, opts)
|
|
154
|
+
else
|
|
155
|
+
r
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def last_insert_id(conn, opts)
|
|
160
|
+
unless sequence = opts[:sequence]
|
|
161
|
+
if t = opts[:table]
|
|
162
|
+
sequence = sequence_for_table(t)
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
if sequence
|
|
166
|
+
sql = "SELECT #{literal(sequence)}.currval FROM dual"
|
|
167
|
+
begin
|
|
168
|
+
cursor = log_yield(sql){conn.exec(sql)}
|
|
169
|
+
row = cursor.fetch
|
|
170
|
+
row.each{|v| return (v.to_i if v)}
|
|
171
|
+
rescue OCIError
|
|
172
|
+
nil
|
|
173
|
+
ensure
|
|
174
|
+
cursor.close if cursor
|
|
70
175
|
end
|
|
71
176
|
end
|
|
72
177
|
end
|
|
73
|
-
alias_method :do, :execute
|
|
74
178
|
|
|
75
|
-
private
|
|
76
|
-
|
|
77
179
|
def begin_transaction(conn, opts={})
|
|
78
180
|
log_yield(TRANSACTION_BEGIN){conn.autocommit = false}
|
|
79
|
-
conn
|
|
80
181
|
end
|
|
81
182
|
|
|
82
183
|
def commit_transaction(conn, opts={})
|
|
@@ -88,49 +189,244 @@ module Sequel
|
|
|
88
189
|
rescue OCIInvalidHandle
|
|
89
190
|
nil
|
|
90
191
|
end
|
|
192
|
+
|
|
193
|
+
def disconnect_error?(e, opts)
|
|
194
|
+
super || (e.is_a?(::OCIError) && CONNECTION_ERROR_CODES.include?(e.code))
|
|
195
|
+
end
|
|
91
196
|
|
|
92
|
-
def
|
|
93
|
-
|
|
197
|
+
def oracle_column_type(h)
|
|
198
|
+
case h[:oci8_type]
|
|
199
|
+
when :number
|
|
200
|
+
case h[:scale]
|
|
201
|
+
when 0
|
|
202
|
+
:integer
|
|
203
|
+
when -127
|
|
204
|
+
:float
|
|
205
|
+
else
|
|
206
|
+
:decimal
|
|
207
|
+
end
|
|
208
|
+
when :date
|
|
209
|
+
:datetime
|
|
210
|
+
else
|
|
211
|
+
schema_column_type(h[:db_type])
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def remove_transaction(conn, committed)
|
|
216
|
+
conn.autocommit = true
|
|
217
|
+
ensure
|
|
94
218
|
super
|
|
95
219
|
end
|
|
96
220
|
|
|
97
221
|
def rollback_transaction(conn, opts={})
|
|
98
222
|
log_yield(TRANSACTION_ROLLBACK){conn.rollback}
|
|
99
223
|
end
|
|
224
|
+
|
|
225
|
+
def schema_parse_table(table, opts={})
|
|
226
|
+
schema, table = schema_and_table(table)
|
|
227
|
+
schema ||= opts[:schema]
|
|
228
|
+
schema_and_table = if ds = opts[:dataset]
|
|
229
|
+
ds.literal(schema ? SQL::QualifiedIdentifier.new(schema, table) : SQL::Identifier.new(table))
|
|
230
|
+
else
|
|
231
|
+
"#{"#{quote_identifier(schema)}." if schema}#{quote_identifier(table)}"
|
|
232
|
+
end
|
|
233
|
+
table_schema = []
|
|
234
|
+
m = output_identifier_meth(ds)
|
|
235
|
+
im = input_identifier_meth(ds)
|
|
236
|
+
|
|
237
|
+
# Primary Keys
|
|
238
|
+
ds = metadata_dataset.from(:all_constraints___cons, :all_cons_columns___cols).
|
|
239
|
+
where(:cols__table_name=>im.call(table), :cons__constraint_type=>'P',
|
|
240
|
+
:cons__constraint_name=>:cols__constraint_name, :cons__owner=>:cols__owner)
|
|
241
|
+
ds = ds.where(:cons__owner=>im.call(schema)) if schema
|
|
242
|
+
pks = ds.select_map(:cols__column_name)
|
|
243
|
+
|
|
244
|
+
# Default values
|
|
245
|
+
defaults = begin
|
|
246
|
+
metadata_dataset.from(:user_tab_cols).
|
|
247
|
+
where(:table_name=>im.call(table)).
|
|
248
|
+
to_hash(:column_name, :data_default)
|
|
249
|
+
rescue DatabaseError
|
|
250
|
+
{}
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
metadata = synchronize(opts[:server]) do |conn|
|
|
254
|
+
begin
|
|
255
|
+
log_yield("Connection.describe_table"){conn.describe_table(schema_and_table)}
|
|
256
|
+
rescue OCIError => e
|
|
257
|
+
raise_error(e)
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
metadata.columns.each do |column|
|
|
261
|
+
h = {
|
|
262
|
+
:primary_key => pks.include?(column.name),
|
|
263
|
+
:default => defaults[column.name],
|
|
264
|
+
:oci8_type => column.data_type,
|
|
265
|
+
:db_type => column.type_string.split(' ')[0],
|
|
266
|
+
:type_string => column.type_string,
|
|
267
|
+
:charset_form => column.charset_form,
|
|
268
|
+
:char_used => column.char_used?,
|
|
269
|
+
:char_size => column.char_size,
|
|
270
|
+
:data_size => column.data_size,
|
|
271
|
+
:precision => column.precision,
|
|
272
|
+
:scale => column.scale,
|
|
273
|
+
:fsprecision => column.fsprecision,
|
|
274
|
+
:lfprecision => column.lfprecision,
|
|
275
|
+
:allow_null => column.nullable?
|
|
276
|
+
}
|
|
277
|
+
h[:type] = oracle_column_type(h)
|
|
278
|
+
table_schema << [m.call(column.name), h]
|
|
279
|
+
end
|
|
280
|
+
table_schema
|
|
281
|
+
end
|
|
100
282
|
end
|
|
101
283
|
|
|
102
284
|
class Dataset < Sequel::Dataset
|
|
103
285
|
include DatasetMethods
|
|
104
286
|
|
|
287
|
+
Database::DatasetClass = self
|
|
288
|
+
|
|
289
|
+
PREPARED_ARG_PLACEHOLDER = ':'.freeze
|
|
290
|
+
|
|
291
|
+
# Oracle already supports named bind arguments, so use directly.
|
|
292
|
+
module ArgumentMapper
|
|
293
|
+
include Sequel::Dataset::ArgumentMapper
|
|
294
|
+
|
|
295
|
+
protected
|
|
296
|
+
|
|
297
|
+
# Return a hash with the same values as the given hash,
|
|
298
|
+
# but with the keys converted to strings.
|
|
299
|
+
def map_to_prepared_args(bind_vars)
|
|
300
|
+
prepared_args.map{|v, t| [bind_vars[v], t]}
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
private
|
|
304
|
+
|
|
305
|
+
# Oracle uses a : before the name of the argument for named
|
|
306
|
+
# arguments.
|
|
307
|
+
def prepared_arg(k)
|
|
308
|
+
y, type = k.to_s.split("__", 2)
|
|
309
|
+
prepared_args << [y.to_sym, type]
|
|
310
|
+
i = prepared_args.length
|
|
311
|
+
LiteralString.new(":#{i}")
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
# Always assume a prepared argument.
|
|
315
|
+
def prepared_arg?(k)
|
|
316
|
+
true
|
|
317
|
+
end
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
# Oracle prepared statement uses a new prepared statement each time
|
|
321
|
+
# it is called, but it does use the bind arguments.
|
|
322
|
+
module BindArgumentMethods
|
|
323
|
+
include ArgumentMapper
|
|
324
|
+
|
|
325
|
+
private
|
|
326
|
+
|
|
327
|
+
# Run execute_select on the database with the given SQL and the stored
|
|
328
|
+
# bind arguments.
|
|
329
|
+
def execute(sql, opts={}, &block)
|
|
330
|
+
super(prepared_sql, {:arguments=>bind_arguments}.merge(opts), &block)
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
# Same as execute, explicit due to intricacies of alias and super.
|
|
334
|
+
def execute_dui(sql, opts={}, &block)
|
|
335
|
+
super(prepared_sql, {:arguments=>bind_arguments}.merge(opts), &block)
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
# Same as execute, explicit due to intricacies of alias and super.
|
|
339
|
+
def execute_insert(sql, opts={}, &block)
|
|
340
|
+
super(prepared_sql, {:arguments=>bind_arguments}.merge(opts), &block)
|
|
341
|
+
end
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
module PreparedStatementMethods
|
|
345
|
+
include BindArgumentMethods
|
|
346
|
+
|
|
347
|
+
private
|
|
348
|
+
|
|
349
|
+
# Execute the stored prepared statement name and the stored bind
|
|
350
|
+
# arguments instead of the SQL given.
|
|
351
|
+
def execute(sql, opts={}, &block)
|
|
352
|
+
super(prepared_statement_name, opts, &block)
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
# Same as execute, explicit due to intricacies of alias and super.
|
|
356
|
+
def execute_dui(sql, opts={}, &block)
|
|
357
|
+
super(prepared_statement_name, opts, &block)
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
# Same as execute, explicit due to intricacies of alias and super.
|
|
361
|
+
def execute_insert(sql, opts={}, &block)
|
|
362
|
+
super(prepared_statement_name, opts, &block)
|
|
363
|
+
end
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
# Execute the given type of statement with the hash of values.
|
|
367
|
+
def call(type, bind_vars={}, *values, &block)
|
|
368
|
+
ps = to_prepared_statement(type, values)
|
|
369
|
+
ps.extend(BindArgumentMethods)
|
|
370
|
+
ps.call(bind_vars, &block)
|
|
371
|
+
end
|
|
372
|
+
|
|
105
373
|
def fetch_rows(sql)
|
|
106
374
|
execute(sql) do |cursor|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
375
|
+
offset = @opts[:offset]
|
|
376
|
+
rn = row_number_column
|
|
377
|
+
cps = db.conversion_procs
|
|
378
|
+
cols = columns = cursor.get_col_names.map{|c| output_identifier(c)}
|
|
379
|
+
metadata = cursor.column_metadata
|
|
380
|
+
cm = cols.zip(metadata).map{|c, m| [c, cps[m.data_type]]}
|
|
381
|
+
columns = cols.reject{|x| x == rn} if offset
|
|
382
|
+
@columns = columns
|
|
383
|
+
while r = cursor.fetch
|
|
384
|
+
row = {}
|
|
385
|
+
r.zip(cm).each{|v, (c, cp)| row[c] = ((v && cp) ? cp.call(v) : v)}
|
|
386
|
+
row.delete(rn) if offset
|
|
387
|
+
yield row
|
|
116
388
|
end
|
|
117
389
|
end
|
|
118
390
|
self
|
|
119
391
|
end
|
|
120
392
|
|
|
393
|
+
# Prepare the given type of query with the given name and store
|
|
394
|
+
# it in the database. Note that a new native prepared statement is
|
|
395
|
+
# created on each call to this prepared statement.
|
|
396
|
+
def prepare(type, name=nil, *values)
|
|
397
|
+
ps = to_prepared_statement(type, values)
|
|
398
|
+
ps.extend(PreparedStatementMethods)
|
|
399
|
+
if name
|
|
400
|
+
ps.prepared_statement_name = name
|
|
401
|
+
db.set_prepared_statement(name, ps)
|
|
402
|
+
end
|
|
403
|
+
ps
|
|
404
|
+
end
|
|
405
|
+
|
|
406
|
+
# Oracle requires type specifiers for placeholders, at least
|
|
407
|
+
# if you ever want to use a nil/NULL value as the value for
|
|
408
|
+
# the placeholder.
|
|
409
|
+
def requires_placeholder_type_specifiers?
|
|
410
|
+
true
|
|
411
|
+
end
|
|
412
|
+
|
|
121
413
|
private
|
|
122
414
|
|
|
123
|
-
def
|
|
415
|
+
def literal_other_append(sql, v)
|
|
124
416
|
case v
|
|
125
417
|
when OraDate
|
|
126
|
-
|
|
418
|
+
literal_append(sql, db.to_application_timestamp(v))
|
|
127
419
|
when OCI8::CLOB
|
|
128
420
|
v.rewind
|
|
129
|
-
|
|
421
|
+
literal_append(sql, v.read)
|
|
130
422
|
else
|
|
131
423
|
super
|
|
132
424
|
end
|
|
133
425
|
end
|
|
426
|
+
|
|
427
|
+
def prepared_arg_placeholder
|
|
428
|
+
PREPARED_ARG_PLACEHOLDER
|
|
429
|
+
end
|
|
134
430
|
end
|
|
135
431
|
end
|
|
136
432
|
end
|