sequel 4.11.0 → 4.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +32 -0
  3. data/Rakefile +1 -5
  4. data/doc/opening_databases.rdoc +5 -1
  5. data/doc/release_notes/4.12.0.txt +105 -0
  6. data/lib/sequel/adapters/jdbc.rb +1 -0
  7. data/lib/sequel/adapters/oracle.rb +1 -0
  8. data/lib/sequel/adapters/postgres.rb +17 -8
  9. data/lib/sequel/adapters/shared/cubrid.rb +2 -1
  10. data/lib/sequel/adapters/shared/db2.rb +1 -0
  11. data/lib/sequel/adapters/shared/mssql.rb +1 -0
  12. data/lib/sequel/adapters/shared/postgres.rb +23 -2
  13. data/lib/sequel/adapters/shared/sqlanywhere.rb +1 -0
  14. data/lib/sequel/adapters/sqlite.rb +11 -5
  15. data/lib/sequel/database/query.rb +14 -1
  16. data/lib/sequel/dataset/prepared_statements.rb +2 -1
  17. data/lib/sequel/dataset/query.rb +48 -37
  18. data/lib/sequel/dataset/sql.rb +0 -39
  19. data/lib/sequel/extensions/pg_interval.rb +1 -1
  20. data/lib/sequel/extensions/pg_static_cache_updater.rb +11 -5
  21. data/lib/sequel/model/associations.rb +2 -2
  22. data/lib/sequel/plugins/auto_validations.rb +16 -4
  23. data/lib/sequel/plugins/hook_class_methods.rb +1 -1
  24. data/lib/sequel/plugins/nested_attributes.rb +72 -59
  25. data/lib/sequel/plugins/prepared_statements.rb +16 -5
  26. data/lib/sequel/plugins/prepared_statements_associations.rb +14 -0
  27. data/lib/sequel/sql.rb +2 -43
  28. data/lib/sequel/version.rb +1 -1
  29. data/spec/adapters/postgres_spec.rb +49 -20
  30. data/spec/bin_spec.rb +2 -2
  31. data/spec/core/dataset_spec.rb +18 -6
  32. data/spec/core/schema_spec.rb +2 -1
  33. data/spec/extensions/auto_validations_spec.rb +23 -2
  34. data/spec/extensions/nested_attributes_spec.rb +32 -1
  35. data/spec/extensions/pg_static_cache_updater_spec.rb +12 -0
  36. data/spec/extensions/prepared_statements_associations_spec.rb +17 -17
  37. data/spec/extensions/prepared_statements_spec.rb +11 -8
  38. data/spec/integration/plugin_test.rb +43 -0
  39. data/spec/integration/schema_test.rb +7 -0
  40. data/spec/model/eager_loading_spec.rb +9 -0
  41. metadata +4 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ced6249de982434d96b02340853663f604357771
4
- data.tar.gz: 2f34bc5dff2cb2e0ffa1c613252291a52a0b5876
3
+ metadata.gz: b15d571f0ccc175749541cfee443b953dcd145fd
4
+ data.tar.gz: 9dec9dd2f6816432f511c0153737646e44da31a1
5
5
  SHA512:
