…XISTS syntax (Fixes #362), bump version to 3.24.1
…ents by default for regular association loading This is similar to the prepared_statements_with_pk plugin, as it also uses Dataset#unbind, but it should be more safe as it skips using a prepared statement completely if it detects that there are association options that it does not handle.
…lean valid? should always return a boolean even if a validation hook fails. However, when save validates, a HookFailure exception should be raised instead. The _valid? method takes a parameter for whether to raise or return false for hook failures. It's no longer safe to override valid?, which I was doing in a few specs. You should only be overriding validate to add errors.
… returning false Because around hooks can now raise exceptions similar to before hooks, rename the exception to HookFailed, but still assign it to the BeforeHookFailed constant as well for backwards compatibility. With this change and the previous one, around hooks are now very similar to ActiveSupport ones in terms of behavior, though they use instance methods instead of blocks.
Use checked_save_failure and raise_hook_failure so that validation failures are handled just like other save failures. Also, try to return intelligent things for super calls inside around hooks. For validation this returns true/false depending on the whether the object has errors. For all other around hooks, just return true since there isn't any other useful information.
…e with models more safe This new plugin doesn't use prepared statements at all, but it's designed to be used with (and requires) the prepared_statements plugin. The basic security issue with using prepared statements implicitly with Sequel is that Sequel by default only uses uses the currently present columns when insert (some subset of the table's columns), and by default when updating only saves the changed columns. For prepared statements to be used, each set of columns in the insert and update statements needs to have its own prepared statement. If you have a table with 1 primary key column and 4 other columns, you can have up to 2^4 = 16 prepared statements created, one for each subset of the 4 columns. If you have 1 primary key column and 20 other columns, there are over a million subsets, and you would assuredly hit your database limit for prepared statements (a denial of service attack). The fix for this is to use every column possible when inserting and updating. For updating, this is simple, as you just save all columns. For inserting, this isn't always possible, as you can't necessarily insert a correct default value, as it could depend on a database function. So for NULL defaults and defaults that Sequel can parse, Sequel will add those columns to the insert statement.
…th_pk plugin This functionality now uses Dataset#unbind to create a more generic dataset, which lowers the risk of an unbounded number of prepared statements being create, but it does not eliminate the risk. This plugin should only be used by those who are sure that their usage of Dataset#with_pk cannot result in a denial of service attack.
…false as bound values A separate prepared_arg? method has been added to see if argument used is actually in the bound variables. The argument mappers used for native bound variable support always return true for this method.
… by unbind The double underscore is already used by the native postgres adapter to specify types. There was already a partial fix for this earlier in the SQLite adapter, but it only handled the SQL serialization. This completes that fix by also handling the bind variables.
…creating prepared statements This adds a new ASTTranformer subclass that does the work, by recognizing some types of ComplexExpressions, extracting bound variables and substituting them with placeholders. The statements can then be prepared and executed (or just called) with the extracted bound variables. Also, fix a small issue with using double underscores for placeholder values in the SQLite native support for argument mapping.
…bstract syntax trees Refactor internals of Dataset#qualify to use a subclass of ASTTransformer. This class is being added to make other types of transforms easier to implement, by using a subclass of ASTTransformer that only cares about the objects you are interested in transforming.
The only change in output is that SQL::Subscript instances had some redudant information removed.
…tes, inserts, deletes, and lookups by primary key This allows easy use of Sequel's prepared statement support by models without any manual effort by the user (other than loading the plugin). Some internal changes: Prepared statements now support an :insert_select prepared type that will prepare the SQL using insert_sql, but execute it with first to retrieve the row value. You should only use this if the dataset supports insert_select. To implement the insert_select support for prepared statements a :returning=>nil option is added to the dataset, which the relevent adapters have been modified to support. In order to get Sequel to use the insert_select method when inserting, the supports_insert_select? method must return true. Quite a few private model instance methods were added to eliminate the code duplication that this would have otherwise required.
… matching primary key value This is being added to make it easier to do a primary key lookup. Sequel has supported Model. for lookups by primary key, but if you wanted to add a filter to that, you had to give the primary key explicitly: Model.filter(:foo=>'bar')[:id=>1] With the addition of the with_pk method, you can do: Model.filter(:foo=>'bar').with_pk(1) Which doesn't require you specify the primary key. Also, Dataset# has been overridden to call with_pk if given a single integer value, so you can do: Model.filter(:foo=>'bar') Unfortunately, due to backwards compatibility, that won't work with strings or composite primary keys, so you will have to use with_pk for those. For composite primary keys, you have to use an array: Model.filter(:foo=>'bar').with_pk([1, 2])
…ing models This allows similar behavior to ActiveRecord, where instantiating a new model will have the database default values set. It improves on this idea by not setting nil/NULL defaults or defaults that cannot be parsed by Sequel. It also allows users to easily modify the default vaues used.
Around hooks wrap both the related before and after hooks. In most cases, before and after hooks are sufficient, but if you need to be able to rescue exceptions raised by a before or after hook or the wrapped behavior (e.g. the actual insert/update/delete), you need to use an around hook. For example, you could use an around hook to turn DatabaseErrors caused by constraints into validation errors, assuming you could correctly parse error messages from the database. This only contains the specs and code changes, the update to the hook documentation will come soon.
Instead of calling #set directly inside #initialize, Sequel now calls #initialize_set, with the default behavior of #initialize_set just calling #set. Previously, there was no easy to set column values that depended on values passed in to initialize and have those columns not show up in changed_columns, without overriding all of initialize (which is called for both new records and existing records).
PostgreSQL 9.0+ enables it by default. This also makes it so you do not have to use a PostgreSQL superuser account to run the specs.