sequel 3.33.0 → 3.34.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 (152) hide show
  1. data/CHANGELOG +140 -0
  2. data/Rakefile +7 -0
  3. data/bin/sequel +22 -2
  4. data/doc/dataset_basics.rdoc +1 -1
  5. data/doc/mass_assignment.rdoc +3 -1
  6. data/doc/querying.rdoc +28 -4
  7. data/doc/reflection.rdoc +23 -3
  8. data/doc/release_notes/3.34.0.txt +671 -0
  9. data/doc/schema_modification.rdoc +18 -2
  10. data/doc/virtual_rows.rdoc +49 -0
  11. data/lib/sequel/adapters/do/mysql.rb +0 -5
  12. data/lib/sequel/adapters/ibmdb.rb +9 -4
  13. data/lib/sequel/adapters/jdbc.rb +9 -4
  14. data/lib/sequel/adapters/jdbc/h2.rb +8 -2
  15. data/lib/sequel/adapters/jdbc/mysql.rb +0 -5
  16. data/lib/sequel/adapters/jdbc/postgresql.rb +43 -0
  17. data/lib/sequel/adapters/jdbc/sqlite.rb +19 -0
  18. data/lib/sequel/adapters/mock.rb +24 -3
  19. data/lib/sequel/adapters/mysql.rb +29 -50
  20. data/lib/sequel/adapters/mysql2.rb +13 -28
  21. data/lib/sequel/adapters/oracle.rb +8 -2
  22. data/lib/sequel/adapters/postgres.rb +115 -20
  23. data/lib/sequel/adapters/shared/db2.rb +1 -1
  24. data/lib/sequel/adapters/shared/mssql.rb +14 -3
  25. data/lib/sequel/adapters/shared/mysql.rb +59 -11
  26. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +6 -0
  27. data/lib/sequel/adapters/shared/oracle.rb +1 -1
  28. data/lib/sequel/adapters/shared/postgres.rb +127 -30
  29. data/lib/sequel/adapters/shared/sqlite.rb +55 -38
  30. data/lib/sequel/adapters/sqlite.rb +9 -3
  31. data/lib/sequel/adapters/swift.rb +2 -2
  32. data/lib/sequel/adapters/swift/mysql.rb +0 -5
  33. data/lib/sequel/adapters/swift/postgres.rb +10 -0
  34. data/lib/sequel/ast_transformer.rb +4 -0
  35. data/lib/sequel/connection_pool.rb +8 -0
  36. data/lib/sequel/connection_pool/sharded_single.rb +5 -0
  37. data/lib/sequel/connection_pool/sharded_threaded.rb +17 -0
  38. data/lib/sequel/connection_pool/single.rb +5 -0
  39. data/lib/sequel/connection_pool/threaded.rb +14 -0
  40. data/lib/sequel/core.rb +24 -3
  41. data/lib/sequel/database/connecting.rb +24 -14
  42. data/lib/sequel/database/dataset_defaults.rb +1 -0
  43. data/lib/sequel/database/misc.rb +16 -25
  44. data/lib/sequel/database/query.rb +20 -2
  45. data/lib/sequel/database/schema_generator.rb +2 -2
  46. data/lib/sequel/database/schema_methods.rb +120 -23
  47. data/lib/sequel/dataset/actions.rb +91 -18
  48. data/lib/sequel/dataset/features.rb +5 -0
  49. data/lib/sequel/dataset/prepared_statements.rb +6 -2
  50. data/lib/sequel/dataset/sql.rb +68 -51
  51. data/lib/sequel/extensions/_pretty_table.rb +79 -0
  52. data/lib/sequel/{core_sql.rb → extensions/core_extensions.rb} +18 -13
  53. data/lib/sequel/extensions/migration.rb +4 -0
  54. data/lib/sequel/extensions/null_dataset.rb +90 -0
  55. data/lib/sequel/extensions/pg_array.rb +460 -0
  56. data/lib/sequel/extensions/pg_array_ops.rb +220 -0
  57. data/lib/sequel/extensions/pg_auto_parameterize.rb +174 -0
  58. data/lib/sequel/extensions/pg_hstore.rb +296 -0
  59. data/lib/sequel/extensions/pg_hstore_ops.rb +259 -0
  60. data/lib/sequel/extensions/pg_statement_cache.rb +316 -0
  61. data/lib/sequel/extensions/pretty_table.rb +5 -71
  62. data/lib/sequel/extensions/query_literals.rb +79 -0
  63. data/lib/sequel/extensions/schema_caching.rb +76 -0
  64. data/lib/sequel/extensions/schema_dumper.rb +227 -31
  65. data/lib/sequel/extensions/select_remove.rb +35 -0
  66. data/lib/sequel/extensions/sql_expr.rb +4 -110
  67. data/lib/sequel/extensions/to_dot.rb +1 -1
  68. data/lib/sequel/model.rb +11 -2
  69. data/lib/sequel/model/associations.rb +35 -7
  70. data/lib/sequel/model/base.rb +159 -36
  71. data/lib/sequel/no_core_ext.rb +2 -0
  72. data/lib/sequel/plugins/caching.rb +25 -18
  73. data/lib/sequel/plugins/composition.rb +1 -1
  74. data/lib/sequel/plugins/hook_class_methods.rb +1 -1
  75. data/lib/sequel/plugins/identity_map.rb +11 -3
  76. data/lib/sequel/plugins/instance_filters.rb +10 -0
  77. data/lib/sequel/plugins/many_to_one_pk_lookup.rb +71 -0
  78. data/lib/sequel/plugins/nested_attributes.rb +4 -3
  79. data/lib/sequel/plugins/prepared_statements.rb +3 -1
  80. data/lib/sequel/plugins/prepared_statements_associations.rb +5 -1
  81. data/lib/sequel/plugins/schema.rb +7 -2
  82. data/lib/sequel/plugins/single_table_inheritance.rb +1 -1
  83. data/lib/sequel/plugins/static_cache.rb +99 -0
  84. data/lib/sequel/plugins/validation_class_methods.rb +1 -1
  85. data/lib/sequel/sql.rb +417 -7
  86. data/lib/sequel/version.rb +1 -1
  87. data/spec/adapters/firebird_spec.rb +1 -1
  88. data/spec/adapters/mssql_spec.rb +12 -15
  89. data/spec/adapters/mysql_spec.rb +81 -23
  90. data/spec/adapters/postgres_spec.rb +444 -77
  91. data/spec/adapters/spec_helper.rb +2 -0
  92. data/spec/adapters/sqlite_spec.rb +8 -8
  93. data/spec/core/connection_pool_spec.rb +85 -0
  94. data/spec/core/database_spec.rb +29 -5
  95. data/spec/core/dataset_spec.rb +171 -3
  96. data/spec/core/expression_filters_spec.rb +364 -0
  97. data/spec/core/mock_adapter_spec.rb +17 -3
  98. data/spec/core/schema_spec.rb +133 -0
  99. data/spec/extensions/association_dependencies_spec.rb +13 -13
  100. data/spec/extensions/caching_spec.rb +26 -3
  101. data/spec/extensions/class_table_inheritance_spec.rb +2 -2
  102. data/spec/{core/core_sql_spec.rb → extensions/core_extensions_spec.rb} +23 -94
  103. data/spec/extensions/force_encoding_spec.rb +4 -2
  104. data/spec/extensions/hook_class_methods_spec.rb +5 -2
  105. data/spec/extensions/identity_map_spec.rb +17 -0
  106. data/spec/extensions/instance_filters_spec.rb +1 -1
  107. data/spec/extensions/lazy_attributes_spec.rb +2 -2
  108. data/spec/extensions/list_spec.rb +4 -4
  109. data/spec/extensions/many_to_one_pk_lookup_spec.rb +140 -0
  110. data/spec/extensions/migration_spec.rb +6 -2
  111. data/spec/extensions/nested_attributes_spec.rb +20 -0
  112. data/spec/extensions/null_dataset_spec.rb +85 -0
  113. data/spec/extensions/optimistic_locking_spec.rb +2 -2
  114. data/spec/extensions/pg_array_ops_spec.rb +105 -0
  115. data/spec/extensions/pg_array_spec.rb +196 -0
  116. data/spec/extensions/pg_auto_parameterize_spec.rb +64 -0
  117. data/spec/extensions/pg_hstore_ops_spec.rb +136 -0
  118. data/spec/extensions/pg_hstore_spec.rb +195 -0
  119. data/spec/extensions/pg_statement_cache_spec.rb +209 -0
  120. data/spec/extensions/prepared_statements_spec.rb +4 -0
  121. data/spec/extensions/pretty_table_spec.rb +6 -0
  122. data/spec/extensions/query_literals_spec.rb +168 -0
  123. data/spec/extensions/schema_caching_spec.rb +41 -0
  124. data/spec/extensions/schema_dumper_spec.rb +231 -11
  125. data/spec/extensions/schema_spec.rb +14 -2
  126. data/spec/extensions/select_remove_spec.rb +38 -0
  127. data/spec/extensions/sharding_spec.rb +6 -6
  128. data/spec/extensions/skip_create_refresh_spec.rb +1 -1
  129. data/spec/extensions/spec_helper.rb +2 -1
  130. data/spec/extensions/sql_expr_spec.rb +28 -19
  131. data/spec/extensions/static_cache_spec.rb +145 -0
  132. data/spec/extensions/touch_spec.rb +1 -1
  133. data/spec/extensions/typecast_on_load_spec.rb +9 -1
  134. data/spec/integration/associations_test.rb +6 -6
  135. data/spec/integration/database_test.rb +1 -1
  136. data/spec/integration/dataset_test.rb +89 -26
  137. data/spec/integration/migrator_test.rb +2 -3
  138. data/spec/integration/model_test.rb +3 -3
  139. data/spec/integration/plugin_test.rb +85 -22
  140. data/spec/integration/prepared_statement_test.rb +28 -8
  141. data/spec/integration/schema_test.rb +78 -7
  142. data/spec/integration/spec_helper.rb +1 -0
  143. data/spec/integration/timezone_test.rb +1 -1
  144. data/spec/integration/transaction_test.rb +4 -6
  145. data/spec/integration/type_test.rb +2 -2
  146. data/spec/model/associations_spec.rb +94 -8
  147. data/spec/model/base_spec.rb +4 -4
  148. data/spec/model/hooks_spec.rb +2 -2
  149. data/spec/model/model_spec.rb +19 -7
  150. data/spec/model/record_spec.rb +135 -58
  151. data/spec/model/spec_helper.rb +1 -0
  152. metadata +35 -7
