sequel 4.9.0 → 4.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +79 -1
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/Rakefile +2 -12
  6. data/bin/sequel +1 -0
  7. data/doc/advanced_associations.rdoc +82 -25
  8. data/doc/association_basics.rdoc +21 -22
  9. data/doc/core_extensions.rdoc +1 -1
  10. data/doc/opening_databases.rdoc +7 -0
  11. data/doc/release_notes/4.10.0.txt +226 -0
  12. data/doc/security.rdoc +1 -0
  13. data/doc/testing.rdoc +7 -7
  14. data/doc/transactions.rdoc +8 -0
  15. data/lib/sequel/adapters/jdbc.rb +160 -168
  16. data/lib/sequel/adapters/jdbc/db2.rb +17 -18
  17. data/lib/sequel/adapters/jdbc/derby.rb +5 -28
  18. data/lib/sequel/adapters/jdbc/h2.rb +11 -22
  19. data/lib/sequel/adapters/jdbc/hsqldb.rb +31 -18
  20. data/lib/sequel/adapters/jdbc/jtds.rb +0 -15
  21. data/lib/sequel/adapters/jdbc/oracle.rb +36 -35
  22. data/lib/sequel/adapters/jdbc/postgresql.rb +72 -90
  23. data/lib/sequel/adapters/jdbc/sqlanywhere.rb +18 -16
  24. data/lib/sequel/adapters/jdbc/sqlite.rb +7 -0
  25. data/lib/sequel/adapters/jdbc/sqlserver.rb +10 -30
  26. data/lib/sequel/adapters/jdbc/transactions.rb +5 -6
  27. data/lib/sequel/adapters/openbase.rb +1 -7
  28. data/lib/sequel/adapters/postgres.rb +1 -1
  29. data/lib/sequel/adapters/shared/access.rb +3 -6
  30. data/lib/sequel/adapters/shared/cubrid.rb +24 -9
  31. data/lib/sequel/adapters/shared/db2.rb +13 -5
  32. data/lib/sequel/adapters/shared/firebird.rb +16 -16
  33. data/lib/sequel/adapters/shared/informix.rb +2 -5
  34. data/lib/sequel/adapters/shared/mssql.rb +72 -63
  35. data/lib/sequel/adapters/shared/mysql.rb +72 -40
  36. data/lib/sequel/adapters/shared/oracle.rb +27 -15
  37. data/lib/sequel/adapters/shared/postgres.rb +24 -44
  38. data/lib/sequel/adapters/shared/progress.rb +1 -5
  39. data/lib/sequel/adapters/shared/sqlanywhere.rb +26 -18
  40. data/lib/sequel/adapters/shared/sqlite.rb +21 -6
  41. data/lib/sequel/adapters/utils/emulate_offset_with_reverse_and_count.rb +8 -1
  42. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +8 -2
  43. data/lib/sequel/adapters/utils/split_alter_table.rb +8 -0
  44. data/lib/sequel/core.rb +14 -9
  45. data/lib/sequel/database/dataset_defaults.rb +1 -0
  46. data/lib/sequel/database/misc.rb +12 -0
  47. data/lib/sequel/database/query.rb +4 -1
  48. data/lib/sequel/database/schema_methods.rb +3 -2
  49. data/lib/sequel/database/transactions.rb +47 -17
  50. data/lib/sequel/dataset/features.rb +12 -2
  51. data/lib/sequel/dataset/mutation.rb +2 -0
  52. data/lib/sequel/dataset/placeholder_literalizer.rb +12 -4
  53. data/lib/sequel/dataset/prepared_statements.rb +6 -0
  54. data/lib/sequel/dataset/query.rb +1 -1
  55. data/lib/sequel/dataset/sql.rb +132 -70
  56. data/lib/sequel/extensions/columns_introspection.rb +1 -1
  57. data/lib/sequel/extensions/null_dataset.rb +8 -4
  58. data/lib/sequel/extensions/pg_array.rb +4 -4
  59. data/lib/sequel/extensions/pg_row.rb +1 -0
  60. data/lib/sequel/model/associations.rb +468 -188
  61. data/lib/sequel/model/base.rb +88 -13
  62. data/lib/sequel/plugins/association_pks.rb +23 -64
  63. data/lib/sequel/plugins/auto_validations.rb +3 -2
  64. data/lib/sequel/plugins/dataset_associations.rb +1 -3
  65. data/lib/sequel/plugins/many_through_many.rb +18 -65
  66. data/lib/sequel/plugins/pg_array_associations.rb +97 -86
  67. data/lib/sequel/plugins/prepared_statements.rb +2 -1
  68. data/lib/sequel/plugins/prepared_statements_associations.rb +36 -27
  69. data/lib/sequel/plugins/rcte_tree.rb +12 -16
  70. data/lib/sequel/plugins/sharding.rb +21 -3
  71. data/lib/sequel/plugins/single_table_inheritance.rb +2 -1
  72. data/lib/sequel/plugins/subclasses.rb +1 -9
  73. data/lib/sequel/plugins/tactical_eager_loading.rb +9 -0
  74. data/lib/sequel/plugins/tree.rb +2 -2
  75. data/lib/sequel/plugins/validation_class_methods.rb +1 -1
  76. data/lib/sequel/version.rb +1 -1
  77. data/spec/adapters/mssql_spec.rb +57 -15
  78. data/spec/adapters/mysql_spec.rb +11 -0
  79. data/spec/bin_spec.rb +2 -2
  80. data/spec/core/database_spec.rb +38 -4
  81. data/spec/core/dataset_spec.rb +45 -7
  82. data/spec/core/placeholder_literalizer_spec.rb +17 -0
  83. data/spec/core/schema_spec.rb +6 -1
  84. data/spec/extensions/active_model_spec.rb +18 -9
  85. data/spec/extensions/association_pks_spec.rb +20 -18
  86. data/spec/extensions/association_proxies_spec.rb +9 -9
  87. data/spec/extensions/auto_validations_spec.rb +6 -0
  88. data/spec/extensions/columns_introspection_spec.rb +1 -0
  89. data/spec/extensions/constraint_validations_spec.rb +3 -1
  90. data/spec/extensions/many_through_many_spec.rb +191 -111
  91. data/spec/extensions/pg_array_associations_spec.rb +133 -103
  92. data/spec/extensions/prepared_statements_associations_spec.rb +23 -4
  93. data/spec/extensions/rcte_tree_spec.rb +35 -27
  94. data/spec/extensions/sequel_3_dataset_methods_spec.rb +0 -1
  95. data/spec/extensions/sharding_spec.rb +2 -2
  96. data/spec/extensions/tactical_eager_loading_spec.rb +4 -0
  97. data/spec/extensions/to_dot_spec.rb +1 -0
  98. data/spec/extensions/touch_spec.rb +2 -2
  99. data/spec/integration/associations_test.rb +130 -37
  100. data/spec/integration/dataset_test.rb +17 -0
  101. data/spec/integration/model_test.rb +17 -0
  102. data/spec/integration/schema_test.rb +14 -0
  103. data/spec/integration/transaction_test.rb +25 -1
  104. data/spec/model/association_reflection_spec.rb +63 -24
  105. data/spec/model/associations_spec.rb +104 -57
  106. data/spec/model/base_spec.rb +14 -1
  107. data/spec/model/class_dataset_methods_spec.rb +1 -0
  108. data/spec/model/eager_loading_spec.rb +221 -74
  109. data/spec/model/model_spec.rb +119 -1
  110. metadata +4 -2
