sequel 3.34.0 → 3.35.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 (102) hide show
  1. data/CHANGELOG +56 -0
  2. data/README.rdoc +3 -1
  3. data/Rakefile +2 -10
  4. data/doc/active_record.rdoc +1 -0
  5. data/doc/migration.rdoc +18 -7
  6. data/doc/model_hooks.rdoc +6 -0
  7. data/doc/opening_databases.rdoc +3 -0
  8. data/doc/prepared_statements.rdoc +0 -1
  9. data/doc/release_notes/3.35.0.txt +144 -0
  10. data/doc/schema_modification.rdoc +16 -1
  11. data/doc/thread_safety.rdoc +17 -0
  12. data/lib/sequel/adapters/do/postgres.rb +1 -52
  13. data/lib/sequel/adapters/do/sqlite.rb +0 -5
  14. data/lib/sequel/adapters/do.rb +2 -2
  15. data/lib/sequel/adapters/firebird.rb +1 -1
  16. data/lib/sequel/adapters/ibmdb.rb +2 -2
  17. data/lib/sequel/adapters/jdbc/db2.rb +0 -5
  18. data/lib/sequel/adapters/jdbc/derby.rb +29 -2
  19. data/lib/sequel/adapters/jdbc/firebird.rb +0 -5
  20. data/lib/sequel/adapters/jdbc/h2.rb +1 -1
  21. data/lib/sequel/adapters/jdbc/hsqldb.rb +7 -0
  22. data/lib/sequel/adapters/jdbc/informix.rb +0 -5
  23. data/lib/sequel/adapters/jdbc/jtds.rb +0 -5
  24. data/lib/sequel/adapters/jdbc/mysql.rb +0 -5
  25. data/lib/sequel/adapters/jdbc/postgresql.rb +4 -35
  26. data/lib/sequel/adapters/jdbc/sqlite.rb +0 -5
  27. data/lib/sequel/adapters/jdbc/sqlserver.rb +0 -5
  28. data/lib/sequel/adapters/jdbc/transactions.rb +4 -4
  29. data/lib/sequel/adapters/jdbc.rb +23 -19
  30. data/lib/sequel/adapters/mysql2.rb +1 -1
  31. data/lib/sequel/adapters/odbc/mssql.rb +14 -1
  32. data/lib/sequel/adapters/odbc.rb +3 -3
  33. data/lib/sequel/adapters/oracle.rb +6 -18
  34. data/lib/sequel/adapters/postgres.rb +36 -53
  35. data/lib/sequel/adapters/shared/db2.rb +16 -2
  36. data/lib/sequel/adapters/shared/mssql.rb +40 -9
  37. data/lib/sequel/adapters/shared/mysql.rb +16 -4
  38. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +2 -2
  39. data/lib/sequel/adapters/shared/oracle.rb +2 -0
  40. data/lib/sequel/adapters/shared/postgres.rb +135 -211
  41. data/lib/sequel/adapters/sqlite.rb +2 -2
  42. data/lib/sequel/adapters/swift/postgres.rb +1 -71
  43. data/lib/sequel/adapters/swift.rb +1 -1
  44. data/lib/sequel/adapters/tinytds.rb +3 -3
  45. data/lib/sequel/core.rb +27 -4
  46. data/lib/sequel/database/connecting.rb +7 -8
  47. data/lib/sequel/database/logging.rb +6 -1
  48. data/lib/sequel/database/misc.rb +20 -4
  49. data/lib/sequel/database/query.rb +38 -18
  50. data/lib/sequel/database/schema_generator.rb +5 -2
  51. data/lib/sequel/database/schema_methods.rb +34 -8
  52. data/lib/sequel/dataset/prepared_statements.rb +1 -1
  53. data/lib/sequel/dataset/sql.rb +18 -24
  54. data/lib/sequel/extensions/core_extensions.rb +0 -23
  55. data/lib/sequel/extensions/migration.rb +22 -8
  56. data/lib/sequel/extensions/pg_auto_parameterize.rb +4 -0
  57. data/lib/sequel/extensions/schema_dumper.rb +1 -1
  58. data/lib/sequel/model/associations.rb +95 -70
  59. data/lib/sequel/model/base.rb +19 -20
  60. data/lib/sequel/model.rb +2 -2
  61. data/lib/sequel/plugins/dirty.rb +214 -0
  62. data/lib/sequel/plugins/identity_map.rb +1 -1
  63. data/lib/sequel/plugins/json_serializer.rb +16 -1
  64. data/lib/sequel/plugins/many_through_many.rb +22 -32
  65. data/lib/sequel/plugins/many_to_one_pk_lookup.rb +2 -2
  66. data/lib/sequel/plugins/prepared_statements.rb +22 -8
  67. data/lib/sequel/plugins/prepared_statements_associations.rb +2 -3
  68. data/lib/sequel/plugins/prepared_statements_with_pk.rb +1 -1
  69. data/lib/sequel/plugins/single_table_inheritance.rb +1 -1
  70. data/lib/sequel/plugins/subclasses.rb +10 -2
  71. data/lib/sequel/plugins/timestamps.rb +1 -1
  72. data/lib/sequel/plugins/xml_serializer.rb +12 -1
  73. data/lib/sequel/sql.rb +1 -1
  74. data/lib/sequel/version.rb +1 -1
  75. data/spec/adapters/postgres_spec.rb +30 -79
  76. data/spec/core/database_spec.rb +46 -2
  77. data/spec/core/dataset_spec.rb +28 -22
  78. data/spec/core/schema_generator_spec.rb +1 -1
  79. data/spec/core/schema_spec.rb +51 -0
  80. data/spec/extensions/arbitrary_servers_spec.rb +0 -4
  81. data/spec/extensions/association_autoreloading_spec.rb +17 -0
  82. data/spec/extensions/association_proxies_spec.rb +4 -4
  83. data/spec/extensions/core_extensions_spec.rb +1 -24
  84. data/spec/extensions/dirty_spec.rb +155 -0
  85. data/spec/extensions/json_serializer_spec.rb +13 -0
  86. data/spec/extensions/migration_spec.rb +28 -15
  87. data/spec/extensions/named_timezones_spec.rb +6 -8
  88. data/spec/extensions/pg_auto_parameterize_spec.rb +6 -5
  89. data/spec/extensions/schema_dumper_spec.rb +3 -1
  90. data/spec/extensions/single_table_inheritance_spec.rb +5 -0
  91. data/spec/extensions/xml_serializer_spec.rb +13 -0
  92. data/spec/files/{transactionless_migrations → transaction_specified_migrations}/001_create_alt_basic.rb +1 -1
  93. data/spec/integration/associations_test.rb +5 -7
  94. data/spec/integration/dataset_test.rb +25 -7
  95. data/spec/integration/plugin_test.rb +1 -1
  96. data/spec/integration/schema_test.rb +16 -1
  97. data/spec/model/associations_spec.rb +2 -2
  98. metadata +14 -9
  99. data/lib/sequel/adapters/odbc/db2.rb +0 -17
  100. /data/spec/files/{transactionless_migrations → transaction_specified_migrations}/002_create_basic.rb +0 -0
  101. /data/spec/files/{transaction_migrations → transaction_unspecified_migrations}/001_create_alt_basic.rb +0 -0
  102. /data/spec/files/{transaction_migrations → transaction_unspecified_migrations}/002_create_basic.rb +0 -0