@@ -11,8 +11,8 @@ module Sequel
11
11
  ACTION_METHODS = (<<-METHS).split.map{|x| x.to_sym}
12
12
  << [] []= all avg count columns columns! delete each
13
13
  empty? fetch_rows first get import insert insert_multiple interval last
14
- map max min multi_insert range select_hash select_map select_order_map
15
- set single_record single_value sum to_csv to_hash truncate update
14
+ map max min multi_insert range select_hash select_hash_groups select_map select_order_map
15
+ set single_record single_value sum to_csv to_hash to_hash_groups truncate update
16
16
  METHS
17
17
 
18
18
  # Inserts the given argument into the database. Returns self so it
@@ -124,13 +124,13 @@ module Sequel
124
124
  # running additional queries inside the provided block. If you are
125
125
  # running queries inside the block, you should use +all+ instead of +each+
126
126
  # for the outer queries, or use a separate thread or shard inside +each+:
127
- def each(&block)
127
+ def each
128
128
  if @opts[:graph]
129
- graph_each(&block)
129
+ graph_each{|r| yield r}
130
130
  elsif row_proc = @row_proc
131
131
  fetch_rows(select_sql){|r| yield row_proc.call(r)}
132
132
  else
133
- fetch_rows(select_sql, &block)
133
+ fetch_rows(select_sql){|r| yield r}
134
134
  end