@@ -145,6 +145,14 @@ module Sequel
145
145
  super && (server_version <= 50512 || server_version >= 50523)
146
146
  end
147
147
 
148
+ # Support fractional timestamps on MySQL 5.6.5+ if the :fractional_seconds
149
+ # Database option is used. Technically, MySQL 5.6.4+ supports them, but
150
+ # automatic initialization of datetime values wasn't supported to 5.6.5+,
151
+ # and this is related to that.
152
+ def supports_timestamp_usecs?
153
+ @supports_timestamp_usecs ||= server_version >= 50605 && typecast_value_boolean(opts[:fractional_seconds])
154
+ end
155
+
148
156
  # MySQL supports transaction isolation levels
149
157
  def supports_transaction_isolation_levels?
150
158
  true
@@ -185,7 +193,11 @@ module Sequel
185
193
  sql = super
186
194
  op[:table] = related
187
195
  op[:key] ||= primary_key_from_schema(related)
188
- sql << ", ADD FOREIGN KEY (#{quote_identifier(op[:name])})#{column_references_sql(op)}"
196
+ sql << ", ADD "
197
+ if constraint_name = op.delete(:foreign_key_constraint_name)
198
+ sql << "CONSTRAINT #{quote_identifier(constraint_name)} "
199
+ end
200
+ sql << "FOREIGN KEY (#{quote_identifier(op[:name])})#{column_references_sql(op)}"
189
201
  else