@@ -5,11 +5,6 @@ module Sequel
5
5
  # Database and Dataset instance methods for JTDS specific
6
6
  # support via JDBC.
7
7
  module JTDS
8
- # Database instance methods for JTDS databases accessed via JDBC.
9
- module DatabaseMethods
10
- include Sequel::JDBC::MSSQL::DatabaseMethods
11
- end
12
-
13
8
  # Dataset class for JTDS datasets accessed via JDBC.
14
9
  class Dataset < JDBC::Dataset
15
10
  include Sequel::MSSQL::DatasetMethods
@@ -62,11 +62,6 @@ module Sequel
62
62
  conn
63
63
  end
64
64
  end
65
-
66
- # Dataset class for MySQL datasets accessed via JDBC.
67
- class Dataset < JDBC::Dataset
68
- include Sequel::MySQL::DatasetMethods
69
- end
70
65
  end
71
66
  end
72
67
  end
@@ -7,32 +7,6 @@ module Sequel
7
7
  # Adapter, Database, and Dataset support for accessing a PostgreSQL
8
8
  # database via JDBC.
9
9
  module Postgres
10
- # Methods to add to the JDBC adapter/connection to allow it to work
11
- # with the shared PostgreSQL code.
12
- module AdapterMethods
13
- include Sequel::Postgres::AdapterMethods
14
-
15
- # Give the JDBC adapter a direct execute method, which creates
16
- # a statement with the given sql and executes it.
17
- def execute(sql, args=nil)
18
- method = block_given? ? :executeQuery : :execute
19
- @db.send(:statement, self) do |stmt|
20
- rows = @db.log_yield(sql){stmt.send(method, sql)}
21
- yield(rows) if block_given?
22
- end
23
- end
24
-
25
- private
26
-
27
- # JDBC specific method of getting specific values from a result set.
28
- def single_value(r)
29
- unless r.nil?
30
- r.next
31
- r.getString(1) unless r.getRow == 0
32
- end
33
- end
34
- end
35
-
36
10
  # Methods to add to Database instances that access PostgreSQL via