135
135
  self
136
136
  end
@@ -421,7 +421,7 @@ module Sequel
421
421
  end
422
422
 
423
423
  # Returns a hash with key_column values as keys and value_column values as
424
- # values. Similar to to_hash, but only selects the two columns.
424
+ # values. Similar to to_hash, but only selects the columns given.
425
425
  #
426
426
  # DB[:table].select_hash(:id, :name) # SELECT id, name FROM table
427
427
  # # => {1=>'a', 2=>'b', ...}
@@ -436,19 +436,28 @@ module Sequel
436
436
  # that Sequel can determine. Usually you can do this by calling the #as method
437
437
  # on the expression and providing an alias.
438
438
  def select_hash(key_column, value_column)
439
- if key_column.is_a?(Array)
440
- if value_column.is_a?(Array)
441
- select(*(key_column + value_column)).to_hash(key_column.map{|c| hash_key_symbol(c)}, value_column.map{|c| hash_key_symbol(c)})
442
- else
443
- select(*(key_column + [value_column])).to_hash(key_column.map{|c| hash_key_symbol(c)}, hash_key_symbol(value_column))
444
- end
445
- elsif value_column.is_a?(Array)
446
- select(key_column, *value_column).to_hash(hash_key_symbol(key_column), value_column.map{|c| hash_key_symbol(c)})
447
- else
448
- select(key_column, value_column).to_hash(hash_key_symbol(key_column), hash_key_symbol(value_column))
449
- end
439
+ _select_hash(:to_hash, key_column, value_column)
450
440
  end
