sequel 4.13.0 → 4.14.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (117) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +24 -0
  3. data/doc/active_record.rdoc +4 -4
  4. data/doc/advanced_associations.rdoc +2 -2
  5. data/doc/association_basics.rdoc +11 -11
  6. data/doc/cheat_sheet.rdoc +7 -7
  7. data/doc/core_extensions.rdoc +1 -1
  8. data/doc/dataset_filtering.rdoc +1 -1
  9. data/doc/extensions.rdoc +1 -1
  10. data/doc/migration.rdoc +3 -3
  11. data/doc/model_hooks.rdoc +1 -1
  12. data/doc/opening_databases.rdoc +4 -0
  13. data/doc/postgresql.rdoc +2 -2
  14. data/doc/prepared_statements.rdoc +1 -1
  15. data/doc/querying.rdoc +31 -31
  16. data/doc/release_notes/4.13.0.txt +1 -1
  17. data/doc/release_notes/4.14.0.txt +68 -0
  18. data/doc/schema_modification.rdoc +1 -1
  19. data/doc/sharding.rdoc +2 -2
  20. data/doc/sql.rdoc +1 -1
  21. data/doc/virtual_rows.rdoc +2 -2
  22. data/lib/sequel/adapters/jdbc/jtds.rb +4 -0
  23. data/lib/sequel/adapters/mysql.rb +18 -18
  24. data/lib/sequel/adapters/mysql2.rb +7 -7
  25. data/lib/sequel/adapters/shared/mysql.rb +15 -5
  26. data/lib/sequel/adapters/shared/postgres.rb +71 -58
  27. data/lib/sequel/adapters/shared/sqlite.rb +2 -2
  28. data/lib/sequel/ast_transformer.rb +1 -1
  29. data/lib/sequel/connection_pool/sharded_single.rb +8 -8
  30. data/lib/sequel/connection_pool/sharded_threaded.rb +8 -8
  31. data/lib/sequel/database/connecting.rb +1 -1
  32. data/lib/sequel/database/schema_generator.rb +12 -0
  33. data/lib/sequel/database/schema_methods.rb +8 -7
  34. data/lib/sequel/database/transactions.rb +1 -2
  35. data/lib/sequel/dataset/actions.rb +4 -4
  36. data/lib/sequel/dataset/graph.rb +4 -0
  37. data/lib/sequel/dataset/query.rb +18 -18
  38. data/lib/sequel/dataset/sql.rb +3 -3
  39. data/lib/sequel/extensions/_pretty_table.rb +1 -0
  40. data/lib/sequel/extensions/arbitrary_servers.rb +3 -2
  41. data/lib/sequel/extensions/columns_introspection.rb +1 -0
  42. data/lib/sequel/extensions/connection_validator.rb +1 -0
  43. data/lib/sequel/extensions/constraint_validations.rb +1 -0
  44. data/lib/sequel/extensions/current_datetime_timestamp.rb +1 -0
  45. data/lib/sequel/extensions/dataset_source_alias.rb +1 -0
  46. data/lib/sequel/extensions/date_arithmetic.rb +1 -0
  47. data/lib/sequel/extensions/empty_array_ignore_nulls.rb +1 -0
  48. data/lib/sequel/extensions/error_sql.rb +1 -0
  49. data/lib/sequel/extensions/eval_inspect.rb +1 -0
  50. data/lib/sequel/extensions/filter_having.rb +1 -0
  51. data/lib/sequel/extensions/from_block.rb +1 -0
  52. data/lib/sequel/extensions/graph_each.rb +1 -0
  53. data/lib/sequel/extensions/hash_aliases.rb +1 -0
  54. data/lib/sequel/extensions/looser_typecasting.rb +1 -0
  55. data/lib/sequel/extensions/meta_def.rb +1 -0
  56. data/lib/sequel/extensions/migration.rb +1 -0
  57. data/lib/sequel/extensions/mssql_emulate_lateral_with_apply.rb +1 -0
  58. data/lib/sequel/extensions/named_timezones.rb +1 -0
  59. data/lib/sequel/extensions/null_dataset.rb +1 -0
  60. data/lib/sequel/extensions/pagination.rb +1 -0
  61. data/lib/sequel/extensions/pg_array.rb +2 -2
  62. data/lib/sequel/extensions/pg_array_ops.rb +1 -0
  63. data/lib/sequel/extensions/pg_enum.rb +1 -0
  64. data/lib/sequel/extensions/pg_hstore_ops.rb +1 -0
  65. data/lib/sequel/extensions/pg_json_ops.rb +1 -0
  66. data/lib/sequel/extensions/pg_loose_count.rb +1 -0
  67. data/lib/sequel/extensions/pg_range_ops.rb +1 -0
  68. data/lib/sequel/extensions/pg_row_ops.rb +1 -0
  69. data/lib/sequel/extensions/pg_static_cache_updater.rb +1 -0
  70. data/lib/sequel/extensions/pretty_table.rb +1 -0
  71. data/lib/sequel/extensions/query.rb +1 -0
  72. data/lib/sequel/extensions/query_literals.rb +1 -0
  73. data/lib/sequel/extensions/schema_caching.rb +1 -0
  74. data/lib/sequel/extensions/schema_dumper.rb +1 -1
  75. data/lib/sequel/extensions/select_remove.rb +1 -0
  76. data/lib/sequel/extensions/sequel_3_dataset_methods.rb +1 -0
  77. data/lib/sequel/extensions/server_block.rb +1 -0
  78. data/lib/sequel/extensions/set_overrides.rb +1 -0
  79. data/lib/sequel/extensions/split_array_nil.rb +1 -0
  80. data/lib/sequel/extensions/thread_local_timezones.rb +1 -0
  81. data/lib/sequel/extensions/to_dot.rb +1 -0
  82. data/lib/sequel/model/associations.rb +5 -5
  83. data/lib/sequel/model/base.rb +3 -3
  84. data/lib/sequel/plugins/association_proxies.rb +1 -1
  85. data/lib/sequel/plugins/caching.rb +8 -3
  86. data/lib/sequel/plugins/class_table_inheritance.rb +20 -11
  87. data/lib/sequel/plugins/composition.rb +18 -18
  88. data/lib/sequel/plugins/json_serializer.rb +3 -3
  89. data/lib/sequel/plugins/lazy_attributes.rb +23 -9
  90. data/lib/sequel/plugins/many_through_many.rb +21 -21
  91. data/lib/sequel/plugins/nested_attributes.rb +7 -3
  92. data/lib/sequel/plugins/pg_row.rb +1 -1
  93. data/lib/sequel/plugins/rcte_tree.rb +13 -13
  94. data/lib/sequel/plugins/sharding.rb +6 -6
  95. data/lib/sequel/plugins/timestamps.rb +4 -4
  96. data/lib/sequel/plugins/touch.rb +7 -7
  97. data/lib/sequel/plugins/tree.rb +1 -1
  98. data/lib/sequel/plugins/validation_class_methods.rb +36 -36
  99. data/lib/sequel/plugins/validation_helpers.rb +3 -4
  100. data/lib/sequel/plugins/xml_serializer.rb +29 -29
  101. data/lib/sequel/sql.rb +22 -11
  102. data/lib/sequel/version.rb +1 -1
  103. data/spec/adapters/postgres_spec.rb +10 -0
  104. data/spec/core/database_spec.rb +3 -4
  105. data/spec/core/dataset_spec.rb +16 -1
  106. data/spec/core/expression_filters_spec.rb +12 -0
  107. data/spec/core/object_graph_spec.rb +5 -0
  108. data/spec/core/placeholder_literalizer_spec.rb +8 -0
  109. data/spec/extensions/caching_spec.rb +18 -0
  110. data/spec/extensions/class_table_inheritance_spec.rb +34 -0
  111. data/spec/extensions/many_through_many_spec.rb +4 -0
  112. data/spec/extensions/nested_attributes_spec.rb +59 -4
  113. data/spec/extensions/pg_array_associations_spec.rb +5 -0
  114. data/spec/extensions/single_table_inheritance_spec.rb +23 -1
  115. data/spec/integration/plugin_test.rb +17 -0
  116. data/spec/model/eager_loading_spec.rb +8 -0
  117. metadata +4 -2
