sequel 4.12.0 → 4.13.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.
Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +64 -0
  3. data/Rakefile +3 -1
  4. data/bin/sequel +13 -5
  5. data/doc/release_notes/4.13.0.txt +169 -0
  6. data/doc/sql.rdoc +3 -3
  7. data/lib/sequel/adapters/do.rb +11 -23
  8. data/lib/sequel/adapters/do/mysql.rb +8 -0
  9. data/lib/sequel/adapters/do/postgres.rb +8 -0
  10. data/lib/sequel/adapters/do/{sqlite.rb → sqlite3.rb} +9 -0
  11. data/lib/sequel/adapters/jdbc.rb +16 -139
  12. data/lib/sequel/adapters/jdbc/as400.rb +9 -0
  13. data/lib/sequel/adapters/jdbc/cubrid.rb +9 -0
  14. data/lib/sequel/adapters/jdbc/db2.rb +9 -0
  15. data/lib/sequel/adapters/jdbc/derby.rb +9 -0
  16. data/lib/sequel/adapters/jdbc/{firebird.rb → firebirdsql.rb} +9 -0
  17. data/lib/sequel/adapters/jdbc/h2.rb +10 -0
  18. data/lib/sequel/adapters/jdbc/hsqldb.rb +9 -0
  19. data/lib/sequel/adapters/jdbc/{informix.rb → informix-sqli.rb} +9 -0
  20. data/lib/sequel/adapters/jdbc/{progress.rb → jdbcprogress.rb} +9 -0
  21. data/lib/sequel/adapters/jdbc/jtds.rb +10 -0
  22. data/lib/sequel/adapters/jdbc/mysql.rb +14 -0
  23. data/lib/sequel/adapters/jdbc/oracle.rb +9 -0
  24. data/lib/sequel/adapters/jdbc/postgresql.rb +9 -0
  25. data/lib/sequel/adapters/jdbc/sqlanywhere.rb +23 -0
  26. data/lib/sequel/adapters/jdbc/sqlite.rb +10 -0
  27. data/lib/sequel/adapters/jdbc/sqlserver.rb +10 -0
  28. data/lib/sequel/adapters/odbc.rb +6 -14
  29. data/lib/sequel/adapters/odbc/db2.rb +9 -0
  30. data/lib/sequel/adapters/odbc/mssql.rb +8 -0
  31. data/lib/sequel/adapters/odbc/progress.rb +8 -0
  32. data/lib/sequel/adapters/oracle.rb +1 -1
  33. data/lib/sequel/adapters/postgres.rb +1 -1
  34. data/lib/sequel/adapters/shared/firebird.rb +8 -1
  35. data/lib/sequel/adapters/shared/mssql.rb +68 -27
  36. data/lib/sequel/adapters/shared/mysql.rb +3 -5
  37. data/lib/sequel/adapters/shared/oracle.rb +17 -3
  38. data/lib/sequel/adapters/shared/postgres.rb +9 -4
  39. data/lib/sequel/adapters/shared/sqlanywhere.rb +6 -6
  40. data/lib/sequel/database/connecting.rb +38 -17
  41. data/lib/sequel/dataset/actions.rb +6 -2
  42. data/lib/sequel/dataset/graph.rb +18 -20
  43. data/lib/sequel/dataset/misc.rb +37 -0
  44. data/lib/sequel/dataset/prepared_statements.rb +1 -2
  45. data/lib/sequel/dataset/query.rb +1 -0
  46. data/lib/sequel/dataset/sql.rb +17 -10
  47. data/lib/sequel/extensions/dataset_source_alias.rb +90 -0
  48. data/lib/sequel/extensions/pg_array.rb +14 -10
  49. data/lib/sequel/extensions/pg_enum.rb +135 -0
  50. data/lib/sequel/extensions/pg_hstore.rb +4 -6
  51. data/lib/sequel/extensions/pg_inet.rb +4 -5
  52. data/lib/sequel/extensions/pg_interval.rb +3 -3
  53. data/lib/sequel/extensions/pg_json.rb +16 -12
  54. data/lib/sequel/extensions/pg_range.rb +5 -3
  55. data/lib/sequel/extensions/pg_row.rb +2 -2
  56. data/lib/sequel/extensions/round_timestamps.rb +52 -0
  57. data/lib/sequel/model.rb +5 -2
  58. data/lib/sequel/model/associations.rb +29 -3
  59. data/lib/sequel/model/base.rb +68 -29
  60. data/lib/sequel/plugins/class_table_inheritance.rb +25 -16
  61. data/lib/sequel/plugins/column_select.rb +57 -0
  62. data/lib/sequel/plugins/composition.rb +14 -16
  63. data/lib/sequel/plugins/dirty.rb +9 -11
  64. data/lib/sequel/plugins/insert_returning_select.rb +70 -0
  65. data/lib/sequel/plugins/instance_filters.rb +7 -9
  66. data/lib/sequel/plugins/lazy_attributes.rb +16 -4
  67. data/lib/sequel/plugins/list.rb +9 -0
  68. data/lib/sequel/plugins/modification_detection.rb +90 -0
  69. data/lib/sequel/plugins/serialization.rb +13 -15
  70. data/lib/sequel/plugins/serialization_modification_detection.rb +9 -9
  71. data/lib/sequel/plugins/single_table_inheritance.rb +3 -1
  72. data/lib/sequel/plugins/timestamps.rb +6 -6
  73. data/lib/sequel/version.rb +1 -1
  74. data/spec/adapters/mysql_spec.rb +7 -0
  75. data/spec/adapters/postgres_spec.rb +41 -0
  76. data/spec/bin_spec.rb +4 -1
  77. data/spec/core/database_spec.rb +6 -0
  78. data/spec/core/dataset_spec.rb +100 -90
  79. data/spec/core/object_graph_spec.rb +5 -0
  80. data/spec/extensions/class_table_inheritance_spec.rb +18 -13
  81. data/spec/extensions/column_select_spec.rb +108 -0
  82. data/spec/extensions/composition_spec.rb +20 -0
  83. data/spec/extensions/dataset_source_alias_spec.rb +51 -0
  84. data/spec/extensions/insert_returning_select_spec.rb +46 -0
  85. data/spec/extensions/lazy_attributes_spec.rb +24 -20
  86. data/spec/extensions/list_spec.rb +5 -0
  87. data/spec/extensions/modification_detection_spec.rb +80 -0
  88. data/spec/extensions/pg_enum_spec.rb +64 -0
  89. data/spec/extensions/pg_json_spec.rb +7 -13
  90. data/spec/extensions/prepared_statements_spec.rb +6 -4
  91. data/spec/extensions/round_timestamps_spec.rb +43 -0
  92. data/spec/extensions/serialization_modification_detection_spec.rb +10 -1
  93. data/spec/extensions/serialization_spec.rb +18 -0
  94. data/spec/extensions/single_table_inheritance_spec.rb +5 -0
  95. data/spec/extensions/timestamps_spec.rb +6 -0
  96. data/spec/integration/plugin_test.rb +14 -8
  97. data/spec/integration/prepared_statement_test.rb +12 -0
  98. data/spec/model/associations_spec.rb +24 -0
  99. data/spec/model/model_spec.rb +13 -3
  100. data/spec/model/record_spec.rb +24 -1
  101. metadata +22 -6
