sequel 2.10.0 → 2.11.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.
- data/CHANGELOG +51 -1
- data/README.rdoc +2 -2
- data/Rakefile +2 -2
- data/doc/advanced_associations.rdoc +6 -18
- data/doc/release_notes/1.0.txt +38 -0
- data/doc/release_notes/1.1.txt +143 -0
- data/doc/release_notes/1.3.txt +101 -0
- data/doc/release_notes/1.4.0.txt +53 -0
- data/doc/release_notes/1.5.0.txt +155 -0
- data/doc/release_notes/2.0.0.txt +298 -0
- data/doc/release_notes/2.1.0.txt +271 -0
- data/doc/release_notes/2.10.0.txt +328 -0
- data/doc/release_notes/2.11.0.txt +215 -0
- data/doc/release_notes/2.2.0.txt +253 -0
- data/doc/release_notes/2.3.0.txt +88 -0
- data/doc/release_notes/2.4.0.txt +106 -0
- data/doc/release_notes/2.5.0.txt +137 -0
- data/doc/release_notes/2.6.0.txt +157 -0
- data/doc/release_notes/2.7.0.txt +166 -0
- data/doc/release_notes/2.8.0.txt +171 -0
- data/doc/release_notes/2.9.0.txt +97 -0
- data/lib/sequel_core/adapters/ado.rb +3 -0
- data/lib/sequel_core/adapters/db2.rb +0 -11
- data/lib/sequel_core/adapters/dbi.rb +0 -11
- data/lib/sequel_core/adapters/do.rb +0 -12
- data/lib/sequel_core/adapters/firebird.rb +21 -16
- data/lib/sequel_core/adapters/informix.rb +1 -11
- data/lib/sequel_core/adapters/jdbc.rb +1 -13
- data/lib/sequel_core/adapters/jdbc/h2.rb +3 -11
- data/lib/sequel_core/adapters/jdbc/mysql.rb +0 -17
- data/lib/sequel_core/adapters/jdbc/postgresql.rb +3 -15
- data/lib/sequel_core/adapters/mysql.rb +31 -27
- data/lib/sequel_core/adapters/odbc.rb +34 -28
- data/lib/sequel_core/adapters/openbase.rb +0 -11
- data/lib/sequel_core/adapters/oracle.rb +11 -9
- data/lib/sequel_core/adapters/postgres.rb +14 -17
- data/lib/sequel_core/adapters/shared/mssql.rb +6 -15
- data/lib/sequel_core/adapters/shared/mysql.rb +29 -14
- data/lib/sequel_core/adapters/shared/oracle.rb +4 -0
- data/lib/sequel_core/adapters/shared/postgres.rb +30 -35
- data/lib/sequel_core/adapters/shared/progress.rb +4 -0
- data/lib/sequel_core/adapters/shared/sqlite.rb +73 -13
- data/lib/sequel_core/adapters/sqlite.rb +8 -18
- data/lib/sequel_core/adapters/utils/date_format.rb +21 -0
- data/lib/sequel_core/{dataset → adapters/utils}/stored_procedures.rb +0 -0
- data/lib/sequel_core/{dataset → adapters/utils}/unsupported.rb +0 -0
- data/lib/sequel_core/core_ext.rb +1 -1
- data/lib/sequel_core/core_sql.rb +9 -4
- data/lib/sequel_core/database.rb +63 -62
- data/lib/sequel_core/dataset.rb +9 -4
- data/lib/sequel_core/dataset/convenience.rb +10 -9
- data/lib/sequel_core/dataset/prepared_statements.rb +1 -1
- data/lib/sequel_core/dataset/sql.rb +130 -36
- data/lib/sequel_core/schema/sql.rb +2 -2
- data/lib/sequel_core/sql.rb +44 -51
- data/lib/sequel_core/version.rb +1 -1
- data/lib/sequel_model/associations.rb +25 -17
- data/lib/sequel_model/base.rb +35 -7
- data/lib/sequel_model/caching.rb +1 -6
- data/lib/sequel_model/record.rb +23 -5
- data/lib/sequel_model/validations.rb +20 -5
- data/spec/adapters/firebird_spec.rb +6 -1
- data/spec/adapters/mysql_spec.rb +12 -0
- data/spec/adapters/postgres_spec.rb +2 -2
- data/spec/adapters/sqlite_spec.rb +81 -2
- data/spec/integration/dataset_test.rb +2 -2
- data/spec/integration/type_test.rb +12 -2
- data/spec/sequel_core/core_sql_spec.rb +46 -12
- data/spec/sequel_core/database_spec.rb +24 -12
- data/spec/sequel_core/dataset_spec.rb +82 -32
- data/spec/sequel_core/schema_spec.rb +16 -0
- data/spec/sequel_model/associations_spec.rb +89 -0
- data/spec/sequel_model/base_spec.rb +66 -0
- data/spec/sequel_model/eager_loading_spec.rb +32 -0
- data/spec/sequel_model/record_spec.rb +9 -9
- data/spec/sequel_model/spec_helper.rb +3 -0
- data/spec/sequel_model/validations_spec.rb +63 -3
- metadata +41 -4
@@ -37,17 +37,6 @@ module Sequel
|
|
37
37
|
end
|
38
38
|
|
39
39
|
class Dataset < Sequel::Dataset
|
40
|
-
def literal(v)
|
41
|
-
case v
|
42
|
-
when Time
|
43
|
-
literal(v.iso8601)
|
44
|
-
when Date, DateTime
|
45
|
-
literal(v.to_s)
|
46
|
-
else
|
47
|
-
super
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
40
|
def fetch_rows(sql)
|
52
41
|
execute(sql) do |result|
|
53
42
|
begin
|
@@ -78,15 +78,6 @@ module Sequel
|
|
78
78
|
class Dataset < Sequel::Dataset
|
79
79
|
include DatasetMethods
|
80
80
|
|
81
|
-
def literal(v)
|
82
|
-
case v
|
83
|
-
when OraDate
|
84
|
-
literal(Time.local(*v.to_a))
|
85
|
-
else
|
86
|
-
super
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
81
|
def fetch_rows(sql, &block)
|
91
82
|
execute(sql) do |cursor|
|
92
83
|
begin
|
@@ -102,6 +93,17 @@ module Sequel
|
|
102
93
|
end
|
103
94
|
self
|
104
95
|
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
def literal_other(v)
|
100
|
+
case v
|
101
|
+
when OraDate
|
102
|
+
literal_time(Time.local(*v.to_a))
|
103
|
+
else
|
104
|
+
super
|
105
|
+
end
|
106
|
+
end
|
105
107
|
end
|
106
108
|
end
|
107
109
|
end
|
@@ -85,7 +85,7 @@ module Sequel
|
|
85
85
|
# Hash with integer keys and proc values for converting PostgreSQL types.
|
86
86
|
PG_TYPES = {
|
87
87
|
16 => lambda{ |s| s == 't' }, # boolean
|
88
|
-
17 => lambda{ |s| Adapter.unescape_bytea(s)
|
88
|
+
17 => lambda{ |s| ::Sequel::SQL::Blob.new(Adapter.unescape_bytea(s)) }, # bytea
|
89
89
|
20 => lambda{ |s| s.to_i }, # int8
|
90
90
|
21 => lambda{ |s| s.to_i }, # int2
|
91
91
|
22 => lambda{ |s| s.to_i }, # int2vector
|
@@ -326,23 +326,9 @@ module Sequel
|
|
326
326
|
end
|
327
327
|
end
|
328
328
|
|
329
|
-
# Literalize strings and blobs using code from the native adapter.
|
330
|
-
def literal(v)
|
331
|
-
case v
|
332
|
-
when LiteralString
|
333
|
-
v
|
334
|
-
when SQL::Blob
|
335
|
-
db.synchronize{|c| "'#{c.escape_bytea(v)}'"}
|
336
|
-
when String
|
337
|
-
db.synchronize{|c| "'#{c.escape_string(v)}'"}
|
338
|
-
else
|
339
|
-
super
|
340
|
-
end
|
341
|
-
end
|
342
|
-
|
343
329
|
if SEQUEL_POSTGRES_USES_PG
|
344
330
|
|
345
|
-
PREPARED_ARG_PLACEHOLDER = '$'.
|
331
|
+
PREPARED_ARG_PLACEHOLDER = LiteralString.new('$').freeze
|
346
332
|
|
347
333
|
# PostgreSQL specific argument mapper used for mapping the named
|
348
334
|
# argument hash to a array with numbered arguments. Only used with
|
@@ -373,7 +359,7 @@ module Sequel
|
|
373
359
|
@prepared_args << y
|
374
360
|
i = @prepared_args.length
|
375
361
|
end
|
376
|
-
"#{prepared_arg_placeholder}#{i}#{"::#{type}" if type}"
|
362
|
+
LiteralString.new("#{prepared_arg_placeholder}#{i}#{"::#{type}" if type}")
|
377
363
|
end
|
378
364
|
end
|
379
365
|
|
@@ -451,6 +437,17 @@ module Sequel
|
|
451
437
|
PREPARED_ARG_PLACEHOLDER
|
452
438
|
end
|
453
439
|
end
|
440
|
+
|
441
|
+
private
|
442
|
+
|
443
|
+
def literal_blob(v)
|
444
|
+
db.synchronize{|c| "'#{c.escape_bytea(v)}'"}
|
445
|
+
end
|
446
|
+
|
447
|
+
def literal_string(v)
|
448
|
+
db.synchronize{|c| "'#{c.escape_string(v)}'"}
|
449
|
+
end
|
450
|
+
|
454
451
|
end
|
455
452
|
end
|
456
453
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'sequel_core/adapters/utils/unsupported'
|
2
|
+
|
1
3
|
module Sequel
|
2
4
|
module MSSQL
|
3
5
|
module DatabaseMethods
|
@@ -52,21 +54,6 @@ module Sequel
|
|
52
54
|
filter("CONTAINS (#{literal(cols)}, #{literal(terms)})")
|
53
55
|
end
|
54
56
|
|
55
|
-
def literal(v)
|
56
|
-
case v
|
57
|
-
when LiteralString
|
58
|
-
v
|
59
|
-
when String
|
60
|
-
"N#{super}"
|
61
|
-
when Time
|
62
|
-
literal(v.iso8601)
|
63
|
-
when Date, DateTime
|
64
|
-
literal(v.to_s)
|
65
|
-
else
|
66
|
-
super
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
57
|
def multi_insert_sql(columns, values)
|
71
58
|
values = values.map {|r| "SELECT #{expression_list(r)}" }.join(" UNION ALL ")
|
72
59
|
["INSERT INTO #{source_list(@opts[:from])} (#{identifier_list(columns)}) #{values}"]
|
@@ -83,6 +70,10 @@ module Sequel
|
|
83
70
|
|
84
71
|
private
|
85
72
|
|
73
|
+
def literal_string(v)
|
74
|
+
"N#{super}"
|
75
|
+
end
|
76
|
+
|
86
77
|
def select_clause_order
|
87
78
|
SELECT_CLAUSE_ORDER
|
88
79
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'sequel_core/adapters/utils/unsupported'
|
2
|
+
|
1
3
|
module Sequel
|
2
4
|
module Schema
|
3
5
|
module SQL
|
@@ -146,8 +148,15 @@ module Sequel
|
|
146
148
|
|
147
149
|
BOOL_TRUE = '1'.freeze
|
148
150
|
BOOL_FALSE = '0'.freeze
|
151
|
+
CAST_TYPES = {String=>:CHAR, Integer=>:SIGNED, Time=>:DATETIME, DateTime=>:DATETIME, Numeric=>:DECIMAL, BigDecimal=>:DECIMAL, File=>:BINARY}
|
152
|
+
TIMESTAMP_FORMAT = "'%Y-%m-%d %H:%M:%S'".freeze
|
149
153
|
COMMA_SEPARATOR = ', '.freeze
|
150
154
|
|
155
|
+
# MySQL can't use the varchar type in a cast.
|
156
|
+
def cast_sql(expr, type)
|
157
|
+
"CAST(#{literal(expr)} AS #{CAST_TYPES[type] || db.send(:type_literal_base, :type=>type)})"
|
158
|
+
end
|
159
|
+
|
151
160
|
# MySQL specific syntax for LIKE/REGEXP searches, as well as
|
152
161
|
# string concatenation.
|
153
162
|
def complex_expression_sql(op, args)
|
@@ -224,20 +233,6 @@ module Sequel
|
|
224
233
|
end
|
225
234
|
end
|
226
235
|
|
227
|
-
# Override the default boolean values.
|
228
|
-
def literal(v)
|
229
|
-
case v
|
230
|
-
when true
|
231
|
-
BOOL_TRUE
|
232
|
-
when false
|
233
|
-
BOOL_FALSE
|
234
|
-
when DateTime, Time
|
235
|
-
v.strftime("'%Y-%m-%d %H:%M:%S'")
|
236
|
-
else
|
237
|
-
super
|
238
|
-
end
|
239
|
-
end
|
240
|
-
|
241
236
|
# MySQL specific syntax for inserting multiple values at once.
|
242
237
|
def multi_insert_sql(columns, values)
|
243
238
|
values = values.map {|r| literal(Array(r))}.join(COMMA_SEPARATOR)
|
@@ -307,6 +302,26 @@ module Sequel
|
|
307
302
|
|
308
303
|
private
|
309
304
|
|
305
|
+
# Use MySQL Timestamp format
|
306
|
+
def literal_datetime(v)
|
307
|
+
v.strftime(TIMESTAMP_FORMAT)
|
308
|
+
end
|
309
|
+
|
310
|
+
# Use 0 for false on MySQL
|
311
|
+
def literal_false
|
312
|
+
BOOL_FALSE
|
313
|
+
end
|
314
|
+
|
315
|
+
# Use MySQL Timestamp format
|
316
|
+
def literal_time(v)
|
317
|
+
v.strftime(TIMESTAMP_FORMAT)
|
318
|
+
end
|
319
|
+
|
320
|
+
# Use 1 for true on MySQL
|
321
|
+
def literal_true
|
322
|
+
BOOL_TRUE
|
323
|
+
end
|
324
|
+
|
310
325
|
# MySQL doesn't support DISTINCT ON
|
311
326
|
def select_distinct_sql(sql, opts)
|
312
327
|
if opts[:distinct]
|
@@ -1,3 +1,6 @@
|
|
1
|
+
require 'sequel_core/adapters/utils/date_format'
|
2
|
+
require 'sequel_core/adapters/utils/unsupported'
|
3
|
+
|
1
4
|
module Sequel
|
2
5
|
module Oracle
|
3
6
|
module DatabaseMethods
|
@@ -13,6 +16,7 @@ module Sequel
|
|
13
16
|
|
14
17
|
module DatasetMethods
|
15
18
|
include Dataset::UnsupportedIntersectExceptAll
|
19
|
+
include Dataset::SQLStandardDateFormat
|
16
20
|
|
17
21
|
SELECT_CLAUSE_ORDER = %w'distinct columns from join where group having compounds order limit'.freeze
|
18
22
|
|
@@ -161,7 +161,7 @@ module Sequel
|
|
161
161
|
|
162
162
|
# Methods shared by Database instances that connect to PostgreSQL.
|
163
163
|
module DatabaseMethods
|
164
|
-
PREPARED_ARG_PLACEHOLDER = '$'.
|
164
|
+
PREPARED_ARG_PLACEHOLDER = LiteralString.new('$').freeze
|
165
165
|
RE_CURRVAL_ERROR = /currval of sequence "(.*)" is not yet defined in this session|relation "(.*)" does not exist/.freeze
|
166
166
|
SQL_BEGIN = 'BEGIN'.freeze
|
167
167
|
SQL_SAVEPOINT = 'SAVEPOINT autopoint_%d'.freeze
|
@@ -333,9 +333,7 @@ module Sequel
|
|
333
333
|
|
334
334
|
# Dataset containing all current database locks
|
335
335
|
def locks
|
336
|
-
dataset.from(:pg_class, :pg_locks)
|
337
|
-
select(:pg_class__relname, :pg_locks.*).
|
338
|
-
filter(:pg_class__relfilenode=>:pg_locks__relation)
|
336
|
+
dataset.from(:pg_class).join(:pg_locks, :relation=>:relfilenode).select(:pg_class__relname, Sequel::SQL::ColumnAll.new(:pg_locks))
|
339
337
|
end
|
340
338
|
|
341
339
|
# Return primary key for the given table.
|
@@ -552,6 +550,7 @@ module Sequel
|
|
552
550
|
FOR_SHARE = ' FOR SHARE'.freeze
|
553
551
|
FOR_UPDATE = ' FOR UPDATE'.freeze
|
554
552
|
LOCK = 'LOCK TABLE %s IN %s MODE'.freeze
|
553
|
+
NULL = LiteralString.new('NULL').freeze
|
555
554
|
PG_TIMESTAMP_FORMAT = "TIMESTAMP '%Y-%m-%d %H:%M:%S".freeze
|
556
555
|
QUERY_PLAN = 'QUERY PLAN'.to_sym
|
557
556
|
ROW_EXCLUSIVE = 'ROW EXCLUSIVE'.freeze
|
@@ -614,7 +613,7 @@ module Sequel
|
|
614
613
|
# Insert given values into the database.
|
615
614
|
def insert(*values)
|
616
615
|
if !@opts[:sql] and server_version >= 80200
|
617
|
-
single_value(:sql=>insert_returning_pk_sql(*values))
|
616
|
+
single_value(default_server_opts(:sql=>insert_returning_pk_sql(*values)))
|
618
617
|
else
|
619
618
|
execute_insert(insert_sql(*values), :table=>opts[:from].first,
|
620
619
|
:values=>values.size == 1 ? values.first : values)
|
@@ -628,32 +627,9 @@ module Sequel
|
|
628
627
|
|
629
628
|
# Insert a record returning the record inserted
|
630
629
|
def insert_select(*values)
|
631
|
-
single_record(:naked=>true, :sql=>insert_returning_sql(nil, *values)) if server_version >= 80200
|
630
|
+
single_record(default_server_opts(:naked=>true, :sql=>insert_returning_sql(nil, *values))) if server_version >= 80200
|
632
631
|
end
|
633
632
|
|
634
|
-
# Handle microseconds for Time and DateTime values, as well as PostgreSQL
|
635
|
-
# specific boolean values and string escaping.
|
636
|
-
def literal(v)
|
637
|
-
case v
|
638
|
-
when LiteralString
|
639
|
-
v
|
640
|
-
when SQL::Blob
|
641
|
-
"'#{v.gsub(/[\000-\037\047\134\177-\377]/){|b| "\\#{("%o" % b[0..1].unpack("C")[0]).rjust(3, '0')}"}}'"
|
642
|
-
when String
|
643
|
-
"'#{v.gsub("'", "''")}'"
|
644
|
-
when Time
|
645
|
-
"#{v.strftime(PG_TIMESTAMP_FORMAT)}.#{sprintf("%06d",v.usec)}'"
|
646
|
-
when DateTime
|
647
|
-
"#{v.strftime(PG_TIMESTAMP_FORMAT)}.#{sprintf("%06d", (v.sec_fraction * 86400000000).to_i)}'"
|
648
|
-
when TrueClass
|
649
|
-
BOOL_TRUE
|
650
|
-
when FalseClass
|
651
|
-
BOOL_FALSE
|
652
|
-
else
|
653
|
-
super
|
654
|
-
end
|
655
|
-
end
|
656
|
-
|
657
633
|
# Locks the table with the specified mode.
|
658
634
|
def lock(mode, server=nil)
|
659
635
|
sql = LOCK % [source_list(@opts[:from]), mode]
|
@@ -678,17 +654,36 @@ module Sequel
|
|
678
654
|
|
679
655
|
private
|
680
656
|
|
681
|
-
# Call execute_insert on the database object with the given values.
|
682
|
-
def execute_insert(sql, opts={})
|
683
|
-
@db.execute_insert(sql, {:server=>@opts[:server] || :default}.merge(opts))
|
684
|
-
end
|
685
|
-
|
686
657
|
# Use the RETURNING clause to return the primary key of the inserted record, if it exists
|
687
658
|
def insert_returning_pk_sql(*values)
|
688
659
|
pk = db.primary_key(opts[:from].first)
|
689
|
-
insert_returning_sql(pk ? Sequel::SQL::Identifier.new(pk) :
|
660
|
+
insert_returning_sql(pk ? Sequel::SQL::Identifier.new(pk) : NULL, *values)
|
690
661
|
end
|
691
662
|
|
663
|
+
def literal_blob(v)
|
664
|
+
"'#{v.gsub(/[\000-\037\047\134\177-\377]/){|b| "\\#{("%o" % b[0..1].unpack("C")[0]).rjust(3, '0')}"}}'"
|
665
|
+
end
|
666
|
+
|
667
|
+
def literal_datetime(v)
|
668
|
+
"#{v.strftime(PG_TIMESTAMP_FORMAT)}.#{sprintf("%06d", (v.sec_fraction * 86400000000).to_i)}'"
|
669
|
+
end
|
670
|
+
|
671
|
+
def literal_false
|
672
|
+
BOOL_FALSE
|
673
|
+
end
|
674
|
+
|
675
|
+
def literal_string(v)
|
676
|
+
"'#{v.gsub("'", "''")}'"
|
677
|
+
end
|
678
|
+
|
679
|
+
def literal_true
|
680
|
+
BOOL_TRUE
|
681
|
+
end
|
682
|
+
|
683
|
+
def literal_time(v)
|
684
|
+
"#{v.strftime(PG_TIMESTAMP_FORMAT)}.#{sprintf("%06d",v.usec)}'"
|
685
|
+
end
|
686
|
+
|
692
687
|
# PostgreSQL is smart and can use parantheses around all datasets to get
|
693
688
|
# the correct answers.
|
694
689
|
def select_compounds_sql(sql, opts)
|
@@ -1,3 +1,6 @@
|
|
1
|
+
require 'sequel_core/adapters/utils/date_format'
|
2
|
+
require 'sequel_core/adapters/utils/unsupported'
|
3
|
+
|
1
4
|
module Sequel
|
2
5
|
module Progress
|
3
6
|
module DatabaseMethods
|
@@ -11,6 +14,7 @@ module Sequel
|
|
11
14
|
|
12
15
|
module DatasetMethods
|
13
16
|
include Dataset::UnsupportedIntersectExcept
|
17
|
+
include Dataset::SQLStandardDateFormat
|
14
18
|
|
15
19
|
SELECT_CLAUSE_ORDER = %w'limit distinct columns from join where group order having compounds'.freeze
|
16
20
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'sequel_core/adapters/utils/unsupported'
|
2
|
+
|
1
3
|
module Sequel
|
2
4
|
module SQLite
|
3
5
|
module DatabaseMethods
|
@@ -22,14 +24,45 @@ module Sequel
|
|
22
24
|
when :add_column, :add_index, :drop_index
|
23
25
|
super
|
24
26
|
when :drop_column
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
"
|
31
|
-
"
|
32
|
-
"
|
27
|
+
qt = quote_schema_table(table)
|
28
|
+
bt = quote_identifier(backup_table_name(qt.gsub('`', '')))
|
29
|
+
columns_str = dataset.send(:identifier_list, columns_for(table, :except => op[:name]))
|
30
|
+
defined_columns_str = column_list_sql(defined_columns_for(table, :except => op[:name]))
|
31
|
+
["CREATE TEMPORARY TABLE #{bt}(#{defined_columns_str})",
|
32
|
+
"INSERT INTO #{bt} SELECT #{columns_str} FROM #{qt}",
|
33
|
+
"DROP TABLE #{qt}",
|
34
|
+
"CREATE TABLE #{qt}(#{defined_columns_str})",
|
35
|
+
"INSERT INTO #{qt} SELECT #{columns_str} FROM #{bt}",
|
36
|
+
"DROP TABLE #{bt}"]
|
37
|
+
when :rename_column
|
38
|
+
qt = quote_schema_table(table)
|
39
|
+
bt = quote_identifier(backup_table_name(qt.gsub('`', '')))
|
40
|
+
old_columns = dataset.send(:identifier_list, columns_for(table))
|
41
|
+
new_columns_arr = columns_for(table)
|
42
|
+
|
43
|
+
# Replace the old column in place. This is extremely important.
|
44
|
+
new_columns_arr[new_columns_arr.index(op[:name])] = op[:new_name]
|
45
|
+
|
46
|
+
new_columns = dataset.send(:identifier_list, new_columns_arr)
|
47
|
+
|
48
|
+
def_old_columns = column_list_sql(defined_columns_for(table))
|
49
|
+
|
50
|
+
def_new_columns_arr = defined_columns_for(table).map do |c|
|
51
|
+
c[:name] = op[:new_name].to_s if c[:name] == op[:name].to_s
|
52
|
+
c
|
53
|
+
end
|
54
|
+
|
55
|
+
def_new_columns = column_list_sql(def_new_columns_arr)
|
56
|
+
|
57
|
+
[
|
58
|
+
"CREATE TEMPORARY TABLE #{bt}(#{def_old_columns})",
|
59
|
+
"INSERT INTO #{bt}(#{old_columns}) SELECT #{old_columns} FROM #{qt}",
|
60
|
+
"DROP TABLE #{qt}",
|
61
|
+
"CREATE TABLE #{qt}(#{def_new_columns})",
|
62
|
+
"INSERT INTO #{qt}(#{new_columns}) SELECT #{old_columns} FROM #{bt}",
|
63
|
+
"DROP TABLE #{bt}"
|
64
|
+
]
|
65
|
+
|
33
66
|
else
|
34
67
|
raise Error, "Unsupported ALTER TABLE operation"
|
35
68
|
end
|
@@ -92,6 +125,32 @@ module Sequel
|
|
92
125
|
end
|
93
126
|
|
94
127
|
private
|
128
|
+
|
129
|
+
# The array of column symbols in the table, except for ones given in opts[:except]
|
130
|
+
def backup_table_name(table, opts={})
|
131
|
+
(opts[:times]||1000).times do |i|
|
132
|
+
table_name = "#{table}_backup#{i}"
|
133
|
+
return table_name unless table_exists?(table_name)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# The array of column symbols in the table, except for ones given in opts[:except]
|
138
|
+
def columns_for(table, opts={})
|
139
|
+
cols = schema_parse_table(table, {}).map{|c| c[0]}
|
140
|
+
cols = cols - Array(opts[:except])
|
141
|
+
cols
|
142
|
+
end
|
143
|
+
|
144
|
+
# The array of column schema hashes, except for the ones given in opts[:except]
|
145
|
+
def defined_columns_for(table, opts={})
|
146
|
+
cols = parse_pragma(table, {})
|
147
|
+
cols.each{|c| c[:default] = LiteralString.new(c[:default]) if c[:default]}
|
148
|
+
if opts[:except]
|
149
|
+
nono= Array(opts[:except]).compact.map{|n| n.to_s}
|
150
|
+
cols.reject!{|c| nono.include? c[:name] }
|
151
|
+
end
|
152
|
+
cols
|
153
|
+
end
|
95
154
|
|
96
155
|
# SQLite folds unquoted identifiers to lowercase, so it shouldn't need to upcase identifiers on input.
|
97
156
|
def identifier_input_method_default
|
@@ -183,16 +242,17 @@ module Sequel
|
|
183
242
|
end
|
184
243
|
|
185
244
|
private
|
245
|
+
|
246
|
+
def literal_blob(v)
|
247
|
+
blob = ''
|
248
|
+
v.each_byte{|x| blob << sprintf('%02x', x)}
|
249
|
+
"X'#{blob}'"
|
250
|
+
end
|
186
251
|
|
187
252
|
# SQLite uses string literals instead of identifiers in AS clauses.
|
188
253
|
def as_sql(expression, aliaz)
|
189
254
|
"#{expression} AS #{literal(aliaz.to_s)}"
|
190
255
|
end
|
191
|
-
|
192
|
-
# Call execute_insert on the database with the given SQL.
|
193
|
-
def execute_insert(sql, opts={})
|
194
|
-
@db.execute_insert(sql, {:server=>@opts[:server] || :default}.merge(opts))
|
195
|
-
end
|
196
256
|
end
|
197
257
|
end
|
198
258
|
end
|