@@ -96,7 +96,7 @@
96
96
  returning the unqualified version of a possibly qualified column.
97
97
 
98
98
  * The composition and serialization plugins now support validations
99
- on the underlying columns. Previously, the didn't update the
99
+ on the underlying columns. Previously, they didn't update the
100
100
  underlying columns until after validations were performed. This
101
101
  works better when using the auto_validations plugin.
102
102
 
@@ -0,0 +1,68 @@
1
+ = New Features
2
+
3
+ * Delayed evaluation blocks can now accept the dataset literalizing
4
+ the delayed evaluation as an argument. This makes it so the
5
+ delayed evaluation result can depend on the dataset doing the
6
+ literalization:
7
+
8
+ ds = DB[:a].where(Sequel.delay do |ds|
9
+ {Sequel.qualify(ds.first_source, :col)=>1}
10
+ end)
11
+ ds.sql # SELECT * FROM a WHERE (a.col = 1)
12
+ ds.from(:b).sql # SELECT * FROM b WHERE (b.col = 1)
13
+
14
+ * Database#create_trigger on PostgreSQL now supports a :when option
15
+ to create a filter for the trigger, so that it is only triggered
16
+ when the filter condition is true.
17
+
18
+ * You can now override the cache key prefix in the caching plugin
19
+ by overriding the cache_key_prefix class method. This can be
20
+ useful when using a table inheritance plugin.
21
+
22
+ = Other Improvements
23
+
24
+ * You can now pass arbitrary types to Dataset#where and related
25
+ methods. Previously, if a type was not explicitly handled, an
26
+ exception would be raised. Now you can pass any object that can
27
+ be literalized. The only exception is that you can't pass
28
+ Numeric objects, since #where and similar methods should
29
+ only deal with boolean expressions.
30
+
31
+ * association_join and related methods now work correctly if the
32
+ dataset already has an explicit selection.
33
+
34
+ * A regression has been fixed in the class_table_inheritance plugin
35
+ when using a hierarchy of more than 2 levels, when using the
36
+ superclass to load a subclass instance more than 2 levels below,
37
+ and later attempting to load a column contained in one of the
38
+ middle tables.
39
+
40
+ * When using _delete or _remove keys in the nested_attributes plugin
41
+ to remove existing associated objects, the associated objects are
42
+ now deleted from the cached association array at time of call.
43
+ This is for consistency when adding new associated objects, where
44
+ the new associated objects are added to the cached association
45
+ array at time of call.
46
+
47
+ * The nested_attributes plugin now handles composite primary keys
48
+ correctly when working around validation issues for one_to_one
49
+ and one_to_many associations.
50
+
51
+ * If exception A is raised during a transaction, and exception B
52
+ is raised while attempting to rollback the transaction, the
53
+ transaction code will now raise exception A instead of exception B.
54
+
55
+ * An additional serialization failure is now detected on PostgreSQL.
56
+
57
+ * An additional disconnect error is now recognized in the jdbc/jtds
58
+ adapter.
59
+
60
+ * The code examples in the RDoc are now syntax highlighted, and
61
+ many minor fixes to the code examples in the RDoc were made.
62
+ Additionally, many other improvements were made to the RDoc.
63
+
64
+ = Backwards Compatibility
65
+
66
+ * Dataset#delayed_evaluation_sql_append now accepts the delayed
67
+ evaluation as an argument, instead of the callable contained by the
68
+ delayed evaluation.
@@ -32,7 +32,7 @@ convert to database types:
32
32
  String :a3, :fixed=>true # char(255)
