sequel 3.21.0 → 3.28.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 +294 -0
- data/README.rdoc +20 -6
- data/Rakefile +20 -15
- data/doc/association_basics.rdoc +210 -43
- data/doc/dataset_basics.rdoc +4 -4
- data/doc/mass_assignment.rdoc +54 -0
- data/doc/migration.rdoc +15 -538
- data/doc/model_hooks.rdoc +64 -27
- data/doc/opening_databases.rdoc +37 -10
- data/doc/prepared_statements.rdoc +16 -10
- data/doc/reflection.rdoc +8 -2
- 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/schema_modification.rdoc +547 -0
- data/doc/testing.rdoc +106 -0
- data/doc/transactions.rdoc +97 -0
- data/doc/virtual_rows.rdoc +2 -2
- data/lib/sequel/adapters/ado.rb +12 -1
- data/lib/sequel/adapters/amalgalite.rb +4 -0
- data/lib/sequel/adapters/db2.rb +95 -58
- data/lib/sequel/adapters/do.rb +12 -0
- data/lib/sequel/adapters/firebird.rb +25 -203
- data/lib/sequel/adapters/ibmdb.rb +440 -0
- data/lib/sequel/adapters/informix.rb +4 -19
- data/lib/sequel/adapters/jdbc/as400.rb +0 -7
- data/lib/sequel/adapters/jdbc/db2.rb +49 -0
- data/lib/sequel/adapters/jdbc/firebird.rb +34 -0
- data/lib/sequel/adapters/jdbc/h2.rb +16 -5
- data/lib/sequel/adapters/jdbc/informix.rb +31 -0
- data/lib/sequel/adapters/jdbc/jtds.rb +34 -0
- data/lib/sequel/adapters/jdbc/mssql.rb +0 -32
- data/lib/sequel/adapters/jdbc/mysql.rb +9 -0
- data/lib/sequel/adapters/jdbc/oracle.rb +2 -27
- data/lib/sequel/adapters/jdbc/postgresql.rb +6 -0
- data/lib/sequel/adapters/jdbc/sqlserver.rb +46 -0
- data/lib/sequel/adapters/jdbc/transactions.rb +34 -0
- data/lib/sequel/adapters/jdbc.rb +62 -29
- data/lib/sequel/adapters/mysql.rb +22 -139
- data/lib/sequel/adapters/mysql2.rb +9 -14
- data/lib/sequel/adapters/odbc/db2.rb +21 -0
- data/lib/sequel/adapters/odbc.rb +15 -3
- data/lib/sequel/adapters/oracle.rb +17 -1
- data/lib/sequel/adapters/postgres.rb +111 -16
- data/lib/sequel/adapters/shared/access.rb +21 -0
- data/lib/sequel/adapters/shared/db2.rb +290 -0
- data/lib/sequel/adapters/shared/firebird.rb +214 -0
- data/lib/sequel/adapters/shared/informix.rb +45 -0
- data/lib/sequel/adapters/shared/mssql.rb +85 -47
- data/lib/sequel/adapters/shared/mysql.rb +50 -7
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +143 -0
- data/lib/sequel/adapters/shared/oracle.rb +0 -4
- data/lib/sequel/adapters/shared/postgres.rb +75 -43
- data/lib/sequel/adapters/shared/sqlite.rb +56 -8
- data/lib/sequel/adapters/sqlite.rb +12 -11
- data/lib/sequel/adapters/swift/mysql.rb +9 -0
- data/lib/sequel/adapters/tinytds.rb +139 -7
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +55 -0
- data/lib/sequel/ast_transformer.rb +190 -0
- data/lib/sequel/connection_pool/threaded.rb +3 -2
- data/lib/sequel/connection_pool.rb +1 -1
- data/lib/sequel/core.rb +6 -5
- data/lib/sequel/database/connecting.rb +5 -5
- data/lib/sequel/database/dataset.rb +1 -1
- data/lib/sequel/database/dataset_defaults.rb +1 -1
- data/lib/sequel/database/logging.rb +1 -1
- data/lib/sequel/database/misc.rb +38 -17
- data/lib/sequel/database/query.rb +50 -19
- data/lib/sequel/database/schema_generator.rb +8 -5
- data/lib/sequel/database/schema_methods.rb +52 -27
- data/lib/sequel/dataset/actions.rb +167 -48
- data/lib/sequel/dataset/features.rb +57 -8
- data/lib/sequel/dataset/graph.rb +1 -1
- data/lib/sequel/dataset/misc.rb +39 -20
- data/lib/sequel/dataset/mutation.rb +3 -3
- data/lib/sequel/dataset/prepared_statements.rb +29 -14
- data/lib/sequel/dataset/query.rb +182 -32
- data/lib/sequel/dataset/sql.rb +31 -58
- data/lib/sequel/dataset.rb +8 -0
- data/lib/sequel/exceptions.rb +4 -0
- data/lib/sequel/extensions/columns_introspection.rb +61 -0
- data/lib/sequel/extensions/migration.rb +6 -4
- data/lib/sequel/extensions/to_dot.rb +95 -83
- data/lib/sequel/model/associations.rb +893 -309
- data/lib/sequel/model/base.rb +302 -105
- data/lib/sequel/model/errors.rb +1 -1
- data/lib/sequel/model/exceptions.rb +5 -1
- data/lib/sequel/model.rb +13 -7
- data/lib/sequel/plugins/association_pks.rb +22 -4
- data/lib/sequel/plugins/defaults_setter.rb +58 -0
- data/lib/sequel/plugins/identity_map.rb +113 -6
- data/lib/sequel/plugins/many_through_many.rb +67 -5
- data/lib/sequel/plugins/prepared_statements.rb +140 -0
- data/lib/sequel/plugins/prepared_statements_associations.rb +84 -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/serialization_modification_detection.rb +51 -0
- data/lib/sequel/plugins/sharding.rb +12 -20
- data/lib/sequel/plugins/single_table_inheritance.rb +2 -0
- data/lib/sequel/plugins/update_primary_key.rb +1 -1
- data/lib/sequel/plugins/xml_serializer.rb +3 -3
- data/lib/sequel/sql.rb +107 -51
- data/lib/sequel/timezones.rb +12 -3
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/db2_spec.rb +146 -0
- data/spec/adapters/mssql_spec.rb +36 -0
- data/spec/adapters/mysql_spec.rb +36 -19
- data/spec/adapters/postgres_spec.rb +115 -28
- data/spec/adapters/spec_helper.rb +6 -0
- data/spec/adapters/sqlite_spec.rb +11 -0
- data/spec/core/connection_pool_spec.rb +62 -77
- data/spec/core/database_spec.rb +244 -287
- data/spec/core/dataset_spec.rb +383 -34
- data/spec/core/expression_filters_spec.rb +159 -41
- data/spec/core/schema_spec.rb +326 -3
- data/spec/core/spec_helper.rb +45 -0
- data/spec/extensions/association_pks_spec.rb +38 -0
- data/spec/extensions/columns_introspection_spec.rb +91 -0
- data/spec/extensions/defaults_setter_spec.rb +64 -0
- data/spec/extensions/identity_map_spec.rb +162 -0
- data/spec/extensions/many_through_many_spec.rb +195 -20
- data/spec/extensions/migration_spec.rb +17 -17
- data/spec/extensions/nested_attributes_spec.rb +1 -0
- data/spec/extensions/prepared_statements_associations_spec.rb +126 -0
- data/spec/extensions/prepared_statements_safe_spec.rb +79 -0
- data/spec/extensions/prepared_statements_spec.rb +72 -0
- data/spec/extensions/prepared_statements_with_pk_spec.rb +38 -0
- data/spec/extensions/schema_dumper_spec.rb +2 -2
- data/spec/extensions/schema_spec.rb +12 -20
- data/spec/extensions/serialization_modification_detection_spec.rb +36 -0
- data/spec/extensions/single_table_inheritance_spec.rb +11 -0
- data/spec/extensions/spec_helper.rb +3 -1
- data/spec/extensions/to_dot_spec.rb +3 -5
- data/spec/extensions/xml_serializer_spec.rb +16 -4
- data/spec/integration/associations_test.rb +405 -15
- data/spec/integration/database_test.rb +4 -2
- data/spec/integration/dataset_test.rb +240 -20
- data/spec/integration/plugin_test.rb +142 -5
- data/spec/integration/prepared_statement_test.rb +174 -95
- data/spec/integration/schema_test.rb +128 -16
- data/spec/integration/spec_helper.rb +15 -0
- data/spec/integration/transaction_test.rb +40 -0
- data/spec/integration/type_test.rb +16 -2
- data/spec/model/association_reflection_spec.rb +91 -0
- data/spec/model/associations_spec.rb +476 -5
- data/spec/model/base_spec.rb +91 -1
- data/spec/model/eager_loading_spec.rb +519 -31
- data/spec/model/hooks_spec.rb +161 -0
- data/spec/model/model_spec.rb +89 -2
- data/spec/model/plugins_spec.rb +17 -0
- data/spec/model/record_spec.rb +184 -12
- data/spec/model/spec_helper.rb +5 -0
- data/spec/model/validations_spec.rb +11 -0
- metadata +85 -34
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
require 'mysql2' unless defined? Mysql2
|
|
2
|
-
|
|
3
|
-
Sequel.require %w'shared/mysql', 'adapters'
|
|
2
|
+
Sequel.require %w'shared/mysql_prepared_statements', 'adapters'
|
|
4
3
|
|
|
5
4
|
module Sequel
|
|
6
5
|
# Module for holding all Mysql2-related classes and modules for Sequel.
|
|
@@ -8,6 +7,7 @@ module Sequel
|
|
|
8
7
|
# Database class for MySQL databases used with Sequel.
|
|
9
8
|
class Database < Sequel::Database
|
|
10
9
|
include Sequel::MySQL::DatabaseMethods
|
|
10
|
+
include Sequel::MySQL::PreparedStatements::DatabaseMethods
|
|
11
11
|
|
|
12
12
|
# Mysql::Error messages that indicate the current connection should be disconnected
|
|
13
13
|
MYSQL_DATABASE_DISCONNECT_ERRORS = /\A(Commands out of sync; you can't run this command now|Can't connect to local MySQL server through socket|MySQL server has gone away)/
|
|
@@ -21,7 +21,6 @@ module Sequel
|
|
|
21
21
|
# a filter for an autoincrement column equals NULL to return the last
|
|
22
22
|
# inserted row.
|
|
23
23
|
# * :charset - Same as :encoding (:encoding takes precendence)
|
|
24
|
-
# * :compress - Set to false to not compress results from the server
|
|
25
24
|
# * :config_default_group - The default group to read from the in
|
|
26
25
|
# the MySQL config file.
|
|
27
26
|
# * :config_local_infile - If provided, sets the Mysql::OPT_LOCAL_INFILE
|
|
@@ -57,6 +56,7 @@ module Sequel
|
|
|
57
56
|
|
|
58
57
|
sqls.each{|sql| log_yield(sql){conn.query(sql)}}
|
|
59
58
|
|
|
59
|
+
add_prepared_statements_cache(conn)
|
|
60
60
|
conn
|
|
61
61
|
end
|
|
62
62
|
|
|
@@ -65,16 +65,6 @@ module Sequel
|
|
|
65
65
|
Mysql2::Dataset.new(self, opts)
|
|
66
66
|
end
|
|
67
67
|
|
|
68
|
-
# Executes the given SQL using an available connection, yielding the
|
|
69
|
-
# connection if the block is given.
|
|
70
|
-
def execute(sql, opts={}, &block)
|
|
71
|
-
if opts[:sproc]
|
|
72
|
-
call_sproc(sql, opts, &block)
|
|
73
|
-
else
|
|
74
|
-
synchronize(opts[:server]){|conn| _execute(conn, sql, opts, &block)}
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
|
|
78
68
|
# Return the version of the MySQL server two which we are connecting.
|
|
79
69
|
def server_version(server=nil)
|
|
80
70
|
@server_version ||= (synchronize(server){|conn| conn.server_info[:id]} || super)
|
|
@@ -94,7 +84,7 @@ module Sequel
|
|
|
94
84
|
yield conn
|
|
95
85
|
end
|
|
96
86
|
rescue ::Mysql2::Error => e
|
|
97
|
-
raise_error(e
|
|
87
|
+
raise_error(e)
|
|
98
88
|
end
|
|
99
89
|
end
|
|
100
90
|
|
|
@@ -108,6 +98,10 @@ module Sequel
|
|
|
108
98
|
[::Mysql2::Error]
|
|
109
99
|
end
|
|
110
100
|
|
|
101
|
+
def disconnect_error?(e, opts)
|
|
102
|
+
super || (e.is_a?(::Mysql2::Error) && MYSQL_DATABASE_DISCONNECT_ERRORS.match(e.message))
|
|
103
|
+
end
|
|
104
|
+
|
|
111
105
|
# The database name when using the native adapter is always stored in
|
|
112
106
|
# the :database option.
|
|
113
107
|
def database_name
|
|
@@ -128,6 +122,7 @@ module Sequel
|
|
|
128
122
|
# Dataset class for MySQL datasets accessed via the native driver.
|
|
129
123
|
class Dataset < Sequel::Dataset
|
|
130
124
|
include Sequel::MySQL::DatasetMethods
|
|
125
|
+
include Sequel::MySQL::PreparedStatements::DatasetMethods
|
|
131
126
|
|
|
132
127
|
# Delete rows matching this dataset
|
|
133
128
|
def delete
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
Sequel.require 'adapters/shared/db2'
|
|
2
|
+
|
|
3
|
+
module Sequel
|
|
4
|
+
module ODBC
|
|
5
|
+
# Database and Dataset instance methods for DB2 specific
|
|
6
|
+
# support via ODBC.
|
|
7
|
+
module DB2
|
|
8
|
+
module DatabaseMethods
|
|
9
|
+
include ::Sequel::DB2::DatabaseMethods
|
|
10
|
+
|
|
11
|
+
def dataset(opts=nil)
|
|
12
|
+
Sequel::ODBC::DB2::Dataset.new(self, opts)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
class Dataset < ODBC::Dataset
|
|
17
|
+
include ::Sequel::DB2::DatasetMethods
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
data/lib/sequel/adapters/odbc.rb
CHANGED
|
@@ -15,9 +15,13 @@ module Sequel
|
|
|
15
15
|
when 'mssql'
|
|
16
16
|
Sequel.ts_require 'adapters/odbc/mssql'
|
|
17
17
|
extend Sequel::ODBC::MSSQL::DatabaseMethods
|
|
18
|
+
set_mssql_unicode_strings
|
|
18
19
|
when 'progress'
|
|
19
20
|
Sequel.ts_require 'adapters/shared/progress'
|
|
20
21
|
extend Sequel::Progress::DatabaseMethods
|
|
22
|
+
when 'db2'
|
|
23
|
+
Sequel.ts_require 'adapters/odbc/db2'
|
|
24
|
+
extend Sequel::ODBC::DB2::DatabaseMethods
|
|
21
25
|
end
|
|
22
26
|
end
|
|
23
27
|
|
|
@@ -51,7 +55,7 @@ module Sequel
|
|
|
51
55
|
r = log_yield(sql){conn.run(sql)}
|
|
52
56
|
yield(r) if block_given?
|
|
53
57
|
rescue ::ODBC::Error, ArgumentError => e
|
|
54
|
-
raise_error(e
|
|
58
|
+
raise_error(e)
|
|
55
59
|
ensure
|
|
56
60
|
r.drop if r
|
|
57
61
|
end
|
|
@@ -64,7 +68,7 @@ module Sequel
|
|
|
64
68
|
begin
|
|
65
69
|
log_yield(sql){conn.do(sql)}
|
|
66
70
|
rescue ::ODBC::Error, ArgumentError => e
|
|
67
|
-
raise_error(e
|
|
71
|
+
raise_error(e)
|
|
68
72
|
end
|
|
69
73
|
end
|
|
70
74
|
end
|
|
@@ -76,9 +80,17 @@ module Sequel
|
|
|
76
80
|
:do
|
|
77
81
|
end
|
|
78
82
|
|
|
83
|
+
def database_error_classes
|
|
84
|
+
[::ODBC::Error]
|
|
85
|
+
end
|
|
86
|
+
|
|
79
87
|
def disconnect_connection(c)
|
|
80
88
|
c.disconnect
|
|
81
89
|
end
|
|
90
|
+
|
|
91
|
+
def disconnect_error?(e, opts)
|
|
92
|
+
super || (e.is_a?(::ODBC::Error) && DISCONNECT_ERRORS.match(e.message))
|
|
93
|
+
end
|
|
82
94
|
end
|
|
83
95
|
|
|
84
96
|
class Dataset < Sequel::Dataset
|
|
@@ -116,7 +128,7 @@ module Sequel
|
|
|
116
128
|
when ::ODBC::TimeStamp
|
|
117
129
|
Sequel.database_to_application_timestamp([v.year, v.month, v.day, v.hour, v.minute, v.second])
|
|
118
130
|
when ::ODBC::Time
|
|
119
|
-
Sequel.
|
|
131
|
+
Sequel::SQLTime.create(v.hour, v.minute, v.second)
|
|
120
132
|
when ::ODBC::Date
|
|
121
133
|
Date.new(v.year, v.month, v.day)
|
|
122
134
|
else
|
|
@@ -24,6 +24,18 @@ module Sequel
|
|
|
24
24
|
conn = OCI8.new(opts[:user], opts[:password], dbname, opts[:privilege])
|
|
25
25
|
conn.autocommit = true
|
|
26
26
|
conn.non_blocking = true
|
|
27
|
+
|
|
28
|
+
# The ruby-oci8 gem which retrieves oracle columns with a type of
|
|
29
|
+
# DATE, TIMESTAMP, TIMESTAMP WITH TIME ZONE is complex based on the
|
|
30
|
+
# ruby version (1.9.2 or later) and Oracle version (9 or later)
|
|
31
|
+
# In the now standard case of 1.9.2 and Oracle 9 or later, the timezone
|
|
32
|
+
# is determined by the Oracle session timezone. Thus if the user
|
|
33
|
+
# requests Sequel provide UTC timezone to the application,
|
|
34
|
+
# we need to alter the session timezone to be UTC
|
|
35
|
+
if Sequel.application_timezone == :utc
|
|
36
|
+
conn.exec("ALTER SESSION SET TIME_ZONE='-00:00'")
|
|
37
|
+
end
|
|
38
|
+
|
|
27
39
|
conn
|
|
28
40
|
end
|
|
29
41
|
|
|
@@ -66,7 +78,7 @@ module Sequel
|
|
|
66
78
|
yield(r) if block_given?
|
|
67
79
|
r
|
|
68
80
|
rescue OCIException => e
|
|
69
|
-
raise_error(e
|
|
81
|
+
raise_error(e)
|
|
70
82
|
end
|
|
71
83
|
end
|
|
72
84
|
end
|
|
@@ -88,6 +100,10 @@ module Sequel
|
|
|
88
100
|
rescue OCIInvalidHandle
|
|
89
101
|
nil
|
|
90
102
|
end
|
|
103
|
+
|
|
104
|
+
def disconnect_error?(e, opts)
|
|
105
|
+
super || (e.is_a?(::OCIException) && CONNECTION_ERROR_CODES.include?(e.code))
|
|
106
|
+
end
|
|
91
107
|
|
|
92
108
|
def remove_transaction(conn)
|
|
93
109
|
conn.autocommit = true if conn
|
|
@@ -93,13 +93,14 @@ module Sequel
|
|
|
93
93
|
def bytea(s) ::Sequel::SQL::Blob.new(Adapter.unescape_bytea(s)) end
|
|
94
94
|
def integer(s) s.to_i end
|
|
95
95
|
def float(s) s.to_f end
|
|
96
|
-
def
|
|
97
|
-
def date(s) ::Sequel.string_to_date(s) end
|
|
98
|
-
def date_iso(s) ::Date.new(*s.split("-").map{|x| x.to_i}) end
|
|
99
|
-
def time(s) ::Sequel.string_to_time(s) end
|
|
100
|
-
def timestamp(s) ::Sequel.database_to_application_timestamp(s) end
|
|
96
|
+
def date(s) ::Date.new(*s.split("-").map{|x| x.to_i}) end
|
|
101
97
|
end.new
|
|
102
98
|
|
|
99
|
+
# Hash with type name symbols and callable values for converting PostgreSQL types.
|
|
100
|
+
# Non-builtin types that don't have fixed numbers should use this to register
|
|
101
|
+
# conversion procs.
|
|
102
|
+
PG_NAMED_TYPES = {}
|
|
103
|
+
|
|
103
104
|
# Hash with integer keys and callable values for converting PostgreSQL types.
|
|
104
105
|
PG_TYPES = {}
|
|
105
106
|
{
|
|
@@ -107,9 +108,9 @@ module Sequel
|
|
|
107
108
|
[17] => tt.method(:bytea),
|
|
108
109
|
[20, 21, 22, 23, 26] => tt.method(:integer),
|
|
109
110
|
[700, 701] => tt.method(:float),
|
|
110
|
-
[790, 1700] =>
|
|
111
|
-
[1083, 1266] =>
|
|
112
|
-
[1114, 1184] =>
|
|
111
|
+
[790, 1700] => ::BigDecimal.method(:new),
|
|
112
|
+
[1083, 1266] => ::Sequel.method(:string_to_time),
|
|
113
|
+
[1114, 1184] => ::Sequel.method(:database_to_application_timestamp)
|
|
113
114
|
}.each do |k,v|
|
|
114
115
|
k.each{|n| PG_TYPES[n] = v}
|
|
115
116
|
end
|
|
@@ -123,7 +124,7 @@ module Sequel
|
|
|
123
124
|
|
|
124
125
|
# Modify the type translator for the date type depending on the value given.
|
|
125
126
|
def self.use_iso_date_format=(v)
|
|
126
|
-
PG_TYPES[1082] = TYPE_TRANSLATOR.method(
|
|
127
|
+
PG_TYPES[1082] = v ? TYPE_TRANSLATOR.method(:date) : Sequel.method(:string_to_date)
|
|
127
128
|
@use_iso_date_format = v
|
|
128
129
|
end
|
|
129
130
|
self.use_iso_date_format = true
|
|
@@ -131,7 +132,10 @@ module Sequel
|
|
|
131
132
|
# PGconn subclass for connection specific methods used with the
|
|
132
133
|
# pg, postgres, or postgres-pr driver.
|
|
133
134
|
class Adapter < ::PGconn
|
|
135
|
+
DISCONNECT_ERROR_RE = /\Acould not receive data from server: Software caused connection abort/
|
|
136
|
+
|
|
134
137
|
include Sequel::Postgres::AdapterMethods
|
|
138
|
+
|
|
135
139
|
self.translate_results = false if respond_to?(:translate_results=)
|
|
136
140
|
|
|
137
141
|
# Hash of prepared statements for this connection. Keys are
|
|
@@ -150,20 +154,23 @@ module Sequel
|
|
|
150
154
|
end
|
|
151
155
|
@prepared_statements = {} if SEQUEL_POSTGRES_USES_PG
|
|
152
156
|
end
|
|
153
|
-
|
|
157
|
+
|
|
154
158
|
# Raise a Sequel::DatabaseDisconnectError if a PGError is raised and
|
|
155
159
|
# the connection status cannot be determined or it is not OK.
|
|
156
160
|
def check_disconnect_errors
|
|
157
161
|
begin
|
|
158
162
|
yield
|
|
159
163
|
rescue PGError =>e
|
|
164
|
+
disconnect = false
|
|
160
165
|
begin
|
|
161
166
|
s = status
|
|
162
167
|
rescue PGError
|
|
163
|
-
|
|
168
|
+
disconnect = true
|
|
164
169
|
end
|
|
165
170
|
status_ok = (s == Adapter::CONNECTION_OK)
|
|
166
|
-
|
|
171
|
+
disconnect ||= !status_ok
|
|
172
|
+
disconnect ||= e.message =~ DISCONNECT_ERROR_RE
|
|
173
|
+
disconnect ? raise(Sequel.convert_exception_class(e, Sequel::DatabaseDisconnectError)) : raise
|
|
167
174
|
ensure
|
|
168
175
|
block if status_ok
|
|
169
176
|
end
|
|
@@ -176,7 +183,7 @@ module Sequel
|
|
|
176
183
|
begin
|
|
177
184
|
block_given? ? yield(q) : q.cmd_tuples
|
|
178
185
|
ensure
|
|
179
|
-
q.clear
|
|
186
|
+
q.clear if q
|
|
180
187
|
end
|
|
181
188
|
end
|
|
182
189
|
|
|
@@ -194,6 +201,10 @@ module Sequel
|
|
|
194
201
|
include Sequel::Postgres::DatabaseMethods
|
|
195
202
|
|
|
196
203
|
set_adapter_scheme :postgres
|
|
204
|
+
|
|
205
|
+
# A hash of conversion procs, keyed by type integer (oid) and
|
|
206
|
+
# having callable values for the conversion proc for that type.
|
|
207
|
+
attr_reader :conversion_procs
|
|
197
208
|
|
|
198
209
|
# Add the primary_keys and primary_key_sequences instance variables,
|
|
199
210
|
# so we can get the correct return values for inserted rows.
|
|
@@ -225,9 +236,74 @@ module Sequel
|
|
|
225
236
|
end
|
|
226
237
|
conn.db = self
|
|
227
238
|
conn.apply_connection_settings
|
|
239
|
+
@conversion_procs ||= get_conversion_procs(conn)
|
|
228
240
|
conn
|
|
229
241
|
end
|
|
230
242
|
|
|
243
|
+
if SEQUEL_POSTGRES_USES_PG
|
|
244
|
+
# +copy_table+ uses PostgreSQL's +COPY+ SQL statement to return formatted
|
|
245
|
+
# results directly to the caller. This method is only support if pg is the
|
|
246
|
+
# underlying ruby driver. This method should only be called if you want
|
|
247
|
+
# results returned to the client. If you are using +COPY FROM+ or +COPY TO+
|
|
248
|
+
# with a filename, you should just use +run+ instead of this method. This
|
|
249
|
+
# method does not currently support +COPY FROM STDIN+, but that may be supported
|
|
250
|
+
# in the future.
|
|
251
|
+
#
|
|
252
|
+
# The table argument supports the following types:
|
|
253
|
+
#
|
|
254
|
+
# String :: Uses the first argument directly as literal SQL. If you are using
|
|
255
|
+
# a version of PostgreSQL before 9.0, you will probably want to
|
|
256
|
+
# use a string if you are using any options at all, as the syntax
|
|
257
|
+
# Sequel uses for options is only compatible with PostgreSQL 9.0+.
|
|
258
|
+
# Dataset :: Uses a query instead of a table name when copying.
|
|
259
|
+
# other :: Uses a table name (usually a symbol) when copying.
|
|
260
|
+
#
|
|
261
|
+
# The following options are respected:
|
|
262
|
+
#
|
|
263
|
+
# :format :: The format to use. text is the default, so this should be :csv or :binary.
|
|
264
|
+
# :options :: An options SQL string to use, which should contain comma separated options.
|
|
265
|
+
# :server :: The server on which to run the query.
|
|
266
|
+
#
|
|
267
|
+
# If a block is provided, the method continually yields to the block, one yield
|
|
268
|
+
# per row. If a block is not provided, a single string is returned with all
|
|
269
|
+
# of the data.
|
|
270
|
+
def copy_table(table, opts={})
|
|
271
|
+
sql = if table.is_a?(String)
|
|
272
|
+
sql = table
|
|
273
|
+
else
|
|
274
|
+
if opts[:options] || opts[:format]
|
|
275
|
+
options = " ("
|
|
276
|
+
options << "FORMAT #{opts[:format]}" if opts[:format]
|
|
277
|
+
options << "#{', ' if opts[:format]}#{opts[:options]}" if opts[:options]
|
|
278
|
+
options << ')'
|
|
279
|
+
end
|
|
280
|
+
table = if table.is_a?(::Sequel::Dataset)
|
|
281
|
+
"(#{table.sql})"
|
|
282
|
+
else
|
|
283
|
+
literal(table)
|
|
284
|
+
end
|
|
285
|
+
sql = "COPY #{table} TO STDOUT#{options}"
|
|
286
|
+
end
|
|
287
|
+
synchronize(opts[:server]) do |conn|
|
|
288
|
+
conn.execute(sql)
|
|
289
|
+
begin
|
|
290
|
+
if block_given?
|
|
291
|
+
while buf = conn.get_copy_data
|
|
292
|
+
yield buf
|
|
293
|
+
end
|
|
294
|
+
nil
|
|
295
|
+
else
|
|
296
|
+
b = ''
|
|
297
|
+
b << buf while buf = conn.get_copy_data
|
|
298
|
+
b
|
|
299
|
+
end
|
|
300
|
+
ensure
|
|
301
|
+
raise DatabaseDisconnectError, "disconnecting as a partial COPY may leave the connection in an unusable state" if buf
|
|
302
|
+
end
|
|
303
|
+
end
|
|
304
|
+
end
|
|
305
|
+
end
|
|
306
|
+
|
|
231
307
|
# Return instance of Sequel::Postgres::Dataset with the given options.
|
|
232
308
|
def dataset(opts = nil)
|
|
233
309
|
Postgres::Dataset.new(self, opts)
|
|
@@ -305,6 +381,19 @@ module Sequel
|
|
|
305
381
|
end
|
|
306
382
|
end
|
|
307
383
|
end
|
|
384
|
+
|
|
385
|
+
# Return the conversion procs hash to use for this database
|
|
386
|
+
def get_conversion_procs(conn)
|
|
387
|
+
procs = PG_TYPES.dup
|
|
388
|
+
conn.execute("SELECT oid, typname FROM pg_type where typtype = 'b'") do |res|
|
|
389
|
+
res.ntuples.times do |recnum|
|
|
390
|
+
if pr = PG_NAMED_TYPES[res.getvalue(recnum, 1).to_sym]
|
|
391
|
+
procs[res.getvalue(recnum, 0).to_i] ||= pr
|
|
392
|
+
end
|
|
393
|
+
end
|
|
394
|
+
end
|
|
395
|
+
procs
|
|
396
|
+
end
|
|
308
397
|
end
|
|
309
398
|
|
|
310
399
|
# Dataset class for PostgreSQL datasets that use the pg, postgres, or
|
|
@@ -372,11 +461,17 @@ module Sequel
|
|
|
372
461
|
end
|
|
373
462
|
LiteralString.new("#{prepared_arg_placeholder}#{i}#{"::#{type}" if type}")
|
|
374
463
|
end
|
|
464
|
+
|
|
465
|
+
# Always assume a prepared argument.
|
|
466
|
+
def prepared_arg?(k)
|
|
467
|
+
true
|
|
468
|
+
end
|
|
375
469
|
end
|
|
376
470
|
|
|
377
471
|
# Allow use of bind arguments for PostgreSQL using the pg driver.
|
|
378
472
|
module BindArgumentMethods
|
|
379
473
|
include ArgumentMapper
|
|
474
|
+
include ::Sequel::Postgres::DatasetMethods::PreparedStatementMethods
|
|
380
475
|
|
|
381
476
|
private
|
|
382
477
|
|
|
@@ -400,7 +495,6 @@ module Sequel
|
|
|
400
495
|
# pg driver.
|
|
401
496
|
module PreparedStatementMethods
|
|
402
497
|
include BindArgumentMethods
|
|
403
|
-
include ::Sequel::Postgres::DatasetMethods::PreparedStatementMethods
|
|
404
498
|
|
|
405
499
|
private
|
|
406
500
|
|
|
@@ -427,7 +521,7 @@ module Sequel
|
|
|
427
521
|
ps.extend(BindArgumentMethods)
|
|
428
522
|
ps.call(bind_vars, &block)
|
|
429
523
|
end
|
|
430
|
-
|
|
524
|
+
|
|
431
525
|
# Prepare the given type of statement with the given name, and store
|
|
432
526
|
# it in the database to be called later.
|
|
433
527
|
def prepare(type, name=nil, *values)
|
|
@@ -483,8 +577,9 @@ module Sequel
|
|
|
483
577
|
# field numers, type conversion procs, and name symbol arrays.
|
|
484
578
|
def fetch_rows_set_cols(res)
|
|
485
579
|
cols = []
|
|
580
|
+
procs = db.conversion_procs
|
|
486
581
|
res.nfields.times do |fieldnum|
|
|
487
|
-
cols << [fieldnum,
|
|
582
|
+
cols << [fieldnum, procs[res.ftype(fieldnum)], output_identifier(res.fname(fieldnum))]
|
|
488
583
|
end
|
|
489
584
|
@columns = cols.map{|c| c.at(2)}
|
|
490
585
|
cols
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
module Sequel
|
|
2
2
|
module Access
|
|
3
3
|
module DatabaseMethods
|
|
4
|
+
# Access uses type :access as the database_type
|
|
4
5
|
def database_type
|
|
5
6
|
:access
|
|
6
7
|
end
|
|
@@ -16,6 +17,7 @@ module Sequel
|
|
|
16
17
|
from(:MSysObjects).filter(:Type=>1, :Flags=>0).select_map(:Name).map{|x| x.to_sym}
|
|
17
18
|
end
|
|
18
19
|
|
|
20
|
+
# Access uses type Counter for an autoincrementing keys
|
|
19
21
|
def serial_primary_key_options
|
|
20
22
|
{:primary_key => true, :type=>:Counter}
|
|
21
23
|
end
|
|
@@ -34,16 +36,35 @@ module Sequel
|
|
|
34
36
|
module DatasetMethods
|
|
35
37
|
SELECT_CLAUSE_METHODS = Dataset.clause_methods(:select, %w'limit distinct columns from join where group order having compounds')
|
|
36
38
|
|
|
39
|
+
# Access doesn't support INTERSECT or EXCEPT
|
|
37
40
|
def supports_intersect_except?
|
|
38
41
|
false
|
|
39
42
|
end
|
|
40
43
|
|
|
41
44
|
private
|
|
42
45
|
|
|
46
|
+
# Access uses # to quote dates
|
|
47
|
+
def literal_date(d)
|
|
48
|
+
d.strftime('#%Y-%m-%d#')
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Access uses # to quote datetimes
|
|
52
|
+
def literal_datetime(t)
|
|
53
|
+
t.strftime('#%Y-%m-%d %H:%M:%S#')
|
|
54
|
+
end
|
|
55
|
+
alias literal_time literal_datetime
|
|
56
|
+
|
|
57
|
+
# Access uses TOP for limits
|
|
58
|
+
def select_limit_sql(sql)
|
|
59
|
+
sql << " TOP #{@opts[:limit]}" if @opts[:limit]
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Access uses [] for quoting identifiers
|
|
43
63
|
def quoted_identifier(v)
|
|
44
64
|
"[#{v}]"
|
|
45
65
|
end
|
|
46
66
|
|
|
67
|
+
# Access requires the limit clause come before other clauses
|
|
47
68
|
def select_clause_methods
|
|
48
69
|
SELECT_CLAUSE_METHODS
|
|
49
70
|
end
|