190
202
  super
191
203
  end
@@ -292,9 +304,8 @@ module Sequel
292
304
  # Use XA START to start a new prepared transaction if the :prepare
293
305
  # option is given.
294
306
  def begin_transaction(conn, opts=OPTS)
295
- if (s = opts[:prepare]) && (th = _trans(conn))[:savepoint_level] == 0
307
+ if (s = opts[:prepare]) && savepoint_level(conn) == 1
296
308
  log_connection_execute(conn, "XA START #{literal(s)}")
297
- th[:savepoint_level] += 1
298
309
  else
299
310
  super
300
311
  end
@@ -315,7 +326,7 @@ module Sequel
315
326
  # Prepare the XA transaction for a two-phase commit if the
316
327
  # :prepare option is given.
317
328
  def commit_transaction(conn, opts=OPTS)
318
- if (s = opts[:prepare]) && _trans(conn)[:savepoint_level] <= 1
329
+ if (s = opts[:prepare]) && savepoint_level(conn) <= 1
319
330
  log_connection_execute(conn, "XA END #{literal(s)}")
320
331
  log_connection_execute(conn, "XA PREPARE #{literal(s)}")
321
332
  else
@@ -421,7 +432,7 @@ module Sequel
421
432
 
422
433
  # Rollback the currently open XA transaction
423
434
  def rollback_transaction(conn, opts=OPTS)
424
- if (s = opts[:prepare]) && _trans(conn)[:savepoint_level] <= 1
435
+ if (s = opts[:prepare]) && savepoint_level(conn) <= 1
425
436
  log_connection_execute(conn, "XA END #{literal(s)}")
426
437
  log_connection_execute(conn, "XA PREPARE #{literal(s)}")
427
438
  log_connection_execute(conn, "XA ROLLBACK #{literal(s)}")
@@ -462,6 +473,12 @@ module Sequel
462
473
  end
463
474
  end
464
475
 
476
+ # Split DROP INDEX ops on MySQL 5.6+, as dropping them in the same
477
+ # statement as dropping a related foreign key causes an error.
478
+ def split_alter_table_op?(op)
479
+ server_version >= 50600 && (op[:op] == :drop_index || (op[:op] == :drop_constraint && op[:type] == :unique))
480
+ end
481
+
465
482
  # MySQL can combine multiple alter table ops into a single query.
466
483
  def supports_combining_alter_table_ops?
467
484
  true
@@ -496,7 +513,9 @@ module Sequel
496
513
  # MySQL has both datetime and timestamp classes, most people are going
497
514
  # to want datetime
498
515
  def type_literal_generic_datetime(column)
499
- if column[:default] == Sequel::CURRENT_TIMESTAMP
516
+ if supports_timestamp_usecs?
517
+ :'datetime(6)'
518
+ elsif column[:default] == Sequel::CURRENT_TIMESTAMP
500
519
  :timestamp
501
520
  else
502
521
  :datetime
@@ -504,9 +523,17 @@ module Sequel
504
523
  end
505
524
 
506
525
  # MySQL has both datetime and timestamp classes, most people are going
507
- # to want datetime
526
+ # to want datetime.
508
527
  def type_literal_generic_time(column)