451
441
 
442
+ # Returns a hash with key_column values as keys and an array of value_column values.
443
+ # Similar to to_hash_groups, but only selects the columns given.
444
+ #
445
+ # DB[:table].select_hash(:name, :id) # SELECT id, name FROM table
446
+ # # => {'a'=>[1, 4, ...], 'b'=>[2, ...], ...}
447
+ #
448
+ # You can also provide an array of column names for either the key_column,
449
+ # the value column, or both:
450
+ #
451
+ # DB[:table].select_hash([:first, :middle], [:last, :id]) # SELECT * FROM table
452
+ # # {['a', 'b']=>[['c', 1], ['d', 2], ...], ...}
453
+ #
454
+ # When using this method, you must be sure that each expression has an alias
455
+ # that Sequel can determine. Usually you can do this by calling the #as method
456
+ # on the expression and providing an alias.
457
+ def select_hash_groups(key_column, value_column)
458
+ _select_hash(:to_hash_groups, key_column, value_column)
459
+ end
460
+
452
461
  # Selects the column given (either as an argument or as a block), and
453
462
  # returns an array of all values of that column in the dataset. If you
454
463
  # give a block argument that returns an array with multiple entries,
@@ -472,7 +481,6 @@ module Sequel
472
481
  def select_map(column=nil, &block)
473
482
  _select_map(column, false, &block)
474
483
  end
475
-
476
484
 
477
485
  # The same as select_map, but in addition orders the array by the column.
478
486
  #
@@ -591,6 +599,49 @@ module Sequel
591
599
  h
592
600
  end
593
601
 
602
+ # Returns a hash with one column used as key and the values being an
603
+ # array of column values. If the value_column is not given or nil, uses
604
+ # the entire hash as the value.
605
+ #
606
+ # DB[:table].to_hash(:name, :id) # SELECT * FROM table
607
+ # # {'Jim'=>[1, 4, 16, ...], 'Bob'=>[2], ...}
608
+ #
609
+ # DB[:table].to_hash(:name) # SELECT * FROM table
610
+ # # {'Jim'=>[{:id=>1, :name=>'Jim'}, {:id=>4, :name=>'Jim'}, ...], 'Bob'=>[{:id=>2, :name=>'Bob'}], ...}
611
+ #
612
+ # You can also provide an array of column names for either the key_column,
613
+ # the value column, or both:
614
+ #
615
+ # DB[:table].to_hash([:first, :middle], [:last, :id]) # SELECT * FROM table
616
+ # # {['Jim', 'Bob']=>[['Smith', 1], ['Jackson', 4], ...], ...}
617
+ #
618
+ # DB[:table].to_hash([:first, :middle]) # SELECT * FROM table
619
+ # # {['Jim', 'Bob']=>[{:id=>1, :first=>'Jim', :middle=>'Bob', :last=>'Smith'}, ...], ...}
620
+ def to_hash_groups(key_column, value_column = nil)
621
+ h = {}
622
+ if value_column
623
+ return naked.to_hash_groups(key_column, value_column) if row_proc
624
+ if value_column.is_a?(Array)
625
+ if key_column.is_a?(Array)
626
+ each{|r| (h[r.values_at(*key_column)] ||= []) << r.values_at(*value_column)}
627
+ else
628
+ each{|r| (h[r[key_column]] ||= []) << r.values_at(*value_column)}
629
+ end
630
+ else
631
+ if key_column.is_a?(Array)
632
+ each{|r| (h[r.values_at(*key_column)] ||= []) << r[value_column]}
633
+ else
634
+ each{|r| (h[r[key_column]] ||= []) << r[value_column]}
635
+ end
636
+ end
637
+ elsif key_column.is_a?(Array)
638
+ each{|r| (h[r.values_at(*key_column)] ||= []) << r}
639
+ else
640
+ each{|r| (h[r[key_column]] ||= []) << r}
641
+ end
642
+ h
643
+ end
644
+
594
645
  # Truncates the dataset. Returns nil.
595
646
  #
596
647
  # DB[:table].truncate # TRUNCATE table