37
11
  # JDBC.
38
12
  module DatabaseMethods
@@ -55,19 +29,14 @@ module Sequel
55
29
  arg.nil? ? cps.setNull(i, JavaSQL::Types::NULL) : super
56
30
  end
57
31
 
58
- # Extend the adapter with the JDBC PostgreSQL AdapterMethods
32
+ # Execute the connection configuration SQL queries on the connection.
59
33
  def setup_connection(conn)
60
34
  conn = super(conn)
61
- conn.extend(Sequel::JDBC::Postgres::AdapterMethods)
62
- conn.db = self
63
- conn.apply_connection_settings
35
+ statement(conn) do |stmt|
36
+ connection_configuration_sqls.each{|sql| log_yield(sql){stmt.execute(sql)}}
37
+ end
64
38
  conn
65
39
  end
66
-
67
- # Call insert_result with the table and values specified in the opts.
68
- def last_insert_id(conn, opts)
69
- insert_result(conn, opts[:table], opts[:values])
70
- end
71
40
  end
72
41
 
73
42
  # Dataset subclass used for datasets that connect to PostgreSQL via JDBC.
@@ -54,11 +54,6 @@ module Sequel
54
54
  conn
55
55
  end
56
56
  end
57
-
58
- # Dataset class for SQLite datasets accessed via JDBC.
59
- class Dataset < JDBC::Dataset
60
- include Sequel::SQLite::DatasetMethods
61
- end
62
57
  end
63
58
  end
64
59
  end
@@ -61,11 +61,6 @@ module Sequel
61
61
  super.extend(MetadataDatasetMethods)
62
62
  end
63
63
  end
64
-
65
- # Dataset class for SQLServer datasets accessed via JDBC.
66
- class Dataset < JDBC::Dataset
67
- include Sequel::MSSQL::DatasetMethods
68
- end
69
64
  end
70
65
  end
71
66
  end
@@ -24,7 +24,7 @@ module Sequel
24
24
  # Use JDBC connection's setAutoCommit to false to start transactions
25
25
  def begin_transaction(conn, opts={})
26
26
  if supports_savepoints?
27
- th = @transactions[conn]
27
+ th = _trans(conn)
28
28
  if sps = th[:savepoints]
29
29
  sps << log_yield(TRANSACTION_SAVEPOINT){conn.set_savepoint}
30
30
  else
@@ -40,7 +40,7 @@ module Sequel
40
40
  # Use JDBC connection's commit method to commit transactions
41
41
  def commit_transaction(conn, opts={})
42
42
  if supports_savepoints?
43
- sps = @transactions[conn][:savepoints]
43
+ sps = _trans(conn)[:savepoints]
44
44
  if sps.empty?
45
45
  log_yield(TRANSACTION_COMMIT){conn.commit}
46
46
  elsif supports_releasing_savepoints?
@@ -54,7 +54,7 @@ module Sequel
54
54
  # Use JDBC connection's setAutoCommit to true to enable non-transactional behavior
55
55
  def remove_transaction(conn, committed)
56
56
  if supports_savepoints?
57
- sps = @transactions[conn][:savepoints]
57
+ sps = _trans(conn)[:savepoints]
58
58
  conn.setAutoCommit(true) if sps.empty?
59
59
  sps.pop
60
60
  else
@@ -67,7 +67,7 @@ module Sequel
67
67
  # Use JDBC connection's rollback method to rollback transactions
68
68
  def rollback_transaction(conn, opts={})
69
69
  if supports_savepoints?
70
- sps = @transactions[conn][:savepoints]
70
+ sps = _trans(conn)[:savepoints]
71
71
  if sps.empty?
72
72
  log_yield(TRANSACTION_ROLLBACK){conn.rollback}
73
73
  else