509
- column[:only_time] ? :time : type_literal_generic_datetime(column)
528
+ if column[:only_time]
529
+ if supports_timestamp_usecs?
530
+ :'time(6)'
531
+ else
532
+ :time
533
+ end
534
+ else
535
+ type_literal_generic_datetime(column)
536
+ end
510
537
  end
511
538
 
512
539
  # MySQL doesn't have a true boolean class, so it uses tinyint(1)
@@ -522,10 +549,6 @@ module Sequel
522
549
  COMMA_SEPARATOR = ', '.freeze
523
550
  FOR_SHARE = ' LOCK IN SHARE MODE'.freeze
524
551
  SQL_CALC_FOUND_ROWS = ' SQL_CALC_FOUND_ROWS'.freeze
525
- DELETE_CLAUSE_METHODS = Dataset.clause_methods(:delete, %w'delete from where order limit')
526
- INSERT_CLAUSE_METHODS = Dataset.clause_methods(:insert, %w'insert ignore into columns values on_duplicate_key_update')
527
- SELECT_CLAUSE_METHODS = Dataset.clause_methods(:select, %w'select distinct calc_found_rows columns from join where group having compounds order limit lock')
528
- UPDATE_CLAUSE_METHODS = Dataset.clause_methods(:update, %w'update ignore table set where order limit')
529
552
  APOS = Dataset::APOS
530
553
  APOS_RE = Dataset::APOS_RE
531
554
  DOUBLE_APOS = Dataset::DOUBLE_APOS
@@ -566,6 +589,15 @@ module Sequel
566
589
  BLOB_START = "0x".freeze
567
590
  EMPTY_BLOB = "''".freeze
568
591
  HSTAR = "H*".freeze
592
+ CURRENT_TIMESTAMP_56 = 'CURRENT_TIMESTAMP(6)'.freeze
593
+
594
+ # Comes directly from MySQL's documentation, used for queries with limits without offsets
595
+ ONLY_OFFSET = ",18446744073709551615".freeze
596
+
597
+ Dataset.def_sql_method(self, :delete, %w'delete from where order limit')
598
+ Dataset.def_sql_method(self, :insert, %w'insert ignore into columns values on_duplicate_key_update')
599
+ Dataset.def_sql_method(self, :select, %w'select distinct calc_found_rows columns from join where group having compounds order limit lock')
600
+ Dataset.def_sql_method(self, :update, %w'update ignore table set where order limit')
569
601
 
570
602
  include Sequel::Dataset::Replace
571
603
 
@@ -610,6 +642,18 @@ module Sequel
610
642
  end
611
643
  end
612
644
 
645
+ # MySQL's CURRENT_TIMESTAMP does not use fractional seconds,
646
+ # even if the database itself supports fractional seconds. If
647
+ # MySQL 5.6.4+ is being used, use a value that will return
648
+ # fractional seconds.
649
+ def constant_sql_append(sql, constant)
650
+ if constant == :CURRENT_TIMESTAMP && supports_timestamp_usecs?
651
+ sql << CURRENT_TIMESTAMP_56
652
+ else
653
+ super
654
+ end
655
+ end
656
+
613
657
  # Use GROUP BY instead of DISTINCT ON if arguments are provided.
614
658
  def distinct(*args)
615
659
  args.empty? ? super : group(*args)
@@ -706,13 +750,6 @@ module Sequel
706
750
  clone(:on_duplicate_key_update => args)
707
751
  end
708
752
 
709
- # MySQL specific syntax for inserting multiple values at once.
710
- def multi_insert_sql(columns, values)
711
- sql = LiteralString.new('VALUES ')
712
- expression_list_append(sql, values.map{|r| Array(r)})
713
- [insert_sql(columns, sql)]
714
- end
715
-
716
753
  # MySQL uses the nonstandard ` (backtick) for quoting identifiers.
717
754
  def quoted_identifier_append(sql, c)
718
755
  sql << BACKTICK << c.to_s.gsub(BACKTICK_RE, DOUBLE_BACKTICK) << BACKTICK
@@ -734,6 +771,11 @@ module Sequel
734
771
  false