@@ -1,8 +1,17 @@
1
+ Sequel::JDBC.load_driver('com.ibm.as400.access.AS400JDBCDriver')
1
2
  Sequel.require 'adapters/jdbc/transactions'
2
3
  Sequel.require 'adapters/utils/emulate_offset_with_row_number'
3
4
 
4
5
  module Sequel
5
6
  module JDBC
7
+ Sequel.synchronize do
8
+ DATABASE_SETUP[:as400] = proc do |db|
9
+ db.extend(Sequel::JDBC::AS400::DatabaseMethods)
10
+ db.dataset_class = Sequel::JDBC::AS400::Dataset
11
+ com.ibm.as400.access.AS400JDBCDriver
12
+ end
13
+ end
14
+
6
15
  # Database and Dataset support for AS400 databases accessed via JDBC.
7
16
  module AS400
8
17
  # Instance methods for AS400 Database objects accessed via JDBC.
@@ -1,8 +1,17 @@
1
+ Sequel::JDBC.load_driver('Java::cubrid.jdbc.driver.CUBRIDDriver')
1
2
  Sequel.require 'adapters/shared/cubrid'
2
3
  Sequel.require 'adapters/jdbc/transactions'
3
4
 
4
5
  module Sequel
5
6
  module JDBC
7
+ Sequel.synchronize do
8
+ DATABASE_SETUP[:cubrid] = proc do |db|
9
+ db.extend(Sequel::JDBC::Cubrid::DatabaseMethods)
10
+ db.extend_datasets Sequel::Cubrid::DatasetMethods
11
+ Java::cubrid.jdbc.driver.CUBRIDDriver
12
+ end
13
+ end
14
+
6
15
  module Cubrid
