sequel 2.10.0 → 2.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. data/CHANGELOG +51 -1
  2. data/README.rdoc +2 -2
  3. data/Rakefile +2 -2
  4. data/doc/advanced_associations.rdoc +6 -18
  5. data/doc/release_notes/1.0.txt +38 -0
  6. data/doc/release_notes/1.1.txt +143 -0
  7. data/doc/release_notes/1.3.txt +101 -0
  8. data/doc/release_notes/1.4.0.txt +53 -0
  9. data/doc/release_notes/1.5.0.txt +155 -0
  10. data/doc/release_notes/2.0.0.txt +298 -0
  11. data/doc/release_notes/2.1.0.txt +271 -0
  12. data/doc/release_notes/2.10.0.txt +328 -0
  13. data/doc/release_notes/2.11.0.txt +215 -0
  14. data/doc/release_notes/2.2.0.txt +253 -0
  15. data/doc/release_notes/2.3.0.txt +88 -0
  16. data/doc/release_notes/2.4.0.txt +106 -0
  17. data/doc/release_notes/2.5.0.txt +137 -0
  18. data/doc/release_notes/2.6.0.txt +157 -0
  19. data/doc/release_notes/2.7.0.txt +166 -0
  20. data/doc/release_notes/2.8.0.txt +171 -0
  21. data/doc/release_notes/2.9.0.txt +97 -0
  22. data/lib/sequel_core/adapters/ado.rb +3 -0
  23. data/lib/sequel_core/adapters/db2.rb +0 -11
  24. data/lib/sequel_core/adapters/dbi.rb +0 -11
  25. data/lib/sequel_core/adapters/do.rb +0 -12
  26. data/lib/sequel_core/adapters/firebird.rb +21 -16
  27. data/lib/sequel_core/adapters/informix.rb +1 -11
  28. data/lib/sequel_core/adapters/jdbc.rb +1 -13
  29. data/lib/sequel_core/adapters/jdbc/h2.rb +3 -11
  30. data/lib/sequel_core/adapters/jdbc/mysql.rb +0 -17
  31. data/lib/sequel_core/adapters/jdbc/postgresql.rb +3 -15
  32. data/lib/sequel_core/adapters/mysql.rb +31 -27
  33. data/lib/sequel_core/adapters/odbc.rb +34 -28
  34. data/lib/sequel_core/adapters/openbase.rb +0 -11
  35. data/lib/sequel_core/adapters/oracle.rb +11 -9
  36. data/lib/sequel_core/adapters/postgres.rb +14 -17
  37. data/lib/sequel_core/adapters/shared/mssql.rb +6 -15
  38. data/lib/sequel_core/adapters/shared/mysql.rb +29 -14
  39. data/lib/sequel_core/adapters/shared/oracle.rb +4 -0
  40. data/lib/sequel_core/adapters/shared/postgres.rb +30 -35
  41. data/lib/sequel_core/adapters/shared/progress.rb +4 -0
  42. data/lib/sequel_core/adapters/shared/sqlite.rb +73 -13
  43. data/lib/sequel_core/adapters/sqlite.rb +8 -18
  44. data/lib/sequel_core/adapters/utils/date_format.rb +21 -0
  45. data/lib/sequel_core/{dataset → adapters/utils}/stored_procedures.rb +0 -0
  46. data/lib/sequel_core/{dataset → adapters/utils}/unsupported.rb +0 -0
  47. data/lib/sequel_core/core_ext.rb +1 -1
  48. data/lib/sequel_core/core_sql.rb +9 -4
  49. data/lib/sequel_core/database.rb +63 -62
  50. data/lib/sequel_core/dataset.rb +9 -4
  51. data/lib/sequel_core/dataset/convenience.rb +10 -9
  52. data/lib/sequel_core/dataset/prepared_statements.rb +1 -1
  53. data/lib/sequel_core/dataset/sql.rb +130 -36
  54. data/lib/sequel_core/schema/sql.rb +2 -2
  55. data/lib/sequel_core/sql.rb +44 -51
  56. data/lib/sequel_core/version.rb +1 -1
  57. data/lib/sequel_model/associations.rb +25 -17
  58. data/lib/sequel_model/base.rb +35 -7
  59. data/lib/sequel_model/caching.rb +1 -6
  60. data/lib/sequel_model/record.rb +23 -5
  61. data/lib/sequel_model/validations.rb +20 -5
  62. data/spec/adapters/firebird_spec.rb +6 -1
  63. data/spec/adapters/mysql_spec.rb +12 -0
  64. data/spec/adapters/postgres_spec.rb +2 -2
  65. data/spec/adapters/sqlite_spec.rb +81 -2
  66. data/spec/integration/dataset_test.rb +2 -2
  67. data/spec/integration/type_test.rb +12 -2
  68. data/spec/sequel_core/core_sql_spec.rb +46 -12
  69. data/spec/sequel_core/database_spec.rb +24 -12
  70. data/spec/sequel_core/dataset_spec.rb +82 -32
  71. data/spec/sequel_core/schema_spec.rb +16 -0
  72. data/spec/sequel_model/associations_spec.rb +89 -0
  73. data/spec/sequel_model/base_spec.rb +66 -0
  74. data/spec/sequel_model/eager_loading_spec.rb +32 -0
  75. data/spec/sequel_model/record_spec.rb +9 -9
  76. data/spec/sequel_model/spec_helper.rb +3 -0
  77. data/spec/sequel_model/validations_spec.rb +63 -3
  78. 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).to_blob }, # bytea
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 = '$'.lit.freeze
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}".lit
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 = '$'.lit.freeze
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) : 'NULL'.lit, *values)
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
- columns_str = (schema_parse_table(table, {}).map{|c| c[0]} - Array(op[:name])).join(",")
26
- defined_columns_str = column_list_sql parse_pragma(table, {}).reject{ |c| c[:name] == op[:name].to_s}
27
- ["CREATE TEMPORARY TABLE #{table}_backup(#{defined_columns_str})",
28
- "INSERT INTO #{table}_backup SELECT #{columns_str} FROM #{table}",
29
- "DROP TABLE #{table}",
30
- "CREATE TABLE #{table}(#{defined_columns_str})",
31
- "INSERT INTO #{table} SELECT #{columns_str} FROM #{table}_backup",
32
- "DROP TABLE #{table}_backup"]
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