33
33
  String :a4, :fixed=>true, :size=>50 # char(50)
34
34
  String :a5, :text=>true # text
35
- File :b, # blob
35
+ File :b # blob
36
36
  Fixnum :c # integer
37
37
  Bignum :d # bigint
38
38
  Float :e # double precision
data/doc/sharding.rdoc CHANGED
@@ -134,12 +134,12 @@ to assume the :default shard. However, you can specify a
134
134
  different shard using the :servers_hash option when connecting
135
135
  to the database:
136
136
 
137
- DB = Sequel.connect(..., :servers_hash=>Hash.new(:some_shard))
137
+ DB = Sequel.connect('postgres://...', :servers_hash=>Hash.new(:some_shard))
138
138
 
139
139
  You can also use this feature to raise an exception if an
140
140
  unconfigured shard is used:
141
141
 
142
- DB = Sequel.connect(..., :servers_hash=>Hash.new{raise ...})
142
+ DB = Sequel.connect('postgres://...', :servers_hash=>Hash.new{raise 'foo'})
143
143
 
144
144
  If you specify a :servers_hash option to raise an exception for non configured
145
145
  shards you should also explicitly specify a :read_only entry in your :servers option
data/doc/sql.rdoc CHANGED
@@ -506,7 +506,7 @@ To select all columns in a table, Sequel supports the * method on identifiers wi
506
506
 