7
16
  module DatabaseMethods
8
17
  extend Sequel::Database::ResetIdentifierMangling
@@ -1,8 +1,17 @@
1
+ Sequel::JDBC.load_driver('com.ibm.db2.jcc.DB2Driver')
1
2
  Sequel.require 'adapters/shared/db2'
2
3
  Sequel.require 'adapters/jdbc/transactions'
3
4
 
4
5
  module Sequel
5
6
  module JDBC
7
+ Sequel.synchronize do
8
+ DATABASE_SETUP[:db2] = proc do |db|
9
+ db.extend(Sequel::JDBC::DB2::DatabaseMethods)
10
+ db.dataset_class = Sequel::JDBC::DB2::Dataset
11
+ com.ibm.db2.jcc.DB2Driver
12
+ end
13
+ end
14
+
6
15
  class TypeConvertor
7
16
  def DB2Clob(r, i)
8
17
  if v = r.getClob(i)
@@ -1,7 +1,16 @@
1
+ Sequel::JDBC.load_driver('org.apache.derby.jdbc.EmbeddedDriver', :Derby)
1
2
  Sequel.require 'adapters/jdbc/transactions'
2
3
 
3
4
  module Sequel
4
5
  module JDBC
6
+ Sequel.synchronize do
7
+ DATABASE_SETUP[:derby] = proc do |db|
8
+ db.extend(Sequel::JDBC::Derby::DatabaseMethods)
9
+ db.dataset_class = Sequel::JDBC::Derby::Dataset
10
+ org.apache.derby.jdbc.EmbeddedDriver
11
+ end
12
+ end
13
+
5
14
  # Database and Dataset support for Derby databases accessed via JDBC.
6
15
  module Derby
7
16
  # Instance methods for Derby Database objects accessed via JDBC.
@@ -1,8 +1,17 @@
1
+ Sequel::JDBC.load_driver('org.firebirdsql.jdbc.FBDriver')
1
2
  Sequel.require 'adapters/shared/firebird'
2
3
  Sequel.require 'adapters/jdbc/transactions'
3
4
 
4
5
  module Sequel
5
6
  module JDBC
7
+ Sequel.synchronize do
8
+ DATABASE_SETUP[:firebirdsql] = proc do |db|
9
+ db.extend(Sequel::JDBC::Firebird::DatabaseMethods)
10
+ db.extend_datasets Sequel::Firebird::DatasetMethods
11
+ org.firebirdsql.jdbc.FBDriver
12
+ end
13
+ end
14
+
6
15
  # Database and Dataset instance methods for Firebird specific
7
16
  # support via JDBC.
8
17
  module Firebird
@@ -1,5 +1,15 @@
1
+ Sequel::JDBC.load_driver('org.h2.Driver', :H2)
2
+
1
3
  module Sequel
2
4
  module JDBC
5
+ Sequel.synchronize do
6
+ DATABASE_SETUP[:h2] = proc do |db|
7
+ db.extend(Sequel::JDBC::H2::DatabaseMethods)
8
+ db.dataset_class = Sequel::JDBC::H2::Dataset
9
+ org.h2.Driver
10
+ end
11
+ end
12
+
3
13
  # Database and Dataset support for H2 databases accessed via JDBC.
4
14
  module H2
5
15
  # Instance methods for H2 Database objects accessed via JDBC.
@@ -1,7 +1,16 @@
1
+ Sequel::JDBC.load_driver('org.hsqldb.jdbcDriver', :HSQLDB)
1
2
  Sequel.require 'adapters/jdbc/transactions'
2
3
 
3
4
  module Sequel
4
5
  module JDBC