735
772
  end
736
773
 
774
+ # MySQL does not support limits in correlated subqueries (or any subqueries that use IN).
775
+ def supports_limits_in_correlated_subqueries?
776
+ false
777
+ end
778
+
737
779
  # MySQL supports modifying joined datasets
738
780
  def supports_modifying_joins?
739
781
  true
@@ -754,7 +796,7 @@ module Sequel
754
796
  # ignores them. Also, using them seems to cause problems on 1.9. Since
755
797
  # they are ignored anyway, not using them is probably best.
756
798
  def supports_timestamp_usecs?
757
- false
799
+ db.supports_timestamp_usecs?
758
800
  end
759
801
 
760
802
  # Sets up the update methods to use UPDATE IGNORE.
@@ -769,11 +811,6 @@ module Sequel
769
811
 
770
812
  private
771
813
 
772
- # MySQL supports the ORDER BY and LIMIT clauses for DELETE statements
773
- def delete_clause_methods
774
- DELETE_CLAUSE_METHODS
775
- end
776
-
777
814
  # Consider the first table in the joined dataset is the table to delete
778
815
  # from, but include the others for the purposes of selecting rows.
779
816
  def delete_from_sql(sql)
@@ -788,12 +825,6 @@ module Sequel
788
825
  end
789
826
  end
790
827
 
791
- # MySQL supports the IGNORE and ON DUPLICATE KEY UPDATE clauses for INSERT statements
792
- def insert_clause_methods
793
- INSERT_CLAUSE_METHODS
794
- end
795
- alias replace_clause_methods insert_clause_methods
796
-
797
828
  # MySQL doesn't use the SQL standard DEFAULT VALUES.
798
829
  def insert_columns_sql(sql)
799
830
  values = opts[:values]
@@ -905,11 +936,17 @@ module Sequel
905
936
  BOOL_TRUE
906
937
  end
907
938
 
908
- # MySQL does not support the SQL WITH clause for SELECT statements
909
- def select_clause_methods
910
- SELECT_CLAUSE_METHODS
939
+ # MySQL supports multiple rows in INSERT.
940
+ def multi_insert_sql_strategy
941
+ :values
911
942
  end
912
-
943
+
944
+ def select_only_offset_sql(sql)
945
+ sql << LIMIT
946
+ literal_append(sql, @opts[:offset])
947
+ sql << ONLY_OFFSET
948
+ end
949
+
913
950
  # Support FOR SHARE locking when using the :share lock style.
914
951
  def select_lock_sql(sql)
915
952
  @opts[:lock] == :share ? (sql << FOR_SHARE) : super
@@ -920,11 +957,6 @@ module Sequel
920
957
  sql << SQL_CALC_FOUND_ROWS if opts[:calc_found_rows]
921
958
  end
922
959
 
923
- # MySQL supports the ORDER BY and LIMIT clauses for UPDATE statements
924
- def update_clause_methods
925
- UPDATE_CLAUSE_METHODS
926
- end
927
-
928
960
  # MySQL uses WITH ROLLUP syntax.
929
961
  def uses_with_rollup?
930
962
  true
@@ -247,7 +247,6 @@ module Sequel
247
247
  end
248
248
 
249
249
  module DatasetMethods
250
- SELECT_CLAUSE_METHODS = Dataset.clause_methods(:select, %w'with select distinct columns from join where group having compounds order lock')
251
250
  ROW_NUMBER_EXPRESSION = LiteralString.new('ROWNUM').freeze
252
251
  SPACE = Dataset::SPACE
253
252
  APOS = Dataset::APOS
@@ -259,9 +258,13 @@ module Sequel
259
258
  BOOL_FALSE = "'N'".freeze
260
259
  BOOL_TRUE = "'Y'".freeze
261
260
  HSTAR = "H*".freeze
262
- DUAL = ['DUAL'.freeze].freeze
261
+ DUAL = ' FROM DUAL'.freeze
263
262
  BITAND_PROC = lambda{|a, b| Sequel.lit(["CAST(BITAND(", ", ", ") AS INTEGER)"], a, b)}
