sequel 4.12.0 → 4.13.0

Sign up to get free protection for your applications and to get access to all the features.
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)