6
+ Sequel.synchronize do
7
+ DATABASE_SETUP[:hsqldb] = proc do |db|
8
+ db.extend(Sequel::JDBC::HSQLDB::DatabaseMethods)
9
+ db.dataset_class = Sequel::JDBC::HSQLDB::Dataset
10
+ org.hsqldb.jdbcDriver
11
+ end
12
+ end
13
+
5
14
  # Database and Dataset support for HSQLDB databases accessed via JDBC.
6
15
  module HSQLDB
7
16
  # Instance methods for HSQLDB Database objects accessed via JDBC.
@@ -1,7 +1,16 @@
1
+ Sequel::JDBC.load_driver('com.informix.jdbc.IfxDriver')
1
2
  Sequel.require 'adapters/shared/informix'
2
3
 
3
4
  module Sequel
4
5
  module JDBC
6
+ Sequel.synchronize do
7
+ DATABASE_SETUP[:"informix-sqli"] = proc do |db|
8
+ db.extend(Sequel::JDBC::Informix::DatabaseMethods)
9
+ db.extend_datasets Sequel::Informix::DatasetMethods
10
+ com.informix.jdbc.IfxDriver
11
+ end
12
+ end
13
+
5
14
  # Database and Dataset instance methods for Informix specific
6
15
  # support via JDBC.
7
16
  module Informix
@@ -1,8 +1,17 @@
1
+ Sequel::JDBC.load_driver('com.progress.sql.jdbc.JdbcProgressDriver')
1
2
  Sequel.require 'adapters/shared/progress'
2
3
  Sequel.require 'adapters/jdbc/transactions'
3
4
 
4
5
  module Sequel
5
6
  module JDBC
7
+ Sequel.synchronize do
8
+ DATABASE_SETUP[:jdbcprogress] = proc do |db|
9
+ db.extend(Sequel::JDBC::Progress::DatabaseMethods)
10
+ db.extend_datasets Sequel::Progress::DatasetMethods
11
+ com.progress.sql.jdbc.JdbcProgressDriver
12
+ end
13
+ end
14
+
6
15
  # Database and Dataset instance methods for Progress v9 specific
7
16
  # support via JDBC.
8
17
  module Progress
@@ -1,7 +1,17 @@
1
+ Sequel::JDBC.load_driver('Java::net.sourceforge.jtds.jdbc.Driver', :JTDS)
1
2
  Sequel.require 'adapters/jdbc/mssql'
2
3
 
3
4
  module Sequel
4
5
  module JDBC
6
+ Sequel.synchronize do
7
+ DATABASE_SETUP[:jtds] = proc do |db|
8
+ db.extend(Sequel::JDBC::JTDS::DatabaseMethods)
9
+ db.dataset_class = Sequel::JDBC::JTDS::Dataset
10
+ db.send(:set_mssql_unicode_strings)
11
+ Java::net.sourceforge.jtds.jdbc.Driver
12
+ end
13
+ end
14
+
5
15
  # Database and Dataset instance methods for JTDS specific
6
16
  # support via JDBC.
7
17
  module JTDS
@@ -1,7 +1,16 @@
1
+ Sequel::JDBC.load_driver('com.mysql.jdbc.Driver', :MySQL)
1
2
  Sequel.require 'adapters/shared/mysql'
2
3
 
3
4
  module Sequel
4
5
  module JDBC
6
+ Sequel.synchronize do
7
+ DATABASE_SETUP[:mysql] = proc do |db|
8
+ db.extend(Sequel::JDBC::MySQL::DatabaseMethods)
9
+ db.extend_datasets Sequel::MySQL::DatasetMethods
10
+ com.mysql.jdbc.Driver
11
+ end
12
+ end
13
+
5
14
  # Database and Dataset instance methods for MySQL specific
6
15
  # support via JDBC.
7
16
  module MySQL
@@ -26,6 +35,11 @@ module Sequel
26
35
  false
27
36
  end
28
37
 
38
+ # Raise a disconnect error if the SQL state of the cause of the exception indicates so.
39
+ def disconnect_error?(exception, opts)
40
+ exception.message =~ /\ACommunications link failure/ || super
41
+ end
42
+
29
43
  # Get the last inserted id using LAST_INSERT_ID().