6
- metadata.gz: 8df573b48f64deb1af7958cdf2d09e75a5f8adb2709519e04f51cabc2b18f7b08e3da857261b0faec876e476b1a3bd961517f82d79bfb33ee9a236dfc066d899
7
- data.tar.gz: becb87b9aecc164e06e48a4b5f86eb983ad9e3d09851155f50c935f0e17bccd26d57987dfdcc4635c4531d1cc07a1e753a20998b55c6fa9921e89c58310bc3dd
6
+ metadata.gz: ec94d8b6fcd34fecdb4d4c3cc4f2b4fb0277c8d7289baebde098b8b84cc99ab0bfd0ab28effa316df0a0fbba1a7bf2cc3bc0fbbfc682e68f6d50326652719306
7
+ data.tar.gz: 919e8651ded7808d66e95788af7993c4b13136487bed14b6e12db2150bca22ab166eef6e0eeb5350b2e2aebdb6f72c36f47ef7dfaef4e3eea2170c396f15f02c
data/CHANGELOG CHANGED
@@ -1,3 +1,35 @@
1
+ === 4.12.0 (2014-07-01)
2
+
3
+ * Support :readonly Database option in sqlite adapter (ippeiukai, jeremyevans) (#832)
4
+
5
+ * Automatically setup max_length validations for string columns in the auto_validations plugin (jeremyevans)
6
+
7
+ * Add :max_length entry to column schema hashes for string types (jeremyevans)
8
+
9
+ * Add :before_thread_exit option to Database#listen_for_static_cache_updates in pg_static_cache_updater extension (jeremyevans)
10
+
11
+ * Add Database#values on PostgreSQL to create a dataset that uses VALUES instead of SELECT (jeremyevans)
12
+
13
+ * Add Model#set_nested_attributes to nested_attributes, allowing setting nested attributes options per-call (jeremyevans)
14
+
15
+ * Use explicit columns when using automatically prepared SELECT statements in the prepared statement plugins (jeremyevans)
16
+
17
+ * Make Dataset#insert_select on PostgreSQL respect existing RETURNING clause (jeremyevans)
18
+
19
+ * Fix eager loading limited associations via a UNION when an association block is used (jeremyevans)
20
+
21
+ * Associate reciprocal object before saving associated object when creating new objects in nested_attributes (chanks, jeremyevans) (#831)
22
+
23
+ * Handle intervals containing more than 100 hours in the pg_interval extension's parser (will) (#827)
24
+
25
+ * Remove methods/class deprecated in 4.11.0 (jeremyevans)
26
+
27
+ * Allow Dataset#natural_join/cross_join and related methods to take a options hash passed to join_table (jeremyevans)
28
+
29
+ * Add :reset_implicit_qualifier option to Dataset#join_table, to set false to not reset the implicit qualifier (jeremyevans)
30
+
31
+ * Support :notice_receiver Database option when postgres adapter is used with pg driver (jeltz, jeremyevans) (#825)
32
+
1
33
  === 4.11.0 (2014-06-03)
2
34
 
3
35
  * Add :model_map option to class_table_inheritance plugin so class names don't need to be stored in the database (jeremyevans)
data/Rakefile CHANGED
@@ -33,10 +33,6 @@ RDOC_DEFAULT_OPTS = ["--line-numbers", "--inline-source", '--title', 'Sequel: Th
33
33
 
34
34
  begin
35
35
  # Sequel uses hanna-nouveau for the website RDoc.
36
- # Due to bugs in older versions of RDoc, and the
37
- # fact that hanna-nouveau does not support RDoc 4,
38
- # a specific version of rdoc is required.
39
- gem 'rdoc', '= 3.12.2'
40
36
  gem 'hanna-nouveau'
41
37
  RDOC_DEFAULT_OPTS.concat(['-f', 'hanna'])
42
38
  rescue Gem::LoadError
@@ -68,7 +64,7 @@ if rdoc_task_class
68
64
  rdoc_task_class.new(:website_rdoc_main) do |rdoc|
69
65
  rdoc.rdoc_dir = "www/public/rdoc"
70
66
  rdoc.options += RDOC_OPTS + %w'--no-ignore-invalid'
71
- rdoc.rdoc_files.add %w"README.rdoc CHANGELOG MIT-LICENSE lib/*.rb lib/sequel/*.rb lib/sequel/{connection_pool,dataset,database,model}/*.rb doc/*.rdoc doc/release_notes/*.txt lib/sequel/extensions/migration.rb lib/sequel/extensions/core_extensions.rb"
67
+ rdoc.rdoc_files.add %w"README.rdoc CHANGELOG MIT-LICENSE lib/*.rb lib/sequel/*.rb lib/sequel/{connection_pool,dataset,database,model}/*.rb doc/*.rdoc doc/release_notes/*.txt lib/sequel/extensions/migration.rb"
72
68
  end
73
69
 
74
70
  rdoc_task_class.new(:website_rdoc_adapters) do |rdoc|
@@ -373,9 +373,12 @@ The following additional options are supported:
373
373
  conversion is done, so an error is raised if you attempt to retrieve an infinite
374
374
  timestamp/date. You can set this to :nil to convert to nil, :string to leave
375
375
  as a string, or :float to convert to an infinite float.
376
- :encoding :: Set the client_encoding to the given string
377
376
  :connect_timeout :: Set the number of seconds to wait for a connection (default 20, only respected
378
377
  if using the pg library).
378
+ :encoding :: Set the client_encoding to the given string
379
+ :notice_receiver :: A proc that be called with the PGresult objects that have notice or warning messages.
380
+ The default notice receiver just prints the messages to stderr, but this can be used
381
+ to handle notice/warning messages differently. Only respected if using the pg library).
379
382
  :sslmode :: Set to 'disable', 'allow', 'prefer', 'require' to choose how to treat SSL (only
380
383
  respected if using the pg library)
381
384
  :use_iso_date_format :: This can be set to false to not force the ISO date format. Sequel forces
@@ -417,6 +420,7 @@ Examples:
417
420
 
418
421
  The following additional options are supported:
419
422
 
423
+ :readonly :: open database in read-only mode
420
424
  :timeout :: the busy timeout to use in milliseconds (default: 5000).
421
425
 
422
426
  === swift
@@ -0,0 +1,105 @@
1
+ = New Features
2
+
3
+ * Database#schema now includes :max_length entries for string
4
+ columns, specifying the size of the string field. The
5
+ auto_validations plugin now uses this information to
6
+ automatically set up max_length validations on those fields.
7
+
8
+ * The Dataset join methods now support a :reset_implicit_qualifier
9
+ option. If set to false, this makes the join not reset the
10
+ implicit qualifier, so that the next join will not consider this
11
+ table as the last table joined. Example:
12
+
13
+ DB[:a].join(:b, :c=>:d).
14
+ join(:e, :f=>:g)
15
+ # SELECT * FROM a
16
+ # INNER JOIN b ON (b.c = a.d)
17
+ # INNER JOIN e ON (e.f = b.g)
18
+
19
+ DB[:a].join(:b, {:c=>:d}, :reset_implicit_qualifier=>false).
20
+ join(:e, :f=>:g)
21
+ # SELECT * FROM a
22
+ # INNER JOIN b ON (b.c = a.d)
23
+ # INNER JOIN e ON (e.f = a.g)
24
+
25
+ * The Dataset cross and natural join methods now accept an options
26
+ hash. Example:
27
+
28
+ DB[:a].cross_join(:b, :table_alias=>:c)
29
+ # SELECT * FROM a CROSS JOIN b AS c
30
+
31
+ * Model#set_nested_attributes has been added to the nested_attributes
32
+ plugin, which allows you to to set the nested_attributes options to
33
+ use per-call. This is very helpful if you have multiple forms that
34
+ handle associated objects, but with different input fields used
35
+ for the associated objects depending on the form. Example:
36
+
37
+ album.set_nested_attributes(:tracks,
38
+ params[:track_attributes],
39
+ :fields=>[:a, :b, :c])
40
+
41
+ * Database#values has been added on PostgreSQL, which creates a
42
+ dataset that uses VALUES instead of SELECT. Just as PostgreSQL
43
+ allows, you can also use orders, limits, and offsets with this
44
+ dataset.
45
+
46
+ * A :notice_receiver option is now supported in the postgres adapter
47
+ if the pg driver is used. This should be a proc, which will be
48
+ passed to the pg connection's set_notice_receiver method.
49
+
50
+ * A Database :readonly option is now supported in the sqlite adapter,
51
+ which opens the database in a read-only mode, causing an error
52
+ if a query is issued that would modify the database.
53
+
54
+ * A :before_thread_exit option has been added to
55
+ Database#listen_for_static_cache_updates in the
56
+ pg_static_cache_updater extension, allowing you to run code before
57
+ the created thread exits.
58
+
59
+ = Other Improvements
60
+
61
+ * Eager loading limited associations using a UNION now works
62
+ correctly when an association block is used. This fixes a
63
+ regression that first occurred in 4.10.0, when the union
64
+ eager loader became the default eager loader.
65
+
66
+ * When creating a new associated object in the nested_attributes
67
+ plugin, where the reciprocal association is a many_to_one
68
+ association, set the cached reciprocal object in the new
69
+ associated object before saving it.
70
+
71
+ This fixes issues when validations in the associated object
72
+ require access to the current object, which may not yet be
73
+ saved in the database.
74
+
75
+ * The prepared_statements and prepared_statements_associations
76
+ plugins now automatically use explicit column references when
77
+ preparing statements. This fixes issues on PostgreSQL when a
78
+ column is added to a table while a prepared statement exists
79
+ that selects * from the table. Previously, all further attempts
80
+ to use the prepared statement will fail.
81
+
82
+ This allows you to run migrations that add columns to tables
83
+ while concurrently running an application that uses the
84
+ prepared statements plugins. Note that many other schema
85
+ modifications can cause issues when running migrations
86
+ while concurrently running an application, but most of those
87
+ are not specific to usage of prepared statements.
88
+
89
+ * Dataset#insert_select on PostgreSQL now respects an existing
90
+ RETURNING clause, and won't override it to use RETURNING *.
91
+
92
+ A similar fix was applied to the generalized prepared statements
93
+ support as well.
94
+
95
+ * The interval parser in the pg_interval extension now supports
96
+ intervals with 2-10 digits for hours. Previously, it only
97
+ supported using 2 digits for hours.
98
+
99
+ = Backwards Compatibility
100
+
101
+ * The methods and classes deprecated in 4.11.0 have been removed.
102
+
103
+ * The nested_attributes internal API has changed significantly. If
104
+ you were calling any private nested_attributes methods, you'll
105
+ probably need to update your code.
@@ -729,6 +729,7 @@ module Sequel
729
729
  metadata(:getColumns, nil, schema, table, nil) do |h|
730
730
  next if schema_parse_table_skip?(h, schema)
731
731
  s = {:type=>schema_column_type(h[:type_name]), :db_type=>h[:type_name], :default=>(h[:column_def] == '' ? nil : h[:column_def]), :allow_null=>(h[:nullable] != 0), :primary_key=>pks.include?(h[:column_name]), :column_size=>h[:column_size], :scale=>h[:decimal_digits]}
732
+ s[:max_length] = s[:column_size] if s[:type] == :string
732
733
  if s[:db_type] =~ DECIMAL_TYPE_RE && s[:scale] == 0
733
734
  s[:type] = :integer
734
735
  end
@@ -305,6 +305,7 @@ module Sequel
305
305
  :allow_null => column.nullable?
306
306
  }
307
307
  h[:type] = oracle_column_type(h)
308
+ h[:max_length] = h[:char_size] if h[:type] == :string
308
309
  table_schema << [m.call(column.name), h]
309
310
  end
310
311
  table_schema
@@ -198,12 +198,13 @@ module Sequel
198
198
  # Connects to the database. In addition to the standard database
199
199
  # options, using the :encoding or :charset option changes the
200
200
  # client encoding for the connection, :connect_timeout is a
201
- # connection timeout in seconds, and :sslmode sets whether postgres's
202
- # sslmode. :connect_timeout and :ssl_mode are only supported if the pg
203
- # driver is used.
201
+ # connection timeout in seconds, :sslmode sets whether postgres's
202
+ # sslmode, and :notice_receiver handles server notices in a proc.
203
+ # :connect_timeout, :ssl_mode, and :notice_receiver are only supported
204
+ # if the pg driver is used.
204
205
  def connect(server)
205
206
  opts = server_opts(server)
206
- conn = if SEQUEL_POSTGRES_USES_PG
207
+ if SEQUEL_POSTGRES_USES_PG
207
208
  connection_params = {
208
209
  :host => opts[:host],
209
210
  :port => opts[:port] || 5432,
@@ -213,9 +214,15 @@ module Sequel
213
214
  :connect_timeout => opts[:connect_timeout] || 20,
214
215
  :sslmode => opts[:sslmode]
215
216
  }.delete_if { |key, value| blank_object?(value) }
216
- Adapter.connect(connection_params)
217
+ conn = Adapter.connect(connection_params)
218
+
219
+ conn.instance_variable_set(:@prepared_statements, {})
220
+
221
+ if receiver = opts[:notice_receiver]
222
+ conn.set_notice_receiver(&receiver)
223
+ end
217
224
  else
218
- Adapter.connect(
225
+ conn = Adapter.connect(
219
226
  (opts[:host] unless blank_object?(opts[:host])),
220
227
  opts[:port] || 5432,
221
228
  nil, '',
@@ -224,6 +231,9 @@ module Sequel
224
231
  opts[:password]
225
232
  )
226
233
  end
234
+
235
+ conn.instance_variable_set(:@db, self)
236
+
227
237
  if encoding = opts[:encoding] || opts[:charset]
228
238
  if conn.respond_to?(:set_client_encoding)
229
239
  conn.set_client_encoding(encoding)
@@ -231,8 +241,7 @@ module Sequel
231
241
  conn.async_exec("set client_encoding to '#{encoding}'")
232
242
  end
233
243
  end
234
- conn.instance_variable_set(:@db, self)
235
- conn.instance_variable_set(:@prepared_statements, {}) if SEQUEL_POSTGRES_USES_PG
244
+
236
245
  connection_configuration_sqls.each{|sql| conn.execute(sql)}
237
246
  conn
238
247
  end
@@ -51,12 +51,13 @@ module Sequel
51
51
  from(:db_attribute).
52
52
  where(:class_name=>m2.call(table_name)).
53
53
  order(:def_order).
54
- select(:attr_name, :data_type___db_type, :default_value___default, :is_nullable___allow_null).
54
+ select(:attr_name, :data_type___db_type, :default_value___default, :is_nullable___allow_null, :prec).
55
55
  map do |row|
56
56
  name = m.call(row.delete(:attr_name))
57
57
  row[:allow_null] = row[:allow_null] == 'YES'
58
58
  row[:primary_key] = pks.include?(name)
59
59
  row[:type] = schema_column_type(row[:db_type])
60
+ row[:max_length] = row[:prec] if row[:type] == :string
60
61
  [name, row]
61
62
  end
62
63
  end
@@ -42,6 +42,7 @@ module Sequel
42
42
  column[:allow_null] = column.delete(:nulls) == 'Y'
43
43
  column[:primary_key] = column.delete(:identity) == 'Y' || !column[:keyseq].nil?
44
44
  column[:type] = schema_column_type(column[:db_type])
45
+ column[:max_length] = column[:longlength] if column[:type] == :string
45
46
  [ m.call(column.delete(:name)), column]
46
47
  end
47
48
  end
@@ -457,6 +457,7 @@ module Sequel
457
457
  else
458
458
  schema_column_type(row[:db_type])
459
459
  end
460
+ row[:max_length] = row[:max_chars] if row[:type] == :string
460
461
  [m.call(row.delete(:column)), row]
461
462
  end
462
463
  end
@@ -524,6 +524,17 @@ module Sequel
524
524
  @supported_types.fetch(type){@supported_types[type] = (from(:pg_type).filter(:typtype=>'b', :typname=>type.to_s).count > 0)}
525
525
  end
526
526
 
527
+ # Creates a dataset that uses the VALUES clause:
528
+ #
529
+ # DB.values([[1, 2], [3, 4]])
530
+ # VALUES ((1, 2), (3, 4))
531
+ #
532
+ # DB.values([[1, 2], [3, 4]]).order(:column2).limit(1, 1)
533
+ # VALUES ((1, 2), (3, 4)) ORDER BY column2 LIMIT 1 OFFSET 1
534
+ def values(v)
535
+ @default_dataset.clone(:values=>v)
536
+ end
537
+
527
538
  # Array of symbols specifying view names in the current database.
528
539
  #
529
540
  # Options:
@@ -1147,12 +1158,13 @@ module Sequel
1147
1158
  CRLF = "\r\n".freeze
1148
1159
  BLOB_RE = /[\000-\037\047\134\177-\377]/n.freeze
1149
1160
  WINDOW = " WINDOW ".freeze
1161
+ SELECT_VALUES = "VALUES ".freeze
1150
1162
  EMPTY_STRING = ''.freeze
1151
1163
  LOCK_MODES = ['ACCESS SHARE', 'ROW SHARE', 'ROW EXCLUSIVE', 'SHARE UPDATE EXCLUSIVE', 'SHARE', 'SHARE ROW EXCLUSIVE', 'EXCLUSIVE', 'ACCESS EXCLUSIVE'].each{|s| s.freeze}
1152
1164
 
1153
1165
  Dataset.def_sql_method(self, :delete, [['if server_version >= 90100', %w'with delete from using where returning'], ['else', %w'delete from using where returning']])
1154
1166
  Dataset.def_sql_method(self, :insert, [['if server_version >= 90100', %w'with insert into columns values returning'], ['else', %w'insert into columns values returning']])
1155
- 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']])
1167
+ Dataset.def_sql_method(self, :select, [['if opts[:values]', %w'values order limit'], ['elsif 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']])
1156
1168
  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']])
1157
1169
 
1158
1170
  # Shared methods for prepared statements when used with PostgreSQL databases.
@@ -1285,7 +1297,10 @@ module Sequel
1285
1297
  # Insert a record returning the record inserted. Always returns nil without
1286
1298
  # inserting a query if disable_insert_returning is used.
1287
1299
  def insert_select(*values)
1288
- returning.insert(*values){|r| return r} unless @opts[:disable_insert_returning]
1300
+ unless @opts[:disable_insert_returning]
1301
+ ds = opts[:returning] ? self : returning
1302
+ ds.insert(*values){|r| return r}
1303
+ end
1289
1304
  end
1290
1305
 
1291
1306
  # Locks all tables in the dataset's FROM clause (but not in JOINs) with
@@ -1510,6 +1525,12 @@ module Sequel
1510
1525
  @opts[:lock] == :share ? (sql << FOR_SHARE) : super
1511
1526
  end
1512
1527
 
1528
+ # Support VALUES clause instead of the SELECT clause to return rows.
1529
+ def select_values_sql(sql)
1530
+ sql << SELECT_VALUES
1531
+ expression_list_append(sql, opts[:values])
1532
+ end
1533
+
1513
1534
  # SQL fragment for named window specifications
1514
1535
  def select_window_sql(sql)
1515
1536
  if ws = @opts[:window]
@@ -66,6 +66,7 @@ module Sequel
66
66
  else
67
67
  schema_column_type(row[:db_type])
68
68
  end
69
+ row[:max_length] = row[:width] if row[:type] == :string
69
70
  [m.call(row.delete(:name)), row]
70
71
  end
71
72
  end
@@ -91,14 +91,20 @@ module Sequel
91
91
  # The conversion procs to use for this database
92
92
  attr_reader :conversion_procs
93
93
 
94
- # Connect to the database. Since SQLite is a file based database,
95
- # the only options available are :database (to specify the database
96
- # name), and :timeout, to specify how long to wait for the database to
97
- # be available if it is locked, given in milliseconds (default is 5000).
94
+ # Connect to the database. Since SQLite is a file based database,
95
+ # available options are limited:
96
+ #
97
+ # :database :: database name (filename or ':memory:' or file: URI)
98
+ # :readonly :: open database in read-only mode; useful for reading
99
+ # static data that you do not want to modify
100
+ # :timeout :: how long to wait for the database to be available if it
101
+ # is locked, given in milliseconds (default is 5000)
98
102
  def connect(server)
99
103
  opts = server_opts(server)
100
104
  opts[:database] = ':memory:' if blank_object?(opts[:database])
101
- db = ::SQLite3::Database.new(opts[:database])
105
+ sqlite3_opts = {}
106
+ sqlite3_opts[:readonly] = typecast_value_boolean(opts[:readonly]) if opts.has_key?(:readonly)
107
+ db = ::SQLite3::Database.new(opts[:database].to_s, sqlite3_opts)
102
108
  db.busy_timeout(opts.fetch(:timeout, 5000))
103
109
 
104
110
  connection_pragmas.each{|s| log_yield(s){db.execute_batch(s)}}
@@ -157,7 +157,12 @@ module Sequel
157
157
 
158
158
  cols = schema_parse_table(table_name, opts)
159
159
  raise(Error, 'schema parsing returned no columns, table probably doesn\'t exist') if cols.nil? || cols.empty?
160
- cols.each{|_,c| c[:ruby_default] = column_schema_to_ruby_default(c[:default], c[:type])}
160
+ cols.each do |_,c|
161
+ c[:ruby_default] = column_schema_to_ruby_default(c[:default], c[:type])
162
+ if !c[:max_length] && c[:type] == :string && (max_length = column_schema_max_length(c[:db_type]))
163
+ c[:max_length] = max_length
164
+ end
165
+ end
161
166
  Sequel.synchronize{@schemas[quoted_name] = cols} if cache_schema
162
167
  cols
163
168
  end
@@ -251,6 +256,14 @@ module Sequel
251
256
  column_schema_default_to_ruby_value(default, type) rescue nil
252
257
  end
253
258
 
259
+ # Look at the db_type and guess the maximum length of the column.
260
+ # This assumes types such as varchar(255).
261
+ def column_schema_max_length(db_type)
262
+ if db_type =~ /\((\d+)\)/
263
+ $1.to_i
264
+ end
265
+ end
266
+
254
267
  # Return a Method object for the dataset's output_identifier_method.
255
268
  # Used in metadata parsing to make sure the returned information is in the
256
269
  # correct format.
@@ -86,7 +86,8 @@ module Sequel
86
86
  when :first
87
87
  clone(:limit=>1).select_sql
88
88
  when :insert_select
89
- returning.insert_sql(*@prepared_modify_values)
89
+ ds = opts[:returning] ? self : returning
90
+ ds.insert_sql(*@prepared_modify_values)
90
91
  when :insert
91
92
  insert_sql(*@prepared_modify_values)
92
93
  when :update
@@ -23,10 +23,9 @@ module Sequel
23
23
  # block from the method call.
24
24
  CONDITIONED_JOIN_TYPES = [:inner, :full_outer, :right_outer, :left_outer, :full, :right, :left]
25
25
 
26
- # These symbols have _join methods created (e.g. natural_join) that
27
- # call join_table with the symbol. They only accept a single table
28
- # argument which is passed to join_table, and they raise an error
29
- # if called with a block.
26
+ # These symbols have _join methods created (e.g. natural_join).
27
+ # They accept a table argument and options hash which is passed to join_table,
28
+ # and they raise an error if called with a block.
30
29
  UNCONDITIONED_JOIN_TYPES = [:natural, :natural_left, :natural_right, :natural_full, :cross]
31
30
 
32
31
  # All methods that return modified datasets with a joined table added.
@@ -387,37 +386,42 @@ module Sequel
387
386
  #
388
387
  # Takes the following arguments:
389
388
  #
390
- # * type - The type of join to do (e.g. :inner)
391
- # * table - Depends on type:
392
- # * Dataset - a subselect is performed with an alias of tN for some value of N
393
- # * String, Symbol: table
394
- # * expr - specifies conditions, depends on type:
395
- # * Hash, Array of two element arrays - Assumes key (1st arg) is column of joined table (unless already
396
- # qualified), and value (2nd arg) is column of the last joined or primary table (or the
397
- # :implicit_qualifier option).
398
- # To specify multiple conditions on a single joined table column, you must use an array.
399
- # Uses a JOIN with an ON clause.
400
- # * Array - If all members of the array are symbols, considers them as columns and
401
- # uses a JOIN with a USING clause. Most databases will remove duplicate columns from
402
- # the result set if this is used.
403
- # * nil - If a block is not given, doesn't use ON or USING, so the JOIN should be a NATURAL
404
- # or CROSS join. If a block is given, uses an ON clause based on the block, see below.
405
- # * Everything else - pretty much the same as a using the argument in a call to where,
406
- # so strings are considered literal, symbols specify boolean columns, and Sequel
407
- # expressions can be used. Uses a JOIN with an ON clause.
408
- # * options - a hash of options, with any of the following keys:
409
- # * :table_alias - the name of the table's alias when joining, necessary for joining
410
- # to the same table more than once. No alias is used by default.
411
- # * :implicit_qualifier - The name to use for qualifying implicit conditions. By default,
412
- # the last joined or primary table is used.
413
- # * :qualify - Can be set to false to not do any implicit qualification. Can be set
414
- # to :deep to use the Qualifier AST Transformer, which will attempt to qualify
415
- # subexpressions of the expression tree. Can be set to :symbol to only qualify
416
- # symbols. Defaults to the value of default_join_table_qualification.
417
- # * block - The block argument should only be given if a JOIN with an ON clause is used,
418
- # in which case it yields the table alias/name for the table currently being joined,
419
- # the table alias/name for the last joined (or first table), and an array of previous
420
- # SQL::JoinClause. Unlike +where+, this block is not treated as a virtual row block.
389
+ # type :: The type of join to do (e.g. :inner)
390
+ # table :: table to join into the current dataset. Generally one of the following types:
391
+ # String, Symbol :: identifier used as table or view name
392
+ # Dataset :: a subselect is performed with an alias of tN for some value of N
393
+ # SQL::Function :: set returning function
394
+ # SQL::AliasedExpression :: already aliased expression. Uses given alias unless
395
+ # overridden by the :table_alias option.
396
+ # expr :: conditions used when joining, depends on type:
397
+ # Hash, Array of pairs :: Assumes key (1st arg) is column of joined table (unless already
398
+ # qualified), and value (2nd arg) is column of the last joined or
399
+ # primary table (or the :implicit_qualifier option).
400
+ # To specify multiple conditions on a single joined table column,
401
+ # you must use an array. Uses a JOIN with an ON clause.
402
+ # Array :: If all members of the array are symbols, considers them as columns and
403
+ # uses a JOIN with a USING clause. Most databases will remove duplicate columns from
404
+ # the result set if this is used.
405
+ # nil :: If a block is not given, doesn't use ON or USING, so the JOIN should be a NATURAL
406
+ # or CROSS join. If a block is given, uses an ON clause based on the block, see below.
407
+ # otherwise :: Treats the argument as a filter expression, so strings are considered literal, symbols
408
+ # specify boolean columns, and Sequel expressions can be used. Uses a JOIN with an ON clause.
409
+ # options :: a hash of options, with the following keys supported:
410
+ # :table_alias :: Override the table alias used when joining. In general you shouldn't use this
411
+ # option, you should provide the appropriate SQL::AliasedExpression as the table
412
+ # argument.
413
+ # :implicit_qualifier :: The name to use for qualifying implicit conditions. By default,
414
+ # the last joined or primary table is used.
415
+ # :reset_implicit_qualifier :: Can set to false to ignore this join when future joins determine qualifier
416
+ # for implicit conditions.
417
+ # :qualify :: Can be set to false to not do any implicit qualification. Can be set
418
+ # to :deep to use the Qualifier AST Transformer, which will attempt to qualify
419
+ # subexpressions of the expression tree. Can be set to :symbol to only qualify
420
+ # symbols. Defaults to the value of default_join_table_qualification.
421
+ # block :: The block argument should only be given if a JOIN with an ON clause is used,
422
+ # in which case it yields the table alias/name for the table currently being joined,
423
+ # the table alias/name for the last joined (or first table), and an array of previous
424
+ # SQL::JoinClause. Unlike +where+, this block is not treated as a virtual row block.
421
425
  #
422
426
  # Examples:
423
427
  #
@@ -505,7 +509,8 @@ module Sequel
505
509
  SQL::JoinOnClause.new(expr, type, table_expr)
506
510
  end
507
511
 
508
- opts = {:join => (@opts[:join] || []) + [join], :last_joined_table => table_name}
512
+ opts = {:join => (@opts[:join] || []) + [join]}
513
+ opts[:last_joined_table] = table_name unless options[:reset_implicit_qualifier] == false
509
514
  opts[:num_dataset_sources] = table_alias_num if table_alias_num
510
515
  clone(opts)
511
516
  end
@@ -514,7 +519,13 @@ module Sequel
514
519
  class_eval("def #{jtype}_join(*args, &block); join_table(:#{jtype}, *args, &block) end", __FILE__, __LINE__)
515
520
  end
516
521
  UNCONDITIONED_JOIN_TYPES.each do |jtype|
517
- class_eval("def #{jtype}_join(table); raise(Sequel::Error, '#{jtype}_join does not accept join table blocks') if block_given?; join_table(:#{jtype}, table) end", __FILE__, __LINE__)
522
+ class_eval(<<-END, __FILE__, __LINE__+1)
523
+ def #{jtype}_join(table, opts=Sequel::OPTS)
524
+ raise(Sequel::Error, '#{jtype}_join does not accept join table blocks') if block_given?
525
+ raise(Sequel::Error, '#{jtype}_join 2nd argument should be an options hash, not conditions') unless opts.is_a?(Hash)
526
+ join_table(:#{jtype}, table, nil, opts)
527
+ end
528
+ END
518
529
  end
519
530
 
520
531
  # Marks this dataset as a lateral dataset. If used in another dataset's FROM