epugh-sequel 0.0.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/README.rdoc +652 -0
- data/VERSION.yml +4 -0
- data/bin/sequel +104 -0
- data/lib/sequel.rb +1 -0
- data/lib/sequel/adapters/ado.rb +85 -0
- data/lib/sequel/adapters/db2.rb +132 -0
- data/lib/sequel/adapters/dbi.rb +101 -0
- data/lib/sequel/adapters/do.rb +197 -0
- data/lib/sequel/adapters/do/mysql.rb +38 -0
- data/lib/sequel/adapters/do/postgres.rb +92 -0
- data/lib/sequel/adapters/do/sqlite.rb +31 -0
- data/lib/sequel/adapters/firebird.rb +307 -0
- data/lib/sequel/adapters/informix.rb +75 -0
- data/lib/sequel/adapters/jdbc.rb +485 -0
- data/lib/sequel/adapters/jdbc/h2.rb +62 -0
- data/lib/sequel/adapters/jdbc/mysql.rb +56 -0
- data/lib/sequel/adapters/jdbc/oracle.rb +23 -0
- data/lib/sequel/adapters/jdbc/postgresql.rb +101 -0
- data/lib/sequel/adapters/jdbc/sqlite.rb +43 -0
- data/lib/sequel/adapters/mysql.rb +370 -0
- data/lib/sequel/adapters/odbc.rb +184 -0
- data/lib/sequel/adapters/openbase.rb +57 -0
- data/lib/sequel/adapters/oracle.rb +140 -0
- data/lib/sequel/adapters/postgres.rb +453 -0
- data/lib/sequel/adapters/shared/mssql.rb +93 -0
- data/lib/sequel/adapters/shared/mysql.rb +341 -0
- data/lib/sequel/adapters/shared/oracle.rb +62 -0
- data/lib/sequel/adapters/shared/postgres.rb +743 -0
- data/lib/sequel/adapters/shared/progress.rb +34 -0
- data/lib/sequel/adapters/shared/sqlite.rb +263 -0
- data/lib/sequel/adapters/sqlite.rb +243 -0
- data/lib/sequel/adapters/utils/date_format.rb +21 -0
- data/lib/sequel/adapters/utils/stored_procedures.rb +75 -0
- data/lib/sequel/adapters/utils/unsupported.rb +62 -0
- data/lib/sequel/connection_pool.rb +258 -0
- data/lib/sequel/core.rb +204 -0
- data/lib/sequel/core_sql.rb +185 -0
- data/lib/sequel/database.rb +687 -0
- data/lib/sequel/database/schema_generator.rb +324 -0
- data/lib/sequel/database/schema_methods.rb +164 -0
- data/lib/sequel/database/schema_sql.rb +324 -0
- data/lib/sequel/dataset.rb +422 -0
- data/lib/sequel/dataset/convenience.rb +237 -0
- data/lib/sequel/dataset/prepared_statements.rb +220 -0
- data/lib/sequel/dataset/sql.rb +1105 -0
- data/lib/sequel/deprecated.rb +529 -0
- data/lib/sequel/exceptions.rb +44 -0
- data/lib/sequel/extensions/blank.rb +42 -0
- data/lib/sequel/extensions/inflector.rb +288 -0
- data/lib/sequel/extensions/pagination.rb +96 -0
- data/lib/sequel/extensions/pretty_table.rb +78 -0
- data/lib/sequel/extensions/query.rb +48 -0
- data/lib/sequel/extensions/string_date_time.rb +47 -0
- data/lib/sequel/metaprogramming.rb +44 -0
- data/lib/sequel/migration.rb +212 -0
- data/lib/sequel/model.rb +142 -0
- data/lib/sequel/model/association_reflection.rb +263 -0
- data/lib/sequel/model/associations.rb +1024 -0
- data/lib/sequel/model/base.rb +911 -0
- data/lib/sequel/model/deprecated.rb +188 -0
- data/lib/sequel/model/deprecated_hooks.rb +103 -0
- data/lib/sequel/model/deprecated_inflector.rb +335 -0
- data/lib/sequel/model/deprecated_validations.rb +384 -0
- data/lib/sequel/model/errors.rb +37 -0
- data/lib/sequel/model/exceptions.rb +7 -0
- data/lib/sequel/model/inflections.rb +230 -0
- data/lib/sequel/model/plugins.rb +74 -0
- data/lib/sequel/object_graph.rb +230 -0
- data/lib/sequel/plugins/caching.rb +122 -0
- data/lib/sequel/plugins/hook_class_methods.rb +122 -0
- data/lib/sequel/plugins/schema.rb +53 -0
- data/lib/sequel/plugins/single_table_inheritance.rb +63 -0
- data/lib/sequel/plugins/validation_class_methods.rb +373 -0
- data/lib/sequel/sql.rb +854 -0
- data/lib/sequel/version.rb +11 -0
- data/lib/sequel_core.rb +1 -0
- data/lib/sequel_model.rb +1 -0
- data/spec/adapters/ado_spec.rb +46 -0
- data/spec/adapters/firebird_spec.rb +376 -0
- data/spec/adapters/informix_spec.rb +96 -0
- data/spec/adapters/mysql_spec.rb +875 -0
- data/spec/adapters/oracle_spec.rb +272 -0
- data/spec/adapters/postgres_spec.rb +692 -0
- data/spec/adapters/spec_helper.rb +10 -0
- data/spec/adapters/sqlite_spec.rb +550 -0
- data/spec/core/connection_pool_spec.rb +526 -0
- data/spec/core/core_ext_spec.rb +156 -0
- data/spec/core/core_sql_spec.rb +528 -0
- data/spec/core/database_spec.rb +1214 -0
- data/spec/core/dataset_spec.rb +3513 -0
- data/spec/core/expression_filters_spec.rb +363 -0
- data/spec/core/migration_spec.rb +261 -0
- data/spec/core/object_graph_spec.rb +280 -0
- data/spec/core/pretty_table_spec.rb +58 -0
- data/spec/core/schema_generator_spec.rb +167 -0
- data/spec/core/schema_spec.rb +778 -0
- data/spec/core/spec_helper.rb +82 -0
- data/spec/core/version_spec.rb +7 -0
- data/spec/extensions/blank_spec.rb +67 -0
- data/spec/extensions/caching_spec.rb +201 -0
- data/spec/extensions/hook_class_methods_spec.rb +470 -0
- data/spec/extensions/inflector_spec.rb +122 -0
- data/spec/extensions/pagination_spec.rb +99 -0
- data/spec/extensions/pretty_table_spec.rb +91 -0
- data/spec/extensions/query_spec.rb +85 -0
- data/spec/extensions/schema_spec.rb +111 -0
- data/spec/extensions/single_table_inheritance_spec.rb +53 -0
- data/spec/extensions/spec_helper.rb +90 -0
- data/spec/extensions/string_date_time_spec.rb +93 -0
- data/spec/extensions/validation_class_methods_spec.rb +1054 -0
- data/spec/integration/dataset_test.rb +160 -0
- data/spec/integration/eager_loader_test.rb +683 -0
- data/spec/integration/prepared_statement_test.rb +130 -0
- data/spec/integration/schema_test.rb +183 -0
- data/spec/integration/spec_helper.rb +75 -0
- data/spec/integration/type_test.rb +96 -0
- data/spec/model/association_reflection_spec.rb +93 -0
- data/spec/model/associations_spec.rb +1780 -0
- data/spec/model/base_spec.rb +494 -0
- data/spec/model/caching_spec.rb +217 -0
- data/spec/model/dataset_methods_spec.rb +78 -0
- data/spec/model/eager_loading_spec.rb +1165 -0
- data/spec/model/hooks_spec.rb +472 -0
- data/spec/model/inflector_spec.rb +126 -0
- data/spec/model/model_spec.rb +588 -0
- data/spec/model/plugins_spec.rb +142 -0
- data/spec/model/record_spec.rb +1243 -0
- data/spec/model/schema_spec.rb +92 -0
- data/spec/model/spec_helper.rb +124 -0
- data/spec/model/validations_spec.rb +1080 -0
- data/spec/rcov.opts +6 -0
- data/spec/spec.opts +0 -0
- data/spec/spec_config.rb.example +10 -0
- metadata +202 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
class Array
|
|
2
|
+
# Return a Sequel::SQL::BooleanExpression created from this array, not matching any of the
|
|
3
|
+
# conditions.
|
|
4
|
+
def ~
|
|
5
|
+
sql_expr_if_all_two_pairs(:OR, true)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
# True if the array is not empty and all of its elements are
|
|
9
|
+
# arrays of size 2. This is used to determine if the array
|
|
10
|
+
# could be a specifier of conditions, used similarly to a hash
|
|
11
|
+
# but allowing for duplicate keys.
|
|
12
|
+
#
|
|
13
|
+
# hash.to_a.all_two_pairs? # => true unless hash is empty
|
|
14
|
+
def all_two_pairs?
|
|
15
|
+
!empty? && all?{|i| (Array === i) && (i.length == 2)}
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Return a Sequel::SQL::CaseExpression with this array as the conditions and the given
|
|
19
|
+
# default value.
|
|
20
|
+
def case(default, expression = nil)
|
|
21
|
+
::Sequel::SQL::CaseExpression.new(self, default, expression)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Return a Sequel::SQL::Array created from this array. Used if this array contains
|
|
25
|
+
# all two pairs and you want it treated as an SQL array instead of a ordered hash-like
|
|
26
|
+
# conditions.
|
|
27
|
+
def sql_array
|
|
28
|
+
::Sequel::SQL::SQLArray.new(self)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Return a Sequel::SQL::BooleanExpression created from this array, matching all of the
|
|
32
|
+
# conditions.
|
|
33
|
+
def sql_expr
|
|
34
|
+
sql_expr_if_all_two_pairs
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Return a Sequel::SQL::BooleanExpression created from this array, matching none
|
|
38
|
+
# of the conditions.
|
|
39
|
+
def sql_negate
|
|
40
|
+
sql_expr_if_all_two_pairs(:AND, true)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Return a Sequel::SQL::BooleanExpression created from this array, matching any of the
|
|
44
|
+
# conditions.
|
|
45
|
+
def sql_or
|
|
46
|
+
sql_expr_if_all_two_pairs(:OR)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Return a Sequel::SQL::BooleanExpression representing an SQL string made up of the
|
|
50
|
+
# concatenation of this array's elements. If an argument is passed
|
|
51
|
+
# it is used in between each element of the array in the SQL
|
|
52
|
+
# concatenation.
|
|
53
|
+
def sql_string_join(joiner=nil)
|
|
54
|
+
if joiner
|
|
55
|
+
args = self.inject([]) do |m, a|
|
|
56
|
+
m << a
|
|
57
|
+
m << joiner
|
|
58
|
+
end
|
|
59
|
+
args.pop
|
|
60
|
+
else
|
|
61
|
+
args = self
|
|
62
|
+
end
|
|
63
|
+
args = args.collect{|a| [Symbol, ::Sequel::SQL::Expression, ::Sequel::LiteralString, TrueClass, FalseClass, NilClass].any?{|c| a.is_a?(c)} ? a : a.to_s}
|
|
64
|
+
::Sequel::SQL::StringExpression.new(:'||', *args)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
private
|
|
68
|
+
|
|
69
|
+
# Raise an error if this array is not made up of all two pairs, otherwise create a Sequel::SQL::BooleanExpression from this array.
|
|
70
|
+
def sql_expr_if_all_two_pairs(*args)
|
|
71
|
+
raise(Sequel::Error, 'Not all elements of the array are arrays of size 2, so it cannot be converted to an SQL expression') unless all_two_pairs?
|
|
72
|
+
::Sequel::SQL::BooleanExpression.from_value_pairs(self, *args)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
class Hash
|
|
77
|
+
# Return a Sequel::SQL::BooleanExpression created from this hash, matching
|
|
78
|
+
# all of the conditions in this hash and the condition specified by
|
|
79
|
+
# the given argument.
|
|
80
|
+
def &(ce)
|
|
81
|
+
::Sequel::SQL::BooleanExpression.new(:AND, self, ce)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Return a Sequel::SQL::BooleanExpression created from this hash, matching
|
|
85
|
+
# all of the conditions in this hash or the condition specified by
|
|
86
|
+
# the given argument.
|
|
87
|
+
def |(ce)
|
|
88
|
+
::Sequel::SQL::BooleanExpression.new(:OR, self, ce)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Return a Sequel::SQL::BooleanExpression created from this hash, not matching any of the
|
|
92
|
+
# conditions.
|
|
93
|
+
def ~
|
|
94
|
+
::Sequel::SQL::BooleanExpression.from_value_pairs(self, :OR, true)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Return a Sequel::SQL::CaseExpression with this hash as the conditions and the given
|
|
98
|
+
# default value. Note that the order of the conditions will be arbitrary, so all
|
|
99
|
+
# conditions should be orthogonal.
|
|
100
|
+
def case(default, expression = nil)
|
|
101
|
+
::Sequel::SQL::CaseExpression.new(to_a, default, expression)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Return a Sequel::SQL::BooleanExpression created from this hash, matching all of the
|
|
105
|
+
# conditions.
|
|
106
|
+
def sql_expr
|
|
107
|
+
::Sequel::SQL::BooleanExpression.from_value_pairs(self)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Return a Sequel::SQL::BooleanExpression created from this hash, matching none
|
|
111
|
+
# of the conditions.
|
|
112
|
+
def sql_negate
|
|
113
|
+
::Sequel::SQL::BooleanExpression.from_value_pairs(self, :AND, true)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Return a Sequel::SQL::BooleanExpression created from this hash, matching any of the
|
|
117
|
+
# conditions.
|
|
118
|
+
def sql_or
|
|
119
|
+
::Sequel::SQL::BooleanExpression.from_value_pairs(self, :OR)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
class String
|
|
124
|
+
include Sequel::SQL::AliasMethods
|
|
125
|
+
include Sequel::SQL::CastMethods
|
|
126
|
+
|
|
127
|
+
# Converts a string into a Sequel::LiteralString, in order to override string
|
|
128
|
+
# literalization, e.g.:
|
|
129
|
+
#
|
|
130
|
+
# DB[:items].filter(:abc => 'def').sql #=>
|
|
131
|
+
# "SELECT * FROM items WHERE (abc = 'def')"
|
|
132
|
+
#
|
|
133
|
+
# DB[:items].filter(:abc => 'def'.lit).sql #=>
|
|
134
|
+
# "SELECT * FROM items WHERE (abc = def)"
|
|
135
|
+
#
|
|
136
|
+
# You can also provide arguments, to create a Sequel::SQL::PlaceholderLiteralString:
|
|
137
|
+
#
|
|
138
|
+
# DB[:items].select{|o| o.count('DISTINCT ?'.lit(:a))}.sql #=>
|
|
139
|
+
# "SELECT count(DISTINCT a) FROM items"
|
|
140
|
+
def lit(*args)
|
|
141
|
+
args.empty? ? Sequel::LiteralString.new(self) : Sequel::SQL::PlaceholderLiteralString.new(self, args)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# Returns a Blob that holds the same data as this string. Blobs provide proper
|
|
145
|
+
# escaping of binary data.
|
|
146
|
+
def to_sequel_blob
|
|
147
|
+
::Sequel::SQL::Blob.new(self)
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
class Symbol
|
|
152
|
+
include Sequel::SQL::QualifyingMethods
|
|
153
|
+
include Sequel::SQL::IdentifierMethods
|
|
154
|
+
include Sequel::SQL::AliasMethods
|
|
155
|
+
include Sequel::SQL::CastMethods
|
|
156
|
+
include Sequel::SQL::OrderMethods
|
|
157
|
+
include Sequel::SQL::BooleanMethods
|
|
158
|
+
include Sequel::SQL::NumericMethods
|
|
159
|
+
include Sequel::SQL::StringMethods
|
|
160
|
+
include Sequel::SQL::ComplexExpressionMethods
|
|
161
|
+
include Sequel::SQL::InequalityMethods if RUBY_VERSION < '1.9.0'
|
|
162
|
+
|
|
163
|
+
# If no argument is given, returns a Sequel::SQL::ColumnAll object specifying all
|
|
164
|
+
# columns for this table.
|
|
165
|
+
# If an argument is given, returns a Sequel::SQL::NumericExpression using the *
|
|
166
|
+
# (multiplication) operator with this and the given argument.
|
|
167
|
+
def *(ce=(arg=false;nil))
|
|
168
|
+
return super(ce) unless arg == false
|
|
169
|
+
Sequel::SQL::ColumnAll.new(self);
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# Returns a Sequel::SQL::Function with this as the function name,
|
|
173
|
+
# and the given arguments. This is aliased as Symbol#[] if ruby 1.9
|
|
174
|
+
# is not being used. ruby 1.9 includes Symbol#[], and Sequel
|
|
175
|
+
# doesn't override methods defined by ruby itself.
|
|
176
|
+
def sql_function(*args)
|
|
177
|
+
Sequel::SQL::Function.new(self, *args)
|
|
178
|
+
end
|
|
179
|
+
alias_method(:[], :sql_function) if RUBY_VERSION < '1.9.0'
|
|
180
|
+
|
|
181
|
+
# Return an SQL array subscript with the given arguments.
|
|
182
|
+
def sql_subscript(*sub)
|
|
183
|
+
Sequel::SQL::Subscript.new(self, sub.flatten)
|
|
184
|
+
end
|
|
185
|
+
end
|
|
@@ -0,0 +1,687 @@
|
|
|
1
|
+
module Sequel
|
|
2
|
+
# Array of all databases to which Sequel has connected. If you are
|
|
3
|
+
# developing an application that can connect to an arbitrary number of
|
|
4
|
+
# databases, delete the database objects from this or they will not get
|
|
5
|
+
# garbage collected.
|
|
6
|
+
DATABASES = []
|
|
7
|
+
|
|
8
|
+
# A Database object represents a virtual connection to a database.
|
|
9
|
+
# The Database class is meant to be subclassed by database adapters in order
|
|
10
|
+
# to provide the functionality needed for executing queries.
|
|
11
|
+
class Database
|
|
12
|
+
extend Metaprogramming
|
|
13
|
+
include Metaprogramming
|
|
14
|
+
|
|
15
|
+
# Array of supported database adapters
|
|
16
|
+
ADAPTERS = %w'ado db2 dbi do firebird informix jdbc mysql odbc openbase oracle postgres sqlite'.collect{|x| x.to_sym}
|
|
17
|
+
|
|
18
|
+
SQL_BEGIN = 'BEGIN'.freeze
|
|
19
|
+
SQL_COMMIT = 'COMMIT'.freeze
|
|
20
|
+
SQL_ROLLBACK = 'ROLLBACK'.freeze
|
|
21
|
+
|
|
22
|
+
# Hash of adapters that have been used
|
|
23
|
+
@@adapters = Hash.new
|
|
24
|
+
|
|
25
|
+
# The identifier input method to use by default
|
|
26
|
+
@@identifier_input_method = nil
|
|
27
|
+
|
|
28
|
+
# The identifier output method to use by default
|
|
29
|
+
@@identifier_output_method = nil
|
|
30
|
+
|
|
31
|
+
# Whether to use the single threaded connection pool by default
|
|
32
|
+
@@single_threaded = false
|
|
33
|
+
|
|
34
|
+
# Whether to quote identifiers (columns and tables) by default
|
|
35
|
+
@@quote_identifiers = nil
|
|
36
|
+
|
|
37
|
+
# The default schema to use
|
|
38
|
+
attr_accessor :default_schema
|
|
39
|
+
|
|
40
|
+
# Array of SQL loggers to use for this database
|
|
41
|
+
attr_accessor :loggers
|
|
42
|
+
|
|
43
|
+
# The options for this database
|
|
44
|
+
attr_reader :opts
|
|
45
|
+
|
|
46
|
+
# The connection pool for this database
|
|
47
|
+
attr_reader :pool
|
|
48
|
+
|
|
49
|
+
# The prepared statement objects for this database, keyed by name
|
|
50
|
+
attr_reader :prepared_statements
|
|
51
|
+
|
|
52
|
+
# Constructs a new instance of a database connection with the specified
|
|
53
|
+
# options hash.
|
|
54
|
+
#
|
|
55
|
+
# Sequel::Database is an abstract class that is not useful by itself.
|
|
56
|
+
#
|
|
57
|
+
# Takes the following options:
|
|
58
|
+
# * :default_schema : The default schema to use, should generally be nil
|
|
59
|
+
# * :disconnection_proc: A proc used to disconnect the connection.
|
|
60
|
+
# * :identifier_input_method: A string method symbol to call on identifiers going into the database
|
|
61
|
+
# * :identifier_output_method: A string method symbol to call on identifiers coming from the database
|
|
62
|
+
# * :loggers : An array of loggers to use.
|
|
63
|
+
# * :quote_identifiers : Whether to quote identifiers
|
|
64
|
+
# * :single_threaded : Whether to use a single-threaded connection pool
|
|
65
|
+
#
|
|
66
|
+
# All options given are also passed to the ConnectionPool. If a block
|
|
67
|
+
# is given, it is used as the connection_proc for the ConnectionPool.
|
|
68
|
+
def initialize(opts = {}, &block)
|
|
69
|
+
@opts ||= opts
|
|
70
|
+
|
|
71
|
+
@single_threaded = opts.include?(:single_threaded) ? opts[:single_threaded] : @@single_threaded
|
|
72
|
+
@schemas = nil
|
|
73
|
+
@default_schema = opts.include?(:default_schema) ? opts[:default_schema] : default_schema_default
|
|
74
|
+
@prepared_statements = {}
|
|
75
|
+
@transactions = []
|
|
76
|
+
@identifier_input_method = nil
|
|
77
|
+
@identifier_output_method = nil
|
|
78
|
+
@quote_identifiers = nil
|
|
79
|
+
if opts.include?(:upcase_identifiers)
|
|
80
|
+
Deprecation.deprecate('The :upcase_identifiers Database option', 'Use the :identifier_input_method => :upcase option instead')
|
|
81
|
+
@identifier_input_method = opts[:upcase_identifiers] ? :upcase : ""
|
|
82
|
+
end
|
|
83
|
+
@pool = (@single_threaded ? SingleThreadedPool : ConnectionPool).new(connection_pool_default_options.merge(opts), &block)
|
|
84
|
+
@pool.connection_proc = proc{|server| connect(server)} unless block
|
|
85
|
+
@pool.disconnection_proc = proc{|conn| disconnect_connection(conn)} unless opts[:disconnection_proc]
|
|
86
|
+
|
|
87
|
+
@loggers = Array(opts[:logger]) + Array(opts[:loggers])
|
|
88
|
+
::Sequel::DATABASES.push(self)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
### Class Methods ###
|
|
92
|
+
|
|
93
|
+
# The Database subclass for the given adapter scheme.
|
|
94
|
+
# Raises Sequel::Error::AdapterNotFound if the adapter
|
|
95
|
+
# could not be loaded.
|
|
96
|
+
def self.adapter_class(scheme)
|
|
97
|
+
scheme = scheme.to_s.gsub('-', '_').to_sym
|
|
98
|
+
|
|
99
|
+
if (klass = @@adapters[scheme]).nil?
|
|
100
|
+
# attempt to load the adapter file
|
|
101
|
+
begin
|
|
102
|
+
Sequel.require "adapters/#{scheme}"
|
|
103
|
+
rescue LoadError => e
|
|
104
|
+
raise Error::AdapterNotFound, "Could not load #{scheme} adapter:\n #{e.message}"
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# make sure we actually loaded the adapter
|
|
108
|
+
if (klass = @@adapters[scheme]).nil?
|
|
109
|
+
raise Error::AdapterNotFound, "Could not load #{scheme} adapter"
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
return klass
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Returns the scheme for the Database class.
|
|
116
|
+
def self.adapter_scheme
|
|
117
|
+
@scheme
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Connects to a database. See Sequel.connect.
|
|
121
|
+
def self.connect(conn_string, opts = {}, &block)
|
|
122
|
+
if conn_string.is_a?(String)
|
|
123
|
+
if conn_string =~ /\Ajdbc:/
|
|
124
|
+
c = adapter_class(:jdbc)
|
|
125
|
+
opts = {:uri=>conn_string}.merge(opts)
|
|
126
|
+
elsif conn_string =~ /\Ado:/
|
|
127
|
+
c = adapter_class(:do)
|
|
128
|
+
opts = {:uri=>conn_string}.merge(opts)
|
|
129
|
+
else
|
|
130
|
+
uri = URI.parse(conn_string)
|
|
131
|
+
scheme = uri.scheme
|
|
132
|
+
scheme = :dbi if scheme =~ /\Adbi-/
|
|
133
|
+
c = adapter_class(scheme)
|
|
134
|
+
uri_options = {}
|
|
135
|
+
uri.query.split('&').collect{|s| s.split('=')}.each{|k,v| uri_options[k.to_sym] = v} unless uri.query.to_s.strip.empty?
|
|
136
|
+
opts = c.send(:uri_to_options, uri).merge(uri_options).merge(opts)
|
|
137
|
+
end
|
|
138
|
+
else
|
|
139
|
+
opts = conn_string.merge(opts)
|
|
140
|
+
c = adapter_class(opts[:adapter] || opts['adapter'])
|
|
141
|
+
end
|
|
142
|
+
# process opts a bit
|
|
143
|
+
opts = opts.inject({}) do |m, kv| k, v = *kv
|
|
144
|
+
k = :user if k.to_s == 'username'
|
|
145
|
+
m[k.to_sym] = v
|
|
146
|
+
m
|
|
147
|
+
end
|
|
148
|
+
if block
|
|
149
|
+
begin
|
|
150
|
+
yield(db = c.new(opts))
|
|
151
|
+
ensure
|
|
152
|
+
db.disconnect if db
|
|
153
|
+
::Sequel::DATABASES.delete(db)
|
|
154
|
+
end
|
|
155
|
+
nil
|
|
156
|
+
else
|
|
157
|
+
c.new(opts)
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# The method to call on identifiers going into the database
|
|
162
|
+
def self.identifier_input_method
|
|
163
|
+
@@identifier_input_method
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# Set the method to call on identifiers going into the database
|
|
167
|
+
def self.identifier_input_method=(v)
|
|
168
|
+
@@identifier_input_method = v || ""
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# The method to call on identifiers coming from the database
|
|
172
|
+
def self.identifier_output_method
|
|
173
|
+
@@identifier_output_method
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# Set the method to call on identifiers coming from the database
|
|
177
|
+
def self.identifier_output_method=(v)
|
|
178
|
+
@@identifier_output_method = v || ""
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
# Sets the default quote_identifiers mode for new databases.
|
|
182
|
+
# See Sequel.quote_identifiers=.
|
|
183
|
+
def self.quote_identifiers=(value)
|
|
184
|
+
@@quote_identifiers = value
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# Sets the default single_threaded mode for new databases.
|
|
188
|
+
# See Sequel.single_threaded=.
|
|
189
|
+
def self.single_threaded=(value)
|
|
190
|
+
@@single_threaded = value
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
### Private Class Methods ###
|
|
194
|
+
|
|
195
|
+
# Sets the adapter scheme for the Database class. Call this method in
|
|
196
|
+
# descendnants of Database to allow connection using a URL. For example the
|
|
197
|
+
# following:
|
|
198
|
+
#
|
|
199
|
+
# class Sequel::MyDB::Database < Sequel::Database
|
|
200
|
+
# set_adapter_scheme :mydb
|
|
201
|
+
# ...
|
|
202
|
+
# end
|
|
203
|
+
#
|
|
204
|
+
# would allow connection using:
|
|
205
|
+
#
|
|
206
|
+
# Sequel.connect('mydb://user:password@dbserver/mydb')
|
|
207
|
+
def self.set_adapter_scheme(scheme) # :nodoc:
|
|
208
|
+
@scheme = scheme
|
|
209
|
+
@@adapters[scheme.to_sym] = self
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
# Converts a uri to an options hash. These options are then passed
|
|
213
|
+
# to a newly created database object.
|
|
214
|
+
def self.uri_to_options(uri) # :nodoc:
|
|
215
|
+
{ :user => uri.user,
|
|
216
|
+
:password => uri.password,
|
|
217
|
+
:host => uri.host,
|
|
218
|
+
:port => uri.port,
|
|
219
|
+
:database => (m = /\/(.*)/.match(uri.path)) && (m[1]) }
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
private_class_method :set_adapter_scheme, :uri_to_options
|
|
223
|
+
|
|
224
|
+
### Instance Methods ###
|
|
225
|
+
|
|
226
|
+
# Executes the supplied SQL statement string.
|
|
227
|
+
def <<(sql)
|
|
228
|
+
Deprecation.deprecate('Passing an array argument to Database#<<', 'Use array.each{|x| database << x}') if Array === sql
|
|
229
|
+
execute_ddl((Array === sql) ? sql.to_sql : sql)
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
# Returns a dataset from the database. If the first argument is a string,
|
|
233
|
+
# the method acts as an alias for Database#fetch, returning a dataset for
|
|
234
|
+
# arbitrary SQL:
|
|
235
|
+
#
|
|
236
|
+
# DB['SELECT * FROM items WHERE name = ?', my_name].print
|
|
237
|
+
#
|
|
238
|
+
# Otherwise, acts as an alias for Database#from, setting the primary
|
|
239
|
+
# table for the dataset:
|
|
240
|
+
#
|
|
241
|
+
# DB[:items].sql #=> "SELECT * FROM items"
|
|
242
|
+
def [](*args, &block)
|
|
243
|
+
(String === args.first) ? fetch(*args, &block) : from(*args, &block)
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
# Call the prepared statement with the given name with the given hash
|
|
247
|
+
# of arguments.
|
|
248
|
+
def call(ps_name, hash={})
|
|
249
|
+
prepared_statements[ps_name].call(hash)
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
# Connects to the database. This method should be overridden by descendants.
|
|
253
|
+
def connect
|
|
254
|
+
raise NotImplementedError, "#connect should be overridden by adapters"
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
# Returns a blank dataset
|
|
258
|
+
def dataset
|
|
259
|
+
ds = Sequel::Dataset.new(self)
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
# Disconnects all available connections from the connection pool. If any
|
|
263
|
+
# connections are currently in use, they will not be disconnected.
|
|
264
|
+
def disconnect
|
|
265
|
+
pool.disconnect
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
# Executes the given SQL. This method should be overridden in descendants.
|
|
269
|
+
def execute(sql, opts={})
|
|
270
|
+
raise NotImplementedError, "#execute should be overridden by adapters"
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
# Method that should be used when submitting any DDL (Data Definition
|
|
274
|
+
# Language) SQL. By default, calls execute_dui.
|
|
275
|
+
def execute_ddl(sql, opts={}, &block)
|
|
276
|
+
execute_dui(sql, opts, &block)
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
# Method that should be used when issuing a DELETE, UPDATE, or INSERT
|
|
280
|
+
# statement. By default, calls execute.
|
|
281
|
+
def execute_dui(sql, opts={}, &block)
|
|
282
|
+
execute(sql, opts, &block)
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
# Method that should be used when issuing a INSERT
|
|
286
|
+
# statement. By default, calls execute_dui.
|
|
287
|
+
def execute_insert(sql, opts={}, &block)
|
|
288
|
+
execute_dui(sql, opts, &block)
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
# Fetches records for an arbitrary SQL statement. If a block is given,
|
|
292
|
+
# it is used to iterate over the records:
|
|
293
|
+
#
|
|
294
|
+
# DB.fetch('SELECT * FROM items'){|r| p r}
|
|
295
|
+
#
|
|
296
|
+
# The method returns a dataset instance:
|
|
297
|
+
#
|
|
298
|
+
# DB.fetch('SELECT * FROM items').print
|
|
299
|
+
#
|
|
300
|
+
# Fetch can also perform parameterized queries for protection against SQL
|
|
301
|
+
# injection:
|
|
302
|
+
#
|
|
303
|
+
# DB.fetch('SELECT * FROM items WHERE name = ?', my_name).print
|
|
304
|
+
def fetch(sql, *args, &block)
|
|
305
|
+
ds = dataset.with_sql(sql, *args)
|
|
306
|
+
ds.each(&block) if block
|
|
307
|
+
ds
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
# Returns a new dataset with the from method invoked. If a block is given,
|
|
311
|
+
# it is used as a filter on the dataset.
|
|
312
|
+
def from(*args, &block)
|
|
313
|
+
ds = dataset.from(*args)
|
|
314
|
+
block ? ds.filter(&block) : ds
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
# Returns a single value from the database, e.g.:
|
|
318
|
+
#
|
|
319
|
+
# # SELECT 1
|
|
320
|
+
# DB.get(1) #=> 1
|
|
321
|
+
#
|
|
322
|
+
# # SELECT version()
|
|
323
|
+
# DB.get(:version.sql_function) #=> ...
|
|
324
|
+
def get(*args, &block)
|
|
325
|
+
dataset.get(*args, &block)
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
# The method to call on identifiers going into the database
|
|
329
|
+
def identifier_input_method
|
|
330
|
+
case @identifier_input_method
|
|
331
|
+
when nil
|
|
332
|
+
@identifier_input_method = @opts.include?(:identifier_input_method) ? @opts[:identifier_input_method] : (@@identifier_input_method.nil? ? identifier_input_method_default : @@identifier_input_method)
|
|
333
|
+
@identifier_input_method == "" ? nil : @identifier_input_method
|
|
334
|
+
when ""
|
|
335
|
+
nil
|
|
336
|
+
else
|
|
337
|
+
@identifier_input_method
|
|
338
|
+
end
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
# Set the method to call on identifiers going into the database
|
|
342
|
+
def identifier_input_method=(v)
|
|
343
|
+
reset_schema_utility_dataset
|
|
344
|
+
@identifier_input_method = v || ""
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
# The method to call on identifiers coming from the database
|
|
348
|
+
def identifier_output_method
|
|
349
|
+
case @identifier_output_method
|
|
350
|
+
when nil
|
|
351
|
+
@identifier_output_method = @opts.include?(:identifier_output_method) ? @opts[:identifier_output_method] : (@@identifier_output_method.nil? ? identifier_output_method_default : @@identifier_output_method)
|
|
352
|
+
@identifier_output_method == "" ? nil : @identifier_output_method
|
|
353
|
+
when ""
|
|
354
|
+
nil
|
|
355
|
+
else
|
|
356
|
+
@identifier_output_method
|
|
357
|
+
end
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
# Set the method to call on identifiers coming from the database
|
|
361
|
+
def identifier_output_method=(v)
|
|
362
|
+
reset_schema_utility_dataset
|
|
363
|
+
@identifier_output_method = v || ""
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
# Returns a string representation of the database object including the
|
|
367
|
+
# class name and the connection URI (or the opts if the URI
|
|
368
|
+
# cannot be constructed).
|
|
369
|
+
def inspect
|
|
370
|
+
"#<#{self.class}: #{(uri rescue opts).inspect}>"
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
# Log a message at level info to all loggers. All SQL logging
|
|
374
|
+
# goes through this method.
|
|
375
|
+
def log_info(message, args=nil)
|
|
376
|
+
message = "#{message}; #{args.inspect}" if args
|
|
377
|
+
@loggers.each{|logger| logger.info(message)}
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
# Return the first logger or nil if no loggers are being used.
|
|
381
|
+
# Should only be used for backwards compatibility.
|
|
382
|
+
def logger
|
|
383
|
+
@loggers.first
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
# Replace the array of loggers with the given logger(s).
|
|
387
|
+
def logger=(logger)
|
|
388
|
+
@loggers = Array(logger)
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
# Returns true unless the database is using a single-threaded connection pool.
|
|
392
|
+
def multi_threaded?
|
|
393
|
+
!@single_threaded
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
# Whether to quote identifiers (columns and tables) for this database
|
|
397
|
+
def quote_identifiers=(v)
|
|
398
|
+
reset_schema_utility_dataset
|
|
399
|
+
@quote_identifiers = v
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
# Returns true if the database quotes identifiers.
|
|
403
|
+
def quote_identifiers?
|
|
404
|
+
return @quote_identifiers unless @quote_identifiers.nil?
|
|
405
|
+
@quote_identifiers = @opts.include?(:quote_identifiers) ? @opts[:quote_identifiers] : (@@quote_identifiers.nil? ? quote_identifiers_default : @@quote_identifiers)
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
# Returns a new dataset with the select method invoked.
|
|
409
|
+
def select(*args, &block)
|
|
410
|
+
dataset.select(*args, &block)
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
# Default serial primary key options.
|
|
414
|
+
def serial_primary_key_options
|
|
415
|
+
{:primary_key => true, :type => Integer, :auto_increment => true}
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
# Returns true if the database is using a single-threaded connection pool.
|
|
419
|
+
def single_threaded?
|
|
420
|
+
@single_threaded
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
# Acquires a database connection, yielding it to the passed block.
|
|
424
|
+
def synchronize(server=nil, &block)
|
|
425
|
+
@pool.hold(server || :default, &block)
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
# Returns true if a table with the given name exists. This requires a query
|
|
429
|
+
# to the database unless this database object already has the schema for
|
|
430
|
+
# the given table name.
|
|
431
|
+
def table_exists?(name)
|
|
432
|
+
if @schemas && @schemas[name]
|
|
433
|
+
true
|
|
434
|
+
else
|
|
435
|
+
begin
|
|
436
|
+
from(name).first
|
|
437
|
+
true
|
|
438
|
+
rescue
|
|
439
|
+
false
|
|
440
|
+
end
|
|
441
|
+
end
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
# Attempts to acquire a database connection. Returns true if successful.
|
|
445
|
+
# Will probably raise an error if unsuccessful.
|
|
446
|
+
def test_connection(server=nil)
|
|
447
|
+
synchronize(server){|conn|}
|
|
448
|
+
true
|
|
449
|
+
end
|
|
450
|
+
|
|
451
|
+
# A simple implementation of SQL transactions. Nested transactions are not
|
|
452
|
+
# supported - calling #transaction within a transaction will reuse the
|
|
453
|
+
# current transaction. Should be overridden for databases that support nested
|
|
454
|
+
# transactions.
|
|
455
|
+
def transaction(opts={})
|
|
456
|
+
unless opts.is_a?(Hash)
|
|
457
|
+
Deprecation.deprecate('Passing an argument other than a Hash to Database#transaction', "Use DB.transaction(:server=>#{opts.inspect})")
|
|
458
|
+
opts = {:server=>opts}
|
|
459
|
+
end
|
|
460
|
+
synchronize(opts[:server]) do |conn|
|
|
461
|
+
return yield(conn) if @transactions.include?(Thread.current)
|
|
462
|
+
log_info(begin_transaction_sql)
|
|
463
|
+
conn.execute(begin_transaction_sql)
|
|
464
|
+
begin
|
|
465
|
+
@transactions << Thread.current
|
|
466
|
+
yield(conn)
|
|
467
|
+
rescue Exception => e
|
|
468
|
+
log_info(rollback_transaction_sql)
|
|
469
|
+
conn.execute(rollback_transaction_sql)
|
|
470
|
+
transaction_error(e)
|
|
471
|
+
ensure
|
|
472
|
+
unless e
|
|
473
|
+
log_info(commit_transaction_sql)
|
|
474
|
+
conn.execute(commit_transaction_sql)
|
|
475
|
+
end
|
|
476
|
+
@transactions.delete(Thread.current)
|
|
477
|
+
end
|
|
478
|
+
end
|
|
479
|
+
end
|
|
480
|
+
|
|
481
|
+
# Typecast the value to the given column_type. Can be overridden in
|
|
482
|
+
# adapters to support database specific column types.
|
|
483
|
+
# This method should raise Sequel::Error::InvalidValue if assigned value
|
|
484
|
+
# is invalid.
|
|
485
|
+
def typecast_value(column_type, value)
|
|
486
|
+
return nil if value.nil?
|
|
487
|
+
begin
|
|
488
|
+
case column_type
|
|
489
|
+
when :integer
|
|
490
|
+
Integer(value)
|
|
491
|
+
when :string
|
|
492
|
+
value.to_s
|
|
493
|
+
when :float
|
|
494
|
+
Float(value)
|
|
495
|
+
when :decimal
|
|
496
|
+
case value
|
|
497
|
+
when BigDecimal
|
|
498
|
+
value
|
|
499
|
+
when String, Float
|
|
500
|
+
value.to_d
|
|
501
|
+
when Integer
|
|
502
|
+
value.to_s.to_d
|
|
503
|
+
else
|
|
504
|
+
raise Sequel::Error::InvalidValue, "invalid value for BigDecimal: #{value.inspect}"
|
|
505
|
+
end
|
|
506
|
+
when :boolean
|
|
507
|
+
case value
|
|
508
|
+
when false, 0, "0", /\Af(alse)?\z/i
|
|
509
|
+
false
|
|
510
|
+
else
|
|
511
|
+
blank_object?(value) ? nil : true
|
|
512
|
+
end
|
|
513
|
+
when :date
|
|
514
|
+
case value
|
|
515
|
+
when Date
|
|
516
|
+
value
|
|
517
|
+
when DateTime, Time
|
|
518
|
+
Date.new(value.year, value.month, value.day)
|
|
519
|
+
when String
|
|
520
|
+
Sequel.string_to_date(value)
|
|
521
|
+
else
|
|
522
|
+
raise Sequel::Error::InvalidValue, "invalid value for Date: #{value.inspect}"
|
|
523
|
+
end
|
|
524
|
+
when :time
|
|
525
|
+
case value
|
|
526
|
+
when Time
|
|
527
|
+
value
|
|
528
|
+
when String
|
|
529
|
+
Sequel.string_to_time(value)
|
|
530
|
+
else
|
|
531
|
+
raise Sequel::Error::InvalidValue, "invalid value for Time: #{value.inspect}"
|
|
532
|
+
end
|
|
533
|
+
when :datetime
|
|
534
|
+
raise(Sequel::Error::InvalidValue, "invalid value for Datetime: #{value.inspect}") unless [DateTime, Date, Time, String].any?{|c| value.is_a?(c)}
|
|
535
|
+
if Sequel.datetime_class === value
|
|
536
|
+
# Already the correct class, no need to convert
|
|
537
|
+
value
|
|
538
|
+
else
|
|
539
|
+
# First convert it to standard ISO 8601 time, then
|
|
540
|
+
# parse that string using the time class.
|
|
541
|
+
Sequel.string_to_datetime(Time === value ? value.iso8601 : value.to_s)
|
|
542
|
+
end
|
|
543
|
+
when :blob
|
|
544
|
+
::Sequel::SQL::Blob.new(value)
|
|
545
|
+
else
|
|
546
|
+
value
|
|
547
|
+
end
|
|
548
|
+
rescue ArgumentError => exp
|
|
549
|
+
e = Sequel::Error::InvalidValue.new("#{exp.class} #{exp.message}")
|
|
550
|
+
e.set_backtrace(exp.backtrace)
|
|
551
|
+
raise e
|
|
552
|
+
end
|
|
553
|
+
end
|
|
554
|
+
|
|
555
|
+
# Returns the URI identifying the database.
|
|
556
|
+
# This method can raise an error if the database used options
|
|
557
|
+
# instead of a connection string.
|
|
558
|
+
def uri
|
|
559
|
+
uri = URI::Generic.new(
|
|
560
|
+
self.class.adapter_scheme.to_s,
|
|
561
|
+
nil,
|
|
562
|
+
@opts[:host],
|
|
563
|
+
@opts[:port],
|
|
564
|
+
nil,
|
|
565
|
+
"/#{@opts[:database]}",
|
|
566
|
+
nil,
|
|
567
|
+
nil,
|
|
568
|
+
nil
|
|
569
|
+
)
|
|
570
|
+
uri.user = @opts[:user]
|
|
571
|
+
uri.password = @opts[:password] if uri.user
|
|
572
|
+
uri.to_s
|
|
573
|
+
end
|
|
574
|
+
|
|
575
|
+
# Explicit alias of uri for easier subclassing.
|
|
576
|
+
def url
|
|
577
|
+
uri
|
|
578
|
+
end
|
|
579
|
+
|
|
580
|
+
private
|
|
581
|
+
|
|
582
|
+
# SQL to BEGIN a transaction.
|
|
583
|
+
def begin_transaction_sql
|
|
584
|
+
SQL_BEGIN
|
|
585
|
+
end
|
|
586
|
+
|
|
587
|
+
# Returns true when the object is considered blank.
|
|
588
|
+
# The only objects that are blank are nil, false,
|
|
589
|
+
# strings with all whitespace, and ones that respond
|
|
590
|
+
# true to empty?
|
|
591
|
+
def blank_object?(obj)
|
|
592
|
+
case obj
|
|
593
|
+
when NilClass, FalseClass
|
|
594
|
+
true
|
|
595
|
+
when Numeric, TrueClass
|
|
596
|
+
false
|
|
597
|
+
when String
|
|
598
|
+
obj.strip.empty?
|
|
599
|
+
else
|
|
600
|
+
!obj.respond_to?(:empty?) || obj.empty?
|
|
601
|
+
end
|
|
602
|
+
end
|
|
603
|
+
|
|
604
|
+
# SQL to COMMIT a transaction.
|
|
605
|
+
def commit_transaction_sql
|
|
606
|
+
SQL_COMMIT
|
|
607
|
+
end
|
|
608
|
+
|
|
609
|
+
# The default options for the connection pool.
|
|
610
|
+
def connection_pool_default_options
|
|
611
|
+
{}
|
|
612
|
+
end
|
|
613
|
+
|
|
614
|
+
# The default value for default_schema.
|
|
615
|
+
def default_schema_default
|
|
616
|
+
nil
|
|
617
|
+
end
|
|
618
|
+
|
|
619
|
+
# The method to apply to identifiers going into the database by default.
|
|
620
|
+
# Should be overridden in subclasses for databases that fold unquoted
|
|
621
|
+
# identifiers to lower case instead of uppercase, such as
|
|
622
|
+
# MySQL, PostgreSQL, and SQLite.
|
|
623
|
+
def identifier_input_method_default
|
|
624
|
+
:upcase
|
|
625
|
+
end
|
|
626
|
+
|
|
627
|
+
# The method to apply to identifiers coming the database by default.
|
|
628
|
+
# Should be overridden in subclasses for databases that fold unquoted
|
|
629
|
+
# identifiers to lower case instead of uppercase, such as
|
|
630
|
+
# MySQL, PostgreSQL, and SQLite.
|
|
631
|
+
def identifier_output_method_default
|
|
632
|
+
:downcase
|
|
633
|
+
end
|
|
634
|
+
|
|
635
|
+
def quote_identifiers_default
|
|
636
|
+
true
|
|
637
|
+
end
|
|
638
|
+
|
|
639
|
+
# SQL to ROLLBACK a transaction.
|
|
640
|
+
def rollback_transaction_sql
|
|
641
|
+
SQL_ROLLBACK
|
|
642
|
+
end
|
|
643
|
+
|
|
644
|
+
# Convert the given exception to a DatabaseError, keeping message
|
|
645
|
+
# and traceback.
|
|
646
|
+
def raise_error(exception, opts={})
|
|
647
|
+
if !opts[:classes] || Array(opts[:classes]).any?{|c| exception.is_a?(c)}
|
|
648
|
+
e = DatabaseError.new("#{exception.class} #{exception.message}")
|
|
649
|
+
e.set_backtrace(exception.backtrace)
|
|
650
|
+
raise e
|
|
651
|
+
else
|
|
652
|
+
raise exception
|
|
653
|
+
end
|
|
654
|
+
end
|
|
655
|
+
|
|
656
|
+
# Split the schema information from the table
|
|
657
|
+
def schema_and_table(table_name)
|
|
658
|
+
schema_utility_dataset.schema_and_table(table_name)
|
|
659
|
+
end
|
|
660
|
+
|
|
661
|
+
# Return the options for the given server by merging the generic
|
|
662
|
+
# options for all server with the specific options for the given
|
|
663
|
+
# server specified in the :servers option.
|
|
664
|
+
def server_opts(server)
|
|
665
|
+
opts = if @opts[:servers] && server_options = @opts[:servers][server]
|
|
666
|
+
case server_options
|
|
667
|
+
when Hash
|
|
668
|
+
@opts.merge(server_options)
|
|
669
|
+
when Proc
|
|
670
|
+
@opts.merge(server_options.call(self))
|
|
671
|
+
else
|
|
672
|
+
raise Error, 'Server opts should be a hash or proc'
|
|
673
|
+
end
|
|
674
|
+
else
|
|
675
|
+
@opts.dup
|
|
676
|
+
end
|
|
677
|
+
opts.delete(:servers)
|
|
678
|
+
opts
|
|
679
|
+
end
|
|
680
|
+
|
|
681
|
+
# Raise a database error unless the exception is an Error::Rollback.
|
|
682
|
+
def transaction_error(e, *classes)
|
|
683
|
+
raise_error(e, :classes=>classes) unless Error::Rollback === e
|
|
684
|
+
end
|
|
685
|
+
end
|
|
686
|
+
end
|
|
687
|
+
|