30
44
  def last_insert_id(conn, opts=OPTS)
31
45
  if stmt = opts[:stmt]
@@ -1,8 +1,17 @@
1
+ Sequel::JDBC.load_driver('Java::oracle.jdbc.driver.OracleDriver')
1
2
  Sequel.require 'adapters/shared/oracle'
2
3
  Sequel.require 'adapters/jdbc/transactions'
3
4
 
4
5
  module Sequel
5
6
  module JDBC
7
+ Sequel.synchronize do
8
+ DATABASE_SETUP[:oracle] = proc do |db|
9
+ db.extend(Sequel::JDBC::Oracle::DatabaseMethods)
10
+ db.dataset_class = Sequel::JDBC::Oracle::Dataset
11
+ Java::oracle.jdbc.driver.OracleDriver
12
+ end
13
+ end
14
+
6
15
  class TypeConvertor
7
16
  JAVA_BIG_DECIMAL_CONSTRUCTOR = java.math.BigDecimal.java_class.constructor(Java::long).method(:new_instance)
8
17
 
@@ -1,9 +1,18 @@
1
+ Sequel::JDBC.load_driver('org.postgresql.Driver', :Postgres)
1
2
  Sequel.require 'adapters/shared/postgres'
2
3
 
3
4
  module Sequel
4
5
  Postgres::CONVERTED_EXCEPTIONS << NativeException
5
6
 
6
7
  module JDBC
8
+ Sequel.synchronize do
9
+ DATABASE_SETUP[:postgresql] = proc do |db|
10
+ db.extend(Sequel::JDBC::Postgres::DatabaseMethods)
11
+ db.dataset_class = Sequel::JDBC::Postgres::Dataset
12
+ org.postgresql.Driver
13
+ end
14
+ end
15
+
7
16
  class TypeConvertor
8
17
  # Return PostgreSQL array types as ruby Arrays instead of
9
18
  # JDBC PostgreSQL driver-specific array type. Only used if the
@@ -3,6 +3,29 @@ Sequel.require 'adapters/jdbc/transactions'
3
3
 
4
4
  module Sequel
5
5
  module JDBC
6
+ drv = [
7
+ lambda{Java::sybase.jdbc4.sqlanywhere.IDriver},
8
+ lambda{Java::ianywhere.ml.jdbcodbc.jdbc4.IDriver},
9
+ lambda{Java::sybase.jdbc.sqlanywhere.IDriver},
10
+ lambda{Java::ianywhere.ml.jdbcodbc.jdbc.IDriver},
11
+ lambda{Java::com.sybase.jdbc4.jdbc.Sybdriver},
12
+ lambda{Java::com.sybase.jdbc3.jdbc.Sybdriver}
13
+ ].each do |class_proc|
14
+ begin
15
+ break class_proc.call
16
+ rescue NameError
17
+ end
18
+ end
19
+ raise(Sequel::AdapterNotFound, "no suitable SQLAnywhere JDBC driver found") unless drv
20
+
21
+ Sequel.synchronize do
22
+ DATABASE_SETUP[:sqlanywhere] = proc do |db|
23
+ db.extend(Sequel::JDBC::SqlAnywhere::DatabaseMethods)
24
+ db.dataset_class = Sequel::JDBC::SqlAnywhere::Dataset
25
+ drv
26
+ end
27
+ end
28
+
6
29
  class TypeConvertor
7
30
  def SqlAnywhereBoolean(r, i)
8
31
  if v = Short(r, i)
@@ -1,7 +1,17 @@
1
+ Sequel::JDBC.load_driver('org.sqlite.JDBC', :SQLite3)
1
2
  Sequel.require 'adapters/shared/sqlite'
2
3
 
3
4
  module Sequel
4
5
  module JDBC
6
+ Sequel.synchronize do
7
+ DATABASE_SETUP[:sqlite] = proc do |db|
8
+ db.extend(Sequel::JDBC::SQLite::DatabaseMethods)
9
+ db.extend_datasets Sequel::SQLite::DatasetMethods
10
+ db.set_integer_booleans
11
+ org.sqlite.JDBC
12
+ end
13
+ end
14
+
5
15
  # Database and Dataset support for SQLite databases accessed via JDBC.
6
16
  module SQLite
