sequel 3.28.0 → 3.29.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +119 -3
- data/Rakefile +5 -3
- data/bin/sequel +1 -5
- data/doc/model_hooks.rdoc +9 -1
- data/doc/opening_databases.rdoc +49 -40
- data/doc/prepared_statements.rdoc +27 -6
- data/doc/release_notes/3.28.0.txt +2 -2
- data/doc/release_notes/3.29.0.txt +459 -0
- data/doc/sharding.rdoc +7 -1
- data/doc/testing.rdoc +18 -9
- data/doc/transactions.rdoc +41 -1
- data/lib/sequel/adapters/ado.rb +28 -17
- data/lib/sequel/adapters/ado/mssql.rb +18 -6
- data/lib/sequel/adapters/amalgalite.rb +11 -7
- data/lib/sequel/adapters/db2.rb +122 -70
- data/lib/sequel/adapters/dbi.rb +15 -15
- data/lib/sequel/adapters/do.rb +5 -36
- data/lib/sequel/adapters/do/mysql.rb +0 -5
- data/lib/sequel/adapters/do/postgres.rb +0 -5
- data/lib/sequel/adapters/do/sqlite.rb +0 -5
- data/lib/sequel/adapters/firebird.rb +3 -6
- data/lib/sequel/adapters/ibmdb.rb +24 -16
- data/lib/sequel/adapters/informix.rb +2 -4
- data/lib/sequel/adapters/jdbc.rb +47 -11
- data/lib/sequel/adapters/jdbc/as400.rb +5 -24
- data/lib/sequel/adapters/jdbc/db2.rb +0 -5
- data/lib/sequel/adapters/jdbc/derby.rb +217 -0
- data/lib/sequel/adapters/jdbc/firebird.rb +0 -5
- data/lib/sequel/adapters/jdbc/h2.rb +10 -12
- data/lib/sequel/adapters/jdbc/hsqldb.rb +166 -0
- data/lib/sequel/adapters/jdbc/informix.rb +0 -5
- data/lib/sequel/adapters/jdbc/jtds.rb +0 -5
- data/lib/sequel/adapters/jdbc/mysql.rb +0 -10
- data/lib/sequel/adapters/jdbc/oracle.rb +70 -3
- data/lib/sequel/adapters/jdbc/postgresql.rb +0 -11
- data/lib/sequel/adapters/jdbc/sqlite.rb +0 -5
- data/lib/sequel/adapters/jdbc/sqlserver.rb +0 -5
- data/lib/sequel/adapters/jdbc/transactions.rb +56 -7
- data/lib/sequel/adapters/mock.rb +315 -0
- data/lib/sequel/adapters/mysql.rb +64 -51
- data/lib/sequel/adapters/mysql2.rb +15 -9
- data/lib/sequel/adapters/odbc.rb +13 -6
- data/lib/sequel/adapters/odbc/db2.rb +0 -4
- data/lib/sequel/adapters/odbc/mssql.rb +0 -5
- data/lib/sequel/adapters/openbase.rb +2 -4
- data/lib/sequel/adapters/oracle.rb +333 -51
- data/lib/sequel/adapters/postgres.rb +80 -27
- data/lib/sequel/adapters/shared/access.rb +0 -6
- data/lib/sequel/adapters/shared/db2.rb +13 -15
- data/lib/sequel/adapters/shared/firebird.rb +6 -6
- data/lib/sequel/adapters/shared/mssql.rb +23 -18
- data/lib/sequel/adapters/shared/mysql.rb +6 -6
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +6 -0
- data/lib/sequel/adapters/shared/oracle.rb +185 -30
- data/lib/sequel/adapters/shared/postgres.rb +35 -18
- data/lib/sequel/adapters/shared/progress.rb +0 -6
- data/lib/sequel/adapters/shared/sqlite.rb +116 -37
- data/lib/sequel/adapters/sqlite.rb +16 -8
- data/lib/sequel/adapters/swift.rb +5 -5
- data/lib/sequel/adapters/swift/mysql.rb +0 -5
- data/lib/sequel/adapters/swift/postgres.rb +0 -5
- data/lib/sequel/adapters/swift/sqlite.rb +6 -4
- data/lib/sequel/adapters/tinytds.rb +13 -10
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +8 -0
- data/lib/sequel/core.rb +40 -0
- data/lib/sequel/database/connecting.rb +1 -2
- data/lib/sequel/database/dataset.rb +3 -3
- data/lib/sequel/database/dataset_defaults.rb +58 -0
- data/lib/sequel/database/misc.rb +62 -2
- data/lib/sequel/database/query.rb +113 -49
- data/lib/sequel/database/schema_methods.rb +7 -2
- data/lib/sequel/dataset/actions.rb +37 -19
- data/lib/sequel/dataset/features.rb +24 -0
- data/lib/sequel/dataset/graph.rb +7 -6
- data/lib/sequel/dataset/misc.rb +11 -3
- data/lib/sequel/dataset/mutation.rb +2 -3
- data/lib/sequel/dataset/prepared_statements.rb +6 -4
- data/lib/sequel/dataset/query.rb +46 -15
- data/lib/sequel/dataset/sql.rb +28 -4
- data/lib/sequel/extensions/named_timezones.rb +5 -0
- data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
- data/lib/sequel/model.rb +2 -1
- data/lib/sequel/model/associations.rb +115 -33
- data/lib/sequel/model/base.rb +91 -31
- data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
- data/lib/sequel/plugins/dataset_associations.rb +100 -0
- data/lib/sequel/plugins/force_encoding.rb +6 -6
- data/lib/sequel/plugins/identity_map.rb +1 -1
- data/lib/sequel/plugins/many_through_many.rb +6 -10
- data/lib/sequel/plugins/prepared_statements.rb +12 -1
- data/lib/sequel/plugins/prepared_statements_associations.rb +1 -1
- data/lib/sequel/plugins/rcte_tree.rb +29 -15
- data/lib/sequel/plugins/serialization.rb +6 -1
- data/lib/sequel/plugins/sharding.rb +0 -5
- data/lib/sequel/plugins/single_table_inheritance.rb +1 -1
- data/lib/sequel/plugins/typecast_on_load.rb +9 -12
- data/lib/sequel/plugins/update_primary_key.rb +1 -1
- data/lib/sequel/timezones.rb +42 -42
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mssql_spec.rb +29 -29
- data/spec/adapters/mysql_spec.rb +86 -104
- data/spec/adapters/oracle_spec.rb +48 -76
- data/spec/adapters/postgres_spec.rb +98 -33
- data/spec/adapters/spec_helper.rb +0 -5
- data/spec/adapters/sqlite_spec.rb +24 -21
- data/spec/core/connection_pool_spec.rb +9 -15
- data/spec/core/core_sql_spec.rb +20 -31
- data/spec/core/database_spec.rb +491 -227
- data/spec/core/dataset_spec.rb +638 -1051
- data/spec/core/expression_filters_spec.rb +0 -1
- data/spec/core/mock_adapter_spec.rb +378 -0
- data/spec/core/object_graph_spec.rb +48 -114
- data/spec/core/schema_generator_spec.rb +3 -3
- data/spec/core/schema_spec.rb +51 -114
- data/spec/core/spec_helper.rb +3 -90
- data/spec/extensions/class_table_inheritance_spec.rb +1 -1
- data/spec/extensions/dataset_associations_spec.rb +199 -0
- data/spec/extensions/instance_hooks_spec.rb +71 -0
- data/spec/extensions/named_timezones_spec.rb +22 -2
- data/spec/extensions/nested_attributes_spec.rb +3 -0
- data/spec/extensions/schema_spec.rb +1 -1
- data/spec/extensions/serialization_modification_detection_spec.rb +1 -0
- data/spec/extensions/serialization_spec.rb +5 -8
- data/spec/extensions/spec_helper.rb +4 -0
- data/spec/extensions/thread_local_timezones_spec.rb +22 -2
- data/spec/extensions/typecast_on_load_spec.rb +1 -6
- data/spec/integration/associations_test.rb +123 -12
- data/spec/integration/dataset_test.rb +140 -47
- data/spec/integration/eager_loader_test.rb +19 -21
- data/spec/integration/model_test.rb +80 -1
- data/spec/integration/plugin_test.rb +179 -128
- data/spec/integration/prepared_statement_test.rb +92 -91
- data/spec/integration/schema_test.rb +42 -23
- data/spec/integration/spec_helper.rb +25 -31
- data/spec/integration/timezone_test.rb +38 -12
- data/spec/integration/transaction_test.rb +161 -34
- data/spec/integration/type_test.rb +3 -3
- data/spec/model/association_reflection_spec.rb +83 -7
- data/spec/model/associations_spec.rb +393 -676
- data/spec/model/base_spec.rb +186 -116
- data/spec/model/dataset_methods_spec.rb +7 -27
- data/spec/model/eager_loading_spec.rb +343 -867
- data/spec/model/hooks_spec.rb +160 -79
- data/spec/model/model_spec.rb +118 -165
- data/spec/model/plugins_spec.rb +7 -13
- data/spec/model/record_spec.rb +138 -207
- data/spec/model/spec_helper.rb +10 -73
- metadata +14 -8
@@ -9,11 +9,6 @@ module Sequel
|
|
9
9
|
module DatabaseMethods
|
10
10
|
include Sequel::Informix::DatabaseMethods
|
11
11
|
|
12
|
-
# Return instance of Sequel::JDBC::Informix::Dataset with the given opts.
|
13
|
-
def dataset(opts=nil)
|
14
|
-
Sequel::JDBC::Informix::Dataset.new(self, opts)
|
15
|
-
end
|
16
|
-
|
17
12
|
private
|
18
13
|
|
19
14
|
# TODO: implement
|
@@ -8,11 +8,6 @@ module Sequel
|
|
8
8
|
# Database instance methods for JTDS databases accessed via JDBC.
|
9
9
|
module DatabaseMethods
|
10
10
|
include Sequel::JDBC::MSSQL::DatabaseMethods
|
11
|
-
|
12
|
-
# Return instance of Sequel::JDBC::JTDS::Dataset with the given opts.
|
13
|
-
def dataset(opts=nil)
|
14
|
-
Sequel::JDBC::JTDS::Dataset.new(self, opts)
|
15
|
-
end
|
16
11
|
end
|
17
12
|
|
18
13
|
# Dataset class for JTDS datasets accessed via JDBC.
|
@@ -9,11 +9,6 @@ module Sequel
|
|
9
9
|
module DatabaseMethods
|
10
10
|
include Sequel::MySQL::DatabaseMethods
|
11
11
|
|
12
|
-
# Return instance of Sequel::JDBC::MySQL::Dataset with the given opts.
|
13
|
-
def dataset(opts=nil)
|
14
|
-
Sequel::JDBC::MySQL::Dataset.new(self, opts)
|
15
|
-
end
|
16
|
-
|
17
12
|
private
|
18
13
|
|
19
14
|
# The database name for the given database. Need to parse it out
|
@@ -71,11 +66,6 @@ module Sequel
|
|
71
66
|
class Dataset < JDBC::Dataset
|
72
67
|
include Sequel::MySQL::DatasetMethods
|
73
68
|
|
74
|
-
# Use execute_insert to execute the insert_sql.
|
75
|
-
def insert(*values)
|
76
|
-
execute_insert(insert_sql(*values))
|
77
|
-
end
|
78
|
-
|
79
69
|
# Use execute_insert to execute the replace_sql.
|
80
70
|
def replace(*args)
|
81
71
|
execute_insert(replace_sql(*args))
|
@@ -9,16 +9,83 @@ module Sequel
|
|
9
9
|
module DatabaseMethods
|
10
10
|
include Sequel::Oracle::DatabaseMethods
|
11
11
|
include Sequel::JDBC::Transactions
|
12
|
+
|
13
|
+
def self.extended(db)
|
14
|
+
db.instance_eval do
|
15
|
+
@autosequence = opts[:autosequence]
|
16
|
+
@primary_key_sequences = {}
|
17
|
+
end
|
18
|
+
end
|
12
19
|
|
13
|
-
|
14
|
-
|
15
|
-
|
20
|
+
private
|
21
|
+
|
22
|
+
def last_insert_id(conn, opts)
|
23
|
+
unless sequence = opts[:sequence]
|
24
|
+
if t = opts[:table]
|
25
|
+
sequence = sequence_for_table(t)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
if sequence
|
29
|
+
sql = "SELECT #{literal(sequence)}.currval FROM dual"
|
30
|
+
statement(conn) do |stmt|
|
31
|
+
begin
|
32
|
+
rs = log_yield(sql){stmt.executeQuery(sql)}
|
33
|
+
rs.next
|
34
|
+
rs.getInt(1)
|
35
|
+
rescue java.sql.SQLException
|
36
|
+
nil
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def schema_parse_table(*)
|
43
|
+
sch = super
|
44
|
+
sch.each do |c, s|
|
45
|
+
if s[:type] == :decimal && s[:scale] == -127
|
46
|
+
s[:type] = :integer
|
47
|
+
elsif s[:db_type] == 'DATE'
|
48
|
+
s[:type] = :datetime
|
49
|
+
end
|
50
|
+
end
|
51
|
+
sch
|
52
|
+
end
|
53
|
+
|
54
|
+
def schema_parse_table_skip?(h, schema)
|
55
|
+
super || (h[:table_schem] != current_user unless schema)
|
56
|
+
end
|
57
|
+
|
58
|
+
# As of Oracle 9.2, releasing savepoints is no longer supported.
|
59
|
+
def supports_releasing_savepoints?
|
60
|
+
false
|
16
61
|
end
|
17
62
|
end
|
18
63
|
|
19
64
|
# Dataset class for Oracle datasets accessed via JDBC.
|
20
65
|
class Dataset < JDBC::Dataset
|
21
66
|
include Sequel::Oracle::DatasetMethods
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def convert_type(v)
|
71
|
+
case v
|
72
|
+
when Java::JavaMath::BigDecimal
|
73
|
+
if v.scale == 0
|
74
|
+
i = v.long_value
|
75
|
+
if v.equals(Java::JavaMath::BigDecimal.new(i))
|
76
|
+
i
|
77
|
+
else
|
78
|
+
super
|
79
|
+
end
|
80
|
+
else
|
81
|
+
super
|
82
|
+
end
|
83
|
+
when Java::OracleSql::TIMESTAMP
|
84
|
+
db.to_application_timestamp(v.to_string)
|
85
|
+
else
|
86
|
+
super
|
87
|
+
end
|
88
|
+
end
|
22
89
|
end
|
23
90
|
end
|
24
91
|
end
|
@@ -47,17 +47,6 @@ module Sequel
|
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
|
-
# Return instance of Sequel::JDBC::Postgres::Dataset with the given opts.
|
51
|
-
def dataset(opts=nil)
|
52
|
-
Sequel::JDBC::Postgres::Dataset.new(self, opts)
|
53
|
-
end
|
54
|
-
|
55
|
-
# Run the INSERT sql on the database and return the primary key
|
56
|
-
# for the record.
|
57
|
-
def execute_insert(sql, opts={})
|
58
|
-
super(sql, {:type=>:insert}.merge(opts))
|
59
|
-
end
|
60
|
-
|
61
50
|
private
|
62
51
|
|
63
52
|
# Use setNull for nil arguments as the default behavior of setString
|
@@ -8,11 +8,6 @@ module Sequel
|
|
8
8
|
module DatabaseMethods
|
9
9
|
include Sequel::SQLite::DatabaseMethods
|
10
10
|
|
11
|
-
# Return Sequel::JDBC::SQLite::Dataset object with the given opts.
|
12
|
-
def dataset(opts=nil)
|
13
|
-
Sequel::JDBC::SQLite::Dataset.new(self, opts)
|
14
|
-
end
|
15
|
-
|
16
11
|
private
|
17
12
|
|
18
13
|
# Use last_insert_rowid() to get the last inserted id.
|
@@ -9,11 +9,6 @@ module Sequel
|
|
9
9
|
module DatabaseMethods
|
10
10
|
include Sequel::JDBC::MSSQL::DatabaseMethods
|
11
11
|
|
12
|
-
# Return instance of Sequel::JDBC::SQLServer::Dataset with the given opts.
|
13
|
-
def dataset(opts=nil)
|
14
|
-
Sequel::JDBC::SQLServer::Dataset.new(self, opts)
|
15
|
-
end
|
16
|
-
|
17
12
|
def metadata_dataset
|
18
13
|
ds = super
|
19
14
|
# Work around a bug in SQL Server JDBC Driver 3.0, where the metadata
|
@@ -3,30 +3,79 @@ module Sequel
|
|
3
3
|
module Transactions
|
4
4
|
TRANSACTION_BEGIN = 'Transaction.begin'.freeze
|
5
5
|
TRANSACTION_COMMIT = 'Transaction.commit'.freeze
|
6
|
+
TRANSACTION_RELEASE_SP = 'Transaction.release_savepoint'.freeze
|
6
7
|
TRANSACTION_ROLLBACK = 'Transaction.rollback'.freeze
|
8
|
+
TRANSACTION_ROLLBACK_SP = 'Transaction.rollback_savepoint'.freeze
|
9
|
+
TRANSACTION_SAVEPOINT= 'Transaction.savepoint'.freeze
|
10
|
+
|
11
|
+
# Check the JDBC DatabaseMetaData for savepoint support
|
12
|
+
def supports_savepoints?
|
13
|
+
return @supports_savepoints if defined?(@supports_savepoints)
|
14
|
+
@supports_savepoints = synchronize{|c| c.get_meta_data.supports_savepoints}
|
15
|
+
end
|
7
16
|
|
8
17
|
private
|
9
18
|
|
19
|
+
# Most JDBC drivers that support savepoints support releasing them.
|
20
|
+
def supports_releasing_savepoints?
|
21
|
+
true
|
22
|
+
end
|
23
|
+
|
10
24
|
# Use JDBC connection's setAutoCommit to false to start transactions
|
11
25
|
def begin_transaction(conn, opts={})
|
12
|
-
|
13
|
-
|
26
|
+
if supports_savepoints?
|
27
|
+
th = @transactions[conn]
|
28
|
+
if sps = th[:savepoints]
|
29
|
+
sps << log_yield(TRANSACTION_SAVEPOINT){conn.set_savepoint}
|
30
|
+
else
|
31
|
+
log_yield(TRANSACTION_BEGIN){conn.setAutoCommit(false)}
|
32
|
+
th[:savepoints] = []
|
33
|
+
end
|
34
|
+
th[:savepoint_level] += 1
|
35
|
+
else
|
36
|
+
log_yield(TRANSACTION_BEGIN){conn.setAutoCommit(false)}
|
37
|
+
end
|
14
38
|
end
|
15
39
|
|
16
40
|
# Use JDBC connection's commit method to commit transactions
|
17
41
|
def commit_transaction(conn, opts={})
|
18
|
-
|
42
|
+
if supports_savepoints?
|
43
|
+
sps = @transactions[conn][:savepoints]
|
44
|
+
if sps.empty?
|
45
|
+
log_yield(TRANSACTION_COMMIT){conn.commit}
|
46
|
+
elsif supports_releasing_savepoints?
|
47
|
+
log_yield(TRANSACTION_RELEASE_SP){supports_releasing_savepoints? ? conn.release_savepoint(sps.last) : sps.last}
|
48
|
+
end
|
49
|
+
else
|
50
|
+
log_yield(TRANSACTION_COMMIT){conn.commit}
|
51
|
+
end
|
19
52
|
end
|
20
53
|
|
21
54
|
# Use JDBC connection's setAutoCommit to true to enable non-transactional behavior
|
22
|
-
def remove_transaction(conn)
|
23
|
-
|
24
|
-
|
55
|
+
def remove_transaction(conn, committed)
|
56
|
+
if supports_savepoints?
|
57
|
+
sps = @transactions[conn][:savepoints]
|
58
|
+
conn.setAutoCommit(true) if sps.empty?
|
59
|
+
sps.pop
|
60
|
+
else
|
61
|
+
conn.setAutoCommit(true)
|
62
|
+
end
|
63
|
+
ensure
|
64
|
+
super
|
25
65
|
end
|
26
66
|
|
27
67
|
# Use JDBC connection's rollback method to rollback transactions
|
28
68
|
def rollback_transaction(conn, opts={})
|
29
|
-
|
69
|
+
if supports_savepoints?
|
70
|
+
sps = @transactions[conn][:savepoints]
|
71
|
+
if sps.empty?
|
72
|
+
log_yield(TRANSACTION_ROLLBACK){conn.rollback}
|
73
|
+
else
|
74
|
+
log_yield(TRANSACTION_ROLLBACK_SP){conn.rollback(sps.last)}
|
75
|
+
end
|
76
|
+
else
|
77
|
+
log_yield(TRANSACTION_ROLLBACK){conn.rollback}
|
78
|
+
end
|
30
79
|
end
|
31
80
|
end
|
32
81
|
end
|
@@ -0,0 +1,315 @@
|
|
1
|
+
module Sequel
|
2
|
+
module Mock
|
3
|
+
# Connection class for Sequel's mock adapter.
|
4
|
+
class Connection
|
5
|
+
# Sequel::Mock::Database object that created this connection
|
6
|
+
attr_reader :db
|
7
|
+
|
8
|
+
# Shard this connection operates on, when using Sequel's
|
9
|
+
# sharding support (always :default for databases not using
|
10
|
+
# sharding).
|
11
|
+
attr_reader :server
|
12
|
+
|
13
|
+
# The specific database options for this connection.
|
14
|
+
attr_reader :opts
|
15
|
+
|
16
|
+
# Store the db, server, and opts.
|
17
|
+
def initialize(db, server, opts)
|
18
|
+
@db = db
|
19
|
+
@server = server
|
20
|
+
@opts = opts
|
21
|
+
end
|
22
|
+
|
23
|
+
# Delegate to the db's #_execute method.
|
24
|
+
def execute(sql)
|
25
|
+
@db.send(:_execute, self, sql)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Database class for Sequel's mock adapter.
|
30
|
+
class Database < Sequel::Database
|
31
|
+
set_adapter_scheme :mock
|
32
|
+
|
33
|
+
# Set the autogenerated primary key integer
|
34
|
+
# to be returned when running an insert query.
|
35
|
+
# Argument types supported:
|
36
|
+
#
|
37
|
+
# nil :: Return nil for all inserts
|
38
|
+
# Integer :: Starting integer for next insert, with
|
39
|
+
# futher inserts getting an incremented
|
40
|
+
# value
|
41
|
+
# Array :: First insert gets the first value in the
|
42
|
+
# array, second gets the second value, etc.
|
43
|
+
# Proc :: Called with the insert SQL query, uses
|
44
|
+
# the value returned
|
45
|
+
# Class :: Should be an Exception subclass, will create a new
|
46
|
+
# instance an raise it wrapped in a DatabaseError.
|
47
|
+
attr_writer :autoid
|
48
|
+
|
49
|
+
# Set the columns to set in the dataset when the dataset fetches
|
50
|
+
# rows. Argument types supported:
|
51
|
+
# nil :: Set no columns
|
52
|
+
# Array of Symbols: Used for all datasets
|
53
|
+
# Array (otherwise): First retrieval gets the first value in the
|
54
|
+
# array, second gets the second value, etc.
|
55
|
+
# Proc :: Called with the select SQL query, uses the value
|
56
|
+
# returned, which should be an array of symbols
|
57
|
+
attr_writer :columns
|
58
|
+
|
59
|
+
# Set the hashes to yield by execute when retrieving rows.
|
60
|
+
# Argument types supported:
|
61
|
+
#
|
62
|
+
# nil :: Yield no rows
|
63
|
+
# Hash :: Always yield a single row with this hash
|
64
|
+
# Array of Hashes :: Yield separately for each hash in this array
|
65
|
+
# Array (otherwise) :: First retrieval gets the first value
|
66
|
+
# in the array, second gets the second value, etc.
|
67
|
+
# Proc :: Called with the select SQL query, uses
|
68
|
+
# the value returned, which should be a hash or
|
69
|
+
# array of hashes.
|
70
|
+
# Class :: Should be an Exception subclass, will create a new
|
71
|
+
# instance an raise it wrapped in a DatabaseError.
|
72
|
+
attr_writer :fetch
|
73
|
+
|
74
|
+
# Set the number of rows to return from update or delete.
|
75
|
+
# Argument types supported:
|
76
|
+
#
|
77
|
+
# nil :: Return 0 for all updates and deletes
|
78
|
+
# Integer :: Used for all updates and deletes
|
79
|
+
# Array :: First update/delete gets the first value in the
|
80
|
+
# array, second gets the second value, etc.
|
81
|
+
# Proc :: Called with the update/delete SQL query, uses
|
82
|
+
# the value returned.
|
83
|
+
# Class :: Should be an Exception subclass, will create a new
|
84
|
+
# instance an raise it wrapped in a DatabaseError.
|
85
|
+
attr_writer :numrows
|
86
|
+
|
87
|
+
# Additional options supported:
|
88
|
+
#
|
89
|
+
# :autoid :: Call #autoid= with the value
|
90
|
+
# :columns :: Call #columns= with the value
|
91
|
+
# :fetch :: Call #fetch= with the value
|
92
|
+
# :numrows :: Call #numrows= with the value
|
93
|
+
# :extend :: A module the object is extended with.
|
94
|
+
# :sqls :: The array to store the SQL queries in.
|
95
|
+
def initialize(opts=nil)
|
96
|
+
super
|
97
|
+
self.autoid = opts[:autoid]
|
98
|
+
self.columns = opts[:columns]
|
99
|
+
self.fetch = opts[:fetch]
|
100
|
+
self.numrows = opts[:numrows]
|
101
|
+
extend(opts[:extend]) if opts[:extend]
|
102
|
+
@sqls = opts[:sqls] || []
|
103
|
+
end
|
104
|
+
|
105
|
+
# Return a related Connection option connecting to the given shard.
|
106
|
+
def connect(server)
|
107
|
+
Connection.new(self, server, server_opts(server))
|
108
|
+
end
|
109
|
+
|
110
|
+
# Store the sql used for later retrieval with #sqls, and return
|
111
|
+
# the appropriate value using either the #autoid, #fetch, or
|
112
|
+
# #numrows methods.
|
113
|
+
def execute(sql, opts={}, &block)
|
114
|
+
synchronize(opts[:server]){|c| _execute(c, sql, opts, &block)}
|
115
|
+
end
|
116
|
+
alias execute_ddl execute
|
117
|
+
|
118
|
+
# Store the sql used, and return the value of the #numrows method.
|
119
|
+
def execute_dui(sql, opts={})
|
120
|
+
execute(sql, opts.merge(:meth=>:numrows))
|
121
|
+
end
|
122
|
+
|
123
|
+
# Store the sql used, and return the value of the #autoid method.
|
124
|
+
def execute_insert(sql, opts={})
|
125
|
+
execute(sql, opts.merge(:meth=>:autoid))
|
126
|
+
end
|
127
|
+
|
128
|
+
# Return all stored SQL queries, and clear the cache
|
129
|
+
# of SQL queries.
|
130
|
+
def sqls
|
131
|
+
s = @sqls.dup
|
132
|
+
@sqls.clear
|
133
|
+
s
|
134
|
+
end
|
135
|
+
|
136
|
+
# Enable use of savepoints.
|
137
|
+
def supports_savepoints?
|
138
|
+
true
|
139
|
+
end
|
140
|
+
|
141
|
+
private
|
142
|
+
|
143
|
+
def _autoid(sql, v, ds=nil)
|
144
|
+
case v
|
145
|
+
when Integer
|
146
|
+
if ds
|
147
|
+
ds.autoid += 1 if ds.autoid.is_a?(Integer)
|
148
|
+
else
|
149
|
+
@autoid += 1
|
150
|
+
end
|
151
|
+
v
|
152
|
+
else
|
153
|
+
_nextres(v, sql, nil)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def _execute(c, sql, opts={}, &block)
|
158
|
+
sql += " -- args: #{opts[:arguments].inspect}" if opts[:arguments]
|
159
|
+
sql += " -- #{@opts[:append]}" if @opts[:append]
|
160
|
+
sql += " -- #{c.server}" if c.server != :default
|
161
|
+
log_info(sql)
|
162
|
+
@sqls << sql
|
163
|
+
|
164
|
+
ds = opts[:dataset]
|
165
|
+
begin
|
166
|
+
if block
|
167
|
+
columns(ds, sql) if ds
|
168
|
+
_fetch(sql, ds._fetch || @fetch, &block)
|
169
|
+
elsif meth = opts[:meth]
|
170
|
+
if meth == :numrows
|
171
|
+
_numrows(sql, ds.numrows || @numrows)
|
172
|
+
else
|
173
|
+
v = ds.autoid
|
174
|
+
_autoid(sql, v || @autoid, (ds if v))
|
175
|
+
end
|
176
|
+
end
|
177
|
+
rescue => e
|
178
|
+
raise_error(e)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def _fetch(sql, f, &block)
|
183
|
+
case f
|
184
|
+
when Hash
|
185
|
+
yield f.dup
|
186
|
+
when Array
|
187
|
+
if f.all?{|h| h.is_a?(Hash)}
|
188
|
+
f.each{|h| yield h.dup}
|
189
|
+
else
|
190
|
+
_fetch(sql, f.shift, &block)
|
191
|
+
end
|
192
|
+
when Proc
|
193
|
+
h = f.call(sql)
|
194
|
+
if h.is_a?(Hash)
|
195
|
+
yield h.dup
|
196
|
+
elsif h
|
197
|
+
h.each{|h1| yield h1.dup}
|
198
|
+
end
|
199
|
+
when Class
|
200
|
+
if f < Exception
|
201
|
+
raise f
|
202
|
+
else
|
203
|
+
raise Error, "Invalid @autoid/@numrows attribute: #{v.inspect}"
|
204
|
+
end
|
205
|
+
when nil
|
206
|
+
# nothing
|
207
|
+
else
|
208
|
+
raise Error, "Invalid @fetch attribute: #{f.inspect}"
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
def _nextres(v, sql, default)
|
213
|
+
case v
|
214
|
+
when Integer
|
215
|
+
v
|
216
|
+
when Array
|
217
|
+
v.empty? ? default : _nextres(v.shift, sql, default)
|
218
|
+
when Proc
|
219
|
+
v.call(sql)
|
220
|
+
when Class
|
221
|
+
if v < Exception
|
222
|
+
raise v
|
223
|
+
else
|
224
|
+
raise Error, "Invalid @autoid/@numrows attribute: #{v.inspect}"
|
225
|
+
end
|
226
|
+
when nil
|
227
|
+
default
|
228
|
+
else
|
229
|
+
raise Error, "Invalid @autoid/@numrows attribute: #{v.inspect}"
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
def _numrows(sql, v)
|
234
|
+
_nextres(v, sql, 0)
|
235
|
+
end
|
236
|
+
|
237
|
+
def columns(ds, sql, cs=@columns)
|
238
|
+
case cs
|
239
|
+
when Array
|
240
|
+
unless cs.empty?
|
241
|
+
if cs.all?{|c| c.is_a?(Symbol)}
|
242
|
+
ds.columns(*cs)
|
243
|
+
else
|
244
|
+
columns(ds, sql, cs.shift)
|
245
|
+
end
|
246
|
+
end
|
247
|
+
when Proc
|
248
|
+
ds.columns(*cs.call(sql))
|
249
|
+
when nil
|
250
|
+
# nothing
|
251
|
+
else
|
252
|
+
raise Error, "Invalid @columns attribute: #{cs.inspect}"
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
def disconnect_connection(c)
|
257
|
+
end
|
258
|
+
|
259
|
+
def quote_identifiers_default
|
260
|
+
false
|
261
|
+
end
|
262
|
+
|
263
|
+
def identifier_input_method_default
|
264
|
+
nil
|
265
|
+
end
|
266
|
+
|
267
|
+
def identifier_input_method_default
|
268
|
+
nil
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
class Dataset < Sequel::Dataset
|
273
|
+
Database::DatasetClass = self
|
274
|
+
|
275
|
+
# Override the databases's autoid setting for this dataset
|
276
|
+
attr_accessor :autoid
|
277
|
+
|
278
|
+
# Override the databases's fetch setting for this dataset
|
279
|
+
attr_accessor :_fetch
|
280
|
+
|
281
|
+
# Override the databases's numrows setting for this dataset
|
282
|
+
attr_accessor :numrows
|
283
|
+
|
284
|
+
# If arguments are provided, use them to set the columns
|
285
|
+
# for this dataset and return self. Otherwise, use the
|
286
|
+
# default Sequel behavior and return the columns.
|
287
|
+
def columns(*cs)
|
288
|
+
if cs.empty?
|
289
|
+
super
|
290
|
+
else
|
291
|
+
@columns = cs
|
292
|
+
self
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
def fetch_rows(sql, &block)
|
297
|
+
execute(sql, &block)
|
298
|
+
end
|
299
|
+
|
300
|
+
private
|
301
|
+
|
302
|
+
def execute(sql, opts={}, &block)
|
303
|
+
super(sql, opts.merge(:dataset=>self), &block)
|
304
|
+
end
|
305
|
+
|
306
|
+
def execute_dui(sql, opts={}, &block)
|
307
|
+
super(sql, opts.merge(:dataset=>self), &block)
|
308
|
+
end
|
309
|
+
|
310
|
+
def execute_insert(sql, opts={}, &block)
|
311
|
+
super(sql, opts.merge(:dataset=>self), &block)
|
312
|
+
end
|
313
|
+
end
|
314
|
+
end
|
315
|
+
end
|