@@ -618,6 +669,13 @@ module Sequel
618
669
  end
619
670
  end
620
671
 
672
+ # Execute the given SQL and return the number of rows deleted. This exists
673
+ # solely as an optimization, replacing with_sql(sql).delete. It's significantly
674
+ # faster as it does not require cloning the current dataset.
675
+ def with_sql_delete(sql)
676
+ execute_dui(sql)
677
+ end
678
+
621
679
  protected
622
680
 
623
681
  # Internals of #import. If primary key values are requested, use
@@ -645,6 +703,21 @@ module Sequel
645
703
 
646
704
  private
647
705
 
706
+ # Internals of +select_hash+ and +select_hash_groups+
707
+ def _select_hash(meth, key_column, value_column)
708
+ if key_column.is_a?(Array)
709
+ if value_column.is_a?(Array)
710
+ select(*(key_column + value_column)).send(meth, key_column.map{|c| hash_key_symbol(c)}, value_column.map{|c| hash_key_symbol(c)})
711
+ else
712
+ select(*(key_column + [value_column])).send(meth, key_column.map{|c| hash_key_symbol(c)}, hash_key_symbol(value_column))
713
+ end
714
+ elsif value_column.is_a?(Array)
715
+ select(key_column, *value_column).send(meth, hash_key_symbol(key_column), value_column.map{|c| hash_key_symbol(c)})
716
+ else
717
+ select(key_column, value_column).send(meth, hash_key_symbol(key_column), hash_key_symbol(value_column))
718
+ end
719
+ end
720
+
648
721
  # Internals of +select_map+ and +select_order_map+
649
722
  def _select_map(column, order, &block)
650
723
  ds = naked.ungraphed
@@ -165,5 +165,10 @@ module Sequel
165
165
  def uses_returning?(type)
166
166
  opts[:returning] && !@opts[:sql] && supports_returning?(type)
167
167
  end
168
+
169
+ # Whether the dataset uses WITH ROLLUP/CUBE instead of ROLLUP()/CUBE().
170
+ def uses_with_rollup?
171
+ false
172
+ end
168
173
  end
169
174
  end
@@ -17,7 +17,7 @@ module Sequel
17
17
 
18
18
  # The bind arguments to use for running this prepared statement
19
19
  attr_accessor :bind_arguments
20
-
20
+
21
21
  # Set the bind arguments based on the hash and call super.
22
22
  def call(bind_vars={}, &block)
23
23
  ds = bind(bind_vars)
@@ -46,6 +46,10 @@ module Sequel
46
46
  module PreparedStatementMethods
47
47
  PLACEHOLDER_RE = /\A\$(.*)\z/
48
48
 
49
+ # Whether to log the full SQL query. By default, just the prepared statement
50
+ # name is generally logged on adapters that support native prepared statements.
51
+ attr_accessor :log_sql
52
+
49
53
  # The type of prepared statement, should be one of :select, :first,
50
54
  # :insert, :update, or :delete
51
55
  attr_accessor :prepared_type
@@ -139,7 +143,7 @@ module Sequel
139
143
  delete
140
144
  when Array
141
145
  case @prepared_type.at(0)
142
- when :map, :to_hash
146
+ when :map, :to_hash, :to_hash_groups
143
147
  send(*@prepared_type, &block)
144
148
  end
145
149
  else
@@ -20,7 +20,7 @@ module Sequel
20
20
  # DB.select(1).where(DB[:items].exists)
21
21
  # # SELECT 1 WHERE (EXISTS (SELECT * FROM items))
22
22
  def exists
23
- SQL::PlaceholderLiteralString.new("EXISTS ?", [self], true)
23
+ SQL::PlaceholderLiteralString.new(EXISTS, [self], true)
24
24
  end
25
25
 
26
26
  # Returns an INSERT SQL query string. See +insert+.
@@ -63,7 +63,7 @@ module Sequel
63
63
 
64
64
  if values.is_a?(Array) && values.empty? && !insert_supports_empty_values?
65
65
  columns = [columns().last]
66
- values = ['DEFAULT'.lit]
66
+ values = [DEFAULT]
67
67
  end
68
68
  clone(:columns=>columns, :values=>values)._insert_sql
69
69
  end
@@ -182,6 +182,7 @@ module Sequel
182
182
  clauses.map{|clause| :"#{type}_#{clause}_sql"}.freeze
183
183
  end
184
184
 