7
17
  # Instance methods for SQLite Database objects accessed via JDBC.
@@ -1,7 +1,17 @@
1
+ Sequel::JDBC.load_driver('com.microsoft.sqlserver.jdbc.SQLServerDriver')
1
2
  Sequel.require 'adapters/jdbc/mssql'
2
3
 
3
4
  module Sequel
4
5
  module JDBC
6
+ Sequel.synchronize do
7
+ DATABASE_SETUP[:sqlserver] = proc do |db|
8
+ db.extend(Sequel::JDBC::SQLServer::DatabaseMethods)
9
+ db.extend_datasets Sequel::MSSQL::DatasetMethods
10
+ db.send(:set_mssql_unicode_strings)
11
+ com.microsoft.sqlserver.jdbc.SQLServerDriver
12
+ end
13
+ end
14
+
5
15
  # Database and Dataset instance methods for SQLServer specific
6
16
  # support via JDBC.
7
17
  module SQLServer
@@ -2,6 +2,10 @@ require 'odbc'
2
2
 
3
3
  module Sequel
4
4
  module ODBC
5
+ # Contains procs keyed on subadapter type that extend the
6
+ # given database object so it supports the correct database type.
7
+ DATABASE_SETUP = {}
8
+
5
9
  class Database < Sequel::Database
6
10
  set_adapter_scheme :odbc
7
11
 
@@ -61,20 +65,8 @@ module Sequel
61
65
  private
62
66
 
63
67
  def adapter_initialize
64
- case @opts[:db_type]
65
- when 'mssql'
66
- Sequel.require 'adapters/odbc/mssql'
67
- extend Sequel::ODBC::MSSQL::DatabaseMethods
68
- self.dataset_class = Sequel::ODBC::MSSQL::Dataset
69
- set_mssql_unicode_strings
70
- when 'progress'
71
- Sequel.require 'adapters/shared/progress'
72
- extend Sequel::Progress::DatabaseMethods
73
- extend_datasets(Sequel::Progress::DatasetMethods)
74
- when 'db2'
75
- Sequel.require 'adapters/shared/db2'
76
- extend ::Sequel::DB2::DatabaseMethods
77
- extend_datasets ::Sequel::DB2::DatasetMethods
68
+ if (db_type = @opts[:db_type]) && (prok = Sequel::Database.load_adapter(db_type.to_sym, :map=>DATABASE_SETUP, :subdir=>'odbc'))
69
+ prok.call(self)
78
70
  end
79
71
  end
80
72
 
@@ -0,0 +1,9 @@
1
+ Sequel.require 'adapters/shared/db2'
2
+
3
+ Sequel.synchronize do
4
+ Sequel::ODBC::DATABASE_SETUP[:db2] = proc do |db|
5
+ db.extend ::Sequel::DB2::DatabaseMethods
6
+ db.extend_datasets ::Sequel::DB2::DatasetMethods
7
+ end
8
+ end
9
+
@@ -2,6 +2,14 @@ Sequel.require 'adapters/shared/mssql'
2
2
 
3
3
  module Sequel
4
4
  module ODBC
5
+ Sequel.synchronize do
6
+ DATABASE_SETUP[:mssql] = proc do |db|
7
+ db.extend Sequel::ODBC::MSSQL::DatabaseMethods
8
+ db.dataset_class = Sequel::ODBC::MSSQL::Dataset
9
+ db.send(:set_mssql_unicode_strings)
10
+ end
11
+ end
12
+
5
13
  # Database and Dataset instance methods for MSSQL specific
6
14
  # support via ODBC.
7
15
  module MSSQL
@@ -0,0 +1,8 @@
1
+ Sequel.require 'adapters/shared/progress'
2
+
3
+ Sequel.synchronize do
4
+ Sequel::ODBC::DATABASE_SETUP[:progress] = proc do |db|
5
+ db.extend Sequel::Progress::DatabaseMethods
6
+ db.extend_datasets(Sequel::Progress::DatasetMethods)
7
+ end
8
+ end
@@ -273,7 +273,7 @@ module Sequel
273
273
 
274
274
  # Default values
275
275
  defaults = begin
276
- metadata_dataset.from(:user_tab_cols).
276
+ metadata_dataset.from(:all_tab_cols).
277
277
  where(:table_name=>im.call(table)).