264
263
 
264
+ include(Module.new do
265
+ Dataset.def_sql_method(self, :select, %w'with select distinct columns from join where group having compounds order lock')
266
+ end)
267
+
265
268
  def complex_expression_sql_append(sql, op, args)
266
269
  case op
267
270
  when :&
@@ -334,7 +337,7 @@ module Sequel
334
337
  def select_sql
335
338
  return super if @opts[:sql]
336
339
  if o = @opts[:offset]
337
- columns = clone(:append_sql=>'').columns
340
+ columns = clone(:append_sql=>'', :placeholder_literal_null=>true).columns
338
341
  dsa1 = dataset_alias(1)
339
342
  rn = row_number_column
340
343
  limit = @opts[:limit]
@@ -366,6 +369,10 @@ module Sequel
366
369
  true
367
370
  end
368
371
 
372
+ def supports_cte?(type=:select)
373
+ type == :select
374
+ end
375
+
369
376
  # Oracle supports GROUP BY CUBE
370
377
  def supports_group_cube?
371
378
  true
@@ -386,6 +393,16 @@ module Sequel
386
393
  false
387
394
  end
388
395
 
396
+ # Oracle does not support limits in correlated subqueries.
397
+ def supports_limits_in_correlated_subqueries?
398
+ false
399
+ end
400
+
401
+ # Oracle does not support offsets in correlated subqueries.
402
+ def supports_offsets_in_correlated_subqueries?
403
+ false
404
+ end
405
+
389
406
  # Oracle does not support SELECT *, column
390
407
  def supports_select_all_and_column?
391
408
  false
@@ -420,6 +437,10 @@ module Sequel
420
437
  TIMESTAMP_FORMAT
421
438
  end
422
439
 
440
+ def empty_from_sql
441
+ DUAL
442
+ end
443
+
423
444
  # If this dataset is associated with a sequence, return the most recently
424
445
  # inserted sequence value.
425
446
  def execute_insert(sql, opts=OPTS)
@@ -457,18 +478,9 @@ module Sequel
457
478
  BOOL_TRUE
458
479
  end
459
480
 
460
- # Use the Oracle-specific SQL clauses (no limit, since it is emulated).
461
- def select_clause_methods
462
- SELECT_CLAUSE_METHODS
463
- end
464
-
465
- # Modify the SQL to add the list of tables to select FROM
466
- # Oracle doesn't support select without FROM clause
467
- # so add the dummy DUAL table if the dataset doesn't select
468
- # from a table.
469
- def select_from_sql(sql)
470
- sql << FROM
471
- source_list_append(sql, @opts[:from] || DUAL)
481
+ # Oracle can insert multiple rows using a UNION
482
+ def multi_insert_sql_strategy
483
+ :union
472
484
  end
473
485
 
474
486
  # Oracle supports quoted function names.
@@ -410,6 +410,8 @@ module Sequel
410
410
  # any named types.
411
411
  def reset_conversion_procs
412
412
  @conversion_procs = get_conversion_procs
413
+ conversion_procs_updated
414
+ @conversion_procs
413
415
  end
414
416
 
415
417
  # Reset the primary key sequence for the given table, basing it on the
@@ -540,6 +542,7 @@ module Sequel
540
542
  convert_named_procs_to_procs(named_procs).each do |oid, pr|
541
543
  procs[oid] ||= pr
542
544
  end
545
+ conversion_procs_updated
543
546
  end
544
547
  end
545
548
 
@@ -596,7 +599,7 @@ module Sequel
596
599
  # If the :prepare option is given and we aren't in a savepoint,
597
600
  # prepare the transaction for a two-phase commit.
598
601
  def commit_transaction(conn, opts=OPTS)
599
- if (s = opts[:prepare]) && _trans(conn)[:savepoint_level] <= 1
602
+ if (s = opts[:prepare]) && savepoint_level(conn) <= 1
600
603
  log_connection_execute(conn, "PREPARE TRANSACTION #{literal(s)}")
601
604
  else
602
605
  super
@@ -658,6 +661,11 @@ module Sequel
658
661
  end