@@ -39,14 +39,14 @@ module Sequel
39
39
  :mysql=>proc do |db|
40
40
  Sequel.ts_require 'adapters/jdbc/mysql'
41
41
  db.extend(Sequel::JDBC::MySQL::DatabaseMethods)
42
- db.dataset_class = Sequel::JDBC::MySQL::Dataset
42
+ db.extend_datasets Sequel::MySQL::DatasetMethods
43
43
  JDBC.load_gem('mysql')
44
44
  com.mysql.jdbc.Driver
45
45
  end,
46
46
  :sqlite=>proc do |db|
47
47
  Sequel.ts_require 'adapters/jdbc/sqlite'
48
48
  db.extend(Sequel::JDBC::SQLite::DatabaseMethods)
49
- db.dataset_class = Sequel::JDBC::SQLite::Dataset
49
+ db.extend_datasets Sequel::SQLite::DatasetMethods
50
50
  db.set_integer_booleans
51
51
  JDBC.load_gem('sqlite3')
52
52
  org.sqlite.JDBC
@@ -60,13 +60,13 @@ module Sequel
60
60
  :sqlserver=>proc do |db|
61
61
  Sequel.ts_require 'adapters/jdbc/sqlserver'
62
62
  db.extend(Sequel::JDBC::SQLServer::DatabaseMethods)
63
- db.dataset_class = Sequel::JDBC::SQLServer::Dataset
63
+ db.extend_datasets Sequel::MSSQL::DatasetMethods
64
64
  db.send(:set_mssql_unicode_strings)
65
65
  com.microsoft.sqlserver.jdbc.SQLServerDriver
66
66
  end,
67
67
  :jtds=>proc do |db|
68
68
  Sequel.ts_require 'adapters/jdbc/jtds'
69
- db.extend(Sequel::JDBC::JTDS::DatabaseMethods)
69
+ db.extend(Sequel::JDBC::MSSQL::DatabaseMethods)
70
70
  db.dataset_class = Sequel::JDBC::JTDS::Dataset
71
71
  db.send(:set_mssql_unicode_strings)
72
72
  JDBC.load_gem('jtds')
@@ -102,19 +102,19 @@ module Sequel
102
102
  :"informix-sqli"=>proc do |db|
103
103
  Sequel.ts_require 'adapters/jdbc/informix'
104
104
  db.extend(Sequel::JDBC::Informix::DatabaseMethods)
105
- db.dataset_class = Sequel::JDBC::Informix::Dataset
105
+ db.extend_datasets Sequel::Informix::DatasetMethods
106
106
  com.informix.jdbc.IfxDriver
107
107
  end,
108
108
  :db2=>proc do |db|
109
109
  Sequel.ts_require 'adapters/jdbc/db2'
110
110
  db.extend(Sequel::JDBC::DB2::DatabaseMethods)
111
- db.dataset_class = Sequel::JDBC::DB2::Dataset
111
+ db.extend_datasets Sequel::DB2::DatasetMethods
112
112
  com.ibm.db2.jcc.DB2Driver
113
113
  end,
114
114
  :firebirdsql=>proc do |db|
115
115
  Sequel.ts_require 'adapters/jdbc/firebird'
116
116
  db.extend(Sequel::JDBC::Firebird::DatabaseMethods)
117
- db.dataset_class = Sequel::JDBC::Firebird::Dataset
117
+ db.extend_datasets Sequel::Firebird::DatasetMethods
118
118
  org.firebirdsql.jdbc.FBDriver
119
119
  end
120
120
  }
@@ -151,6 +151,8 @@ module Sequel
151
151
  # uri, since JDBC requires one.
152
152
  def initialize(opts)
153
153
  super
154
+ @connection_prepared_statements = {}
155
+ @connection_prepared_statements_mutex = Mutex.new
154
156
  @convert_types = typecast_value_boolean(@opts.fetch(:convert_types, true))
155
157
  raise(Error, "No connection string specified") unless uri
156
158
 
@@ -312,8 +314,15 @@ module Sequel
312
314
 
313
315
  private
314
316
 
315
- # Close given adapter connections
317
+ # Yield the native prepared statements hash for the given connection
318
+ # to the block in a thread-safe manner.
319
+ def cps_sync(conn, &block)
320
+ @connection_prepared_statements_mutex.synchronize{yield(@connection_prepared_statements[conn] ||= {})}
321
+ end
322
+
323
+ # Close given adapter connections, and delete any related prepared statements.
316
324
  def disconnect_connection(c)