278
278
  to_hash(:column_name, :data_default)
279
279
  rescue DatabaseError
@@ -108,7 +108,7 @@ module Sequel
108
108
  # PGconn subclass for connection specific methods used with the
109
109
  # pg, postgres, or postgres-pr driver.
110
110
  class Adapter < ::PGconn
111
- DISCONNECT_ERROR_RE = /\A(?:could not receive data from server|no connection to the server|connection not open)/
111
+ DISCONNECT_ERROR_RE = /\A(?:could not receive data from server|no connection to the server|connection not open|terminating connection due to administrator command)/
112
112
 
113
113
  self.translate_results = false if respond_to?(:translate_results=)
114
114
 
@@ -175,7 +175,14 @@ module Sequel
175
175
 
176
176
  # Insert a record returning the record inserted
177
177
  def insert_select(*values)
178
- returning.insert(*values){|r| return r}
178
+ with_sql_first(insert_select_sql(*values))
179
+ end
180
+
181
+ # The SQL to use for an insert_select, adds a RETURNING clause to the insert
182
+ # unless the RETURNING clause is already present.
183
+ def insert_select_sql(*values)
184
+ ds = opts[:returning] ? self : returning
185
+ ds.insert_sql(*values)
179
186
  end
180
187
 
181
188
  def requires_sql_standard_datetimes?
@@ -525,7 +525,6 @@ module Sequel
525
525
  DATEPART_SECOND_MIDDLE = ') + datepart(ns, '.freeze
526
526
  DATEPART_SECOND_CLOSE = ")/1000000000.0) AS double precision)".freeze
527
527
  DATEPART_OPEN = "datepart(".freeze
528
- TIMESTAMP_USEC_FORMAT = ".%03d".freeze
529
528
  OUTPUT_INSERTED = " OUTPUT INSERTED.*".freeze
530
529
  HEX_START = '0x'.freeze
531
530
  UNICODE_STRING_START = "N'".freeze
@@ -624,7 +623,14 @@ module Sequel
624
623
  # Use the OUTPUT clause to get the value of all columns for the newly inserted record.
625
624
  def insert_select(*values)
626
625
  return unless supports_insert_select?
627
- naked.clone(default_server_opts(:sql=>output(nil, [SQL::ColumnAll.new(:inserted)]).insert_sql(*values))).single_record
626
+ with_sql_first(insert_select_sql(*values))
627
+ end
628
+
629
+ # Add OUTPUT clause unless there is already an existing output clause, then return
630
+ # the SQL to insert.
631
+ def insert_select_sql(*values)
632
+ ds = (opts[:output] || opts[:returning]) ? self : output(nil, [SQL::ColumnAll.new(:inserted)])
633
+ ds.insert_sql(*values)
628
634
  end
629
635
 
630
636
  # Specify a table for a SELECT ... INTO query.
@@ -658,20 +664,31 @@ module Sequel
658
664
  raise(Error, "SQL Server versions 2000 and earlier do not support the OUTPUT clause") unless supports_output_clause?
659
665
  output = {}
660
666
  case values
661
- when Hash
662
- output[:column_list], output[:select_list] = values.keys, values.values
663
- when Array
664
- output[:select_list] = values
667
+ when Hash
668
+ output[:column_list], output[:select_list] = values.keys, values.values
669
+ when Array
670
+ output[:select_list] = values
665
671
  end
666
672
  output[:into] = into
667
- clone({:output => output})
673
+ clone(:output => output)
668
674
  end
669
675
 
670
676
  # MSSQL uses [] to quote identifiers.
671
677
  def quoted_identifier_append(sql, name)
672
678
  sql << BRACKET_OPEN << name.to_s.gsub(/\]/, DOUBLE_BRACKET_CLOSE) << BRACKET_CLOSE
673
679
  end
674
-
680
+
681
+ # Emulate RETURNING using the output clause. This only handles values that are simple column references.
682
+ def returning(*values)
683
+ values = values.map do |v|
684
+ unless r = unqualified_column_for(v)
685
+ raise(Error, "cannot emulate RETURNING via OUTPUT for value: #{v.inspect}")
686
+ end
687
+ r
688
+ end
689
+ clone(:returning=>values)
690
+ end
691
+
675
692
  # On MSSQL 2012+ add a default order to the current dataset if an offset is used.