185
+ WILDCARD = LiteralString.new('*').freeze
185
186
  ALL = ' ALL'.freeze
186
187
  AND_SEPARATOR = " AND ".freeze
187
188
  APOS = "'".freeze
@@ -200,7 +201,6 @@ module Sequel
200
201
  CASE_THEN = " THEN ".freeze
201
202
  CASE_WHEN = " WHEN ".freeze
202
203
  CAST_OPEN = 'CAST('.freeze
203
- COLUMN_ALL = '.*'.freeze
204
204
  COLUMN_REF_RE1 = /\A((?:(?!__).)+)__((?:(?!___).)+)___(.+)\z/.freeze
205
205
  COLUMN_REF_RE2 = /\A((?:(?!___).)+)___(.+)\z/.freeze
206
206
  COLUMN_REF_RE3 = /\A((?:(?!__).)+)__(.+)\z/.freeze
@@ -209,8 +209,9 @@ module Sequel
209
209
  CONDITION_FALSE = '(1 = 0)'.freeze
210
210
  CONDITION_TRUE = '(1 = 1)'.freeze
211
211
  COUNT_FROM_SELF_OPTS = [:distinct, :group, :sql, :limit, :compounds]
212
- COUNT_OF_ALL_AS_COUNT = SQL::Function.new(:count, LiteralString.new('*'.freeze)).as(:count)
212
+ COUNT_OF_ALL_AS_COUNT = SQL::Function.new(:count, WILDCARD).as(:count)
213
213
  DATASET_ALIAS_BASE_NAME = 't'.freeze
214
+ DEFAULT = LiteralString.new('DEFAULT').freeze
214
215
  DEFAULT_VALUES = " DEFAULT VALUES".freeze
215
216
  DELETE = 'DELETE'.freeze
216
217
  DELETE_CLAUSE_METHODS = clause_methods(:delete, %w'delete from where')
@@ -221,6 +222,7 @@ module Sequel
221
222
  DOUBLE_QUOTE = '""'.freeze
222
223
  EQUAL = ' = '.freeze
223
224
  EXTRACT = 'extract('.freeze
225
+ EXISTS = ['EXISTS '.freeze].freeze
224
226
  FOR_UPDATE = ' FOR UPDATE'.freeze
225
227
  FORMAT_DATE = "'%Y-%m-%d'".freeze
226
228
  FORMAT_DATE_STANDARD = "DATE '%Y-%m-%d'".freeze
@@ -267,6 +269,7 @@ module Sequel
267
269
  SET = ' SET '.freeze
268
270
  SPACE = ' '.freeze
269
271
  SQL_WITH = "WITH ".freeze
272
+ SPACE_WITH = " WITH ".freeze
270
273
  TILDE = '~'.freeze
271
274
  TIMESTAMP_FORMAT = "'%Y-%m-%d %H:%M:%S%N%z'".freeze
272
275
  STANDARD_TIMESTAMP_FORMAT = "TIMESTAMP #{TIMESTAMP_FORMAT}".freeze
@@ -276,8 +279,9 @@ module Sequel
276
279
  UPDATE_CLAUSE_METHODS = clause_methods(:update, %w'update table set where')
277
280
  USING = ' USING ('.freeze
278
281
  VALUES = " VALUES ".freeze
282
+ V187 = '1.8.7'.freeze
283
+ V190 = '1.9.0'.freeze
279
284
  WHERE = " WHERE ".freeze
280
- WILDCARD = LiteralString.new('*').freeze
281
285
 
282
286
  PUBLIC_APPEND_METHODS = (<<-END).split.map{|x| x.to_sym}
283
287
  literal
@@ -392,10 +396,10 @@ module Sequel
392
396
 
393
397
  # SQL fragment for specifying all columns in a given table
394
398
  def column_all_sql_append(sql, ca)
395
- quote_schema_table_append(sql, ca.table)
396
- sql << COLUMN_ALL
399
+ qualified_identifier_sql_append(sql, ca.table, WILDCARD)
397
400
  end
398
401
 
402
+ # SQL fragment for the complex expression.
399
403
  def complex_expression_sql_append(sql, op, args)
400
404
  case op
401
405
  when *IS_OPERATORS
@@ -509,7 +513,7 @@ module Sequel
509
513
  table_alias = jc.table_alias
510
514
  table_alias = nil if table == table_alias
511
515
  sql << SPACE << join_type_sql(jc.join_type) << SPACE