507
507
  Sequel allows the easy production of SQL CASE statements using the <tt>Sequel.case</tt> method. The first argument is a hash or array of two element arrays representing the conditions, the second argument is the default value (ELSE). The keys of the hash (or first element in each array) is the WHEN condition, and the values of the hash (or second element in each array) is the THEN result. Here are some examples:
508
508
 
509
- Sequel.case({:column=>1, 0) # (CASE WHEN "column" THEN 1 ELSE 0 END)
509
+ Sequel.case({:column=>1}, 0) # (CASE WHEN "column" THEN 1 ELSE 0 END)
510
510
  Sequel.case([[column, 1]], 0) # (CASE WHEN "column" THEN 1 ELSE 0 END)
511
511
  Sequel.case({{:column=>nil}=>1}, 0) # (CASE WHEN (column IS NULL) THEN 1 ELSE 0 END)
512
512
 
@@ -157,7 +157,7 @@ function without arguments, then call the * method on the function:
157
157
  To append the DISTINCT keyword before the method arguments, just call the
158
158
  distinct method on the returned Function:
159
159
 
160
- ds.select{|o| o.count(o.col1).distinct)}
160
+ ds.select{|o| o.count(o.col1).distinct}
161
161
  ds.select{count(col1).distinct}
162
162
  # SELECT count(DISTINCT col1)
163
163
 
@@ -230,7 +230,7 @@ virtual row block to create a literal string:
230
230
  You can use this on a regular virtual row block too, but it
231
231
  doesn't look as nice:
232
232
 
233
- ds.where{|o| o.>(:a, o.`('some SQL')}
233
+ ds.where{|o| o.>(:a, o.`('some SQL'))}
234
234
 
235
235
  == Returning multiple values
236
236
 
@@ -26,6 +26,10 @@ module Sequel
26
26
  false
27
27
  end
28
28
 
29
+ def disconnect_error?(exception, opts)
30
+ super || exception.message =~ /\AInvalid state, the Connection object is closed\.\z/
31
+ end
32
+
29
33
  # Handle nil values by using setNull with the correct parameter type.
30
34
  def set_ps_arg_nil(cps, i)
31
35
  cps.setNull(i, cps.getParameterMetaData.getParameterType(i))
@@ -62,24 +62,24 @@ module Sequel
62
62
  # Connect to the database. In addition to the usual database options,
63
63
  # the following options have effect:
64
64
  #
65
- # * :auto_is_null - Set to true to use MySQL default behavior of having
66
- # a filter for an autoincrement column equals NULL to return the last
67
- # inserted row.
68
- # * :charset - Same as :encoding (:encoding takes precendence)
69
- # * :compress - Set to false to not compress results from the server
70
- # * :config_default_group - The default group to read from the in
71
- # the MySQL config file.
72
- # * :config_local_infile - If provided, sets the Mysql::OPT_LOCAL_INFILE
73
- # option on the connection with the given value.
74
- # * :connect_timeout - Set the timeout in seconds before a connection
75
- # attempt is abandoned.
76
- # * :encoding - Set all the related character sets for this
77
- # connection (connection, client, database, server, and results).
78
- # * :read_timeout - Set the timeout in seconds for reading back results
79
- # to a query.
80
- # * :socket - Use a unix socket file instead of connecting via TCP/IP.
81
- # * :timeout - Set the timeout in seconds before the server will
82
- # disconnect this connection (a.k.a @@wait_timeout).
65
+ # :auto_is_null :: Set to true to use MySQL default behavior of having
66
+ # a filter for an autoincrement column equals NULL to return the last
67
+ # inserted row.
68
+ # :charset :: Same as :encoding (:encoding takes precendence)
69
+ # :compress :: Set to false to not compress results from the server
70
+ # :config_default_group :: The default group to read from the in
71
+ # the MySQL config file.
72
+ # :config_local_infile :: If provided, sets the Mysql::OPT_LOCAL_INFILE
73
+ # option on the connection with the given value.
74
+ # :connect_timeout :: Set the timeout in seconds before a connection
75
+ # attempt is abandoned.
76
+ # :encoding :: Set all the related character sets for this
77
+ # connection (connection, client, database, server, and results).
78
+ # :read_timeout :: Set the timeout in seconds for reading back results
79
+ # to a query.
80
+ # :socket :: Use a unix socket file instead of connecting via TCP/IP.
81
+ # :timeout :: Set the timeout in seconds before the server will
82
+ # disconnect this connection (a.k.a @@wait_timeout).
83
83
  def connect(server)