676
693
  # The default offset emulation using a subquery would be used in the unordered
677
694
  # case by default, and that also adds a default order, so it's better to just
@@ -738,11 +755,16 @@ module Sequel
738
755
  is_2012_or_later?
739
756
  end
740
757
 
741
- # MSSQL 2005+ supports the output clause.
758
+ # MSSQL 2005+ supports the OUTPUT clause.
742
759
  def supports_output_clause?
743
760
  is_2005_or_later?
744
761
  end
745
762
 
763
+ # MSSQL 2005+ can emulate RETURNING via the OUTPUT clause.
764
+ def supports_returning?(type)
765
+ supports_insert_select?
766
+ end
767
+
746
768
  # MSSQL 2005+ supports window functions
747
769
  def supports_window_functions?
748
770
  true
@@ -816,6 +838,10 @@ module Sequel
816
838
  end
817
839
  alias update_from_sql delete_from2_sql
818
840
 
841
+ def delete_output_sql(sql)
842
+ output_sql(sql, :DELETED)
843
+ end
844
+
819
845
  # There is no function on Microsoft SQL Server that does character length
820
846
  # and respects trailing spaces (datalength respects trailing spaces, but
821
847
  # counts bytes instead of characters). Use a hack to work around the
@@ -844,22 +870,10 @@ module Sequel
844
870
  @db.schema(self).map{|k, v| k if v[:primary_key] == true}.compact.first
845
871
  end
846
872
 
847
- # MSSQL raises an error if you try to provide more than 3 decimal places
848
- # for a fractional timestamp. This probably doesn't work for smalldatetime
849
- # fields.
850
- def format_timestamp_usec(usec)
851
- sprintf(TIMESTAMP_USEC_FORMAT, usec/1000)
852
- end
853
-
854
- # Use OUTPUT INSERTED.* to return all columns of the inserted row,
855
- # for use with the prepared statement code.
856
873
  def insert_output_sql(sql)
857
- if @opts.has_key?(:returning)
858
- sql << OUTPUT_INSERTED
859
- else
860
- output_sql(sql)
861
- end
874
+ output_sql(sql, :INSERTED)
862
875
  end
876
+ alias update_output_sql insert_output_sql
863
877
 
864
878
  # Handle CROSS APPLY and OUTER APPLY JOIN types
865
879
  def join_type_sql(join_type)
@@ -964,9 +978,16 @@ module Sequel
964
978
  end
965
979
 
966
980
  # SQL fragment for MSSQL's OUTPUT clause.
967
- def output_sql(sql)
981
+ def output_sql(sql, type)
968
982
  return unless supports_output_clause?
969
- return unless output = @opts[:output]
983
+ if output = @opts[:output]
984
+ output_list_sql(sql, output)
985
+ elsif values = @opts[:returning]
986
+ output_returning_sql(sql, type, values)
987
+ end
988
+ end
989
+
990
+ def output_list_sql(sql, output)
970
991
  sql << OUTPUT
971
992
  column_list_append(sql, output[:select_list])
972
993
  if into = output[:into]
@@ -979,8 +1000,28 @@ module Sequel
979
1000
  end
980
1001
  end
981
1002
  end
982
- alias delete_output_sql output_sql
983
- alias update_output_sql output_sql
1003
+
1004
+ def output_returning_sql(sql, type, values)
1005
+ sql << OUTPUT
1006
+ if values.empty?
1007
+ literal_append(sql, SQL::ColumnAll.new(type))
1008
+ else
1009
+ values = values.map do |v|
1010
+ case v
1011
+ when SQL::AliasedExpression
1012
+ Sequel.qualify(type, v.expression).as(v.alias)
1013
+ else
1014
+ Sequel.qualify(type, v)
1015
+ end
1016
+ end
1017
+ column_list_append(sql, values)
1018
+ end
1019
+ end
1020
+
1021
+ # MSSQL supports millisecond timestamp precision.
1022
+ def timestamp_precision
1023
+ 3
1024
+ end
984
1025
 
985
1026
  # Only include the primary table in the main update clause
986
1027
  def update_table_sql(sql)