659
662
  end
660
663
 
664
+ # Callback used when conversion procs are updated.
665
+ def conversion_procs_updated
666
+ nil
667
+ end
668
+
661
669
  # Convert the hash of named conversion procs into a hash a oid conversion procs.
662
670
  def convert_named_procs_to_procs(named_procs)
663
671
  h = {}
@@ -674,6 +682,7 @@ module Sequel
674
682
  oids.each do |oid|
675
683
  procs[oid] = PG_TYPES[oid]
676
684
  end
685
+ conversion_procs_updated
677
686
  end
678
687
 
679
688
  EXCLUSION_CONSTRAINT_SQL_STATE = '23P01'.freeze
@@ -1094,27 +1103,19 @@ module Sequel
1094
1103
  BOOL_FALSE = 'false'.freeze
1095
1104
  BOOL_TRUE = 'true'.freeze
1096
1105
  COMMA_SEPARATOR = ', '.freeze
1097
- DELETE_CLAUSE_METHODS = Dataset.clause_methods(:delete, %w'delete from using where returning')
1098
- DELETE_CLAUSE_METHODS_91 = Dataset.clause_methods(:delete, %w'with delete from using where returning')
1099
1106
  EXCLUSIVE = 'EXCLUSIVE'.freeze
1100
1107
  EXPLAIN = 'EXPLAIN '.freeze
1101
1108
  EXPLAIN_ANALYZE = 'EXPLAIN ANALYZE '.freeze
1102
1109
  FOR_SHARE = ' FOR SHARE'.freeze
1103
- INSERT_CLAUSE_METHODS = Dataset.clause_methods(:insert, %w'insert into columns values returning')
1104
- INSERT_CLAUSE_METHODS_91 = Dataset.clause_methods(:insert, %w'with insert into columns values returning')
1105
1110
  NULL = LiteralString.new('NULL').freeze
1106
1111
  PG_TIMESTAMP_FORMAT = "TIMESTAMP '%Y-%m-%d %H:%M:%S".freeze
1107
1112
  QUERY_PLAN = 'QUERY PLAN'.to_sym
1108
1113
  ROW_EXCLUSIVE = 'ROW EXCLUSIVE'.freeze
1109
1114
  ROW_SHARE = 'ROW SHARE'.freeze
1110
- SELECT_CLAUSE_METHODS = Dataset.clause_methods(:select, %w'select distinct columns from join where group having compounds order limit lock')
1111
- SELECT_CLAUSE_METHODS_84 = Dataset.clause_methods(:select, %w'with select distinct columns from join where group having window compounds order limit lock')
1112
1115
  SHARE = 'SHARE'.freeze
1113
1116
  SHARE_ROW_EXCLUSIVE = 'SHARE ROW EXCLUSIVE'.freeze
1114
1117
  SHARE_UPDATE_EXCLUSIVE = 'SHARE UPDATE EXCLUSIVE'.freeze
1115
1118
  SQL_WITH_RECURSIVE = "WITH RECURSIVE ".freeze
1116
- UPDATE_CLAUSE_METHODS = Dataset.clause_methods(:update, %w'update table set from where returning')
1117
- UPDATE_CLAUSE_METHODS_91 = Dataset.clause_methods(:update, %w'with update table set from where returning')
1118
1119
  SPACE = Dataset::SPACE
1119
1120
  FROM = Dataset::FROM
1120
1121
  APOS = Dataset::APOS
@@ -1133,6 +1134,11 @@ module Sequel
1133
1134
  EMPTY_STRING = ''.freeze
1134
1135
  LOCK_MODES = ['ACCESS SHARE', 'ROW SHARE', 'ROW EXCLUSIVE', 'SHARE UPDATE EXCLUSIVE', 'SHARE', 'SHARE ROW EXCLUSIVE', 'EXCLUSIVE', 'ACCESS EXCLUSIVE'].each{|s| s.freeze}
1135
1136
 