84
84
  opts = server_opts(server)
85
85
  conn = Mysql.init
@@ -17,12 +17,12 @@ module Sequel
17
17
  # Connect to the database. In addition to the usual database options,
18
18
  # the following options have effect:
19
19
  #
20
- # * :auto_is_null - Set to true to use MySQL default behavior of having
21
- # a filter for an autoincrement column equals NULL to return the last
22
- # inserted row.
23
- # * :charset - Same as :encoding (:encoding takes precendence)
24
- # * :encoding - Set all the related character sets for this
25
- # connection (connection, client, database, server, and results).
20
+ # :auto_is_null :: Set to true to use MySQL default behavior of having
21
+ # a filter for an autoincrement column equals NULL to return the last
22
+ # inserted row.
23
+ # :charset :: Same as :encoding (:encoding takes precendence)
24
+ # :encoding :: Set all the related character sets for this
25
+ # connection (connection, client, database, server, and results).
26
26
  #
27
27
  # The options hash is also passed to mysql2, and can include mysql2
28
28
  # options such as :local_infile.
@@ -61,7 +61,7 @@ module Sequel
61
61
  execute(sql, opts){|c| return c.last_id}
62
62
  end
63
63
 
64
- # Return the version of the MySQL server two which we are connecting.
64
+ # Return the version of the MySQL server to which we are connecting.
65
65
  def server_version(server=nil)
66
66
  @server_version ||= (synchronize(server){|conn| conn.server_info[:id]} || super)
67
67
  end
@@ -161,7 +161,7 @@ module Sequel
161
161
  # Return an array of symbols specifying table names in the current database.
162
162
  #
163
163
  # Options:
164
- # * :server - Set the server to use
164
+ # :server :: Set the server to use
165
165
  def tables(opts=OPTS)
166
166
  full_tables('BASE TABLE', opts)
167
167
  end
@@ -178,7 +178,7 @@ module Sequel
178
178
  # Return an array of symbols specifying view names in the current database.
179
179
  #
180
180
  # Options:
181
- # * :server - Set the server to use
181
+ # :server :: Set the server to use
182
182
  def views(opts=OPTS)
183
183
  full_tables('VIEW', opts)
184
184
  end
@@ -363,8 +363,8 @@ module Sequel
363
363
  end
364
364
 
365
365
  # Split column constraints into table constraints in some cases:
366
- # * foreign key - Always
367
- # * unique, primary_key - Only if constraint has a name
366
+ # foreign key - Always
367
+ # unique, primary_key - Only if constraint has a name
368
368
  generator.columns.each do |c|
369
369
  if t = c.delete(:table)
370
370
  same_table = t == name
@@ -733,7 +733,9 @@ module Sequel
733
733
  # Sets up the insert methods to use ON DUPLICATE KEY UPDATE
734
734
  # If you pass no arguments, ALL fields will be
735
735
  # updated with the new values. If you pass the fields you
736
- # want then ONLY those field will be updated.
736
+ # want then ONLY those field will be updated. If you pass a
737
+ # hash you can customize the values (for example, to increment
738
+ # a numeric field).
737
739
  #
738
740
  # Useful if you have a unique key and want to update
739
741
  # inserting rows that violate the unique key restriction.
@@ -749,6 +751,14 @@ module Sequel
749
751
  # )
750
752
  # # INSERT INTO tablename (name, value) VALUES (a, 1), (b, 2)
751
753
  # # ON DUPLICATE KEY UPDATE value=VALUES(value)
