sequel 4.9.0 → 4.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +79 -1
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/Rakefile +2 -12
- data/bin/sequel +1 -0
- data/doc/advanced_associations.rdoc +82 -25
- data/doc/association_basics.rdoc +21 -22
- data/doc/core_extensions.rdoc +1 -1
- data/doc/opening_databases.rdoc +7 -0
- data/doc/release_notes/4.10.0.txt +226 -0
- data/doc/security.rdoc +1 -0
- data/doc/testing.rdoc +7 -7
- data/doc/transactions.rdoc +8 -0
- data/lib/sequel/adapters/jdbc.rb +160 -168
- data/lib/sequel/adapters/jdbc/db2.rb +17 -18
- data/lib/sequel/adapters/jdbc/derby.rb +5 -28
- data/lib/sequel/adapters/jdbc/h2.rb +11 -22
- data/lib/sequel/adapters/jdbc/hsqldb.rb +31 -18
- data/lib/sequel/adapters/jdbc/jtds.rb +0 -15
- data/lib/sequel/adapters/jdbc/oracle.rb +36 -35
- data/lib/sequel/adapters/jdbc/postgresql.rb +72 -90
- data/lib/sequel/adapters/jdbc/sqlanywhere.rb +18 -16
- data/lib/sequel/adapters/jdbc/sqlite.rb +7 -0
- data/lib/sequel/adapters/jdbc/sqlserver.rb +10 -30
- data/lib/sequel/adapters/jdbc/transactions.rb +5 -6
- data/lib/sequel/adapters/openbase.rb +1 -7
- data/lib/sequel/adapters/postgres.rb +1 -1
- data/lib/sequel/adapters/shared/access.rb +3 -6
- data/lib/sequel/adapters/shared/cubrid.rb +24 -9
- data/lib/sequel/adapters/shared/db2.rb +13 -5
- data/lib/sequel/adapters/shared/firebird.rb +16 -16
- data/lib/sequel/adapters/shared/informix.rb +2 -5
- data/lib/sequel/adapters/shared/mssql.rb +72 -63
- data/lib/sequel/adapters/shared/mysql.rb +72 -40
- data/lib/sequel/adapters/shared/oracle.rb +27 -15
- data/lib/sequel/adapters/shared/postgres.rb +24 -44
- data/lib/sequel/adapters/shared/progress.rb +1 -5
- data/lib/sequel/adapters/shared/sqlanywhere.rb +26 -18
- data/lib/sequel/adapters/shared/sqlite.rb +21 -6
- data/lib/sequel/adapters/utils/emulate_offset_with_reverse_and_count.rb +8 -1
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +8 -2
- data/lib/sequel/adapters/utils/split_alter_table.rb +8 -0
- data/lib/sequel/core.rb +14 -9
- data/lib/sequel/database/dataset_defaults.rb +1 -0
- data/lib/sequel/database/misc.rb +12 -0
- data/lib/sequel/database/query.rb +4 -1
- data/lib/sequel/database/schema_methods.rb +3 -2
- data/lib/sequel/database/transactions.rb +47 -17
- data/lib/sequel/dataset/features.rb +12 -2
- data/lib/sequel/dataset/mutation.rb +2 -0
- data/lib/sequel/dataset/placeholder_literalizer.rb +12 -4
- data/lib/sequel/dataset/prepared_statements.rb +6 -0
- data/lib/sequel/dataset/query.rb +1 -1
- data/lib/sequel/dataset/sql.rb +132 -70
- data/lib/sequel/extensions/columns_introspection.rb +1 -1
- data/lib/sequel/extensions/null_dataset.rb +8 -4
- data/lib/sequel/extensions/pg_array.rb +4 -4
- data/lib/sequel/extensions/pg_row.rb +1 -0
- data/lib/sequel/model/associations.rb +468 -188
- data/lib/sequel/model/base.rb +88 -13
- data/lib/sequel/plugins/association_pks.rb +23 -64
- data/lib/sequel/plugins/auto_validations.rb +3 -2
- data/lib/sequel/plugins/dataset_associations.rb +1 -3
- data/lib/sequel/plugins/many_through_many.rb +18 -65
- data/lib/sequel/plugins/pg_array_associations.rb +97 -86
- data/lib/sequel/plugins/prepared_statements.rb +2 -1
- data/lib/sequel/plugins/prepared_statements_associations.rb +36 -27
- data/lib/sequel/plugins/rcte_tree.rb +12 -16
- data/lib/sequel/plugins/sharding.rb +21 -3
- data/lib/sequel/plugins/single_table_inheritance.rb +2 -1
- data/lib/sequel/plugins/subclasses.rb +1 -9
- data/lib/sequel/plugins/tactical_eager_loading.rb +9 -0
- data/lib/sequel/plugins/tree.rb +2 -2
- data/lib/sequel/plugins/validation_class_methods.rb +1 -1
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mssql_spec.rb +57 -15
- data/spec/adapters/mysql_spec.rb +11 -0
- data/spec/bin_spec.rb +2 -2
- data/spec/core/database_spec.rb +38 -4
- data/spec/core/dataset_spec.rb +45 -7
- data/spec/core/placeholder_literalizer_spec.rb +17 -0
- data/spec/core/schema_spec.rb +6 -1
- data/spec/extensions/active_model_spec.rb +18 -9
- data/spec/extensions/association_pks_spec.rb +20 -18
- data/spec/extensions/association_proxies_spec.rb +9 -9
- data/spec/extensions/auto_validations_spec.rb +6 -0
- data/spec/extensions/columns_introspection_spec.rb +1 -0
- data/spec/extensions/constraint_validations_spec.rb +3 -1
- data/spec/extensions/many_through_many_spec.rb +191 -111
- data/spec/extensions/pg_array_associations_spec.rb +133 -103
- data/spec/extensions/prepared_statements_associations_spec.rb +23 -4
- data/spec/extensions/rcte_tree_spec.rb +35 -27
- data/spec/extensions/sequel_3_dataset_methods_spec.rb +0 -1
- data/spec/extensions/sharding_spec.rb +2 -2
- data/spec/extensions/tactical_eager_loading_spec.rb +4 -0
- data/spec/extensions/to_dot_spec.rb +1 -0
- data/spec/extensions/touch_spec.rb +2 -2
- data/spec/integration/associations_test.rb +130 -37
- data/spec/integration/dataset_test.rb +17 -0
- data/spec/integration/model_test.rb +17 -0
- data/spec/integration/schema_test.rb +14 -0
- data/spec/integration/transaction_test.rb +25 -1
- data/spec/model/association_reflection_spec.rb +63 -24
- data/spec/model/associations_spec.rb +104 -57
- data/spec/model/base_spec.rb +14 -1
- data/spec/model/class_dataset_methods_spec.rb +1 -0
- data/spec/model/eager_loading_spec.rb +221 -74
- data/spec/model/model_spec.rb +119 -1
- 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
|
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]) && (
|
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]) &&
|
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]) &&
|
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
|
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]
|
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
|
-
|
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
|
909
|
-
def
|
910
|
-
|
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 =
|
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
|
-
#
|
461
|
-
def
|
462
|
-
|
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]) &&
|
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
|
-
|
1283
|
-
|
1284
|
-
|
1285
|
-
|
1286
|
-
|
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
|
-
#
|
1483
|
-
def
|
1484
|
-
|
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)
|