512
- table_ref_append(sql, table)
516
+ identifier_append(sql, table)
513
517
  as_sql_append(sql, table_alias) if table_alias
514
518
  end
515
519
 
@@ -550,11 +554,11 @@ module Sequel
550
554
  # SQL fragment for a literal string with placeholders
551
555
  def placeholder_literal_string_sql_append(sql, pls)
552
556
  args = pls.args
557
+ str = pls.str
553
558
  sql << PAREN_OPEN if pls.parens
554
559
  if args.is_a?(Hash)
555
560
  re = /:(#{args.keys.map{|k| Regexp.escape(k.to_s)}.join('|')})\b/
556
- if RUBY_VERSION >= '1.8.7'
557
- str = pls.str
561
+ if RUBY_VERSION >= V187
558
562
  loop do
559
563
  previous, q, str = str.partition(re)
560
564
  sql << previous
@@ -562,12 +566,17 @@ module Sequel
562
566
  break if str.empty?
563
567
  end
564
568
  else
565
- sql << pls.str.gsub(re){literal(args[$1.to_sym])}
569
+ sql << str.gsub(re){literal(args[$1.to_sym])}
570
+ end
571
+ elsif str.is_a?(Array)
572
+ len = args.length
573
+ str.each_with_index do |s, i|
574
+ sql << s
575
+ literal_append(sql, args[i]) unless i == len
566
576
  end
567
577
  else
568
578
  i = -1
569
- if RUBY_VERSION >= '1.8.7'
570
- str = pls.str
579
+ if RUBY_VERSION >= V187
571
580
  loop do
572
581
  previous, q, str = str.partition(QUESTION_MARK)
573
582
  sql << previous
@@ -575,7 +584,7 @@ module Sequel
575
584
  break if str.empty?
576
585
  end
577
586
  else
578
- sql << pls.str.gsub(QUESTION_MARK_RE){literal(args.at(i+=1))}
587
+ sql << str.gsub(QUESTION_MARK_RE){literal(args.at(i+=1))}
579
588
  end
580
589
  end
581
590
  sql << PAREN_CLOSE if pls.parens
@@ -583,20 +592,12 @@ module Sequel
583
592
 
584
593
  # SQL fragment for the qualifed identifier, specifying
585
594
  # a table and a column (or schema and table).
586
- def qualified_identifier_sql_append(sql, qcr)
587
- case t = qcr.table
588
- when Symbol, SQL::QualifiedIdentifier, SQL::Identifier
589
- literal_append(sql, t)
590
- else
591
- quote_identifier_append(sql, t)
592
- end
595
+ # If 3 arguments are given, the 2nd should be the table/qualifier and the third should be
596
+ # column/qualified. If 2 arguments are given, the 2nd should be an SQL::QualifiedIdentifier.
597
+ def qualified_identifier_sql_append(sql, table, column=(c = table.column; table = table.table; c))
598
+ identifier_append(sql, table)
593
599
  sql << DOT
594
- case c = qcr.column
595
- when Symbol, SQL::QualifiedIdentifier, SQL::Identifier
596
- literal_append(sql, c)
597
- else
598
- quote_identifier_append(sql, c)
599
- end
600
+ identifier_append(sql, column)
600
601
  end
601
602
 
602
603
  # Adds quoting to identifiers (columns and tables). If identifiers are not
@@ -802,7 +803,7 @@ module Sequel
802
803
 
803
804
  # Prepare an SQL statement by calling all clause methods for the given statement type.
804
805
  def clause_sql(type)
805
- sql = @opts[:append_sql] || ''
806
+ sql = @opts[:append_sql] || sql_string_origin
806
807
  send("#{type}_clause_methods").each{|x| send(x, sql)}
807
808
  sql
808
809
  end
@@ -869,7 +870,7 @@ module Sequel
869
870
  c ||= true
870
871
  end
871
872
  end
872
-
873
+
873
874
  def empty_array_value(op, cols)
874
875
  if Sequel.empty_array_handle_nulls
875
876
  c = Array(cols)
@@ -887,7 +888,7 @@ module Sequel
887
888
  v2 = db.from_application_timestamp(v)
888
889
  fmt = default_timestamp_format.gsub(FORMAT_TIMESTAMP_RE) do |m|
889
890
  if m == FORMAT_USEC
890
- format_timestamp_usec(v.is_a?(DateTime) ? v.sec_fraction*(RUBY_VERSION < '1.9.0' ? 86400000000 : 1000000) : v.usec) if supports_timestamp_usecs?
891
+ format_timestamp_usec(v.is_a?(DateTime) ? v.sec_fraction*(RUBY_VERSION < V190 ? 86400000000 : 1000000) : v.usec) if supports_timestamp_usecs?
891
892
  else
892
893
  if supports_timestamp_timezones?
893
894
  # Would like to just use %z format, but it doesn't appear to work on Windows
@@ -911,6 +912,24 @@ module Sequel
911
912
  sprintf(FORMAT_TIMESTAMP_USEC, usec)
912
913
  end
913
914
 
915
+ # Append the value, but special case regular (non-literal, non-blob) strings
916
+ # so that they are considered as identifiers and not SQL strings.
917
+ def identifier_append(sql, v)
918
+ if v.is_a?(String)
919
+ case v
920
+ when LiteralString
921
+ sql << v
922
+ when SQL::Blob
923
+ literal_append(sql, v)
924
+ else
925
+ quote_identifier_append(sql, v)
926
+ end
927
+ else
928
+ literal_append(sql, v)
929
+ end
930
+ end
931
+ alias table_ref_append identifier_append
932
+
914
933
  # Modify the identifier returned from the database based on the
915
934
  # identifier_output_method.
916
935
  def input_identifier(v)
@@ -937,11 +956,7 @@ module Sequel
937
956
  co = COMMA
938
957
  columns.each do |col|
939
958
  sql << co if c
940
- if col.is_a?(String) && !col.is_a?(LiteralString)
941
- quote_identifier_append(sql, col)
942
- else
943
- literal_append(sql, col)
944
- end
959
+ identifier_append(sql, col)
945
960
  c ||= true
946
961
  end
947
962
  sql << PAREN_CLOSE
@@ -1058,7 +1073,7 @@ module Sequel
1058
1073
  def literal_integer(v)
1059
1074
  v.to_s
1060
1075
  end
1061
-
1076
+
1062
1077
  # SQL fragment for nil
1063
1078
  def literal_nil
1064
1079
  NULL
@@ -1194,11 +1209,17 @@ module Sequel
1194
1209
  if group = @opts[:group]
1195
1210
  sql << GROUP_BY
1196
1211
  if go = @opts[:group_options]
1197
- sql << go.to_s.upcase
1198
- sql << PAREN_OPEN
1212
+ if uses_with_rollup?
1213
+ expression_list_append(sql, group)
1214
+ sql << SPACE_WITH << go.to_s.upcase
1215
+ else
1216
+ sql << go.to_s.upcase << PAREN_OPEN
1217
+ expression_list_append(sql, group)
1218
+ sql << PAREN_CLOSE
1219
+ end
1220
+ else
1221
+ expression_list_append(sql, group)
1199
1222
  end
1200
- expression_list_append(sql, group)
1201
- sql << PAREN_CLOSE if go
1202
1223
  end
1203
1224
  end
1204
1225
 
@@ -1300,7 +1321,7 @@ module Sequel
1300
1321
  co = COMMA
1301
1322
  sources.each do |s|
1302
1323
  sql << co if c
1303
- table_ref_append(sql, s)
1324
+ identifier_append(sql, s)
1304
1325
  c ||= true
1305
1326
  end
1306
1327
  end
@@ -1323,6 +1344,12 @@ module Sequel
1323
1344
  end
1324
1345
  end
1325
1346
 
1347
+ # The string that is appended to to create the SQL query, the empty
1348
+ # string by default
1349
+ def sql_string_origin
1350
+ ''
1351
+ end
1352
+
1326
1353
  # SQL to use if this dataset uses static SQL. Since static SQL
1327
1354
  # can be a PlaceholderLiteralString in addition to a String,
1328
1355
  # we literalize nonstrings.
@@ -1347,16 +1374,6 @@ module Sequel
1347
1374
  ds.clone(:append_sql=>sql).sql
1348
1375
  end
1349
1376
 
1350
- # SQL fragment specifying a table name.
1351
- def table_ref_append(sql, t)
1352
- if t.is_a?(String)
1353
- quote_identifier_append(sql, t)
1354
- else
1355
- literal_append(sql, t)
1356
- end
1357
- end
1358
- alias identifier_append table_ref_append
1359
-
1360
1377
  # The order of methods to call to build the UPDATE SQL statement
1361
1378
  def update_clause_methods
1362
1379
  UPDATE_CLAUSE_METHODS