754
+ #
755
+ # dataset.on_duplicate_key_update(
756
+ # :value => Sequel.lit('value + VALUES(value)')
757
+ # ).multi_insert(
758
+ # [{:name => 'a', :value => 1}, {:name => 'b', :value => 2}]
759
+ # )
760
+ # # INSERT INTO tablename (name, value) VALUES (a, 1), (b, 2)
761
+ # # ON DUPLICATE KEY UPDATE value=value + VALUES(value)
752
762
  def on_duplicate_key_update(*args)
753
763
  clone(:on_duplicate_key_update => args)
754
764
  end
@@ -161,59 +161,60 @@ module Sequel
161
161
  end
162
162
 
163
163
  # Creates the function in the database. Arguments:
164
- # * name : name of the function to create
165
- # * definition : string definition of the function, or object file for a dynamically loaded C function.
166
- # * opts : options hash:
167
- # * :args : function arguments, can be either a symbol or string specifying a type or an array of 1-3 elements:
168
- # * element 1 : argument data type
169
- # * element 2 : argument name
170
- # * element 3 : argument mode (e.g. in, out, inout)
171
- # * :behavior : Should be IMMUTABLE, STABLE, or VOLATILE. PostgreSQL assumes VOLATILE by default.
172
- # * :cost : The estimated cost of the function, used by the query planner.
173
- # * :language : The language the function uses. SQL is the default.
174
- # * :link_symbol : For a dynamically loaded see function, the function's link symbol if different from the definition argument.
175
- # * :returns : The data type returned by the function. If you are using OUT or INOUT argument modes, this is ignored.
176
- # Otherwise, if this is not specified, void is used by default to specify the function is not supposed to return a value.
177
- # * :rows : The estimated number of rows the function will return. Only use if the function returns SETOF something.
178
- # * :security_definer : Makes the privileges of the function the same as the privileges of the user who defined the function instead of
179
- # the privileges of the user who runs the function. There are security implications when doing this, see the PostgreSQL documentation.
180
- # * :set : Configuration variables to set while the function is being run, can be a hash or an array of two pairs. search_path is
181
- # often used here if :security_definer is used.
182
- # * :strict : Makes the function return NULL when any argument is NULL.
164
+ # name :: name of the function to create
165
+ # definition :: string definition of the function, or object file for a dynamically loaded C function.
166
+ # opts :: options hash:
167
+ # :args :: function arguments, can be either a symbol or string specifying a type or an array of 1-3 elements:
168
+ # 1 :: argument data type
169
+ # 2 :: argument name
170
+ # 3 :: argument mode (e.g. in, out, inout)
171
+ # :behavior :: Should be IMMUTABLE, STABLE, or VOLATILE. PostgreSQL assumes VOLATILE by default.
172
+ # :cost :: The estimated cost of the function, used by the query planner.
173
+ # :language :: The language the function uses. SQL is the default.
174
+ # :link_symbol :: For a dynamically loaded see function, the function's link symbol if different from the definition argument.
175
+ # :returns :: The data type returned by the function. If you are using OUT or INOUT argument modes, this is ignored.
176
+ # Otherwise, if this is not specified, void is used by default to specify the function is not supposed to return a value.
177
+ # :rows :: The estimated number of rows the function will return. Only use if the function returns SETOF something.
178
+ # :security_definer :: Makes the privileges of the function the same as the privileges of the user who defined the function instead of
179
+ # the privileges of the user who runs the function. There are security implications when doing this, see the PostgreSQL documentation.
180
+ # :set :: Configuration variables to set while the function is being run, can be a hash or an array of two pairs. search_path is
181
+ # often used here if :security_definer is used.
182
+ # :strict :: Makes the function return NULL when any argument is NULL.
183
183
  def create_function(name, definition, opts=OPTS)
184
184
  self << create_function_sql(name, definition, opts)
185
185
  end
186
186
 
187
187
  # Create the procedural language in the database. Arguments:
188
- # * name : Name of the procedural language (e.g. plpgsql)
189
- # * opts : options hash:
190
- # * :handler : The name of a previously registered function used as a call handler for this language.
191
- # * :replace : Replace the installed language if it already exists (on PostgreSQL 9.0+).
192
- # * :trusted : Marks the language being created as trusted, allowing unprivileged users to create functions using this language.
193
- # * :validator : The name of previously registered function used as a validator of functions defined in this language.
188
+ # name :: Name of the procedural language (e.g. plpgsql)
189
+ # opts :: options hash:
190
+ # :handler :: The name of a previously registered function used as a call handler for this language.
191
+ # :replace :: Replace the installed language if it already exists (on PostgreSQL 9.0+).
192
+ # :trusted :: Marks the language being created as trusted, allowing unprivileged users to create functions using this language.
193
+ # :validator :: The name of previously registered function used as a validator of functions defined in this language.
194
194
  def create_language(name, opts=OPTS)
195
195
  self << create_language_sql(name, opts)
196
196
  end
197
197
 
198
198
  # Create a schema in the database. Arguments:
199
- # * name : Name of the schema (e.g. admin)
200
- # * opts : options hash:
201
- # * :if_not_exists : Don't raise an error if the schema already exists (PostgreSQL 9.3+)
202
- # * :owner : The owner to set for the schema (defaults to current user if not specified)
199
+ # name :: Name of the schema (e.g. admin)
200
+ # opts :: options hash:
201
+ # :if_not_exists :: Don't raise an error if the schema already exists (PostgreSQL 9.3+)
202
+ # :owner :: The owner to set for the schema (defaults to current user if not specified)
203
203
  def create_schema(name, opts=OPTS)
204
204
  self << create_schema_sql(name, opts)
205
205
  end
206
206
 
207
207
  # Create a trigger in the database. Arguments:
208
- # * table : the table on which this trigger operates
209
- # * name : the name of this trigger
210
- # * function : the function to call for this trigger, which should return type trigger.
211
- # * opts : options hash:
212
- # * :after : Calls the trigger after execution instead of before.
213
- # * :args : An argument or array of arguments to pass to the function.
214
- # * :each_row : Calls the trigger for each row instead of for each statement.
215
- # * :events : Can be :insert, :update, :delete, or an array of any of those. Calls the trigger whenever that type of statement is used. By default,
216
- # the trigger is called for insert, update, or delete.
208
+ # table :: the table on which this trigger operates
209
+ # name :: the name of this trigger
210
+ # function :: the function to call for this trigger, which should return type trigger.
211
+ # opts :: options hash:
212
+ # :after :: Calls the trigger after execution instead of before.
213
+ # :args :: An argument or array of arguments to pass to the function.
214
+ # :each_row :: Calls the trigger for each row instead of for each statement.
215
+ # :events :: Can be :insert, :update, :delete, or an array of any of those. Calls the trigger whenever that type of statement is used. By default,
216
+ # the trigger is called for insert, update, or delete.
217
+ # :when :: A filter to use for the trigger
217
218
  def create_trigger(table, name, function, opts=OPTS)
218
219
  self << create_trigger_sql(table, name, function, opts)
219
220
  end
@@ -234,39 +235,39 @@ module Sequel
234
235
  end
235
236
 
236
237
  # Drops the function from the database. Arguments:
237
- # * name : name of the function to drop
238
- # * opts : options hash:
239
- # * :args : The arguments for the function. See create_function_sql.
240
- # * :cascade : Drop other objects depending on this function.
241
- # * :if_exists : Don't raise an error if the function doesn't exist.
238
+ # name :: name of the function to drop
239
+ # opts :: options hash:
240
+ # :args :: The arguments for the function. See create_function_sql.
241
+ # :cascade :: Drop other objects depending on this function.
242
+ # :if_exists :: Don't raise an error if the function doesn't exist.
242
243
  def drop_function(name, opts=OPTS)
243
244
  self << drop_function_sql(name, opts)
244
245
  end
245
246
 
246
247
  # Drops a procedural language from the database. Arguments:
247
- # * name : name of the procedural language to drop
248
- # * opts : options hash:
249
- # * :cascade : Drop other objects depending on this function.
250
- # * :if_exists : Don't raise an error if the function doesn't exist.
248
+ # name :: name of the procedural language to drop
249
+ # opts :: options hash:
250
+ # :cascade :: Drop other objects depending on this function.
251
+ # :if_exists :: Don't raise an error if the function doesn't exist.
251
252
  def drop_language(name, opts=OPTS)
252
253
  self << drop_language_sql(name, opts)
253
254
  end
