Last Update: 2011-12-01 10:07:58 -0800

Dataset Literalization Refactoring

  • As warned about in the 3.29.0 release notes, dataset literalization has been completely refactored. It now uses an append-only design which is faster in all cases, about twice as fast for large objects and deeply nested structures, and over two orders of magnitude faster in some pathological cases.

    This change should not affect applications, but may affect custom extensions or adapters that dealt with literalization of objects. Most literalization methods now have a method with an _append suffix that does the actual literalization, which takes the sql string to append to as the first argument. If you were overriding a literalization method, you now probably need to override the _append version instead. If you have this literalization method:

     def foo_sql(bar)
       "BAR #{literal(bar.baz)}"
    You need to change the code to:
     def foo_sql_append(sql, bar)
       sql << "BAR "
       literal_append(sql, bar.baz)
     def foo_sql(bar)
       sql = ""
       foo_sql_append(sql, bar)

    If you have questions about modifying your custom adapter or extension, please ask on the Google Group or the IRC channel.

New Features

  • Model#set_server has been added to the base support (it was previously only in the sharding plugin), which allows you to set the shard on which to save/delete the model instance:

  • Model#save now accepts a :server option that uses set_server to set the shard to use. Unlike most other save options, this option persists past the end of the save. Previously, the :server option only affected the transaction code, it now affects the INSERT/UPDATE statement as well.

  • When initiating a new dataset graph, any existing selected columns is assumed to be the columns to select for the graph from the current/master table. Before, there was not a way to specify the columns to select from the current/master table.

  • A :graph_alias_base association option has been added, which is used to set the base alias name to use when eager graphing. This is mostly useful when cascading eager graphs to dependent associations, where multiple associations with the same name in different models are being graphed simultaneously.

  • You can now specify nanoseconds and a timezone offset when converting a hash or array to a timestamp. The nanoseconds and offset are the 7th and 8th entries in the array, and the :nanos and :offset entry in the hash.

  • The postgres adapter now respects a :connect_timeout option if you are using the pg driver.

Other Improvements

  • Type conversion of Java to Ruby types in the JDBC adapter has been made much faster, as conversion method lookup is now O(number of columns) instead of O(number of columns*number of rows).

  • Sequel::SQL::Blob literalization is now much faster on adapters that use hex encoding, by switching to String#unpack('H*').

  • Database#after_commit and after_rollback now respect the :server option to set the server/shard to use.

  • Symbol splitting (e.g. for table__column) is now slightly faster.

  • All adapters now pass the dataset :limit/:offset value through Dataset#literal instead of using it verbatim. Note that Dataset#limit already called to_i on input strings, so this isn't a security issue. However, the previous code broke if you provided a Sequel-specific object (e.g. Sequel::SQL::Function) as the :limit/:offset value.

  • Calling graph and eager_graph on an already graphed dataset no longer modifies the receiver.

  • Model#set_server now correctly handles the case where @this is already loaded.

  • Dataset#destroy for model datasets now uses the dataset's shard for transactions.

  • When emulating offset support using ROW_NUMBER (on Microsoft SQL Server, DB2, and Oracle), explicitly order by the ROW_NUMBER result, as otherwise the results are not guaranteed to be ordered.

  • Explicitly force a case insensitive collation when emulating ILIKE on Microsoft SQL Server. Previously, ILIKE could be case sensitive on Microsoft SQL Server if case sensitive collation was the database default.

  • Using on_duplicate_key_update with prepared statements on MySQL now works correctly.

  • The tinytds adapter now works correctly if the identifier_output_method is nil.

  • The plugin/extension specs were cleaned up using the mock adapter.

Backwards Compatibility

  • In addition to the previously mentioned dataset literalization changes, any custom adapters that overrode *_clause_methods methods need to be modified to add a method that adds the SELECT/UPDATE/INSERT/DELETE. Previously, this was done by default, but due to common table expressions and the dataset literalization changes, a separate method is now needed.

  • Dataset#on_duplicate_key_update_sql has been removed from the shared mysql adapter.

  • The :columns dataset option used when inserting is no longer literalized in advance.

  • Dataset#as_sql no longer takes an expression, it just takes the alias, and only adds the alias part.