325
+ @connection_prepared_statements_mutex.synchronize{@connection_prepared_statements.delete(c)}
317
326
  c.close
318
327
  end
319
328
 
@@ -336,16 +345,16 @@ module Sequel
336
345
  ps = name
337
346
  name = ps.prepared_statement_name
338
347
  else
339
- ps = prepared_statements[name]
348
+ ps = prepared_statement(name)
340
349
  end
341
350
  sql = ps.prepared_sql
342
351
  synchronize(opts[:server]) do |conn|
343
- if name and cps = conn.prepared_statements[name] and cps[0] == sql
352
+ if name and cps = cps_sync(conn){|cpsh| cpsh[name]} and cps[0] == sql
344
353
  cps = cps[1]
345
354
  else
346
355
  log_yield("CLOSE #{name}"){cps[1].close} if cps
347
356
  cps = log_yield("PREPARE#{" #{name}:" if name} #{sql}"){conn.prepareStatement(sql)}
348
- conn.prepared_statements[name] = [sql, cps] if name
357
+ cps_sync(conn){|cpsh| cpsh[name] = [sql, cps]} if name
349
358
  end
350
359
  i = 0
351
360
  args.each{|arg| set_ps_arg(cps, arg, i+=1)}
@@ -476,14 +485,9 @@ module Sequel
476
485
  end
477
486
  end
478
487
 
479
- # Add a prepared_statements accessor to the connection,
480
- # and set it to an empty hash. This is used to store
481
- # adapter specific prepared statements.
488
+ # Return the connection. Used to do configuration on the
489
+ # connection object before adding it to the connection pool.
482
490
  def setup_connection(conn)
483
- class << conn
484
- attr_accessor :prepared_statements
485
- end
486
- conn.prepared_statements = {}
487
491
  conn
488
492
  end
489
493
 
@@ -608,7 +612,7 @@ module Sequel
608
612
  ps.extend(PreparedStatementMethods)
609
613
  if name
610
614
  ps.prepared_statement_name = name
611
- db.prepared_statements[name] = ps
615
+ db.set_prepared_statement(name, ps)
612
616
  end
613
617
  ps
614
618
  end
@@ -1,4 +1,4 @@
1
- require 'mysql2' unless defined? Mysql2
1
+ require 'mysql2'
2
2
  Sequel.require %w'shared/mysql_prepared_statements', 'adapters'
3
3
 
4
4
  module Sequel
@@ -28,9 +28,22 @@ module Sequel
28
28
  end
29
29
  end
30
30
  end
31
-
32
31
  class Dataset < ODBC::Dataset
33
32
  include Sequel::MSSQL::DatasetMethods
33
+
34
+ private
35
+
36
+ # Use ODBC format, not Microsoft format, as the ODBC layer does
37
+ # some translation.
38
+ def default_timestamp_format
39
+ TIMESTAMP_FORMAT
40
+ end
41
+
42
+ # Use ODBC format, not Microsoft format, as the ODBC layer does
43
+ # some translation.
44
+ def literal_date(v)
45
+ v.strftime(ODBC_DATE_FORMAT)
46
+ end
34
47
  end
35
48
  end
36
49
  end
@@ -22,9 +22,9 @@ module Sequel
22
22
  extend Sequel::Progress::DatabaseMethods
23
23
  extend_datasets(Sequel::Progress::DatasetMethods)
24
24
  when 'db2'
25
- Sequel.ts_require 'adapters/odbc/db2'
26
- extend Sequel::ODBC::DB2::DatabaseMethods
27
- @dataset_class = Sequel::ODBC::DB2::Dataset
25
+ Sequel.ts_require 'adapters/shared/db2'
26
+ extend ::Sequel::DB2::DatabaseMethods
27
+ extend_datasets ::Sequel::DB2::DatasetMethods
28
28
  end
29
29
  end
30
30
 
@@ -126,7 +126,7 @@ module Sequel
126
126
  end
127
127
 
128
128
  def execute_prepared_statement(conn, type, name, opts)
129
- ps = prepared_statements[name]
129
+ ps = prepared_statement(name)
130
130
  sql = ps.prepared_sql
131
131
  if cursora = conn.prepared_statements[name]
132
132
  cursor, cursor_sql = cursora
@@ -243,7 +243,7 @@ module Sequel
243
243
 
244
244
  # Default values
245
245
  defaults = begin
246
- metadata_dataset.from(:dba_tab_cols).
246
+ metadata_dataset.from(:user_tab_cols).
247
247
  where(:table_name=>im.call(table)).
248
248
  to_hash(:column_name, :data_default)
249
249
  rescue DatabaseError
@@ -370,19 +370,6 @@ module Sequel
370
370
  ps.call(bind_vars, &block)
371
371
  end
372
372
 
373
- # Prepare the given type of query with the given name and store
374
- # it in the database. Note that a new native prepared statement is
375
- # created on each call to this prepared statement.
376
- def prepare(type, name=nil, *values)
377
- ps = to_prepared_statement(type, values)
378
- ps.extend(PreparedStatementMethods)
379
- if name
380
- ps.prepared_statement_name = name
381
- db.prepared_statements[name] = ps
382
- end
383
- ps
384
- end
385
-
386
373
  def fetch_rows(sql)
387
374
  execute(sql) do |cursor|
388
375
  offset = @opts[:offset]
@@ -403,14 +390,15 @@ module Sequel
403
390
  self
404
391
  end
405
392
 
406
- # Create a named prepared statement that is stored in the
407
- # database (and connection) for reuse.
393
+ # Prepare the given type of query with the given name and store
394
+ # it in the database. Note that a new native prepared statement is
395
+ # created on each call to this prepared statement.
408
396
  def prepare(type, name=nil, *values)
409
397
  ps = to_prepared_statement(type, values)
410
398
  ps.extend(PreparedStatementMethods)
411
399
  if name
412
400
  ps.prepared_statement_name = name
413
- db.prepared_statements[name] = ps
401
+ db.set_prepared_statement(name, ps)
414
402
  end
415
403
  ps
416
404
  end
@@ -12,7 +12,7 @@ rescue LoadError => e
12
12
  class PGconn
13
13
  unless method_defined?(:escape_string)
14
14
  if self.respond_to?(:escape)
15
- # If there is no escape_string instead method, but there is an
15
+ # If there is no escape_string instance method, but there is an
16
16
  # escape class method, use that instead.
17
17
  def escape_string(str)
18
18
  Sequel::Postgres.force_standard_strings ? str.gsub("'", "''") : self.class.escape(str)
@@ -91,24 +91,29 @@ module Sequel
91
91
  NAN = 0.0/0.0
92
92
  PLUS_INFINITY = 1.0/0.0
93
93
  MINUS_INFINITY = -1.0/0.0
94
+ NAN_STR = 'NaN'.freeze
95
+ PLUS_INFINITY_STR = 'Infinity'.freeze
96
+ MINUS_INFINITY_STR = '-Infinity'.freeze
97
+ TRUE_STR = 't'.freeze
98
+ DASH_STR = '-'.freeze
94
99
 
95
100
  TYPE_TRANSLATOR = tt = Class.new do
96
- def boolean(s) s == 't' end
101
+ def boolean(s) s == TRUE_STR end
97
102
  def bytea(s) ::Sequel::SQL::Blob.new(Adapter.unescape_bytea(s)) end
98
103
  def integer(s) s.to_i end
99
104
  def float(s)
100
105
  case s
101
- when 'NaN'
106
+ when NAN_STR
102
107
  NAN
103
- when 'Infinity'
108
+ when PLUS_INFINITY_STR
104
109
  PLUS_INFINITY
105
- when '-Infinity'
110
+ when MINUS_INFINITY_STR
106
111
  MINUS_INFINITY
107
112
  else
108
113
  s.to_f
109
114
  end
110
115
  end
111
- def date(s) ::Date.new(*s.split("-").map{|x| x.to_i}) end
116
+ def date(s) ::Date.new(*s.split(DASH_STR).map{|x| x.to_i}) end
112
117
  end.new
113
118
 
114
119
  # Hash with type name strings/symbols and callable values for converting PostgreSQL types.
@@ -149,8 +154,6 @@ module Sequel
149
154
  class Adapter < ::PGconn
150
155
  DISCONNECT_ERROR_RE = /\Acould not receive data from server: Software caused connection abort/
151
156
 
152
- include Sequel::Postgres::AdapterMethods
153
-
154
157
  self.translate_results = false if respond_to?(:translate_results=)
155
158
 
156
159
  # Hash of prepared statements for this connection. Keys are
@@ -158,18 +161,6 @@ module Sequel
158
161
  # are SQL strings.
159
162
  attr_reader(:prepared_statements) if SEQUEL_POSTGRES_USES_PG
160
163
 
161
- # Apply connection settings for this connection. Current sets
162
- # the date style to ISO in order make Date object creation in ruby faster,
163
- # if Postgres.use_iso_date_format is true.
164
- def apply_connection_settings
165
- super
166
- if Postgres.use_iso_date_format
167
- sql = "SET DateStyle = 'ISO'"
168
- execute(sql)
169
- end
170
- @prepared_statements = {} if SEQUEL_POSTGRES_USES_PG
171
- end
172
-
173
164
  # Raise a Sequel::DatabaseDisconnectError if a PGError is raised and
174
165
  # the connection status cannot be determined or it is not OK.
175
166
  def check_disconnect_errors
@@ -210,11 +201,6 @@ module Sequel
210
201
  def execute_query(sql, args)
211
202
  @db.log_yield(sql, args){args ? async_exec(sql, args) : async_exec(sql)}
212
203
  end
213
-
214
- # Return the requested values for the given row.
215
- def single_value(r)
216
- r.getvalue(0, 0) unless r.nil? || (r.ntuples == 0)
217
- end
218
204
  end
219
205
 
220
206
  # Database class for PostgreSQL databases used with Sequel and the
@@ -223,7 +209,7 @@ module Sequel
223
209
  include Sequel::Postgres::DatabaseMethods
224
210
 
225
211
  INFINITE_TIMESTAMP_STRINGS = ['infinity'.freeze, '-infinity'.freeze].freeze
226
- INFINITE_DATETIME_VALUES = ([1.0/0.0, -1.0/0.0] + INFINITE_TIMESTAMP_STRINGS).freeze
212
+ INFINITE_DATETIME_VALUES = ([PLUS_INFINITY, MINUS_INFINITY] + INFINITE_TIMESTAMP_STRINGS).freeze
227
213
 
228
214
  set_adapter_scheme :postgres
229
215
 
@@ -299,8 +285,9 @@ module Sequel
299
285
  conn.async_exec("set client_encoding to '#{encoding}'")
300
286
  end
301
287
  end
302
- conn.db = self
303
- conn.apply_connection_settings
288
+ conn.instance_variable_set(:@db, self)
289
+ conn.instance_variable_set(:@prepared_statements, {}) if SEQUEL_POSTGRES_USES_PG
290
+ connection_configuration_sqls.each{|sql| conn.execute(sql)}
304
291
  @conversion_procs ||= get_conversion_procs(conn)
305
292
  conn
306
293
  end
@@ -312,19 +299,7 @@ module Sequel
312
299
  synchronize(opts[:server]){|conn| conn.execute(sql, opts[:arguments], &block)}
313
300
  end
314
301
  end
315
-
316
- # Insert the values into the table and return the primary key (if
317
- # automatically generated).
318
- def execute_insert(sql, opts={})
319
- return execute(sql, opts) if Symbol === sql
320
- check_database_errors do
321
- synchronize(opts[:server]) do |conn|
322
- conn.execute(sql, opts[:arguments])
323
- insert_result(conn, opts[:table], opts[:values])
324
- end
325
- end
326
- end
327
-
302
+
328
303
  if SEQUEL_POSTGRES_USES_PG
329
304
  # +copy_table+ uses PostgreSQL's +COPY+ SQL statement to return formatted
330
305
  # results directly to the caller. This method is only supported if pg is the
@@ -470,6 +445,13 @@ module Sequel
470
445
  end
471
446
  end
472
447
 
448
+ # Set the DateStyle to ISO if configured, for faster date parsing.
449
+ def connection_configuration_sqls
450
+ sqls = super
451
+ sqls << "SET DateStyle = 'ISO'" if Postgres.use_iso_date_format
452
+ sqls
453
+ end
454
+
473
455
  # Disconnect given connection
474
456
  def disconnect_connection(conn)
475
457
  begin
@@ -487,7 +469,7 @@ module Sequel
487
469
  # of rows changed. If the :insert option is passed, return the value
488
470
  # of the primary key for the last inserted row.
489
471
  def execute_prepared_statement(name, opts={})
490
- ps = prepared_statements[name]
472
+ ps = prepared_statement(name)
491
473
  sql = ps.prepared_sql
492
474
  ps_name = name.to_s
493
475
  synchronize(opts[:server]) do |conn|
@@ -511,14 +493,10 @@ module Sequel
511
493
  end
512
494
 
513
495
  q = conn.check_disconnect_errors{log_yield(log_sql, args){conn.exec_prepared(ps_name, args)}}
514
- if opts[:table] && opts[:values]
515
- insert_result(conn, opts[:table], opts[:values])
516
- else
517
- begin
518
- block_given? ? yield(q) : q.cmd_tuples
519
- ensure
520
- q.clear
521
- end
496
+ begin
497
+ block_given? ? yield(q) : q.cmd_tuples
498
+ ensure
499
+ q.clear
522
500
  end
523
501
  end
524
502
  end
@@ -549,6 +527,10 @@ module Sequel
549
527
  end
550
528
  end
551
529
 
530
+ # Don't log, since logging is done by the underlying connection.
531
+ def log_connection_execute(conn, sql)
532
+ conn.execute(sql)
533
+ end
552
534
 
553
535
  # If the value is an infinite value (either an infinite float or a string returned by
554
536
  # by PostgreSQL for an infinite timestamp), return it without converting it if
@@ -573,6 +555,7 @@ module Sequel
573
555
  include Sequel::Postgres::DatasetMethods
574
556
 
575
557
  Database::DatasetClass = self
558
+ APOS = Sequel::Dataset::APOS
576
559
 
577
560
  # Yield all rows returned by executing the given SQL and converting
578
561
  # the types.
@@ -708,7 +691,7 @@ module Sequel
708
691
  ps.extend(PreparedStatementMethods)
709
692
  if name
710
693
  ps.prepared_statement_name = name
711
- db.prepared_statements[name] = ps
694
+ db.set_prepared_statement(name, ps)
712
695
  end
713
696
  ps
714
697
  end
@@ -766,12 +749,12 @@ module Sequel
766
749
 
767
750
  # Use the driver's escape_bytea
768
751
  def literal_blob_append(sql, v)
769
- sql << "'" << db.synchronize{|c| c.escape_bytea(v)} << "'"
752
+ sql << APOS << db.synchronize{|c| c.escape_bytea(v)} << APOS
770
753
  end
771
754
 
772
755
  # Use the driver's escape_string
773
756
  def literal_string_append(sql, v)
774
- sql << "'" << db.synchronize{|c| c.escape_string(v)} << "'"
757
+ sql << APOS << db.synchronize{|c| c.escape_string(v)} << APOS
775
758
  end
776
759
 
777
760
  # For each row in the result set, yield a hash with column name symbol
@@ -131,12 +131,24 @@ module Sequel
131
131
  super
132
132
  end
133
133
 
134
+ # Insert data from the current table into the new table after
135
+ # creating the table, since it is not possible to do it in one step.
136
+ def create_table_as(name, sql, options)
137
+ super
138
+ from(name).insert(sql.is_a?(Dataset) ? sql : dataset.with_sql(sql))
139
+ end
140
+
141
+ # DB2 requires parens around the SELECT, and DEFINITION ONLY at the end.
142
+ def create_table_as_sql(name, sql, options)
143
+ "#{create_table_prefix_sql(name, options)} AS (#{sql}) DEFINITION ONLY"
144
+ end
145
+
134
146
  # Here we use DGTT which has most backward compatibility, which uses
135
147
  # DECLARE instead of CREATE. CGTT can only be used after version 9.7.
136
148
  # http://www.ibm.com/developerworks/data/library/techarticle/dm-0912globaltemptable/
137
- def create_table_sql(name, generator, options)
149
+ def create_table_prefix_sql(name, options)
138
150
  if options[:temp]
139
- "DECLARE GLOBAL TEMPORARY TABLE #{quote_identifier(name)} (#{column_list_sql(generator)})"
151
+ "DECLARE GLOBAL TEMPORARY TABLE #{quote_identifier(name)}"
140
152
  else
141
153
  super
142
154
  end
@@ -221,6 +233,8 @@ module Sequel
221
233
  sql << complex_expression_arg_pairs(args){|a, b| "(#{literal(a)} * POWER(2, #{literal(b)}))"}
222
234
  when :>>
223
235
  sql << complex_expression_arg_pairs(args){|a, b| "(#{literal(a)} / POWER(2, #{literal(b)}))"}
236
+ when :%
237
+ sql << complex_expression_arg_pairs(args){|a, b| "MOD(#{literal(a)}, #{literal(b)})"}
224
238
  when :'B~'
225
239
  literal_append(sql, SQL::Function.new(:BITNOT, *args))
226
240
  when :extract