254
255
 
255
256
  # Drops a schema from the database. Arguments:
256
- # * name : name of the schema to drop
257
- # * opts : options hash:
258
- # * :cascade : Drop all objects in this schema.
259
- # * :if_exists : Don't raise an error if the schema doesn't exist.
257
+ # name :: name of the schema to drop
258
+ # opts :: options hash:
259
+ # :cascade :: Drop all objects in this schema.
260
+ # :if_exists :: Don't raise an error if the schema doesn't exist.
260
261
  def drop_schema(name, opts=OPTS)
261
262
  self << drop_schema_sql(name, opts)
262
263
  end
263
264
 
264
265
  # Drops a trigger from the database. Arguments:
265
- # * table : table from which to drop the trigger
266
- # * name : name of the trigger to drop
267
- # * opts : options hash:
268
- # * :cascade : Drop other objects depending on this function.
269
- # * :if_exists : Don't raise an error if the function doesn't exist.
266
+ # table :: table from which to drop the trigger
267
+ # name :: name of the trigger to drop
268
+ # opts :: options hash:
269
+ # :cascade :: Drop other objects depending on this function.
270
+ # :if_exists :: Don't raise an error if the function doesn't exist.
270
271
  def drop_trigger(table, name, opts=OPTS)
271
272
  self << drop_trigger_sql(table, name, opts)
272
273
  end
@@ -482,6 +483,11 @@ module Sequel
482
483
  true
483
484
  end
484
485
 
486
+ # PostgreSQL 9.0+ supports trigger conditions.
487
+ def supports_trigger_conditions?
488
+ server_version >= 90000
489
+ end
490
+
485
491
  # PostgreSQL supports prepared transactions (two-phase commit) if
486
492
  # max_prepared_transactions is greater than 0.
487
493
  def supports_prepared_transactions?
@@ -708,9 +714,12 @@ module Sequel
708
714
  end
709
715
 
710
716
  EXCLUSION_CONSTRAINT_SQL_STATE = '23P01'.freeze
717
+ DEADLOCK_SQL_STATE = '40P01'.freeze
711
718
  def database_specific_error_class_from_sqlstate(sqlstate)
712
719
  if sqlstate == EXCLUSION_CONSTRAINT_SQL_STATE
713
720
  ExclusionConstraintViolation
721
+ elsif sqlstate == DEADLOCK_SQL_STATE
722
+ SerializationFailure
714
723
  else
715
724
  super
716
725
  end
@@ -841,7 +850,11 @@ module Sequel
841
850
  def create_trigger_sql(table, name, function, opts=OPTS)
842
851
  events = opts[:events] ? Array(opts[:events]) : [:insert, :update, :delete]
843
852
  whence = opts[:after] ? 'AFTER' : 'BEFORE'
844
- "CREATE TRIGGER #{name} #{whence} #{events.map{|e| e.to_s.upcase}.join(' OR ')} ON #{quote_schema_table(table)}#{' FOR EACH ROW' if opts[:each_row]} EXECUTE PROCEDURE #{function}(#{Array(opts[:args]).map{|a| literal(a)}.join(', ')})"
853
+ if filter = opts[:when]
854
+ raise Error, "Trigger conditions are not supported for this database" unless supports_trigger_conditions?
855
+ filter = " WHEN #{filter_expr(filter)}"
856
+ end
857
+ "CREATE TRIGGER #{name} #{whence} #{events.map{|e| e.to_s.upcase}.join(' OR ')} ON #{quote_schema_table(table)}#{' FOR EACH ROW' if opts[:each_row]}#{filter} EXECUTE PROCEDURE #{function}(#{Array(opts[:args]).map{|a| literal(a)}.join(', ')})"
845
858
  end
846
859
 
847
860
  # DDL fragment for initial part of CREATE VIEW statement
@@ -1387,7 +1400,7 @@ module Sequel
1387
1400
  #
1388
1401
  # Options:
1389
1402
  # :cascade :: whether to use the CASCADE option, useful when truncating
1390
- # tables with Foreign Keys.
1403
+ # tables with foreign keys.
1391
1404
  # :only :: truncate using ONLY, so child tables are unaffected
1392
1405
  # :restart :: use RESTART IDENTITY to restart any related sequences
1393
1406
  #