1137
+ Dataset.def_sql_method(self, :delete, [['if server_version >= 90100', %w'with delete from using where returning'], ['else', %w'delete from using where returning']])
1138
+ Dataset.def_sql_method(self, :insert, [['if server_version >= 90100', %w'with insert into columns values returning'], ['else', %w'insert into columns values returning']])
1139
+ Dataset.def_sql_method(self, :select, [['if server_version >= 80400', %w'with select distinct columns from join where group having window compounds order limit lock'], ['else', %w'select distinct columns from join where group having compounds order limit lock']])
1140
+ Dataset.def_sql_method(self, :update, [['if server_version >= 90100', %w'with update table set from where returning'], ['else', %w'update table set from where returning']])
1141
+
1136
1142
  # Shared methods for prepared statements when used with PostgreSQL databases.
1137
1143
  module PreparedStatementMethods
1138
1144
  # Override insert action to use RETURNING if the server supports it.
@@ -1279,11 +1285,12 @@ module Sequel
1279
1285
  nil
1280
1286
  end
1281
1287
 
1282
- # PostgreSQL allows inserting multiple rows at once.
1283
- def multi_insert_sql(columns, values)
1284
- sql = LiteralString.new('VALUES ')
1285
- expression_list_append(sql, values.map{|r| Array(r)})
1286
- [insert_sql(columns, sql)]
1288
+ def supports_cte?(type=:select)
1289
+ if type == :select
1290
+ server_version >= 80400
1291
+ else
1292
+ server_version >= 90100
1293
+ end
1287
1294
  end
1288
1295
 
1289
1296
  # PostgreSQL supports using the WITH clause in subqueries if it
@@ -1393,15 +1400,6 @@ module Sequel
1393
1400
  raise(InvalidOperation, "Joined datasets cannot be truncated") if opts[:join]
1394
1401
  end
1395
1402
 
1396
- # PostgreSQL allows deleting from joined datasets
1397
- def delete_clause_methods
1398
- if server_version >= 90100
1399
- DELETE_CLAUSE_METHODS_91
1400
- else
1401
- DELETE_CLAUSE_METHODS
1402
- end
1403
- end
1404
-
1405
1403
  # Only include the primary table in the main delete clause
1406
1404
  def delete_from_sql(sql)
1407
1405
  sql << FROM
@@ -1413,15 +1411,6 @@ module Sequel
1413
1411
  join_from_sql(:USING, sql)
1414
1412
  end
1415
1413
 
1416
- # PostgreSQL allows a RETURNING clause.
1417
- def insert_clause_methods
1418
- if server_version >= 90100
1419
- INSERT_CLAUSE_METHODS_91
1420
- else
1421
- INSERT_CLAUSE_METHODS
1422
- end
1423
- end
1424
-
1425
1414
  # Return the primary key to use for RETURNING in an INSERT statement
1426
1415
  def insert_pk
1427
1416
  if (f = opts[:from]) && !f.empty?
@@ -1479,9 +1468,9 @@ module Sequel
1479
1468
  BOOL_TRUE
1480
1469
  end
1481
1470
 
1482
- # The order of clauses in the SELECT SQL statement
1483
- def select_clause_methods
1484
- server_version >= 80400 ? SELECT_CLAUSE_METHODS_84 : SELECT_CLAUSE_METHODS
1471
+ # PostgreSQL supports multiple rows in INSERT.
1472
+ def multi_insert_sql_strategy
1473
+ :values
1485
1474
  end
1486
1475
 
1487
1476
  # PostgreSQL requires parentheses around compound datasets if they use
@@ -1537,15 +1526,6 @@ module Sequel
1537
1526
  SQL::StringExpression.new(:'||', *cols)
1538
1527
  end
1539
1528
 
1540
- # PostgreSQL splits the main table from the joined tables
1541
- def update_clause_methods
1542
- if server_version >= 90100
1543
- UPDATE_CLAUSE_METHODS_91
1544
- else
1545
- UPDATE_CLAUSE_METHODS
1546
- end
1547
- end
1548
-
1549
1529
  # Use FROM to specify additional tables in an update query
1550
1530
  def update_from_sql(sql)
1551
1531
  join_from_sql(:FROM, sql)