[Bast-commits] r9313 - in DBIx-Class/0.08/branches/group_by_consistency: . lib/DBIx lib/DBIx/Class lib/DBIx/Class/Admin lib/DBIx/Class/CDBICompat lib/DBIx/Class/InflateColumn lib/DBIx/Class/Manual lib/DBIx/Class/Optional lib/DBIx/Class/Relationship lib/DBIx/Class/ResultSource lib/DBIx/Class/SQLAHacks lib/DBIx/Class/Schema lib/DBIx/Class/Storage lib/DBIx/Class/Storage/DBI lib/DBIx/Class/Storage/DBI/ODBC lib/DBIx/Class/Storage/DBI/Oracle lib/DBIx/Class/Storage/DBI/Replicated lib/DBIx/Class/Storage/DBI/Replicated/Balancer lib/DBIx/Class/Storage/DBI/Role lib/DBIx/Class/Storage/DBI/Sybase lib/DBIx/Class/Storage/DBI/Sybase/ASE lib/SQL/Translator/Parser/DBIx maint script t t/admin t/bind t/cdbi t/count t/inflate t/lib t/lib/DBICNSTest/Result t/lib/DBICNSTest/ResultSet t/lib/DBICTest t/lib/DBICTest/Schema t/multi_create t/ordered t/prefetch t/relationship t/resultset t/row t/search t/sqlahacks t/sqlahacks/limit_dialects t/sqlahacks/quotes t/sqlahacks/sql_maker t/storage

ribasushi at dev.catalyst.perl.org ribasushi at dev.catalyst.perl.org
Thu May 6 09:42:51 GMT 2010


Author: ribasushi
Date: 2010-05-06 10:42:51 +0100 (Thu, 06 May 2010)
New Revision: 9313

Added:
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Admin.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Admin/
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Admin/Descriptive.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Admin/Types.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Admin/Usage.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Optional/
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Optional/Dependencies.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/SQLAHacks/SQLite.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/InterBase.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/ODBC/Firebird.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/UniqueIdentifier.pm
   DBIx-Class/0.08/branches/group_by_consistency/maint/benchmark_datafetch.pl
   DBIx-Class/0.08/branches/group_by_consistency/maint/joint_deps.pl
   DBIx-Class/0.08/branches/group_by_consistency/t/10optional_deps.t
   DBIx-Class/0.08/branches/group_by_consistency/t/750firebird.t
   DBIx-Class/0.08/branches/group_by_consistency/t/admin/
   DBIx-Class/0.08/branches/group_by_consistency/t/admin/01load.t
   DBIx-Class/0.08/branches/group_by_consistency/t/admin/02ddl.t
   DBIx-Class/0.08/branches/group_by_consistency/t/admin/03data.t
   DBIx-Class/0.08/branches/group_by_consistency/t/admin/10script.t
   DBIx-Class/0.08/branches/group_by_consistency/t/count/group_by_func.t
   DBIx-Class/0.08/branches/group_by_consistency/t/inflate/datetime_firebird.t
   DBIx-Class/0.08/branches/group_by_consistency/t/inflate/datetime_informix.t
   DBIx-Class/0.08/branches/group_by_consistency/t/lib/DBICNSTest/Result/D.pm
   DBIx-Class/0.08/branches/group_by_consistency/t/lib/DBICNSTest/ResultSet/D.pm
   DBIx-Class/0.08/branches/group_by_consistency/t/lib/DBICTest/Schema/TimestampPrimaryKey.pm
   DBIx-Class/0.08/branches/group_by_consistency/t/prefetch/one_to_many_to_one.t
   DBIx-Class/0.08/branches/group_by_consistency/t/relationship/unresolvable.t
   DBIx-Class/0.08/branches/group_by_consistency/t/resultset/as_subselect_rs.t
   DBIx-Class/0.08/branches/group_by_consistency/t/resultset/is_ordered.t
   DBIx-Class/0.08/branches/group_by_consistency/t/row/
   DBIx-Class/0.08/branches/group_by_consistency/t/row/inflate_result.t
   DBIx-Class/0.08/branches/group_by_consistency/t/row/pkless.t
   DBIx-Class/0.08/branches/group_by_consistency/t/search/select_chains.t
   DBIx-Class/0.08/branches/group_by_consistency/t/sqlahacks/limit_dialects/rno.t
   DBIx-Class/0.08/branches/group_by_consistency/t/sqlahacks/limit_dialects/rownum.t
   DBIx-Class/0.08/branches/group_by_consistency/t/sqlahacks/oraclejoin.t
   DBIx-Class/0.08/branches/group_by_consistency/t/sqlahacks/sqlite.t
   DBIx-Class/0.08/branches/group_by_consistency/t/storage/dbi_env.t
   DBIx-Class/0.08/branches/group_by_consistency/t/storage/deploy.t
   DBIx-Class/0.08/branches/group_by_consistency/t/storage/global_destruction.t
   DBIx-Class/0.08/branches/group_by_consistency/t/storage/replicated.t
Removed:
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/AmbiguousGlob.pm
   DBIx-Class/0.08/branches/group_by_consistency/t/41orrible.t
   DBIx-Class/0.08/branches/group_by_consistency/t/89dbicadmin.t
   DBIx-Class/0.08/branches/group_by_consistency/t/storage/replication.t
Modified:
   DBIx-Class/0.08/branches/group_by_consistency/
   DBIx-Class/0.08/branches/group_by_consistency/Changes
   DBIx-Class/0.08/branches/group_by_consistency/Makefile.PL
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/CDBICompat.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/CDBICompat/AbstractSearch.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/CDBICompat/ColumnCase.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/CDBICompat/ColumnsAsHash.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/CDBICompat/Copy.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/CDBICompat/Iterator.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Componentised.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/InflateColumn.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/InflateColumn/DateTime.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/InflateColumn/File.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Manual/Component.pod
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Manual/Cookbook.pod
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Manual/Example.pod
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Manual/FAQ.pod
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Manual/Intro.pod
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Manual/Joining.pod
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Manual/Reading.pod
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Manual/Troubleshooting.pod
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Ordered.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/PK.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Relationship.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Relationship/Accessor.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Relationship/Base.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Relationship/BelongsTo.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Relationship/CascadeActions.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Relationship/HasMany.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Relationship/HasOne.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/ResultSet.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/ResultSetColumn.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/ResultSource.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/ResultSource/Table.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/ResultSourceHandle.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/ResultSourceProxy.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Row.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/SQLAHacks.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/SQLAHacks/MySQL.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/SQLAHacks/OracleJoins.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Schema.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Schema/Versioned.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/StartupCheck.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/AutoCast.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Informix.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/MSSQL.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/MultiColumnIn.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/ODBC.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/ODBC/ACCESS.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/ODBC/Microsoft_SQL_Server.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Oracle/Generic.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Oracle/WhereJoins.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Pg.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Replicated.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Replicated/Balancer.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Replicated/Balancer/First.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Replicated/Introduction.pod
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Replicated/Pool.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Replicated/Replicant.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Role/QueryCounter.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/SQLAnywhere.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/SQLite.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Sybase.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Sybase/ASE.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Sybase/ASE/NoBindVars.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Sybase/Microsoft_SQL_Server.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/mysql.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBIHacks.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/TxnScopeGuard.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/UTF8Columns.pm
   DBIx-Class/0.08/branches/group_by_consistency/lib/SQL/Translator/Parser/DBIx/Class.pm
   DBIx-Class/0.08/branches/group_by_consistency/script/dbicadmin
   DBIx-Class/0.08/branches/group_by_consistency/t/02pod.t
   DBIx-Class/0.08/branches/group_by_consistency/t/03podcoverage.t
   DBIx-Class/0.08/branches/group_by_consistency/t/06notabs.t
   DBIx-Class/0.08/branches/group_by_consistency/t/07eol.t
   DBIx-Class/0.08/branches/group_by_consistency/t/39load_namespaces_1.t
   DBIx-Class/0.08/branches/group_by_consistency/t/39load_namespaces_3.t
   DBIx-Class/0.08/branches/group_by_consistency/t/51threads.t
   DBIx-Class/0.08/branches/group_by_consistency/t/52cycle.t
   DBIx-Class/0.08/branches/group_by_consistency/t/60core.t
   DBIx-Class/0.08/branches/group_by_consistency/t/69update.t
   DBIx-Class/0.08/branches/group_by_consistency/t/71mysql.t
   DBIx-Class/0.08/branches/group_by_consistency/t/72pg.t
   DBIx-Class/0.08/branches/group_by_consistency/t/73oracle.t
   DBIx-Class/0.08/branches/group_by_consistency/t/746mssql.t
   DBIx-Class/0.08/branches/group_by_consistency/t/746sybase.t
   DBIx-Class/0.08/branches/group_by_consistency/t/748informix.t
   DBIx-Class/0.08/branches/group_by_consistency/t/749sybase_asa.t
   DBIx-Class/0.08/branches/group_by_consistency/t/74mssql.t
   DBIx-Class/0.08/branches/group_by_consistency/t/75limit.t
   DBIx-Class/0.08/branches/group_by_consistency/t/76joins.t
   DBIx-Class/0.08/branches/group_by_consistency/t/76select.t
   DBIx-Class/0.08/branches/group_by_consistency/t/81transactions.t
   DBIx-Class/0.08/branches/group_by_consistency/t/85utf8.t
   DBIx-Class/0.08/branches/group_by_consistency/t/86sqlt.t
   DBIx-Class/0.08/branches/group_by_consistency/t/87ordered.t
   DBIx-Class/0.08/branches/group_by_consistency/t/90join_torture.t
   DBIx-Class/0.08/branches/group_by_consistency/t/93single_accessor_object.t
   DBIx-Class/0.08/branches/group_by_consistency/t/94versioning.t
   DBIx-Class/0.08/branches/group_by_consistency/t/99dbic_sqlt_parser.t
   DBIx-Class/0.08/branches/group_by_consistency/t/bind/attribute.t
   DBIx-Class/0.08/branches/group_by_consistency/t/cdbi/columns_as_hashes.t
   DBIx-Class/0.08/branches/group_by_consistency/t/count/count_rs.t
   DBIx-Class/0.08/branches/group_by_consistency/t/count/distinct.t
   DBIx-Class/0.08/branches/group_by_consistency/t/count/prefetch.t
   DBIx-Class/0.08/branches/group_by_consistency/t/inflate/datetime_mssql.t
   DBIx-Class/0.08/branches/group_by_consistency/t/inflate/datetime_sybase.t
   DBIx-Class/0.08/branches/group_by_consistency/t/inflate/datetime_sybase_asa.t
   DBIx-Class/0.08/branches/group_by_consistency/t/inflate/file_column.t
   DBIx-Class/0.08/branches/group_by_consistency/t/inflate/hri.t
   DBIx-Class/0.08/branches/group_by_consistency/t/lib/DBICTest/AuthorCheck.pm
   DBIx-Class/0.08/branches/group_by_consistency/t/lib/DBICTest/Schema.pm
   DBIx-Class/0.08/branches/group_by_consistency/t/lib/DBICTest/Schema/Employee.pm
   DBIx-Class/0.08/branches/group_by_consistency/t/lib/DBICTest/Schema/Encoded.pm
   DBIx-Class/0.08/branches/group_by_consistency/t/lib/DBICTest/Schema/Event.pm
   DBIx-Class/0.08/branches/group_by_consistency/t/lib/DBICTest/Schema/EventTZPg.pm
   DBIx-Class/0.08/branches/group_by_consistency/t/lib/DBICTest/Schema/FileColumn.pm
   DBIx-Class/0.08/branches/group_by_consistency/t/lib/DBICTest/Schema/ForceForeign.pm
   DBIx-Class/0.08/branches/group_by_consistency/t/lib/sqlite.sql
   DBIx-Class/0.08/branches/group_by_consistency/t/multi_create/in_memory.t
   DBIx-Class/0.08/branches/group_by_consistency/t/multi_create/standard.t
   DBIx-Class/0.08/branches/group_by_consistency/t/ordered/cascade_delete.t
   DBIx-Class/0.08/branches/group_by_consistency/t/prefetch/grouped.t
   DBIx-Class/0.08/branches/group_by_consistency/t/prefetch/via_search_related.t
   DBIx-Class/0.08/branches/group_by_consistency/t/relationship/core.t
   DBIx-Class/0.08/branches/group_by_consistency/t/sqlahacks/limit_dialects/toplimit.t
   DBIx-Class/0.08/branches/group_by_consistency/t/sqlahacks/quotes/quotes.t
   DBIx-Class/0.08/branches/group_by_consistency/t/sqlahacks/quotes/quotes_newstyle.t
   DBIx-Class/0.08/branches/group_by_consistency/t/sqlahacks/sql_maker/sql_maker_quote.t
   DBIx-Class/0.08/branches/group_by_consistency/t/storage/error.t
Log:
 r8580 at Thesaurus (orig r8567):  gshank | 2010-02-05 22:29:24 +0100
 add doc on 'where' attribute
 
 r8587 at Thesaurus (orig r8574):  frew | 2010-02-07 21:07:03 +0100
 add as_subselect_rs
 r8588 at Thesaurus (orig r8575):  frew | 2010-02-07 21:13:04 +0100
 fix longstanding unmentioned bug ("me")
 r8589 at Thesaurus (orig r8576):  frew | 2010-02-08 06:17:43 +0100
 another example of as_subselect_rs
 r8590 at Thesaurus (orig r8577):  frew | 2010-02-08 06:23:58 +0100
 fix bug in UTF8Columns
 r8591 at Thesaurus (orig r8578):  ribasushi | 2010-02-08 09:31:01 +0100
 Extend utf8columns test to trap fixed bug
 r8592 at Thesaurus (orig r8579):  ribasushi | 2010-02-08 12:03:23 +0100
 Cleanup rel accessor type handling
 r8593 at Thesaurus (orig r8580):  ribasushi | 2010-02-08 12:20:47 +0100
 Fix some fallout
 r8595 at Thesaurus (orig r8582):  ribasushi | 2010-02-08 12:38:19 +0100
 Merge some obsolete code cleanup from the prefetch branch
 r8596 at Thesaurus (orig r8583):  ribasushi | 2010-02-08 12:42:09 +0100
 Merge fix of RT54039 from prefetch branch
 r8598 at Thesaurus (orig r8585):  ribasushi | 2010-02-08 12:48:31 +0100
 Release 0.08118
 r8600 at Thesaurus (orig r8587):  ribasushi | 2010-02-08 12:52:33 +0100
 Bump trunk version
 r8606 at Thesaurus (orig r8593):  ribasushi | 2010-02-08 16:16:44 +0100
 cheaper lookup
 r8609 at Thesaurus (orig r8596):  ribasushi | 2010-02-10 12:40:37 +0100
 Consolidate last_insert_id handling with a fallback-attempt on DBI::last_insert_id
 r8614 at Thesaurus (orig r8601):  caelum | 2010-02-10 21:29:51 +0100
 workaround for Moose bug affecting Replicated storage
 r8615 at Thesaurus (orig r8602):  caelum | 2010-02-10 21:40:07 +0100
 revert Moose bug workaround, bump Moose dep for Replicated to 0.98
 r8616 at Thesaurus (orig r8603):  caelum | 2010-02-10 22:48:34 +0100
 add a couple proxy methods to Replicated so it can run
 r8628 at Thesaurus (orig r8615):  caelum | 2010-02-11 11:35:01 +0100
  r21090 at hlagh (orig r7836):  caelum | 2009-11-02 06:40:52 -0500
  new branch to fix unhandled methods in Storage::DBI::Replicated
  r21091 at hlagh (orig r7837):  caelum | 2009-11-02 06:42:00 -0500
  add test to display unhandled methods
  r21092 at hlagh (orig r7838):  caelum | 2009-11-02 06:55:34 -0500
  minor fix to last committed test
  r21093 at hlagh (orig r7839):  caelum | 2009-11-02 09:26:00 -0500
  minor test code cleanup
  r23125 at hlagh (orig r8607):  caelum | 2010-02-10 19:25:51 -0500
  add unimplemented Storage::DBI methods to ::DBI::Replicated
  r23130 at hlagh (orig r8612):  ribasushi | 2010-02-11 05:12:48 -0500
  Podtesting exclusion
 
 r8630 at Thesaurus (orig r8617):  frew | 2010-02-11 11:45:54 +0100
 Changes (from a while ago)
 r8631 at Thesaurus (orig r8618):  caelum | 2010-02-11 11:46:58 +0100
 savepoints for SQLAnywhere
 r8640 at Thesaurus (orig r8627):  ribasushi | 2010-02-11 12:33:19 +0100
  r8424 at Thesaurus (orig r8411):  ribasushi | 2010-01-22 11:19:40 +0100
  Chaining POC test
 
 r8641 at Thesaurus (orig r8628):  ribasushi | 2010-02-11 12:34:19 +0100
  r8426 at Thesaurus (orig r8413):  ribasushi | 2010-01-22 11:35:15 +0100
  Moev failing regression test away from trunk
 
 r8642 at Thesaurus (orig r8629):  ribasushi | 2010-02-11 12:34:56 +0100
 
 r8643 at Thesaurus (orig r8630):  ribasushi | 2010-02-11 12:35:03 +0100
  r8507 at Thesaurus (orig r8494):  frew | 2010-02-01 04:33:08 +0100
  small refactor to put select/as/+select/+as etc merging in it's own function
 
 r8644 at Thesaurus (orig r8631):  ribasushi | 2010-02-11 12:35:11 +0100
  r8514 at Thesaurus (orig r8501):  frew | 2010-02-02 05:12:29 +0100
  revert actual changes from yesterday as per ribasushis advice
 
 r8645 at Thesaurus (orig r8632):  ribasushi | 2010-02-11 12:35:16 +0100
  r8522 at Thesaurus (orig r8509):  frew | 2010-02-02 19:39:33 +0100
  delete +stuff if stuff exists
 
 r8646 at Thesaurus (orig r8633):  ribasushi | 2010-02-11 12:35:23 +0100
  r8534 at Thesaurus (orig r8521):  frew | 2010-02-03 06:14:44 +0100
  change deletion/overriding to fix t/76
 
 r8647 at Thesaurus (orig r8634):  ribasushi | 2010-02-11 12:35:30 +0100
  r8535 at Thesaurus (orig r8522):  frew | 2010-02-03 06:57:15 +0100
  some basic readability factorings (aka, fewer nested ternaries and long maps)
 
 r8648 at Thesaurus (orig r8635):  ribasushi | 2010-02-11 12:36:01 +0100
  r8558 at Thesaurus (orig r8545):  frew | 2010-02-04 20:32:54 +0100
  fix incorrect test in t/76select.t and posit an incorrect solution
 
 r8649 at Thesaurus (orig r8636):  ribasushi | 2010-02-11 12:38:47 +0100
 
 r8650 at Thesaurus (orig r8637):  ribasushi | 2010-02-11 12:38:57 +0100
  r8578 at Thesaurus (orig r8565):  ribasushi | 2010-02-05 19:11:09 +0100
  Should not be needed
 
 r8651 at Thesaurus (orig r8638):  ribasushi | 2010-02-11 12:39:03 +0100
  r8579 at Thesaurus (orig r8566):  ribasushi | 2010-02-05 19:13:24 +0100
  SQLA now fixed
 
 r8652 at Thesaurus (orig r8639):  ribasushi | 2010-02-11 12:39:10 +0100
  r8624 at Thesaurus (orig r8611):  ribasushi | 2010-02-11 10:31:08 +0100
  MOAR testing
 
 r8653 at Thesaurus (orig r8640):  ribasushi | 2010-02-11 12:39:17 +0100
  r8626 at Thesaurus (orig r8613):  frew | 2010-02-11 11:16:30 +0100
  fix bad test
 
 r8654 at Thesaurus (orig r8641):  ribasushi | 2010-02-11 12:39:23 +0100
  r8627 at Thesaurus (orig r8614):  frew | 2010-02-11 11:21:52 +0100
  fix t/76, break rsc tests
 
 r8655 at Thesaurus (orig r8642):  ribasushi | 2010-02-11 12:39:30 +0100
  r8632 at Thesaurus (orig r8619):  frew | 2010-02-11 11:53:50 +0100
  fix incorrect test
 
 r8656 at Thesaurus (orig r8643):  ribasushi | 2010-02-11 12:39:35 +0100
  r8633 at Thesaurus (orig r8620):  frew | 2010-02-11 11:54:49 +0100
  make t/76s and t/88 pass by deleting from the correct attr hash
 
 r8657 at Thesaurus (orig r8644):  ribasushi | 2010-02-11 12:39:40 +0100
  r8634 at Thesaurus (orig r8621):  frew | 2010-02-11 11:55:41 +0100
  fix a test due to ordering issues
 
 r8658 at Thesaurus (orig r8645):  ribasushi | 2010-02-11 12:39:45 +0100
  r8635 at Thesaurus (orig r8622):  frew | 2010-02-11 11:58:23 +0100
  this is why you run tests before you commit them.
 
 r8659 at Thesaurus (orig r8646):  ribasushi | 2010-02-11 12:39:51 +0100
  r8636 at Thesaurus (orig r8623):  frew | 2010-02-11 12:00:59 +0100
  fix another ordering issue
 
 r8660 at Thesaurus (orig r8647):  ribasushi | 2010-02-11 12:39:57 +0100
  r8637 at Thesaurus (orig r8624):  frew | 2010-02-11 12:11:31 +0100
  fix for search/select_chains
 
 r8661 at Thesaurus (orig r8648):  ribasushi | 2010-02-11 12:40:03 +0100
 
 r8662 at Thesaurus (orig r8649):  caelum | 2010-02-11 12:40:07 +0100
 test nanosecond precision for SQLAnywhere
 r8663 at Thesaurus (orig r8650):  ribasushi | 2010-02-11 12:40:09 +0100
  r8639 at Thesaurus (orig r8626):  ribasushi | 2010-02-11 12:33:03 +0100
  Changes and small ommission
 
 r8666 at Thesaurus (orig r8653):  ribasushi | 2010-02-11 18:16:45 +0100
 Changes
 r8674 at Thesaurus (orig r8661):  ribasushi | 2010-02-12 09:12:45 +0100
 Fix moose dep
 r8680 at Thesaurus (orig r8667):  dew | 2010-02-12 18:05:11 +0100
 Add is_ordered to DBIC::ResultSet
 r8688 at Thesaurus (orig r8675):  ribasushi | 2010-02-13 09:36:29 +0100
  r8667 at Thesaurus (orig r8654):  ribasushi | 2010-02-11 18:17:35 +0100
  Try a dep-handling idea
  r8675 at Thesaurus (orig r8662):  ribasushi | 2010-02-12 12:46:11 +0100
  Move optional deps out of the Makefile
  r8676 at Thesaurus (orig r8663):  ribasushi | 2010-02-12 13:40:53 +0100
  Support methods to verify group dependencies
  r8677 at Thesaurus (orig r8664):  ribasushi | 2010-02-12 13:45:18 +0100
  Move sqlt dephandling to Optional::Deps
  r8679 at Thesaurus (orig r8666):  ribasushi | 2010-02-12 14:03:17 +0100
  Move replicated to Opt::Deps
  r8684 at Thesaurus (orig r8671):  ribasushi | 2010-02-13 02:47:52 +0100
  Auto-POD for Optional Deps
  r8685 at Thesaurus (orig r8672):  ribasushi | 2010-02-13 02:53:20 +0100
  Privatize the full list method
  r8686 at Thesaurus (orig r8673):  ribasushi | 2010-02-13 02:59:51 +0100
  Scary warning
  r8687 at Thesaurus (orig r8674):  ribasushi | 2010-02-13 09:35:01 +0100
  Changes
 
 r8691 at Thesaurus (orig r8678):  ribasushi | 2010-02-13 10:07:15 +0100
 Autogen comment for Dependencies.pod
 r8692 at Thesaurus (orig r8679):  ribasushi | 2010-02-13 10:11:24 +0100
 Ask for newer M::I
 r8698 at Thesaurus (orig r8685):  ribasushi | 2010-02-13 11:11:10 +0100
 Add author/license to pod
 r8699 at Thesaurus (orig r8686):  arcanez | 2010-02-13 13:43:22 +0100
 fix typo per nuba on irc
 r8705 at Thesaurus (orig r8692):  ribasushi | 2010-02-13 15:15:33 +0100
  r8001 at Thesaurus (orig r7989):  goraxe | 2009-11-30 01:14:47 +0100
  Branch for dbicadmin script refactor
  
  r8003 at Thesaurus (orig r7991):  goraxe | 2009-11-30 01:26:39 +0100
  add DBIx::Class::Admin
  r8024 at Thesaurus (orig r8012):  goraxe | 2009-12-02 22:49:27 +0100
  get deployment tests to pass
  r8025 at Thesaurus (orig r8013):  goraxe | 2009-12-02 22:50:42 +0100
  get deployment tests to pass
  r8026 at Thesaurus (orig r8014):  goraxe | 2009-12-02 23:52:40 +0100
  all ddl tests now pass
  r8083 at Thesaurus (orig r8071):  goraxe | 2009-12-12 17:01:11 +0100
  add quite attribute to DBIx::Class admin
  r8086 at Thesaurus (orig r8074):  goraxe | 2009-12-12 17:36:58 +0100
  add tests for data manipulation ported from 89dbicadmin.t
  r8088 at Thesaurus (orig r8076):  goraxe | 2009-12-12 17:38:07 +0100
  add sleep 1 to t/admin/02ddl.t so insert into upgrade table does not happen too quickly
  r8089 at Thesaurus (orig r8077):  goraxe | 2009-12-12 17:40:33 +0100
  update DBIx::Class::Admin data manip functions to pass the test
  r8095 at Thesaurus (orig r8083):  goraxe | 2009-12-12 19:36:22 +0100
  change passing of preversion to be a parameter
  r8096 at Thesaurus (orig r8084):  goraxe | 2009-12-12 19:38:26 +0100
  add some pod to DBIx::Class::Admin
  r8103 at Thesaurus (orig r8091):  goraxe | 2009-12-12 22:08:55 +0100
  some changes to make DBIx::Class::Admin more compatible with dbicadmin interface
  r8104 at Thesaurus (orig r8092):  goraxe | 2009-12-12 22:09:39 +0100
  commit refactored dbicadmin script and very minor changes to its existing test suite
  r8107 at Thesaurus (orig r8095):  goraxe | 2009-12-12 22:34:35 +0100
  add compatability for --op for dbicadmin, revert test suite
  r8127 at Thesaurus (orig r8115):  goraxe | 2009-12-15 22:14:20 +0100
  dep check to end of module
  r8128 at Thesaurus (orig r8116):  goraxe | 2009-12-15 23:15:25 +0100
  add namespace::autoclean to DBIx::Class::Admin
  r8129 at Thesaurus (orig r8117):  goraxe | 2009-12-15 23:16:00 +0100
  update test suite to skip if cannot load DBIx::Class::Admin
  r8130 at Thesaurus (orig r8118):  goraxe | 2009-12-15 23:18:35 +0100
  add deps check for 89dbicadmin.t
  r8131 at Thesaurus (orig r8119):  goraxe | 2009-12-15 23:19:01 +0100
  include deps for dbicadmin DBIx::Class::Admin to Makefile.PL
  r8149 at Thesaurus (orig r8137):  goraxe | 2009-12-17 23:21:50 +0100
  use DBICTest::_database over creating a schema object to steal conn info
  r8338 at Thesaurus (orig r8326):  goraxe | 2010-01-15 19:00:17 +0100
  change white space to not be tabs
  r8339 at Thesaurus (orig r8327):  goraxe | 2010-01-15 19:10:42 +0100
  remove Module::Load from test suite
  r8358 at Thesaurus (orig r8346):  ribasushi | 2010-01-17 17:52:10 +0100
  Real detabify
  r8359 at Thesaurus (orig r8347):  ribasushi | 2010-01-17 18:01:53 +0100
  Fix POD (spacing matters)
  r8360 at Thesaurus (orig r8348):  ribasushi | 2010-01-17 21:57:53 +0100
  More detabification
  r8361 at Thesaurus (orig r8349):  ribasushi | 2010-01-17 22:33:12 +0100
  Test cleanup
  r8362 at Thesaurus (orig r8350):  ribasushi | 2010-01-17 22:41:11 +0100
  More tets cleanup
  r8363 at Thesaurus (orig r8351):  ribasushi | 2010-01-17 22:43:57 +0100
  And more cleanup
  r8364 at Thesaurus (orig r8352):  ribasushi | 2010-01-17 22:51:21 +0100
  Disallow mucking with INC
  r8365 at Thesaurus (orig r8353):  ribasushi | 2010-01-17 23:23:15 +0100
  More cleanup
  r8366 at Thesaurus (orig r8354):  ribasushi | 2010-01-17 23:27:49 +0100
  Add lib path to ENV so that $^X can see it
  r8367 at Thesaurus (orig r8355):  ribasushi | 2010-01-17 23:33:10 +0100
  Move script-test
  r8368 at Thesaurus (orig r8356):  goraxe | 2010-01-17 23:35:03 +0100
  change warns/dies -> carp/throw_exception
  r8369 at Thesaurus (orig r8357):  goraxe | 2010-01-17 23:53:54 +0100
  add goraxe to contributors
  r8370 at Thesaurus (orig r8358):  goraxe | 2010-01-17 23:54:15 +0100
  remove comment headers 
  r8404 at Thesaurus (orig r8391):  caelum | 2010-01-20 20:54:29 +0100
  minor fixups
  r8405 at Thesaurus (orig r8392):  goraxe | 2010-01-20 21:13:24 +0100
  add private types to coerce
  r8406 at Thesaurus (orig r8393):  goraxe | 2010-01-20 21:17:19 +0100
  remove un-needed coerce from schema_class of type Str
  r8411 at Thesaurus (orig r8398):  caelum | 2010-01-21 23:36:25 +0100
  minor documentation updates
  r8436 at Thesaurus (orig r8423):  caelum | 2010-01-25 02:56:30 +0100
  this code never runs anyway
  r8440 at Thesaurus (orig r8427):  caelum | 2010-01-26 14:05:53 +0100
  prefer JSON::DWIW for barekey support
  r8693 at Thesaurus (orig r8680):  ribasushi | 2010-02-13 10:27:18 +0100
  dbicadmin dependencies
  r8694 at Thesaurus (orig r8681):  ribasushi | 2010-02-13 10:28:04 +0100
  Some cleaup, make use of Text::CSV
  r8695 at Thesaurus (orig r8682):  ribasushi | 2010-02-13 10:34:19 +0100
  We use Try::Tiny in a single spot, not grounds for inlusion in deps
  r8696 at Thesaurus (orig r8683):  ribasushi | 2010-02-13 10:37:30 +0100
  POD section
  r8697 at Thesaurus (orig r8684):  ribasushi | 2010-02-13 11:05:17 +0100
  Switch tests to Optional::Deps
  r8700 at Thesaurus (orig r8687):  ribasushi | 2010-02-13 14:32:50 +0100
  Switch Admin/dbicadmin to Opt::Deps
  r8702 at Thesaurus (orig r8689):  ribasushi | 2010-02-13 14:39:24 +0100
  JSON dep is needed for Admin.pm itself
  r8703 at Thesaurus (orig r8690):  ribasushi | 2010-02-13 15:06:28 +0100
  Test fixes
  r8704 at Thesaurus (orig r8691):  ribasushi | 2010-02-13 15:13:31 +0100
  Changes
 
 r8707 at Thesaurus (orig r8694):  ribasushi | 2010-02-13 16:37:57 +0100
 Test for optional deps manager
 r8710 at Thesaurus (orig r8697):  caelum | 2010-02-14 05:22:03 +0100
 add doc on maximum cursors for SQLAnywhere
 r8711 at Thesaurus (orig r8698):  ribasushi | 2010-02-14 09:23:09 +0100
 Cleanup dependencies / Admin inheritance
 r8712 at Thesaurus (orig r8699):  ribasushi | 2010-02-14 09:28:29 +0100
 Some formatting
 r8715 at Thesaurus (orig r8702):  ribasushi | 2010-02-14 10:46:51 +0100
 This is Moose, so use CMOP
 r8720 at Thesaurus (orig r8707):  ribasushi | 2010-02-15 10:28:22 +0100
 Final POD touches
 r8721 at Thesaurus (orig r8708):  ribasushi | 2010-02-15 10:31:38 +0100
 Spellcheck (jawnsy++)
 r8722 at Thesaurus (orig r8709):  ribasushi | 2010-02-15 10:32:24 +0100
 One more
 r8723 at Thesaurus (orig r8710):  ribasushi | 2010-02-15 14:49:26 +0100
 Release 0.08119
 r8725 at Thesaurus (orig r8712):  ribasushi | 2010-02-15 14:50:56 +0100
 Bump trunl version
 r8726 at Thesaurus (orig r8713):  rafl | 2010-02-15 15:49:55 +0100
 Make sure we actually run all tests, given we're using done_testing.
 r8727 at Thesaurus (orig r8714):  rafl | 2010-02-15 15:50:01 +0100
 Make sure overriding deployment_statements is possible from within schemas.
 r8728 at Thesaurus (orig r8715):  rafl | 2010-02-15 15:56:06 +0100
 Changelogging.
 r8729 at Thesaurus (orig r8716):  rafl | 2010-02-15 15:58:09 +0100
 Make some cookbook code compile.
 r8730 at Thesaurus (orig r8717):  nuba | 2010-02-15 16:11:52 +0100
 spelling fixes in the documaentation, sholud be gud now ;)
 r8732 at Thesaurus (orig r8719):  caelum | 2010-02-16 11:09:58 +0100
 use OO interface of Hash::Merge for ::DBI::Replicated
 r8734 at Thesaurus (orig r8721):  ribasushi | 2010-02-16 11:41:06 +0100
 Augment did-author-run-makefile check to include OptDeps
 r8735 at Thesaurus (orig r8722):  ribasushi | 2010-02-16 12:16:06 +0100
 Reorg support section, add live-chat link
 r8739 at Thesaurus (orig r8726):  caelum | 2010-02-16 14:51:58 +0100
 set behavior for Hash::Merge in ::DBI::Replicated, otherwise it uses the global setting
 r8740 at Thesaurus (orig r8727):  caelum | 2010-02-16 15:43:25 +0100
 POD touchups
 r8759 at Thesaurus (orig r8746):  ribasushi | 2010-02-19 00:30:37 +0100
 Fix bogus test
 r8760 at Thesaurus (orig r8747):  ribasushi | 2010-02-19 00:34:22 +0100
 Retire useless abstraction (all rdbms need this anyway)
 r8761 at Thesaurus (orig r8748):  ribasushi | 2010-02-19 00:35:01 +0100
 Fix count of group_by over aliased function
 r8765 at Thesaurus (orig r8752):  ribasushi | 2010-02-19 10:11:20 +0100
  r8497 at Thesaurus (orig r8484):  ribasushi | 2010-01-31 10:06:29 +0100
  Branch to unify mandatory PK handling
  r8498 at Thesaurus (orig r8485):  ribasushi | 2010-01-31 10:20:36 +0100
  This is not really used for anything (same code in DBI)
  r8499 at Thesaurus (orig r8486):  ribasushi | 2010-01-31 10:25:55 +0100
  Helper primary_columns wrapper to throw if a PK is not defined
  r8500 at Thesaurus (orig r8487):  ribasushi | 2010-01-31 11:07:25 +0100
  Stupid errors
  r8501 at Thesaurus (orig r8488):  ribasushi | 2010-01-31 12:18:57 +0100
  Saner handling of nonexistent/partial conditions
  r8762 at Thesaurus (orig r8749):  ribasushi | 2010-02-19 10:07:40 +0100
  trap unresolvable conditions due to incomplete relationship specification
  r8764 at Thesaurus (orig r8751):  ribasushi | 2010-02-19 10:11:09 +0100
  Changes
 
 r8767 at Thesaurus (orig r8754):  ribasushi | 2010-02-19 11:14:30 +0100
 Fix for RT54697
 r8769 at Thesaurus (orig r8756):  caelum | 2010-02-19 12:21:53 +0100
 bump Test::Pod dep
 r8770 at Thesaurus (orig r8757):  caelum | 2010-02-19 12:23:07 +0100
 bump Test::Pod dep in Optional::Dependencies too
 r8773 at Thesaurus (orig r8760):  rabbit | 2010-02-19 16:41:24 +0100
 Fix stupid sqlt parser regression
 r8774 at Thesaurus (orig r8761):  rabbit | 2010-02-19 16:42:40 +0100
 Port remaining tests to the Opt::Dep reposiory
 r8775 at Thesaurus (orig r8762):  rabbit | 2010-02-19 16:43:36 +0100
 Some test cleanups
 r8780 at Thesaurus (orig r8767):  rabbit | 2010-02-20 20:59:20 +0100
 Test::Deep actually isn't required
 r8786 at Thesaurus (orig r8773):  rabbit | 2010-02-20 22:21:41 +0100
 These are core for perl 5.8
 r8787 at Thesaurus (orig r8774):  rabbit | 2010-02-21 10:52:40 +0100
 Shuffle tests a bit
 r8788 at Thesaurus (orig r8775):  rabbit | 2010-02-21 12:09:25 +0100
 Bogus require
 r8789 at Thesaurus (orig r8776):  rabbit | 2010-02-21 12:09:48 +0100
 Bogus unnecessary dep
 r8800 at Thesaurus (orig r8787):  rabbit | 2010-02-21 13:39:21 +0100
  r8748 at Thesaurus (orig r8735):  goraxe | 2010-02-17 23:17:15 +0100
  branch for dbicadmin pod fixes
  
  r8778 at Thesaurus (orig r8765):  goraxe | 2010-02-20 20:35:00 +0100
  add G:L:D sub classes to generate pod
  r8779 at Thesaurus (orig r8766):  goraxe | 2010-02-20 20:56:16 +0100
  dbicadmin: use subclassed G:L:D to generate some pod
  r8782 at Thesaurus (orig r8769):  goraxe | 2010-02-20 21:48:29 +0100
  adjust Makefile.pl to generate dbicadmin.pod
  r8783 at Thesaurus (orig r8770):  goraxe | 2010-02-20 21:50:55 +0100
  add svn-ignore for dbicadmin.pod
  r8784 at Thesaurus (orig r8771):  goraxe | 2010-02-20 22:01:41 +0100
  change Options to Arguments
  r8785 at Thesaurus (orig r8772):  goraxe | 2010-02-20 22:10:29 +0100
  add DBIx::Class::Admin::{Descriptive,Usage} to podcover ignore list
  r8790 at Thesaurus (orig r8777):  rabbit | 2010-02-21 12:35:38 +0100
  Cleanup the makefile regen a bit
  r8792 at Thesaurus (orig r8779):  rabbit | 2010-02-21 12:53:01 +0100
  Bah humbug
  r8793 at Thesaurus (orig r8780):  rabbit | 2010-02-21 12:55:18 +0100
  And another one
  r8797 at Thesaurus (orig r8784):  rabbit | 2010-02-21 13:32:03 +0100
  The minimal pod seems to confuse the manpage generator, commenting out for now
  r8798 at Thesaurus (orig r8785):  rabbit | 2010-02-21 13:38:03 +0100
  Add license/author to dbicadmin autogen POD
  r8799 at Thesaurus (orig r8786):  rabbit | 2010-02-21 13:38:58 +0100
  Reorder makefile author actions to make output more readable
 
 r8803 at Thesaurus (orig r8790):  ribasushi | 2010-02-21 14:24:15 +0100
 Fix exception text
 r8804 at Thesaurus (orig r8791):  ribasushi | 2010-02-21 15:14:58 +0100
 Extra testdep
 r8808 at Thesaurus (orig r8795):  caelum | 2010-02-22 20:16:07 +0100
 with_deferred_fk_checks for Oracle
 r8809 at Thesaurus (orig r8796):  rabbit | 2010-02-22 21:26:20 +0100
 Add a hidden option to dbicadmin to self-inject autogenerated POD
 r8810 at Thesaurus (orig r8797):  caelum | 2010-02-22 21:48:43 +0100
 improve with_deferred_fk_checks for Oracle, add tests
 r8812 at Thesaurus (orig r8799):  rbuels | 2010-02-22 23:09:40 +0100
 added package name to DBD::Pg warning in Pg storage driver to make it explicit where the warning is coming from
 r8815 at Thesaurus (orig r8802):  rabbit | 2010-02-23 11:21:10 +0100
 Looks like the distdir wrapping is finally taken care of
 r8818 at Thesaurus (orig r8805):  rabbit | 2010-02-23 14:05:14 +0100
 remove POD
 r8819 at Thesaurus (orig r8806):  rabbit | 2010-02-23 14:05:32 +0100
 More index exclusions
 r8821 at Thesaurus (orig r8808):  goraxe | 2010-02-23 15:00:38 +0100
 remove short options from dbicadmin
 r8822 at Thesaurus (orig r8809):  rabbit | 2010-02-23 15:15:00 +0100
 Whitespace
 r8826 at Thesaurus (orig r8813):  rabbit | 2010-02-24 09:28:43 +0100
  r8585 at Thesaurus (orig r8572):  faxm0dem | 2010-02-06 23:01:04 +0100
  sqlt::producer::oracle is now able to handle quotes correctly. Now we need to take advantage of that as currently the oracle producer capitalises everything
  r8586 at Thesaurus (orig r8573):  faxm0dem | 2010-02-06 23:03:31 +0100
  the way I thought. ribasushi suggested to override deploy(ment_statements)
  r8607 at Thesaurus (orig r8594):  faxm0dem | 2010-02-09 21:53:48 +0100
  should work now
  r8714 at Thesaurus (orig r8701):  faxm0dem | 2010-02-14 09:49:44 +0100
  oracle_version
  r8747 at Thesaurus (orig r8734):  faxm0dem | 2010-02-17 18:54:45 +0100
  still need to uc source_name if quotes off
  r8817 at Thesaurus (orig r8804):  rabbit | 2010-02-23 12:03:23 +0100
  Cleanup code (hopefully no functional changes)
  r8820 at Thesaurus (orig r8807):  rabbit | 2010-02-23 14:14:19 +0100
  Proper error message
  r8823 at Thesaurus (orig r8810):  faxm0dem | 2010-02-23 15:46:11 +0100
  Schema Object Naming Rules :
  [...]
  However, database names, global database names, and database link names are always case insensitive and are stored as uppercase.
  
  # source: http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/sql_elements008.htm
  
  r8824 at Thesaurus (orig r8811):  rabbit | 2010-02-23 16:09:36 +0100
  Changes and dep-bump
 
 r8828 at Thesaurus (orig r8815):  rabbit | 2010-02-24 09:32:53 +0100
 Changelogging
 r8829 at Thesaurus (orig r8816):  rabbit | 2010-02-24 09:37:14 +0100
 Protect dbicadmin from self-injection when not in make
 r8830 at Thesaurus (orig r8817):  rabbit | 2010-02-24 10:00:43 +0100
 Release 0.08120
 r8832 at Thesaurus (orig r8819):  rabbit | 2010-02-24 10:02:36 +0100
 Bump trunk version
 r8833 at Thesaurus (orig r8820):  goraxe | 2010-02-24 14:21:23 +0100
  do not include hidden opts in generated pod
 r8834 at Thesaurus (orig r8821):  rabbit | 2010-02-24 15:50:34 +0100
 small tool to query cpan deps
 r8835 at Thesaurus (orig r8822):  rabbit | 2010-02-26 00:22:51 +0100
 Typo
 r8849 at Thesaurus (orig r8836):  rabbit | 2010-03-01 01:32:03 +0100
 Cleanup logic in RSC
 r8850 at Thesaurus (orig r8837):  rabbit | 2010-03-01 01:36:24 +0100
 Fix incorrect placement of condition resolution failure trap
 r8851 at Thesaurus (orig r8838):  rabbit | 2010-03-01 01:37:53 +0100
 Changes
 r8855 at Thesaurus (orig r8842):  rabbit | 2010-03-01 18:04:23 +0100
 Add has_relationship proxy to row
 r8856 at Thesaurus (orig r8843):  rabbit | 2010-03-02 10:29:18 +0100
 Do not autoviv empty ENV vars
 r8857 at Thesaurus (orig r8844):  rabbit | 2010-03-02 11:09:06 +0100
 This test is identical to the one above it
 r8858 at Thesaurus (orig r8845):  rabbit | 2010-03-02 11:13:55 +0100
 Test belongs_to accessor in-memory tie
 r8859 at Thesaurus (orig r8846):  rabbit | 2010-03-02 11:35:19 +0100
 proving rafl wrong
 r8865 at Thesaurus (orig r8852):  mo | 2010-03-03 12:05:51 +0100
 Fix for SQLite to ignore the { for => ... } attribute
 r8866 at Thesaurus (orig r8853):  rabbit | 2010-03-03 12:15:22 +0100
 Fix whitespace
 r8869 at Thesaurus (orig r8856):  castaway | 2010-03-03 23:07:40 +0100
 Minor doc tweaks
 
 r8870 at Thesaurus (orig r8857):  castaway | 2010-03-03 23:33:07 +0100
 Added note+warning about how Ordered works, from steveo_aa
 
 r8900 at Thesaurus (orig r8887):  rabbit | 2010-03-04 19:11:32 +0100
 Fix identity fiasco
 r8901 at Thesaurus (orig r8888):  rjbs | 2010-03-04 19:39:54 +0100
 fix a typo in FAQ
 r8904 at Thesaurus (orig r8891):  acmoore | 2010-03-05 22:37:55 +0100
 Fix regression where SQL files with comments were not handled properly by ::Schema::Versioned.
 
 
 r8913 at Thesaurus (orig r8900):  ribasushi | 2010-03-06 12:26:10 +0100
 More checks for weird usage of _determine_driver (maint/gen-schema)
 r8916 at Thesaurus (orig r8903):  rabbit | 2010-03-06 12:30:56 +0100
  r8422 at Thesaurus (orig r8409):  ribasushi | 2010-01-22 11:14:57 +0100
  Branches for some stuff
  r8477 at Thesaurus (orig r8464):  ribasushi | 2010-01-28 12:26:40 +0100
  RT#52681
  r8478 at Thesaurus (orig r8465):  ribasushi | 2010-01-28 12:41:25 +0100
  Deprecate IC::File
  r8479 at Thesaurus (orig r8466):  ribasushi | 2010-01-28 12:41:56 +0100
  Deprecate IC::File(2)
  r8487 at Thesaurus (orig r8474):  ribasushi | 2010-01-30 13:11:18 +0100
  Draft PK explanation
  r8488 at Thesaurus (orig r8475):  frew | 2010-01-30 21:19:30 +0100
  clarify PK stuff in intro just a bit
  r8489 at Thesaurus (orig r8476):  frew | 2010-01-30 21:24:21 +0100
  no first in POD
  r8910 at Thesaurus (orig r8897):  rabbit | 2010-03-06 11:37:12 +0100
  Improve POD about PKs and why they matter
  r8912 at Thesaurus (orig r8899):  rabbit | 2010-03-06 11:42:41 +0100
  One more PODlink
  r8915 at Thesaurus (orig r8902):  rabbit | 2010-03-06 12:27:29 +0100
  Fully deprecate IC::File
 
 r8919 at Thesaurus (orig r8906):  rabbit | 2010-03-06 12:44:59 +0100
 Fix RT54063
 r8920 at Thesaurus (orig r8907):  rabbit | 2010-03-06 13:18:02 +0100
 me-- not thinking
 r8925 at Thesaurus (orig r8912):  wreis | 2010-03-06 18:51:59 +0100
 improvements for HasOne relationship validationn
 r8934 at Thesaurus (orig r8921):  rabbit | 2010-03-07 00:52:51 +0100
 Cascading delete needs a guard to remain atomic
 r8936 at Thesaurus (orig r8923):  rabbit | 2010-03-07 02:35:51 +0100
 Fix the docs for select/as
 r8937 at Thesaurus (orig r8924):  rabbit | 2010-03-07 02:58:09 +0100
 Unmark Opt::Deps experimental and add extra method as per RT55211
 r8938 at Thesaurus (orig r8925):  rabbit | 2010-03-07 03:22:08 +0100
 Switch NoTab/EOL checks to Opt::Deps
 Enable NoTab checks
 Disable EOL checks
 r8939 at Thesaurus (orig r8926):  rabbit | 2010-03-07 10:23:24 +0100
 Cleanup a bit
 r8941 at Thesaurus (orig r8928):  rabbit | 2010-03-07 11:38:35 +0100
 Fix MC bug reported by felix
 r8944 at Thesaurus (orig r8931):  caelum | 2010-03-07 11:55:06 +0100
  r23004 at hlagh (orig r8530):  moritz | 2010-02-04 07:41:29 -0500
  create branch for Storage::DBI::InterBase
  
  r23005 at hlagh (orig r8531):  moritz | 2010-02-04 07:44:02 -0500
  primitive, non-working and very specific Storage::DBI::InterBase
  r23006 at hlagh (orig r8532):  moritz | 2010-02-04 08:00:05 -0500
  [Storage::DBI::InterBase] remove cruft copied from MSSQL
  r23008 at hlagh (orig r8534):  moritz | 2010-02-04 08:34:22 -0500
  [Storage::DBI::InterBase] remove more cruft
  r23014 at hlagh (orig r8540):  caelum | 2010-02-04 10:08:27 -0500
  test file for firebird, not passing yet
  r23015 at hlagh (orig r8541):  caelum | 2010-02-04 11:24:51 -0500
  Firebird: fix test cleanup, add ODBC wrapper
  r23016 at hlagh (orig r8542):  caelum | 2010-02-04 13:18:48 -0500
  limit and better autoinc for Firebird
  r23018 at hlagh (orig r8544):  caelum | 2010-02-04 14:19:51 -0500
  override quoting columns for RETURNING in Firebird ODBC (where it doesn't work) and generate a RETURNING clause only when necessary
  r23022 at hlagh (orig r8548):  caelum | 2010-02-05 03:55:43 -0500
  fix up my Row code for non-pk autoincs, add pretty crappy DT inflation for Firebird
  r23023 at hlagh (orig r8549):  caelum | 2010-02-05 04:26:03 -0500
  rename a couple of variables
  r23024 at hlagh (orig r8550):  caelum | 2010-02-05 04:46:31 -0500
  check for both NULL and null, rename _fb_auto_incs to _auto_incs
  r23025 at hlagh (orig r8551):  caelum | 2010-02-05 05:07:14 -0500
  support autoinc PKs without is_auto_increment set
  r23047 at hlagh (orig r8570):  caelum | 2010-02-06 07:35:31 -0500
  move Firebird ODBC override for RETURNING to a SQLAHacks class
  r23048 at hlagh (orig r8571):  caelum | 2010-02-06 08:06:44 -0500
  Firebird: add POD, fix BLOB tests
  r23085 at hlagh (orig r8588):  caelum | 2010-02-08 08:26:41 -0500
  better DT inflation for Firebird and _ping
  r23087 at hlagh (orig r8590):  moritz | 2010-02-08 08:32:26 -0500
  test ->update({...}) for firebird
  r23088 at hlagh (orig r8591):  caelum | 2010-02-08 08:33:09 -0500
  test update
  r23089 at hlagh (orig r8592):  moritz | 2010-02-08 08:43:50 -0500
  use quoting in firebird tests
  r23115 at hlagh (orig r8597):  caelum | 2010-02-10 07:05:21 -0500
  default to sql dialect 3 unless overridden
  r23116 at hlagh (orig r8598):  caelum | 2010-02-10 07:42:17 -0500
  turn on ib_softcommit, savepoint tests now pass for DBD::InterBase
  r23123 at hlagh (orig r8605):  caelum | 2010-02-10 17:38:24 -0500
  fix savepoints for Firebird ODBC
  r23170 at hlagh (orig r8652):  caelum | 2010-02-11 07:27:19 -0500
  support the DATE data type for Firebird
  r23186 at hlagh (orig r8668):  caelum | 2010-02-12 14:43:20 -0500
  special bind_param_array move to make DBD::InterBase happy (RT#54561)
  r23213 at hlagh (orig r8695):  caelum | 2010-02-13 15:15:46 -0500
  fix fail in t/72pg.t related to new autoinc retrieval code in ::Row
  r23214 at hlagh (orig r8696):  caelum | 2010-02-13 15:18:27 -0500
  fix multiple cursor test
  r23246 at hlagh (orig r8728):  caelum | 2010-02-16 09:47:43 -0500
  POD fix
  r23358 at hlagh (orig r8758):  caelum | 2010-02-19 06:25:27 -0500
  s/primary_columns/_pri_cols/ for Firebird
  r23420 at hlagh (orig r8800):  rkitover | 2010-02-22 19:33:13 -0500
  don't use ib_softcommit by default
  r23496 at hlagh (orig r8841):  rkitover | 2010-03-01 04:22:19 -0500
  update POD
  r23545 at hlagh (orig r8855):  rkitover | 2010-03-03 12:59:41 -0500
  destroy cached statements in $storage->disconnect too
  r23582 at hlagh (orig r8892):  rkitover | 2010-03-05 18:06:33 -0500
  auto_nextval support for Firebird
  r23598 at hlagh (orig r8908):  rkitover | 2010-03-06 11:48:41 -0500
  remove that code for non-pk autoincs from Row, move to ::DBI::InterBase
  r23599 at hlagh (orig r8909):  rkitover | 2010-03-06 12:00:15 -0500
  remove BindType2 test class
  r23601 at hlagh (orig r8911):  rkitover | 2010-03-06 12:12:55 -0500
  cache autoinc sequence in column_info
  r23609 at hlagh (orig r8919):  rkitover | 2010-03-06 18:05:24 -0500
  remove connect_info from maint/gen-schema.pl
  r23610 at hlagh (orig r8920):  rkitover | 2010-03-06 18:15:13 -0500
  don't die on insert in firebird with no pk
  r23612 at hlagh (orig r8922):  ribasushi | 2010-03-06 19:18:46 -0500
  What I really meant
  r23619 at hlagh (orig r8929):  rkitover | 2010-03-07 05:46:04 -0500
  fix RETURNING for empty INSERT
 
 r8946 at Thesaurus (orig r8933):  caelum | 2010-03-07 12:08:00 +0100
 remove unnecessary transaction_depth check in DBI::insert_bulk
 r8963 at Thesaurus (orig r8950):  ilmari | 2010-03-09 15:06:48 +0100
 Fix POD link
 r8965 at Thesaurus (orig r8952):  hobbs | 2010-03-09 20:29:50 +0100
 Support add_columns('+colname'=>{...}) syntax to augment column definitions.
 
 r8966 at Thesaurus (orig r8953):  rabbit | 2010-03-10 09:34:38 +0100
 docpatch close RT52681
 r8974 at Thesaurus (orig r8961):  rabbit | 2010-03-11 08:08:57 +0100
 Where is my spellchecker (not that it would catch this)
 r9005 at Thesaurus (orig r8992):  caelum | 2010-03-13 00:47:40 +0100
 update Firebird docs
 r9006 at Thesaurus (orig r8993):  mo | 2010-03-13 10:03:24 +0100
 test the dynamic subclassing example
 r9008 at Thesaurus (orig r8995):  mo | 2010-03-13 13:09:59 +0100
 call inflate_result on new_result, but not from the CDBI compat layer
 r9009 at Thesaurus (orig r8996):  mo | 2010-03-13 13:37:40 +0100
 reverting 8995, was supposed to go to a branch
 r9010 at Thesaurus (orig r8997):  nigel | 2010-03-14 18:09:26 +0100
 Corrected a link to connect_info in Manual::Intro
 r9018 at Thesaurus (orig r9005):  rabbit | 2010-03-15 14:55:17 +0100
 Proper fix for RETURNING with default insert
 r9026 at Thesaurus (orig r9013):  nigel | 2010-03-15 18:36:44 +0100
 Documentation on Unicode use with DBIC
 r9027 at Thesaurus (orig r9014):  rabbit | 2010-03-16 02:55:27 +0100
 Horrible horrible rewrite of the aliastype scanner, but folks are starting to complain that their unqualified columns are making joins go away (this was the initial idea). Hopefully this code will silently die some day. /me can haz shame
 r9028 at Thesaurus (orig r9015):  rabbit | 2010-03-16 16:49:45 +0100
 Regenerate test DDL
 r9029 at Thesaurus (orig r9016):  caelum | 2010-03-16 22:01:21 +0100
 _ping for MSSQL
 r9030 at Thesaurus (orig r9017):  caelum | 2010-03-17 11:49:51 +0100
 add connect_call_use_foreign_keys for SQLite
 r9031 at Thesaurus (orig r9018):  abraxxa | 2010-03-17 16:36:13 +0100
 fixed Alexander Hartmaier's mail address
 
 r9039 at Thesaurus (orig r9026):  frew | 2010-03-18 15:59:55 +0100
 use update instead of set_columns in update_all
 r9040 at Thesaurus (orig r9027):  frew | 2010-03-18 20:53:28 +0100
 Ch Ch Ch Ch Changes!
 r9041 at Thesaurus (orig r9028):  caelum | 2010-03-19 16:03:41 +0100
 POD fixups
 r9042 at Thesaurus (orig r9029):  rabbit | 2010-03-19 18:39:02 +0100
 Fix UTF8Column out of order loading warning
 r9043 at Thesaurus (orig r9030):  rabbit | 2010-03-20 09:00:00 +0100
 Something is wrong with HRI inflation - too slow
 r9044 at Thesaurus (orig r9031):  rabbit | 2010-03-20 09:26:12 +0100
 Extend benchmark
 r9045 at Thesaurus (orig r9032):  rabbit | 2010-03-20 09:41:30 +0100
 MOAR bench
 r9048 at Thesaurus (orig r9035):  caelum | 2010-03-22 16:10:38 +0100
 redo Pg auto-columns using INSERT RETURNING
 r9049 at Thesaurus (orig r9036):  caelum | 2010-03-22 16:45:55 +0100
 move INSERT ... RETURNING code into ::DBI::InsertReturning component for Pg and Firebird
 r9050 at Thesaurus (orig r9037):  rabbit | 2010-03-22 18:03:13 +0100
 Even cleaner way of handling returning (no column interrogation in storage)
 r9051 at Thesaurus (orig r9038):  caelum | 2010-03-22 23:43:19 +0100
 update proxied methods for DBI::Replicated
 r9052 at Thesaurus (orig r9039):  caelum | 2010-03-23 06:56:12 +0100
 fix sort
 r9056 at Thesaurus (orig r9043):  rabbit | 2010-03-24 11:27:37 +0100
 A better illustration how to add relationships at runtime
 r9057 at Thesaurus (orig r9044):  rabbit | 2010-03-24 11:33:04 +0100
 Clearer 'no such rel' errors, correct exception on pkless prefetch
 r9058 at Thesaurus (orig r9045):  rabbit | 2010-03-24 11:44:50 +0100
 One missed step
 r9059 at Thesaurus (orig r9046):  ribasushi | 2010-03-24 12:11:12 +0100
 Straight_join support RT55579
 r9060 at Thesaurus (orig r9047):  rabbit | 2010-03-24 12:43:02 +0100
 bump SQLA dep
 r9061 at Thesaurus (orig r9048):  ribasushi | 2010-03-24 14:10:33 +0100
 Really fix INSERT RETURNING - simply make it a flag on the storage and keep the machinery in core
 r9062 at Thesaurus (orig r9049):  rabbit | 2010-03-24 14:30:17 +0100
 Cosmetics + changes
 r9063 at Thesaurus (orig r9050):  caelum | 2010-03-24 20:44:15 +0100
 Pg version check for can_insert_returning
 r9064 at Thesaurus (orig r9051):  caelum | 2010-03-24 21:25:24 +0100
 collect _server_info on connection
 r9065 at Thesaurus (orig r9052):  caelum | 2010-03-24 21:49:38 +0100
 s/_get_server_info/_populate_server_info/
 r9066 at Thesaurus (orig r9053):  caelum | 2010-03-25 01:24:09 +0100
 remove _get_mssql_version
 r9067 at Thesaurus (orig r9054):  caelum | 2010-03-25 06:32:51 +0100
 minor fix for SQLite version check
 r9068 at Thesaurus (orig r9055):  caelum | 2010-03-25 07:37:36 +0100
 add storage->_server_info->{dbms_ver_normalized}
 r9069 at Thesaurus (orig r9056):  caelum | 2010-03-26 09:55:46 +0100
 a couple minor Informix fixes
 r9070 at Thesaurus (orig r9057):  caelum | 2010-03-26 10:55:55 +0100
 savepoints for Informix
 r9071 at Thesaurus (orig r9058):  caelum | 2010-03-26 12:23:26 +0100
 InflateColumn::DateTime support for Informix
 r9072 at Thesaurus (orig r9059):  caelum | 2010-03-26 15:08:16 +0100
 with_deferred_fk_checks for Informix
 r9073 at Thesaurus (orig r9060):  caelum | 2010-03-26 15:28:24 +0100
 minor cleanups
 r9074 at Thesaurus (orig r9061):  castaway | 2010-03-26 21:16:44 +0100
 Added clarification of quoting to cookbook pod for sql funcs, from metaperl
 
 r9075 at Thesaurus (orig r9062):  caelum | 2010-03-27 00:12:37 +0100
 missing local
 r9076 at Thesaurus (orig r9063):  caelum | 2010-03-27 00:19:56 +0100
 move warning suppression into ::DBI::InterBase
 r9077 at Thesaurus (orig r9064):  caelum | 2010-03-27 00:30:02 +0100
 a bit cleaner warning suppression for DBD::InterBase only
 r9083 at Thesaurus (orig r9070):  rabbit | 2010-03-29 10:12:44 +0200
 pod error
 r9092 at Thesaurus (orig r9079):  boghead | 2010-04-02 22:44:32 +0200
 - Minor language cleanup in some of the Cookbook documentation
   (thanks metaperl and jester)
 - Fix the synopsis for DBIC::Storage::DBI.  ->datetime_parser returns a class,
   so you need to call a method on it in order to transform a DateTime object
 
 
 r9096 at Thesaurus (orig r9083):  ribasushi | 2010-04-05 21:53:13 +0200
 Minor test cleanups
 r9097 at Thesaurus (orig r9084):  caelum | 2010-04-05 22:08:48 +0200
 fix test count
 r9098 at Thesaurus (orig r9085):  ribasushi | 2010-04-06 05:36:04 +0200
 Fix embarassing join optimizer bug
 r9112 at Thesaurus (orig r9099):  caelum | 2010-04-07 02:13:38 +0200
 UUID support for SQL Anywhere
 r9114 at Thesaurus (orig r9101):  caelum | 2010-04-07 19:23:53 +0200
 clean up UUID stringification for SQL Anywhere
 r9115 at Thesaurus (orig r9102):  rabbit | 2010-04-08 11:36:35 +0200
 Fix utf8columns loading-order test/code (really just as POC at this point)
 r9116 at Thesaurus (orig r9103):  ribasushi | 2010-04-08 12:10:12 +0200
 Make the insert_returning capability private (and saner naming)
 r9117 at Thesaurus (orig r9104):  rabbit | 2010-04-08 12:36:06 +0200
 Refactor the version handling
 Clean up normalization wrt non-numeric version parts (i.e. mysql)
 r9118 at Thesaurus (orig r9105):  ribasushi | 2010-04-08 12:56:33 +0200
 Even safer version normalization
 r9119 at Thesaurus (orig r9106):  rabbit | 2010-04-08 13:16:19 +0200
 Changes
 r9121 at Thesaurus (orig r9108):  caelum | 2010-04-08 18:17:29 +0200
 syntax error
 r9122 at Thesaurus (orig r9109):  caelum | 2010-04-08 18:38:59 +0200
 use min dbms_version for ::Replicated
 r9123 at Thesaurus (orig r9110):  matthewt | 2010-04-08 19:19:58 +0200
 fix POD links
 r9126 at Thesaurus (orig r9113):  rabbit | 2010-04-09 13:29:38 +0200
 Test to show utf8columns being indeed broken (sqlite papers over it)
 r9127 at Thesaurus (orig r9114):  rabbit | 2010-04-09 14:16:23 +0200
 Use a sloppy but recommended fix for Test warnings
 r9128 at Thesaurus (orig r9115):  ribasushi | 2010-04-11 10:43:56 +0200
 RT 55865
 r9135 at Thesaurus (orig r9122):  frew | 2010-04-11 19:28:54 +0200
 bump SQLA dep
 r9136 at Thesaurus (orig r9123):  rabbit | 2010-04-11 19:32:20 +0200
 Warn about both UTF8Columns and ForceUTF8 when loaded improperly
 r9137 at Thesaurus (orig r9124):  rabbit | 2010-04-11 20:35:53 +0200
 Deprecate UTF8Columns with a lot of warning whistles
 r9138 at Thesaurus (orig r9125):  frew | 2010-04-11 20:51:23 +0200
 Release 0.08121
 r9139 at Thesaurus (orig r9126):  frew | 2010-04-11 20:54:43 +0200
 set version for dev users
 r9146 at Thesaurus (orig r9133):  caelum | 2010-04-12 20:23:11 +0200
 better way to find minimal dbms version in ::Replicated
 r9155 at Thesaurus (orig r9142):  rabbit | 2010-04-14 15:41:51 +0200
 Add forgotten changes
 r9156 at Thesaurus (orig r9143):  caelum | 2010-04-14 17:04:00 +0200
 support $ENV{DBI_DSN} and $ENV{DBI_DRIVER} (patch from Possum)
 r9157 at Thesaurus (orig r9144):  rabbit | 2010-04-14 17:50:58 +0200
 Fix exception message
 r9190 at Thesaurus (orig r9177):  caelum | 2010-04-15 01:41:26 +0200
 datetime millisecond precision for MSSQL
 r9200 at Thesaurus (orig r9187):  ribasushi | 2010-04-18 23:06:29 +0200
 Fix leftover tabs
 r9201 at Thesaurus (orig r9188):  castaway | 2010-04-20 08:06:26 +0200
 Warn if a class found in ResultSet/ is not a subclass of ::ResultSet
 
 r9203 at Thesaurus (orig r9190):  rbuels | 2010-04-20 21:12:22 +0200
 create_ddl_dir mkpaths its dir if necessary.  also, added storage/deploy.t as place to put deployment tests
 r9204 at Thesaurus (orig r9191):  rbuels | 2010-04-20 21:20:06 +0200
 do not croak, rbuels!  jeez.
 r9205 at Thesaurus (orig r9192):  castaway | 2010-04-21 08:03:08 +0200
 Added missing test file (oops)
 
 r9213 at Thesaurus (orig r9200):  rabbit | 2010-04-24 02:23:05 +0200
 10% speed up on quoted statement generation
 r9215 at Thesaurus (orig r9202):  rabbit | 2010-04-24 02:27:47 +0200
 Revert bogus commit
 r9216 at Thesaurus (orig r9203):  ribasushi | 2010-04-24 02:31:06 +0200
 _quote is now properly handled in SQLA
 r9217 at Thesaurus (orig r9204):  caelum | 2010-04-24 02:32:58 +0200
 add "IMPROVING PERFORMANCE" section to Cookbook
 r9231 at Thesaurus (orig r9218):  ribasushi | 2010-04-26 13:13:13 +0200
 Bump CAG and SQLA dependencies
 r9232 at Thesaurus (orig r9219):  ribasushi | 2010-04-26 15:27:38 +0200
 Bizarre fork failure
 r9233 at Thesaurus (orig r9220):  castaway | 2010-04-26 21:45:32 +0200
 Add tests using select/as to sqlahacks
 
 r9234 at Thesaurus (orig r9221):  castaway | 2010-04-26 21:49:10 +0200
 Add test for fetching related obj/col as well
 
 r9245 at Thesaurus (orig r9232):  abraxxa | 2010-04-27 15:58:56 +0200
 fixed missing ' in update_or_create with key attr example
 
 r9247 at Thesaurus (orig r9234):  ribasushi | 2010-04-27 16:53:06 +0200
 Better concurrency in test (parent blocks)
 r9248 at Thesaurus (orig r9235):  ribasushi | 2010-04-27 16:53:34 +0200
 Reformat tests/comments a bit
 r9249 at Thesaurus (orig r9236):  ribasushi | 2010-04-27 18:40:10 +0200
 Better comment
 r9250 at Thesaurus (orig r9237):  ribasushi | 2010-04-27 18:40:31 +0200
 Rename test
 r9251 at Thesaurus (orig r9238):  ribasushi | 2010-04-27 19:11:45 +0200
 Fix global destruction problems
 r9271 at Thesaurus (orig r9258):  ribasushi | 2010-04-28 11:10:00 +0200
 Refactor SQLA/select interaction (in reality just cleanup)
 r9272 at Thesaurus (orig r9259):  caelum | 2010-04-28 11:20:08 +0200
 update ::DBI::Replicated
 r9273 at Thesaurus (orig r9260):  caelum | 2010-04-28 12:20:01 +0200
 add _verify_pid and _verify_tid to methods that croak in ::Replicated
 r9274 at Thesaurus (orig r9261):  ribasushi | 2010-04-28 14:39:02 +0200
 Fix failing test and some warnings
 r9288 at Thesaurus (orig r9275):  rabbit | 2010-04-29 10:32:10 +0200
 Allow limit syntax change in-flight without digging into internals
 r9292 at Thesaurus (orig r9279):  castaway | 2010-04-30 12:26:52 +0200
 Argh.. committing missing test file for load_namespaces tests
 
 r9295 at Thesaurus (orig r9282):  rabbit | 2010-05-01 11:06:21 +0200
 The final version of the test
 r9309 at Thesaurus (orig r9296):  rabbit | 2010-05-04 09:44:51 +0200
 Test for RT#56257
 r9310 at Thesaurus (orig r9297):  rabbit | 2010-05-04 10:00:11 +0200
 Refactor count handling, make count-resultset attribute lists inclusive rather than exclusive (side effect - solves RT#56257
 r9318 at Thesaurus (orig r9305):  rabbit | 2010-05-05 11:49:51 +0200
  r9296 at Thesaurus (orig r9283):  ribasushi | 2010-05-01 11:51:15 +0200
  Branch to clean up various limit dialects
  r9297 at Thesaurus (orig r9284):  rabbit | 2010-05-01 11:55:04 +0200
  Preliminary version
  r9301 at Thesaurus (orig r9288):  rabbit | 2010-05-03 18:31:24 +0200
  Fix incorrect comparison
  r9302 at Thesaurus (orig r9289):  rabbit | 2010-05-03 18:32:36 +0200
  Do not add TOP prefixes to queries already containing it
  r9303 at Thesaurus (orig r9290):  rabbit | 2010-05-03 18:33:15 +0200
  Add an as selector to a prefetch subquery to aid the subselecting-limit analyzer
  r9304 at Thesaurus (orig r9291):  rabbit | 2010-05-03 18:34:49 +0200
  Rewrite mssql test to verify both types of limit dialects with and without quoting, rewrite the RNO, Top and RowNum dialects to rely on a factored out column re-aliaser
  r9305 at Thesaurus (orig r9292):  rabbit | 2010-05-03 21:06:01 +0200
  Fix Top tests, make extra col selector order consistent
  r9307 at Thesaurus (orig r9294):  ribasushi | 2010-05-04 00:50:35 +0200
  Fix test warning
  r9308 at Thesaurus (orig r9295):  ribasushi | 2010-05-04 01:04:32 +0200
  Some databases (db2) do not like leading __s - use a different weird identifier for extra selector names
  r9313 at Thesaurus (orig r9300):  rabbit | 2010-05-05 11:08:33 +0200
  Rename test
  r9314 at Thesaurus (orig r9301):  rabbit | 2010-05-05 11:11:32 +0200
  If there was no offset, there is no sense in reordering
  r9315 at Thesaurus (orig r9302):  rabbit | 2010-05-05 11:12:19 +0200
  Split and fix oracle tests
  r9317 at Thesaurus (orig r9304):  rabbit | 2010-05-05 11:49:33 +0200
  Changes
 
 r9321 at Thesaurus (orig r9308):  rabbit | 2010-05-05 13:01:35 +0200
 Changes
 r9322 at Thesaurus (orig r9309):  rabbit | 2010-05-05 13:02:39 +0200
 Fix obsucre bug with as_subselect_rs (gah wrong commit msg)
 r9323 at Thesaurus (orig r9310):  rabbit | 2010-05-05 14:56:38 +0200
 Forgotten pieces



Property changes on: DBIx-Class/0.08/branches/group_by_consistency
___________________________________________________________________
Modified: svk:merge
   - 168d5346-440b-0410-b799-f706be625ff1:/DBIx-Class-current:2207
462d4d0c-b505-0410-bf8e-ce8f877b3390:/local/bast/DBIx-Class:3159
4d5fae46-8e6a-4e08-abee-817e9fb894a2:/local/bast/DBIx-Class/0.08/branches/cookbook_fixes:7657
4d5fae46-8e6a-4e08-abee-817e9fb894a2:/local/bast/DBIx-Class/0.08/branches/prefetch_bug-unqualified_column_in_search_related_cond:7959
4d5fae46-8e6a-4e08-abee-817e9fb894a2:/local/bast/DBIx-Class/0.08/branches/resultsetcolumn_custom_columns:5160
4d5fae46-8e6a-4e08-abee-817e9fb894a2:/local/bast/DBIx-Class/0.08/branches/sqla_1.50_compat:5414
4d5fae46-8e6a-4e08-abee-817e9fb894a2:/local/bast/DBIx-Class/0.08/branches/void_populate_resultset_cond:7935
4d5fae46-8e6a-4e08-abee-817e9fb894a2:/local/bast/DBIx-Class/0.08/trunk:7982
9c88509d-e914-0410-b01c-b9530614cbfe:/local/DBIx-Class:32260
9c88509d-e914-0410-b01c-b9530614cbfe:/local/DBIx-Class-CDBICompat:54993
9c88509d-e914-0410-b01c-b9530614cbfe:/vendor/DBIx-Class:31122
ab17426e-7cd3-4704-a2a2-80b7c0a611bb:/local/dbic_column_attr:10946
ab17426e-7cd3-4704-a2a2-80b7c0a611bb:/local/dbic_trunk:11788
bd5ac9a7-f185-4d95-9186-dbb8b392a572:/local/os/bast/DBIx-Class/0.08/trunk:2798
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/_abandoned_but_possibly_useful/table_name_ref:7266
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/ado_mssql:7886
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/autocast:7418
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/belongs_to_null_col_fix:5244
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/cdbicompat_integration:4160
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/column_attr:5074
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/complex_join_rels:4589
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/connect_info_hash:7435
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/connected_schema_leak:8264
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/cookbook_fixes:7479
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/count_distinct:6218
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/count_rs:6741
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/create_scalarref_rt51559:8027
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/diamond_relationships:6310
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/discard_changes_replication_fix:7252
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/file_column:3920
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/fix-update-and-delete-as_query:6162
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/get_inflated_columns_rt46953:7964
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/grouped_has_many_join:7382
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/grouped_prefetch:6885
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/ic_dt_post_inflate:8517
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/informix:8434
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/is_resultset_paginated:7769
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/joined_count:6323
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/mc_fixes:6645
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/mssql_limit_regression:8278
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/mssql_money_type:7096
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/mssql_rno_pagination:8054
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/mssql_storage_minor_refactor:7210
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/mssql_top_fixes:6971
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/multi_stuff:5565
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/multicreate_fixes:7275
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/multiple_version_upgrade:8429
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/mysql_ansi:7175
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/mystery_join:6589
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/new_replication_transaction_fixup:7058
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/no_duplicate_indexes_for_pk_cols:8373
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/normalize_connect_info:8274
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/null_column_regression:8314
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/on_connect_call:6854
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/on_disconnect_do:3694
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/oracle-tweaks:6222
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/oracle_sequence:4173
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/oracle_shorten_aliases:8234
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/order_by_refactor:6475
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/parser_fk_index:4485
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/pg_unqualified_schema:7842
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/prefetch:5699
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/prefetch-group_by:7917
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/prefetch_bug-unqualified_column_in_search_related_cond:7900
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/prefetch_limit:6724
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/prefetch_pager:8431
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/prefetch_redux:7206
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/reduce_pings:7261
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/replication_dedux:4600
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/rsrc_in_storage:6577
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/rt_bug_41083:5437
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/savepoints:4223
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/search_related_prefetch:6818
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/sqla_1.50_compat:5321
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/sqlt_parser_view:8145
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/storage-ms-access:4142
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/storage-tweaks:6262
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/subclassed_rsset:5930
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/subquery:5617
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/syb_connected:6919
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/sybase:7682
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/sybase_asa:8513
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/sybase_bulk_insert:7679
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/sybase_bulkinsert_support:7796
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/sybase_computed_columns:8496
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/sybase_mssql:6125
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/sybase_refactor:7940
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/sybase_support:7797
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/table_name_ref:7132
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/top_limit_altfix:6429
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/type_aware_update:6619
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/unresolvable_prefetch:6949
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/versioned_enhancements:4125
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/versioning:4578
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/view_rels:7908
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/views:5585
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/void_populate_resultset_cond:7944
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/tags/0.08108_prerelease_please_do_not_pull_into_it:7008
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/tags/pre_0.08109_please_do_not_merge:7336
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/trunk:8561
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class-C3:318
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class-current:2222
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class-joins:173
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class-resultset:570
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/datetime:1716
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/find_compat:1855
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/find_unique_query_fixes:2142
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/inflate:1988
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/many_to_many:2025
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/re_refactor_bugfix:1944
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/reorganize_tests:1827
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/resultset-new-refactor:1766
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/resultset_2_electric_boogaloo:2175
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/resultset_cleanup:2102
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/sqlt_tests_refactor:2043
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/trunk/DBIx-Class:3606
fe160bb6-dc1c-0410-9f2b-d64a711b54a5:/local/DBIC-trunk-0.08:10510
   + 168d5346-440b-0410-b799-f706be625ff1:/DBIx-Class-current:2207
462d4d0c-b505-0410-bf8e-ce8f877b3390:/local/bast/DBIx-Class:3159
4d5fae46-8e6a-4e08-abee-817e9fb894a2:/local/bast/DBIx-Class/0.08/branches/cookbook_fixes:7657
4d5fae46-8e6a-4e08-abee-817e9fb894a2:/local/bast/DBIx-Class/0.08/branches/prefetch_bug-unqualified_column_in_search_related_cond:7959
4d5fae46-8e6a-4e08-abee-817e9fb894a2:/local/bast/DBIx-Class/0.08/branches/resultsetcolumn_custom_columns:5160
4d5fae46-8e6a-4e08-abee-817e9fb894a2:/local/bast/DBIx-Class/0.08/branches/sqla_1.50_compat:5414
4d5fae46-8e6a-4e08-abee-817e9fb894a2:/local/bast/DBIx-Class/0.08/branches/void_populate_resultset_cond:7935
4d5fae46-8e6a-4e08-abee-817e9fb894a2:/local/bast/DBIx-Class/0.08/trunk:7982
9c88509d-e914-0410-b01c-b9530614cbfe:/local/DBIx-Class:32260
9c88509d-e914-0410-b01c-b9530614cbfe:/local/DBIx-Class-CDBICompat:54993
9c88509d-e914-0410-b01c-b9530614cbfe:/vendor/DBIx-Class:31122
ab17426e-7cd3-4704-a2a2-80b7c0a611bb:/local/dbic_column_attr:10946
ab17426e-7cd3-4704-a2a2-80b7c0a611bb:/local/dbic_trunk:11788
bd5ac9a7-f185-4d95-9186-dbb8b392a572:/local/os/bast/DBIx-Class/0.08/trunk:2798
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/_abandoned_but_possibly_useful/table_name_ref:7266
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/ado_mssql:7886
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/autocast:7418
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/belongs_to_null_col_fix:5244
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/cdbicompat_integration:4160
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/chaining_fixes:8626
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/column_attr:5074
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/complex_join_rels:4589
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/connect_info_hash:7435
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/connected_schema_leak:8264
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/cookbook_fixes:7479
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/count_distinct:6218
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/count_rs:6741
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/create_scalarref_rt51559:8027
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/dbicadmin_pod:8786
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/dbicadmin_refactor:8691
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/dephandling:8674
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/diamond_relationships:6310
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/discard_changes_replication_fix:7252
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/file_column:3920
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/fix-update-and-delete-as_query:6162
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/get_inflated_columns_rt46953:7964
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/grouped_has_many_join:7382
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/grouped_prefetch:6885
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/handle_all_storage_methods_in_replicated:8612
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/ic_dt_post_inflate:8517
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/informix:8434
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/is_resultset_paginated:7769
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/joined_count:6323
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/mc_fixes:6645
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/mssql_limit_regression:8278
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/mssql_money_type:7096
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/mssql_rno_pagination:8054
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/mssql_storage_minor_refactor:7210
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/mssql_top_fixes:6971
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/multi_stuff:5565
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/multicreate_fixes:7275
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/multiple_version_upgrade:8429
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/mysql_ansi:7175
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/mystery_join:6589
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/new_replication_transaction_fixup:7058
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/no_duplicate_indexes_for_pk_cols:8373
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/normalize_connect_info:8274
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/null_column_regression:8314
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/on_connect_call:6854
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/on_disconnect_do:3694
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/oracle-tweaks:6222
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/oracle_quotes:8812
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/oracle_sequence:4173
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/oracle_shorten_aliases:8234
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/order_by_refactor:6475
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/parser_fk_index:4485
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/pg_unqualified_schema:7842
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/pod_fixes:8902
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/prefetch:5699
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/prefetch-group_by:7917
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/prefetch_bug-unqualified_column_in_search_related_cond:7900
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/prefetch_limit:6724
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/prefetch_pager:8431
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/prefetch_redux:7206
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/pri_key_refactor:8751
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/reduce_pings:7261
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/replication_dedux:4600
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/rsrc_in_storage:6577
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/rt_bug_41083:5437
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/savepoints:4223
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/search_related_prefetch:6818
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/sqla_1.50_compat:5321
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/sqlt_parser_view:8145
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/storage-interbase:8929
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/storage-ms-access:4142
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/storage-tweaks:6262
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/subclassed_rsset:5930
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/subqueried_limit_fixes:9304
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/subquery:5617
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/syb_connected:6919
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/sybase:7682
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/sybase_asa:8513
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/sybase_bulk_insert:7679
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/sybase_bulkinsert_support:7796
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/sybase_computed_columns:8496
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/sybase_mssql:6125
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/sybase_refactor:7940
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/sybase_support:7797
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/table_name_ref:7132
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/top_limit_altfix:6429
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/type_aware_update:6619
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/unresolvable_prefetch:6949
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/versioned_enhancements:4125
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/versioning:4578
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/view_rels:7908
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/views:5585
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/branches/void_populate_resultset_cond:7944
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/tags/0.08108_prerelease_please_do_not_pull_into_it:7008
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/tags/pre_0.08109_please_do_not_merge:7336
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/DBIx-Class/0.08/trunk:9310
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class-C3:318
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class-current:2222
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class-joins:173
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class-resultset:570
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/datetime:1716
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/find_compat:1855
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/find_unique_query_fixes:2142
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/inflate:1988
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/many_to_many:2025
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/re_refactor_bugfix:1944
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/reorganize_tests:1827
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/resultset-new-refactor:1766
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/resultset_2_electric_boogaloo:2175
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/resultset_cleanup:2102
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/branches/DBIx-Class/sqlt_tests_refactor:2043
bd8105ee-0ff8-0310-8827-fb3f25b6796d:/trunk/DBIx-Class:3606
fe160bb6-dc1c-0410-9f2b-d64a711b54a5:/local/DBIC-trunk-0.08:10510

Modified: DBIx-Class/0.08/branches/group_by_consistency/Changes
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/Changes	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/Changes	2010-05-06 09:42:51 UTC (rev 9313)
@@ -1,5 +1,92 @@
 Revision history for DBIx::Class
 
+        - Add a warning to load_namespaces if a class in ResultSet/
+          is not a subclass of DBIx::Class::ResultSet
+        - ::Storage::DBI now correctly preserves a parent $dbh from
+          terminating children, even during interpreter-global
+          out-of-order destruction
+        - InflateColumn::DateTime support for MSSQL via DBD::Sybase
+        - Millisecond precision support for MSSQL datetimes for
+          InflateColumn::DateTime
+        - Support connecting using $ENV{DBI_DSN} and $ENV{DBI_DRIVER}
+        - current_source_alias method on ResultSet objects to
+          determine the alias to use in programatically assembled
+          search()es (originally added in 0.08100 but unmentioned)
+        - Rewrite/unification of all subselecting limit emulations
+          (RNO, Top, RowNum) to be much more robust wrt complex joined
+          resultsets
+        - MSSQL limits now don't require nearly as many applications of
+          the unsafe_subselect_ok attribute, due to optimized queries
+        - Fix as_subselect_rs to not inject resultset class-wide where
+          conditions outside of the resulting subquery
+        - Depend on optimized SQL::Abstract (faster SQL generation)
+
+0.08121 2010-04-11 18:43:00 (UTC)
+        - Support for Firebird RDBMS with DBD::InterBase and ODBC
+        - Add core support for INSERT RETURNING (for storages that
+          supports this syntax, currently PostgreSQL and Firebird)
+        - Fix spurious warnings on multiple UTF8Columns component loads
+        - DBIx::Class::UTF8Columns entered deprecated state
+        - DBIx::Class::InflateColumn::File entered deprecated state
+        - DBIx::Class::Optional::Dependencies left experimental state
+        - Add req_group_list to Opt::Deps (RT#55211)
+        - Add support for mysql-specific STRAIGHT_JOIN (RT#55579)
+        - Cascading delete/update are now wrapped in a transaction
+          for atomicity
+        - Fix accidental autovivification of ENV vars
+        - Fix update_all and delete_all to be wrapped in a transaction
+        - Fix multiple deficiencies when using MultiCreate with
+          data-encoder components (e.g. ::EncodedColumn)
+        - Fix regression where SQL files with comments were not
+          handled properly by ::Schema::Versioned.
+        - Fix regression on not properly throwing when $obj->relationship
+          is unresolvable
+        - Fix the join-optimiser to consider unqualified column names
+          whenever possible
+        - Fix an issue with multiple same-table joins confusing the join
+          optimizier
+        - Add has_relationship method to row objects
+        - Fix regression in set_column on PK-less objects
+        - Better error text on malformed/missing relationships
+        - Add POD about the significance of PK columns
+        - Fix for SQLite to ignore the (unsupported) { for => ... }
+          attribute
+        - Fix ambiguity in default directory handling of create_ddl_dir
+          (RT#54063)
+        - Support add_columns('+colname' => { ... }) to augment column
+          definitions.
+
+0.08120 2010-02-24 08:58:00 (UTC)
+        - Make sure possibly overwritten deployment_statements methods in
+          schemas get called on $schema->deploy
+        - Fix count() with group_by aliased-function resultsets
+        - with_deferred_fk_checks() Oracle support
+        - Massive refactor and cleanup of primary key handling
+        - Fixed regression losing custom result_class (really this time)
+          (RT#54697)
+        - Fixed regression in DBIC SQLT::Parser failing with a classname
+          (as opposed to a schema object)
+        - Changes to Storage::DBI::Oracle to accomodate changes in latest
+          SQL::Translator (quote handling)
+        - Make sure deployment_statements is per-storage overridable
+        - Fix dbicadmin's (lack of) POD
+
+0.08119 2010-02-15 09:36:00 (UTC)
+        - Add $rs->is_ordered to test for existing order_by on a resultset
+        - Add as_subselect_rs to DBIC::ResultSet from
+          DBIC::Helper::ResultSet::VirtualView::as_virtual_view
+        - Refactor dbicadmin adding DDL manipulation capabilities
+        - New optional dependency manager to aid extension writers
+        - Depend on newest bugfixed Moose
+        - Make resultset chaining consistent wrt selection specification
+        - Storage::DBI::Replicated cleanup
+        - Fix autoinc PKs without an autoinc flag on Sybase ASA
+
+0.08118 2010-02-08 11:53:00 (UTC)
+        - Fix a bug causing UTF8 columns not to be decoded (RT#54395)
+        - Fix bug in One->Many->One prefetch-collapse handling (RT#54039)
+        - Cleanup handling of relationship accessor types
+
 0.08117 2010-02-05 17:10:00 (UTC)
         - Perl 5.8.1 is now the minimum supported version
         - Massive optimization of the join resolution code - now joins

Modified: DBIx-Class/0.08/branches/group_by_consistency/Makefile.PL
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/Makefile.PL	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/Makefile.PL	2010-05-06 09:42:51 UTC (rev 9313)
@@ -1,149 +1,162 @@
-use inc::Module::Install 0.89;
+use inc::Module::Install 0.93;
 use strict;
 use warnings;
 use POSIX ();
 
 use 5.008001;
 
-# ****** DO NOT ADD OPTIONAL DEPENDENCIES. EVER. --mst ******
+use FindBin;
+use lib "$FindBin::Bin/lib";
 
+# adjust ENV for $AUTHOR system() calls
+use Config;
+$ENV{PERL5LIB} = join ($Config{path_sep}, @INC);
+
+
+###
+### DO NOT ADD OPTIONAL DEPENDENCIES HERE, EVEN AS recommends()
+### All of them should go to DBIx::Class::Optional::Dependencies
+###
+
 name     'DBIx-Class';
 perl_version '5.008001';
 all_from 'lib/DBIx/Class.pm';
 
+my $build_requires = {
+  'DBD::SQLite'              => '1.25',
+};
 
-test_requires 'Test::Builder'       => '0.33';
-test_requires 'Test::Deep'          => '0';
-test_requires 'Test::Exception'     => '0';
-test_requires 'Test::More'          => '0.92';
-test_requires 'Test::Warn'          => '0.21';
+my $test_requires = {
+  'File::Temp'               => '0.22',
+  'Test::Builder'            => '0.33',
+  'Test::Exception'          => '0',
+  'Test::More'               => '0.92',
+  'Test::Warn'               => '0.21',
+};
 
-test_requires 'File::Temp'          => '0.22';
+my $runtime_requires = {
+  'Carp::Clan'               => '6.0',
+  'Class::Accessor::Grouped' => '0.09003',
+  'Class::C3::Componentised' => '1.0005',
+  'Class::Inspector'         => '1.24',
+  'Data::Page'               => '2.00',
+  'DBI'                      => '1.609',
+  'MRO::Compat'              => '0.09',
+  'Module::Find'             => '0.06',
+  'Path::Class'              => '0.18',
+  'SQL::Abstract'            => '1.66',
+  'SQL::Abstract::Limit'     => '0.13',
+  'Sub::Name'                => '0.04',
+  'Data::Dumper::Concise'    => '1.000',
+  'Scope::Guard'             => '0.03',
+  'Context::Preserve'        => '0.01',
+};
 
+# this is so we can order requires alphabetically
+# copies are needed for author requires injection
+my $reqs = {
+  build_requires => { %$build_requires },
+  requires => { %$runtime_requires },
+  test_requires => { %$test_requires },
+};
 
-# Core
-requires 'List::Util'               => '0';
-requires 'Scalar::Util'             => '0';
-requires 'Storable'                 => '0';
 
-# Dependencies (keep in alphabetical order)
-requires 'Carp::Clan'               => '6.0';
-requires 'Class::Accessor::Grouped' => '0.09002';
-requires 'Class::C3::Componentised' => '1.0005';
-requires 'Class::Inspector'         => '1.24';
-requires 'Data::Page'               => '2.00';
-requires 'DBD::SQLite'              => '1.25';
-requires 'DBI'                      => '1.609';
-requires 'JSON::Any'                => '1.18';
-requires 'MRO::Compat'              => '0.09';
-requires 'Module::Find'             => '0.06';
-requires 'Path::Class'              => '0.16';
-requires 'Scope::Guard'             => '0.03';
-requires 'SQL::Abstract'            => '1.61';
-requires 'SQL::Abstract::Limit'     => '0.13';
-requires 'Sub::Name'                => '0.04';
-requires 'Data::Dumper::Concise'    => '1.000';
+# require extra modules for testing if we're in a checkout
+if ($Module::Install::AUTHOR) {
+  warn <<'EOW';
+******************************************************************************
+******************************************************************************
+***                                                                        ***
+*** AUTHOR MODE: all optional test dependencies converted to hard requires ***
+***                                                                        ***
+******************************************************************************
+******************************************************************************
 
-my %replication_requires = (
-  'Moose',                    => '0.90',
-  'MooseX::Types',            => '0.21',
-  'namespace::clean'          => '0.11',
-  'Hash::Merge',              => '0.11',
-);
+EOW
 
-#************************************************************************#
-# Make *ABSOLUTELY SURE* that nothing on this list is a real require,    #
-# since every module listed in %force_requires_if_author is deleted      #
-# from the final META.yml (thus will never make it as a CPAN dependency) #
-#************************************************************************#
-my %force_requires_if_author = (
-  %replication_requires,
+  require DBIx::Class::Optional::Dependencies;
+  $reqs->{test_requires} = {
+    %{$reqs->{test_requires}},
+    map { %$_ } (values %{DBIx::Class::Optional::Dependencies->req_group_list}),
+  };
+}
 
-  # when changing also adjust $DBIx::Class::Storage::DBI::minimum_sqlt_version
-  'SQL::Translator'           => '0.11002',
+# compose final req list, for alphabetical ordering
+my %final_req;
+for my $rtype (keys %$reqs) {
+  for my $mod (keys %{$reqs->{$rtype}} ) {
 
-#  'Module::Install::Pod::Inherit' => '0.01',
+    # sanity check req duplications
+    if ($final_req{$mod}) {
+      die "$mod specified as both a '$rtype' and a '$final_req{$mod}[0]'\n";
+    }
 
-  # when changing also adjust version in t/02pod.t
-  'Test::Pod'                 => '1.26',
+    $final_req{$mod} = [ $rtype, $reqs->{$rtype}{$mod}||0 ],
+  }
+}
 
-  # when changing also adjust version in t/06notabs.t
-#  'Test::NoTabs'              => '0.9',
+# actual require
+for my $mod (sort keys %final_req) {
+  my ($rtype, $ver) = @{$final_req{$mod}};
+  no strict 'refs';
+  $rtype->($mod, $ver);
+}
 
-  # when changing also adjust version in t/07eol.t
-#  'Test::EOL'                 => '0.6',
+auto_install();
 
-  # when changing also adjust version in t/03podcoverage.t
-  'Test::Pod::Coverage'       => '1.08',
-  'Pod::Coverage'             => '0.20',
+# re-create various autogenerated documentation bits
+if ($Module::Install::AUTHOR) {
 
-  # CDBI-compat related
-  'DBIx::ContextualFetch'     => '0',
-  'Class::DBI::Plugin::DeepAbstractSearch' => '0',
-  'Class::Trigger'            => '0',
-  'Time::Piece::MySQL'        => '0',
-  'Clone'                     => '0',
-  'Date::Simple'              => '3.03',
+  print "Regenerating README\n";
+  system('pod2text lib/DBIx/Class.pm > README');
 
-  # t/52cycle.t
-  'Test::Memory::Cycle'       => '0',
-  'Devel::Cycle'              => '1.10',
+  if (-f 'MANIFEST') {
+    print "Removing MANIFEST\n";
+    unlink 'MANIFEST';
+  }
 
-  # t/36datetime.t
-  # t/60core.t
-  'DateTime::Format::SQLite'  => '0',
+  print "Regenerating Optional/Dependencies.pod\n";
+  require DBIx::Class::Optional::Dependencies;
+  DBIx::Class::Optional::Dependencies->_gen_pod;
 
-  # t/96_is_deteministic_value.t
-  'DateTime::Format::Strptime'=> '0',
+  # FIXME Disabled due to unsolved issues, ask theorbtwo
+  #  require Module::Install::Pod::Inherit;
+  #  PodInherit();
+}
 
-  # database-dependent reqs
-  #
-  $ENV{DBICTEST_PG_DSN}
-    ? (
-      'Sys::SigAction' => '0',
-      'DBD::Pg' => '2.009002',
-      'DateTime::Format::Pg' => '0',
-    ) : ()
-  ,
+tests_recursive (qw|
+    t
+|);
 
-  $ENV{DBICTEST_MYSQL_DSN}
-    ? (
-      'DateTime::Format::MySQL' => '0',
-    ) : ()
-  ,
+install_script (qw|
+    script/dbicadmin
+|);
 
-  $ENV{DBICTEST_ORA_DSN}
-    ? (
-      'DateTime::Format::Oracle' => '0',
-    ) : ()
-  ,
 
-  $ENV{DBICTEST_SYBASE_DSN}
-    ? (
-      'DateTime::Format::Sybase' => 0,
-    ) : ()
-  ,
-  grep $_, @ENV{qw/DBICTEST_SYBASE_ASA_DSN DBICTEST_SYBASE_ASA_ODBC_DSN/}
-    ? (
-      'DateTime::Format::Strptime' => 0,
-    ) : ()
-  ,
-);
-#************************************************************************#
-# Make ABSOLUTELY SURE that nothing on the list above is a real require, #
-# since every module listed in %force_requires_if_author is deleted      #
-# from the final META.yml (thus will never make it as a CPAN dependency) #
-#************************************************************************#
+### Mangle makefile - read the comments for more info
+#
+postamble <<"EOP";
 
+# This will add an extra dep-spec for the distdir target,
+# which `make` will fold together in a first-come first-serve
+# fashion. What we do here is essentially adding extra
+# commands to execute once the distdir is assembled (via
+# create_distdir), but before control is returned to a higher
+# calling rule.
+distdir : dbicadmin_pod_inject
 
-install_script (qw|
-    script/dbicadmin
-|);
+# The pod self-injection code is in fact a hidden option in
+# dbicadmin itself
+dbicadmin_pod_inject :
+\tcd \$(DISTVNAME) && \$(ABSPERL) -Ilib script/dbicadmin --selfinject-pod
 
-tests_recursive (qw|
-    t
-|);
+# Regenerate manifest before running create_distdir.
+create_distdir : manifest
 
+EOP
+
+
+
 resources 'IRC'         => 'irc://irc.perl.org/#dbix-class';
 resources 'license'     => 'http://dev.perl.org/licenses/';
 resources 'repository'  => 'http://dev.catalyst.perl.org/repos/bast/DBIx-Class/';
@@ -151,54 +164,29 @@
 
 # Deprecated/internal modules need no exposure
 no_index directory => $_ for (qw|
+  lib/DBIx/Class/Admin
   lib/DBIx/Class/SQLAHacks
   lib/DBIx/Class/PK/Auto
+  lib/DBIx/Class/CDBICompat
 |);
 no_index package => $_ for (qw/
-  DBIx::Class::Storage::DBI::AmbiguousGlob
   DBIx::Class::SQLAHacks DBIx::Class::Storage::DBIHacks
 /);
 
-# re-build README and require extra modules for testing if we're in a checkout
 
-if ($Module::Install::AUTHOR) {
-  warn <<'EOW';
-******************************************************************************
-******************************************************************************
-***                                                                        ***
-*** AUTHOR MODE: all optional test dependencies converted to hard requires ***
-***                                                                        ***
-******************************************************************************
-******************************************************************************
-
-EOW
-
-  foreach my $module (sort keys %force_requires_if_author) {
-    build_requires ($module => $force_requires_if_author{$module});
-  }
-
-  print "Regenerating README\n";
-  system('pod2text lib/DBIx/Class.pm > README');
-
-  if (-f 'MANIFEST') {
-    print "Removing MANIFEST\n";
-    unlink 'MANIFEST';
-  }
-
-#  require Module::Install::Pod::Inherit;
-#  PodInherit();
-}
-
-auto_install();
-
 WriteAll();
 
+
 # Re-write META.yml to _exclude_ all forced requires (we do not want to ship this)
 if ($Module::Install::AUTHOR) {
 
+  # FIXME test_requires is not yet part of META
+  my %original_build_requires = ( %$build_requires, %$test_requires );
+
+  print "Regenerating META with author requires excluded\n";
   Meta->{values}{build_requires} = [ grep
-    { not exists $force_requires_if_author{$_->[0]} }
-    ( @{Meta->{values}{build_requires}} )
+    { exists $original_build_requires{$_->[0]} }
+   ( @{Meta->{values}{build_requires}} )
   ];
 
   Meta->write;

Added: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Admin/Descriptive.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Admin/Descriptive.pm	                        (rev 0)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Admin/Descriptive.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -0,0 +1,10 @@
+package     # hide from PAUSE
+    DBIx::Class::Admin::Descriptive;
+
+use DBIx::Class::Admin::Usage;
+
+use base 'Getopt::Long::Descriptive';
+
+sub usage_class { 'DBIx::Class::Admin::Usage'; }
+
+1;

Added: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Admin/Types.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Admin/Types.pm	                        (rev 0)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Admin/Types.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -0,0 +1,48 @@
+package # hide from PAUSE
+    DBIx::Class::Admin::Types;
+
+use MooseX::Types -declare => [qw(
+    DBICConnectInfo
+    DBICArrayRef
+    DBICHashRef
+)];
+use MooseX::Types::Moose qw/Int HashRef ArrayRef Str Any Bool/;
+use MooseX::Types::JSON qw(JSON);
+
+subtype DBICArrayRef,
+    as ArrayRef;
+
+subtype DBICHashRef,
+    as HashRef;
+
+coerce DBICArrayRef,
+  from JSON,
+  via { _json_to_data ($_) };
+
+coerce DBICHashRef,
+  from JSON,
+  via { _json_to_data($_) };
+
+subtype DBICConnectInfo,
+  as ArrayRef;
+
+coerce DBICConnectInfo,
+  from JSON,
+   via { return _json_to_data($_) } ;
+
+coerce DBICConnectInfo,
+  from Str,
+    via { return _json_to_data($_) };
+
+coerce DBICConnectInfo,
+  from HashRef,
+   via { [ $_ ] };
+
+sub _json_to_data {
+  my ($json_str) = @_;
+  my $json = JSON::Any->new(allow_barekey => 1, allow_singlequote => 1, relaxed=>1);
+  my $ret = $json->jsonToObj($json_str);
+  return $ret;
+}
+
+1;

Added: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Admin/Usage.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Admin/Usage.pm	                        (rev 0)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Admin/Usage.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -0,0 +1,79 @@
+package     # hide from PAUSE
+    DBIx::Class::Admin::Usage;
+
+
+use base 'Getopt::Long::Descriptive::Usage';
+
+use base 'Class::Accessor::Grouped';
+
+use Class::C3;
+
+__PACKAGE__->mk_group_accessors('simple', 'synopsis', 'short_description');
+
+sub prog_name {
+    Getopt::Long::Descriptive::prog_name();
+}
+
+sub set_simple {
+    my ($self,$field, $value) = @_;
+    my $prog_name = prog_name();
+    $value =~ s/%c/$prog_name/g;
+    $self->next::method($field, $value);
+}
+
+
+
+# This returns the usage formated as a pod document
+sub pod {
+  my ($self) = @_;
+  return join qq{\n}, $self->pod_leader_text, $self->pod_option_text, $self->pod_authorlic_text;
+}
+
+sub pod_leader_text {
+  my ($self) = @_;
+
+  return qq{=head1 NAME\n\n}.prog_name()." - ".$self->short_description().qq{\n\n}.
+         qq{=head1 SYNOPSIS\n\n}.$self->leader_text().qq{\n}.$self->synopsis().qq{\n\n};
+
+}
+
+sub pod_authorlic_text {
+
+  return join ("\n\n",
+    '=head1 AUTHORS',
+    'See L<DBIx::Class/CONTRIBUTORS>',
+    '=head1 LICENSE',
+    'You may distribute this code under the same terms as Perl itself',
+    '=cut',
+  );
+}
+
+
+sub pod_option_text {
+  my ($self) = @_;
+  my @options = @{ $self->{options} || [] };
+  my $string = q{};
+  return $string unless @options;
+
+  $string .= "=head1 OPTIONS\n\n=over\n\n";
+
+  foreach my $opt (@options) {
+    my $spec = $opt->{spec};
+    my $desc = $opt->{desc};
+    next if ($desc eq 'hidden');
+    if ($desc eq 'spacer') {
+        $string .= "=back\n\n=head2 $spec\n\n=cut\n\n=over\n\n";
+        next;
+    }
+
+    $spec = Getopt::Long::Descriptive->_strip_assignment($spec);
+    $string .= "=item " . join " or ", map { length > 1 ? "B<--$_>" : "B<-$_>" }
+                             split /\|/, $spec; 
+    $string .= "\n\n$desc\n\n=cut\n\n";
+
+  }
+  $string .= "=back\n\n";
+  return $string;
+}
+
+1;

Added: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Admin.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Admin.pm	                        (rev 0)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Admin.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -0,0 +1,568 @@
+package DBIx::Class::Admin;
+
+# check deps
+BEGIN {
+  use Carp::Clan qw/^DBIx::Class/;
+  use DBIx::Class;
+  croak('The following modules are required for DBIx::Class::Admin ' . DBIx::Class::Optional::Dependencies->req_missing_for ('admin') )
+    unless DBIx::Class::Optional::Dependencies->req_ok_for ('admin');
+}
+
+use Moose;
+use MooseX::Types::Moose qw/Int Str Any Bool/;
+use DBIx::Class::Admin::Types qw/DBICConnectInfo DBICHashRef/;
+use MooseX::Types::JSON qw(JSON);
+use MooseX::Types::Path::Class qw(Dir File);
+use Try::Tiny;
+use JSON::Any qw(DWIW XS JSON);
+use namespace::autoclean;
+
+=head1 NAME
+
+DBIx::Class::Admin - Administration object for schemas
+
+=head1 SYNOPSIS
+
+  $ dbicadmin --help
+
+  $ dbicadmin --schema=MyApp::Schema \
+    --connect='["dbi:SQLite:my.db", "", ""]' \
+    --deploy
+
+  $ dbicadmin --schema=MyApp::Schema --class=Employee \
+    --connect='["dbi:SQLite:my.db", "", ""]' \
+    --op=update --set='{ "name": "New_Employee" }'
+
+  use DBIx::Class::Admin;
+
+  # ddl manipulation
+  my $admin = DBIx::Class::Admin->new(
+    schema_class=> 'MY::Schema',
+    sql_dir=> $sql_dir,
+    connect_info => { dsn => $dsn, user => $user, password => $pass },
+  );
+
+  # create SQLite sql
+  $admin->create('SQLite');
+
+  # create SQL diff for an upgrade
+  $admin->create('SQLite', {} , "1.0");
+
+  # upgrade a database
+  $admin->upgrade();
+
+  # install a version for an unversioned schema
+  $admin->install("3.0");
+
+=head1 REQUIREMENTS
+
+The Admin interface has additional requirements not currently part of
+L<DBIx::Class>. See L<DBIx::Class::Optional::Dependencies> for more details.
+
+=head1 ATTRIBUTES
+
+=head2 schema_class
+
+the class of the schema to load
+
+=cut
+
+has 'schema_class' => (
+  is  => 'ro',
+  isa => Str,
+);
+
+
+=head2 schema
+
+A pre-connected schema object can be provided for manipulation
+
+=cut
+
+has 'schema' => (
+  is          => 'ro',
+  isa         => 'DBIx::Class::Schema',
+  lazy_build  => 1,
+);
+
+sub _build_schema {
+  my ($self)  = @_;
+  require Class::MOP;
+  Class::MOP::load_class($self->schema_class);
+
+  $self->connect_info->[3]->{ignore_version} =1;
+  return $self->schema_class->connect(@{$self->connect_info()} ); # ,  $self->connect_info->[3], { ignore_version => 1} );
+}
+
+
+=head2 resultset
+
+a resultset from the schema to operate on
+
+=cut
+
+has 'resultset' => (
+  is  => 'rw',
+  isa => Str,
+);
+
+
+=head2 where
+
+a hash ref or json string to be used for identifying data to manipulate
+
+=cut
+
+has 'where' => (
+  is      => 'rw',
+  isa     => DBICHashRef,
+  coerce  => 1,
+);
+
+
+=head2 set
+
+a hash ref or json string to be used for inserting or updating data
+
+=cut
+
+has 'set' => (
+  is      => 'rw',
+  isa     => DBICHashRef,
+  coerce  => 1,
+);
+
+
+=head2 attrs
+
+a hash ref or json string to be used for passing additonal info to the ->search call
+
+=cut
+
+has 'attrs' => (
+  is      => 'rw',
+  isa     => DBICHashRef,
+  coerce  => 1,
+);
+
+
+=head2 connect_info
+
+connect_info the arguments to provide to the connect call of the schema_class
+
+=cut
+
+has 'connect_info' => (
+  is          => 'ro',
+  isa         => DBICConnectInfo,
+  lazy_build  => 1,
+  coerce      => 1,
+);
+
+sub _build_connect_info {
+  my ($self) = @_;
+  return $self->_find_stanza($self->config, $self->config_stanza);
+}
+
+
+=head2 config_file
+
+config_file provide a config_file to read connect_info from, if this is provided
+config_stanze should also be provided to locate where the connect_info is in the config
+The config file should be in a format readable by Config::General
+
+=cut
+
+has config_file => (
+  is      => 'ro',
+  isa     => File,
+  coerce  => 1,
+);
+
+
+=head2 config_stanza
+
+config_stanza for use with config_file should be a '::' deliminated 'path' to the connection information
+designed for use with catalyst config files
+
+=cut
+
+has 'config_stanza' => (
+  is  => 'ro',
+  isa => Str,
+);
+
+
+=head2 config
+
+Instead of loading from a file the configuration can be provided directly as a hash ref.  Please note 
+config_stanza will still be required.
+
+=cut
+
+has config => (
+  is          => 'ro',
+  isa         => DBICHashRef,
+  lazy_build  => 1,
+);
+
+sub _build_config {
+  my ($self) = @_;
+
+  eval { require Config::Any }
+    or die ("Config::Any is required to parse the config file.\n");
+
+  my $cfg = Config::Any->load_files ( {files => [$self->config_file], use_ext =>1, flatten_to_hash=>1});
+
+  # just grab the config from the config file
+  $cfg = $cfg->{$self->config_file};
+  return $cfg;
+}
+
+
+=head2 sql_dir
+
+The location where sql ddl files should be created or found for an upgrade.
+
+=cut
+
+has 'sql_dir' => (
+  is      => 'ro',
+  isa     => Dir,
+  coerce  => 1,
+);
+
+
+=head2 version
+
+Used for install, the version which will be 'installed' in the schema
+
+=cut
+
+has version => (
+  is  => 'rw',
+  isa => Str,
+);
+
+
+=head2 preversion
+
+Previouse version of the schema to create an upgrade diff for, the full sql for that version of the sql must be in the sql_dir
+
+=cut
+
+has preversion => (
+  is  => 'rw',
+  isa => Str,
+);
+
+
+=head2 force
+
+Try and force certain operations.
+
+=cut
+
+has force => (
+  is  => 'rw',
+  isa => Bool,
+);
+
+
+=head2 quiet
+
+Be less verbose about actions
+
+=cut
+
+has quiet => (
+  is  => 'rw',
+  isa => Bool,
+);
+
+has '_confirm' => (
+  is  => 'bare',
+  isa => Bool,
+);
+
+
+=head1 METHODS
+
+=head2 create
+
+=over 4
+
+=item Arguments: $sqlt_type, \%sqlt_args, $preversion
+
+=back
+
+L<create> will generate sql for the supplied schema_class in sql_dir.  The flavour of sql to 
+generate can be controlled by suppling a sqlt_type which should be a L<SQL::Translator> name.  
+
+Arguments for L<SQL::Translator> can be supplied in the sqlt_args hashref.
+
+Optional preversion can be supplied to generate a diff to be used by upgrade.
+
+=cut
+
+sub create {
+  my ($self, $sqlt_type, $sqlt_args, $preversion) = @_;
+
+  $preversion ||= $self->preversion();
+
+  my $schema = $self->schema();
+  # create the dir if does not exist
+  $self->sql_dir->mkpath() if ( ! -d $self->sql_dir);
+
+  $schema->create_ddl_dir( $sqlt_type, (defined $schema->schema_version ? $schema->schema_version : ""), $self->sql_dir->stringify, $preversion, $sqlt_args );
+}
+
+
+=head2 upgrade
+
+=over 4
+
+=item Arguments: <none>
+
+=back
+
+upgrade will attempt to upgrade the connected database to the same version as the schema_class.
+B<MAKE SURE YOU BACKUP YOUR DB FIRST>
+
+=cut
+
+sub upgrade {
+  my ($self) = @_;
+  my $schema = $self->schema();
+  if (!$schema->get_db_version()) {
+    # schema is unversioned
+    $schema->throw_exception ("Could not determin current schema version, please either install() or deploy().\n");
+  } else {
+    my $ret = $schema->upgrade();
+    return $ret;
+  }
+}
+
+
+=head2 install
+
+=over 4
+
+=item Arguments: $version
+
+=back
+
+install is here to help when you want to move to L<DBIx::Class::Schema::Versioned> and have an existing 
+database.  install will take a version and add the version tracking tables and 'install' the version.  No 
+further ddl modification takes place.  Setting the force attribute to a true value will allow overriding of 
+already versioned databases.
+
+=cut
+
+sub install {
+  my ($self, $version) = @_;
+
+  my $schema = $self->schema();
+  $version ||= $self->version();
+  if (!$schema->get_db_version() ) {
+    # schema is unversioned
+    print "Going to install schema version\n";
+    my $ret = $schema->install($version);
+    print "retun is $ret\n";
+  }
+  elsif ($schema->get_db_version() and $self->force ) {
+    carp "Forcing install may not be a good idea";
+    if($self->_confirm() ) {
+      $self->schema->_set_db_version({ version => $version});
+    }
+  }
+  else {
+    $schema->throw_exception ("Schema already has a version. Try upgrade instead.\n");
+  }
+
+}
+
+
+=head2 deploy
+
+=over 4
+
+=item Arguments: $args
+
+=back
+
+deploy will create the schema at the connected database.  C<$args> are passed straight to 
+L<DBIx::Class::Schema/deploy>.
+
+=cut
+
+sub deploy {
+  my ($self, $args) = @_;
+  my $schema = $self->schema();
+  if (!$schema->get_db_version() ) {
+    # schema is unversioned
+    $schema->deploy( $args, $self->sql_dir)
+      or $schema->throw_exception ("Could not deploy schema.\n"); # FIXME deploy() does not return 1/0 on success/fail
+  } else {
+    $schema->throw_exception("A versioned schema has already been deployed, try upgrade instead.\n");
+  }
+}
+
+=head2 insert
+
+=over 4
+
+=item Arguments: $rs, $set
+
+=back
+
+insert takes the name of a resultset from the schema_class and a hashref of data to insert
+into that resultset
+
+=cut
+
+sub insert {
+  my ($self, $rs, $set) = @_;
+
+  $rs ||= $self->resultset();
+  $set ||= $self->set();
+  my $resultset = $self->schema->resultset($rs);
+  my $obj = $resultset->create( $set );
+  print ''.ref($resultset).' ID: '.join(',',$obj->id())."\n" if (!$self->quiet);
+}
+
+
+=head2 update
+
+=over 4
+
+=item Arguments: $rs, $set, $where
+
+=back
+
+update takes the name of a resultset from the schema_class, a hashref of data to update and
+a where hash used to form the search for the rows to update.
+
+=cut
+
+sub update {
+  my ($self, $rs, $set, $where) = @_;
+
+  $rs ||= $self->resultset();
+  $where ||= $self->where();
+  $set ||= $self->set();
+  my $resultset = $self->schema->resultset($rs);
+  $resultset = $resultset->search( ($where||{}) );
+
+  my $count = $resultset->count();
+  print "This action will modify $count ".ref($resultset)." records.\n" if (!$self->quiet);
+
+  if ( $self->force || $self->_confirm() ) {
+    $resultset->update_all( $set );
+  }
+}
+
+
+=head2 delete
+
+=over 4
+
+=item Arguments: $rs, $where, $attrs
+
+=back
+
+delete takes the name of a resultset from the schema_class, a where hashref and a attrs to pass to ->search.
+The found data is deleted and cannot be recovered.
+
+=cut
+
+sub delete {
+  my ($self, $rs, $where, $attrs) = @_;
+
+  $rs ||= $self->resultset();
+  $where ||= $self->where();
+  $attrs ||= $self->attrs();
+  my $resultset = $self->schema->resultset($rs);
+  $resultset = $resultset->search( ($where||{}), ($attrs||()) );
+
+  my $count = $resultset->count();
+  print "This action will delete $count ".ref($resultset)." records.\n" if (!$self->quiet);
+
+  if ( $self->force || $self->_confirm() ) {
+    $resultset->delete_all();
+  }
+}
+
+
+=head2 select
+
+=over 4
+
+=item Arguments: $rs, $where, $attrs
+
+=back
+
+select takes the name of a resultset from the schema_class, a where hashref and a attrs to pass to ->search. 
+The found data is returned in a array ref where the first row will be the columns list.
+
+=cut
+
+sub select {
+  my ($self, $rs, $where, $attrs) = @_;
+
+  $rs ||= $self->resultset();
+  $where ||= $self->where();
+  $attrs ||= $self->attrs();
+  my $resultset = $self->schema->resultset($rs);
+  $resultset = $resultset->search( ($where||{}), ($attrs||()) );
+
+  my @data;
+  my @columns = $resultset->result_source->columns();
+  push @data, [@columns];# 
+
+  while (my $row = $resultset->next()) {
+    my @fields;
+    foreach my $column (@columns) {
+      push( @fields, $row->get_column($column) );
+    }
+    push @data, [@fields];
+  }
+
+  return \@data;
+}
+
+sub _confirm {
+  my ($self) = @_;
+  print "Are you sure you want to do this? (type YES to confirm) \n";
+  # mainly here for testing
+  return 1 if ($self->meta->get_attribute('_confirm')->get_value($self));
+  my $response = <STDIN>;
+  return 1 if ($response=~/^YES/);
+  return;
+}
+
+sub _find_stanza {
+  my ($self, $cfg, $stanza) = @_;
+  my @path = split /::/, $stanza;
+  while (my $path = shift @path) {
+    if (exists $cfg->{$path}) {
+      $cfg = $cfg->{$path};
+    }
+    else {
+      die ("Could not find $stanza in config, $path does not seem to exist.\n");
+    }
+  }
+  return $cfg;
+}
+
+=head1 AUTHOR
+
+See L<DBIx::Class/CONTRIBUTORS>.
+
+=head1 LICENSE
+
+You may distribute this code under the same terms as Perl itself
+
+=cut
+
+1;

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/CDBICompat/AbstractSearch.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/CDBICompat/AbstractSearch.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/CDBICompat/AbstractSearch.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -10,7 +10,7 @@
 
 =head1 SYNOPSIS
 
-See DBIx::Class::CDBICompat for directions for use.
+See DBIx::Class::CDBICompat for usage directions.
 
 =head1 DESCRIPTION
 

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/CDBICompat/ColumnCase.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/CDBICompat/ColumnCase.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/CDBICompat/ColumnCase.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -25,9 +25,15 @@
 
 sub has_many {
   my ($class, $rel, $f_class, $f_key, @rest) = @_;
-  return $class->next::method($rel, $f_class, ( ref($f_key) ?
-                                                          $f_key :
-                                                          lc($f_key) ), @rest);
+  return $class->next::method(
+    $rel,
+    $f_class,
+    (ref($f_key) ?
+      $f_key :
+      lc($f_key||'')
+    ),
+    @rest
+  );
 }
 
 sub get_inflated_column {

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/CDBICompat/ColumnsAsHash.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/CDBICompat/ColumnsAsHash.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/CDBICompat/ColumnsAsHash.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -11,7 +11,7 @@
 
 =head1 SYNOPSIS
 
-See DBIx::Class::CDBICompat for directions for use.
+See DBIx::Class::CDBICompat for usage directions.
 
 =head1 DESCRIPTION
 

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/CDBICompat/Copy.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/CDBICompat/Copy.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/CDBICompat/Copy.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -12,7 +12,7 @@
 
 =head1 SYNOPSIS
 
-See DBIx::Class::CDBICompat for directions for use.
+See DBIx::Class::CDBICompat for usage directions.
 
 =head1 DESCRIPTION
 

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/CDBICompat/Iterator.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/CDBICompat/Iterator.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/CDBICompat/Iterator.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -10,7 +10,7 @@
 
 =head1 SYNOPSIS
 
-See DBIx::Class::CDBICompat for directions for use.
+See DBIx::Class::CDBICompat for usage directions.
 
 =head1 DESCRIPTION
 

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/CDBICompat.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/CDBICompat.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/CDBICompat.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -91,7 +91,7 @@
 
 =head2 Choosing Features
 
-In fact, this class is just a receipe containing all the features emulated.
+In fact, this class is just a recipe containing all the features emulated.
 If you like, you can choose which features to emulate by building your 
 own class and loading it like this:
 
@@ -145,7 +145,7 @@
 
 =item Relationships
 
-Relationships between tables (has_a, has_many...) must be delcared after all tables in the relationship have been declared.  Thus the usual CDBI idiom of declaring columns and relationships for each class together will not work.  They must instead be done like so:
+Relationships between tables (has_a, has_many...) must be declared after all tables in the relationship have been declared.  Thus the usual CDBI idiom of declaring columns and relationships for each class together will not work.  They must instead be done like so:
 
     package Foo;
     use base qw(Class::DBI);

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Componentised.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Componentised.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Componentised.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -8,36 +8,71 @@
 use Carp::Clan qw/^DBIx::Class|^Class::C3::Componentised/;
 use mro 'c3';
 
+my $warned;
+
 # this warns of subtle bugs introduced by UTF8Columns hacky handling of store_column
+# if and only if it is placed before something overriding store_column
 sub inject_base {
   my $class = shift;
-  my $target = shift;
+  my ($target, @complist) = @_;
 
-  my @present_components = (@{mro::get_linear_isa ($target)||[]});
+  # we already did load the component
+  my $keep_checking = ! (
+    $target->isa ('DBIx::Class::UTF8Columns')
+      ||
+    $target->isa ('DBIx::Class::ForceUTF8')
+  );
 
-  no strict 'refs';
-  for my $comp (reverse @_) {
+  my @target_isa;
 
-    if ($comp->isa ('DBIx::Class::UTF8Columns') ) {
-      require B;
+  while ($keep_checking && @complist) {
+
+    @target_isa = do { no strict 'refs'; @{"$target\::ISA"} }
+      unless @target_isa;
+
+    my $comp = pop @complist;
+
+    # warn here on use of either component, as we have no access to ForceUTF8,
+    # the author does not respond, and the Catalyst wiki used to recommend it
+    for (qw/DBIx::Class::UTF8Columns DBIx::Class::ForceUTF8/) {
+      if ($comp->isa ($_) ) {
+        $keep_checking = 0; # no use to check from this point on
+        carp "Use of $_ is strongly discouraged. See documentationm of DBIx::Class::UTF8Columns for more info\n"
+          unless ($warned->{UTF8Columns}++ || $ENV{DBIC_UTF8COLUMNS_OK});
+        last;
+      }
+    }
+
+    # something unset $keep_checking - we got a unicode mangler
+    if (! $keep_checking) {
+
+      my $base_store_column = do { require DBIx::Class::Row; DBIx::Class::Row->can ('store_column') };
+
       my @broken;
+      for my $existing_comp (@target_isa) {
+        my $sc = $existing_comp->can ('store_column')
+          or next;
 
-      for (@present_components) {
-        my $cref = $_->can ('store_column')
-         or next;
-        push @broken, $_ if B::svref_2object($cref)->STASH->NAME ne 'DBIx::Class::Row';
+        if ($sc ne $base_store_column) {
+          require B;
+          my $definer = B::svref_2object($sc)->STASH->NAME;
+          push @broken, ($definer eq $existing_comp)
+            ? $existing_comp
+            : "$existing_comp (via $definer)"
+          ;
+        }
       }
 
-      carp "Incorrect loading order of $comp by ${target} will affect other components overriding store_column ("
+      carp "Incorrect loading order of $comp by $target will affect other components overriding 'store_column' ("
           . join (', ', @broken)
           .'). Refer to the documentation of DBIx::Class::UTF8Columns for more info'
-       if @broken;
+        if @broken;
     }
 
-    unshift @present_components, $comp;
+    unshift @target_isa, $comp;
   }
 
-  $class->next::method($target, @_);
+  $class->next::method(@_);
 }
 
 1;

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/InflateColumn/DateTime.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/InflateColumn/DateTime.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/InflateColumn/DateTime.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -132,7 +132,7 @@
       $info->{_ic_dt_method} ||= "timestamp_without_timezone";
     } elsif ($type eq "smalldatetime") {
       $type = "datetime";
-      $info->{_ic_dt_method} ||= "datetime";
+      $info->{_ic_dt_method} ||= "smalldatetime";
     }
   }
 

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/InflateColumn/File.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/InflateColumn/File.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/InflateColumn/File.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -7,6 +7,17 @@
 use File::Copy;
 use Path::Class;
 
+use Carp::Clan qw/^DBIx::Class/;
+carp 'InflateColumn::File has entered a deprecation cycle. This component '
+    .'has a number of architectural deficiencies that can quickly drive '
+    .'your filesystem and database out of sync and is not recommended '
+    .'for further use. It will be retained for backwards '
+    .'compatibility, but no new functionality patches will be accepted. '
+    .'Please consider using the much more mature and actively maintained '
+    .'DBIx::Class::InflateColumn::FS. You can set the environment variable '
+    .'DBIC_IC_FILE_NOWARN to a true value to disable  this warning.'
+unless $ENV{DBIC_IC_FILE_NOWARN};
+
 __PACKAGE__->load_components(qw/InflateColumn/);
 
 sub register_column {
@@ -107,8 +118,18 @@
 
 =head1 NAME
 
-DBIx::Class::InflateColumn::File -  map files from the Database to the filesystem.
+DBIx::Class::InflateColumn::File -  DEPRECATED (superseded by DBIx::Class::InflateColumn::FS)
 
+=head2 Deprecation Notice
+
+ This component has a number of architectural deficiencies that can quickly
+ drive your filesystem and database out of sync and is not recommended for
+ further use. It will be retained for backwards compatibility, but no new
+ functionality patches will be accepted. Please consider using the much more
+ mature and actively supported DBIx::Class::InflateColumn::FS. You can set
+ the environment variable DBIC_IC_FILE_NOWARN to a true value to disable
+ this warning.
+
 =head1 SYNOPSIS
 
 In your L<DBIx::Class> table class:
@@ -176,7 +197,7 @@
 
 =head2 _file_column_callback ($file,$ret,$target)
 
-method made to be overridden for callback purposes.
+Method made to be overridden for callback purposes.
 
 =cut
 

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/InflateColumn.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/InflateColumn.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/InflateColumn.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -26,7 +26,7 @@
 
 It can be used, for example, to automatically convert to and from
 L<DateTime> objects for your date and time fields. There's a
-conveniece component to actually do that though, try
+convenience component to actually do that though, try
 L<DBIx::Class::InflateColumn::DateTime>.
 
 It will handle all types of references except scalar references. It
@@ -79,7 +79,8 @@
   $self->throw_exception("inflate_column needs attr hashref")
     unless ref $attrs eq 'HASH';
   $self->column_info($col)->{_inflate_info} = $attrs;
-  $self->mk_group_accessors('inflated_column' => [$self->column_info($col)->{accessor} || $col, $col]);
+  my $acc = $self->column_info($col)->{accessor};
+  $self->mk_group_accessors('inflated_column' => [ (defined $acc ? $acc : $col), $col]);
   return 1;
 }
 
@@ -113,7 +114,7 @@
 
 Fetch a column value in its inflated state.  This is directly
 analogous to L<DBIx::Class::Row/get_column> in that it only fetches a
-column already retreived from the database, and then inflates it.
+column already retrieved from the database, and then inflates it.
 Throws an exception if the column requested is not an inflated column.
 
 =cut

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Manual/Component.pod
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Manual/Component.pod	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Manual/Component.pod	2010-05-06 09:42:51 UTC (rev 9313)
@@ -106,7 +106,7 @@
 
 =head2 Experimental
 
-These components are under development, there interfaces may
+These components are under development, their interfaces may
 change, they may not work, etc.  So, use them if you want, but
 be warned.
 

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Manual/Cookbook.pod
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Manual/Cookbook.pod	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Manual/Cookbook.pod	2010-05-06 09:42:51 UTC (rev 9313)
@@ -141,7 +141,7 @@
   );
 
 ... and you'll get back a perfect L<DBIx::Class::ResultSet> (except, of course,
-that you cannot modify the rows it contains, ie. cannot call L</update>,
+that you cannot modify the rows it contains, e.g. cannot call L</update>,
 L</delete>, ...  on it).
 
 Note that you cannot have bind parameters unless is_virtual is set to true.
@@ -201,7 +201,7 @@
   # SELECT name name, LENGTH( name )
   # FROM artist
 
-Note that the C<as> attribute B<has absolutely nothing to do> with the sql
+Note that the C<as> attribute B<has absolutely nothing to do> with the SQL
 syntax C< SELECT foo AS bar > (see the documentation in 
 L<DBIx::Class::ResultSet/ATTRIBUTES>). You can control the C<AS> part of the
 generated SQL via the C<-as> field attribute as follows:
@@ -292,7 +292,7 @@
   my $count = $rs->count;
 
   # Equivalent SQL:
-  # SELECT COUNT( * ) FROM (SELECT me.name FROM artist me GROUP BY me.name) count_subq:
+  # SELECT COUNT( * ) FROM (SELECT me.name FROM artist me GROUP BY me.name) me:
 
 =head2 Grouping results
 
@@ -329,7 +329,7 @@
     artist_id => { 'IN' => $inside_rs->get_column('id')->as_query },
   });
 
-The usual operators ( =, !=, IN, NOT IN, etc) are supported.
+The usual operators ( =, !=, IN, NOT IN, etc.) are supported.
 
 B<NOTE>: You have to explicitly use '=' when doing an equality comparison.
 The following will B<not> work:
@@ -367,8 +367,8 @@
 
 =head2 Predefined searches
 
-You can write your own L<DBIx::Class::ResultSet> class by inheriting from it
-and defining often used searches as methods:
+You can define frequently used searches as methods by subclassing
+L<DBIx::Class::ResultSet>:
 
   package My::DBIC::ResultSet::CD;
   use strict;
@@ -411,10 +411,16 @@
 
 Using SQL functions on the left hand side of a comparison is generally not a
 good idea since it requires a scan of the entire table. (Unless your RDBMS
-supports indexes on expressions - including return values of functions -, and
+supports indexes on expressions - including return values of functions - and
 you create an index on the return value of the function in question.) However,
 it can be accomplished with C<DBIx::Class> when necessary.
 
+Your approach for doing so will depend on whether you have turned
+quoting on via the C<quote_char> and C<name_sep> attributes. If you
+explicitly defined C<quote_char> and C<name_sep> in your
+C<connect_info> (see L<DBIx::Class::Storage::DBI/"connect_info">) then
+you are using quoting, otherwise not.
+
 If you do not have quoting on, simply include the function in your search
 specification as you would any column:
 
@@ -771,7 +777,7 @@
 
     package My::App::Schema;
 
-    use base DBIx::Class::Schema;
+    use base 'DBIx::Class::Schema';
 
     # load subclassed classes from My::App::Schema::Result/ResultSet
     __PACKAGE__->load_namespaces;
@@ -791,7 +797,7 @@
 
     use strict;
     use warnings;
-    use base My::Shared::Model::Result::Baz;
+    use base 'My::Shared::Model::Result::Baz';
 
     # WARNING: Make sure you call table() again in your subclass,
     # otherwise DBIx::Class::ResultSourceProxy::Table will not be called
@@ -814,7 +820,7 @@
 for admin.  We would like like to give the admin users
 objects (L<DBIx::Class::Row>) the same methods as a regular user but
 also special admin only methods.  It doesn't make sense to create two
-seperate proxy-class files for this.  We would be copying all the user
+separate proxy-class files for this.  We would be copying all the user
 methods into the Admin class.  There is a cleaner way to accomplish
 this.
 
@@ -1217,6 +1223,8 @@
 
 =head1 TRANSACTIONS
 
+=head2 Transactions with txn_do
+
 As of version 0.04001, there is improved transaction support in
 L<DBIx::Class::Storage> and L<DBIx::Class::Schema>.  Here is an
 example of the recommended way to use it:
@@ -1248,11 +1256,16 @@
     deal_with_failed_transaction();
   }
 
+Note: by default C<txn_do> will re-run the coderef one more time if an
+error occurs due to client disconnection (e.g. the server is bounced).
+You need to make sure that your coderef can be invoked multiple times
+without terrible side effects.
+
 Nested transactions will work as expected. That is, only the outermost
 transaction will actually issue a commit to the $dbh, and a rollback
 at any level of any transaction will cause the entire nested
 transaction to fail.
- 
+
 =head2 Nested transactions and auto-savepoints
 
 If savepoints are supported by your RDBMS, it is possible to achieve true
@@ -1268,7 +1281,7 @@
   my $schema = MySchema->connect("dbi:Pg:dbname=my_db");
 
   # Start a transaction. Every database change from here on will only be 
-  # commited into the database if the eval block succeeds.
+  # committed into the database if the eval block succeeds.
   eval {
     $schema->txn_do(sub {
       # SQL: BEGIN WORK;
@@ -1321,7 +1334,7 @@
   };
   if ($@) {
     # There was an error while handling the $job. Rollback all changes
-    # since the transaction started, including the already commited
+    # since the transaction started, including the already committed
     # ('released') savepoints. There will be neither a new $job nor any
     # $thing entry in the database.
 
@@ -1344,9 +1357,19 @@
 the C<eval>-block around C<txn_do> fails, a rollback is issued. If the C<eval>
 succeeds, the transaction is committed (or the savepoint released).
 
-While you can get more fine-grained controll using C<svp_begin>, C<svp_release>
+While you can get more fine-grained control using C<svp_begin>, C<svp_release>
 and C<svp_rollback>, it is strongly recommended to use C<txn_do> with coderefs.
 
+=head2 Simple Transactions with DBIx::Class::Storage::TxnScopeGuard
+
+An easy way to use transactions is with
+L<DBIx::Class::Storage::TxnScopeGuard>. See L</Automatically creating
+related objects> for an example.
+
+Note that unlike txn_do, TxnScopeGuard will only make sure the connection is
+alive when issuing the C<BEGIN> statement. It will not (and really can not)
+retry if the server goes away mid-operations, unlike C<txn_do>.
+
 =head1 SQL
 
 =head2 Creating Schemas From An Existing Database
@@ -1621,10 +1644,10 @@
 Add the L<DBIx::Class::Schema::Versioned> schema component to your
 Schema class. This will add a new table to your database called
 C<dbix_class_schema_vesion> which will keep track of which version is installed
-and warn if the user trys to run a newer schema version than the
+and warn if the user tries to run a newer schema version than the
 database thinks it has.
 
-Alternatively, you can send the conversion sql scripts to your
+Alternatively, you can send the conversion SQL scripts to your
 customers as above.
 
 =head2 Setting quoting for the generated SQL
@@ -1706,7 +1729,7 @@
     }
   );
 
-In conditions (eg. C<\%cond> in the L<DBIx::Class::ResultSet/search> family of
+In conditions (e.g. C<\%cond> in the L<DBIx::Class::ResultSet/search> family of
 methods) you cannot directly use array references (since this is interpreted as
 a list of values to be C<OR>ed), but you can use the following syntax to force
 passing them as bind values:
@@ -1724,6 +1747,75 @@
 arrayrefs together with the column name, like this: C<< [column_name => value]
 >>.
 
+=head2 Using Unicode
+
+When using unicode character data there are two alternatives -
+either your database supports unicode characters (including setting
+the utf8 flag on the returned string), or you need to encode/decode
+data appropriately each time a string field is inserted into or
+retrieved from the database. It is better to avoid
+encoding/decoding data and to use your database's own unicode
+capabilities if at all possible.
+
+The L<DBIx::Class::UTF8Columns> component handles storing selected
+unicode columns in a database that does not directly support
+unicode. If used with a database that does correctly handle unicode
+then strange and unexpected data corrupt B<will> occur.
+
+The Catalyst Wiki Unicode page at
+L<http://wiki.catalystframework.org/wiki/tutorialsandhowtos/using_unicode>
+has additional information on the use of Unicode with Catalyst and
+DBIx::Class.
+
+The following databases do correctly handle unicode data:-
+
+=head3 MySQL
+
+MySQL supports unicode, and will correctly flag utf8 data from the
+database if the C<mysql_enable_utf8> is set in the connect options.
+
+  my $schema = My::Schema->connection('dbi:mysql:dbname=test',
+                                      $user, $pass,
+                                      { mysql_enable_utf8 => 1} );
+  
+
+When set, a data retrieved from a textual column type (char,
+varchar, etc) will have the UTF-8 flag turned on if necessary. This
+enables character semantics on that string. You will also need to
+ensure that your database / table / column is configured to use
+UTF8. See Chapter 10 of the mysql manual for details.
+
+See L<DBD::mysql> for further details.
+
+=head3 Oracle
+
+Information about Oracle support for unicode can be found in
+L<DBD::Oracle/Unicode>.
+
+=head3 PostgreSQL
+
+PostgreSQL supports unicode if the character set is correctly set
+at database creation time. Additionally the C<pg_enable_utf8>
+should be set to ensure unicode data is correctly marked.
+
+  my $schema = My::Schema->connection('dbi:Pg:dbname=test',
+                                      $user, $pass,
+                                      { pg_enable_utf8 => 1} );
+
+Further information can be found in L<DBD::Pg>.
+
+=head3 SQLite
+
+SQLite version 3 and above natively use unicode internally. To
+correctly mark unicode strings taken from the database, the
+C<sqlite_unicode> flag should be set at connect time (in versions
+of L<DBD::SQLite> prior to 1.27 this attribute was named
+C<unicode>).
+
+  my $schema = My::Schema->connection('dbi:SQLite:/tmp/test.db',
+                                      '', '',
+                                      { sqlite_unicode => 1} );
+
 =head1 BOOTSTRAPPING/MIGRATING
 
 =head2 Easy migration from class-based to schema-based setup
@@ -1821,13 +1913,28 @@
   sub insert {
     my ( $self, @args ) = @_;
     $self->next::method(@args);
-    $self->cds->new({})->fill_from_artist($self)->insert;
+    $self->create_related ('cds', \%initial_cd_data );
     return $self;
   }
 
-where C<fill_from_artist> is a method you specify in C<CD> which sets
-values in C<CD> based on the data in the C<Artist> object you pass in.
+If you want to wrap the two inserts in a transaction (for consistency,
+an excellent idea), you can use the awesome
+L<DBIx::Class::Storage::TxnScopeGuard>:
 
+  sub insert {
+    my ( $self, @args ) = @_;
+
+    my $guard = $self->result_source->schema->txn_scope_guard;
+
+    $self->next::method(@args);
+    $self->create_related ('cds', \%initial_cd_data );
+
+    $guard->commit;
+
+    return $self
+  }
+
+
 =head2 Wrapping/overloading a column accessor
 
 B<Problem:>
@@ -1977,6 +2084,47 @@
 statement and dig down to see if certain parameters cause aberrant behavior.
 You might want to check out L<DBIx::Class::QueryLog> as well.
 
+=head1 IMPROVING PERFORMANCE
+
+=over
+
+=item *
+
+Install L<Class::XSAccessor> to speed up L<Class::Accessor::Grouped>.
+
+=item *
+
+On Perl 5.8 install L<Class::C3::XS>.
+
+=item *
+
+L<prefetch|DBIx::Class::ResultSet/prefetch> relationships, where possible. See
+L</Using joins and prefetch>.
+
+=item *
+
+Use L<populate|DBIx::Class::ResultSet/populate> in void context to insert data
+when you don't need the resulting L<DBIx::Class::Row> objects, if possible, but
+see the caveats.
+
+When inserting many rows, for best results, populate a large number of rows at a
+time, but not so large that the table is locked for an unacceptably long time.
+
+If using L<create|DBIx::Class::ResultSet/create> instead, use a transaction and
+commit every C<X> rows; where C<X> gives you the best performance without
+locking the table for too long. 
+
+=item *
+
+When selecting many rows, if you don't need full-blown L<DBIx::Class::Row>
+objects, consider using L<DBIx::Class::ResultClass::HashRefInflator>.
+
+=item *
+
+See also L</STARTUP SPEED> and L</MEMORY USAGE> in this document.
+
+=back
+
 =head1 STARTUP SPEED
 
 L<DBIx::Class|DBIx::Class> programs can have a significant startup delay

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Manual/Example.pod
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Manual/Example.pod	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Manual/Example.pod	2010-05-06 09:42:51 UTC (rev 9313)
@@ -58,7 +58,7 @@
     title TEXT NOT NULL
   );
 
-and create the sqlite database file:
+and create the SQLite database file:
 
   sqlite3 example.db < example.sql
 
@@ -198,7 +198,7 @@
   use strict;
 
   my $schema = MyDatabase::Main->connect('dbi:SQLite:db/example.db');
-  # for other DSNs, e.g. MySql, see the perldoc for the relevant dbd
+  # for other DSNs, e.g. MySQL, see the perldoc for the relevant dbd
   # driver, e.g perldoc L<DBD::mysql>.
 
   get_tracks_by_cd('Bad');
@@ -345,7 +345,7 @@
 
 =head1 Notes
 
-A reference implentation of the database and scripts in this example
+A reference implementation of the database and scripts in this example
 are available in the main distribution for DBIx::Class under the
 directory F<t/examples/Schema>.
 

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Manual/FAQ.pod
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Manual/FAQ.pod	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Manual/FAQ.pod	2010-05-06 09:42:51 UTC (rev 9313)
@@ -56,6 +56,12 @@
 L<DBIx::Class::Schema/deploy>. See there for details, or the
 L<DBIx::Class::Manual::Cookbook>.
 
+=item .. store/retrieve Unicode data in my database?
+
+Make sure you database supports Unicode and set the connect
+attributes appropriately - see
+L<DBIx::Class::Manual::Cookbook/Using Unicode>
+
 =item .. connect to my database?
 
 Once you have created all the appropriate table/source classes, and an
@@ -126,7 +132,7 @@
 the tables are to be joined. The condition may contain as many fields
 as you like. See L<DBIx::Class::Relationship::Base>.
 
-=item .. define a relatiopnship across an intermediate table? (many-to-many)
+=item .. define a relationship across an intermediate table? (many-to-many)
 
 Read the documentation on L<DBIx::Class::Relationship/many_to_many>.
 
@@ -182,16 +188,10 @@
 
 =item .. sort my results based on fields I've aliased using C<as>?
 
-You don't. You'll need to supply the same functions/expressions to
-C<order_by>, as you did to C<select>.
+You didn't alias anything, since L<as|DBIx::Class::ResultSet/as>
+B<has nothing to do> with the produced SQL. See
+L<DBIx::Class::ResultSet/select> for details.
 
-To get "fieldname AS alias" in your SQL, you'll need to supply a
-literal chunk of SQL in your C<select> attribute, such as:
-
- ->search({}, { select => [ \'now() AS currenttime'] })
-
-Then you can use the alias in your C<order_by> attribute.
-
 =item .. group the results of my search?
 
 Supply a list of columns you want to group on, to the C<group_by>
@@ -199,16 +199,8 @@
 
 =item .. group my results based on fields I've aliased using C<as>?
 
-You don't. You'll need to supply the same functions/expressions to
-C<group_by>, as you did to C<select>.
+You don't. See the explanation on ordering by an alias above.
 
-To get "fieldname AS alias" in your SQL, you'll need to supply a
-literal chunk of SQL in your C<select> attribute, such as:
-
- ->search({}, { select => [ \'now() AS currenttime'] })
-
-Then you can use the alias in your C<group_by> attribute.
-
 =item .. filter the results of my search?
 
 The first argument to C<search> is a hashref of accessor names and
@@ -641,7 +633,7 @@
 second one will use a default port of 5433, while L<DBD::Pg> is compiled with a
 default port of 5432.
 
-You can chance the port setting in C<postgresql.conf>.
+You can change the port setting in C<postgresql.conf>.
 
 =item I've lost or forgotten my mysql password
 

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Manual/Intro.pod
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Manual/Intro.pod	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Manual/Intro.pod	2010-05-06 09:42:51 UTC (rev 9313)
@@ -114,6 +114,10 @@
   __PACKAGE__->load_components(qw/ Ordered /);
   __PACKAGE__->position_column('rank');
 
+Ordered will refer to a field called 'position' unless otherwise directed.  Here you are defining
+the ordering field to be named 'rank'.  (NOTE: Insert errors may occur if you use the Ordered 
+component, but have not defined a position column or have a 'position' field in your row.)
+
 Set the table for your class:
 
   __PACKAGE__->table('album');
@@ -225,7 +229,7 @@
 Note that L<DBIx::Class::Schema> does not cache connections for you. If you use
 multiple connections, you need to do this manually.
 
-To execute some sql statements on every connect you can add them as an option in
+To execute some SQL statements on every connect you can add them as an option in
 a special fifth argument to connect:
 
   my $another_schema = My::Schema->connect(
@@ -236,7 +240,7 @@
       { on_connect_do => \@on_connect_sql_statments }
   );
 
-See L<DBIx::Class::Schema::Storage::DBI/connect_info> for more information about
+See L<DBIx::Class::Storage::DBI/connect_info> for more information about
 this and other special C<connect>-time options.
 
 =head3 Via a database handle
@@ -397,6 +401,53 @@
 
 =head1 NOTES
 
+=head2 The Significance and Importance of Primary Keys
+
+The concept of a L<primary key|DBIx::Class::ResultSource/set_primary_key> in
+DBIx::Class warrants special discussion. The formal definition (which somewhat
+resembles that of a classic RDBMS) is I<a unique constraint that is least
+likely to change after initial row creation>. However this is where the
+similarity ends. Any time you call a CRUD operation on a row (e.g.
+L<delete|DBIx::Class::Row/delete>,
+L<update|DBIx::Class::Row/update>,
+L<discard_changes|DBIx::Class::Row/discard_changes>,
+etc.) DBIx::Class will use the values of of the
+L<primary key|DBIx::Class::ResultSource/set_primary_key> columns to populate
+the C<WHERE> clause necessary to accomplish the operation. This is why it is
+important to declare a L<primary key|DBIx::Class::ResultSource/set_primary_key>
+on all your result sources B<even if the underlying RDBMS does not have one>.
+In a pinch one can always declare each row identifiable by all its columns:
+
+ __PACKAGE__->set_primary_keys (__PACKAGE__->columns);
+
+Note that DBIx::Class is smart enough to store a copy of the PK values before
+any row-object changes take place, so even if you change the values of PK
+columns the C<WHERE> clause will remain correct.
+
+If you elect not to declare a C<primary key>, DBIx::Class will behave correctly
+by throwing exceptions on any row operation that relies on unique identifiable
+rows. If you inherited datasets with multiple identical rows in them, you can
+still operate with such sets provided you only utilize
+L<DBIx::Class::ResultSet> CRUD methods:
+L<search|DBIx::Class::ResultSet/search>,
+L<update|DBIx::Class::ResultSet/update>,
+L<delete|DBIx::Class::ResultSet/delete>
+
+For example, the following would not work (assuming C<People> does not have
+a declared PK):
+
+ my $row = $schema->resultset('People')
+                   ->search({ last_name => 'Dantes' })
+                    ->next;
+ $row->update({ children => 2 }); # <-- exception thrown because $row isn't
+                                  # necessarily unique
+
+So instead the following should be done:
+
+ $schema->resultset('People')
+         ->search({ last_name => 'Dantes' })
+          ->update({ children => 2 }); # <-- update's ALL Dantes to have children of 2
+
 =head2 Problems on RHEL5/CentOS5
 
 There used to be an issue with the system perl on Red Hat Enterprise

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Manual/Joining.pod
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Manual/Joining.pod	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Manual/Joining.pod	2010-05-06 09:42:51 UTC (rev 9313)
@@ -113,7 +113,7 @@
 
 =head2 Whole related objects
 
-To fetch entire related objects, eg CDs and all Track data, use the
+To fetch entire related objects, e.g. CDs and all Track data, use the
 'prefetch' attribute:
 
   $schema->resultset('CD')->search(
@@ -129,7 +129,7 @@
   SELECT cd.ID, cd.Title, cd.Year, tracks.id, tracks.Name, tracks.Artist FROM CD JOIN Tracks ON CD.ID = tracks.CDID WHERE cd.Title = 'Funky CD' ORDER BY 'tracks.id';
 
 The syntax of 'prefetch' is the same as 'join' and implies the
-joining, so no need to use both together.
+joining, so there is no need to use both together.
 
 =head2 Subset of related fields
 
@@ -232,7 +232,7 @@
 
 To perform joins using relations of the tables you are joining to, use
 a hashref to indicate the join depth. This can theoretically go as
-deep as you like (warning, contrived examples!): 
+deep as you like (warning: contrived examples!): 
 
   join => { room => { table => 'leg' } }
 

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Manual/Reading.pod
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Manual/Reading.pod	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Manual/Reading.pod	2010-05-06 09:42:51 UTC (rev 9313)
@@ -17,14 +17,14 @@
 Methods should be documented in the files which also contain the code
 for the method, or that file should be hidden from PAUSE completely,
 in which case the methods are documented in the file which loads
-it. Methods may also be documented and refered to in files
+it. Methods may also be documented and referred to in files
 representing the major objects or components on which they can be
 called.
 
 For example, L<DBIx::Class::Relationship> documents the methods
 actually coded in the helper relationship classes like
 DBIx::Class::Relationship::BelongsTo. The BelongsTo file itself is
-hidden from pause as it has no documentation. The accessors created by
+hidden from PAUSE as it has no documentation. The accessors created by
 relationships should be mentioned in L<DBIx::Class::Row>, the major
 object that they will be called on.
 
@@ -46,7 +46,7 @@
 what the method returns.
 
 The first item provides a list of all possible values for the
-arguments of the method in order, separated by C<, >, preceeded by the
+arguments of the method in order, separated by C<, >, preceded by the
 text "Arguments: "
 
 Example (for the belongs_to relationship):
@@ -145,10 +145,10 @@
 =item *
 
 The argument list is followed by some examples of how to use the
-method, using it's various types of arguments.
+method, using its various types of arguments.
 
 The examples can also include ways to use the results if
-applicable. For instance if the documentation is for a relationship
+applicable. For instance, if the documentation is for a relationship
 type, the examples can include how to call the resulting relation
 accessor, how to use the relation name in a search and so on.
 

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Manual/Troubleshooting.pod
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Manual/Troubleshooting.pod	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Manual/Troubleshooting.pod	2010-05-06 09:42:51 UTC (rev 9313)
@@ -23,7 +23,7 @@
 
   $schema->storage->debugfh(IO::File->new('/tmp/trace.out', 'w');
 
-Alternatively you can do this with the environment variable too:-
+Alternatively you can do this with the environment variable, too:-
 
   export DBIC_TRACE="1=/tmp/trace.out"
 
@@ -51,9 +51,8 @@
 
 There's likely a syntax error in the table class referred to elsewhere
 in this error message.  In particular make sure that the package
-declaration is correct, so for a schema C< MySchema > you need to
-specify a fully qualified namespace: C< package MySchema::MyTable; >
-for example.
+declaration is correct. For example, for a schema C< MySchema > 
+you need to specify a fully qualified namespace: C< package MySchema::MyTable; >.
 
 =head2 syntax error at or near "<something>" ...
 
@@ -103,7 +102,7 @@
 =head2 column "foo DESC" does not exist ...
 
 This can happen if you are still using the obsolete order hack, and also
-happen to turn on sql-quoting.
+happen to turn on SQL-quoting.
 
   $rs->search( {}, { order_by => [ 'name DESC' ] } );
 
@@ -133,15 +132,15 @@
   Fedora 8     - perl-5.8.8-41.fc8
   RHEL5        - perl-5.8.8-15.el5_2.1
 
-The issue is due to perl doing an exhaustive search of blessed objects
+This issue is due to perl doing an exhaustive search of blessed objects
 under certain circumstances.  The problem shows up as performance
-degredation exponential to the number of L<DBIx::Class> row objects in
-memory, so can be unoticeable with certain data sets, but with huge
+degradation exponential to the number of L<DBIx::Class> row objects in
+memory, so can be unnoticeable with certain data sets, but with huge
 performance impacts on other datasets.
 
-A pair of tests for susceptability to the issue, and performance effects
+A pair of tests for susceptibility to the issue and performance effects
 of the bless/overload problem can be found in the L<DBIx::Class> test
-suite in the file C<t/99rh_perl_perf_bug.t>
+suite, in the C<t/99rh_perl_perf_bug.t> file.
 
 Further information on this issue can be found in
 L<https://bugzilla.redhat.com/show_bug.cgi?id=379791>,
@@ -150,7 +149,7 @@
 
 =head2 Excessive Memory Allocation with TEXT/BLOB/etc. Columns and Large LongReadLen
 
-It has been observed, using L<DBD::ODBC>, that a creating a L<DBIx::Class::Row> 
+It has been observed, using L<DBD::ODBC>, that creating a L<DBIx::Class::Row> 
 object which includes a column of data type TEXT/BLOB/etc. will allocate 
 LongReadLen bytes.  This allocation does not leak, but if LongReadLen 
 is large in size, and many such row objects are created, e.g. as the 
@@ -159,5 +158,13 @@
 
 The solution is to use the smallest practical value for LongReadLen.
 
+=head2 create_ddl_dir does not produce DDL for MySQL views
+
+L<SQL::Translator> does not create DDL for MySQL views if it doesn't know you
+are using mysql version 5.000001 or higher.  To explicity set this version, add
+C<mysql_version> to the C<producer_args> in the C<%sqlt> options.
+
+  $schema->create_ddl_dir(['MySQL'], '1.0', './sql/', undef, { producer_args => { mysql_version => 5.000058 } })
+
 =cut
 


Property changes on: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Optional
___________________________________________________________________
Added: svn:ignore
   + Dependencies.pod


Added: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Optional/Dependencies.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Optional/Dependencies.pm	                        (rev 0)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Optional/Dependencies.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -0,0 +1,442 @@
+package DBIx::Class::Optional::Dependencies;
+
+use warnings;
+use strict;
+
+use Carp;
+
+# NO EXTERNAL NON-5.8.1 CORE DEPENDENCIES EVER (e.g. C::A::G)
+# This module is to be loaded by Makefile.PM on a pristine system
+
+# POD is generated automatically by calling _gen_pod from the
+# Makefile.PL in $AUTHOR mode
+
+my $moose_basic = {
+  'Moose'                      => '0.98',
+  'MooseX::Types'              => '0.21',
+};
+
+my $admin_basic = {
+  %$moose_basic,
+  'MooseX::Types::Path::Class' => '0.05',
+  'MooseX::Types::JSON'        => '0.02',
+  'JSON::Any'                  => '1.22',
+  'namespace::autoclean'       => '0.09',
+};
+
+my $reqs = {
+  dist => {
+    #'Module::Install::Pod::Inherit' => '0.01',
+  },
+
+  replicated => {
+    req => {
+      %$moose_basic,
+      'namespace::clean'          => '0.11',
+      'Hash::Merge'               => '0.12',
+    },
+    pod => {
+      title => 'Storage::Replicated',
+      desc => 'Modules required for L<DBIx::Class::Storage::DBI::Replicated>',
+    },
+  },
+
+  admin => {
+    req => {
+      %$admin_basic,
+    },
+    pod => {
+      title => 'DBIx::Class::Admin',
+      desc => 'Modules required for the DBIx::Class administrative library',
+    },
+  },
+
+  admin_script => {
+    req => {
+      %$moose_basic,
+      %$admin_basic,
+      'Getopt::Long::Descriptive' => '0.081',
+      'Text::CSV'                 => '1.16',
+    },
+    pod => {
+      title => 'dbicadmin',
+      desc => 'Modules required for the CLI DBIx::Class interface dbicadmin',
+    },
+  },
+
+  deploy => {
+    req => {
+      'SQL::Translator'           => '0.11005',
+    },
+    pod => {
+      title => 'Storage::DBI::deploy()',
+      desc => 'Modules required for L<DBIx::Class::Storage::DBI/deploy> and L<DBIx::Class::Storage::DBI/deploymen_statements>',
+    },
+  },
+
+
+  test_pod => {
+    req => {
+      'Test::Pod'                 => '1.41',
+    },
+  },
+
+  test_podcoverage => {
+    req => {
+      'Test::Pod::Coverage'       => '1.08',
+      'Pod::Coverage'             => '0.20',
+    },
+  },
+
+  test_notabs => {
+    req => {
+      'Test::NoTabs'              => '0.9',
+    },
+  },
+
+  test_eol => {
+    req => {
+      'Test::EOL'                 => '0.6',
+    },
+  },
+
+  test_cycle => {
+    req => {
+      'Test::Memory::Cycle'       => '0',
+      'Devel::Cycle'              => '1.10',
+    },
+  },
+
+  test_dtrelated => {
+    req => {
+      # t/36datetime.t
+      # t/60core.t
+      'DateTime::Format::SQLite'  => '0',
+
+      # t/96_is_deteministic_value.t
+      'DateTime::Format::Strptime'=> '0',
+
+      # t/inflate/datetime_mysql.t
+      # (doesn't need Mysql itself)
+      'DateTime::Format::MySQL' => '0',
+
+      # t/inflate/datetime_pg.t
+      # (doesn't need PG itself)
+      'DateTime::Format::Pg'  => '0',
+    },
+  },
+
+  cdbicompat => {
+    req => {
+      'DBIx::ContextualFetch'     => '0',
+      'Class::DBI::Plugin::DeepAbstractSearch' => '0',
+      'Class::Trigger'            => '0',
+      'Time::Piece::MySQL'        => '0',
+      'Clone'                     => '0',
+      'Date::Simple'              => '3.03',
+    },
+  },
+
+  rdbms_pg => {
+    req => {
+      $ENV{DBICTEST_PG_DSN}
+        ? (
+          'Sys::SigAction'        => '0',
+          'DBD::Pg'               => '2.009002',
+        ) : ()
+    },
+  },
+
+  rdbms_mysql => {
+    req => {
+      $ENV{DBICTEST_MYSQL_DSN}
+        ? (
+          'DBD::mysql'              => '0',
+        ) : ()
+    },
+  },
+
+  rdbms_oracle => {
+    req => {
+      $ENV{DBICTEST_ORA_DSN}
+        ? (
+          'DateTime::Format::Oracle' => '0',
+        ) : ()
+    },
+  },
+
+  rdbms_ase => {
+    req => {
+      $ENV{DBICTEST_SYBASE_DSN}
+        ? (
+          'DateTime::Format::Sybase' => 0,
+        ) : ()
+    },
+  },
+
+  rdbms_asa => {
+    req => {
+      (scalar grep { $ENV{$_} } (qw/DBICTEST_SYBASE_ASA_DSN DBICTEST_SYBASE_ASA_ODBC_DSN/) )
+        ? (
+          'DateTime::Format::Strptime' => 0,
+        ) : ()
+    },
+  },
+
+  rdbms_db2 => {
+    req => {
+      $ENV{DBICTEST_DB2_DSN}
+        ? (
+          'DBD::DB2' => 0,
+        ) : ()
+    },
+  },
+
+};
+
+
+sub req_list_for {
+  my ($class, $group) = @_;
+
+  croak "req_list_for() expects a requirement group name"
+    unless $group;
+
+  my $deps = $reqs->{$group}{req}
+    or croak "Requirement group '$group' does not exist";
+
+  return { %$deps };
+}
+
+
+our %req_availability_cache;
+sub req_ok_for {
+  my ($class, $group) = @_;
+
+  croak "req_ok_for() expects a requirement group name"
+    unless $group;
+
+  $class->_check_deps ($group) unless $req_availability_cache{$group};
+
+  return $req_availability_cache{$group}{status};
+}
+
+sub req_missing_for {
+  my ($class, $group) = @_;
+
+  croak "req_missing_for() expects a requirement group name"
+    unless $group;
+
+  $class->_check_deps ($group) unless $req_availability_cache{$group};
+
+  return $req_availability_cache{$group}{missing};
+}
+
+sub req_errorlist_for {
+  my ($class, $group) = @_;
+
+  croak "req_errorlist_for() expects a requirement group name"
+    unless $group;
+
+  $class->_check_deps ($group) unless $req_availability_cache{$group};
+
+  return $req_availability_cache{$group}{errorlist};
+}
+
+sub _check_deps {
+  my ($class, $group) = @_;
+
+  my $deps = $class->req_list_for ($group);
+
+  my %errors;
+  for my $mod (keys %$deps) {
+    if (my $ver = $deps->{$mod}) {
+      eval "use $mod $ver ()";
+    }
+    else {
+      eval "require $mod";
+    }
+
+    $errors{$mod} = $@ if $@;
+  }
+
+  if (keys %errors) {
+    my $missing = join (', ', map { $deps->{$_} ? "$_ >= $deps->{$_}" : $_ } (sort keys %errors) );
+    $missing .= " (see $class for details)" if $reqs->{$group}{pod};
+    $req_availability_cache{$group} = {
+      status => 0,
+      errorlist => { %errors },
+      missing => $missing,
+    };
+  }
+  else {
+    $req_availability_cache{$group} = {
+      status => 1,
+      errorlist => {},
+      missing => '',
+    };
+  }
+}
+
+sub req_group_list {
+  return { map { $_ => { %{ $reqs->{$_}{req} || {} } } } (keys %$reqs) };
+}
+
+# This is to be called by the author only (automatically in Makefile.PL)
+sub _gen_pod {
+  my $class = shift;
+  my $modfn = __PACKAGE__ . '.pm';
+  $modfn =~ s/\:\:/\//g;
+
+  require DBIx::Class;
+  my $distver = DBIx::Class->VERSION;
+  my $sqltver = $class->req_list_for ('deploy')->{'SQL::Translator'}
+    or die "Hrmm? No sqlt dep?";
+
+  my @chunks = (
+    <<"EOC",
+#########################################################################
+#####################  A U T O G E N E R A T E D ########################
+#########################################################################
+#
+# The contents of this POD file are auto-generated.  Any changes you make
+# will be lost. If you need to change the generated text edit _gen_pod()
+# at the end of $modfn
+#
+EOC
+    '=head1 NAME',
+    "$class - Optional module dependency specifications (for module authors)",
+    '=head1 SYNOPSIS',
+    <<EOS,
+Somewhere in your build-file (e.g. L<Module::Install>'s Makefile.PL):
+
+  ...
+
+  configure_requires 'DBIx::Class' => '$distver';
+
+  require $class;
+
+  my \$deploy_deps = $class->req_list_for ('deploy');
+
+  for (keys %\$deploy_deps) {
+    requires \$_ => \$deploy_deps->{\$_};
+  }
+
+  ...
+
+Note that there are some caveats regarding C<configure_requires()>, more info
+can be found at L<Module::Install/configure_requires>
+EOS
+    '=head1 DESCRIPTION',
+    <<'EOD',
+Some of the less-frequently used features of L<DBIx::Class> have external
+module dependencies on their own. In order not to burden the average user
+with modules he will never use, these optional dependencies are not included
+in the base Makefile.PL. Instead an exception with a descriptive message is
+thrown when a specific feature is missing one or several modules required for
+its operation. This module is the central holding place for  the current list
+of such dependencies, for DBIx::Class core authors, and DBIx::Class extension
+authors alike.
+EOD
+    '=head1 CURRENT REQUIREMENT GROUPS',
+    <<'EOD',
+Dependencies are organized in C<groups> and each group can list one or more
+required modules, with an optional minimum version (or 0 for any version).
+The group name can be used in the 
+EOD
+  );
+
+  for my $group (sort keys %$reqs) {
+    my $p = $reqs->{$group}{pod}
+      or next;
+
+    my $modlist = $reqs->{$group}{req}
+      or next;
+
+    next unless keys %$modlist;
+
+    push @chunks, (
+      "=head2 $p->{title}",
+      "$p->{desc}",
+      '=over',
+      ( map { "=item * $_" . ($modlist->{$_} ? " >= $modlist->{$_}" : '') } (sort keys %$modlist) ),
+      '=back',
+      "Requirement group: B<$group>",
+    );
+  }
+
+  push @chunks, (
+    '=head1 METHODS',
+    '=head2 req_group_list',
+    '=over',
+    '=item Arguments: $none',
+    '=item Returns: \%list_of_requirement_groups',
+    '=back',
+    <<EOD,
+This method should be used by DBIx::Class packagers, to get a hashref of all
+dependencies keyed by dependency group. Each key (group name) can be supplied
+to one of the group-specific methods below.
+EOD
+
+    '=head2 req_list_for',
+    '=over',
+    '=item Arguments: $group_name',
+    '=item Returns: \%list_of_module_version_pairs',
+    '=back',
+    <<EOD,
+This method should be used by DBIx::Class extension authors, to determine the
+version of modules a specific feature requires in the B<current> version of
+DBIx::Class. See the L</SYNOPSIS> for a real-world
+example.
+EOD
+
+    '=head2 req_ok_for',
+    '=over',
+    '=item Arguments: $group_name',
+    '=item Returns: 1|0',
+    '=back',
+    'Returns true or false depending on whether all modules required by C<$group_name> are present on the system and loadable',
+
+    '=head2 req_missing_for',
+    '=over',
+    '=item Arguments: $group_name',
+    '=item Returns: $error_message_string',
+    '=back',
+    <<EOD,
+Returns a single line string suitable for inclusion in larger error messages.
+This method would normally be used by DBIx::Class core-module author, to
+indicate to the user that he needs to install specific modules before he will
+be able to use a specific feature.
+
+For example if some of the requirements for C<deploy> are not available,
+the returned string could look like:
+
+ SQL::Translator >= $sqltver (see $class for details)
+
+The author is expected to prepend the necessary text to this message before
+returning the actual error seen by the user.
+EOD
+
+    '=head2 req_errorlist_for',
+    '=over',
+    '=item Arguments: $group_name',
+    '=item Returns: \%list_of_loaderrors_per_module',
+    '=back',
+    <<'EOD',
+Returns a hashref containing the actual errors that occured while attempting
+to load each module in the requirement group.
+EOD
+    '=head1 AUTHOR',
+    'See L<DBIx::Class/CONTRIBUTORS>.',
+    '=head1 LICENSE',
+    'You may distribute this code under the same terms as Perl itself',
+  );
+
+  my $fn = __FILE__;
+  $fn =~ s/\.pm$/\.pod/;
+
+  open (my $fh, '>', $fn) or croak "Unable to write to $fn: $!";
+  print $fh join ("\n\n", @chunks);
+  close ($fh);
+}
+
+1;

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Ordered.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Ordered.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Ordered.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -127,7 +127,7 @@
 This method specifies a value of L</position_column> which B<would
 never be assigned to a row> during normal operation. When
 a row is moved, its position is set to this value temporarily, so
-that any unique constrainst can not be violated. This value defaults
+that any unique constraints can not be violated. This value defaults
 to 0, which should work for all cases except when your positions do
 indeed start from 0.
 
@@ -797,15 +797,15 @@
 
     if (grep { $_ eq $position_column } ( map { @$_ } (values %{{ $rsrc->unique_constraints }} ) ) ) {
 
-        my @pcols = $rsrc->primary_columns;
+        my @pcols = $rsrc->_pri_cols;
         my $cursor = $shift_rs->search ({}, { order_by => { "-$ord", $position_column }, columns => \@pcols } )->cursor;
         my $rs = $self->result_source->resultset;
 
-        while (my @pks = $cursor->next ) {
-
+        my @all_pks = $cursor->all;
+        while (my $pks = shift @all_pks) {
           my $cond;
           for my $i (0.. $#pcols) {
-            $cond->{$pcols[$i]} = $pks[$i];
+            $cond->{$pcols[$i]} = $pks->[$i];
           }
 
           $rs->search($cond)->update ({ $position_column => \ "$position_column $op 1" } );
@@ -921,7 +921,7 @@
 triggering any of the positioning integrity code).
 
 Some day you might get confronted by datasets that have ambiguous
-positioning data (i.e. duplicate position values within the same group,
+positioning data (e.g. duplicate position values within the same group,
 in a table without unique constraints). When manually fixing such data
 keep in mind that you can not invoke L<DBIx::Class::Row/update> like
 you normally would, as it will get confused by the wrong data before
@@ -956,14 +956,14 @@
 
 =head2 Multiple Moves
 
-Be careful when issueing move_* methods to multiple objects.  If 
+Be careful when issuing move_* methods to multiple objects.  If 
 you've pre-loaded the objects then when you move one of the objects 
 the position of the other object will not reflect their new value 
 until you reload them from the database - see
 L<DBIx::Class::Row/discard_changes>.
 
 There are times when you will want to move objects as groups, such 
-as changeing the parent of several objects at once - this directly 
+as changing the parent of several objects at once - this directly 
 conflicts with this problem.  One solution is for us to write a 
 ResultSet class that supports a parent() method, for example.  Another 
 solution is to somehow automagically modify the objects that exist 

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/PK.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/PK.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/PK.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -31,13 +31,28 @@
   my ($self) = @_;
   $self->throw_exception( "Can't call id() as a class method" )
     unless ref $self;
-  my @pk = $self->_ident_values;
-  return (wantarray ? @pk : $pk[0]);
+  my @id_vals = $self->_ident_values;
+  return (wantarray ? @id_vals : $id_vals[0]);
 }
 
 sub _ident_values {
   my ($self) = @_;
-  return (map { $self->{_column_data}{$_} } $self->primary_columns);
+
+  my (@ids, @missing);
+
+  for ($self->_pri_cols) {
+    push @ids, $self->get_column($_);
+    push @missing, $_ if (! defined $ids[-1] and ! $self->has_column_loaded ($_) );
+  }
+
+  if (@missing && $self->in_storage) {
+    $self->throw_exception (
+      'Unable to uniquely identify row object with missing PK columns: '
+      . join (', ', @missing )
+    );
+  }
+
+  return @ids;
 }
 
 =head2 ID
@@ -64,12 +79,11 @@
   $self->throw_exception( "Can't call ID() as a class method" )
     unless ref $self;
   return undef unless $self->in_storage;
-  return $self->_create_ID(map { $_ => $self->{_column_data}{$_} }
-                             $self->primary_columns);
+  return $self->_create_ID(%{$self->ident_condition});
 }
 
 sub _create_ID {
-  my ($self,%vals) = @_;
+  my ($self, %vals) = @_;
   return undef unless 0 == grep { !defined } values %vals;
   return join '|', ref $self || $self, $self->result_source->name,
     map { $_ . '=' . $vals{$_} } sort keys %vals;
@@ -87,9 +101,25 @@
 
 sub ident_condition {
   my ($self, $alias) = @_;
-  my %cond;
+
+  my @pks = $self->_pri_cols;
+  my @vals = $self->_ident_values;
+
+  my (%cond, @undef);
   my $prefix = defined $alias ? $alias.'.' : '';
-  $cond{$prefix.$_} = $self->get_column($_) for $self->primary_columns;
+  for my $col (@pks) {
+    if (! defined ($cond{$prefix.$col} = shift @vals) ) {
+      push @undef, $col;
+    }
+  }
+
+  if (@undef && $self->in_storage) {
+    $self->throw_exception (
+      'Unable to construct row object identity condition due to NULL PK columns: '
+      . join (', ', @undef)
+    );
+  }
+
   return \%cond;
 }
 

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Relationship/Accessor.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Relationship/Accessor.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Relationship/Accessor.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -4,7 +4,6 @@
 use strict;
 use warnings;
 use Sub::Name ();
-use Class::Inspector ();
 
 our %_pod_inherit_config = 
   (

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Relationship/Base.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Relationship/Base.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Relationship/Base.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -30,6 +30,8 @@
 
   __PACKAGE__->add_relationship('relname', 'Foreign::Class', $cond, $attrs);
 
+=head3 condition
+
 The condition needs to be an L<SQL::Abstract>-style representation of the
 join between the tables. When resolving the condition for use in a C<JOIN>,
 keys using the pseudo-table C<foreign> are resolved to mean "the Table on the
@@ -67,10 +69,19 @@
 To add an C<OR>ed condition, use an arrayref of hashrefs. See the
 L<SQL::Abstract> documentation for more details.
 
-In addition to the
-L<standard ResultSet attributes|DBIx::Class::ResultSet/ATTRIBUTES>,
-the following attributes are also valid:
+=head3 attributes
 
+The L<standard ResultSet attributes|DBIx::Class::ResultSet/ATTRIBUTES> may
+be used as relationship attributes. In particular, the 'where' attribute is
+useful for filtering relationships:
+
+     __PACKAGE__->has_many( 'valid_users', 'MyApp::Schema::User',
+        { 'foreign.user_id' => 'self.user_id' },
+        { where => { valid => 1 } }
+    );
+
+The following attributes are also valid:
+
 =over 4
 
 =item join_type
@@ -189,13 +200,23 @@
     my $query = ((@_ > 1) ? {@_} : shift);
 
     my $source = $self->result_source;
-    my $cond = $source->_resolve_condition(
-      $rel_info->{cond}, $rel, $self
-    );
+
+    # condition resolution may fail if an incomplete master-object prefetch
+    # is encountered - that is ok during prefetch construction (not yet in_storage)
+    my $cond = eval { $source->_resolve_condition( $rel_info->{cond}, $rel, $self ) };
+    if (my $err = $@) {
+      if ($self->in_storage) {
+        $self->throw_exception ($err);
+      }
+      else {
+        $cond = $DBIx::Class::ResultSource::UNRESOLVABLE_CONDITION;
+      }
+    }
+
     if ($cond eq $DBIx::Class::ResultSource::UNRESOLVABLE_CONDITION) {
       my $reverse = $source->reverse_relationship_info($rel);
       foreach my $rev_rel (keys %$reverse) {
-        if ($reverse->{$rev_rel}{attrs}{accessor} eq 'multi') {
+        if ($reverse->{$rev_rel}{attrs}{accessor} && $reverse->{$rev_rel}{attrs}{accessor} eq 'multi') {
           $attrs->{related_objects}{$rev_rel} = [ $self ];
           Scalar::Util::weaken($attrs->{related_object}{$rev_rel}[0]);
         } else {
@@ -249,7 +270,7 @@
   ( $objects_rs ) = $rs->search_related_rs('relname', $cond, $attrs);
 
 This method works exactly the same as search_related, except that 
-it guarantees a restultset, even in list context.
+it guarantees a resultset, even in list context.
 
 =cut
 
@@ -381,7 +402,7 @@
 call set_from_related on the book.
 
 This is called internally when you pass existing objects as values to
-L<DBIx::Class::ResultSet/create>, or pass an object to a belongs_to acessor.
+L<DBIx::Class::ResultSet/create>, or pass an object to a belongs_to accessor.
 
 The columns are only set in the local copy of the object, call L</update> to
 set them in the storage.

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Relationship/BelongsTo.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Relationship/BelongsTo.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Relationship/BelongsTo.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -24,19 +24,14 @@
   # no join condition or just a column name
   if (!ref $cond) {
     $class->ensure_class_loaded($f_class);
-    my %f_primaries = map { $_ => 1 } eval { $f_class->primary_columns };
+    my %f_primaries = map { $_ => 1 } eval { $f_class->_pri_cols };
     $class->throw_exception(
-      "Can't infer join condition for ${rel} on ${class}; ".
-      "unable to load ${f_class}: $@"
+      "Can't infer join condition for ${rel} on ${class}: $@"
     ) if $@;
 
     my ($pri, $too_many) = keys %f_primaries;
     $class->throw_exception(
       "Can't infer join condition for ${rel} on ${class}; ".
-      "${f_class} has no primary keys"
-    ) unless defined $pri;
-    $class->throw_exception(
-      "Can't infer join condition for ${rel} on ${class}; ".
       "${f_class} has multiple primary keys"
     ) if $too_many;
 

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Relationship/CascadeActions.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Relationship/CascadeActions.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Relationship/CascadeActions.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -16,15 +16,24 @@
     # be handling this anyway. Assuming we have joins we probably actually
     # *could* do them, but I'd rather not.
 
-  my $ret = $self->next::method(@rest);
-
   my $source = $self->result_source;
   my %rels = map { $_ => $source->relationship_info($_) } $source->relationships;
   my @cascade = grep { $rels{$_}{attrs}{cascade_delete} } keys %rels;
-  foreach my $rel (@cascade) {
-    $self->search_related($rel)->delete_all;
+
+  if (@cascade) {
+    my $guard = $source->schema->txn_scope_guard;
+
+    my $ret = $self->next::method(@rest);
+
+    foreach my $rel (@cascade) {
+      $self->search_related($rel)->delete_all;
+    }
+
+    $guard->commit;
+    return $ret;
   }
-  return $ret;
+
+  $self->next::method(@rest);
 }
 
 sub update {
@@ -32,19 +41,31 @@
   return $self->next::method(@rest) unless ref $self;
     # Because update cascades on a class *really* don't make sense!
 
-  my $ret = $self->next::method(@rest);
-
   my $source = $self->result_source;
   my %rels = map { $_ => $source->relationship_info($_) } $source->relationships;
   my @cascade = grep { $rels{$_}{attrs}{cascade_update} } keys %rels;
-  foreach my $rel (@cascade) {
-    next if (
-      $rels{$rel}{attrs}{accessor} eq 'single'
-      && !exists($self->{_relationship_data}{$rel})
-    );
-    $_->update for grep defined, $self->$rel;
+
+  if (@cascade) {
+    my $guard = $source->schema->txn_scope_guard;
+
+    my $ret = $self->next::method(@rest);
+
+    foreach my $rel (@cascade) {
+      next if (
+        $rels{$rel}{attrs}{accessor}
+          &&
+        $rels{$rel}{attrs}{accessor} eq 'single'
+          &&
+        !exists($self->{_relationship_data}{$rel})
+      );
+      $_->update for grep defined, $self->$rel;
+    }
+
+    $guard->commit;
+    return $ret;
   }
-  return $ret;
+
+  $self->next::method(@rest);
 }
 
 1;

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Relationship/HasMany.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Relationship/HasMany.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Relationship/HasMany.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -14,7 +14,10 @@
 
   unless (ref $cond) {
     $class->ensure_class_loaded($f_class);
-    my ($pri, $too_many) = $class->primary_columns;
+    my ($pri, $too_many) = eval { $class->_pri_cols };
+    $class->throw_exception(
+      "Can't infer join condition for ${rel} on ${class}: $@"
+    ) if $@;
 
     $class->throw_exception(
       "has_many can only infer join for a single primary key; ".

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Relationship/HasOne.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Relationship/HasOne.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Relationship/HasOne.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -24,7 +24,7 @@
     $class->ensure_class_loaded($f_class);
 
     my $pri = $class->_get_primary_key;
-  
+
     $class->throw_exception(
       "might_have/has_one needs a primary key  to infer a join; ".
       "${class} has none"
@@ -47,7 +47,7 @@
     ) if $f_class_loaded && !$f_class->has_column($f_key);
     $cond = { "foreign.${f_key}" => "self.${pri}" };
   }
-  $class->_validate_cond($cond);
+  $class->_validate_has_one_condition($cond);
   $class->add_relationship($rel, $f_class,
    $cond,
    { accessor => 'single',
@@ -60,15 +60,19 @@
 sub _get_primary_key {
   my ( $class, $target_class ) = @_;
   $target_class ||= $class;
-  my ($pri, $too_many) = $target_class->primary_columns;
+  my ($pri, $too_many) = eval { $target_class->_pri_cols };
   $class->throw_exception(
+    "Can't infer join condition on ${target_class}: $@"
+  ) if $@;
+
+  $class->throw_exception(
     "might_have/has_one can only infer join for a single primary key; ".
     "${class} has more"
   ) if $too_many;
   return $pri;
 }
 
-sub _validate_cond {
+sub _validate_has_one_condition {
   my ($class, $cond )  = @_;
 
   return if $ENV{DBIC_DONT_VALIDATE_RELS};
@@ -80,6 +84,8 @@
     # warning
     return unless $self_id =~ /^self\.(.*)$/;
     my $key = $1;
+    $class->throw_exception("Defining rel on ${class} that includes ${key} but no such column defined here yet")
+        unless $class->has_column($key);
     my $column_info = $class->column_info($key);
     if ( $column_info->{is_nullable} ) {
       carp(qq'"might_have/has_one" must not be on columns with is_nullable set to true ($class/$key). This might indicate an incorrect use of those relationship helpers instead of belongs_to.');

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Relationship.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Relationship.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Relationship.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -111,7 +111,7 @@
 you want to use the default value for it, but still want to set C<\%attrs>.
 
 See L<DBIx::Class::Relationship::Base> for documentation on the
-attrubutes that are allowed in the C<\%attrs> argument.
+attributes that are allowed in the C<\%attrs> argument.
 
 
 =head2 belongs_to
@@ -234,7 +234,7 @@
 
 Creates a one-to-many relationship where the foreign class refers to
 this class's primary key. This relationship refers to zero or more
-records in the foreign table (ie, a C<LEFT JOIN>). This relationship 
+records in the foreign table (e.g. a C<LEFT JOIN>). This relationship 
 defaults to using the end of this classes namespace as the foreign key
 in C<$related_class> to resolve the join, unless C<$their_fk_column>
 specifies the foreign key column in C<$related_class> or C<cond>

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/ResultSet.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/ResultSet.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/ResultSet.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -25,6 +25,10 @@
 =head1 SYNOPSIS
 
   my $users_rs   = $schema->resultset('User');
+  while( $user = $users_rs->next) {
+    print $user->username;
+  }
+
   my $registered_users_rs   = $schema->resultset('User')->search({ registered => 1 });
   my @cds_in_2005 = $schema->resultset('CD')->search({ year => 2005 })->all();
 
@@ -141,7 +145,7 @@
 =head1 OVERLOADING
 
 If a resultset is used in a numeric context it returns the L</count>.
-However, if it is used in a booleand context it is always true.  So if
+However, if it is used in a boolean context it is always true.  So if
 you want to check if a resultset has any results use C<if $rs != 0>.
 C<if $rs> will always be true.
 
@@ -291,10 +295,15 @@
     $rows = $self->get_cache;
   }
 
+  # reset the selector list
+  if (List::Util::first { exists $attrs->{$_} } qw{columns select as}) {
+     delete @{$our_attrs}{qw{select as columns +select +as +columns include_columns}};
+  }
+
   my $new_attrs = { %{$our_attrs}, %{$attrs} };
 
   # merge new attrs into inherited
-  foreach my $key (qw/join prefetch +select +as bind/) {
+  foreach my $key (qw/join prefetch +select +as +columns include_columns bind/) {
     next unless exists $attrs->{$key};
     $new_attrs->{$key} = $self->_merge_attr($our_attrs->{$key}, $attrs->{$key});
   }
@@ -519,7 +528,7 @@
     # in ::Relationship::Base::search_related (the row method), and furthermore
     # the relationship is of the 'single' type. This means that the condition
     # provided by the relationship (already attached to $self) is sufficient,
-    # as there can be only one row in the databse that would satisfy the
+    # as there can be only one row in the database that would satisfy the
     # relationship
   }
   else {
@@ -530,7 +539,7 @@
   }
 
   # Run the query
-  my $rs = $self->search ($query, {result_class => $self->result_class, %$attrs});
+  my $rs = $self->search ($query, $attrs);
   if (keys %{$rs->_resolved_attrs->{collapse}}) {
     my $row = $rs->next;
     carp "Query returned more than one row" if $rs->next;
@@ -634,7 +643,7 @@
 =head2 search_related_rs
 
 This method works exactly the same as search_related, except that
-it guarantees a restultset, even in list context.
+it guarantees a resultset, even in list context.
 
 =cut
 
@@ -692,7 +701,7 @@
 
 =item B<Note>
 
-As of 0.08100, this method enforces the assumption that the preceeding
+As of 0.08100, this method enforces the assumption that the preceding
 query returns only one row. If more than one row is returned, you will receive
 a warning:
 
@@ -998,7 +1007,7 @@
   # without having to contruct the full hash
 
   if (keys %collapse) {
-    my %pri = map { ($_ => 1) } $self->result_source->primary_columns;
+    my %pri = map { ($_ => 1) } $self->result_source->_pri_cols;
     foreach my $i (0 .. $#construct_as) {
       next if defined($construct_as[$i][0]); # only self table
       if (delete $pri{$construct_as[$i][1]}) {
@@ -1131,6 +1140,7 @@
   if ($result_class) {
     $self->ensure_class_loaded($result_class);
     $self->_result_class($result_class);
+    $self->{attrs}{result_class} = $result_class if ref $self;
   }
   $self->_result_class;
 }
@@ -1225,11 +1235,12 @@
   my $rsrc = $self->result_source;
   $attrs ||= $self->_resolved_attrs;
 
-  my $tmp_attrs = { %$attrs };
+  # only take pieces we need for a simple count
+  my $tmp_attrs = { map
+    { $_ => $attrs->{$_} }
+    qw/ alias from where bind join /
+  };
 
-  # take off any limits, record_filter is cdbi, and no point of ordering a count
-  delete $tmp_attrs->{$_} for (qw/select as rows offset order_by record_filter/);
-
   # overwrite the selector (supplied by the storage)
   $tmp_attrs->{select} = $rsrc->storage->_count_select ($rsrc, $tmp_attrs);
   $tmp_attrs->{as} = 'count';
@@ -1246,37 +1257,43 @@
   my ($self, $attrs) = @_;
 
   my $rsrc = $self->result_source;
-  $attrs ||= $self->_resolved_attrs_copy;
+  $attrs ||= $self->_resolved_attrs;
 
-  my $sub_attrs = { %$attrs };
+  my $sub_attrs = { map
+    { $_ => $attrs->{$_} }
+    qw/ alias from where bind join group_by having rows offset /
+  };
 
-  # extra selectors do not go in the subquery and there is no point of ordering it
-  delete $sub_attrs->{$_} for qw/collapse select _prefetch_select as order_by/;
-
   # if we multi-prefetch we group_by primary keys only as this is what we would
   # get out of the rs via ->next/->all. We *DO WANT* to clobber old group_by regardless
   if ( keys %{$attrs->{collapse}}  ) {
-    $sub_attrs->{group_by} = [ map { "$attrs->{alias}.$_" } ($rsrc->primary_columns) ]
+    $sub_attrs->{group_by} = [ map { "$attrs->{alias}.$_" } ($rsrc->_pri_cols) ]
   }
 
-  $sub_attrs->{select} = $rsrc->storage->_subq_count_select ($rsrc, $sub_attrs);
+  # Calculate subquery selector
+  if (my $g = $sub_attrs->{group_by}) {
 
-  # this is so that the query can be simplified e.g.
-  # * ordering can be thrown away in things like Top limit
-  $sub_attrs->{-for_count_only} = 1;
+    # necessary as the group_by may refer to aliased functions
+    my $sel_index;
+    for my $sel (@{$attrs->{select}}) {
+      $sel_index->{$sel->{-as}} = $sel
+        if (ref $sel eq 'HASH' and $sel->{-as});
+    }
 
-  my $sub_rs = $rsrc->resultset_class->new ($rsrc, $sub_attrs);
+    for my $g_part (@$g) {
+      push @{$sub_attrs->{select}}, $sel_index->{$g_part} || $g_part;
+    }
+  }
+  else {
+    my @pcols = map { "$attrs->{alias}.$_" } ($rsrc->primary_columns);
+    $sub_attrs->{select} = @pcols ? \@pcols : [ 1 ];
+  }
 
-  $attrs->{from} = [{
-    -alias => 'count_subq',
-    -source_handle => $rsrc->handle,
-    count_subq => $sub_rs->as_query,
-  }];
-
-  # the subquery replaces this
-  delete $attrs->{$_} for qw/where bind collapse group_by having having_bind rows offset/;
-
-  return $self->_count_rs ($attrs);
+  return $rsrc->resultset_class
+               ->new ($rsrc, $sub_attrs)
+                ->as_subselect_rs
+                 ->search ({}, { columns => { count => $rsrc->storage->_count_select ($rsrc, $attrs) } })
+                  -> get_column ('count');
 }
 
 sub _bool {
@@ -1415,7 +1432,7 @@
     my $attrs = $self->_resolved_attrs_copy;
 
     delete $attrs->{$_} for qw/collapse select as/;
-    $attrs->{columns} = [ map { "$attrs->{alias}.$_" } ($self->result_source->primary_columns) ];
+    $attrs->{columns} = [ map { "$attrs->{alias}.$_" } ($self->result_source->_pri_cols) ];
 
     if ($needs_group_by_subq) {
       # make sure no group_by was supplied, or if there is one - make sure it matches
@@ -1503,9 +1520,10 @@
   my ($self, $values) = @_;
   $self->throw_exception('Values for update_all must be a hash')
     unless ref $values eq 'HASH';
-  foreach my $obj ($self->all) {
-    $obj->set_columns($values)->update;
-  }
+
+  my $guard = $self->result_source->schema->txn_scope_guard;
+  $_->update($values) for $self->all;
+  $guard->commit;
   return 1;
 }
 
@@ -1523,7 +1541,7 @@
 will not run DBIC cascade triggers. See L</delete_all> if you need triggers
 to run. See also L<DBIx::Class::Row/delete>.
 
-Return value will be the amount of rows deleted; exact type of return value
+Return value will be the number of rows deleted; exact type of return value
 is storage-dependent.
 
 =cut
@@ -1556,7 +1574,9 @@
   $self->throw_exception('delete_all does not accept any arguments')
     if @_;
 
+  my $guard = $self->result_source->schema->txn_scope_guard;
   $_->delete for $self->all;
+  $guard->commit;
   return 1;
 }
 
@@ -1592,7 +1612,7 @@
       ],
      },
      { artistid => 5, name => 'Angsty-Whiny Girl', cds => [
-        { title => 'My parents sold me to a record company' ,year => 2005 },
+        { title => 'My parents sold me to a record company', year => 2005 },
         { title => 'Why Am I So Ugly?', year => 2006 },
         { title => 'I Got Surgery and am now Popular', year => 2007 }
       ],
@@ -1620,7 +1640,7 @@
     [qw/artistid name/],
     [100, 'A Formally Unknown Singer'],
     [101, 'A singer that jumped the shark two albums ago'],
-    [102, 'An actually cool singer.'],
+    [102, 'An actually cool singer'],
   ]);
 
 Please note an important effect on your data when choosing between void and
@@ -2127,7 +2147,7 @@
 B<keyed on the relationship name>. If the relationship is of type C<multi>
 (L<DBIx::Class::Relationship/has_many>) - pass an arrayref of hashrefs.
 The process will correctly identify columns holding foreign keys, and will
-transparrently populate them from the keys of the corresponding relation.
+transparently populate them from the keys of the corresponding relation.
 This can be applied recursively, and will work correctly for a structure
 with an arbitrary depth and width, as long as the relationships actually
 exists and the correct column data has been supplied.
@@ -2285,7 +2305,7 @@
     producer => $producer,
     name => 'harry',
   }, {
-    key => 'primary,
+    key => 'primary',
   });
 
 
@@ -2465,6 +2485,23 @@
   return !!$self->{attrs}{page};
 }
 
+=head2 is_ordered
+
+=over 4
+
+=item Arguments: none
+
+=item Return Value: true, if the resultset has been ordered with C<order_by>.
+
+=back
+
+=cut
+
+sub is_ordered {
+  my ($self) = @_;
+  return scalar $self->result_source->storage->_parse_order_by($self->{attrs}{order_by});
+}
+
 =head2 related_resultset
 
 =over 4
@@ -2502,7 +2539,7 @@
         ->relname_to_table_alias($rel, $join_count);
 
     # since this is search_related, and we already slid the select window inwards
-    # (the select/as attrs were deleted in the beginning), we need to flip all 
+    # (the select/as attrs were deleted in the beginning), we need to flip all
     # left joins to inner, so we get the expected results
     # read the comment on top of the actual function to see what this does
     $attrs->{from} = $rsrc->schema->storage->_straight_join_to_node ($attrs->{from}, $alias);
@@ -2588,6 +2625,78 @@
   return ($self->{attrs} || {})->{alias} || 'me';
 }
 
+=head2 as_subselect_rs
+
+=over 4
+
+=item Arguments: none
+
+=item Return Value: $resultset
+
+=back
+
+Act as a barrier to SQL symbols.  The resultset provided will be made into a
+"virtual view" by including it as a subquery within the from clause.  From this
+point on, any joined tables are inaccessible to ->search on the resultset (as if
+it were simply where-filtered without joins).  For example:
+
+ my $rs = $schema->resultset('Bar')->search({'x.name' => 'abc'},{ join => 'x' });
+
+ # 'x' now pollutes the query namespace
+
+ # So the following works as expected
+ my $ok_rs = $rs->search({'x.other' => 1});
+
+ # But this doesn't: instead of finding a 'Bar' related to two x rows (abc and
+ # def) we look for one row with contradictory terms and join in another table
+ # (aliased 'x_2') which we never use
+ my $broken_rs = $rs->search({'x.name' => 'def'});
+
+ my $rs2 = $rs->as_subselect_rs;
+
+ # doesn't work - 'x' is no longer accessible in $rs2, having been sealed away
+ my $not_joined_rs = $rs2->search({'x.other' => 1});
+
+ # works as expected: finds a 'table' row related to two x rows (abc and def)
+ my $correctly_joined_rs = $rs2->search({'x.name' => 'def'});
+
+Another example of when one might use this would be to select a subset of
+columns in a group by clause:
+
+ my $rs = $schema->resultset('Bar')->search(undef, {
+   group_by => [qw{ id foo_id baz_id }],
+ })->as_subselect_rs->search(undef, {
+   columns => [qw{ id foo_id }]
+ });
+
+In the above example normally columns would have to be equal to the group by,
+but because we isolated the group by into a subselect the above works.
+
+=cut
+
+sub as_subselect_rs {
+  my $self = shift;
+
+  my $attrs = $self->_resolved_attrs;
+
+  my $fresh_rs = (ref $self)->new (
+    $self->result_source
+  );
+
+  # these pieces will be locked in the subquery
+  delete $fresh_rs->{cond};
+  delete @{$fresh_rs->{attrs}}{qw/where bind/};
+
+  return $fresh_rs->search( {}, {
+    from => [{
+      $attrs->{alias} => $self->as_query,
+      -alias         => $attrs->{alias},
+      -source_handle => $self->result_source->handle,
+    }],
+    alias => $attrs->{alias},
+  });
+}
+
 # This code is called by search_related, and makes sure there
 # is clear separation between the joins before, during, and
 # after the relationship. This information is needed later
@@ -2610,7 +2719,7 @@
   # ->_resolve_join as otherwise they get lost - captainL
   my $join = $self->_merge_attr( $attrs->{join}, $attrs->{prefetch} );
 
-  delete @{$attrs}{qw/join prefetch collapse distinct select as columns +select +as +columns/};
+  delete @{$attrs}{qw/join prefetch collapse group_by distinct select as columns +select +as +columns/};
 
   my $seen = { %{ (delete $attrs->{seen_join}) || {} } };
 
@@ -2636,7 +2745,7 @@
       -alias => $attrs->{alias},
       $attrs->{alias} => $rs_copy->as_query,
     }];
-    delete @{$attrs}{@force_subq_attrs, 'where'};
+    delete @{$attrs}{@force_subq_attrs, qw/where bind/};
     $seen->{-relation_chain_depth} = 0;
   }
   elsif ($attrs->{from}) {  #shallow copy suffices
@@ -2715,41 +2824,46 @@
   # build columns (as long as select isn't set) into a set of as/select hashes
   unless ( $attrs->{select} ) {
 
-    my @cols = ( ref($attrs->{columns}) eq 'ARRAY' )
-      ? @{ delete $attrs->{columns}}
-      : (
-          ( delete $attrs->{columns} )
-            ||
-          $source->columns
-        )
-    ;
+    my @cols;
+    if ( ref $attrs->{columns} eq 'ARRAY' ) {
+      @cols = @{ delete $attrs->{columns}}
+    } elsif ( defined $attrs->{columns} ) {
+      @cols = delete $attrs->{columns}
+    } else {
+      @cols = $source->columns
+    }
 
-    @colbits = map {
-      ( ref($_) eq 'HASH' )
-      ? $_
-      : {
-          (
-            /^\Q${alias}.\E(.+)$/
-              ? "$1"
-              : "$_"
-          )
-            =>
-          (
-            /\./
-              ? "$_"
-              : "${alias}.$_"
-          )
-        }
-    } @cols;
+    for (@cols) {
+      if ( ref $_ eq 'HASH' ) {
+        push @colbits, $_
+      } else {
+        my $key = /^\Q${alias}.\E(.+)$/
+          ? "$1"
+          : "$_";
+        my $value = /\./
+          ? "$_"
+          : "${alias}.$_";
+        push @colbits, { $key => $value };
+      }
+    }
   }
 
   # add the additional columns on
-  foreach ( 'include_columns', '+columns' ) {
-      push @colbits, map {
-          ( ref($_) eq 'HASH' )
-            ? $_
-            : { ( split( /\./, $_ ) )[-1] => ( /\./ ? $_ : "${alias}.$_" ) }
-      } ( ref($attrs->{$_}) eq 'ARRAY' ) ? @{ delete $attrs->{$_} } : delete $attrs->{$_} if ( $attrs->{$_} );
+  foreach (qw{include_columns +columns}) {
+    if ( $attrs->{$_} ) {
+      my @list = ( ref($attrs->{$_}) eq 'ARRAY' )
+        ? @{ delete $attrs->{$_} }
+        : delete $attrs->{$_};
+      for (@list) {
+        if ( ref($_) eq 'HASH' ) {
+          push @colbits, $_
+        } else {
+          my $key = ( split /\./, $_ )[-1];
+          my $value = ( /\./ ? $_ : "$alias.$_" );
+          push @colbits, { $key => $value };
+        }
+      }
+    }
   }
 
   # start with initial select items
@@ -2758,15 +2872,22 @@
         ( ref $attrs->{select} eq 'ARRAY' )
       ? [ @{ $attrs->{select} } ]
       : [ $attrs->{select} ];
-    $attrs->{as} = (
-      $attrs->{as}
-      ? (
-        ref $attrs->{as} eq 'ARRAY'
-        ? [ @{ $attrs->{as} } ]
-        : [ $attrs->{as} ]
+
+    if ( $attrs->{as} ) {
+      $attrs->{as} =
+        (
+          ref $attrs->{as} eq 'ARRAY'
+            ? [ @{ $attrs->{as} } ]
+            : [ $attrs->{as} ]
         )
-      : [ map { m/^\Q${alias}.\E(.+)$/ ? $1 : $_ } @{ $attrs->{select} } ]
-    );
+    } else {
+      $attrs->{as} = [ map {
+         m/^\Q${alias}.\E(.+)$/
+           ? $1
+           : $_
+         } @{ $attrs->{select} }
+      ]
+    }
   }
   else {
 
@@ -2776,27 +2897,24 @@
   }
 
   # now add colbits to select/as
-  push( @{ $attrs->{select} }, map { values( %{$_} ) } @colbits );
-  push( @{ $attrs->{as} },     map { keys( %{$_} ) } @colbits );
+  push @{ $attrs->{select} }, map values %{$_}, @colbits;
+  push @{ $attrs->{as}     }, map keys   %{$_}, @colbits;
 
-  my $adds;
-  if ( $adds = delete $attrs->{'+select'} ) {
+  if ( my $adds = delete $attrs->{'+select'} ) {
     $adds = [$adds] unless ref $adds eq 'ARRAY';
-    push(
-      @{ $attrs->{select} },
-      map { /\./ || ref $_ ? $_ : "${alias}.$_" } @$adds
-    );
+    push @{ $attrs->{select} },
+      map { /\./ || ref $_ ? $_ : "$alias.$_" } @$adds;
   }
-  if ( $adds = delete $attrs->{'+as'} ) {
+  if ( my $adds = delete $attrs->{'+as'} ) {
     $adds = [$adds] unless ref $adds eq 'ARRAY';
-    push( @{ $attrs->{as} }, @$adds );
+    push @{ $attrs->{as} }, @$adds;
   }
 
-  $attrs->{from} ||= [ {
+  $attrs->{from} ||= [{
     -source_handle => $source->handle,
     -alias => $self->{attrs}{alias},
     $self->{attrs}{alias} => $source->from,
-  } ];
+  }];
 
   if ( $attrs->{join} || $attrs->{prefetch} ) {
 
@@ -2816,7 +2934,7 @@
           $join,
           $alias,
           { %{ $attrs->{seen_join} || {} } },
-          ($attrs->{seen_join} && keys %{$attrs->{seen_join}})
+          ( $attrs->{seen_join} && keys %{$attrs->{seen_join}})
             ? $attrs->{from}[-1][0]{-join_path}
             : []
           ,
@@ -3161,23 +3279,27 @@
     select => [
       'name',
       { count => 'employeeid' },
-      { sum => 'salary' }
+      { max => { length => 'name' }, -as => 'longest_name' }
     ]
   });
 
-When you use function/stored procedure names and do not supply an C<as>
-attribute, the column names returned are storage-dependent. E.g. MySQL would
-return a column named C<count(employeeid)> in the above example.
+  # Equivalent SQL
+  SELECT name, COUNT( employeeid ), MAX( LENGTH( name ) ) AS longest_name FROM employee
 
-B<NOTE:> You will almost always need a corresponding 'as' entry when you use
-'select'.
+B<NOTE:> You will almost always need a corresponding L</as> attribute when you
+use L</select>, to instruct DBIx::Class how to store the result of the column.
+Also note that the L</as> attribute has nothing to do with the SQL-side 'AS'
+identifier aliasing. You can however alias a function, so you can use it in
+e.g. an C<ORDER BY> clause. This is done via the C<-as> B<select function
+attribute> supplied as shown in the example above.
 
 =head2 +select
 
 =over 4
 
 Indicates additional columns to be selected from storage.  Works the same as
-L</select> but adds columns to the selection.
+L</select> but adds columns to the default selection, instead of specifying
+an explicit list.
 
 =back
 
@@ -3197,25 +3319,26 @@
 
 =back
 
-Indicates column names for object inflation. That is, C<as>
-indicates the name that the column can be accessed as via the
-C<get_column> method (or via the object accessor, B<if one already
-exists>).  It has nothing to do with the SQL code C<SELECT foo AS bar>.
+Indicates column names for object inflation. That is L</as> indicates the
+slot name in which the column value will be stored within the
+L<Row|DBIx::Class::Row> object. The value will then be accessible via this
+identifier by the C<get_column> method (or via the object accessor B<if one
+with the same name already exists>) as shown below. The L</as> attribute has
+B<nothing to do> with the SQL-side C<AS>. See L</select> for details.
 
-The C<as> attribute is used in conjunction with C<select>,
-usually when C<select> contains one or more function or stored
-procedure names:
-
   $rs = $schema->resultset('Employee')->search(undef, {
     select => [
       'name',
-      { count => 'employeeid' }
+      { count => 'employeeid' },
+      { max => { length => 'name' }, -as => 'longest_name' }
     ],
-    as => ['name', 'employee_count'],
+    as => [qw/
+      name
+      employee_count
+      max_name_length
+    /],
   });
 
-  my $employee = $rs->first(); # get the first Employee
-
 If the object against which the search is performed already has an accessor
 matching a column name specified in C<as>, the value can be retrieved using
 the accessor as normal:
@@ -3230,16 +3353,6 @@
 You can create your own accessors if required - see
 L<DBIx::Class::Manual::Cookbook> for details.
 
-Please note: This will NOT insert an C<AS employee_count> into the SQL
-statement produced, it is used for internal access only. Thus
-attempting to use the accessor in an C<order_by> clause or similar
-will fail miserably.
-
-To get around this limitation, you can supply literal SQL to your
-C<select> attibute that contains the C<AS alias> text, eg:
-
-  select => [\'myfield AS alias']
-
 =head2 join
 
 =over 4
@@ -3347,7 +3460,7 @@
 C<prefetch> can be used with the following relationship types: C<belongs_to>,
 C<has_one> (or if you're using C<add_relationship>, any relationship declared
 with an accessor type of 'single' or 'filter'). A more complex example that
-prefetches an artists cds, the tracks on those cds, and the tags associted
+prefetches an artists cds, the tracks on those cds, and the tags associated
 with that artist is given below (assuming many-to-many from artists to tags):
 
  my $rs = $schema->resultset('Artist')->search(
@@ -3426,7 +3539,7 @@
 
 =back
 
-Specifes the maximum number of rows for direct retrieval or the number of
+Specifies the maximum number of rows for direct retrieval or the number of
 rows per page if the page attribute or method is used.
 
 =head2 offset

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/ResultSetColumn.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/ResultSetColumn.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/ResultSetColumn.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -45,6 +45,7 @@
   $rs->throw_exception('column must be supplied') unless $column;
 
   my $orig_attrs = $rs->_resolved_attrs;
+  my $alias = $rs->current_source_alias;
 
   # If $column can be found in the 'as' list of the parent resultset, use the
   # corresponding element of its 'select' list (to keep any custom column
@@ -59,35 +60,24 @@
   # analyze the order_by, and see if it is done over a function/nonexistentcolumn
   # if this is the case we will need to wrap a subquery since the result of RSC
   # *must* be a single column select
-  my %collist = map { $_ => 1 } ($rs->result_source->columns, $column);
+  my %collist = map 
+    { $_ => 1, ($_ =~ /\./) ? () : ( "$alias.$_" => 1 ) }
+    ($rs->result_source->columns, $column)
+  ;
   if (
     scalar grep
       { ! $collist{$_} }
       ( $rs->result_source->schema->storage->_parse_order_by ($orig_attrs->{order_by} ) ) 
   ) {
-    my $alias = $rs->current_source_alias;
     # nuke the prefetch before collapsing to sql
     my $subq_rs = $rs->search;
     $subq_rs->{attrs}{join} = $subq_rs->_merge_attr( $subq_rs->{attrs}{join}, delete $subq_rs->{attrs}{prefetch} );
-
-    $new_parent_rs = $rs->result_source->resultset->search ( {}, {
-      alias => $alias,
-      from => [{
-        $alias => $subq_rs->as_query,
-        -alias => $alias,
-        -source_handle => $rs->result_source->handle,
-      }]
-    });
+    $new_parent_rs = $subq_rs->as_subselect_rs;
   }
 
   $new_parent_rs ||= $rs->search_rs;
   my $new_attrs = $new_parent_rs->{attrs} ||= {};
 
-  # FIXME - this should go away when the chaining branch is merged
-  # since what we do is actually chain to the original resultset, we need to throw
-  # away all selectors (otherwise they'll chain)
-  delete $new_attrs->{$_} for (qw/columns +columns select +select as +as cols include_columns/);
-
   # prefetch causes additional columns to be fetched, but we can not just make a new
   # rs via the _resolved_attrs trick - we need to retain the separation between
   # +select/+as and select/as. At the same time we want to preserve any joins that the
@@ -96,7 +86,7 @@
 
   # {collapse} would mean a has_many join was injected, which in turn means
   # we need to group *IF WE CAN* (only if the column in question is unique)
-  if (!$new_attrs->{group_by} && keys %{$orig_attrs->{collapse}}) {
+  if (!$orig_attrs->{group_by} && keys %{$orig_attrs->{collapse}}) {
 
     # scan for a constraint that would contain our column only - that'd be proof
     # enough it is unique

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/ResultSource/Table.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/ResultSource/Table.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/ResultSource/Table.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -16,7 +16,7 @@
 
 =head1 DESCRIPTION
 
-Table object that inherits from L<DBIx::Class::ResultSource>
+Table object that inherits from L<DBIx::Class::ResultSource>.
 
 =head1 METHODS
 

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/ResultSource.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/ResultSource.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/ResultSource.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -139,6 +139,13 @@
 L<DBIx::Class::Row> objects. You can change the name of the accessor
 by supplying an L</accessor> in the column_info hash.
 
+If a column name beginning with a plus sign ('+col1') is provided, the
+attributes provided will be merged with any existing attributes for the
+column, with the new attributes taking precedence in the case that an
+attribute already exists. Using this without a hashref 
+(C<< $source->add_columns(qw/+col1 +col2/) >>) is legal, but useless --
+it does the same thing it would do without the plus.
+
 The contents of the column_info are not set in stone. The following
 keys are currently recognised/used by DBIx::Class:
 
@@ -250,9 +257,9 @@
 L</sequence> value as well.
 
 Also set this for MSSQL columns with the 'uniqueidentifier'
-L<DBIx::Class::ResultSource/data_type> whose values you want to automatically
-generate using C<NEWID()>, unless they are a primary key in which case this will
-be done anyway.
+L<data_type|DBIx::Class::ResultSource/data_type> whose values you want to
+automatically generate using C<NEWID()>, unless they are a primary key in which
+case this will be done anyway.
 
 =item extra
 
@@ -288,9 +295,17 @@
   my @added;
   my $columns = $self->_columns;
   while (my $col = shift @cols) {
+    my $column_info = {};
+    if ($col =~ s/^\+//) {
+      $column_info = $self->column_info($col);
+    }
+
     # If next entry is { ... } use that for the column info, if not
     # use an empty hashref
-    my $column_info = ref $cols[0] ? shift(@cols) : {};
+    if (ref $cols[0]) {
+      my $new_info = shift(@cols);
+      %$column_info = (%$column_info, %$new_info);
+    }
     push(@added, $col) unless exists $columns->{$col};
     $columns->{$col} = $column_info;
   }
@@ -465,10 +480,11 @@
 Additionally, defines a L<unique constraint|add_unique_constraint>
 named C<primary>.
 
-The primary key columns are used by L<DBIx::Class::PK::Auto> to
-retrieve automatically created values from the database. They are also
-used as default joining columns when specifying relationships, see
-L<DBIx::Class::Relationship>.
+Note: you normally do want to define a primary key on your sources
+B<even if the underlying database table does not have a primary key>.
+See
+L<DBIx::Class::Intro/The Significance and Importance of Primary Keys>
+for more info.
 
 =cut
 
@@ -503,6 +519,19 @@
   return @{shift->_primaries||[]};
 }
 
+# a helper method that will automatically die with a descriptive message if
+# no pk is defined on the source in question. For internal use to save
+# on if @pks... boilerplate
+sub _pri_cols {
+  my $self = shift;
+  my @pcols = $self->primary_columns
+    or $self->throw_exception (sprintf(
+      "Operation requires a primary key to be declared on '%s' via set_primary_key",
+      $self->source_name,
+    ));
+  return @pcols;
+}
+
 =head2 add_unique_constraint
 
 =over 4
@@ -1188,12 +1217,6 @@
   return $found;
 }
 
-sub resolve_join {
-  carp 'resolve_join is a private method, stop calling it';
-  my $self = shift;
-  $self->_resolve_join (@_);
-}
-
 # Returns the {from} structure used to express JOIN conditions
 sub _resolve_join {
   my ($self, $join, $alias, $seen, $jpath, $parent_force_left) = @_;
@@ -1222,7 +1245,7 @@
     for my $rel (keys %$join) {
 
       my $rel_info = $self->relationship_info($rel)
-        or $self->throw_exception("No such relationship ${rel}");
+        or $self->throw_exception("No such relationship '$rel' on " . $self->source_name);
 
       my $force_left = $parent_force_left;
       $force_left ||= lc($rel_info->{attrs}{join_type}||'') eq 'left';
@@ -1252,7 +1275,7 @@
     );
 
     my $rel_info = $self->relationship_info($join)
-      or $self->throw_exception("No such relationship ${join}");
+      or $self->throw_exception("No such relationship $join on " . $self->source_name);
 
     my $rel_src = $self->related_source($join);
     return [ { $as => $rel_src->from,
@@ -1262,7 +1285,11 @@
                   : $rel_info->{attrs}{join_type}
                 ,
                -join_path => [@$jpath, { $join => $as } ],
-               -is_single => (List::Util::first { $rel_info->{attrs}{accessor} eq $_ } (qw/single filter/) ),
+               -is_single => (
+                  $rel_info->{attrs}{accessor}
+                    &&
+                  List::Util::first { $rel_info->{attrs}{accessor} eq $_ } (qw/single filter/)
+                ),
                -alias => $as,
                -relation_chain_depth => $seen->{-relation_chain_depth} || 0,
              },
@@ -1373,78 +1400,7 @@
   }
 }
 
-# Legacy code, needs to go entirely away (fully replaced by _resolve_prefetch)
-sub resolve_prefetch {
-  carp 'resolve_prefetch is a private method, stop calling it';
 
-  my ($self, $pre, $alias, $seen, $order, $collapse) = @_;
-  $seen ||= {};
-  if( ref $pre eq 'ARRAY' ) {
-    return
-      map { $self->resolve_prefetch( $_, $alias, $seen, $order, $collapse ) }
-        @$pre;
-  }
-  elsif( ref $pre eq 'HASH' ) {
-    my @ret =
-    map {
-      $self->resolve_prefetch($_, $alias, $seen, $order, $collapse),
-      $self->related_source($_)->resolve_prefetch(
-               $pre->{$_}, "${alias}.$_", $seen, $order, $collapse)
-    } keys %$pre;
-    return @ret;
-  }
-  elsif( ref $pre ) {
-    $self->throw_exception(
-      "don't know how to resolve prefetch reftype ".ref($pre));
-  }
-  else {
-    my $count = ++$seen->{$pre};
-    my $as = ($count > 1 ? "${pre}_${count}" : $pre);
-    my $rel_info = $self->relationship_info( $pre );
-    $self->throw_exception( $self->name . " has no such relationship '$pre'" )
-      unless $rel_info;
-    my $as_prefix = ($alias =~ /^.*?\.(.+)$/ ? $1.'.' : '');
-    my $rel_source = $self->related_source($pre);
-
-    if (exists $rel_info->{attrs}{accessor}
-         && $rel_info->{attrs}{accessor} eq 'multi') {
-      $self->throw_exception(
-        "Can't prefetch has_many ${pre} (join cond too complex)")
-        unless ref($rel_info->{cond}) eq 'HASH';
-      my $dots = @{[$as_prefix =~ m/\./g]} + 1; # +1 to match the ".${as_prefix}"
-      if (my ($fail) = grep { @{[$_ =~ m/\./g]} == $dots }
-                         keys %{$collapse}) {
-        my ($last) = ($fail =~ /([^\.]+)$/);
-        carp (
-          "Prefetching multiple has_many rels ${last} and ${pre} "
-          .(length($as_prefix)
-            ? "at the same level (${as_prefix}) "
-            : "at top level "
-          )
-          . 'will explode the number of row objects retrievable via ->next or ->all. '
-          . 'Use at your own risk.'
-        );
-      }
-      #my @col = map { (/^self\.(.+)$/ ? ("${as_prefix}.$1") : ()); }
-      #              values %{$rel_info->{cond}};
-      $collapse->{".${as_prefix}${pre}"} = [ $rel_source->primary_columns ];
-        # action at a distance. prepending the '.' allows simpler code
-        # in ResultSet->_collapse_result
-      my @key = map { (/^foreign\.(.+)$/ ? ($1) : ()); }
-                    keys %{$rel_info->{cond}};
-      my @ord = (ref($rel_info->{attrs}{order_by}) eq 'ARRAY'
-                   ? @{$rel_info->{attrs}{order_by}}
-                   : (defined $rel_info->{attrs}{order_by}
-                       ? ($rel_info->{attrs}{order_by})
-                       : ()));
-      push(@$order, map { "${as}.$_" } (@key, @ord));
-    }
-
-    return map { [ "${as}.$_", "${as_prefix}${pre}.$_", ] }
-      $rel_source->columns;
-  }
-}
-
 # Accepts one or more relationships for the current source and returns an
 # array of column names for each of those relationships. Column names are
 # prefixed relative to the current source, in accordance with where they appear
@@ -1487,13 +1443,12 @@
     my $as = shift @{$p->{-join_aliases}};
 
     my $rel_info = $self->relationship_info( $pre );
-    $self->throw_exception( $self->name . " has no such relationship '$pre'" )
+    $self->throw_exception( $self->source_name . " has no such relationship '$pre'" )
       unless $rel_info;
     my $as_prefix = ($alias =~ /^.*?\.(.+)$/ ? $1.'.' : '');
     my $rel_source = $self->related_source($pre);
 
-    if (exists $rel_info->{attrs}{accessor}
-         && $rel_info->{attrs}{accessor} eq 'multi') {
+    if ($rel_info->{attrs}{accessor} && $rel_info->{attrs}{accessor} eq 'multi') {
       $self->throw_exception(
         "Can't prefetch has_many ${pre} (join cond too complex)")
         unless ref($rel_info->{cond}) eq 'HASH';
@@ -1513,14 +1468,15 @@
       }
       #my @col = map { (/^self\.(.+)$/ ? ("${as_prefix}.$1") : ()); }
       #              values %{$rel_info->{cond}};
-      $collapse->{".${as_prefix}${pre}"} = [ $rel_source->primary_columns ];
+      $collapse->{".${as_prefix}${pre}"} = [ $rel_source->_pri_cols ];
         # action at a distance. prepending the '.' allows simpler code
         # in ResultSet->_collapse_result
       my @key = map { (/^foreign\.(.+)$/ ? ($1) : ()); }
                     keys %{$rel_info->{cond}};
       my @ord = (ref($rel_info->{attrs}{order_by}) eq 'ARRAY'
                    ? @{$rel_info->{attrs}{order_by}}
-                   : (defined $rel_info->{attrs}{order_by}
+   
+                : (defined $rel_info->{attrs}{order_by}
                        ? ($rel_info->{attrs}{order_by})
                        : ()));
       push(@$order, map { "${as}.$_" } (@key, @ord));
@@ -1548,7 +1504,7 @@
 sub related_source {
   my ($self, $rel) = @_;
   if( !$self->has_relationship( $rel ) ) {
-    $self->throw_exception("No such relationship '$rel'");
+    $self->throw_exception("No such relationship '$rel' on " . $self->source_name);
   }
   return $self->schema->source($self->relationship_info($rel)->{source});
 }
@@ -1570,7 +1526,7 @@
 sub related_class {
   my ($self, $rel) = @_;
   if( !$self->has_relationship( $rel ) ) {
-    $self->throw_exception("No such relationship '$rel'");
+    $self->throw_exception("No such relationship '$rel' on " . $self->source_name);
   }
   return $self->schema->class($self->relationship_info($rel)->{source});
 }
@@ -1638,7 +1594,7 @@
   __PACKAGE__->column_info_from_storage(1);
 
 Enables the on-demand automatic loading of the above column
-metadata from storage as neccesary.  This is *deprecated*, and
+metadata from storage as necessary.  This is *deprecated*, and
 should not be used.  It will be removed before 1.0.
 
 

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/ResultSourceHandle.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/ResultSourceHandle.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/ResultSourceHandle.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -87,7 +87,7 @@
 =head2 STORABLE_thaw
 
 Thaws frozen handle. Resets the internal schema reference to the package
-variable C<$thaw_schema>. The recomened way of setting this is to use 
+variable C<$thaw_schema>. The recommended way of setting this is to use 
 C<< $schema->thaw($ice) >> which handles this for you.
 
 =cut

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/ResultSourceProxy.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/ResultSourceProxy.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/ResultSourceProxy.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -37,6 +37,9 @@
   my $source = $class->result_source_instance;
   $source->add_columns(@cols);
   foreach my $c (grep { !ref } @cols) {
+    # If this is an augment definition get the real colname.
+    $c =~ s/^\+//;
+
     $class->register_column($c => $source->column_info($c));
   }
 }
@@ -75,6 +78,10 @@
   shift->result_source_instance->primary_columns(@_);
 }
 
+sub _pri_cols {
+  shift->result_source_instance->_pri_cols(@_);
+}
+
 sub add_unique_constraint {
   shift->result_source_instance->add_unique_constraint(@_);
 }
@@ -106,4 +113,7 @@
   shift->result_source_instance->relationship_info(@_);
 }
 
+sub has_relationship {
+  shift->result_source_instance->has_relationship(@_);
+}
 1;

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Row.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Row.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Row.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -105,26 +105,40 @@
 
 sub __new_related_find_or_new_helper {
   my ($self, $relname, $data) = @_;
-  if ($self->__their_pk_needs_us($relname, $data)) {
+
+  my $rsrc = $self->result_source;
+
+  # create a mock-object so all new/set_column component overrides will run:
+  my $rel_rs = $rsrc->related_source($relname)->resultset;
+  my $new_rel_obj = $rel_rs->new_result($data);
+  my $proc_data = { $new_rel_obj->get_columns };
+
+  if ($self->__their_pk_needs_us($relname)) {
     MULTICREATE_DEBUG and warn "MC $self constructing $relname via new_result";
-    return $self->result_source
-                ->related_source($relname)
-                ->resultset
-                ->new_result($data);
+    return $new_rel_obj;
   }
-  if ($self->result_source->_pk_depends_on($relname, $data)) {
-    MULTICREATE_DEBUG and warn "MC $self constructing $relname via find_or_new";
-    return $self->result_source
-                ->related_source($relname)
-                ->resultset
-                ->find_or_new($data);
+  elsif ($rsrc->_pk_depends_on($relname, $proc_data )) {
+    if (! keys %$proc_data) {
+      # there is nothing to search for - blind create
+      MULTICREATE_DEBUG and warn "MC $self constructing default-insert $relname";
+    }
+    else {
+      MULTICREATE_DEBUG and warn "MC $self constructing $relname via find_or_new";
+      # this is not *really* find or new, as we don't want to double-new the
+      # data (thus potentially double encoding or whatever)
+      my $exists = $rel_rs->find ($proc_data);
+      return $exists if $exists;
+    }
+    return $new_rel_obj;
   }
-  MULTICREATE_DEBUG and warn "MC $self constructing $relname via find_or_new_related";
-  return $self->find_or_new_related($relname, $data);
+  else {
+    my $us = $rsrc->source_name;
+    $self->throw_exception ("'$us' neither depends nor is depended on by '$relname', something is wrong...");
+  }
 }
 
 sub __their_pk_needs_us { # this should maybe be in resultsource.
-  my ($self, $relname, $data) = @_;
+  my ($self, $relname) = @_;
   my $source = $self->result_source;
   my $reverse = $source->reverse_relationship_info($relname);
   my $rel_source = $source->related_source($relname);
@@ -171,9 +185,8 @@
         $new->throw_exception("Can't do multi-create without result source")
           unless $source;
         my $info = $source->relationship_info($key);
-        if ($info && $info->{attrs}{accessor}
-          && $info->{attrs}{accessor} eq 'single')
-        {
+        my $acc_type = $info->{attrs}{accessor} || '';
+        if ($acc_type eq 'single') {
           my $rel_obj = delete $attrs->{$key};
           if(!Scalar::Util::blessed($rel_obj)) {
             $rel_obj = $new->__new_related_find_or_new_helper($key, $rel_obj);
@@ -188,9 +201,8 @@
 
           $related->{$key} = $rel_obj;
           next;
-        } elsif ($info && $info->{attrs}{accessor}
-            && $info->{attrs}{accessor} eq 'multi'
-            && ref $attrs->{$key} eq 'ARRAY') {
+        }
+        elsif ($acc_type eq 'multi' && ref $attrs->{$key} eq 'ARRAY' ) {
           my $others = delete $attrs->{$key};
           my $total = @$others;
           my @objects;
@@ -210,9 +222,8 @@
           }
           $related->{$key} = \@objects;
           next;
-        } elsif ($info && $info->{attrs}{accessor}
-          && $info->{attrs}{accessor} eq 'filter')
-        {
+        }
+        elsif ($acc_type eq 'filter') {
           ## 'filter' should disappear and get merged in with 'single' above!
           my $rel_obj = delete $attrs->{$key};
           if(!Scalar::Util::blessed($rel_obj)) {
@@ -304,12 +315,20 @@
       MULTICREATE_DEBUG and warn "MC $self pre-reconstructing $relname $rel_obj\n";
 
       my $them = { %{$rel_obj->{_relationship_data} || {} }, $rel_obj->get_inflated_columns };
-      my $re = $self->result_source
-                    ->related_source($relname)
-                    ->resultset
-                    ->find_or_create($them);
+      my $existing;
 
-      %{$rel_obj} = %{$re};
+      # if there are no keys - nothing to search for
+      if (keys %$them and $existing = $self->result_source
+                                           ->related_source($relname)
+                                           ->resultset
+                                           ->find($them)
+      ) {
+        %{$rel_obj} = %{$existing};
+      }
+      else {
+        $rel_obj->insert;
+      }
+
       $self->{_rel_in_storage}{$relname} = 1;
     }
 
@@ -323,34 +342,50 @@
     $rollback_guard ||= $source->storage->txn_scope_guard
   }
 
+  ## PK::Auto
+  my %auto_pri;
+  my $auto_idx = 0;
+  for ($self->primary_columns) {
+    if (
+      not defined $self->get_column($_)
+        ||
+      (ref($self->get_column($_)) eq 'SCALAR')
+    ) {
+      my $col_info = $source->column_info($_);
+      $auto_pri{$_} = $auto_idx++ unless $col_info->{auto_nextval};   # auto_nextval's are pre-fetched in the storage
+    }
+  }
+
   MULTICREATE_DEBUG and do {
     no warnings 'uninitialized';
     warn "MC $self inserting (".join(', ', $self->get_columns).")\n";
   };
-  my $updated_cols = $source->storage->insert($source, { $self->get_columns });
+  my $updated_cols = $source->storage->insert(
+    $source,
+    { $self->get_columns },
+    (keys %auto_pri) && $source->storage->_supports_insert_returning
+      ? { returning => [ sort { $auto_pri{$a} <=> $auto_pri{$b} } keys %auto_pri ] }
+      : ()
+    ,
+  );
+
   foreach my $col (keys %$updated_cols) {
     $self->store_column($col, $updated_cols->{$col});
+    delete $auto_pri{$col};
   }
 
-  ## PK::Auto
-  my @auto_pri = grep {
-                  (not defined $self->get_column($_))
-                    ||
-                  (ref($self->get_column($_)) eq 'SCALAR')
-                 } $self->primary_columns;
-
-  if (@auto_pri) {
-    MULTICREATE_DEBUG and warn "MC $self fetching missing PKs ".join(', ', @auto_pri)."\n";
+  if (keys %auto_pri) {
+    my @missing = sort { $auto_pri{$a} <=> $auto_pri{$b} } keys %auto_pri;
+    MULTICREATE_DEBUG and warn "MC $self fetching missing PKs ".join(', ', @missing )."\n";
     my $storage = $self->result_source->storage;
     $self->throw_exception( "Missing primary key but Storage doesn't support last_insert_id" )
       unless $storage->can('last_insert_id');
-    my @ids = $storage->last_insert_id($self->result_source, at auto_pri);
+    my @ids = $storage->last_insert_id($self->result_source, @missing);
     $self->throw_exception( "Can't get last insert id" )
-      unless (@ids == @auto_pri);
-    $self->store_column($auto_pri[$_] => $ids[$_]) for 0 .. $#ids;
+      unless (@ids == @missing);
+    $self->store_column($missing[$_] => $ids[$_]) for 0 .. $#missing;
   }
 
-
   $self->{_dirty_columns} = {};
   $self->{related_resultsets} = {};
 
@@ -370,7 +405,7 @@
       foreach my $obj (@cands) {
         $obj->set_from_related($_, $self) for keys %$reverse;
         my $them = { %{$obj->{_relationship_data} || {} }, $obj->get_inflated_columns };
-        if ($self->__their_pk_needs_us($relname, $them)) {
+        if ($self->__their_pk_needs_us($relname)) {
           if (exists $self->{_ignore_at_insert}{$relname}) {
             MULTICREATE_DEBUG and warn "MC $self skipping post-insert on $relname";
           } else {
@@ -443,9 +478,13 @@
 according to L</in_storage>.
 
 This method issues an SQL UPDATE query to commit any changes to the
-object to the database if required.
+object to the database if required (see L</get_dirty_columns>).
+It throws an exception if a proper WHERE clause uniquely identifying
+the database row can not be constructed (see
+L<significance of primary keys|DBIx::Class::Manual::Intro/The Significance and Importance of Primary Keys>
+for more details).
 
-Also takes an optional hashref of C<< column_name => value> >> pairs
+Also takes an optional hashref of C<< column_name => value >> pairs
 to update on the object first. Be aware that the hashref will be
 passed to C<set_inflated_columns>, which might edit it in place, so
 don't rely on it being the same after a call to C<update>.  If you
@@ -453,7 +492,7 @@
 to C<update>, e.g. ( { %{ $href } } )
 
 If the values passed or any of the column values set on the object
-contain scalar references, eg:
+contain scalar references, e.g.:
 
   $row->last_modified(\'NOW()');
   # OR
@@ -480,17 +519,18 @@
 sub update {
   my ($self, $upd) = @_;
   $self->throw_exception( "Not in database" ) unless $self->in_storage;
-  my $ident_cond = $self->ident_condition;
-  $self->throw_exception("Cannot safely update a row in a PK-less table")
+
+  my $ident_cond = $self->{_orig_ident} || $self->ident_condition;
+
+  $self->throw_exception('Unable to update a row with incomplete or no identity')
     if ! keys %$ident_cond;
 
   $self->set_inflated_columns($upd) if $upd;
   my %to_update = $self->get_dirty_columns;
   return $self unless keys %to_update;
   my $rows = $self->result_source->storage->update(
-               $self->result_source, \%to_update,
-               $self->{_orig_ident} || $ident_cond
-             );
+    $self->result_source, \%to_update, $ident_cond
+  );
   if ($rows == 0) {
     $self->throw_exception( "Can't update ${self}: row not found" );
   } elsif ($rows > 1) {
@@ -498,7 +538,7 @@
   }
   $self->{_dirty_columns} = {};
   $self->{related_resultsets} = {};
-  undef $self->{_orig_ident};
+  delete $self->{_orig_ident};
   return $self;
 }
 
@@ -515,8 +555,10 @@
 =back
 
 Throws an exception if the object is not in the database according to
-L</in_storage>. Runs an SQL DELETE statement using the primary key
-values to locate the row.
+L</in_storage>. Also throws an exception if a proper WHERE clause
+uniquely identifying the database row can not be constructed (see
+L<significance of primary keys|DBIx::Class::Manual::Intro/The Significance and Importance of Primary Keys>
+for more details).
 
 The object is still perfectly usable, but L</in_storage> will
 now return 0 and the object must be reinserted using L</insert>
@@ -547,17 +589,19 @@
   my $self = shift;
   if (ref $self) {
     $self->throw_exception( "Not in database" ) unless $self->in_storage;
+
     my $ident_cond = $self->{_orig_ident} || $self->ident_condition;
-    $self->throw_exception("Cannot safely delete a row in a PK-less table")
+    $self->throw_exception('Unable to delete a row with incomplete or no identity')
       if ! keys %$ident_cond;
-    foreach my $column (keys %$ident_cond) {
-            $self->throw_exception("Can't delete the object unless it has loaded the primary keys")
-              unless exists $self->{_column_data}{$column};
-    }
+
     $self->result_source->storage->delete(
-      $self->result_source, $ident_cond);
+      $self->result_source, $ident_cond
+    );
+
+    delete $self->{_orig_ident};
     $self->in_storage(undef);
-  } else {
+  }
+  else {
     $self->throw_exception("Can't do class delete without a ResultSource instance")
       unless $self->can('result_source_instance');
     my $attrs = @_ > 1 && ref $_[$#_] eq 'HASH' ? { %{pop(@_)} } : {};
@@ -763,9 +807,7 @@
   for my $col (keys %loaded_colinfo) {
     if (exists $loaded_colinfo{$col}{accessor}) {
       my $acc = $loaded_colinfo{$col}{accessor};
-      if (defined $acc) {
-        $inflated{$col} = $self->$acc;
-      }
+      $inflated{$col} = $self->$acc if defined $acc;
     }
     else {
       $inflated{$col} = $self->$col;
@@ -817,9 +859,10 @@
 sub set_column {
   my ($self, $column, $new_value) = @_;
 
-  $self->{_orig_ident} ||= $self->ident_condition;
+  # if we can't get an ident condition on first try - mark the object as unidentifiable
+  $self->{_orig_ident} ||= (eval { $self->ident_condition }) || {};
+
   my $old_value = $self->get_column($column);
-
   $new_value = $self->store_column($column, $new_value);
 
   my $dirty;
@@ -903,7 +946,7 @@
 L<DBIx::Class::Relationship/has_many> key, and create the related
 objects if necessary.
 
-Be aware that the input hashref might be edited in place, so dont rely
+Be aware that the input hashref might be edited in place, so don't rely
 on it being the same after a call to C<set_inflated_columns>. If you
 need to preserve the hashref, it is sufficient to pass a shallow copy
 to C<set_inflated_columns>, e.g. ( { %{ $href } } )
@@ -917,21 +960,18 @@
   foreach my $key (keys %$upd) {
     if (ref $upd->{$key}) {
       my $info = $self->relationship_info($key);
-      if ($info && $info->{attrs}{accessor}
-        && $info->{attrs}{accessor} eq 'single')
-      {
+      my $acc_type = $info->{attrs}{accessor} || '';
+      if ($acc_type eq 'single') {
         my $rel = delete $upd->{$key};
         $self->set_from_related($key => $rel);
         $self->{_relationship_data}{$key} = $rel;
-      } elsif ($info && $info->{attrs}{accessor}
-        && $info->{attrs}{accessor} eq 'multi') {
-          $self->throw_exception(
-            "Recursive update is not supported over relationships of type multi ($key)"
-          );
       }
-      elsif ($self->has_column($key)
-        && exists $self->column_info($key)->{_inflate_info})
-      {
+      elsif ($acc_type eq 'multi') {
+        $self->throw_exception(
+          "Recursive update is not supported over relationships of type '$acc_type' ($key)"
+        );
+      }
+      elsif ($self->has_column($key) && exists $self->column_info($key)->{_inflate_info}) {
         $self->set_inflated_column($key, delete $upd->{$key});
       }
     }
@@ -960,7 +1000,7 @@
 the new object.
 
 Relationships will be followed by the copy procedure B<only> if the
-relationship specifes a true value for its
+relationship specifies a true value for its
 L<cascade_copy|DBIx::Class::Relationship::Base> attribute. C<cascade_copy>
 is set by default on C<has_many> relationships and unset on all others.
 
@@ -983,7 +1023,7 @@
   $new->insert;
 
   # Its possible we'll have 2 relations to the same Source. We need to make
-  # sure we don't try to insert the same row twice esle we'll violate unique
+  # sure we don't try to insert the same row twice else we'll violate unique
   # constraints
   my $rels_copied = {};
 
@@ -1070,9 +1110,10 @@
   my ($source_handle) = $source;
 
   if ($source->isa('DBIx::Class::ResultSourceHandle')) {
-      $source = $source_handle->resolve
-  } else {
-      $source_handle = $source->handle
+    $source = $source_handle->resolve
+  } 
+  else {
+    $source_handle = $source->handle
   }
 
   my $new = {
@@ -1081,17 +1122,29 @@
   };
   bless $new, (ref $class || $class);
 
-  my $schema;
   foreach my $pre (keys %{$prefetch||{}}) {
-    my $pre_val = $prefetch->{$pre};
-    my $pre_source = $source->related_source($pre);
-    $class->throw_exception("Can't prefetch non-existent relationship ${pre}")
-      unless $pre_source;
-    if (ref($pre_val->[0]) eq 'ARRAY') { # multi
-      my @pre_objects;
 
-      for my $me_pref (@$pre_val) {
+    my $pre_source = $source->related_source($pre)
+      or $class->throw_exception("Can't prefetch non-existent relationship ${pre}");
 
+    my $accessor = $source->relationship_info($pre)->{attrs}{accessor}
+      or $class->throw_exception("No accessor for prefetched $pre");
+
+    my @pre_vals;
+    if (ref $prefetch->{$pre}[0] eq 'ARRAY') {
+      @pre_vals = @{$prefetch->{$pre}};
+    }
+    elsif ($accessor eq 'multi') {
+      $class->throw_exception("Implicit prefetch (via select/columns) not supported with accessor 'multi'");
+    }
+    else {
+      @pre_vals = $prefetch->{$pre};
+    }
+
+    my @pre_objects;
+    for my $me_pref (@pre_vals) {
+
+        # FIXME - this should not be necessary
         # the collapser currently *could* return bogus elements with all
         # columns set to undef
         my $has_def;
@@ -1106,29 +1159,16 @@
         push @pre_objects, $pre_source->result_class->inflate_result(
           $pre_source, @$me_pref
         );
-      }
+    }
 
-      $new->related_resultset($pre)->set_cache(\@pre_objects);
-    } elsif (defined $pre_val->[0]) {
-      my $fetched;
-      unless ($pre_source->primary_columns == grep { exists $pre_val->[0]{$_}
-         and !defined $pre_val->[0]{$_} } $pre_source->primary_columns)
-      {
-        $fetched = $pre_source->result_class->inflate_result(
-                      $pre_source, @{$pre_val});
-      }
-      my $accessor = $source->relationship_info($pre)->{attrs}{accessor};
-      $class->throw_exception("No accessor for prefetched $pre")
-       unless defined $accessor;
-      if ($accessor eq 'single') {
-        $new->{_relationship_data}{$pre} = $fetched;
-      } elsif ($accessor eq 'filter') {
-        $new->{_inflated_column}{$pre} = $fetched;
-      } else {
-       $class->throw_exception("Implicit prefetch (via select/columns) not supported with accessor '$accessor'");
-      }
-      $new->related_resultset($pre)->set_cache([ $fetched ]);
+    if ($accessor eq 'single') {
+      $new->{_relationship_data}{$pre} = $pre_objects[0];
     }
+    elsif ($accessor eq 'filter') {
+      $new->{_inflated_column}{$pre} = $pre_objects[0];
+    }
+
+    $new->related_resultset($pre)->set_cache(\@pre_objects);
   }
 
   $new->in_storage (1);
@@ -1280,8 +1320,11 @@
 =back
 
 Fetches a fresh copy of the Row object from the database and returns it.
-
-If passed the \%attrs argument, will first apply these attributes to
+Throws an exception if a proper WHERE clause identifying the database row
+can not be constructed (i.e. if the original object does not contain its
+entire
+ L<primary key|DBIx::Class::Manual::Intro/The Significance and Importance of Primary Keys>
+). If passed the \%attrs argument, will first apply these attributes to
 the resultset used to find the row.
 
 This copy can then be used to compare to an existing row object, to
@@ -1305,13 +1348,22 @@
       $resultset = $resultset->search(undef, $attrs);
     }
 
-    return $resultset->find($self->{_orig_ident} || $self->ident_condition);
+    my $ident_cond = $self->{_orig_ident} || $self->ident_condition;
+
+    $self->throw_exception('Unable to requery a row with incomplete or no identity')
+      if ! keys %$ident_cond;
+
+    return $resultset->find($ident_cond);
 }
 
 =head2 discard_changes ($attrs)
 
 Re-selects the row from the database, losing any changes that had
-been made.
+been made. Throws an exception if a proper WHERE clause identifying
+the database row can not be constructed (i.e. if the original object
+does not contain its entire
+L<primary key|DBIx::Class::Manual::Intro/The Significance and Importance of Primary Keys>
+).
 
 This method can also be used to refresh from storage, retrieving any
 changes made since the row was last read from storage.

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/SQLAHacks/MySQL.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/SQLAHacks/MySQL.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/SQLAHacks/MySQL.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -21,4 +21,14 @@
   return $self->SUPER::insert (@_);
 }
 
+# Allow STRAIGHT_JOIN's
+sub _generate_join_clause {
+    my ($self, $join_type) = @_;
+
+    if( $join_type && $join_type =~ /^STRAIGHT\z/i ) {
+        return ' STRAIGHT_JOIN '
+    }
+
+    return $self->SUPER::_generate_join_clause( $join_type );
+}
 1;

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/SQLAHacks/OracleJoins.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/SQLAHacks/OracleJoins.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/SQLAHacks/OracleJoins.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -5,13 +5,13 @@
 use Carp::Clan qw/^DBIx::Class|^SQL::Abstract/;
 
 sub select {
-  my ($self, $table, $fields, $where, $order, @rest) = @_;
+  my ($self, $table, $fields, $where, $rs_attrs, @rest) = @_;
 
   if (ref($table) eq 'ARRAY') {
     $where = $self->_oracle_joins($where, @{ $table });
   }
 
-  return $self->SUPER::select($table, $fields, $where, $order, @rest);
+  return $self->SUPER::select($table, $fields, $where, $rs_attrs, @rest);
 }
 
 sub _recurse_from {
@@ -96,8 +96,7 @@
 
 This module was originally written to support Oracle < 9i where ANSI joins
 weren't supported at all, but became the module for Oracle >= 8 because
-Oracle's optimising of ANSI joins is horrible.  (See:
-http://scsys.co.uk:8001/7495)
+Oracle's optimising of ANSI joins is horrible.
 
 =head1 SYNOPSIS
 

Added: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/SQLAHacks/SQLite.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/SQLAHacks/SQLite.pm	                        (rev 0)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/SQLAHacks/SQLite.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -0,0 +1,21 @@
+package # Hide from PAUSE
+  DBIx::Class::SQLAHacks::SQLite;
+
+use base qw( DBIx::Class::SQLAHacks );
+use Carp::Clan qw/^DBIx::Class|^SQL::Abstract/;
+
+#
+# SQLite does not understand SELECT ... FOR UPDATE
+# Disable it here
+#
+sub _parse_rs_attrs {
+  my ($self, $attrs) = @_;
+
+  return $self->SUPER::_parse_rs_attrs ($attrs)
+    if ref $attrs ne 'HASH';
+
+  local $attrs->{for};
+  return $self->SUPER::_parse_rs_attrs ($attrs);
+}
+
+1;

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/SQLAHacks.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/SQLAHacks.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/SQLAHacks.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -46,32 +46,168 @@
   $self;
 }
 
+# !!! THIS IS ALSO HORRIFIC !!! /me ashamed
+#
+# generate inner/outer select lists for various limit dialects
+# which result in one or more subqueries (e.g. RNO, Top, RowNum)
+# Any non-root-table columns need to have their table qualifier
+# turned into a column alias (otherwise names in subqueries clash
+# and/or lose their source table)
+#
+# returns inner/outer strings of SQL QUOTED selectors with aliases
+# (to be used in whatever select statement), and an alias index hashref
+# of QUOTED SEL => QUOTED ALIAS pairs (to maybe be used for string-subst
+# higher up)
+#
+# If the $scan_order option is supplied, it signals that the limit dialect
+# needs to order the outer side of the query, which in turn means that the
+# inner select needs to bring out columns used in implicit (non-selected)
+# orders, and the order condition itself needs to be realiased to the proper
+# names in the outer query.
+#
+# In this case ($scan_order os true) we also return a hashref (order doesn't
+# matter) of QUOTED EXTRA-SEL => QUOTED ALIAS pairs, which is a list of extra
+# selectors that do *not* exist in the original select list
 
-# ANSI standard Limit/Offset implementation. DB2 and MSSQL use this
+sub _subqueried_limit_attrs {
+  my ($self, $rs_attrs, $scan_order) = @_;
+
+  croak 'Limit dialect implementation usable only in the context of DBIC (missing $rs_attrs)'
+    unless ref ($rs_attrs) eq 'HASH';
+
+  my ($re_sep, $re_alias) = map { quotemeta $_ } (
+    $self->name_sep || '.',
+    $rs_attrs->{alias},
+  );
+
+  # correlate select and as, build selection index
+  my (@sel, $in_sel_index);
+  for my $i (0 .. $#{$rs_attrs->{select}}) {
+
+    my $s = $rs_attrs->{select}[$i];
+    my $sql_sel = $self->_recurse_fields ($s);
+    my $sql_alias = (ref $s) eq 'HASH' ? $s->{-as} : undef;
+
+
+    push @sel, {
+      sql => $sql_sel,
+      unquoted_sql => do { local $self->{quote_char}; $self->_recurse_fields ($s) },
+      as =>
+        $sql_alias
+          ||
+        $rs_attrs->{as}[$i]
+          ||
+        croak "Select argument $i ($s) without corresponding 'as'"
+      ,
+    };
+
+    $in_sel_index->{$sql_sel}++;
+    $in_sel_index->{$self->_quote ($sql_alias)}++ if $sql_alias;
+
+# this *may* turn out to be necessary, not sure yet
+#    my ($sql_unqualified_sel) = $sql_sel =~ / $re_sep (.+) $/x
+#      if ! ref $s;
+#    $in_sel_index->{$sql_unqualified_sel}++;
+  }
+
+
+  # re-alias and remove any name separators from aliases,
+  # unless we are dealing with the current source alias
+  # (which will transcend the subqueries as it is necessary
+  # for possible further chaining)
+  my (@in_sel, @out_sel, %renamed);
+  for my $node (@sel) {
+    if (List::Util::first { $_ =~ / (?<! $re_alias ) $re_sep /x } ($node->{as}, $node->{unquoted_sql}) )  {
+      $node->{as} =~ s/ $re_sep /__/xg;
+      my $quoted_as = $self->_quote($node->{as});
+      push @in_sel, sprintf '%s AS %s', $node->{sql}, $quoted_as;
+      push @out_sel, $quoted_as;
+      $renamed{$node->{sql}} = $quoted_as;
+    }
+    else {
+      push @in_sel, $node->{sql};
+      push @out_sel, $self->_quote ($node->{as});
+    }
+  }
+
+  my %extra_order_sel;
+  if ($scan_order) {
+    for my $chunk ($self->_order_by_chunks ($rs_attrs->{order_by})) {
+      # order with bind
+      $chunk = $chunk->[0] if (ref $chunk) eq 'ARRAY';
+      $chunk =~ s/\s+ (?: ASC|DESC ) \s* $//ix;
+
+      next if $in_sel_index->{$chunk};
+
+      $extra_order_sel{$chunk} ||= $self->_quote (
+        'ORDER__BY__' . scalar keys %extra_order_sel
+      );
+    }
+  }
+  return (
+    (map { join (', ', @$_ ) } (
+      \@in_sel,
+      \@out_sel)
+    ),
+    \%renamed,
+    keys %extra_order_sel ? \%extra_order_sel : (),
+  );
+}
+
+# ANSI standard Limit/Offset implementation. DB2 and MSSQL >= 2005 use this
 sub _RowNumberOver {
-  my ($self, $sql, $order, $rows, $offset ) = @_;
+  my ($self, $sql, $rs_attrs, $rows, $offset ) = @_;
 
-  # get the select to make the final amount of columns equal the original one
-  my ($select) = $sql =~ /^ \s* SELECT \s+ (.+?) \s+ FROM/ix
+  # mangle the input sql as we will be replacing the selector
+  $sql =~ s/^ \s* SELECT \s+ .+? \s+ (?= \b FROM \b )//ix
     or croak "Unrecognizable SELECT: $sql";
 
-  # get the order_by only (or make up an order if none exists)
-  my $order_by = $self->_order_by(
-    (delete $order->{order_by}) || $self->_rno_default_order
+  # get selectors, and scan the order_by (if any)
+  my ($in_sel, $out_sel, $alias_map, $extra_order_sel) = $self->_subqueried_limit_attrs (
+    $rs_attrs, 'scan_order_by',
   );
 
-  # whatever is left of the order_by
-  my $group_having = $self->_order_by($order);
+  # make up an order if none exists
+  my $requested_order = (delete $rs_attrs->{order_by}) || $self->_rno_default_order;
+  my $rno_ord = $self->_order_by ($requested_order);
 
-  my $qalias = $self->_quote ($self->{_dbic_rs_attrs}{alias});
+  # this is the order supplement magic
+  my $mid_sel = $out_sel;
+  if ($extra_order_sel) {
+    for my $extra_col (sort
+      { $extra_order_sel->{$a} cmp $extra_order_sel->{$b} }
+      keys %$extra_order_sel
+    ) {
+      $in_sel .= sprintf (', %s AS %s',
+        $extra_col,
+        $extra_order_sel->{$extra_col},
+      );
 
+      $mid_sel .= ', ' . $extra_order_sel->{$extra_col};
+    }
+  }
+
+  # and this is order re-alias magic
+  for ($extra_order_sel, $alias_map) {
+    for my $col (keys %$_) {
+      my $re_col = quotemeta ($col);
+      $rno_ord =~ s/$re_col/$_->{$col}/;
+    }
+  }
+
+  # whatever is left of the order_by (only where is processed at this point)
+  my $group_having = $self->_parse_rs_attrs($rs_attrs);
+
+  my $qalias = $self->_quote ($rs_attrs->{alias});
+  my $idx_name = $self->_quote ('rno__row__index');
+
   $sql = sprintf (<<EOS, $offset + 1, $offset + $rows, );
 
-SELECT $select FROM (
-  SELECT $qalias.*, ROW_NUMBER() OVER($order_by ) AS rno__row__index FROM (
-    ${sql}${group_having}
+SELECT $out_sel FROM (
+  SELECT $mid_sel, ROW_NUMBER() OVER( $rno_ord ) AS $idx_name FROM (
+    SELECT $in_sel ${sql}${group_having}
   ) $qalias
-) $qalias WHERE rno__row__index BETWEEN %d AND %d
+) $qalias WHERE $idx_name BETWEEN %d AND %d
 
 EOS
 
@@ -86,7 +222,7 @@
 
 # Informix specific limit, almost like LIMIT/OFFSET
 sub _SkipFirst {
-  my ($self, $sql, $order, $rows, $offset) = @_;
+  my ($self, $sql, $rs_attrs, $rows, $offset) = @_;
 
   $sql =~ s/^ \s* SELECT \s+ //ix
     or croak "Unrecognizable SELECT: $sql";
@@ -98,203 +234,159 @@
     ,
     sprintf ('FIRST %d ', $rows),
     $sql,
-    $self->_order_by ($order),
+    $self->_parse_rs_attrs ($rs_attrs),
   );
 }
 
-# Crappy Top based Limit/Offset support. Legacy from MSSQL.
-sub _Top {
-  my ( $self, $sql, $order, $rows, $offset ) = @_;
+# Firebird specific limit, reverse of _SkipFirst for Informix
+sub _FirstSkip {
+  my ($self, $sql, $rs_attrs, $rows, $offset) = @_;
 
-  # mangle the input sql so it can be properly aliased in the outer queries
-  $sql =~ s/^ \s* SELECT \s+ (.+?) \s+ (?=FROM)//ix
+  $sql =~ s/^ \s* SELECT \s+ //ix
     or croak "Unrecognizable SELECT: $sql";
-  my $sql_select = $1;
-  my @sql_select = split (/\s*,\s*/, $sql_select);
 
-  # we can't support subqueries (in fact MSSQL can't) - croak
-  if (@sql_select != @{$self->{_dbic_rs_attrs}{select}}) {
-    croak (sprintf (
-      'SQL SELECT did not parse cleanly - retrieved %d comma separated elements, while '
-    . 'the resultset select attribure contains %d elements: %s',
-      scalar @sql_select,
-      scalar @{$self->{_dbic_rs_attrs}{select}},
-      $sql_select,
-    ));
-  }
+  return sprintf ('SELECT %s%s%s%s',
+    sprintf ('FIRST %d ', $rows),
+    $offset
+      ? sprintf ('SKIP %d ', $offset)
+      : ''
+    ,
+    $sql,
+    $self->_parse_rs_attrs ($rs_attrs),
+  );
+}
 
-  my $name_sep = $self->name_sep || '.';
-  my $esc_name_sep = "\Q$name_sep\E";
-  my $col_re = qr/ ^ (?: (.+) $esc_name_sep )? ([^$esc_name_sep]+) $ /x;
+# WhOracle limits
+sub _RowNum {
+  my ( $self, $sql, $rs_attrs, $rows, $offset ) = @_;
 
-  my $rs_alias = $self->{_dbic_rs_attrs}{alias};
-  my $quoted_rs_alias = $self->_quote ($rs_alias);
+  # mangle the input sql as we will be replacing the selector
+  $sql =~ s/^ \s* SELECT \s+ .+? \s+ (?= \b FROM \b )//ix
+    or croak "Unrecognizable SELECT: $sql";
 
-  # construct the new select lists, rename(alias) some columns if necessary
-  my (@outer_select, @inner_select, %seen_names, %col_aliases, %outer_col_aliases);
+  my ($insel, $outsel) = $self->_subqueried_limit_attrs ($rs_attrs);
 
-  for (@{$self->{_dbic_rs_attrs}{select}}) {
-    next if ref $_;
-    my ($table, $orig_colname) = ( $_ =~ $col_re );
-    next unless $table;
-    $seen_names{$orig_colname}++;
-  }
+  my $qalias = $self->_quote ($rs_attrs->{alias});
+  my $idx_name = $self->_quote ('rownum__index');
+  my $order_group_having = $self->_parse_rs_attrs($rs_attrs);
 
-  for my $i (0 .. $#sql_select) {
+  $sql = sprintf (<<EOS, $offset + 1, $offset + $rows, );
 
-    my $colsel_arg = $self->{_dbic_rs_attrs}{select}[$i];
-    my $colsel_sql = $sql_select[$i];
+SELECT $outsel FROM (
+  SELECT $outsel, ROWNUM $idx_name FROM (
+    SELECT $insel ${sql}${order_group_having}
+  ) $qalias
+) $qalias WHERE $idx_name BETWEEN %d AND %d
 
-    # this may or may not work (in case of a scalarref or something)
-    my ($table, $orig_colname) = ( $colsel_arg =~ $col_re );
+EOS
 
-    my $quoted_alias;
-    # do not attempt to understand non-scalar selects - alias numerically
-    if (ref $colsel_arg) {
-      $quoted_alias = $self->_quote ('column_' . (@inner_select + 1) );
-    }
-    # column name seen more than once - alias it
-    elsif ($orig_colname &&
-          ($seen_names{$orig_colname} && $seen_names{$orig_colname} > 1) ) {
-      $quoted_alias = $self->_quote ("${table}__${orig_colname}");
-    }
+  $sql =~ s/\s*\n\s*/ /g;   # easier to read in the debugger
+  return $sql;
+}
 
-    # we did rename - make a record and adjust
-    if ($quoted_alias) {
-      # alias inner
-      push @inner_select, "$colsel_sql AS $quoted_alias";
+# Crappy Top based Limit/Offset support. Legacy for MSSQL < 2005
+sub _Top {
+  my ( $self, $sql, $rs_attrs, $rows, $offset ) = @_;
 
-      # push alias to outer
-      push @outer_select, $quoted_alias;
+  # mangle the input sql as we will be replacing the selector
+  $sql =~ s/^ \s* SELECT \s+ .+? \s+ (?= \b FROM \b )//ix
+    or croak "Unrecognizable SELECT: $sql";
 
-      # Any aliasing accumulated here will be considered
-      # both for inner and outer adjustments of ORDER BY
-      $self->__record_alias (
-        \%col_aliases,
-        $quoted_alias,
-        $colsel_arg,
-        $table ? $orig_colname : undef,
-      );
-    }
+  # get selectors
+  my ($in_sel, $out_sel, $alias_map, $extra_order_sel)
+    = $self->_subqueried_limit_attrs ($rs_attrs, 'outer_order_by');
 
-    # otherwise just leave things intact inside, and use the abbreviated one outside
-    # (as we do not have table names anymore)
-    else {
-      push @inner_select, $colsel_sql;
+  my $requested_order = delete $rs_attrs->{order_by};
 
-      my $outer_quoted = $self->_quote ($orig_colname);  # it was not a duplicate so should just work
-      push @outer_select, $outer_quoted;
-      $self->__record_alias (
-        \%outer_col_aliases,
-        $outer_quoted,
-        $colsel_arg,
-        $table ? $orig_colname : undef,
-      );
-    }
-  }
+  my $order_by_requested = $self->_order_by ($requested_order);
 
-  my $outer_select = join (', ', @outer_select );
-  my $inner_select = join (', ', @inner_select );
+  # make up an order unless supplied
+  my $inner_order = ($order_by_requested
+    ? $requested_order
+    : [ map
+      { join ('', $rs_attrs->{alias}, $self->{name_sep}||'.', $_ ) }
+      ( $rs_attrs->{_rsroot_source_handle}->resolve->_pri_cols )
+    ]
+  );
 
-  %outer_col_aliases = (%outer_col_aliases, %col_aliases);
+  my ($order_by_inner, $order_by_reversed);
 
-  # deal with order
-  croak '$order supplied to SQLAHacks limit emulators must be a hash'
-    if (ref $order ne 'HASH');
+  # localise as we already have all the bind values we need
+  {
+    local $self->{order_bind};
+    $order_by_inner = $self->_order_by ($inner_order);
 
-  $order = { %$order }; #copy
+    my @out_chunks;
+    for my $ch ($self->_order_by_chunks ($inner_order)) {
+      $ch = $ch->[0] if ref $ch eq 'ARRAY';
 
-  my $req_order = $order->{order_by};
+      $ch =~ s/\s+ ( ASC|DESC ) \s* $//ix;
+      my $dir = uc ($1||'ASC');
 
-  # examine normalized version, collapses nesting
-  my $limit_order;
-  if (scalar $self->_order_by_chunks ($req_order)) {
-    $limit_order = $req_order;
+      push @out_chunks, \join (' ', $ch, $dir eq 'ASC' ? 'DESC' : 'ASC' );
+    }
+
+    $order_by_reversed = $self->_order_by (\@out_chunks);
   }
-  else {
-    $limit_order = [ map
-      { join ('', $rs_alias, $name_sep, $_ ) }
-      ( $self->{_dbic_rs_attrs}{_source_handle}->resolve->primary_columns )
-    ];
-  }
 
-  my ( $order_by_inner, $order_by_outer ) = $self->_order_directions($limit_order);
-  my $order_by_requested = $self->_order_by ($req_order);
+  # this is the order supplement magic
+  my $mid_sel = $out_sel;
+  if ($extra_order_sel) {
+    for my $extra_col (sort
+      { $extra_order_sel->{$a} cmp $extra_order_sel->{$b} }
+      keys %$extra_order_sel
+    ) {
+      $in_sel .= sprintf (', %s AS %s',
+        $extra_col,
+        $extra_order_sel->{$extra_col},
+      );
 
-  # generate the rest
-  delete $order->{order_by};
-  my $grpby_having = $self->_order_by ($order);
-
-  # short circuit for counts - the ordering complexity is needless
-  if ($self->{_dbic_rs_attrs}{-for_count_only}) {
-    return "SELECT TOP $rows $inner_select $sql $grpby_having $order_by_outer";
+      $mid_sel .= ', ' . $extra_order_sel->{$extra_col};
+    }
   }
 
-  # we can't really adjust the order_by columns, as introspection is lacking
-  # resort to simple substitution
-  for my $col (keys %outer_col_aliases) {
-    for ($order_by_requested, $order_by_outer) {
-      $_ =~ s/\s+$col\s+/ $outer_col_aliases{$col} /g;
+  # and this is order re-alias magic
+  for my $map ($extra_order_sel, $alias_map) {
+    for my $col (keys %$map) {
+      my $re_col = quotemeta ($col);
+      $_ =~ s/$re_col/$map->{$col}/
+        for ($order_by_reversed, $order_by_requested);
     }
   }
-  for my $col (keys %col_aliases) {
-    $order_by_inner =~ s/\s+$col\s+/ $col_aliases{$col} /g;
-  }
 
+  # generate the rest of the sql
+  my $grpby_having = $self->_parse_rs_attrs ($rs_attrs);
 
-  my $inner_lim = $rows + $offset;
+  my $quoted_rs_alias = $self->_quote ($rs_attrs->{alias});
 
-  $sql = "SELECT TOP $inner_lim $inner_select $sql $grpby_having $order_by_inner";
+  $sql = sprintf ('SELECT TOP %d %s %s %s %s',
+    $rows + ($offset||0),
+    $in_sel,
+    $sql,
+    $grpby_having,
+    $order_by_inner,
+  );
 
-  if ($offset) {
-    $sql = <<"SQL";
+  $sql = sprintf ('SELECT TOP %d %s FROM ( %s ) %s %s',
+    $rows,
+    $mid_sel,
+    $sql,
+    $quoted_rs_alias,
+    $order_by_reversed,
+  ) if $offset;
 
-    SELECT TOP $rows $outer_select FROM
-    (
-      $sql
-    ) $quoted_rs_alias
-    $order_by_outer
-SQL
+  $sql = sprintf ('SELECT TOP %d %s FROM ( %s ) %s %s',
+    $rows,
+    $out_sel,
+    $sql,
+    $quoted_rs_alias,
+    $order_by_requested,
+  ) if ( ($offset && $order_by_requested) || ($mid_sel ne $out_sel) );
 
-  }
-
-  if ($order_by_requested) {
-    $sql = <<"SQL";
-
-    SELECT $outer_select FROM
-      ( $sql ) $quoted_rs_alias
-    $order_by_requested
-SQL
-
-  }
-
-  $sql =~ s/\s*\n\s*/ /g; # parsing out multiline statements is harder than a single line
   return $sql;
 }
 
-# action at a distance to shorten Top code above
-sub __record_alias {
-  my ($self, $register, $alias, $fqcol, $col) = @_;
 
-  # record qualified name
-  $register->{$fqcol} = $alias;
-  $register->{$self->_quote($fqcol)} = $alias;
-
-  return unless $col;
-
-  # record unqualified name, undef (no adjustment) if a duplicate is found
-  if (exists $register->{$col}) {
-    $register->{$col} = undef;
-  }
-  else {
-    $register->{$col} = $alias;
-  }
-
-  $register->{$self->_quote($col)} = $register->{$col};
-}
-
-
-
 # While we're at it, this should make LIMIT queries more efficient,
 #  without digging into things too deeply
 sub _find_syntax {
@@ -302,14 +394,10 @@
   return $self->{_cached_syntax} ||= $self->SUPER::_find_syntax($syntax);
 }
 
-my $for_syntax = {
-  update => 'FOR UPDATE',
-  shared => 'FOR SHARE',
-};
 # Quotes table names, handles "limit" dialects (e.g. where rownum between x and
-# y), supports SELECT ... FOR UPDATE and SELECT ... FOR SHARE.
+# y)
 sub select {
-  my ($self, $table, $fields, $where, $order, @rest) = @_;
+  my ($self, $table, $fields, $where, $rs_attrs, @rest) = @_;
 
   $self->{"${_}_bind"} = [] for (qw/having from order/);
 
@@ -317,18 +405,13 @@
     $table = $self->_quote($table);
   }
 
-  local $self->{rownum_hack_count} = 1
-    if (defined $rest[0] && $self->{limit_dialect} eq 'RowNum');
   @rest = (-1) unless defined $rest[0];
   croak "LIMIT 0 Does Not Compute" if $rest[0] == 0;
     # and anyway, SQL::Abstract::Limit will cause a barf if we don't first
+
   my ($sql, @where_bind) = $self->SUPER::select(
-    $table, $self->_recurse_fields($fields), $where, $order, @rest
+    $table, $self->_recurse_fields($fields), $where, $rs_attrs, @rest
   );
-  if (my $for = delete $self->{_dbic_rs_attrs}{for}) {
-    $sql .= " $for_syntax->{$for}" if $for_syntax->{$for};
-  }
-
   return wantarray ? ($sql, @{$self->{from_bind}}, @where_bind, @{$self->{having_bind}}, @{$self->{order_bind}} ) : $sql;
 }
 
@@ -342,7 +425,13 @@
   # which is sadly understood only by MySQL. Change default behavior here,
   # until SQLA2 comes with proper dialect support
   if (! $_[0] or (ref $_[0] eq 'HASH' and !keys %{$_[0]} ) ) {
-    return "INSERT INTO ${table} DEFAULT VALUES"
+    my $sql = "INSERT INTO ${table} DEFAULT VALUES";
+
+    if (my $ret = ($_[1]||{})->{returning} ) {
+      $sql .= $self->_insert_returning ($ret);
+    }
+
+    return $sql;
   }
 
   $self->SUPER::insert($table, @_);
@@ -366,35 +455,36 @@
 
 sub _emulate_limit {
   my $self = shift;
+  # my ( $syntax, $sql, $order, $rows, $offset ) = @_;
+
   if ($_[3] == -1) {
-    return $_[1].$self->_order_by($_[2]);
+    return $_[1] . $self->_parse_rs_attrs($_[2]);
   } else {
     return $self->SUPER::_emulate_limit(@_);
   }
 }
 
 sub _recurse_fields {
-  my ($self, $fields, $params) = @_;
+  my ($self, $fields) = @_;
   my $ref = ref $fields;
   return $self->_quote($fields) unless $ref;
   return $$fields if $ref eq 'SCALAR';
 
   if ($ref eq 'ARRAY') {
-    return join(', ', map {
-      $self->_recurse_fields($_)
-        .(exists $self->{rownum_hack_count} && !($params && $params->{no_rownum_hack})
-          ? ' AS col'.$self->{rownum_hack_count}++
-          : '')
-      } @$fields);
+    return join(', ', map { $self->_recurse_fields($_) } @$fields);
   }
   elsif ($ref eq 'HASH') {
-    my %hash = %$fields;
+    my %hash = %$fields;  # shallow copy
 
     my $as = delete $hash{-as};   # if supplied
 
-    my ($func, $args) = each %hash;
-    delete $hash{$func};
+    my ($func, $args, @toomany) = %hash;
 
+    # there should be only one pair
+    if (@toomany) {
+      croak "Malformed select argument - too many keys in hash: " . join (',', keys %$fields );
+    }
+
     if (lc ($func) eq 'distinct' && ref $args eq 'ARRAY' && @$args > 1) {
       croak (
         'The select => { distinct => ... } syntax is not supported for multiple columns.'
@@ -411,11 +501,6 @@
         : ''
     );
 
-    # there should be nothing left
-    if (keys %hash) {
-      croak "Malformed select argument - too many keys in hash: " . join (',', keys %$fields );
-    }
-
     return $select;
   }
   # Is the second check absolutely necessary?
@@ -427,34 +512,55 @@
   }
 }
 
-sub _order_by {
+my $for_syntax = {
+  update => 'FOR UPDATE',
+  shared => 'FOR SHARE',
+};
+
+# this used to be a part of _order_by but is broken out for clarity.
+# What we have been doing forever is hijacking the $order arg of
+# SQLA::select to pass in arbitrary pieces of data (first the group_by,
+# then pretty much the entire resultset attr-hash, as more and more
+# things in the SQLA space need to have mopre info about the $rs they
+# create SQL for. The alternative would be to keep expanding the
+# signature of _select with more and more positional parameters, which
+# is just gross. All hail SQLA2!
+sub _parse_rs_attrs {
   my ($self, $arg) = @_;
 
-  if (ref $arg eq 'HASH' and keys %$arg and not grep { $_ =~ /^-(?:desc|asc)/i } keys %$arg ) {
+  my $sql = '';
 
-    my $ret = '';
+  if (my $g = $self->_recurse_fields($arg->{group_by}) ) {
+    $sql .= $self->_sqlcase(' group by ') . $g;
+  }
 
-    if (my $g = $self->_recurse_fields($arg->{group_by}, { no_rownum_hack => 1 }) ) {
-      $ret = $self->_sqlcase(' group by ') . $g;
-    }
+  if (defined $arg->{having}) {
+    my ($frag, @bind) = $self->_recurse_where($arg->{having});
+    push(@{$self->{having_bind}}, @bind);
+    $sql .= $self->_sqlcase(' having ') . $frag;
+  }
 
-    if (defined $arg->{having}) {
-      my ($frag, @bind) = $self->_recurse_where($arg->{having});
-      push(@{$self->{having_bind}}, @bind);
-      $ret .= $self->_sqlcase(' having ').$frag;
-    }
+  if (defined $arg->{order_by}) {
+    $sql .= $self->_order_by ($arg->{order_by});
+  }
 
-    if (defined $arg->{order_by}) {
-      my ($frag, @bind) = $self->SUPER::_order_by($arg->{order_by});
-      push(@{$self->{order_bind}}, @bind);
-      $ret .= $frag;
-    }
+  if (my $for = $arg->{for}) {
+    $sql .= " $for_syntax->{$for}" if $for_syntax->{$for};
+  }
 
-    return $ret;
+  return $sql;
+}
+
+sub _order_by {
+  my ($self, $arg) = @_;
+
+  # check that we are not called in legacy mode (order_by as 4th argument)
+  if (ref $arg eq 'HASH' and not grep { $_ =~ /^-(?:desc|asc)/i } keys %$arg ) {
+    return $self->_parse_rs_attrs ($arg);
   }
   else {
     my ($sql, @bind) = $self->SUPER::_order_by ($arg);
-    push(@{$self->{order_bind}}, @bind);
+    push @{$self->{order_bind}}, @bind;
     return $sql;
   }
 }
@@ -485,6 +591,14 @@
   }
 }
 
+sub _generate_join_clause {
+    my ($self, $join_type) = @_;
+
+    return sprintf ('%s JOIN ',
+      $join_type ?  ' ' . uc($join_type) : ''
+    );
+}
+
 sub _recurse_from {
   my ($self, $from, @join) = @_;
   my @sqlf;
@@ -503,10 +617,7 @@
 
     $join_type = $self->{_default_jointype} if not defined $join_type;
 
-    my $join_clause = sprintf ('%s JOIN ',
-      $join_type ?  ' ' . uc($join_type) : ''
-    );
-    push @sqlf, $join_clause;
+    push @sqlf, $self->_generate_join_clause( $join_type );
 
     if (ref $to eq 'ARRAY') {
       push(@sqlf, '(', $self->_recurse_from(@$to), ')');
@@ -567,26 +678,12 @@
   }
 }
 
-sub _quote {
-  my ($self, $label) = @_;
-  return '' unless defined $label;
-  return $$label if ref($label) eq 'SCALAR';
-  return "*" if $label eq '*';
-  return $label unless $self->{quote_char};
-  if(ref $self->{quote_char} eq "ARRAY"){
-    return $self->{quote_char}->[0] . $label . $self->{quote_char}->[1]
-      if !defined $self->{name_sep};
-    my $sep = $self->{name_sep};
-    return join($self->{name_sep},
-        map { $self->{quote_char}->[0] . $_ . $self->{quote_char}->[1]  }
-       split(/\Q$sep\E/,$label));
-  }
-  return $self->SUPER::_quote($label);
-}
-
 sub limit_dialect {
     my $self = shift;
-    $self->{limit_dialect} = shift if @_;
+    if (@_) {
+      $self->{limit_dialect} = shift;
+      undef $self->{_cached_syntax};
+    }
     return $self->{limit_dialect};
 }
 

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Schema/Versioned.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Schema/Versioned.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Schema/Versioned.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -258,7 +258,7 @@
 
 =back
 
-Virtual method that should be overriden to create an upgrade file.
+Virtual method that should be overridden to create an upgrade file.
 This is useful in the case of upgrading across multiple versions
 to concatenate several files to create one upgrade file.
 
@@ -279,7 +279,7 @@
 
 =back
 
-Virtual method that should be overriden to return an ordered list
+Virtual method that should be overridden to return an ordered list
 of schema versions. This is then used to produce a set of steps to
 upgrade through to achieve the required schema version.
 
@@ -303,7 +303,7 @@
 then it is assumed you can do the upgrade as a single step). It
 then iterates through the list of versions between the current db
 version and the schema version applying one update at a time until
-all relvant updates are applied.
+all relevant updates are applied.
 
 The individual update steps are performed by using
 L</upgrade_single_step>, which will apply the update and also
@@ -544,7 +544,7 @@
 compatibility between the old versions table (SchemaVersions) and the new one
 (dbix_class_schema_versions).
 
-To avoid the checks on connect, set the env var DBIC_NO_VERSION_CHECK or alternatively you can set the ignore_version attr in the forth argument like so:
+To avoid the checks on connect, set the environment var DBIC_NO_VERSION_CHECK or alternatively you can set the ignore_version attr in the forth argument like so:
 
   my $schema = MyApp::Schema->connect(
     $dsn,
@@ -617,8 +617,9 @@
     return;
   }
 
-  $self->throw_exception($self->storage->_sqlt_version_error)
-    if (not $self->storage->_sqlt_version_ok);
+  unless (DBIx::Class::Optional::Dependencies->req_ok_for ('deploy')) {
+    $self->throw_exception("Unable to proceed without " . DBIx::Class::Optional::Dependencies->req_missing_for ('deploy') );
+  }
 
   my $db_tr = SQL::Translator->new({
                                     add_drop_table => 1,
@@ -708,12 +709,12 @@
   my @data = split /\n/, join '', <$fh>;
   close $fh;
 
-  @data = grep {
-     $_ &&
-     !/^--/ &&
-     !/^(BEGIN|BEGIN TRANSACTION|COMMIT)/m
-  } split /;/,
-     join '', @data;
+  @data = split /;/,
+     join '',
+       grep { $_ &&
+              !/^--/  &&
+              !/^(BEGIN|BEGIN TRANSACTION|COMMIT)/mi }
+         @data;
 
   return \@data;
 }

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Schema.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Schema.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Schema.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -82,7 +82,7 @@
 
 With no arguments, this method uses L<Module::Find> to load all your
 Result classes from a sub-namespace F<Result> under your Schema class'
-namespace. Eg. With a Schema of I<MyDB::Schema> all files in
+namespace, i.e. with a Schema of I<MyDB::Schema> all files in
 I<MyDB::Schema::Result> are assumed to be Result classes.
 
 It also finds all ResultSet classes in the namespace F<ResultSet> and
@@ -271,6 +271,10 @@
       }
       elsif($rs_class ||= $default_resultset_class) {
         $class->ensure_class_loaded($rs_class);
+        if(!$rs_class->isa("DBIx::Class::ResultSet")) {
+            carp "load_namespaces found ResultSet class $rs_class that does not subclass DBIx::Class::ResultSet";
+        }
+
         $class->_ns_get_rsrc_instance ($result_class)->resultset_class($rs_class);
       }
 
@@ -669,7 +673,7 @@
 
 Begins a transaction (does nothing if AutoCommit is off). Equivalent to
 calling $schema->storage->txn_begin. See
-L<DBIx::Class::Storage::DBI/"txn_begin"> for more information.
+L<DBIx::Class::Storage/"txn_begin"> for more information.
 
 =cut
 
@@ -685,7 +689,7 @@
 =head2 txn_commit
 
 Commits the current transaction. Equivalent to calling
-$schema->storage->txn_commit. See L<DBIx::Class::Storage::DBI/"txn_commit">
+$schema->storage->txn_commit. See L<DBIx::Class::Storage/"txn_commit">
 for more information.
 
 =cut
@@ -703,7 +707,7 @@
 
 Rolls back the current transaction. Equivalent to calling
 $schema->storage->txn_rollback. See
-L<DBIx::Class::Storage::DBI/"txn_rollback"> for more information.
+L<DBIx::Class::Storage/"txn_rollback"> for more information.
 
 =cut
 
@@ -748,7 +752,7 @@
 L<DBIx::Class::ResultSet/create>, and a arrayref of the resulting row
 objects is returned.
 
-i.e.,
+e.g.
 
   $schema->populate('Artist', [
     [ qw/artistid name/ ],
@@ -851,7 +855,7 @@
 
 It also attaches a corresponding L<DBIx::Class::ResultSource> object to the
 new $schema object. If C<$additional_base_class> is given, the new composed
-classes will inherit from first the corresponding classe from the current
+classes will inherit from first the corresponding class from the current
 schema then the base class.
 
 For example, for a schema with My::Schema::CD and My::Schema::Artist classes,
@@ -927,7 +931,7 @@
 
 Creates a new savepoint (does nothing outside a transaction). 
 Equivalent to calling $schema->storage->svp_begin.  See
-L<DBIx::Class::Storage::DBI/"svp_begin"> for more information.
+L<DBIx::Class::Storage/"svp_begin"> for more information.
 
 =cut
 
@@ -944,7 +948,7 @@
 
 Releases a savepoint (does nothing outside a transaction). 
 Equivalent to calling $schema->storage->svp_release.  See
-L<DBIx::Class::Storage::DBI/"svp_release"> for more information.
+L<DBIx::Class::Storage/"svp_release"> for more information.
 
 =cut
 
@@ -961,7 +965,7 @@
 
 Rollback to a savepoint (does nothing outside a transaction). 
 Equivalent to calling $schema->storage->svp_rollback.  See
-L<DBIx::Class::Storage::DBI/"svp_rollback"> for more information.
+L<DBIx::Class::Storage/"svp_rollback"> for more information.
 
 =cut
 
@@ -1155,7 +1159,7 @@
 
 Provided as the recommended way of thawing schema objects. You can call 
 C<Storable::thaw> directly if you wish, but the thawed objects will not have a
-reference to any schema, so are rather useless
+reference to any schema, so are rather useless.
 
 =cut
 
@@ -1167,8 +1171,8 @@
 
 =head2 freeze
 
-This doesn't actualy do anything more than call L<Storable/freeze>, it is just
-provided here for symetry.
+This doesn't actually do anything more than call L<Storable/freeze>, it is just
+provided here for symmetry.
 
 =cut
 

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/StartupCheck.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/StartupCheck.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/StartupCheck.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -17,7 +17,7 @@
 triggers, incorrectly flagging those versions of perl to be buggy. A
 more comprehensive check has been moved into the test suite in
 C<t/99rh_perl_perf_bug.t> and further information about the bug has been
-put in L<DBIx::Class::Manual::Troubleshooting>
+put in L<DBIx::Class::Manual::Troubleshooting>.
 
 Other checks may be added from time to time.
 

Deleted: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/AmbiguousGlob.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/AmbiguousGlob.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/AmbiguousGlob.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -1,47 +0,0 @@
-package DBIx::Class::Storage::DBI::AmbiguousGlob;
-
-use strict;
-use warnings;
-
-use base 'DBIx::Class::Storage::DBI';
-use mro 'c3';
-
-=head1 NAME
-
-DBIx::Class::Storage::DBI::AmbiguousGlob - Storage component for RDBMS choking on count(*)
-
-=head1 DESCRIPTION
-
-Some servers choke on things like:
-
-  COUNT(*) FROM (SELECT tab1.col, tab2.col FROM tab1 JOIN tab2 ... )
-
-claiming that col is a duplicate column (it loses the table specifiers by
-the time it gets to the *). Thus for any subquery count we select only the
-primary keys of the main table in the inner query. This hopefully still
-hits the indexes and keeps the server happy.
-
-At this point the only overriden method is C<_subq_count_select()>
-
-=cut
-
-sub _subq_count_select {
-  my ($self, $source, $rs_attrs) = @_;
-
-  return $rs_attrs->{group_by} if $rs_attrs->{group_by};
-
-  my @pcols = map { join '.', $rs_attrs->{alias}, $_ } ($source->primary_columns);
-  return @pcols ? \@pcols : [ 1 ];
-}
-
-=head1 AUTHORS
-
-See L<DBIx::Class/CONTRIBUTORS>
-
-=head1 LICENSE
-
-You may distribute this code under the same terms as Perl itself.
-
-=cut
-
-1;

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/AutoCast.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/AutoCast.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/AutoCast.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -23,13 +23,14 @@
 throw implicit type conversion errors.
 
 As long as a column L<data_type|DBIx::Class::ResultSource/add_columns> is
-defined, and it resolves to a base RDBMS native type via L</_native_data_type> as
+defined and resolves to a base RDBMS native type via L</_native_data_type> as
 defined in your Storage driver, the placeholder for this column will be
 converted to:
 
   CAST(? as $mapped_type)
 
-This option can also be enabled in L<DBIx::Class::Storage::DBI/connect_info> as:
+This option can also be enabled in
+L<connect_info|DBIx::Class::Storage::DBI/connect_info> as:
 
   on_connect_call => ['set_auto_cast']
 
@@ -76,7 +77,7 @@
 
     on_connect_call => ['set_auto_cast']
 
-in L<DBIx::Class::Storage::DBI/connect_info>.
+in L<connect_info|DBIx::Class::Storage::DBI/connect_info>.
 
 =cut
 

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Informix.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Informix.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Informix.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -3,11 +3,25 @@
 use warnings;
 
 use base qw/DBIx::Class::Storage::DBI/;
-
 use mro 'c3';
 
+use Scope::Guard ();
+use Context::Preserve ();
+
 __PACKAGE__->mk_group_accessors('simple' => '__last_insert_id');
 
+=head1 NAME
+
+DBIx::Class::Storage::DBI::Informix - Base Storage Class for Informix Support
+
+=head1 DESCRIPTION
+
+This class implements storage-specific support for the Informix RDBMS
+
+=head1 METHODS
+
+=cut
+
 sub _execute {
   my $self = shift;
   my ($op) = @_;
@@ -32,24 +46,142 @@
   return { limit_dialect => 'SkipFirst', %{$self->{_sql_maker_opts}||{}} };
 }
 
-1;
+sub _svp_begin {
+    my ($self, $name) = @_;
 
-__END__
+    $self->_get_dbh->do("SAVEPOINT $name");
+}
 
-=head1 NAME
+# can't release savepoints
+sub _svp_release { 1 }
 
-DBIx::Class::Storage::DBI::Informix - Base Storage Class for INFORMIX Support
+sub _svp_rollback {
+    my ($self, $name) = @_;
 
-=head1 SYNOPSIS
+    $self->_get_dbh->do("ROLLBACK TO SAVEPOINT $name")
+}
 
-=head1 DESCRIPTION
+sub with_deferred_fk_checks {
+  my ($self, $sub) = @_;
 
-This class implements storage-specific support for Informix
+  my $txn_scope_guard = $self->txn_scope_guard;
 
-=head1 AUTHORS
+  $self->_do_query('SET CONSTRAINTS ALL DEFERRED');
 
-See L<DBIx::Class/CONTRIBUTORS>
+  my $sg = Scope::Guard->new(sub {
+    $self->_do_query('SET CONSTRAINTS ALL IMMEDIATE');
+  });
 
+  return Context::Preserve::preserve_context(sub { $sub->() },
+    after => sub { $txn_scope_guard->commit });
+}
+
+=head2 connect_call_datetime_setup
+
+Used as:
+
+  on_connect_call => 'datetime_setup'
+
+In L<connect_info|DBIx::Class::Storage::DBI/connect_info> to set the C<DATE> and
+C<DATETIME> formats.
+
+Sets the following environment variables:
+
+    GL_DATE="%m/%d/%Y"
+    GL_DATETIME="%Y-%m-%d %H:%M:%S%F5"
+
+The C<DBDATE> and C<DBCENTURY> environment variables are cleared.
+
+B<NOTE:> setting the C<GL_DATE> environment variable seems to have no effect
+after the process has started, so the default format is used. The C<GL_DATETIME>
+setting does take effect however.
+
+The C<DATETIME> data type supports up to 5 digits after the decimal point for
+second precision, depending on how you have declared your column. The full
+possible precision is used.
+
+The column declaration for a C<DATETIME> with maximum precision is:
+
+  column_name DATETIME YEAR TO FRACTION(5)
+
+The C<DATE> data type stores the date portion only, and it B<MUST> be declared
+with:
+
+  data_type => 'date'
+
+in your Result class.
+
+You will need the L<DateTime::Format::Strptime> module for inflation to work.
+
+=cut
+
+sub connect_call_datetime_setup {
+  my $self = shift;
+
+  delete @ENV{qw/DBDATE DBCENTURY/};
+
+  $ENV{GL_DATE}     = "%m/%d/%Y";
+  $ENV{GL_DATETIME} = "%Y-%m-%d %H:%M:%S%F5";
+}
+
+sub datetime_parser_type {
+  'DBIx::Class::Storage::DBI::Informix::DateTime::Format'
+}
+
+package # hide from PAUSE
+  DBIx::Class::Storage::DBI::Informix::DateTime::Format;
+
+my $timestamp_format = '%Y-%m-%d %H:%M:%S.%5N'; # %F %T
+my $date_format      = '%m/%d/%Y';
+
+my ($timestamp_parser, $date_parser);
+
+sub parse_datetime {
+  shift;
+  require DateTime::Format::Strptime;
+  $timestamp_parser ||= DateTime::Format::Strptime->new(
+    pattern  => $timestamp_format,
+    on_error => 'croak',
+  );
+  return $timestamp_parser->parse_datetime(shift);
+}
+
+sub format_datetime {
+  shift;
+  require DateTime::Format::Strptime;
+  $timestamp_parser ||= DateTime::Format::Strptime->new(
+    pattern  => $timestamp_format,
+    on_error => 'croak',
+  );
+  return $timestamp_parser->format_datetime(shift);
+}
+
+sub parse_date {
+  shift;
+  require DateTime::Format::Strptime;
+  $date_parser ||= DateTime::Format::Strptime->new(
+    pattern  => $date_format,
+    on_error => 'croak',
+  );
+  return $date_parser->parse_datetime(shift);
+}
+
+sub format_date {
+  shift;
+  require DateTime::Format::Strptime;
+  $date_parser ||= DateTime::Format::Strptime->new(
+    pattern  => $date_format,
+    on_error => 'croak',
+  );
+  return $date_parser->format_datetime(shift);
+}
+
+1;
+
+=head1 AUTHOR
+
+See L<DBIx::Class/AUTHOR> and L<DBIx::Class/CONTRIBUTORS>.
+
 =head1 LICENSE
 
 You may distribute this code under the same terms as Perl itself.

Added: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/InterBase.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/InterBase.pm	                        (rev 0)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/InterBase.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -0,0 +1,320 @@
+package DBIx::Class::Storage::DBI::InterBase;
+
+use strict;
+use warnings;
+use base qw/DBIx::Class::Storage::DBI/;
+use mro 'c3';
+use List::Util();
+
+=head1 NAME
+
+DBIx::Class::Storage::DBI::InterBase - Driver for the Firebird RDBMS
+
+=head1 DESCRIPTION
+
+This class implements autoincrements for Firebird using C<RETURNING> as well as
+L<auto_nextval|DBIx::Class::ResultSource/auto_nextval> sets the limit dialect to
+C<FIRST X SKIP X> and provides L<DBIx::Class::InflateColumn::DateTime> support.
+
+You need to use either the
+L<disable_sth_caching|DBIx::Class::Storage::DBI/disable_sth_caching> option or
+L</connect_call_use_softcommit> (see L</CAVEATS>) for your code to function
+correctly with this driver. Otherwise you will likely get bizarre error messages
+such as C<no statement executing>. The alternative is to use the
+L<ODBC|DBIx::Class::Storage::DBI::ODBC::Firebird> driver, which is more suitable
+for long running processes such as under L<Catalyst>.
+
+To turn on L<DBIx::Class::InflateColumn::DateTime> support, see
+L</connect_call_datetime_setup>.
+
+=cut
+
+sub _supports_insert_returning { 1 }
+
+sub _sequence_fetch {
+  my ($self, $nextval, $sequence) = @_;
+
+  if ($nextval ne 'nextval') {
+    $self->throw_exception("Can only fetch 'nextval' for a sequence");
+  }
+
+  $self->throw_exception('No sequence to fetch') unless $sequence;
+  
+  my ($val) = $self->_get_dbh->selectrow_array(
+'SELECT GEN_ID(' . $self->sql_maker->_quote($sequence) .
+', 1) FROM rdb$database');
+
+  return $val;
+} 
+
+sub _dbh_get_autoinc_seq {
+  my ($self, $dbh, $source, $col) = @_;
+
+  my $table_name = $source->from;
+  $table_name    = $$table_name if ref $table_name;
+  $table_name    = $self->sql_maker->quote_char ? $table_name : uc($table_name);
+
+  local $dbh->{LongReadLen} = 100000;
+  local $dbh->{LongTruncOk} = 1;
+
+  my $sth = $dbh->prepare(<<'EOF');
+SELECT t.rdb$trigger_source
+FROM rdb$triggers t
+WHERE t.rdb$relation_name = ?
+AND t.rdb$system_flag = 0 -- user defined
+AND t.rdb$trigger_type = 1 -- BEFORE INSERT
+EOF
+  $sth->execute($table_name);
+
+  while (my ($trigger) = $sth->fetchrow_array) {
+    my @trig_cols = map {
+      /^"([^"]+)/ ? $1 : uc($1)
+    } $trigger =~ /new\.("?\w+"?)/ig;
+
+    my ($quoted, $generator) = $trigger =~
+/(?:gen_id\s* \( \s* |next \s* value \s* for \s*)(")?(\w+)/ix;
+
+    if ($generator) {
+      $generator = uc $generator unless $quoted;
+
+      return $generator
+        if List::Util::first {
+          $self->sql_maker->quote_char ? ($_ eq $col) : (uc($_) eq uc($col))
+        } @trig_cols;
+    }
+  }
+
+  return undef;
+}
+
+# this sub stolen from DB2
+
+sub _sql_maker_opts {
+  my ( $self, $opts ) = @_;
+
+  if ( $opts ) {
+    $self->{_sql_maker_opts} = { %$opts };
+  }
+
+  return { limit_dialect => 'FirstSkip', %{$self->{_sql_maker_opts}||{}} };
+}
+
+sub _svp_begin {
+    my ($self, $name) = @_;
+
+    $self->_get_dbh->do("SAVEPOINT $name");
+}
+
+sub _svp_release {
+    my ($self, $name) = @_;
+
+    $self->_get_dbh->do("RELEASE SAVEPOINT $name");
+}
+
+sub _svp_rollback {
+    my ($self, $name) = @_;
+
+    $self->_get_dbh->do("ROLLBACK TO SAVEPOINT $name")
+}
+
+sub _ping {
+  my $self = shift;
+
+  my $dbh = $self->_dbh or return 0;
+
+  local $dbh->{RaiseError} = 1;
+  local $dbh->{PrintError} = 0;
+
+  eval {
+    $dbh->do('select 1 from rdb$database');
+  };
+
+  return $@ ? 0 : 1;
+}
+
+# We want dialect 3 for new features and quoting to work, DBD::InterBase uses
+# dialect 1 (interbase compat) by default.
+sub _init {
+  my $self = shift;
+  $self->_set_sql_dialect(3);
+}
+
+sub _set_sql_dialect {
+  my $self = shift;
+  my $val  = shift || 3;
+
+  my $dsn = $self->_dbi_connect_info->[0];
+
+  return if ref($dsn) eq 'CODE';
+
+  if ($dsn !~ /ib_dialect=/) {
+    $self->_dbi_connect_info->[0] = "$dsn;ib_dialect=$val";
+    my $connected = defined $self->_dbh;
+    $self->disconnect;
+    $self->ensure_connected if $connected;
+  }
+}
+
+sub _get_server_version {
+  my $self = shift;
+
+  return $self->next::method(@_) if ref $self ne __PACKAGE__;
+
+  local $SIG{__WARN__} = sub {}; # silence warning due to bug in DBD::InterBase
+
+  return $self->next::method(@_);
+}
+
+=head2 connect_call_use_softcommit
+
+Used as:
+
+  on_connect_call => 'use_softcommit'
+
+In L<connect_info|DBIx::Class::Storage::DBI/connect_info> to set the
+L<DBD::InterBase> C<ib_softcommit> option.
+
+You need either this option or C<< disable_sth_caching => 1 >> for
+L<DBIx::Class> code to function correctly (otherwise you may get C<no statement
+executing> errors.) Or use the L<ODBC|DBIx::Class::Storage::DBI::ODBC::Firebird>
+driver.
+
+The downside of using this option is that your process will B<NOT> see UPDATEs,
+INSERTs and DELETEs from other processes for already open statements.
+
+=cut
+
+sub connect_call_use_softcommit {
+  my $self = shift;
+
+  $self->_dbh->{ib_softcommit} = 1;
+}
+
+=head2 connect_call_datetime_setup
+
+Used as:
+
+  on_connect_call => 'datetime_setup'
+
+In L<connect_info|DBIx::Class::Storage::DBI/connect_info> to set the date and
+timestamp formats using:
+
+  $dbh->{ib_time_all} = 'ISO';
+
+See L<DBD::InterBase> for more details.
+
+The C<TIMESTAMP> data type supports up to 4 digits after the decimal point for
+second precision. The full precision is used.
+
+The C<DATE> data type stores the date portion only, and it B<MUST> be declared
+with:
+
+  data_type => 'date'
+
+in your Result class.
+
+Timestamp columns can be declared with either C<datetime> or C<timestamp>.
+
+You will need the L<DateTime::Format::Strptime> module for inflation to work.
+
+For L<DBIx::Class::Storage::DBI::ODBC::Firebird>, this is a noop and sub-second
+precision is not currently available.
+
+=cut
+
+sub connect_call_datetime_setup {
+  my $self = shift;
+
+  $self->_get_dbh->{ib_time_all} = 'ISO';
+}
+
+sub datetime_parser_type {
+  'DBIx::Class::Storage::DBI::InterBase::DateTime::Format'
+}
+
+package # hide from PAUSE
+  DBIx::Class::Storage::DBI::InterBase::DateTime::Format;
+
+my $timestamp_format = '%Y-%m-%d %H:%M:%S.%4N'; # %F %T
+my $date_format      = '%Y-%m-%d';
+
+my ($timestamp_parser, $date_parser);
+
+sub parse_datetime {
+  shift;
+  require DateTime::Format::Strptime;
+  $timestamp_parser ||= DateTime::Format::Strptime->new(
+    pattern  => $timestamp_format,
+    on_error => 'croak',
+  );
+  return $timestamp_parser->parse_datetime(shift);
+}
+
+sub format_datetime {
+  shift;
+  require DateTime::Format::Strptime;
+  $timestamp_parser ||= DateTime::Format::Strptime->new(
+    pattern  => $timestamp_format,
+    on_error => 'croak',
+  );
+  return $timestamp_parser->format_datetime(shift);
+}
+
+sub parse_date {
+  shift;
+  require DateTime::Format::Strptime;
+  $date_parser ||= DateTime::Format::Strptime->new(
+    pattern  => $date_format,
+    on_error => 'croak',
+  );
+  return $date_parser->parse_datetime(shift);
+}
+
+sub format_date {
+  shift;
+  require DateTime::Format::Strptime;
+  $date_parser ||= DateTime::Format::Strptime->new(
+    pattern  => $date_format,
+    on_error => 'croak',
+  );
+  return $date_parser->format_datetime(shift);
+}
+
+1;
+
+=head1 CAVEATS
+
+=over 4
+
+=item *
+
+with L</connect_call_use_softcommit>, you will not be able to see changes made
+to data in other processes. If this is an issue, use
+L<disable_sth_caching|DBIx::Class::Storage::DBI/disable_sth_caching> as a
+workaround for the C<no statement executing> errors, this of course adversely
+affects performance.
+
+Alternately, use the L<ODBC|DBIx::Class::Storage::DBI::ODBC::Firebird> driver.
+
+=item *
+
+C<last_insert_id> support by default only works for Firebird versions 2 or
+greater, L<auto_nextval|DBIx::Class::ResultSource/auto_nextval> however should
+work with earlier versions.
+
+=item *
+
+Sub-second precision for TIMESTAMPs is not currently available when using the
+L<ODBC|DBIx::Class::Storage::DBI::ODBC::Firebird> driver.
+
+=back
+
+=head1 AUTHOR
+
+See L<DBIx::Class/AUTHOR> and L<DBIx::Class/CONTRIBUTORS>.
+
+=head1 LICENSE
+
+You may distribute this code under the same terms as Perl itself.
+
+=cut

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/MSSQL.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/MSSQL.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/MSSQL.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -3,7 +3,7 @@
 use strict;
 use warnings;
 
-use base qw/DBIx::Class::Storage::DBI::AmbiguousGlob DBIx::Class::Storage::DBI/;
+use base qw/DBIx::Class::Storage::DBI::UniqueIdentifier/;
 use mro 'c3';
 
 use List::Util();
@@ -66,43 +66,12 @@
   }
 }
 
-# support MSSQL GUID column types
-
 sub insert {
   my $self = shift;
   my ($source, $to_insert) = @_;
 
   my $supplied_col_info = $self->_resolve_column_info($source, [keys %$to_insert] );
 
-  my %guid_cols;
-  my @pk_cols = $source->primary_columns;
-  my %pk_cols;
-  @pk_cols{@pk_cols} = ();
-
-  my @pk_guids = grep {
-    $source->column_info($_)->{data_type}
-    &&
-    $source->column_info($_)->{data_type} =~ /^uniqueidentifier/i
-  } @pk_cols;
-
-  my @auto_guids = grep {
-    $source->column_info($_)->{data_type}
-    &&
-    $source->column_info($_)->{data_type} =~ /^uniqueidentifier/i
-    &&
-    $source->column_info($_)->{auto_nextval}
-  } grep { not exists $pk_cols{$_} } $source->columns;
-
-  my @get_guids_for =
-    grep { not exists $to_insert->{$_} } (@pk_guids, @auto_guids);
-
-  my $updated_cols = {};
-
-  for my $guid_col (@get_guids_for) {
-    my ($new_guid) = $self->_get_dbh->selectrow_array('SELECT NEWID()');
-    $updated_cols->{$guid_col} = $to_insert->{$guid_col} = $new_guid;
-  }
-
   my $is_identity_insert = (List::Util::first { $_->{is_auto_increment} } (values %$supplied_col_info) )
      ? 1
      : 0;
@@ -111,13 +80,12 @@
      $self->_set_identity_insert ($source->name);
   }
 
-  $updated_cols = { %$updated_cols, %{ $self->next::method(@_) } };
+  my $updated_cols = $self->next::method(@_);
 
   if ($is_identity_insert) {
      $self->_unset_identity_insert ($source->name);
   }
 
-
   return $updated_cols;
 }
 
@@ -190,7 +158,11 @@
 
   # see if this is an ordered subquery
   my $attrs = $_[3];
-  if ( scalar $self->_parse_order_by ($attrs->{order_by}) ) {
+  if (
+    $sql !~ /^ \s* SELECT \s+ TOP \s+ \d+ \s+ /xi
+      &&
+    scalar $self->_parse_order_by ($attrs->{order_by}) 
+  ) {
     $self->throw_exception(
       'An ordered subselect encountered - this is not safe! Please see "Ordered Subselects" in DBIx::Class::Storage::DBI::MSSQL
     ') unless $attrs->{unsafe_subselect_ok};
@@ -222,35 +194,20 @@
   $self->_get_dbh->do("ROLLBACK TRANSACTION $name");
 }
 
-sub build_datetime_parser {
-  my $self = shift;
-  my $type = "DateTime::Format::Strptime";
-  eval "use ${type}";
-  $self->throw_exception("Couldn't load ${type}: $@") if $@;
-  return $type->new( pattern => '%Y-%m-%d %H:%M:%S' );  # %F %T
-}
+sub datetime_parser_type {
+  'DBIx::Class::Storage::DBI::MSSQL::DateTime::Format'
+} 
 
 sub sqlt_type { 'SQLServer' }
 
-sub _get_mssql_version {
-  my $self = shift;
-
-  my $data = $self->_get_dbh->selectrow_hashref('xp_msver ProductVersion');
-
-  if ($data->{Character_Value} =~ /^(\d+)\./) {
-    return $1;
-  } else {
-    $self->throw_exception(q{Your ProductVersion's Character_Value is missing or malformed!});
-  }
-}
-
 sub sql_maker {
   my $self = shift;
 
   unless ($self->_sql_maker) {
     unless ($self->{_sql_maker_opts}{limit_dialect}) {
-      my $version = eval { $self->_get_mssql_version; } || 0;
 
+      my $version = $self->_server_info->{normalized_dbms_version} || 0;
+
       $self->{_sql_maker_opts} = {
         limit_dialect => ($version >= 9 ? 'RowNumberOver' : 'Top'),
         %{$self->{_sql_maker_opts}||{}}
@@ -263,6 +220,69 @@
   return $self->_sql_maker;
 }
 
+sub _ping {
+  my $self = shift;
+
+  my $dbh = $self->_dbh or return 0;
+
+  local $dbh->{RaiseError} = 1;
+  local $dbh->{PrintError} = 0;
+
+  eval {
+    $dbh->do('select 1');
+  };
+
+  return $@ ? 0 : 1;
+}
+
+package # hide from PAUSE
+  DBIx::Class::Storage::DBI::MSSQL::DateTime::Format;
+
+my $datetime_format      = '%Y-%m-%d %H:%M:%S.%3N'; # %F %T 
+my $smalldatetime_format = '%Y-%m-%d %H:%M:%S';
+
+my ($datetime_parser, $smalldatetime_parser);
+
+sub parse_datetime {
+  shift;
+  require DateTime::Format::Strptime;
+  $datetime_parser ||= DateTime::Format::Strptime->new(
+    pattern  => $datetime_format,
+    on_error => 'croak',
+  );
+  return $datetime_parser->parse_datetime(shift);
+}
+
+sub format_datetime {
+  shift;
+  require DateTime::Format::Strptime;
+  $datetime_parser ||= DateTime::Format::Strptime->new(
+    pattern  => $datetime_format,
+    on_error => 'croak',
+  );
+  return $datetime_parser->format_datetime(shift);
+}
+
+sub parse_smalldatetime {
+  shift;
+  require DateTime::Format::Strptime;
+  $smalldatetime_parser ||= DateTime::Format::Strptime->new(
+    pattern  => $smalldatetime_format,
+    on_error => 'croak',
+  );
+  return $smalldatetime_parser->parse_datetime(shift);
+}
+
+sub format_smalldatetime {
+  shift;
+  require DateTime::Format::Strptime;
+  $smalldatetime_parser ||= DateTime::Format::Strptime->new(
+    pattern  => $smalldatetime_format,
+    on_error => 'croak',
+  );
+  return $smalldatetime_parser->format_datetime(shift);
+}
+
 1;
 
 =head1 NAME
@@ -341,7 +361,7 @@
 Thus compromise between usability and perfection is the MSSQL-specific
 L<resultset attribute|DBIx::Class::ResultSet/ATTRIBUTES> C<unsafe_subselect_ok>.
 It is deliberately not possible to set this on the Storage level, as the user
-should inspect (and preferrably regression-test) the return of every such
+should inspect (and preferably regression-test) the return of every such
 ResultSet individually. The example above would work if written like:
 
  $rs->search ({}, {
@@ -354,11 +374,11 @@
 If it is possible to rewrite the search() in a way that will avoid the need
 for this flag - you are urged to do so. If DBIC internals insist that an
 ordered subselect is necessary for an operation, and you believe there is a
-differnt/better way to get the same result - please file a bugreport.
+different/better way to get the same result - please file a bugreport.
 
 =head1 AUTHOR
 
-See L<DBIx::Class/CONTRIBUTORS>.
+See L<DBIx::Class/AUTHOR> and L<DBIx::Class/CONTRIBUTORS>.
 
 =head1 LICENSE
 

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/MultiColumnIn.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/MultiColumnIn.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/MultiColumnIn.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -17,7 +17,7 @@
 The storage class for any such RDBMS should inherit from this class, in order
 to dramatically speed up update/delete operations on joined multipk resultsets.
 
-At this point the only overriden method is C<_multipk_update_delete()>
+At this point the only overridden method is C<_multipk_update_delete()>
 
 =cut
 
@@ -26,7 +26,7 @@
   my ($rs, $op, $values) = @_;
 
   my $rsrc = $rs->result_source;
-  my @pcols = $rsrc->primary_columns;
+  my @pcols = $rsrc->_pri_cols;
   my $attrs = $rs->_resolved_attrs;
 
   # naive check - this is an internal method after all, we should know what we are doing 

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/ODBC/ACCESS.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/ODBC/ACCESS.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/ODBC/ACCESS.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -79,7 +79,7 @@
 
 =head1 IMPLEMENTATION NOTES
 
-MS Access supports the @@IDENTITY function for retriving the id of the latest inserted row.
+MS Access supports the @@IDENTITY function for retrieving the id of the latest inserted row.
 @@IDENTITY is global to the connection, so to support the possibility of getting the last inserted
 id for different tables, the insert() function stores the inserted id on a per table basis.
 last_insert_id() then just returns the stored value.

Added: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/ODBC/Firebird.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/ODBC/Firebird.pm	                        (rev 0)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/ODBC/Firebird.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -0,0 +1,95 @@
+package DBIx::Class::Storage::DBI::ODBC::Firebird;
+
+use strict;
+use warnings;
+use base qw/DBIx::Class::Storage::DBI::InterBase/;
+use mro 'c3';
+
+=head1 NAME
+
+DBIx::Class::Storage::DBI::ODBC::Firebird - Driver for using the Firebird RDBMS
+through ODBC
+
+=head1 DESCRIPTION
+
+Most functionality is provided by L<DBIx::Class::Storage::DBI::Interbase>, see
+that module for details.
+
+To build the ODBC driver for Firebird on Linux for unixODBC, see:
+
+L<http://www.firebirdnews.org/?p=1324>
+
+This driver does not suffer from the nested statement handles across commits
+issue that the L<DBD::InterBase|DBIx::Class::Storage::DBI::InterBase> based
+driver does. This makes it more suitable for long running processes such as
+under L<Catalyst>.
+
+=cut
+
+# XXX seemingly no equivalent to ib_time_all from DBD::InterBase via ODBC
+sub connect_call_datetime_setup { 1 }
+
+# we don't need DBD::InterBase-specific initialization
+sub _init { 1 }
+
+# ODBC uses dialect 3 by default, good
+sub _set_sql_dialect { 1 }
+
+# releasing savepoints doesn't work, but that shouldn't matter
+sub _svp_release { 1 }
+
+sub datetime_parser_type {
+  'DBIx::Class::Storage::DBI::ODBC::Firebird::DateTime::Format'
+}
+
+package # hide from PAUSE
+  DBIx::Class::Storage::DBI::ODBC::Firebird::DateTime::Format;
+
+# inherit parse/format date
+our @ISA = 'DBIx::Class::Storage::DBI::InterBase::DateTime::Format';
+
+my $timestamp_format = '%Y-%m-%d %H:%M:%S'; # %F %T, no fractional part
+my $timestamp_parser;
+
+sub parse_datetime {
+  shift;
+  require DateTime::Format::Strptime;
+  $timestamp_parser ||= DateTime::Format::Strptime->new(
+    pattern  => $timestamp_format,
+    on_error => 'croak',
+  );
+  return $timestamp_parser->parse_datetime(shift);
+}
+
+sub format_datetime {
+  shift;
+  require DateTime::Format::Strptime;
+  $timestamp_parser ||= DateTime::Format::Strptime->new(
+    pattern  => $timestamp_format,
+    on_error => 'croak',
+  );
+  return $timestamp_parser->format_datetime(shift);
+}
+
+1;
+
+=head1 CAVEATS
+
+=over 4
+
+=item *
+
+This driver (unlike L<DBD::InterBase>) does not currently support reading or
+writing C<TIMESTAMP> values with sub-second precision.
+
+=back
+
+=head1 AUTHOR
+
+See L<DBIx::Class/AUTHOR> and L<DBIx::Class/CONTRIBUTORS>.
+
+=head1 LICENSE
+
+You may distribute this code under the same terms as Perl itself.
+
+=cut

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/ODBC/Microsoft_SQL_Server.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/ODBC/Microsoft_SQL_Server.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/ODBC/Microsoft_SQL_Server.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -37,7 +37,7 @@
 
   on_connect_call => 'use_dynamic_cursors'
 
-in your L<DBIx::Class::Storage::DBI/connect_info> as one way to enable multiple
+in your L<connect_info|DBIx::Class::Storage::DBI/connect_info> as one way to enable multiple
 concurrent statements.
 
 Will add C<< odbc_cursortype => 2 >> to your DBI connection attributes. See
@@ -175,14 +175,6 @@
   }
 }
 
-sub _get_mssql_version {
-  my $self = shift;
-
-  my ($version) = $self->_get_dbh->get_info(18) =~ /^(\d+)/;
-
-  return $version;
-}
-
 1;
 
 =head1 AUTHOR

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/ODBC.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/ODBC.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/ODBC.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -21,15 +21,6 @@
     }
 }
 
-sub _dbh_last_insert_id {
-    my ($self, $dbh, $source, $col) = @_;
-
-    # punt: if there is no derived class for the specific backend, attempt
-    # to use the DBI->last_insert_id, which may not be sufficient (see the
-    # discussion of last_insert_id in perldoc DBI)
-    return $dbh->last_insert_id(undef, undef, $source->from, $col);
-}
-
 1;
 
 =head1 NAME

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Oracle/Generic.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Oracle/Generic.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Oracle/Generic.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -2,6 +2,8 @@
 
 use strict;
 use warnings;
+use Scope::Guard ();
+use Context::Preserve ();
 
 =head1 NAME
 
@@ -28,6 +30,22 @@
 use base qw/DBIx::Class::Storage::DBI/;
 use mro 'c3';
 
+sub deployment_statements {
+  my $self = shift;;
+  my ($schema, $type, $version, $dir, $sqltargs, @rest) = @_;
+
+  $sqltargs ||= {};
+  my $quote_char = $self->schema->storage->sql_maker->quote_char;
+  $sqltargs->{quote_table_names} = $quote_char ? 1 : 0;
+  $sqltargs->{quote_field_names} = $quote_char ? 1 : 0;
+
+  my $oracle_version = eval { $self->_get_dbh->get_info(18) };
+
+  $sqltargs->{producer_args}{oracle_version} = $oracle_version;
+
+  $self->next::method($schema, $type, $version, $dir, $sqltargs, @rest);
+}
+
 sub _dbh_last_insert_id {
   my ($self, $dbh, $source, @columns) = @_;
   my @ids = ();
@@ -42,46 +60,42 @@
 sub _dbh_get_autoinc_seq {
   my ($self, $dbh, $source, $col) = @_;
 
-  # look up the correct sequence automatically
-  my $sql = q{
-    SELECT trigger_body FROM ALL_TRIGGERS t
-    WHERE t.table_name = ?
-    AND t.triggering_event = 'INSERT'
-    AND t.status = 'ENABLED'
-  };
+  my $sql_maker = $self->sql_maker;
 
-  # trigger_body is a LONG
-  local $dbh->{LongReadLen} = 64 * 1024 if ($dbh->{LongReadLen} < 64 * 1024);
-
-  my $sth;
-
   my $source_name;
-  if ( ref $source->name ne 'SCALAR' ) {
-      $source_name = $source->name;
+  if ( ref $source->name eq 'SCALAR' ) {
+    $source_name = ${$source->name};
   }
   else {
-      $source_name = ${$source->name};
+    $source_name = $source->name;
   }
+  $source_name = uc($source_name) unless $sql_maker->quote_char;
 
-  # check for fully-qualified name (eg. SCHEMA.TABLENAME)
-  if ( my ( $schema, $table ) = $source_name =~ /(\w+)\.(\w+)/ ) {
-    $sql = q{
-      SELECT trigger_body FROM ALL_TRIGGERS t
-      WHERE t.owner = ? AND t.table_name = ?
-      AND t.triggering_event = 'INSERT'
-      AND t.status = 'ENABLED'
-    };
-    $sth = $dbh->prepare($sql);
-    $sth->execute( uc($schema), uc($table) );
-  }
-  else {
-    $sth = $dbh->prepare($sql);
-    $sth->execute( uc( $source_name ) );
-  }
+  # trigger_body is a LONG
+  local $dbh->{LongReadLen} = 64 * 1024 if ($dbh->{LongReadLen} < 64 * 1024);
+
+  # disable default bindtype
+  local $sql_maker->{bindtype} = 'normal';
+
+  # look up the correct sequence automatically
+  my ( $schema, $table ) = $source_name =~ /(\w+)\.(\w+)/;
+  my ($sql, @bind) = $sql_maker->select (
+    'ALL_TRIGGERS',
+    ['trigger_body'],
+    {
+      $schema ? (owner => $schema) : (),
+      table_name => $table || $source_name,
+      triggering_event => 'INSERT',
+      status => 'ENABLED',
+     },
+  );
+  my $sth = $dbh->prepare($sql);
+  $sth->execute (@bind);
+
   while (my ($insert_trigger) = $sth->fetchrow_array) {
-    return uc($1) if $insert_trigger =~ m!(\w+)\.nextval!i; # col name goes here???
+    return $1 if $insert_trigger =~ m!("?\w+"?)\.nextval!i; # col name goes here???
   }
-  $self->throw_exception("Unable to find a sequence INSERT trigger on table '" . $source->name . "'.");
+  $self->throw_exception("Unable to find a sequence INSERT trigger on table '$source_name'.");
 }
 
 sub _sequence_fetch {
@@ -96,9 +110,10 @@
   my $dbh = $self->_dbh or return 0;
 
   local $dbh->{RaiseError} = 1;
+  local $dbh->{PrintError} = 0;
 
   eval {
-    $dbh->do("select 1 from dual");
+    $dbh->do('select 1 from dual');
   };
 
   return $@ ? 0 : 1;
@@ -135,7 +150,7 @@
 
   $self->throw_exception($exception) if $exception;
 
-  wantarray ? @res : $res[0]
+  $wantarray ? @res : $res[0]
 }
 
 =head2 get_autoinc_seq
@@ -160,7 +175,7 @@
 sub columns_info_for {
   my ($self, $table) = @_;
 
-  $self->next::method(uc($table));
+  $self->next::method($table);
 }
 
 =head2 datetime_parser_type
@@ -178,10 +193,10 @@
 
     on_connect_call => 'datetime_setup'
 
-In L<DBIx::Class::Storage::DBI/connect_info> to set the session nls date, and
-timestamp values for use with L<DBIx::Class::InflateColumn::DateTime> and the
-necessary environment variables for L<DateTime::Format::Oracle>, which is used
-by it.
+In L<connect_info|DBIx::Class::Storage::DBI/connect_info> to set the session nls
+date, and timestamp values for use with L<DBIx::Class::InflateColumn::DateTime>
+and the necessary environment variables for L<DateTime::Format::Oracle>, which
+is used by it.
 
 Maximum allowable precision is used, unless the environment variables have
 already been set.
@@ -326,6 +341,35 @@
   return $new_alias;
 }
 
+=head2 with_deferred_fk_checks
+
+Runs a coderef between:
+
+  alter session set constraints = deferred
+  ...
+  alter session set constraints = immediate
+
+to defer foreign key checks.
+
+Constraints must be declared C<DEFERRABLE> for this to work.
+
+=cut
+
+sub with_deferred_fk_checks {
+  my ($self, $sub) = @_;
+
+  my $txn_scope_guard = $self->txn_scope_guard;
+
+  $self->_do_query('alter session set constraints = deferred');
+  
+  my $sg = Scope::Guard->new(sub {
+    $self->_do_query('alter session set constraints = immediate');
+  });
+
+  return Context::Preserve::preserve_context(sub { $sub->() },
+    after => sub { $txn_scope_guard->commit });
+}
+
 =head1 AUTHOR
 
 See L<DBIx::Class/CONTRIBUTORS>.

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Oracle/WhereJoins.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Oracle/WhereJoins.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Oracle/WhereJoins.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -23,8 +23,7 @@
 
 This module was originally written to support Oracle < 9i where ANSI joins
 weren't supported at all, but became the module for Oracle >= 8 because
-Oracle's optimising of ANSI joins is horrible.  (See:
-http://scsys.co.uk:8001/7495)
+Oracle's optimising of ANSI joins is horrible.
 
 =head1 SYNOPSIS
 
@@ -44,7 +43,7 @@
 It should properly support left joins, and right joins.  Full outer joins are
 not possible due to the fact that Oracle requires the entire query be written
 to union the results of a left and right join, and by the time this module is
-called to create the where query and table definition part of the sql query,
+called to create the where query and table definition part of the SQL query,
 it's already too late.
 
 =head1 METHODS

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Pg.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Pg.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Pg.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -3,22 +3,44 @@
 use strict;
 use warnings;
 
-use base qw/DBIx::Class::Storage::DBI::MultiColumnIn/;
+use base qw/
+    DBIx::Class::Storage::DBI::MultiColumnIn
+/;
 use mro 'c3';
 
 use DBD::Pg qw(:pg_types);
+use Scope::Guard ();
+use Context::Preserve ();
 
 # Ask for a DBD::Pg with array support
-warn "DBD::Pg 2.9.2 or greater is strongly recommended\n"
+warn __PACKAGE__.": DBD::Pg 2.9.2 or greater is strongly recommended\n"
   if ($DBD::Pg::VERSION < 2.009002);  # pg uses (used?) version::qv()
 
+sub _supports_insert_returning {
+  my $self = shift;
+
+  return 1
+    if $self->_server_info->{normalized_dbms_version} >= 8.002;
+
+  return 0;
+}
+
 sub with_deferred_fk_checks {
   my ($self, $sub) = @_;
 
-  $self->_get_dbh->do('SET CONSTRAINTS ALL DEFERRED');
-  $sub->();
+  my $txn_scope_guard = $self->txn_scope_guard;
+
+  $self->_do_query('SET CONSTRAINTS ALL DEFERRED');
+
+  my $sg = Scope::Guard->new(sub {
+    $self->_do_query('SET CONSTRAINTS ALL IMMEDIATE');
+  });
+
+  return Context::Preserve::preserve_context(sub { $sub->() },
+    after => sub { $txn_scope_guard->commit });
 }
 
+# only used when INSERT ... RETURNING is disabled
 sub last_insert_id {
   my ($self,$source, at cols) = @_;
 
@@ -32,20 +54,24 @@
           $col,
       ));
 
-    push @values, $self->_dbh_last_insert_id ($self->_dbh, $seq);
+    push @values, $self->_dbh->last_insert_id(undef, undef, undef, undef, {sequence => $seq});
   }
 
   return @values;
 }
 
-# there seems to be absolutely no reason to have this as a separate method,
-# but leaving intact in case someone is already overriding it
-sub _dbh_last_insert_id {
-  my ($self, $dbh, $seq) = @_;
-  $dbh->last_insert_id(undef, undef, undef, undef, {sequence => $seq});
+sub _sequence_fetch {
+  my ($self, $function, $sequence) = @_;
+
+  $self->throw_exception('No sequence to fetch') unless $sequence;
+
+  my ($val) = $self->_get_dbh->selectrow_array(
+    sprintf ("select %s('%s')", $function, $sequence)
+  );
+
+  return $val;
 }
 
-
 sub _dbh_get_autoinc_seq {
   my ($self, $dbh, $source, $col) = @_;
 
@@ -155,12 +181,6 @@
   }
 }
 
-sub _sequence_fetch {
-  my ( $self, $type, $seq ) = @_;
-  my ($id) = $self->_get_dbh->selectrow_array("SELECT nextval('${seq}')");
-  return $id;
-}
-
 sub _svp_begin {
     my ($self, $name) = @_;
 

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Replicated/Balancer/First.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Replicated/Balancer/First.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Replicated/Balancer/First.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -19,7 +19,7 @@
 database's (L<DBIx::Class::Storage::DBI::Replicated::Replicant>), defines a
 method by which query load can be spread out across each replicant in the pool.
 
-This Balancer just get's whatever is the first replicant in the pool
+This Balancer just gets whichever is the first replicant in the pool.
 
 =head1 ATTRIBUTES
 

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Replicated/Balancer.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Replicated/Balancer.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Replicated/Balancer.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -110,7 +110,7 @@
 This method should be defined in the class which consumes this role.
 
 Given a pool object, return the next replicant that will serve queries.  The
-default behavior is to grap the first replicant it finds but you can write 
+default behavior is to grab the first replicant it finds but you can write 
 your own subclasses of L<DBIx::Class::Storage::DBI::Replicated::Balancer> to 
 support other balance systems.
 

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Replicated/Introduction.pod
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Replicated/Introduction.pod	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Replicated/Introduction.pod	2010-05-06 09:42:51 UTC (rev 9313)
@@ -9,8 +9,8 @@
 This is an introductory document for L<DBIx::Class::Storage::Replication>.
 
 This document is not an overview of what replication is or why you should be
-using it.  It is not a document explaing how to setup MySQL native replication
-either.  Copious external resources are avialable for both.  This document
+using it.  It is not a document explaining how to setup MySQL native replication
+either.  Copious external resources are available for both.  This document
 presumes you have the basics down.
   
 =head1 DESCRIPTION
@@ -33,7 +33,7 @@
 For an easy way to start playing with MySQL native replication, see:
 L<MySQL::Sandbox>.
 
-If you are using this with a L<Catalyst> based appplication, you may also wish
+If you are using this with a L<Catalyst> based application, you may also want
 to see more recent updates to L<Catalyst::Model::DBIC::Schema>, which has 
 support for replication configuration options as well.
 
@@ -41,15 +41,15 @@
 
 By default, when you start L<DBIx::Class>, your Schema (L<DBIx::Class::Schema>)
 is assigned a storage_type, which when fully connected will reflect your
-underlying storage engine as defined by your choosen database driver.  For
+underlying storage engine as defined by your chosen database driver.  For
 example, if you connect to a MySQL database, your storage_type will be
 L<DBIx::Class::Storage::DBI::mysql>  Your storage type class will contain 
 database specific code to help smooth over the differences between databases
 and let L<DBIx::Class> do its thing.
 
 If you want to use replication, you will override this setting so that the
-replicated storage engine will 'wrap' your underlying storages and present to
-the end programmer a unified interface.  This wrapper storage class will
+replicated storage engine will 'wrap' your underlying storages and present 
+a unified interface to the end programmer.  This wrapper storage class will
 delegate method calls to either a master database or one or more replicated
 databases based on if they are read only (by default sent to the replicants)
 or write (reserved for the master).  Additionally, the Replicated storage 
@@ -72,8 +72,8 @@
 storage itself (L<DBIx::Class::Storage::DBI::Replicated>).  A replicated storage
 takes a pool of replicants (L<DBIx::Class::Storage::DBI::Replicated::Pool>)
 and a software balancer (L<DBIx::Class::Storage::DBI::Replicated::Pool>).  The
-balancer does the job of splitting up all the read traffic amongst each
-replicant in the Pool. Currently there are two types of balancers, a Random one
+balancer does the job of splitting up all the read traffic amongst the
+replicants in the Pool. Currently there are two types of balancers, a Random one
 which chooses a Replicant in the Pool using a naive randomizer algorithm, and a
 First replicant, which just uses the first one in the Pool (and obviously is
 only of value when you have a single replicant).
@@ -132,7 +132,7 @@
 balancers have the 'auto_validate_every' option.  This is the number of seconds
 we allow to pass between validation checks on a load balanced replicant. So
 the higher the number, the more possibility that your reads to the replicant 
-may be inconsistant with what's on the master.  Setting this number too low
+may be inconsistent with what's on the master.  Setting this number too low
 will result in increased database loads, so choose a number with care.  Our
 experience is that setting the number around 5 seconds results in a good
 performance / integrity balance.
@@ -145,14 +145,14 @@
 This object (L<DBIx::Class::Storage::DBI::Replicated::Pool>) manages all the
 declared replicants.  'maximum_lag' is the number of seconds a replicant is
 allowed to lag behind the master before being temporarily removed from the pool.
-Keep in mind that the Balancer option 'auto_validate_every' determins how often
+Keep in mind that the Balancer option 'auto_validate_every' determines how often
 a replicant is tested against this condition, so the true possible lag can be
 higher than the number you set.  The default is zero.
 
 No matter how low you set the maximum_lag or the auto_validate_every settings,
 there is always the chance that your replicants will lag a bit behind the
 master for the supported replication system built into MySQL.  You can ensure
-reliabily reads by using a transaction, which will force both read and write
+reliable reads by using a transaction, which will force both read and write
 activity to the master, however this will increase the load on your master
 database.
 

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Replicated/Pool.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Replicated/Pool.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Replicated/Pool.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -7,6 +7,7 @@
 use DBI ();
 use Carp::Clan qw/^DBIx::Class/;
 use MooseX::Types::Moose qw/Num Int ClassName HashRef/;
+use DBIx::Class::Storage::DBI::Replicated::Types 'DBICStorageDBI';
 
 use namespace::clean -except => 'meta';
 
@@ -22,7 +23,7 @@
 =head1 DESCRIPTION
 
 In a replicated storage type, there is at least one replicant to handle the
-read only traffic.  The Pool class manages this replicant, or list of 
+read-only traffic.  The Pool class manages this replicant, or list of 
 replicants, and gives some methods for querying information about their status.
 
 =head1 ATTRIBUTES
@@ -52,7 +53,7 @@
 
 This is an integer representing a time since the last time the replicants were
 validated. It's nothing fancy, just an integer provided via the perl L<time|perlfunc/time>
-builtin.
+built-in.
 
 =cut
 
@@ -86,7 +87,7 @@
 =head2 replicants
 
 A hashref of replicant, with the key being the dsn and the value returning the
-actual replicant storage.  For example if the $dsn element is something like:
+actual replicant storage.  For example, if the $dsn element is something like:
 
   "dbi:SQLite:dbname=dbfile"
 
@@ -116,7 +117,7 @@
 
 =item delete_replicant ($key)
 
-removes the replicant under $key from the pool
+Removes the replicant under $key from the pool
 
 =back
 
@@ -152,6 +153,14 @@
   },
 );
 
+=head2 master
+
+Reference to the master Storage.
+
+=cut
+
+has master => (is => 'rw', isa => DBICStorageDBI, weak_ref => 1);
+
 =head1 METHODS
 
 This class defines the following methods.
@@ -243,7 +252,13 @@
     $replicant->_determine_driver
   });
 
-  DBIx::Class::Storage::DBI::Replicated::Replicant->meta->apply($replicant);  
+  Moose::Meta::Class->initialize(ref $replicant);
+
+  DBIx::Class::Storage::DBI::Replicated::Replicant->meta->apply($replicant);
+
+  # link back to master
+  $replicant->master($self->master);
+
   return $replicant;
 }
 
@@ -253,7 +268,7 @@
 connect.  For the master database this is desirable, but since replicants are
 allowed to fail, this behavior is not desirable.  This method wraps the call
 to ensure_connected in an eval in order to catch any generated errors.  That
-way a slave can go completely offline (ie, the box itself can die) without
+way a slave can go completely offline (e.g. the box itself can die) without
 bringing down your entire pool of databases.
 
 =cut
@@ -350,7 +365,7 @@
 inactive, and thus removed from the replication pool.
 
 This tests L<all_replicants>, since a replicant that has been previous marked
-as inactive can be reactived should it start to pass the validation tests again.
+as inactive can be reactivated should it start to pass the validation tests again.
 
 See L<DBIx::Class::Storage::DBI> for more about checking if a replicating
 connection is not following a master or is lagging.

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Replicated/Replicant.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Replicated/Replicant.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Replicated/Replicant.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -4,6 +4,7 @@
 requires qw/_query_start/;
 with 'DBIx::Class::Storage::DBI::Replicated::WithDSN';
 use MooseX::Types::Moose qw/Bool Str/;
+use DBIx::Class::Storage::DBI::Replicated::Types 'DBICStorageDBI';
 
 use namespace::clean -except => 'meta';
 
@@ -32,14 +33,14 @@
 =head2 active
 
 This is a boolean which allows you to programmatically activate or deactivate a
-replicant from the pool.  This way to you do stuff like disallow a replicant
-when it get's too far behind the master, if it stops replicating, etc.
+replicant from the pool.  This way you can do stuff like disallow a replicant
+when it gets too far behind the master, if it stops replicating, etc.
 
 This attribute DOES NOT reflect a replicant's internal status, i.e. if it is
 properly replicating from a master and has not fallen too many seconds behind a
 reliability threshold.  For that, use L</is_replicating>  and L</lag_behind_master>.
 Since the implementation of those functions database specific (and not all DBIC
-supported DB's support replication) you should refer your database specific
+supported DBs support replication) you should refer your database-specific
 storage driver for more information.
 
 =cut
@@ -55,6 +56,14 @@
 has dsn => (is => 'rw', isa => Str);
 has id  => (is => 'rw', isa => Str);
 
+=head2 master
+
+Reference to the master Storage.
+
+=cut
+
+has master => (is => 'rw', isa => DBICStorageDBI, weak_ref => 1);
+
 =head1 METHODS
 
 This class defines the following methods.
@@ -66,7 +75,9 @@
 =cut
 
 sub debugobj {
-    return shift->schema->storage->debugobj;
+  my $self = shift;
+
+  return $self->master->debugobj;
 }
 
 =head1 ALSO SEE

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Replicated.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Replicated.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Replicated.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -2,27 +2,9 @@
 
 BEGIN {
   use Carp::Clan qw/^DBIx::Class/;
-
-  ## Modules required for Replication support not required for general DBIC
-  ## use, so we explicitly test for these.
-
-  my %replication_required = (
-    'Moose' => '0.90',
-    'MooseX::Types' => '0.21',
-    'namespace::clean' => '0.11',
-    'Hash::Merge' => '0.11'
-  );
-
-  my @didnt_load;
-
-  for my $module (keys %replication_required) {
-    eval "use $module $replication_required{$module}";
-    push @didnt_load, "$module $replication_required{$module}"
-      if $@;
-  }
-
-  croak("@{[ join ', ', @didnt_load ]} are missing and are required for Replication")
-    if @didnt_load;
+  use DBIx::Class;
+  croak('The following modules are required for Replication ' . DBIx::Class::Optional::Dependencies->req_missing_for ('replicated') )
+    unless DBIx::Class::Optional::Dependencies->req_ok_for ('replicated');
 }
 
 use Moose;
@@ -32,7 +14,8 @@
 use DBIx::Class::Storage::DBI::Replicated::Types qw/BalancerClassNamePart DBICSchema DBICStorageDBI/;
 use MooseX::Types::Moose qw/ClassName HashRef Object/;
 use Scalar::Util 'reftype';
-use Hash::Merge 'merge';
+use Hash::Merge;
+use List::Util qw/min max reduce/;
 
 use namespace::clean -except => 'meta';
 
@@ -43,7 +26,7 @@
 =head1 SYNOPSIS
 
 The Following example shows how to change an existing $schema to a replicated
-storage type, add some replicated (readonly) databases, and perform reporting
+storage type, add some replicated (read-only) databases, and perform reporting
 tasks.
 
 You should set the 'storage_type attribute to a replicated type.  You should
@@ -92,7 +75,7 @@
 Warning: This class is marked BETA.  This has been running a production
 website using MySQL native replication as its backend and we have some decent
 test coverage but the code hasn't yet been stressed by a variety of databases.
-Individual DB's may have quirks we are not aware of.  Please use this in first
+Individual DBs may have quirks we are not aware of.  Please use this in first
 development and pass along your experiences/bug fixes.
 
 This class implements replicated data store for DBI. Currently you can define
@@ -106,28 +89,21 @@
 to all existing storages.  This way our storage class is a drop in replacement
 for L<DBIx::Class::Storage::DBI>.
 
-Read traffic is spread across the replicants (slaves) occuring to a user
+Read traffic is spread across the replicants (slaves) occurring to a user
 selected algorithm.  The default algorithm is random weighted.
 
 =head1 NOTES
 
-The consistancy betweeen master and replicants is database specific.  The Pool
+The consistency between master and replicants is database specific.  The Pool
 gives you a method to validate its replicants, removing and replacing them
 when they fail/pass predefined criteria.  Please make careful use of the ways
 to force a query to run against Master when needed.
 
 =head1 REQUIREMENTS
 
-Replicated Storage has additional requirements not currently part of L<DBIx::Class>
+Replicated Storage has additional requirements not currently part of
+L<DBIx::Class>. See L<DBIx::Class::Optional::Dependencies> for more details.
 
-  Moose => '0.90',
-  MooseX::Types => '0.21',
-  namespace::clean => '0.11',
-  Hash::Merge => '0.11'
-
-You will need to install these modules manually via CPAN or make them part of the
-Makefile for your distribution.
-
 =head1 ATTRIBUTES
 
 This class defines the following attributes.
@@ -276,12 +252,17 @@
     select
     select_single
     columns_info_for
+    _dbh_columns_info_for 
+    _select
   /],
 );
 
 =head2 write_handler
 
-Defines an object that implements the write side of L<BIx::Class::Storage::DBI>.
+Defines an object that implements the write side of L<BIx::Class::Storage::DBI>,
+as well as methods that don't write or read that can be called on only one
+storage, methods that return a C<$dbh>, and any methods that don't make sense to
+run on a replicant.
 
 =cut
 
@@ -292,7 +273,10 @@
   handles=>[qw/
     on_connect_do
     on_disconnect_do
+    on_connect_call
+    on_disconnect_call
     connect_info
+    _connect_info
     throw_exception
     sql_maker
     sqlt_type
@@ -322,22 +306,89 @@
 
     backup
     is_datatype_numeric
+    _supports_insert_returning
     _count_select
-    _subq_count_select
     _subq_update_delete
     svp_rollback
     svp_begin
     svp_release
+    relname_to_table_alias
+    _straight_join_to_node
+    _dbh_last_insert_id
+    _fix_bind_params
+    _default_dbi_connect_attributes
+    _dbi_connect_info
+    auto_savepoint
+    _sqlt_version_ok
+    _query_end
+    bind_attribute_by_data_type
+    transaction_depth
+    _dbh
+    _select_args
+    _dbh_execute_array
+    _sql_maker_args
+    _sql_maker
+    _query_start
+    _sqlt_version_error
+    _per_row_update_delete
+    _dbh_begin_work
+    _dbh_execute_inserts_with_no_binds
+    _select_args_to_query
+    _svp_generate_name
+    _multipk_update_delete
+    source_bind_attributes
+    _normalize_connect_info
+    _parse_connect_do
+    _dbh_commit
+    _execute_array
+    _placeholders_supported
+    savepoints
+    _sqlt_minimum_version
+    _sql_maker_opts
+    _conn_pid
+    _typeless_placeholders_supported
+    _conn_tid
+    _dbh_autocommit
+    _native_data_type
+    _get_dbh
+    sql_maker_class
+    _dbh_rollback
+    _adjust_select_args_for_complex_prefetch
+    _resolve_ident_sources
+    _resolve_column_info
+    _prune_unused_joins
+    _strip_cond_qualifiers
+    _parse_order_by
+    _resolve_aliastypes_from_select_args
+    _execute
+    _do_query
+    _dbh_sth
+    _dbh_execute
+    _prefetch_insert_auto_nextvals
+    _server_info_hash
   /],
 );
 
+my @unimplemented = qw(
+  _arm_global_destructor
+  _preserve_foreign_dbh
+  _verify_pid
+  _verify_tid
+);
+
+for my $method (@unimplemented) {
+  __PACKAGE__->meta->add_method($method, sub {
+    croak "$method must not be called on ".(blessed shift).' objects';
+  });
+}
+
 has _master_connect_info_opts =>
   (is => 'rw', isa => HashRef, default => sub { {} });
 
 =head2 around: connect_info
 
-Preserve master's C<connect_info> options (for merging with replicants.)
-Also set any Replicated related options from connect_info, such as
+Preserves master's C<connect_info> options (for merging with replicants.)
+Also sets any Replicated-related options from connect_info, such as
 C<pool_type>, C<pool_args>, C<balancer_type> and C<balancer_args>.
 
 =cut
@@ -347,10 +398,12 @@
 
   my $wantarray = wantarray;
 
+  my $merge = Hash::Merge->new('LEFT_PRECEDENT');
+
   my %opts;
   for my $arg (@$info) {
     next unless (reftype($arg)||'') eq 'HASH';
-    %opts = %{ merge($arg, \%opts) };
+    %opts = %{ $merge->merge($arg, \%opts) };
   }
   delete $opts{dsn};
 
@@ -359,7 +412,7 @@
       if $opts{pool_type};
 
     $self->pool_args(
-      merge((delete $opts{pool_args} || {}), $self->pool_args)
+      $merge->merge((delete $opts{pool_args} || {}), $self->pool_args)
     );
 
     $self->pool($self->_build_pool)
@@ -371,7 +424,7 @@
       if $opts{balancer_type};
 
     $self->balancer_args(
-      merge((delete $opts{balancer_args} || {}), $self->balancer_args)
+      $merge->merge((delete $opts{balancer_args} || {}), $self->balancer_args)
     );
 
     $self->balancer($self->_build_balancer)
@@ -391,8 +444,12 @@
   my $master = $self->master;
   $master->_determine_driver;
   Moose::Meta::Class->initialize(ref $master);
+
   DBIx::Class::Storage::DBI::Replicated::WithDSN->meta->apply($master);
 
+  # link pool back to master
+  $self->pool->master($master);
+
   $wantarray ? @res : $res;
 };
 
@@ -512,7 +569,8 @@
     $self->throw_exception('too many hashrefs in connect_info')
       if @hashes > 2;
 
-    my %opts = %{ merge(reverse @hashes) };
+    my $merge = Hash::Merge->new('LEFT_PRECEDENT');
+    my %opts = %{ $merge->merge(reverse @hashes) };
 
 # delete them
     splice @$r, $i+1, ($#{$r} - $i), ();
@@ -525,7 +583,7 @@
     delete $master_opts{dbh_maker};
 
 # merge with master
-    %opts = %{ merge(\%opts, \%master_opts) };
+    %opts = %{ $merge->merge(\%opts, \%master_opts) };
 
 # update
     $r->[$i] = \%opts;
@@ -553,7 +611,7 @@
 =head2 execute_reliably ($coderef, ?@args)
 
 Given a coderef, saves the current state of the L</read_handler>, forces it to
-use reliable storage (ie sets it to the master), executes a coderef and then
+use reliable storage (e.g. sets it to the master), executes a coderef and then
 restores the original state.
 
 Example:
@@ -633,7 +691,7 @@
 =head2 set_balanced_storage
 
 Sets the current $schema to be use the </balancer> for all reads, while all
-writea are sent to the master only
+writes are sent to the master only
 
 =cut
 
@@ -744,50 +802,35 @@
 
 =head2 debugobj
 
-set a debug object across all storages
+set a debug object
 
 =cut
 
 sub debugobj {
   my $self = shift @_;
-  if(@_) {
-    foreach my $source ($self->all_storages) {
-      $source->debugobj(@_);
-    }
-  }
-  return $self->master->debugobj;
+  return $self->master->debugobj(@_);
 }
 
 =head2 debugfh
 
-set a debugfh object across all storages
+set a debugfh object
 
 =cut
 
 sub debugfh {
   my $self = shift @_;
-  if(@_) {
-    foreach my $source ($self->all_storages) {
-      $source->debugfh(@_);
-    }
-  }
-  return $self->master->debugfh;
+  return $self->master->debugfh(@_);
 }
 
 =head2 debugcb
 
-set a debug callback across all storages
+set a debug callback
 
 =cut
 
 sub debugcb {
   my $self = shift @_;
-  if(@_) {
-    foreach my $source ($self->all_storages) {
-      $source->debugcb(@_);
-    }
-  }
-  return $self->master->debugcb;
+  return $self->master->debugcb(@_);
 }
 
 =head2 disconnect
@@ -818,6 +861,195 @@
   $self->master->cursor_class;
 }
 
+=head2 cursor
+
+set cursor class on all storages, or return master's, alias for L</cursor_class>
+above.
+
+=cut
+
+sub cursor {
+  my ($self, $cursor_class) = @_;
+
+  if ($cursor_class) {
+    $_->cursor($cursor_class) for $self->all_storages;
+  }
+  $self->master->cursor;
+}
+
+=head2 unsafe
+
+sets the L<DBIx::Class::Storage::DBI/unsafe> option on all storages or returns
+master's current setting
+
+=cut
+
+sub unsafe {
+  my $self = shift;
+
+  if (@_) {
+    $_->unsafe(@_) for $self->all_storages;
+  }
+
+  return $self->master->unsafe;
+}
+
+=head2 disable_sth_caching
+
+sets the L<DBIx::Class::Storage::DBI/disable_sth_caching> option on all storages
+or returns master's current setting
+
+=cut
+
+sub disable_sth_caching {
+  my $self = shift;
+
+  if (@_) {
+    $_->disable_sth_caching(@_) for $self->all_storages;
+  }
+
+  return $self->master->disable_sth_caching;
+}
+
+=head2 lag_behind_master
+
+returns the highest Replicant L<DBIx::Class::Storage::DBI/lag_behind_master>
+setting
+
+=cut
+
+sub lag_behind_master {
+  my $self = shift;
+
+  return max map $_->lag_behind_master, $self->replicants;
+} 
+
+=head2 is_replicating
+
+returns true if all replicants return true for
+L<DBIx::Class::Storage::DBI/is_replicating>
+
+=cut
+
+sub is_replicating {
+  my $self = shift;
+
+  return (grep $_->is_replicating, $self->replicants) == ($self->replicants);
+}
+
+=head2 connect_call_datetime_setup
+
+calls L<DBIx::Class::Storage::DBI/connect_call_datetime_setup> for all storages
+
+=cut
+
+sub connect_call_datetime_setup {
+  my $self = shift;
+  $_->connect_call_datetime_setup for $self->all_storages;
+}
+
+sub _populate_dbh {
+  my $self = shift;
+  $_->_populate_dbh for $self->all_storages;
+}
+
+sub _connect {
+  my $self = shift;
+  $_->_connect for $self->all_storages;
+}
+
+sub _rebless {
+  my $self = shift;
+  $_->_rebless for $self->all_storages;
+}
+
+sub _determine_driver {
+  my $self = shift;
+  $_->_determine_driver for $self->all_storages;
+}
+
+sub _driver_determined {
+  my $self = shift;
+  
+  if (@_) {
+    $_->_driver_determined(@_) for $self->all_storages;
+  }
+
+  return $self->master->_driver_determined;
+}
+
+sub _init {
+  my $self = shift;
+  
+  $_->_init for $self->all_storages;
+}
+
+sub _run_connection_actions {
+  my $self = shift;
+  
+  $_->_run_connection_actions for $self->all_storages;
+}
+
+sub _do_connection_actions {
+  my $self = shift;
+  
+  if (@_) {
+    $_->_do_connection_actions(@_) for $self->all_storages;
+  }
+}
+
+sub connect_call_do_sql {
+  my $self = shift;
+  $_->connect_call_do_sql(@_) for $self->all_storages;
+}
+
+sub disconnect_call_do_sql {
+  my $self = shift;
+  $_->disconnect_call_do_sql(@_) for $self->all_storages;
+}
+
+sub _seems_connected {
+  my $self = shift;
+
+  return min map $_->_seems_connected, $self->all_storages;
+}
+
+sub _ping {
+  my $self = shift;
+
+  return min map $_->_ping, $self->all_storages;
+}
+
+my $numify_ver = sub {
+  my $ver = shift;
+  my @numparts = split /\D+/, $ver;
+  my $format = '%d.' . (join '', ('%05d') x (@numparts - 1));
+
+  return sprintf $format, @numparts;
+};
+
+sub _server_info {
+  my $self = shift;
+
+  if (not $self->_server_info_hash) {
+    my $min_version_info = (
+      reduce { $a->[0] < $b->[0] ? $a : $b } 
+      map [ $numify_ver->($_->{dbms_version}), $_ ],
+      map $_->_server_info, $self->all_storages
+    )->[1];
+
+    $self->_server_info_hash($min_version_info); # on master
+  }
+
+  return $self->_server_info_hash;
+}
+
+sub _get_server_version {
+  my $self = shift;
+
+  return $self->_server_info->{dbms_version};
+}
+
 =head1 GOTCHAS
 
 Due to the fact that replicants can lag behind a master, you must take care to

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Role/QueryCounter.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Role/QueryCounter.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Role/QueryCounter.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -19,7 +19,7 @@
 
 This package defines the following attributes.
 
-head2 _query_count
+=head2 _query_count
 
 Is the attribute holding the current query count.  It defines a public reader
 called 'query_count' which you can use to access the total number of queries
@@ -42,7 +42,7 @@
 
 =head2 _query_start
 
-override on the method so that we count the queries.
+Override on the method so that we count the queries.
 
 =cut
 

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/SQLAnywhere.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/SQLAnywhere.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/SQLAnywhere.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -2,7 +2,7 @@
 
 use strict;
 use warnings;
-use base qw/DBIx::Class::Storage::DBI/;
+use base qw/DBIx::Class::Storage::DBI::UniqueIdentifier/;
 use mro 'c3';
 use List::Util ();
 
@@ -25,7 +25,7 @@
 
   /opt/sqlanywhere11/sdk/perl
 
-Recommended L<DBIx::Class::Storage::DBI/connect_info> settings:
+Recommended L<connect_info|DBIx::Class::Storage::DBI/connect_info> settings:
 
   on_connect_call => 'datetime_setup'
 
@@ -35,6 +35,8 @@
 
 sub last_insert_id { shift->_identity }
 
+sub _new_uuid { 'UUIDTOSTR(NEWID())' }
+
 sub insert {
   my $self = shift;
   my ($source, $to_insert) = @_;
@@ -43,16 +45,53 @@
       $source->column_info($_)->{is_auto_increment} 
   } $source->columns;
 
+# user might have an identity PK without is_auto_increment
+  if (not $identity_col) {
+    foreach my $pk_col ($source->primary_columns) {
+      if (not exists $to_insert->{$pk_col} &&
+          $source->column_info($pk_col)->{data_type} !~ /^uniqueidentifier/i)
+      {
+        $identity_col = $pk_col;
+        last;
+      }
+    }
+  }
+
   if ($identity_col && (not exists $to_insert->{$identity_col})) {
     my $dbh = $self->_get_dbh;
     my $table_name = $source->from;
     $table_name    = $$table_name if ref $table_name;
 
-    my ($identity) = $dbh->selectrow_array("SELECT GET_IDENTITY('$table_name')");
+    my ($identity) = eval {
+      local $@; $dbh->selectrow_array("SELECT GET_IDENTITY('$table_name')")
+    };
 
-    $to_insert->{$identity_col} = $identity;
+    if (defined $identity) {
+      $to_insert->{$identity_col} = $identity;
+      $self->_identity($identity);
+    }
+  }
 
-    $self->_identity($identity);
+  return $self->next::method(@_);
+}
+
+# convert UUIDs to strings in selects
+sub _select_args {
+  my $self = shift;
+  my ($ident, $select) = @_;
+
+  my $col_info = $self->_resolve_column_info($ident);
+
+  for my $select_idx (0..$#$select) {
+    my $selected = $select->[$select_idx];
+
+    next if ref $selected;
+
+    my $data_type = $col_info->{$selected}{data_type};
+
+    if ($data_type && lc($data_type) eq 'uniqueidentifier') {
+      $select->[$select_idx] = { UUIDTOSTR => $selected };
+    }
   }
 
   return $self->next::method(@_);
@@ -86,8 +125,8 @@
 
     on_connect_call => 'datetime_setup'
 
-In L<DBIx::Class::Storage::DBI/connect_info> to set the date and timestamp
-formats (as temporary options for the session) for use with
+In L<connect_info|DBIx::Class::Storage::DBI/connect_info> to set the date and
+timestamp formats (as temporary options for the session) for use with
 L<DBIx::Class::InflateColumn::DateTime>.
 
 The C<TIMESTAMP> data type supports up to 6 digits after the decimal point for
@@ -112,8 +151,36 @@
   );
 }
 
+sub _svp_begin {
+    my ($self, $name) = @_;
+
+    $self->_get_dbh->do("SAVEPOINT $name");
+}
+
+# can't release savepoints that have been rolled back
+sub _svp_release { 1 }
+
+sub _svp_rollback {
+    my ($self, $name) = @_;
+
+    $self->_get_dbh->do("ROLLBACK TO SAVEPOINT $name")
+}
+
 1;
 
+=head1 MAXIMUM CURSORS
+
+A L<DBIx::Class> application can use a lot of cursors, due to the usage of
+L<prepare_cached|DBI/prepare_cached>.
+
+The default cursor maximum is C<50>, which can be a bit too low. This limit can
+be turned off (or increased) by the DBA by executing:
+
+  set option max_statement_count = 0
+  set option max_cursor_count    = 0
+
+Highly recommended.
+
 =head1 AUTHOR
 
 See L<DBIx::Class/AUTHOR> and L<DBIx::Class/CONTRIBUTORS>.

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/SQLite.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/SQLite.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/SQLite.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -10,10 +10,7 @@
 use File::Copy;
 use File::Spec;
 
-sub _dbh_last_insert_id {
-  my ($self, $dbh, $source, $col) = @_;
-  $dbh->func('last_insert_rowid');
-}
+__PACKAGE__->sql_maker_class('DBIx::Class::SQLAHacks::SQLite');
 
 sub backup
 {
@@ -53,18 +50,44 @@
 
   $sqltargs ||= {};
 
-  my $sqlite_version = $self->_get_dbh->{sqlite_version};
+  # it'd be cool to use the normalized perl-style version but this needs sqlt hacking as well
+  if (my $sqlite_version = $self->_server_info->{dbms_version}) {
+    # numify, SQLT does a numeric comparison
+    $sqlite_version =~ s/^(\d+) \. (\d+) (?: \. (\d+))? .*/${1}.${2}/x;
 
-  # numify, SQLT does a numeric comparison
-  $sqlite_version =~ s/^(\d+) \. (\d+) (?: \. (\d+))? .*/${1}.${2}/x;
+    $sqltargs->{producer_args}{sqlite_version} = $sqlite_version if $sqlite_version;
+  }
 
-  $sqltargs->{producer_args}{sqlite_version} = $sqlite_version;
-
   $self->next::method($schema, $type, $version, $dir, $sqltargs, @rest);
 }
 
 sub datetime_parser_type { return "DateTime::Format::SQLite"; } 
 
+=head2 connect_call_use_foreign_keys
+
+Used as:
+
+    on_connect_call => 'use_foreign_keys'
+
+In L<connect_info|DBIx::Class::Storage::DBI/connect_info> to turn on foreign key
+(including cascading) support for recent versions of SQLite and L<DBD::SQLite>.
+
+Executes:
+
+  PRAGMA foreign_keys = ON 
+
+See L<http://www.sqlite.org/foreignkeys.html> for more information.
+
+=cut
+
+sub connect_call_use_foreign_keys {
+  my $self = shift;
+
+  $self->_do_query(
+    'PRAGMA foreign_keys = ON'
+  );
+}
+
 1;
 
 =head1 NAME

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Sybase/ASE/NoBindVars.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Sybase/ASE/NoBindVars.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Sybase/ASE/NoBindVars.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -68,8 +68,8 @@
 
 =head1 DESCRIPTION
 
-If you're using this driver than your version of Sybase, or the libraries you
-use to connect to it, do not support placeholders.
+If you're using this driver then your version of Sybase or the libraries you
+use to connect to it do not support placeholders.
 
 You can also enable this driver explicitly using:
 
@@ -81,7 +81,7 @@
 $sth->execute >> for details on the pros and cons of using placeholders.
 
 One advantage of not using placeholders is that C<select @@identity> will work
-for obtainging the last insert id of an C<IDENTITY> column, instead of having to
+for obtaining the last insert id of an C<IDENTITY> column, instead of having to
 do C<select max(col)> in a transaction as the base Sybase driver does.
 
 When using this driver, bind variables will be interpolated (properly quoted of

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Sybase/ASE.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Sybase/ASE.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Sybase/ASE.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -49,7 +49,7 @@
 without doing a C<SELECT MAX(col)>. This is done safely in a transaction
 (locking the table.) See L</INSERTS WITH PLACEHOLDERS>.
 
-A recommended L<DBIx::Class::Storage::DBI/connect_info> setting:
+A recommended L<connect_info|DBIx::Class::Storage::DBI/connect_info> setting:
 
   on_connect_call => [['datetime_setup'], ['blob_setup', log_on_update => 0]]
 
@@ -728,11 +728,10 @@
 sub _update_blobs {
   my ($self, $source, $blob_cols, $where) = @_;
 
-  my (@primary_cols) = $source->primary_columns;
+  my @primary_cols = eval { $source->_pri_cols };
+  $self->throw_exception("Cannot update TEXT/IMAGE column(s): $@")
+    if $@;
 
-  $self->throw_exception('Cannot update TEXT/IMAGE column(s) without a primary key')
-    unless @primary_cols;
-
 # check if we're updating a single row by PK
   my $pk_cols_in_where = 0;
   for my $col (@primary_cols) {
@@ -763,11 +762,10 @@
   my $table = $source->name;
 
   my %row = %$row;
-  my (@primary_cols) = $source->primary_columns;
+  my @primary_cols = eval { $source->_pri_cols} ;
+  $self->throw_exception("Cannot update TEXT/IMAGE column(s): $@")
+    if $@;
 
-  $self->throw_exception('Cannot update TEXT/IMAGE column(s) without a primary key')
-    unless @primary_cols;
-
   $self->throw_exception('Cannot update TEXT/IMAGE column(s) without primary key values')
     if ((grep { defined $row{$_} } @primary_cols) != @primary_cols);
 
@@ -848,7 +846,7 @@
 
   on_connect_call => 'datetime_setup'
 
-In L<DBIx::Class::Storage::DBI/connect_info> to set:
+In L<connect_info|DBIx::Class::Storage::DBI/connect_info> to set:
 
   $dbh->syb_date_fmt('ISO_strict'); # output fmt: 2004-08-21T14:36:48.080Z
   $dbh->do('set dateformat mdy');   # input fmt:  08/13/1979 18:08:55.080
@@ -977,7 +975,7 @@
 definitions in your Result classes, and are mapped to a Sybase type (if it isn't
 already) using a mapping based on L<SQL::Translator>.
 
-In other configurations, placeholers will work just as they do with the Sybase
+In other configurations, placeholders will work just as they do with the Sybase
 Open Client libraries.
 
 Inserts or updates of TEXT/IMAGE columns will B<NOT> work with FreeTDS.
@@ -998,8 +996,8 @@
 
 =head1 TRANSACTIONS
 
-Due to limitations of the TDS protocol, L<DBD::Sybase>, or both; you cannot
-begin a transaction while there are active cursors; nor can you use multiple
+Due to limitations of the TDS protocol, L<DBD::Sybase>, or both, you cannot
+begin a transaction while there are active cursors, nor can you use multiple
 active cursors within a transaction. An active cursor is, for example, a
 L<ResultSet|DBIx::Class::ResultSet> that has been executed using C<next> or
 C<first> but has not been exhausted or L<reset|DBIx::Class::ResultSet/reset>.
@@ -1071,11 +1069,12 @@
 instead.
 
 However, the C<LongReadLen> you pass in
-L<DBIx::Class::Storage::DBI/connect_info> is used to execute the equivalent
-C<SET TEXTSIZE> command on connection.
+L<connect_info|DBIx::Class::Storage::DBI/connect_info> is used to execute the
+equivalent C<SET TEXTSIZE> command on connection.
 
-See L</connect_call_blob_setup> for a L<DBIx::Class::Storage::DBI/connect_info>
-setting you need to work with C<IMAGE> columns.
+See L</connect_call_blob_setup> for a
+L<connect_info|DBIx::Class::Storage::DBI/connect_info> setting you need to work
+with C<IMAGE> columns.
 
 =head1 BULK API
 

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Sybase/Microsoft_SQL_Server.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Sybase/Microsoft_SQL_Server.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Sybase/Microsoft_SQL_Server.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -8,6 +8,7 @@
   DBIx::Class::Storage::DBI::MSSQL
 /;
 use mro 'c3';
+use Carp::Clan qw/^DBIx::Class/;
 
 sub _rebless {
   my $self = shift;
@@ -55,6 +56,88 @@
   $dbh->do('ROLLBACK');
 }
 
+sub _get_server_version {
+  my $self = shift;
+
+  my $product_version = $self->_get_dbh->selectrow_hashref('xp_msver ProductVersion');
+
+  if ((my $version = $product_version->{Character_Value}) =~ /^(\d+)\./) {
+    return $version;
+  }
+  else {
+    $self->throw_exception(
+      "MSSQL Version Retrieval Failed, Your ProductVersion's Character_Value is missing or malformed!"
+    );
+  }
+}
+
+=head2 connect_call_datetime_setup
+
+Used as:
+
+  on_connect_call => 'datetime_setup'
+
+In L<connect_info|DBIx::Class::Storage::DBI/connect_info> to set:
+
+  $dbh->syb_date_fmt('ISO_strict'); # output fmt: 2004-08-21T14:36:48.080Z
+
+On connection for use with L<DBIx::Class::InflateColumn::DateTime>
+
+This works for both C<DATETIME> and C<SMALLDATETIME> columns, although
+C<SMALLDATETIME> columns only have minute precision.
+
+=cut
+
+{
+  my $old_dbd_warned = 0;
+
+  sub connect_call_datetime_setup {
+    my $self = shift;
+    my $dbh = $self->_get_dbh;
+
+    if ($dbh->can('syb_date_fmt')) {
+      # amazingly, this works with FreeTDS
+      $dbh->syb_date_fmt('ISO_strict');
+    } elsif (not $old_dbd_warned) {
+      carp "Your DBD::Sybase is too old to support ".
+      "DBIx::Class::InflateColumn::DateTime, please upgrade!";
+      $old_dbd_warned = 1;
+    }
+  }
+}
+
+sub datetime_parser_type {
+  'DBIx::Class::Storage::DBI::Sybase::Microsoft_SQL_Server::DateTime::Format'
+} 
+
+package # hide from PAUSE
+  DBIx::Class::Storage::DBI::Sybase::Microsoft_SQL_Server::DateTime::Format;
+
+my $datetime_parse_format  = '%Y-%m-%dT%H:%M:%S.%3NZ';
+my $datetime_format_format = '%Y-%m-%d %H:%M:%S.%3N'; # %F %T 
+
+my ($datetime_parser, $datetime_formatter);
+
+sub parse_datetime {
+  shift;
+  require DateTime::Format::Strptime;
+  $datetime_parser ||= DateTime::Format::Strptime->new(
+    pattern  => $datetime_parse_format,
+    on_error => 'croak',
+  );
+  return $datetime_parser->parse_datetime(shift);
+}
+
+sub format_datetime {
+  shift;
+  require DateTime::Format::Strptime;
+  $datetime_formatter ||= DateTime::Format::Strptime->new(
+    pattern  => $datetime_format_format,
+    on_error => 'croak',
+  );
+  return $datetime_formatter->format_datetime(shift);
+}
+
 1;
 
 =head1 NAME

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Sybase.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Sybase.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/Sybase.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -103,8 +103,8 @@
   $dbh->do("SET TEXTSIZE $bytes");
 
 Takes the number of bytes, or uses the C<LongReadLen> value from your
-L<DBIx::Class/connect_info> if omitted, lastly falls back to the C<32768> which
-is the L<DBD::Sybase> default.
+L<connect_info|DBIx::Class::Storage::DBI/connect_info> if omitted, lastly falls
+back to the C<32768> which is the L<DBD::Sybase> default.
 
 =cut
 

Added: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/UniqueIdentifier.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/UniqueIdentifier.pm	                        (rev 0)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/UniqueIdentifier.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -0,0 +1,83 @@
+package DBIx::Class::Storage::DBI::UniqueIdentifier;
+
+use strict;
+use warnings;
+use base 'DBIx::Class::Storage::DBI';
+use mro 'c3';
+
+=head1 NAME
+
+DBIx::Class::Storage::DBI::UniqueIdentifier - Storage component for RDBMSes
+supporting the 'uniqueidentifier' type
+
+=head1 DESCRIPTION
+
+This is a storage component for databases that support the C<uniqueidentifier>
+type and the C<NEWID()> function for generating UUIDs.
+
+UUIDs are generated automatically for PK columns with the C<uniqueidentifier>
+L<data_type|DBIx::Class::ResultSource/data_type>, as well as non-PK with this
+L<data_type|DBIx::Class::ResultSource/data_type> and
+L<auto_nextval|DBIx::Class::ResultSource/auto_nextval>.
+
+Currently used by L<DBIx::Class::Storage::DBI::MSSQL> and
+L<DBIx::Class::Storage::DBI::SQLAnywhere>.
+
+The composing class can define a C<_new_uuid> method to override the function
+used to generate a new UUID.
+
+=cut
+
+sub _new_uuid { 'NEWID()' }
+
+sub insert {
+  my $self = shift;
+  my ($source, $to_insert) = @_;
+
+  my $supplied_col_info = $self->_resolve_column_info($source, [keys %$to_insert] );
+
+  my %guid_cols;
+  my @pk_cols = $source->primary_columns;
+  my %pk_cols;
+  @pk_cols{@pk_cols} = ();
+
+  my @pk_guids = grep {
+    $source->column_info($_)->{data_type}
+    &&
+    $source->column_info($_)->{data_type} =~ /^uniqueidentifier/i
+  } @pk_cols;
+
+  my @auto_guids = grep {
+    $source->column_info($_)->{data_type}
+    &&
+    $source->column_info($_)->{data_type} =~ /^uniqueidentifier/i
+    &&
+    $source->column_info($_)->{auto_nextval}
+  } grep { not exists $pk_cols{$_} } $source->columns;
+
+  my @get_guids_for =
+    grep { not exists $to_insert->{$_} } (@pk_guids, @auto_guids);
+
+  my $updated_cols = {};
+
+  for my $guid_col (@get_guids_for) {
+    my ($new_guid) = $self->_get_dbh->selectrow_array('SELECT '.$self->_new_uuid);
+    $updated_cols->{$guid_col} = $to_insert->{$guid_col} = $new_guid;
+  }
+
+  $updated_cols = { %$updated_cols, %{ $self->next::method(@_) } };
+
+  return $updated_cols;
+}
+
+=head1 AUTHOR
+
+See L<DBIx::Class/AUTHOR> and L<DBIx::Class/CONTRIBUTORS>.
+
+=head1 LICENSE
+
+You may distribute this code under the same terms as Perl itself.
+
+=cut
+
+1;

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/mysql.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/mysql.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI/mysql.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -5,7 +5,6 @@
 
 use base qw/
   DBIx::Class::Storage::DBI::MultiColumnIn
-  DBIx::Class::Storage::DBI::AmbiguousGlob
   DBIx::Class::Storage::DBI
 /;
 use mro 'c3';
@@ -100,8 +99,13 @@
 
 =head1 DESCRIPTION
 
-This class implements MySQL specific bits of L<DBIx::Class::Storage::DBI>.
+This class implements MySQL specific bits of L<DBIx::Class::Storage::DBI>,
+like AutoIncrement column support and savepoints. Also it augments the
+SQL maker to support the MySQL-specific C<STRAIGHT_JOIN> join type, which
+you can use by specifying C<< join_type => 'straight' >> in the
+L<relationship attributes|DBIx::Class::Relationship::Base/join_type>
 
+
 It also provides a one-stop on-connect macro C<set_strict_mode> which sets
 session variables such that MySQL behaves more predictably as far as the
 SQL standard is concerned.

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBI.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -16,14 +16,12 @@
 use Data::Dumper::Concise();
 use Sub::Name ();
 
-# what version of sqlt do we require if deploy() without a ddl_dir is invoked
-# when changing also adjust the corresponding author_require in Makefile.PL
-my $minimum_sqlt_version = '0.11002';
+use File::Path ();
 
-
 __PACKAGE__->mk_group_accessors('simple' =>
   qw/_connect_info _dbi_connect_info _dbh _sql_maker _sql_maker_opts _conn_pid
-     _conn_tid transaction_depth _dbh_autocommit _driver_determined savepoints/
+     _conn_tid transaction_depth _dbh_autocommit _driver_determined savepoints
+     _server_info_hash/
 );
 
 # the values for these accessors are picked out (and deleted) from
@@ -38,13 +36,16 @@
 # default cursor class, overridable in connect_info attributes
 __PACKAGE__->cursor_class('DBIx::Class::Storage::DBI::Cursor');
 
-__PACKAGE__->mk_group_accessors('inherited' => qw/sql_maker_class/);
+__PACKAGE__->mk_group_accessors('inherited' => qw/
+  sql_maker_class
+  _supports_insert_returning
+/);
 __PACKAGE__->sql_maker_class('DBIx::Class::SQLAHacks');
 
-
 # Each of these methods need _determine_driver called before itself
 # in order to function reliably. This is a purely DRY optimization
 my @rdbms_specific_methods = qw/
+  deployment_statements
   sqlt_type
   build_datetime_parser
   datetime_parser_type
@@ -93,7 +94,7 @@
   );
 
   $schema->resultset('Book')->search({
-     written_on => $schema->storage->datetime_parser(DateTime->now)
+     written_on => $schema->storage->datetime_parser->format_datetime(DateTime->now)
   });
 
 =head1 DESCRIPTION
@@ -115,9 +116,102 @@
   $new->{_in_dbh_do} = 0;
   $new->{_dbh_gen} = 0;
 
+  # read below to see what this does
+  $new->_arm_global_destructor;
+
   $new;
 }
 
+# This is hack to work around perl shooting stuff in random
+# order on exit(). If we do not walk the remaining storage
+# objects in an END block, there is a *small but real* chance
+# of a fork()ed child to kill the parent's shared DBI handle,
+# *before perl reaches the DESTROY in this package*
+# Yes, it is ugly and effective.
+{
+  my %seek_and_destroy;
+
+  sub _arm_global_destructor {
+    my $self = shift;
+    my $key = Scalar::Util::refaddr ($self);
+    $seek_and_destroy{$key} = $self;
+    Scalar::Util::weaken ($seek_and_destroy{$key});
+  }
+
+  END {
+    local $?; # just in case the DBI destructor changes it somehow
+
+    # destroy just the object if not native to this process/thread
+    $_->_preserve_foreign_dbh for (grep
+      { defined $_ }
+      values %seek_and_destroy
+    );
+  }
+}
+
+sub DESTROY {
+  my $self = shift;
+
+  # destroy just the object if not native to this process/thread
+  $self->_preserve_foreign_dbh;
+
+  # some databases need this to stop spewing warnings
+  if (my $dbh = $self->_dbh) {
+    local $@;
+    eval {
+      %{ $dbh->{CachedKids} } = ();
+      $dbh->disconnect;
+    };
+  }
+
+  $self->_dbh(undef);
+}
+
+sub _preserve_foreign_dbh {
+  my $self = shift;
+
+  return unless $self->_dbh;
+
+  $self->_verify_tid;
+
+  return unless $self->_dbh;
+
+  $self->_verify_pid;
+
+}
+
+# handle pid changes correctly - do not destroy parent's connection
+sub _verify_pid {
+  my $self = shift;
+
+  return if ( defined $self->_conn_pid and $self->_conn_pid == $$ );
+
+  $self->_dbh->{InactiveDestroy} = 1;
+  $self->_dbh(undef);
+  $self->{_dbh_gen}++;
+
+  return;
+}
+
+# very similar to above, but seems to FAIL if I set InactiveDestroy
+sub _verify_tid {
+  my $self = shift;
+
+  if ( ! defined $self->_conn_tid ) {
+    return; # no threads
+  }
+  elsif ( $self->_conn_tid == threads->tid ) {
+    return; # same thread
+  }
+
+  #$self->_dbh->{InactiveDestroy} = 1;  # why does t/51threads.t fail...?
+  $self->_dbh(undef);
+  $self->{_dbh_gen}++;
+
+  return;
+}
+
+
 =head2 connect_info
 
 This method is normally called by L<DBIx::Class::Schema/connection>, which
@@ -195,7 +289,7 @@
 In addition to the standard L<DBI|DBI/ATTRIBUTES_COMMON_TO_ALL_HANDLES>
 L<connection|DBI/Database_Handle_Attributes> attributes, DBIx::Class recognizes
 the following connection options. These options can be mixed in with your other
-L<DBI> connection attributes, or placed in a seperate hashref
+L<DBI> connection attributes, or placed in a separate hashref
 (C<\%extra_attributes>) as shown above.
 
 Every time C<connect_info> is invoked, any previous settings for
@@ -347,7 +441,7 @@
 =item name_sep
 
 This only needs to be used in conjunction with C<quote_char>, and is used to
-specify the charecter that seperates elements (schemas, tables, columns) from
+specify the character that separates elements (schemas, tables, columns) from
 each other. In most cases this is simply a C<.>.
 
 The consequences of not supplying this value is that L<SQL::Abstract>
@@ -746,6 +840,7 @@
 
     $self->_dbh_rollback unless $self->_dbh_autocommit;
 
+    %{ $self->_dbh->{CachedKids} } = ();
     $self->_dbh->disconnect;
     $self->_dbh(undef);
     $self->{_dbh_gen}++;
@@ -783,8 +878,8 @@
 
 =back
 
-Verifies that the the current database handle is active and ready to execute
-an SQL statement (i.e. the connection did not get stale, server is still
+Verifies that the current database handle is active and ready to execute
+an SQL statement (e.g. the connection did not get stale, server is still
 answering, etc.) This method is used internally by L</dbh>.
 
 =cut
@@ -802,19 +897,11 @@
 sub _seems_connected {
   my $self = shift;
 
+  $self->_preserve_foreign_dbh;
+
   my $dbh = $self->_dbh
     or return 0;
 
-  if(defined $self->_conn_tid && $self->_conn_tid != threads->tid) {
-    $self->_dbh(undef);
-    $self->{_dbh_gen}++;
-    return 0;
-  }
-  else {
-    $self->_verify_pid;
-    return 0 if !$self->_dbh;
-  }
-
   return $dbh->FETCH('Active');
 }
 
@@ -826,20 +913,6 @@
   return $dbh->ping;
 }
 
-# handle pid changes correctly
-#  NOTE: assumes $self->_dbh is a valid $dbh
-sub _verify_pid {
-  my ($self) = @_;
-
-  return if defined $self->_conn_pid && $self->_conn_pid == $$;
-
-  $self->_dbh->{InactiveDestroy} = 1;
-  $self->_dbh(undef);
-  $self->{_dbh_gen}++;
-
-  return;
-}
-
 sub ensure_connected {
   my ($self) = @_;
 
@@ -853,7 +926,7 @@
 Returns a C<$dbh> - a data base handle of class L<DBI>. The returned handle
 is guaranteed to be healthy by implicitly calling L</connected>, and if
 necessary performing a reconnection before returning. Keep in mind that this
-is very B<expensive> on some database engines. Consider using L<dbh_do>
+is very B<expensive> on some database engines. Consider using L</dbh_do>
 instead.
 
 =cut
@@ -872,7 +945,7 @@
 # this is the internal "get dbh or connect (don't check)" method
 sub _get_dbh {
   my $self = shift;
-  $self->_verify_pid if $self->_dbh;
+  $self->_preserve_foreign_dbh;
   $self->_populate_dbh unless $self->_dbh;
   return $self->_dbh;
 }
@@ -907,6 +980,7 @@
 
   my @info = @{$self->_dbi_connect_info || []};
   $self->_dbh(undef); # in case ->connected failed we might get sent here
+  $self->_server_info_hash (undef);
   $self->_dbh($self->_connect(@info));
 
   $self->_conn_pid($$);
@@ -931,6 +1005,48 @@
   $self->_do_connection_actions(connect_call_ => $_) for @actions;
 }
 
+sub _server_info {
+  my $self = shift;
+
+  unless ($self->_server_info_hash) {
+
+    my %info;
+
+    my $server_version = $self->_get_server_version;
+
+    if (defined $server_version) {
+      $info{dbms_version} = $server_version;
+
+      my ($numeric_version) = $server_version =~ /^([\d\.]+)/;
+      my @verparts = split (/\./, $numeric_version);
+      if (
+        @verparts
+          &&
+        $verparts[0] <= 999
+      ) {
+        # consider only up to 3 version parts, iff not more than 3 digits
+        my @use_parts;
+        while (@verparts && @use_parts < 3) {
+          my $p = shift @verparts;
+          last if $p > 999;
+          push @use_parts, $p;
+        }
+        push @use_parts, 0 while @use_parts < 3;
+
+        $info{normalized_dbms_version} = sprintf "%d.%03d%03d", @use_parts;
+      }
+    }
+
+    $self->_server_info_hash(\%info);
+  }
+
+  return $self->_server_info_hash
+}
+
+sub _get_server_version {
+  eval { shift->_get_dbh->get_info(18) };
+}
+
 sub _determine_driver {
   my ($self) = @_;
 
@@ -953,15 +1069,20 @@
         else {
           # try to use dsn to not require being connected, the driver may still
           # force a connection in _rebless to determine version
-          ($driver) = $self->_dbi_connect_info->[0] =~ /dbi:([^:]+):/i;
+          # (dsn may not be supplied at all if all we do is make a mock-schema)
+          my $dsn = $self->_dbi_connect_info->[0] || $ENV{DBI_DSN} || '';
+          ($driver) = $dsn =~ /dbi:([^:]+):/i;
+          $driver ||= $ENV{DBI_DRIVER};
         }
       }
 
-      my $storage_class = "DBIx::Class::Storage::DBI::${driver}";
-      if ($self->load_optional_class($storage_class)) {
-        mro::set_mro($storage_class, 'c3');
-        bless $self, $storage_class;
-        $self->_rebless();
+      if ($driver) {
+        my $storage_class = "DBIx::Class::Storage::DBI::${driver}";
+        if ($self->load_optional_class($storage_class)) {
+          mro::set_mro($storage_class, 'c3');
+          bless $self, $storage_class;
+          $self->_rebless();
+        }
       }
     }
 
@@ -1362,30 +1483,57 @@
     $self->dbh_do('_dbh_execute', @_);  # retry over disconnects
 }
 
-sub insert {
+sub _prefetch_insert_auto_nextvals {
   my ($self, $source, $to_insert) = @_;
 
-  my $ident = $source->from;
-  my $bind_attributes = $self->source_bind_attributes($source);
+  my $upd = {};
 
-  my $updated_cols = {};
-
   foreach my $col ( $source->columns ) {
     if ( !defined $to_insert->{$col} ) {
       my $col_info = $source->column_info($col);
 
       if ( $col_info->{auto_nextval} ) {
-        $updated_cols->{$col} = $to_insert->{$col} = $self->_sequence_fetch(
+        $upd->{$col} = $to_insert->{$col} = $self->_sequence_fetch(
           'nextval',
-          $col_info->{sequence} ||
-            $self->_dbh_get_autoinc_seq($self->_get_dbh, $source)
+          $col_info->{sequence} ||=
+            $self->_dbh_get_autoinc_seq($self->_get_dbh, $source, $col)
         );
       }
     }
   }
 
-  $self->_execute('insert' => [], $source, $bind_attributes, $to_insert);
+  return $upd;
+}
 
+sub insert {
+  my $self = shift;
+  my ($source, $to_insert, $opts) = @_;
+
+  my $updated_cols = $self->_prefetch_insert_auto_nextvals (@_);
+
+  my $bind_attributes = $self->source_bind_attributes($source);
+
+  my ($rv, $sth) = $self->_execute('insert' => [], $source, $bind_attributes, $to_insert, $opts);
+
+  if ($opts->{returning}) {
+    my @ret_cols = @{$opts->{returning}};
+
+    my @ret_vals = eval {
+      local $SIG{__WARN__} = sub {};
+      my @r = $sth->fetchrow_array;
+      $sth->finish;
+      @r;
+    };
+
+    my %ret;
+    @ret{@ret_cols} = @ret_vals if (@ret_vals);
+
+    $updated_cols = {
+      %$updated_cols,
+      %ret,
+    };
+  }
+
   return $updated_cols;
 }
 
@@ -1471,7 +1619,7 @@
   # neither _execute_array, nor _execute_inserts_with_no_binds are
   # atomic (even if _execute _array is a single call). Thus a safety
   # scope guard
-  my $guard = $self->txn_scope_guard unless $self->{transaction_depth} != 0;
+  my $guard = $self->txn_scope_guard;
 
   $self->_query_start( $sql, ['__BULK__'] );
   my $sth = $self->sth($sql);
@@ -1488,9 +1636,8 @@
 
   $self->_query_end( $sql, ['__BULK__'] );
 
+  $guard->commit;
 
-  $guard->commit if $guard;
-
   return (wantarray ? ($rv, $sth, @bind) : $rv);
 }
 
@@ -1518,7 +1665,11 @@
 
     my @data = map { $_->[$data_index] } @$data;
 
-    $sth->bind_param_array( $placeholder_index, [@data], $attributes );
+    $sth->bind_param_array(
+      $placeholder_index,
+      [@data],
+      (%$attributes ?  $attributes : ()),
+    );
     $placeholder_index++;
   }
 
@@ -1606,15 +1757,7 @@
   my $rsrc = $rs->result_source;
 
   # quick check if we got a sane rs on our hands
-  my @pcols = $rsrc->primary_columns;
-  unless (@pcols) {
-    $self->throw_exception (
-      sprintf (
-        "You must declare primary key(s) on source '%s' (via set_primary_key) in order to update or delete complex resultsets",
-        $rsrc->source_name || $rsrc->from
-      )
-    );
-  }
+  my @pcols = $rsrc->_pri_cols;
 
   my $sel = $rs->_resolved_attrs->{select};
   $sel = [ $sel ] unless ref $sel eq 'ARRAY';
@@ -1667,7 +1810,7 @@
   my ($rs, $op, $values) = @_;
 
   my $rsrc = $rs->result_source;
-  my @pcols = $rsrc->primary_columns;
+  my @pcols = $rsrc->_pri_cols;
 
   my $guard = $self->txn_scope_guard;
 
@@ -1699,31 +1842,18 @@
 
 sub _select {
   my $self = shift;
-
-  # localization is neccessary as
-  # 1) there is no infrastructure to pass this around before SQLA2
-  # 2) _select_args sets it and _prep_for_execute consumes it
-  my $sql_maker = $self->sql_maker;
-  local $sql_maker->{_dbic_rs_attrs};
-
-  return $self->_execute($self->_select_args(@_));
+  $self->_execute($self->_select_args(@_));
 }
 
 sub _select_args_to_query {
   my $self = shift;
 
-  # localization is neccessary as
-  # 1) there is no infrastructure to pass this around before SQLA2
-  # 2) _select_args sets it and _prep_for_execute consumes it
-  my $sql_maker = $self->sql_maker;
-  local $sql_maker->{_dbic_rs_attrs};
-
-  # my ($op, $bind, $ident, $bind_attrs, $select, $cond, $order, $rows, $offset)
+  # my ($op, $bind, $ident, $bind_attrs, $select, $cond, $rs_attrs, $rows, $offset)
   #  = $self->_select_args($ident, $select, $cond, $attrs);
   my ($op, $bind, $ident, $bind_attrs, @args) =
     $self->_select_args(@_);
 
-  # my ($sql, $prepared_bind) = $self->_prep_for_execute($op, $bind, $ident, [ $select, $cond, $order, $rows, $offset ]);
+  # my ($sql, $prepared_bind) = $self->_prep_for_execute($op, $bind, $ident, [ $select, $cond, $rs_attrs, $rows, $offset ]);
   my ($sql, $prepared_bind) = $self->_prep_for_execute($op, $bind, $ident, \@args);
   $prepared_bind ||= [];
 
@@ -1736,16 +1866,16 @@
 sub _select_args {
   my ($self, $ident, $select, $where, $attrs) = @_;
 
+  my $sql_maker = $self->sql_maker;
   my ($alias2source, $rs_alias) = $self->_resolve_ident_sources ($ident);
 
-  my $sql_maker = $self->sql_maker;
-  $sql_maker->{_dbic_rs_attrs} = {
+  $attrs = {
     %$attrs,
     select => $select,
     from => $ident,
     where => $where,
     $rs_alias && $alias2source->{$rs_alias}
-      ? ( _source_handle => $alias2source->{$rs_alias}->handle )
+      ? ( _rsroot_source_handle => $alias2source->{$rs_alias}->handle )
       : ()
     ,
   };
@@ -1801,18 +1931,7 @@
     #limited has_many
     ( $attrs->{rows} && keys %{$attrs->{collapse}} )
        ||
-    # limited prefetch with RNO subqueries
-    (
-      $attrs->{rows}
-        &&
-      $sql_maker->limit_dialect eq 'RowNumberOver'
-        &&
-      $attrs->{_prefetch_select}
-        &&
-      @{$attrs->{_prefetch_select}}
-    )
-      ||
-    # grouped prefetch
+    # grouped prefetch (to satisfy group_by == select)
     ( $attrs->{group_by}
         &&
       @{$attrs->{group_by}}
@@ -1825,39 +1944,6 @@
     ($ident, $select, $where, $attrs)
       = $self->_adjust_select_args_for_complex_prefetch ($ident, $select, $where, $attrs);
   }
-
-  elsif (
-    ($attrs->{rows} || $attrs->{offset})
-      &&
-    $sql_maker->limit_dialect eq 'RowNumberOver'
-      &&
-    (ref $ident eq 'ARRAY' && @$ident > 1)  # indicates a join
-      &&
-    scalar $self->_parse_order_by ($attrs->{order_by})
-  ) {
-    # the RNO limit dialect above mangles the SQL such that the join gets lost
-    # wrap a subquery here
-
-    push @limit, delete @{$attrs}{qw/rows offset/};
-
-    my $subq = $self->_select_args_to_query (
-      $ident,
-      $select,
-      $where,
-      $attrs,
-    );
-
-    $ident = {
-      -alias => $attrs->{alias},
-      -source_handle => $ident->[0]{-source_handle},
-      $attrs->{alias} => $subq,
-    };
-
-    # all part of the subquery now
-    delete @{$attrs}{qw/order_by group_by having/};
-    $where = undef;
-  }
-
   elsif (! $attrs->{software_limit} ) {
     push @limit, $attrs->{rows}, $attrs->{offset};
   }
@@ -1875,12 +1961,7 @@
   # invoked, and that's just bad...
 ###
 
-  my $order = { map
-    { $attrs->{$_} ? ( $_ => $attrs->{$_} ) : ()  }
-    (qw/order_by group_by having/ )
-  };
-
-  return ('select', $attrs->{bind}, $ident, $bind_attrs, $select, $where, $order, @limit);
+  return ('select', $attrs->{bind}, $ident, $bind_attrs, $select, $where, $attrs, @limit);
 }
 
 # Returns a counting SELECT for a simple count
@@ -1892,21 +1973,7 @@
   return { count => '*' };
 }
 
-# Returns a SELECT which will end up in the subselect
-# There may or may not be a group_by, as the subquery
-# might have been called to accomodate a limit
-#
-# Most databases would be happy with whatever ends up
-# here, but some choke in various ways.
-#
-sub _subq_count_select {
-  my ($self, $source, $rs_attrs) = @_;
-  return $rs_attrs->{group_by} if $rs_attrs->{group_by};
 
-  my @pcols = map { join '.', $rs_attrs->{alias}, $_ } ($source->primary_columns);
-  return @pcols ? \@pcols : [ 1 ];
-}
-
 sub source_bind_attributes {
   my ($self, $source) = @_;
 
@@ -2053,18 +2120,14 @@
 =cut
 
 sub _dbh_last_insert_id {
-    # All Storage's need to register their own _dbh_last_insert_id
-    # the old SQLite-based method was highly inappropriate
+    my ($self, $dbh, $source, $col) = @_;
 
-    my $self = shift;
+    my $id = eval { $dbh->last_insert_id (undef, undef, $source->name, $col) };
+
+    return $id if defined $id;
+
     my $class = ref $self;
-    $self->throw_exception (<<EOE);
-
-No _dbh_last_insert_id() method found in $class.
-Since the method of obtaining the autoincrement id of the last insert
-operation varies greatly between different databases, this method must be
-individually implemented for every storage class.
-EOE
+    $self->throw_exception ("No storage specific _dbh_last_insert_id() method implemented in $class, and the generic DBI::last_insert_id() failed");
 }
 
 sub last_insert_id {
@@ -2238,10 +2301,16 @@
 sub create_ddl_dir {
   my ($self, $schema, $databases, $version, $dir, $preversion, $sqltargs) = @_;
 
-  if(!$dir || !-d $dir) {
+  unless ($dir) {
     carp "No directory given, using ./\n";
-    $dir = "./";
+    $dir = './';
+  } else {
+      -d $dir or File::Path::mkpath($dir)
+          or $self->throw_exception("create_ddl_dir: $! creating dir '$dir'");
   }
+
+  $self->throw_exception ("Directory '$dir' does not exist\n") unless(-d $dir);
+
   $databases ||= ['MySQL', 'SQLite', 'PostgreSQL'];
   $databases = [ $databases ] if(ref($databases) ne 'ARRAY');
 
@@ -2255,8 +2324,9 @@
     %{$sqltargs || {}}
   };
 
-  $self->throw_exception("Can't create a ddl file without SQL::Translator: " . $self->_sqlt_version_error)
-    if !$self->_sqlt_version_ok;
+  unless (DBIx::Class::Optional::Dependencies->req_ok_for ('deploy')) {
+    $self->throw_exception("Can't create a ddl file without " . DBIx::Class::Optional::Dependencies->req_missing_for ('deploy') );
+  }
 
   my $sqlt = SQL::Translator->new( $sqltargs );
 
@@ -2398,8 +2468,9 @@
       return join('', @rows);
   }
 
-  $self->throw_exception("Can't deploy without either SQL::Translator or a ddl_dir: " . $self->_sqlt_version_error )
-    if !$self->_sqlt_version_ok;
+  unless (DBIx::Class::Optional::Dependencies->req_ok_for ('deploy') ) {
+    $self->throw_exception("Can't deploy without a ddl_dir or " . DBIx::Class::Optional::Dependencies->req_missing_for ('deploy') );
+  }
 
   # sources needs to be a parser arg, but for simplicty allow at top level
   # coming in
@@ -2449,7 +2520,7 @@
     }
     $self->_query_end($line);
   };
-  my @statements = $self->deployment_statements($schema, $type, undef, $dir, { %{ $sqltargs || {} }, no_comments => 1 } );
+  my @statements = $schema->deployment_statements($type, undef, $dir, { %{ $sqltargs || {} }, no_comments => 1 } );
   if (@statements > 1) {
     foreach my $statement (@statements) {
       $deploy->( $statement );
@@ -2523,33 +2594,6 @@
     return;
 }
 
-# SQLT version handling
-{
-  my $_sqlt_version_ok;     # private
-  my $_sqlt_version_error;  # private
-
-  sub _sqlt_version_ok {
-    if (!defined $_sqlt_version_ok) {
-      eval "use SQL::Translator $minimum_sqlt_version";
-      if ($@) {
-        $_sqlt_version_ok = 0;
-        $_sqlt_version_error = $@;
-      }
-      else {
-        $_sqlt_version_ok = 1;
-      }
-    }
-    return $_sqlt_version_ok;
-  }
-
-  sub _sqlt_version_error {
-    shift->_sqlt_version_ok unless defined $_sqlt_version_ok;
-    return $_sqlt_version_error;
-  }
-
-  sub _sqlt_minimum_version { $minimum_sqlt_version };
-}
-
 =head2 relname_to_table_alias
 
 =over 4
@@ -2564,8 +2608,8 @@
 This hook is to allow specific L<DBIx::Class::Storage> drivers to change the
 way these aliases are named.
 
-The default behavior is C<"$relname_$join_count" if $join_count > 1>, otherwise
-C<"$relname">.
+The default behavior is C<< "$relname_$join_count" if $join_count > 1 >>,
+otherwise C<"$relname">.
 
 =cut
 
@@ -2578,23 +2622,6 @@
   return $alias;
 }
 
-sub DESTROY {
-  my $self = shift;
-
-  $self->_verify_pid if $self->_dbh;
-
-  # some databases need this to stop spewing warnings
-  if (my $dbh = $self->_dbh) {
-    local $@;
-    eval {
-      %{ $dbh->{CachedKids} } = ();
-      $dbh->disconnect;
-    };
-  }
-
-  $self->_dbh(undef);
-}
-
 1;
 
 =head1 USAGE NOTES

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBIHacks.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBIHacks.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/DBIHacks.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -94,10 +94,12 @@
     }
 
     push @$inner_select, $sel;
+
+    push @{$inner_attrs->{as}}, $attrs->{as}[$i];
   }
 
   # construct the inner $from for the subquery
-  # we need to prune first, because this will determine if we need a group_bu below
+  # we need to prune first, because this will determine if we need a group_by below
   my $inner_from = $self->_prune_unused_joins ($from, $inner_select, $where, $inner_attrs);
 
   # if a multi-type join was needed in the subquery - add a group_by to simulate the
@@ -164,10 +166,10 @@
   while (my $j = shift @$from) {
     my $alias = $j->[0]{-alias};
 
-    if ($outer_aliastypes->{select}{$alias}) {
+    if ($outer_aliastypes->{selecting}{$alias}) {
       push @outer_from, $j;
     }
-    elsif ($outer_aliastypes->{restrict}{$alias}) {
+    elsif ($outer_aliastypes->{restricting}{$alias}) {
       push @outer_from, $j;
       $outer_attrs->{group_by} ||= $outer_select unless $j->[0]{-is_single};
     }
@@ -186,15 +188,17 @@
   return (\@outer_from, $outer_select, $where, $outer_attrs);
 }
 
+#
+# I KNOW THIS SUCKS! GET SQLA2 OUT THE DOOR SO THIS CAN DIE!
+#
 # Due to a lack of SQLA2 we fall back to crude scans of all the
 # select/where/order/group attributes, in order to determine what
 # aliases are neded to fulfill the query. This information is used
 # throughout the code to prune unnecessary JOINs from the queries
 # in an attempt to reduce the execution time.
 # Although the method is pretty horrific, the worst thing that can
-# happen is for it to fail due to an unqualified column, which in
-# turn will result in a vocal exception. Qualifying the column will
-# invariably solve the problem.
+# happen is for it to fail due to some scalar SQL, which in turn will
+# result in a vocal exception.
 sub _resolve_aliastypes_from_select_args {
   my ( $self, $from, $select, $where, $attrs ) = @_;
 
@@ -217,36 +221,83 @@
       unless $j->{-is_single};
   }
 
+  # get a column to source/alias map (including unqualified ones)
+  my $colinfo = $self->_resolve_column_info ($from);
+
   # set up a botched SQLA
   my $sql_maker = $self->sql_maker;
   my $sep = quotemeta ($self->_sql_maker_opts->{name_sep} || '.');
-  local $sql_maker->{quote_char}; # so that we can regex away
 
-
-  my $select_sql = $sql_maker->_recurse_fields ($select);
-  my $where_sql = $sql_maker->where ($where);
-  my $group_by_sql = $sql_maker->_order_by({
-    map { $_ => $attrs->{$_} } qw/group_by having/
+  my ($orig_lquote, $orig_rquote) = map { quotemeta $_ } (do {
+    if (ref $sql_maker->{quote_char} eq 'ARRAY') {
+      @{$sql_maker->{quote_char}}
+    }
+    else {
+      ($sql_maker->{quote_char} || '') x 2;
+    }
   });
-  my @order_by_chunks = ($self->_parse_order_by ($attrs->{order_by}) );
 
-  # match every alias to the sql chunks above
+  local $sql_maker->{quote_char} = "\x00"; # so that we can regex away
+
+  # generate sql chunks
+  my $to_scan = {
+    restricting => [
+      $sql_maker->_recurse_where ($where),
+      $sql_maker->_order_by({
+        map { $_ => $attrs->{$_} } (qw/group_by having/)
+      }),
+    ],
+    selecting => [
+      $self->_parse_order_by ($attrs->{order_by}, $sql_maker),
+      $sql_maker->_recurse_fields ($select),
+    ],
+  };
+
+  # throw away empty chunks
+  $_ = [ map { $_ || () } @$_ ] for values %$to_scan;
+
+  # first loop through all fully qualified columns and get the corresponding
+  # alias (should work even if they are in scalarrefs)
   for my $alias (keys %$alias_list) {
-    my $al_re = qr/\b $alias $sep/x;
+    my $al_re = qr/
+      \x00 $alias \x00 $sep
+        |
+      \b $alias $sep
+    /x;
 
-    for my $piece ($where_sql, $group_by_sql) {
-      $aliases_by_type->{restrict}{$alias} = 1 if ($piece =~ $al_re);
+    # add matching for possible quoted literal sql
+    $al_re = qr/ $al_re | $orig_lquote $alias $orig_rquote /x
+      if ($orig_lquote && $orig_rquote);
+
+
+    for my $type (keys %$to_scan) {
+      for my $piece (@{$to_scan->{$type}}) {
+        $aliases_by_type->{$type}{$alias} = 1 if ($piece =~ $al_re);
+      }
     }
+  }
 
-    for my $piece ($select_sql, @order_by_chunks ) {
-      $aliases_by_type->{select}{$alias} = 1 if ($piece =~ $al_re);
+  # now loop through unqualified column names, and try to locate them within
+  # the chunks
+  for my $col (keys %$colinfo) {
+    next if $col =~ $sep;   # if column is qualified it was caught by the above
+
+    my $col_re = qr/ \x00 $col \x00 /x;
+
+    $col_re = qr/ $col_re | $orig_lquote $col $orig_rquote /x
+      if ($orig_lquote && $orig_rquote);
+
+    for my $type (keys %$to_scan) {
+      for my $piece (@{$to_scan->{$type}}) {
+        $aliases_by_type->{$type}{$colinfo->{$col}{-source_alias}} = 1 if ($piece =~ $col_re);
+      }
     }
   }
 
   # Add any non-left joins to the restriction list (such joins are indeed restrictions)
   for my $j (values %$alias_list) {
     my $alias = $j->{-alias} or next;
-    $aliases_by_type->{restrict}{$alias} = 1 if (
+    $aliases_by_type->{restricting}{$alias} = 1 if (
       (not $j->{-join_type})
         or
       ($j->{-join_type} !~ /^left (?: \s+ outer)? $/xi)
@@ -258,7 +309,7 @@
   for my $type (keys %$aliases_by_type) {
     for my $alias (keys %{$aliases_by_type->{$type}}) {
       $aliases_by_type->{$type}{$_} = 1
-        for (map { keys %$_ } @{ $alias_list->{$alias}{-join_path} || [] });
+        for (map { values %$_ } @{ $alias_list->{$alias}{-join_path} || [] });
     }
   }
 
@@ -403,7 +454,7 @@
   # anyway, and deep cloning is just too fucking expensive
   # So replace the first hashref in the node arrayref manually 
   my @new_from = ($from->[0]);
-  my $sw_idx = { map { values %$_ => 1 } @$switch_branch };
+  my $sw_idx = { map { (values %$_), 1 } @$switch_branch }; #there's one k/v per join-path
 
   for my $j (@{$from}[1 .. $#$from]) {
     my $jalias = $j->[0]{-alias};
@@ -485,20 +536,31 @@
 }
 
 sub _parse_order_by {
-  my ($self, $order_by) = @_;
+  my ($self, $order_by, $sql_maker) = @_;
 
-  return scalar $self->sql_maker->_order_by_chunks ($order_by)
-    unless wantarray;
+  my $parser = sub {
+    my ($sql_maker, $order_by) = @_;
 
-  my $sql_maker = $self->sql_maker;
-  local $sql_maker->{quote_char}; #disable quoting
-  my @chunks;
-  for my $chunk (map { ref $_ ? @$_ : $_ } ($sql_maker->_order_by_chunks ($order_by) ) ) {
-    $chunk =~ s/\s+ (?: ASC|DESC ) \s* $//ix;
-    push @chunks, $chunk;
+    return scalar $sql_maker->_order_by_chunks ($order_by)
+      unless wantarray;
+
+    my @chunks;
+    for my $chunk (map { ref $_ ? @$_ : $_ } ($sql_maker->_order_by_chunks ($order_by) ) ) {
+      $chunk =~ s/\s+ (?: ASC|DESC ) \s* $//ix;
+      push @chunks, $chunk;
+    }
+
+    return @chunks;
+  };
+
+  if ($sql_maker) {
+    return $parser->($sql_maker, $order_by);
   }
-
-  return @chunks;
+  else {
+    $sql_maker = $self->sql_maker;
+    local $sql_maker->{quote_char};
+    return $parser->($sql_maker, $order_by);
+  }
 }
 
 1;

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/TxnScopeGuard.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/TxnScopeGuard.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage/TxnScopeGuard.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -89,7 +89,7 @@
 =head2 commit
 
 Commit the transaction, and stop guarding the scope. If this method is not
-called and this object goes out of scope (i.e. an exception is thrown) then
+called and this object goes out of scope (e.g. an exception is thrown) then
 the transaction is rolled back, via L<DBIx::Class::Storage/txn_rollback>
 
 =cut
@@ -102,7 +102,7 @@
 
 Ash Berlin, 2008.
 
-Insipred by L<Scope::Guard> by chocolateboy.
+Inspired by L<Scope::Guard> by chocolateboy.
 
 This module is free software. It may be used, redistributed and/or modified
 under the same terms as Perl itself.

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/Storage.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -353,7 +353,7 @@
 =head2 debugfh
 
 Set or retrieve the filehandle used for trace/debug output.  This should be
-an IO::Handle compatible ojbect (only the C<print> method is used.  Initially
+an IO::Handle compatible object (only the C<print> method is used.  Initially
 set to be STDERR - although see information on the
 L<DBIC_TRACE> environment variable.
 

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/UTF8Columns.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/UTF8Columns.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class/UTF8Columns.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -2,13 +2,12 @@
 use strict;
 use warnings;
 use base qw/DBIx::Class/;
-use utf8;
 
 __PACKAGE__->mk_classdata( '_utf8_columns' );
 
 =head1 NAME
 
-DBIx::Class::UTF8Columns - Force UTF8 (Unicode) flag on columns
+DBIx::Class::UTF8Columns - Force UTF8 (Unicode) flag on columns (DEPRECATED)
 
 =head1 SYNOPSIS
 
@@ -24,10 +23,55 @@
 
 =head1 DESCRIPTION
 
-This module allows you to get columns data that have utf8 (Unicode) flag.
+This module allows you to get and store utf8 (unicode) column data
+in a database that does not natively support unicode. It ensures
+that column data is correctly serialised as a byte stream when
+stored and de-serialised to unicode strings on retrieval.
 
-=head2 Warning
+  THE USE OF THIS MODULE (AND ITS COUSIN DBIx::Class::ForceUTF8) IS VERY
+  STRONGLY DISCOURAGED, PLEASE READ THE WARNINGS BELOW FOR AN EXPLANATION.
 
+If you want to continue using this module and do not want to recieve
+further warnings set the environmane variable C<DBIC_UTF8COLUMNS_OK>
+to a true value.
+
+=head2 Warning - Module does not function properly on create/insert
+
+Recently (April 2010) a bug was found deep in the core of L<DBIx::Class>
+which affects any component attempting to perform encoding/decoding by
+overloading L<store_column|DBIx::Class::Row/store_column> and
+L<get_columns|DBIx::Class::Row/get_columns>. As a result of this problem
+L<create|DBIx::Class::ResultSet/create> sends the original column values
+to the database, while L<update|DBIx::Class::ResultSet/update> sends the
+encoded values. L<DBIx::Class::UTF8Columns> and L<DBIx::Class::ForceUTF8>
+are both affected by ths bug.
+
+It is unclear how this bug went undetected for so long (it was
+introduced in March 2006), No attempts to fix it will be made while the
+implications of changing such a fundamental behavior of DBIx::Class are
+being evaluated. However in this day and age you should not be using
+this module anyway as Unicode is properly supported by all major
+database engines, as explained below.
+
+If you have specific questions about the integrity of your data in light
+of this development - please 
+L<join us on IRC or the mailing list|DBIx::Class/GETTING HELP/SUPPORT>
+to further discuss your concerns with the team.
+
+=head2 Warning - Native Database Unicode Support
+
+If your database natively supports Unicode (as does SQLite with the
+C<sqlite_unicode> connect flag, MySQL with C<mysql_enable_utf8>
+connect flag or Postgres with the C<pg_enable_utf8> connect flag),
+then this component should B<not> be used, and will corrupt unicode
+data in a subtle and unexpected manner.
+
+It is far better to do Unicode support within the database if
+possible rather than converting data to and from raw bytes on every
+database round trip.
+
+=head2 Warning - Component Overloading
+
 Note that this module overloads L<DBIx::Class::Row/store_column> in a way
 that may prevent other components overloading the same method from working
 correctly. This component must be the last one before L<DBIx::Class::Row>
@@ -114,7 +158,8 @@
 
 # override this if you want to force everything to be encoded/decoded
 sub _is_utf8_column {
-  return (shift->utf8_columns || {})->{shift};
+  # my ($self, $col) = @_;
+  return ($_[0]->utf8_columns || {})->{$_[1]};
 }
 
 =head1 AUTHORS

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/DBIx/Class.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -6,6 +6,8 @@
 use MRO::Compat;
 use mro 'c3';
 
+use DBIx::Class::Optional::Dependencies;
+
 use vars qw($VERSION);
 use base qw/DBIx::Class::Componentised Class::Accessor::Grouped/;
 use DBIx::Class::StartupCheck;
@@ -25,9 +27,9 @@
 # Always remember to do all digits for the version even if they're 0
 # i.e. first release of 0.XX *must* be 0.XX000. This avoids fBSD ports
 # brain damage and presumably various other packaging systems too
-$VERSION = '0.08117_01';
+$VERSION = '0.08121_01';
 
-$VERSION = eval $VERSION; # numify for warning-free dev releases
+$VERSION = eval $VERSION if $VERSION =~ /_/; # numify for warning-free dev releases
 
 sub MODIFY_CODE_ATTRIBUTES {
   my ($class,$code, at attrs) = @_;
@@ -54,14 +56,21 @@
 
 The community can be found via:
 
-  Mailing list: http://lists.scsys.co.uk/mailman/listinfo/dbix-class/
+=over
 
-  SVN: http://dev.catalyst.perl.org/repos/bast/DBIx-Class/
+=item * IRC: L<irc.perl.org#dbix-class (click for instant chatroom login)
+|http://mibbit.com/chat/#dbix-class@irc.perl.org>
 
-  SVNWeb: http://dev.catalyst.perl.org/svnweb/bast/browse/DBIx-Class/
+=item * Mailing list: L<http://lists.scsys.co.uk/mailman/listinfo/dbix-class>
 
-  IRC: irc.perl.org#dbix-class
+=item * RT Bug Tracker: L<https://rt.cpan.org/Dist/Display.html?Queue=DBIx-Class>
 
+=item * SVNWeb: L<http://dev.catalyst.perl.org/svnweb/bast/browse/DBIx-Class/0.08>
+
+=item * SVN: L<http://dev.catalyst.perl.org/repos/bast/DBIx-Class/0.08>
+
+=back
+
 =head1 SYNOPSIS
 
 Create a schema class called MyDB/Schema.pm:
@@ -209,10 +218,12 @@
 
 =head1 CONTRIBUTORS
 
-abraxxa: Alexander Hartmaier <alex_hartmaier at hotmail.com>
+abraxxa: Alexander Hartmaier <abraxxa at cpan.org>
 
 aherzog: Adam Herzog <adam at herzogdesigns.com>
 
+amoore: Andrew Moore <amoore at cpan.org>
+
 andyg: Andy Grundman <andy at hybridized.org>
 
 ank: Andres Kievsky
@@ -245,20 +256,28 @@
 
 debolaz: Anders Nor Berle <berle at cpan.org>
 
+dew: Dan Thomas <dan at godders.org>
+
 dkubb: Dan Kubb <dan.kubb-cpan at onautopilot.com>
 
 dnm: Justin Wheeler <jwheeler at datademons.com>
 
+dpetrov: Dimitar Petrov <mitakaa at gmail.com>
+
 dwc: Daniel Westermann-Clark <danieltwc at cpan.org>
 
 dyfrgi: Michael Leuchtenburg <michael at slashhome.org>
 
 frew: Arthur Axel "fREW" Schmidt <frioux at gmail.com>
 
+goraxe: Gordon Irving <goraxe at cpan.org>
+
 gphat: Cory G Watson <gphat at cpan.org>
 
 groditi: Guillermo Roditi <groditi at cpan.org>
 
+hobbs: Andrew Rodland <arodland at cpan.org>
+
 ilmari: Dagfinn Ilmari MannsE<aring>ker <ilmari at ilmari.org>
 
 jasonmay: Jason May <jason.a.may at gmail.com>
@@ -297,6 +316,8 @@
 
 norbi: Norbert Buchmuller <norbi at nix.hu>
 
+nuba: Nuba Princigalli <nuba at cpan.org>
+
 Numa: Dan Sully <daniel at cpan.org>
 
 ovid: Curtis "Ovid" Poe <ovid at cpan.org>
@@ -363,9 +384,11 @@
 
 zamolxes: Bogdan Lucaciu <bogdan at wiz.ro>
 
+Possum: Daniel LeWarne <possum at cpan.org>
+
 =head1 COPYRIGHT
 
-Copyright (c) 2005 - 2009 the DBIx::Class L</AUTHOR> and L</CONTRIBUTORS>
+Copyright (c) 2005 - 2010 the DBIx::Class L</AUTHOR> and L</CONTRIBUTORS>
 as listed above.
 
 =head1 LICENSE

Modified: DBIx-Class/0.08/branches/group_by_consistency/lib/SQL/Translator/Parser/DBIx/Class.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/lib/SQL/Translator/Parser/DBIx/Class.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/lib/SQL/Translator/Parser/DBIx/Class.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -33,7 +33,7 @@
 sub parse {
     # this is a hack to prevent schema leaks due to a retarded SQLT implementation
     # DO NOT REMOVE (until SQLT2 is out, the all of this will be rewritten anyway)
-    Scalar::Util::weaken ($_[1]);
+    Scalar::Util::weaken ($_[1]) if ref ($_[1]);
 
     my ($tr, $data)   = @_;
     my $args          = $tr->parser_args;

Added: DBIx-Class/0.08/branches/group_by_consistency/maint/benchmark_datafetch.pl
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/maint/benchmark_datafetch.pl	                        (rev 0)
+++ DBIx-Class/0.08/branches/group_by_consistency/maint/benchmark_datafetch.pl	2010-05-06 09:42:51 UTC (rev 9313)
@@ -0,0 +1,38 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Benchmark qw/cmpthese/;
+use FindBin;
+use lib "$FindBin::Bin/../t/lib";
+use lib "$FindBin::Bin/../lib";
+use DBICTest::Schema;
+use DBIx::Class::ResultClass::HashRefInflator;  # older dbic didn't load it
+
+printf "Benchmarking DBIC version %s\n", DBIx::Class->VERSION;
+
+my $schema = DBICTest::Schema->connect ('dbi:SQLite::memory:');
+$schema->deploy;
+
+my $rs = $schema->resultset ('Artist');
+$rs->populate ([ map { { name => "Art_$_"} } (1 .. 10000) ]);
+
+my $dbh = $schema->storage->dbh;
+my $sql = sprintf ('SELECT %s FROM %s %s',
+  join (',', @{$rs->_resolved_attrs->{select}} ),
+  $rs->result_source->name,
+  $rs->_resolved_attrs->{alias},
+);
+
+my $compdbi = sub {
+  my @r = $schema->storage->dbh->selectall_arrayref ('SELECT * FROM ' . ${$rs->as_query}->[0] )
+} if $rs->can ('as_query');
+
+cmpthese(-3, {
+  Cursor => sub { $rs->reset; my @r = $rs->cursor->all },
+  HRI => sub { $rs->reset; my @r = $rs->search ({}, { result_class => 'DBIx::Class::ResultClass::HashRefInflator' } )->all },
+  RowObj => sub { $rs->reset; my @r = $rs->all },
+  RawDBI => sub { my @r = $dbh->selectall_arrayref ($sql) },
+  $compdbi ? (CompDBI => $compdbi) : (),
+});


Property changes on: DBIx-Class/0.08/branches/group_by_consistency/maint/benchmark_datafetch.pl
___________________________________________________________________
Added: svn:executable
   + *

Added: DBIx-Class/0.08/branches/group_by_consistency/maint/joint_deps.pl
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/maint/joint_deps.pl	                        (rev 0)
+++ DBIx-Class/0.08/branches/group_by_consistency/maint/joint_deps.pl	2010-05-06 09:42:51 UTC (rev 9313)
@@ -0,0 +1,60 @@
+#!/usr/bin/perl
+
+use warnings;
+use strict;
+
+use CPANDB;
+use DBIx::Class::Schema::Loader 0.05;
+use Data::Dumper::Concise;
+
+{
+  package CPANDB::Schema;
+  use base qw/DBIx::Class::Schema::Loader/;
+
+  __PACKAGE__->loader_options (
+    naming => 'v5',
+  );
+}
+
+my $s = CPANDB::Schema->connect (sub { CPANDB->dbh } );
+
+# reference names are unstable - just create rels manually
+my $distrsrc = $s->source('Distribution');
+
+# the has_many helper is a class-only method (why?), thus
+# manual add_rel
+$distrsrc->add_relationship (
+  'deps',
+  $s->class('Dependency'),
+  { 'foreign.distribution' => 'self.' . ($distrsrc->primary_columns)[0] },
+  { accessor => 'multi', join_type => 'left' },
+);
+
+# here is how one could use the helper currently:
+#
+#my $distresult = $s->class('Distribution');
+#$distresult->has_many (
+#  'deps',
+#  $s->class('Dependency'),
+#  'distribution',
+#);
+#$s->unregister_source ('Distribution');
+#$s->register_class ('Distribution', $distresult);
+
+
+# a proof of concept how to find out who uses us *AND* SQLT
+my $us_and_sqlt = $s->resultset('Distribution')->search (
+  {
+    'deps.dependency' => 'DBIx-Class',
+    'deps_2.dependency' => 'SQL-Translator',
+  },
+  {
+    join => [qw/deps deps/],
+    order_by => 'me.author',
+    select => [ 'me.distribution', 'me.author', map { "$_.phase" } (qw/deps deps_2/)],
+    as => [qw/dist_name dist_author req_dbic_at req_sqlt_at/],
+    result_class => 'DBIx::Class::ResultClass::HashRefInflator',
+  },
+);
+
+print Dumper [$us_and_sqlt->all];


Property changes on: DBIx-Class/0.08/branches/group_by_consistency/maint/joint_deps.pl
___________________________________________________________________
Added: svn:executable
   + *

Modified: DBIx-Class/0.08/branches/group_by_consistency/script/dbicadmin
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/script/dbicadmin	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/script/dbicadmin	2010-05-06 09:42:51 UTC (rev 9313)
@@ -1,221 +1,134 @@
 #!/usr/bin/perl
+
 use strict;
 use warnings;
 
-use Getopt::Long;
-use Pod::Usage;
-use JSON::Any;
+BEGIN {
+  use DBIx::Class;
+  die (  'The following modules are required for the dbicadmin utility: '
+       . DBIx::Class::Optional::Dependencies->req_missing_for ('admin_script')
+       . "\n"
+  ) unless DBIx::Class::Optional::Dependencies->req_ok_for ('admin_script');
+}
 
+use DBIx::Class::Admin::Descriptive;
+#use Getopt::Long::Descriptive;
+use DBIx::Class::Admin;
 
-my $json = JSON::Any->new(allow_barekey => 1, allow_singlequote => 1);
+my $short_description = "utility for administrating DBIx::Class schemata";
+my $synopsis_text =q|
+  deploy a schema to a database
+  %c --schema=MyApp::Schema \
+    --connect='["dbi:SQLite:my.db", "", ""]' \
+    --deploy
 
-GetOptions(
-    'schema=s'  => \my $schema_class,
-    'class=s'   => \my $resultset_class,
-    'connect=s' => \my $connect,
-    'op=s'      => \my $op,
-    'set=s'     => \my $set,
-    'where=s'   => \my $where,
-    'attrs=s'   => \my $attrs,
-    'format=s'  => \my $format,
-    'force'     => \my $force,
-    'trace'     => \my $trace,
-    'quiet'     => \my $quiet,
-    'help'      => \my $help,
-    'tlibs'      => \my $t_libs,
+  update an existing record
+  %c --schema=MyApp::Schema --class=Employee \
+    --connect='["dbi:SQLite:my.db", "", ""]' \
+    --op=update --set='{ "name": "New_Employee" }'
+|;
+
+my ($opts, $usage) = describe_options(
+    "%c: %o",
+  (
+    ['Actions'],
+    ["action" => hidden => { one_of => [
+      ['create' => 'Create version diffs needs preversion',],
+      ['upgrade' => 'Upgrade the database to the current schema '],
+      ['install' => 'Install the schema version tables to an existing database',],
+      ['deploy' => 'Deploy the schema to the database',],
+      ['select'   => 'Select data from the schema', ],
+      ['insert'   => 'Insert data into the schema', ],
+      ['update'   => 'Update data in the schema', ], 
+      ['delete'   => 'Delete data from the schema',],
+      ['op:s' => 'compatiblity option all of the above can be suppied as --op=<action>'],
+      ['help' => 'display this help', { implies => { schema_class => '__dummy__' } } ],
+      ['selfinject-pod' => 'hidden', { implies => { schema_class => '__dummy__' } } ],
+    ], required=> 1 }],
+    ['Arguments'],
+    ['schema-class:s' => 'The class of the schema to load', { required => 1 } ],
+    ['resultset|resultset-class|class:s' => 'The resultset to operate on for data manipulation' ],
+    ['config-stanza:s' => 'Where in the config to find the connection_info, supply in form MyApp::Model::DB',],
+    ['config:s' => 'Supply the config file for parsing by Config::Any', { depends => 'config_stanza'} ],
+    ['connect-info:s%' => 'Supply the connect info as additonal options ie -I dsn=<dsn> user=<user> password=<pass> '],
+    ['connect:s' => 'Supply the connect info as a json string' ],
+    ['sql-dir:s' => 'The directory where sql diffs will be created'],
+    ['sql-type:s' => 'The RDBMs flavour you wish to use'],
+    ['version:i' => 'Supply a version install'],
+    ['preversion:s' => 'The previous version to diff against',],
+    ['set:s' => 'JSON data used to perform data operations' ],
+    ['attrs:s' => 'JSON string to be used for the second argument for search'],
+    ['where:s' => 'JSON string to be used for the where clause of search'],
+    ['force' => 'Be forceful with some operations'],
+    ['trace' => 'Turn on DBIx::Class trace output'],
+    ['quiet' => 'Be less verbose'],
+  )
 );
 
-if ($t_libs) {
-    unshift( @INC, 't/lib', 'lib' );
-}
+die "please only use one of --config or --connect-info\n" if ($opts->{config} and $opts->{connect_info});
 
-pod2usage(1) if ($help);
-$ENV{DBIC_TRACE} = 1 if ($trace);
+if($opts->{selfinject_pod}) {
 
-die('No op specified') if(!$op);
-die('Invalid op') if ($op!~/^insert|update|delete|select$/s);
-my $csv_class;
-if ($op eq 'select') {
-    $format ||= 'tsv';
-    die('Invalid format') if ($format!~/^tsv|csv$/s);
-    $csv_class = 'Text::CSV_XS';
-    eval{ require Text::CSV_XS };
-    if ($@) {
-        $csv_class = 'Text::CSV_PP';
-        eval{ require Text::CSV_PP };
-        die('The select op requires either the Text::CSV_XS or the Text::CSV_PP module') if ($@);
-    }
+    die "This is an internal method, do not call!!!\n"
+      unless $ENV{MAKELEVEL};
+
+    $usage->synopsis($synopsis_text);
+    $usage->short_description($short_description);
+    exec (
+      $^X,
+      qw/-p -0777 -i -e/,
+      (
+        's/^# auto_pod_begin.*^# auto_pod_end/'
+      . quotemeta($usage->pod)
+      . '/ms'
+      ),
+      __FILE__
+    );
 }
 
-die('No schema specified') if(!$schema_class);
-eval("require $schema_class");
-die('Unable to load schema') if ($@);
-$connect = $json->jsonToObj( $connect ) if ($connect);
-my $schema = $schema_class->connect(
-    ( $connect ? @$connect : () )
-);
-
-die('No class specified') if(!$resultset_class);
-my $resultset = eval{ $schema->resultset($resultset_class) };
-die('Unable to load the class with the schema') if ($@);
-
-$set = $json->jsonToObj( $set ) if ($set);
-$where = $json->jsonToObj( $where ) if ($where);
-$attrs = $json->jsonToObj( $attrs ) if ($attrs);
-
-if ($op eq 'insert') {
-    die('Do not use the where option with the insert op') if ($where);
-    die('Do not use the attrs option with the insert op') if ($attrs);
-    my $obj = $resultset->create( $set );
-    print ''.ref($resultset).' ID: '.join(',',$obj->id())."\n" if (!$quiet);
+if($opts->{help}) {
+    $usage->die();
 }
-elsif ($op eq 'update') {
-    $resultset = $resultset->search( ($where||{}) );
-    my $count = $resultset->count();
-    print "This action will modify $count ".ref($resultset)." records.\n" if (!$quiet);
-    if ( $force || confirm() ) {
-        $resultset->update_all( $set );
-    }
-}
-elsif ($op eq 'delete') {
-    die('Do not use the set option with the delete op') if ($set);
-    $resultset = $resultset->search( ($where||{}), ($attrs||()) );
-    my $count = $resultset->count();
-    print "This action will delete $count ".ref($resultset)." records.\n" if (!$quiet);
-    if ( $force || confirm() ) {
-        $resultset->delete_all();
-    }
-}
-elsif ($op eq 'select') {
-    die('Do not use the set option with the select op') if ($set);
-    my $csv = $csv_class->new({
-        sep_char => ( $format eq 'tsv' ? "\t" : ',' ),
-    });
-    $resultset = $resultset->search( ($where||{}), ($attrs||()) );
-    my @columns = $resultset->result_source->columns();
-    $csv->combine( @columns );
-    print $csv->string()."\n";
-    while (my $row = $resultset->next()) {
-        my @fields;
-        foreach my $column (@columns) {
-            push( @fields, $row->get_column($column) );
-        }
-        $csv->combine( @fields );
-        print $csv->string()."\n";
-    }
-}
 
-sub confirm {
-    print "Are you sure you want to do this? (type YES to confirm) ";
-    my $response = <STDIN>;
-    return 1 if ($response=~/^YES/);
-    return;
+# option compatability mangle
+if($opts->{connect}) {
+  $opts->{connect_info} = delete $opts->{connect};
 }
 
-__END__
+my $admin = DBIx::Class::Admin->new( %$opts );
 
-=head1 NAME
 
-dbicadmin - Execute operations upon DBIx::Class objects.
+my $action = $opts->{action};
 
-=head1 SYNOPSIS
+$action = $opts->{op} if ($action eq 'op');
 
-  dbicadmin --op=insert --schema=My::Schema --class=Class --set=JSON
-  dbicadmin --op=update --schema=My::Schema --class=Class --set=JSON --where=JSON
-  dbicadmin --op=delete --schema=My::Schema --class=Class --where=JSON
-  dbicadmin --op=select --schema=My::Schema --class=Class --where=JSON --format=tsv
+print "Performig action $action...\n";
 
-=head1 DESCRIPTION
+my $res = $admin->$action();
+if ($action eq 'select') {
 
-This utility provides the ability to run INSERTs, UPDATEs, 
-DELETEs, and SELECTs on any DBIx::Class object.
+  my $format = $opts->{format} || 'tsv';
+  die('Invalid format') if ($format!~/^tsv|csv$/s);
 
-=head1 OPTIONS
+  require Text::CSV;
 
-=head2 op
+  my $csv = Text::CSV->new({
+    sep_char => ( $format eq 'tsv' ? "\t" : ',' ),
+  });
 
-The type of operation.  Valid values are insert, update, delete, 
-and select.
+  foreach my $row (@$res) {
+    $csv->combine( @$row );
+    print $csv->string()."\n";
+  }
+}
 
-=head2 schema
 
-The name of your schema class.
+__END__
 
-=head2 class
+# auto_pod_begin
+#
+# This will be replaced by the actual pod when selfinject-pod is invoked
+#
+# auto_pod_end
 
-The name of the class, within your schema, that you want to run 
-the operation on.
-
-=head2 connect
-
-A JSON array to be passed to your schema class upon connecting.  
-The array will need to be compatible with whatever the DBIC 
-->connect() method requires.
-
-=head2 set
-
-This option must be valid JSON data string and is passed in to 
-the DBIC update() method.  Use this option with the update 
-and insert ops.
-
-=head2 where
-
-This option must be valid JSON data string and is passed in as 
-the first argument to the DBIC search() method.  Use this 
-option with the update, delete, and select ops.
-
-=head2 attrs
-
-This option must be valid JSON data string and is passed in as 
-the second argument to the DBIC search() method.  Use this 
-option with the update, delete, and select ops.
-
-=head2 help
-
-Display this help page.
-
-=head2 force
-
-Suppresses the confirmation dialogues that are usually displayed 
-when someone runs a DELETE or UPDATE action.
-
-=head2 quiet
-
-Do not display status messages.
-
-=head2 trace
-
-Turns on tracing on the DBI storage, thus printing SQL as it is 
-executed.
-
-=head2 tlibs
-
-This option is purely for testing during the DBIC installation.  Do 
-not use it.
-
-=head1 JSON
-
-JSON is a lightweight data-interchange format.  It allows you 
-to express complex data structures for use in the where and 
-set options.
-
-This module turns on L<JSON>'s BareKey and QuotApos options so 
-that your data can look a bit more readable.
-
-  --where={"this":"that"} # generic JSON
-  --where={this:'that'}   # with BareKey and QuoteApos
-
-Consider wrapping your JSON in outer quotes so that you don't 
-have to escape your inner quotes.
-
-  --where={this:\"that\"} # no outer quote
-  --where='{this:"that"}' # outer quoted
-
-=head1 AUTHOR
-
-Aran Deltac <bluefeet at cpan.org>
-
-=head1 LICENSE
-
-You may distribute this code under the same terms as Perl itself.
-
+# vim: et ft=perl

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/02pod.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/02pod.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/02pod.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -5,23 +5,17 @@
 use lib qw(t/lib);
 use DBICTest;
 
-my @MODULES = (
-  'Test::Pod 1.26',
-);
-
 # Don't run tests for installs
 unless ( DBICTest::AuthorCheck->is_author || $ENV{AUTOMATED_TESTING} || $ENV{RELEASE_TESTING} ) {
   plan( skip_all => "Author tests not required for installation" );
 }
 
-# Load the testing modules
-foreach my $MODULE ( @MODULES ) {
-  eval "use $MODULE";
-  if ( $@ ) {
-    $ENV{RELEASE_TESTING}
-    ? die( "Failed to load required release-testing module $MODULE" )
-    : plan( skip_all => "$MODULE not available for testing" );
-  }
+require DBIx::Class;
+unless ( DBIx::Class::Optional::Dependencies->req_ok_for ('test_pod') ) {
+  my $missing = DBIx::Class::Optional::Dependencies->req_missing_for ('test_pod');
+  $ENV{RELEASE_TESTING} || DBICTest::AuthorCheck->is_author
+    ? die ("Failed to load release-testing module requirements: $missing")
+    : plan skip_all => "Test needs: $missing"
 }
 
-all_pod_files_ok();
+Test::Pod::all_pod_files_ok();

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/03podcoverage.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/03podcoverage.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/03podcoverage.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -6,24 +6,17 @@
 use lib qw(t/lib);
 use DBICTest;
 
-my @MODULES = (
-  'Test::Pod::Coverage 1.08',
-  'Pod::Coverage 0.20',
-);
-
 # Don't run tests for installs
 unless ( DBICTest::AuthorCheck->is_author || $ENV{AUTOMATED_TESTING} || $ENV{RELEASE_TESTING} ) {
   plan( skip_all => "Author tests not required for installation" );
 }
 
-# Load the testing modules
-foreach my $MODULE ( @MODULES ) {
-  eval "use $MODULE";
-  if ( $@ ) {
-    $ENV{RELEASE_TESTING}
-    ? die( "Failed to load required release-testing module $MODULE" )
-    : plan( skip_all => "$MODULE not available for testing" );
-  }
+require DBIx::Class;
+unless ( DBIx::Class::Optional::Dependencies->req_ok_for ('test_podcoverage') ) {
+  my $missing = DBIx::Class::Optional::Dependencies->req_missing_for ('test_podcoverage');
+  $ENV{RELEASE_TESTING} || DBICTest::AuthorCheck->is_author
+    ? die ("Failed to load release-testing module requirements: $missing")
+    : plan skip_all => "Test needs: $missing"
 }
 
 # Since this is about checking documentation, a little documentation
@@ -86,6 +79,14 @@
         /]
     },
 
+    'DBIx::Class::Storage::DBI::Replicated*'        => {
+        ignore => [ qw/
+            connect_call_do_sql
+            disconnect_call_do_sql
+        /]
+    },
+
+    'DBIx::Class::Admin::*'                         => { skip => 1 },
     'DBIx::Class::ClassResolver::PassThrough'       => { skip => 1 },
     'DBIx::Class::Componentised'                    => { skip => 1 },
     'DBIx::Class::Relationship::*'                  => { skip => 1 },
@@ -95,7 +96,6 @@
     'DBIx::Class::Storage::DBI::Replicated::Types'  => { skip => 1 },
 
 # test some specific components whose parents are exempt below
-    'DBIx::Class::Storage::DBI::Replicated*'        => {},
     'DBIx::Class::Relationship::Base'               => {},
 
 # internals
@@ -141,7 +141,7 @@
         if exists($ex->{ignore});
 
     # run the test with the potentially modified parm set
-    pod_coverage_ok($module, $parms, "$module POD coverage");
+    Test::Pod::Coverage::pod_coverage_ok($module, $parms, "$module POD coverage");
   }
 }
 

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/06notabs.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/06notabs.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/06notabs.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -5,26 +5,20 @@
 use lib 't/lib';
 use DBICTest;
 
-my @MODULES = (
-  'Test::NoTabs 0.9',
-);
-
-plan skip_all => 'Does not work with done_testing, temp disabled';
-
 # Don't run tests for installs
 unless ( DBICTest::AuthorCheck->is_author || $ENV{AUTOMATED_TESTING} || $ENV{RELEASE_TESTING} ) {
   plan( skip_all => "Author tests not required for installation" );
 }
-# Load the testing modules
-foreach my $MODULE ( @MODULES ) {
-  eval "use $MODULE";
-  if ( $@ ) {
-    $ENV{RELEASE_TESTING}
-    ? die( "Failed to load required release-testing module $MODULE" )
-    : plan( skip_all => "$MODULE not available for testing" );
-  }
+
+require DBIx::Class;
+unless ( DBIx::Class::Optional::Dependencies->req_ok_for ('test_notabs') ) {
+  my $missing = DBIx::Class::Optional::Dependencies->req_missing_for ('test_notabs');
+  $ENV{RELEASE_TESTING} || DBICTest::AuthorCheck->is_author
+    ? die ("Failed to load release-testing module requirements: $missing")
+    : plan skip_all => "Test needs: $missing"
 }
 
-all_perl_files_ok(qw/t lib script maint/);
+Test::NoTabs::all_perl_files_ok(qw/t lib script maint/);
 
-done_testing;
+# FIXME - need to fix Test::NoTabs
+#done_testing;

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/07eol.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/07eol.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/07eol.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -5,29 +5,25 @@
 use lib 't/lib';
 use DBICTest;
 
-my @MODULES = (
-  'Test::EOL 0.6',
-);
-
-plan skip_all => 'Does not work with done_testing, temp disabled';
-
 # Don't run tests for installs
 unless ( DBICTest::AuthorCheck->is_author || $ENV{AUTOMATED_TESTING} || $ENV{RELEASE_TESTING} ) {
   plan( skip_all => "Author tests not required for installation" );
 }
-# Load the testing modules
-foreach my $MODULE ( @MODULES ) {
-  eval "use $MODULE";
-  if ( $@ ) {
-    $ENV{RELEASE_TESTING}
-    ? die( "Failed to load required release-testing module $MODULE" )
-    : plan( skip_all => "$MODULE not available for testing" );
-  }
+
+plan skip_all => 'Test::EOL very broken';
+
+require DBIx::Class;
+unless ( DBIx::Class::Optional::Dependencies->req_ok_for ('test_eol') ) {
+  my $missing = DBIx::Class::Optional::Dependencies->req_missing_for ('test_eol');
+  $ENV{RELEASE_TESTING} || DBICTest::AuthorCheck->is_author
+    ? die ("Failed to load release-testing module requirements: $missing")
+    : plan skip_all => "Test needs: $missing"
 }
 
 TODO: {
   local $TODO = 'Do not fix those yet - we have way too many branches out there, merging will be hell';
-  all_perl_files_ok({ trailing_whitespace => 1}, qw/t lib script maint/);
+  Test::EOL::all_perl_files_ok({ trailing_whitespace => 1}, qw/t lib script maint/);
 }
 
-done_testing;
+# FIXME - need to fix Test::EOL
+#done_testing;

Added: DBIx-Class/0.08/branches/group_by_consistency/t/10optional_deps.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/10optional_deps.t	                        (rev 0)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/10optional_deps.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -0,0 +1,70 @@
+use strict;
+use warnings;
+no warnings qw/once/;
+
+use Test::More;
+use lib qw(t/lib);
+use Scalar::Util; # load before we break require()
+
+use_ok 'DBIx::Class::Optional::Dependencies';
+
+my $sqlt_dep = DBIx::Class::Optional::Dependencies->req_list_for ('deploy');
+is_deeply (
+  [ keys %$sqlt_dep ],
+  [ 'SQL::Translator' ],
+  'Correct deploy() dependency list',
+);
+
+# make module loading impossible, regardless of actual libpath contents
+ at INC = (sub { die('Optional Dep Test') } );
+
+ok (
+  ! DBIx::Class::Optional::Dependencies->req_ok_for ('deploy'),
+  'deploy() deps missing',
+);
+
+like (
+  DBIx::Class::Optional::Dependencies->req_missing_for ('deploy'),
+  qr/^SQL::Translator \>\= \d/,
+  'expected missing string contents',
+);
+
+like (
+  DBIx::Class::Optional::Dependencies->req_errorlist_for ('deploy')->{'SQL::Translator'},
+  qr/Optional Dep Test/,
+  'custom exception found in errorlist',
+);
+
+
+#make it so module appears loaded
+$INC{'SQL/Translator.pm'} = 1;
+$SQL::Translator::VERSION = 999;
+
+ok (
+  ! DBIx::Class::Optional::Dependencies->req_ok_for ('deploy'),
+  'deploy() deps missing cached properly',
+);
+
+#reset cache
+%DBIx::Class::Optional::Dependencies::req_availability_cache = ();
+
+
+ok (
+  DBIx::Class::Optional::Dependencies->req_ok_for ('deploy'),
+  'deploy() deps present',
+);
+
+is (
+  DBIx::Class::Optional::Dependencies->req_missing_for ('deploy'),
+  '',
+  'expected null missing string',
+);
+
+is_deeply (
+  DBIx::Class::Optional::Dependencies->req_errorlist_for ('deploy'),
+  {},
+  'expected empty errorlist',
+);
+
+
+done_testing;

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/39load_namespaces_1.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/39load_namespaces_1.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/39load_namespaces_1.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -7,8 +7,6 @@
 use lib qw(t/lib);
 use DBICTest; # do not remove even though it is not used
 
-plan tests => 8;
-
 my $warnings;
 eval {
     local $SIG{__WARN__} = sub { $warnings .= shift };
@@ -16,9 +14,11 @@
     use base qw/DBIx::Class::Schema/;
     __PACKAGE__->load_namespaces;
 };
-ok(!$@) or diag $@;
-like($warnings, qr/load_namespaces found ResultSet class C with no corresponding Result class/);
+ok(!$@, 'load_namespaces doesnt die') or diag $@;
+like($warnings, qr/load_namespaces found ResultSet class C with no corresponding Result class/, 'Found warning about extra ResultSet classes');
 
+like($warnings, qr/load_namespaces found ResultSet class DBICNSTest::ResultSet::D that does not subclass DBIx::Class::ResultSet/, 'Found warning about ResultSets with incorrect subclass');
+
 my $source_a = DBICNSTest->source('A');
 isa_ok($source_a, 'DBIx::Class::ResultSource::Table');
 my $rset_a   = DBICNSTest->resultset('A');
@@ -31,5 +31,7 @@
 
 for my $moniker (qw/A B/) {
   my $class = "DBICNSTest::Result::$moniker";
-  ok(!defined($class->result_source_instance->source_name));
+  ok(!defined($class->result_source_instance->source_name), "Source name of $moniker not defined");
 }
+
+done_testing;

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/39load_namespaces_3.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/39load_namespaces_3.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/39load_namespaces_3.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -3,25 +3,25 @@
 use strict;
 use warnings;
 use Test::More;
+use Test::Exception;
+use Test::Warn;
 
 use lib qw(t/lib);
 use DBICTest; # do not remove even though it is not used
 
-plan tests => 7;
+lives_ok (sub {
+  warnings_exist ( sub {
+      package DBICNSTestOther;
+      use base qw/DBIx::Class::Schema/;
+      __PACKAGE__->load_namespaces(
+          result_namespace => [ '+DBICNSTest::Rslt', '+DBICNSTest::OtherRslt' ],
+          resultset_namespace => '+DBICNSTest::RSet',
+      );
+    },
+    qr/load_namespaces found ResultSet class C with no corresponding Result class/,
+  );
+});
 
-my $warnings;
-eval {
-    local $SIG{__WARN__} = sub { $warnings .= shift };
-    package DBICNSTestOther;
-    use base qw/DBIx::Class::Schema/;
-    __PACKAGE__->load_namespaces(
-        result_namespace => [ '+DBICNSTest::Rslt', '+DBICNSTest::OtherRslt' ],
-        resultset_namespace => '+DBICNSTest::RSet',
-    );
-};
-ok(!$@) or diag $@;
-like($warnings, qr/load_namespaces found ResultSet class C with no corresponding Result class/);
-
 my $source_a = DBICNSTestOther->source('A');
 isa_ok($source_a, 'DBIx::Class::ResultSource::Table');
 my $rset_a   = DBICNSTestOther->resultset('A');
@@ -34,3 +34,5 @@
 
 my $source_d = DBICNSTestOther->source('D');
 isa_ok($source_d, 'DBIx::Class::ResultSource::Table');
+
+done_testing;

Deleted: DBIx-Class/0.08/branches/group_by_consistency/t/41orrible.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/41orrible.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/41orrible.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -1,89 +0,0 @@
-use strict;
-use warnings;
-
-use Test::More;
-use DBIx::Class::SQLAHacks::OracleJoins;
-
-use lib qw(t/lib);
-use DBICTest; # do not remove even though it is not used
-use DBIC::SqlMakerTest;
-
-plan tests => 4;
-
-my $sa = new DBIx::Class::SQLAHacks::OracleJoins;
-
-$sa->limit_dialect('RowNum');
-
-is($sa->select('rubbish',
-                  [ 'foo.id', 'bar.id', \'TO_CHAR(foo.womble, "blah")' ],
-                  undef, undef, 1, 3),
-   'SELECT * FROM
-(
-    SELECT A.*, ROWNUM r FROM
-    (
-        SELECT foo.id AS col1, bar.id AS col2, TO_CHAR(foo.womble, "blah") AS col3 FROM rubbish 
-    ) A
-    WHERE ROWNUM < 5
-) B
-WHERE r >= 4
-', 'Munged stuff to make Oracle not explode');
-
-# test WhereJoins
-# search with undefined or empty $cond
-
-#  my ($self, $table, $fields, $where, $order, @rest) = @_;
-my ($sql, @bind) = $sa->select(
-    [
-        { me => "cd" },
-        [
-            { "-join_type" => "LEFT", artist => "artist" },
-            { "artist.artistid" => "me.artist" },
-        ],
-    ],
-    [ 'cd.cdid', 'cd.artist', 'cd.title', 'cd.year', 'artist.artistid', 'artist.name' ],
-    undef,
-    undef
-);
-is_same_sql_bind(
-  $sql, \@bind,
-  'SELECT cd.cdid, cd.artist, cd.title, cd.year, artist.artistid, artist.name FROM cd me, artist artist WHERE ( artist.artistid(+) = me.artist )', [],
-  'WhereJoins search with empty where clause'
-);
-
-($sql, @bind) = $sa->select(
-    [
-        { me => "cd" },
-        [
-            { "-join_type" => "", artist => "artist" },
-            { "artist.artistid" => "me.artist" },
-        ],
-    ],
-    [ 'cd.cdid', 'cd.artist', 'cd.title', 'cd.year', 'artist.artistid', 'artist.name' ],
-    { 'artist.artistid' => 3 },
-    undef
-);
-is_same_sql_bind(
-  $sql, \@bind,
-  'SELECT cd.cdid, cd.artist, cd.title, cd.year, artist.artistid, artist.name FROM cd me, artist artist WHERE ( ( ( artist.artistid = me.artist ) AND ( artist.artistid = ? ) ) )', [3],
-  'WhereJoins search with where clause'
-);
-
-($sql, @bind) = $sa->select(
-    [
-        { me => "cd" },
-        [
-            { "-join_type" => "LEFT", artist => "artist" },
-            { "artist.artistid" => "me.artist" },
-        ],
-    ],
-    [ 'cd.cdid', 'cd.artist', 'cd.title', 'cd.year', 'artist.artistid', 'artist.name' ],
-    [{ 'artist.artistid' => 3 }, { 'me.cdid' => 5 }],
-    undef
-);
-is_same_sql_bind(
-  $sql, \@bind,
-  'SELECT cd.cdid, cd.artist, cd.title, cd.year, artist.artistid, artist.name FROM cd me, artist artist WHERE ( ( ( artist.artistid(+) = me.artist ) AND ( ( ( artist.artistid = ? ) OR ( me.cdid = ? ) ) ) ) )', [3, 5],
-  'WhereJoins search with or in where clause'
-);
-
-

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/51threads.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/51threads.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/51threads.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -1,6 +1,9 @@
 use strict;
 use warnings;
+
 use Test::More;
+use Test::Exception;
+
 use Config;
 
 # README: If you set the env var to a number greater than 10,
@@ -38,7 +41,7 @@
 
 my $parent_rs;
 
-eval {
+lives_ok (sub {
     my $dbh = $schema->storage->dbh;
 
     {
@@ -52,8 +55,7 @@
 
     $parent_rs = $schema->resultset('CD')->search({ year => 1901 });
     $parent_rs->next;
-};
-ok(!$@) or diag "Creation eval failed: $@";
+}, 'populate successfull');
 
 my @children;
 while(@children < $num_children) {

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/52cycle.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/52cycle.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/52cycle.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -5,10 +5,9 @@
 use lib qw(t/lib);
 
 BEGIN {
-  eval { require Test::Memory::Cycle; require Devel::Cycle };
-  if ($@ or Devel::Cycle->VERSION < 1.10) {
-    plan skip_all => "leak test needs Test::Memory::Cycle and Devel::Cycle >= 1.10";
-  };
+  require DBIx::Class;
+  plan skip_all => 'Test needs: ' . DBIx::Class::Optional::Dependencies->req_missing_for ('test_cycle')
+    unless ( DBIx::Class::Optional::Dependencies->req_ok_for ('test_cycle') );
 }
 
 use DBICTest;

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/60core.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/60core.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/60core.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -419,11 +419,52 @@
   is($en_row->encoded, 'amliw', 'insert does not encode again');
 }
 
+#make sure multicreate encoding still works
+{
+  my $empl_rs = $schema->resultset('Employee');
+
+  my $empl = $empl_rs->create ({
+    name => 'Secret holder',
+    secretkey => {
+      encoded => 'CAN HAZ',
+    },
+  });
+  is($empl->secretkey->encoded, 'ZAH NAC', 'correctly encoding on multicreate');
+
+  my $empl2 = $empl_rs->create ({
+    name => 'Same secret holder',
+    secretkey => {
+      encoded => 'CAN HAZ',
+    },
+  });
+  is($empl2->secretkey->encoded, 'ZAH NAC', 'correctly encoding on preexisting multicreate');
+
+  $empl_rs->create ({
+    name => 'cat1',
+    secretkey => {
+      encoded => 'CHEEZBURGER',
+      keyholders => [
+        {
+          name => 'cat2',
+        },
+        {
+          name => 'cat3',
+        },
+      ],
+    },
+  });
+
+  is($empl_rs->find({name => 'cat1'})->secretkey->encoded, 'REGRUBZEEHC', 'correct secret in database for empl1');
+  is($empl_rs->find({name => 'cat2'})->secretkey->encoded, 'REGRUBZEEHC', 'correct secret in database for empl2');
+  is($empl_rs->find({name => 'cat3'})->secretkey->encoded, 'REGRUBZEEHC', 'correct secret in database for empl3');
+
+}
+
 # make sure we got rid of the compat shims
 SKIP: {
-    skip "Remove in 0.09", 5 if $DBIx::Class::VERSION < 0.09;
+    skip "Remove in 0.082", 3 if $DBIx::Class::VERSION < 0.082;
 
-    for (qw/compare_relationship_keys pk_depends_on resolve_condition resolve_join resolve_prefetch/) {
+    for (qw/compare_relationship_keys pk_depends_on resolve_condition/) {
       ok (! DBIx::Class::ResultSource->can ($_), "$_ no longer provided by DBIx::Class::ResultSource");
     }
 }

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/69update.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/69update.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/69update.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -7,11 +7,6 @@
 
 my $schema = DBICTest->init_schema();
 
-BEGIN {
-        eval "use DBD::SQLite";
-        plan $@ ? (skip_all => 'needs DBD::SQLite for testing') : (tests => 6);
-}                                                                               
-
 my $art = $schema->resultset("Artist")->find(1);
 
 isa_ok $art => 'DBICTest::Artist';
@@ -20,10 +15,10 @@
 
 ok($art->name($name) eq $name, 'update');
 
-{ 
+{
   my @changed_keys = $art->is_changed;
   is( scalar (@changed_keys), 0, 'field changed but same value' );
-}                                                                               
+}
 
 $art->discard_changes;
 
@@ -34,3 +29,5 @@
 my $art_100 = $schema->resultset("Artist")->find(100);
 $art_100->artistid(101);
 ok($art_100->update(), 'update allows pk mutation via column accessor');
+
+done_testing;

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/71mysql.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/71mysql.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/71mysql.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -194,6 +194,29 @@
   );
 }
 
+{
+  # Test support for straight joins
+  my $cdsrc = $schema->source('CD');
+  my $artrel_info = $cdsrc->relationship_info ('artist');
+  $cdsrc->add_relationship(
+    'straight_artist',
+    $artrel_info->{class},
+    $artrel_info->{cond},
+    { %{$artrel_info->{attrs}}, join_type => 'straight' },
+  );
+  is_same_sql_bind (
+    $cdsrc->resultset->search({}, { prefetch => 'straight_artist' })->as_query,
+    '(
+      SELECT me.cdid, me.artist, me.title, me.year, me.genreid, me.single_track,
+             straight_artist.artistid, straight_artist.name, straight_artist.rank, straight_artist.charfield
+        FROM cd me
+        STRAIGHT_JOIN artist straight_artist ON straight_artist.artistid = me.artist
+    )',
+    [],
+    'straight joins correctly supported for mysql'
+  );
+}
+
 ## Can we properly deal with the null search problem?
 ##
 ## Only way is to do a SET SQL_AUTO_IS_NULL = 0; on connect

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/72pg.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/72pg.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/72pg.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -11,12 +11,11 @@
 
 plan skip_all => <<EOM unless $dsn && $user;
 Set \$ENV{DBICTEST_PG_DSN}, _USER and _PASS to run this test
-( NOTE: This test drops and creates tables called 'artist', 'casecheck',
-  'array_test' and 'sequence_test' as well as following sequences:
-  'pkid1_seq', 'pkid2_seq' and 'nonpkid_seq''.  as well as following
-  schemas: 'dbic_t_schema', 'dbic_t_schema_2', 'dbic_t_schema_3',
-  'dbic_t_schema_4', and 'dbic_t_schema_5'
-)
+( NOTE: This test drops and creates tables called 'artist', 'cd',
+'timestamp_primary_key_test', 'track', 'casecheck', 'array_test' and
+'sequence_test' as well as following sequences: 'pkid1_seq', 'pkid2_seq' and
+'nonpkid_seq''. as well as following schemas: 'dbic_t_schema',
+'dbic_t_schema_2', 'dbic_t_schema_3', 'dbic_t_schema_4', and 'dbic_t_schema_5')
 EOM
 
 ### load any test classes that are defined further down in the file via BEGIN blocks
@@ -24,250 +23,297 @@
 our @test_classes; #< array that will be pushed into by test classes defined in this file
 DBICTest::Schema->load_classes( map {s/.+:://;$_} @test_classes ) if @test_classes;
 
+my $test_server_supports_insert_returning = do {
+  my $s = DBICTest::Schema->connect($dsn, $user, $pass);
+  $s->storage->_determine_driver;
+  $s->storage->_supports_insert_returning;
+};
 
+my $schema;
+
+for my $use_insert_returning ($test_server_supports_insert_returning
+  ? (0,1)
+  : (0)
+) {
+  no warnings qw/redefine once/;
+  local *DBIx::Class::Storage::DBI::Pg::_supports_insert_returning = sub {
+    $use_insert_returning
+  };
+
 ###  pre-connect tests (keep each test separate as to make sure rebless() runs)
-{
-  my $s = DBICTest::Schema->connect($dsn, $user, $pass);
+  {
+    my $s = DBICTest::Schema->connect($dsn, $user, $pass);
 
-  ok (!$s->storage->_dbh, 'definitely not connected');
+    ok (!$s->storage->_dbh, 'definitely not connected');
 
-  # Check that datetime_parser returns correctly before we explicitly connect.
-  SKIP: {
-      eval { require DateTime::Format::Pg };
-      skip "DateTime::Format::Pg required", 2 if $@;
+    # Check that datetime_parser returns correctly before we explicitly connect.
+    SKIP: {
+        eval { require DateTime::Format::Pg };
+        skip "DateTime::Format::Pg required", 2 if $@;
 
-      my $store = ref $s->storage;
-      is($store, 'DBIx::Class::Storage::DBI', 'Started with generic storage');
+        my $store = ref $s->storage;
+        is($store, 'DBIx::Class::Storage::DBI', 'Started with generic storage');
 
-      my $parser = $s->storage->datetime_parser;
-      is( $parser, 'DateTime::Format::Pg', 'datetime_parser is as expected');
+        my $parser = $s->storage->datetime_parser;
+        is( $parser, 'DateTime::Format::Pg', 'datetime_parser is as expected');
+    }
+
+    ok (!$s->storage->_dbh, 'still not connected');
   }
+  {
+    my $s = DBICTest::Schema->connect($dsn, $user, $pass);
+    # make sure sqlt_type overrides work (::Storage::DBI::Pg does this)
+    ok (!$s->storage->_dbh, 'definitely not connected');
+    is ($s->storage->sqlt_type, 'PostgreSQL', 'sqlt_type correct pre-connection');
+    ok (!$s->storage->_dbh, 'still not connected');
+  }
 
-  ok (!$s->storage->_dbh, 'still not connected');
-}
-{
-  my $s = DBICTest::Schema->connect($dsn, $user, $pass);
-  # make sure sqlt_type overrides work (::Storage::DBI::Pg does this)
-  ok (!$s->storage->_dbh, 'definitely not connected');
-  is ($s->storage->sqlt_type, 'PostgreSQL', 'sqlt_type correct pre-connection');
-  ok (!$s->storage->_dbh, 'still not connected');
-}
-
 ### connect, create postgres-specific test schema
 
-my $schema = DBICTest::Schema->connect($dsn, $user, $pass);
+  $schema = DBICTest::Schema->connect($dsn, $user, $pass);
+  $schema->storage->ensure_connected;
 
-drop_test_schema($schema);
-create_test_schema($schema);
+  drop_test_schema($schema);
+  create_test_schema($schema);
 
 ### begin main tests
 
-
 # run a BIG bunch of tests for last-insert-id / Auto-PK / sequence
 # discovery
-run_apk_tests($schema); #< older set of auto-pk tests
-run_extended_apk_tests($schema); #< new extended set of auto-pk tests
+  run_apk_tests($schema); #< older set of auto-pk tests
+  run_extended_apk_tests($schema); #< new extended set of auto-pk tests
 
+### type_info tests
 
+  my $test_type_info = {
+      'artistid' => {
+          'data_type' => 'integer',
+          'is_nullable' => 0,
+          'size' => 4,
+      },
+      'name' => {
+          'data_type' => 'character varying',
+          'is_nullable' => 1,
+          'size' => 100,
+          'default_value' => undef,
+      },
+      'rank' => {
+          'data_type' => 'integer',
+          'is_nullable' => 0,
+          'size' => 4,
+          'default_value' => 13,
 
+      },
+      'charfield' => {
+          'data_type' => 'character',
+          'is_nullable' => 1,
+          'size' => 10,
+          'default_value' => undef,
+      },
+      'arrayfield' => {
+          'data_type' => 'integer[]',
+          'is_nullable' => 1,
+          'size' => undef,
+          'default_value' => undef,
+      },
+  };
 
+  my $type_info = $schema->storage->columns_info_for('dbic_t_schema.artist');
+  my $artistid_defval = delete $type_info->{artistid}->{default_value};
+  like($artistid_defval,
+       qr/^nextval\('([^\.]*\.){0,1}artist_artistid_seq'::(?:text|regclass)\)/,
+       'columns_info_for - sequence matches Pg get_autoinc_seq expectations');
+  is_deeply($type_info, $test_type_info,
+            'columns_info_for - column data types');
 
-### type_info tests
 
-my $test_type_info = {
-    'artistid' => {
-        'data_type' => 'integer',
-        'is_nullable' => 0,
-        'size' => 4,
-    },
-    'name' => {
-        'data_type' => 'character varying',
-        'is_nullable' => 1,
-        'size' => 100,
-        'default_value' => undef,
-    },
-    'rank' => {
-        'data_type' => 'integer',
-        'is_nullable' => 0,
-        'size' => 4,
-        'default_value' => 13,
 
-    },
-    'charfield' => {
-        'data_type' => 'character',
-        'is_nullable' => 1,
-        'size' => 10,
-        'default_value' => undef,
-    },
-    'arrayfield' => {
-        'data_type' => 'integer[]',
-        'is_nullable' => 1,
-        'size' => undef,
-        'default_value' => undef,
-    },
-};
 
-my $type_info = $schema->storage->columns_info_for('dbic_t_schema.artist');
-my $artistid_defval = delete $type_info->{artistid}->{default_value};
-like($artistid_defval,
-     qr/^nextval\('([^\.]*\.){0,1}artist_artistid_seq'::(?:text|regclass)\)/,
-     'columns_info_for - sequence matches Pg get_autoinc_seq expectations');
-is_deeply($type_info, $test_type_info,
-          'columns_info_for - column data types');
+####### Array tests
 
+  BEGIN {
+    package DBICTest::Schema::ArrayTest;
+    push @main::test_classes, __PACKAGE__;
 
+    use strict;
+    use warnings;
+    use base 'DBIx::Class::Core';
 
+    __PACKAGE__->table('dbic_t_schema.array_test');
+    __PACKAGE__->add_columns(qw/id arrayfield/);
+    __PACKAGE__->column_info_from_storage(1);
+    __PACKAGE__->set_primary_key('id');
 
-####### Array tests
+  }
+  SKIP: {
+    skip "Need DBD::Pg 2.9.2 or newer for array tests", 4 if $DBD::Pg::VERSION < 2.009002;
 
-BEGIN {
-  package DBICTest::Schema::ArrayTest;
-  push @main::test_classes, __PACKAGE__;
+    lives_ok {
+      $schema->resultset('ArrayTest')->create({
+        arrayfield => [1, 2],
+      });
+    } 'inserting arrayref as pg array data';
 
-  use strict;
-  use warnings;
-  use base 'DBIx::Class::Core';
+    lives_ok {
+      $schema->resultset('ArrayTest')->update({
+        arrayfield => [3, 4],
+      });
+    } 'updating arrayref as pg array data';
 
-  __PACKAGE__->table('dbic_t_schema.array_test');
-  __PACKAGE__->add_columns(qw/id arrayfield/);
-  __PACKAGE__->column_info_from_storage(1);
-  __PACKAGE__->set_primary_key('id');
-
-}
-SKIP: {
-  skip "Need DBD::Pg 2.9.2 or newer for array tests", 4 if $DBD::Pg::VERSION < 2.009002;
-
-  lives_ok {
     $schema->resultset('ArrayTest')->create({
-      arrayfield => [1, 2],
+      arrayfield => [5, 6],
     });
-  } 'inserting arrayref as pg array data';
 
-  lives_ok {
-    $schema->resultset('ArrayTest')->update({
-      arrayfield => [3, 4],
-    });
-  } 'updating arrayref as pg array data';
+    my $count;
+    lives_ok {
+      $count = $schema->resultset('ArrayTest')->search({
+        arrayfield => \[ '= ?' => [arrayfield => [3, 4]] ],   #Todo anything less ugly than this?
+      })->count;
+    } 'comparing arrayref to pg array data does not blow up';
+    is($count, 1, 'comparing arrayref to pg array data gives correct result');
+  }
 
-  $schema->resultset('ArrayTest')->create({
-    arrayfield => [5, 6],
-  });
 
-  my $count;
-  lives_ok {
-    $count = $schema->resultset('ArrayTest')->search({
-      arrayfield => \[ '= ?' => [arrayfield => [3, 4]] ],   #Todo anything less ugly than this?
-    })->count;
-  } 'comparing arrayref to pg array data does not blow up';
-  is($count, 1, 'comparing arrayref to pg array data gives correct result');
-}
 
-
-
 ########## Case check
 
-BEGIN {
-  package DBICTest::Schema::Casecheck;
-  push @main::test_classes, __PACKAGE__;
+  BEGIN {
+    package DBICTest::Schema::Casecheck;
+    push @main::test_classes, __PACKAGE__;
 
-  use strict;
-  use warnings;
-  use base 'DBIx::Class::Core';
+    use strict;
+    use warnings;
+    use base 'DBIx::Class::Core';
 
-  __PACKAGE__->table('dbic_t_schema.casecheck');
-  __PACKAGE__->add_columns(qw/id name NAME uc_name/);
-  __PACKAGE__->column_info_from_storage(1);
-  __PACKAGE__->set_primary_key('id');
-}
+    __PACKAGE__->table('dbic_t_schema.casecheck');
+    __PACKAGE__->add_columns(qw/id name NAME uc_name/);
+    __PACKAGE__->column_info_from_storage(1);
+    __PACKAGE__->set_primary_key('id');
+  }
 
-my $name_info = $schema->source('Casecheck')->column_info( 'name' );
-is( $name_info->{size}, 1, "Case sensitive matching info for 'name'" );
+  my $name_info = $schema->source('Casecheck')->column_info( 'name' );
+  is( $name_info->{size}, 1, "Case sensitive matching info for 'name'" );
 
-my $NAME_info = $schema->source('Casecheck')->column_info( 'NAME' );
-is( $NAME_info->{size}, 2, "Case sensitive matching info for 'NAME'" );
+  my $NAME_info = $schema->source('Casecheck')->column_info( 'NAME' );
+  is( $NAME_info->{size}, 2, "Case sensitive matching info for 'NAME'" );
 
-my $uc_name_info = $schema->source('Casecheck')->column_info( 'uc_name' );
-is( $uc_name_info->{size}, 3, "Case insensitive matching info for 'uc_name'" );
+  my $uc_name_info = $schema->source('Casecheck')->column_info( 'uc_name' );
+  is( $uc_name_info->{size}, 3, "Case insensitive matching info for 'uc_name'" );
 
 
 
 
 ## Test SELECT ... FOR UPDATE
 
-SKIP: {
-    if(eval "require Sys::SigAction" && !$@) {
-        Sys::SigAction->import( 'set_sig_handler' );
-    }
-    else {
-      skip "Sys::SigAction is not available", 6;
-    }
+  SKIP: {
+      if(eval "require Sys::SigAction" && !$@) {
+          Sys::SigAction->import( 'set_sig_handler' );
+      }
+      else {
+        skip "Sys::SigAction is not available", 6;
+      }
 
-    my ($timed_out, $artist2);
+      my ($timed_out, $artist2);
 
-    for my $t (
-      {
-        # Make sure that an error was raised, and that the update failed
-        update_lock => 1,
-        test_sub => sub {
-          ok($timed_out, "update from second schema times out");
-          ok($artist2->is_column_changed('name'), "'name' column is still dirty from second schema");
+      for my $t (
+        {
+          # Make sure that an error was raised, and that the update failed
+          update_lock => 1,
+          test_sub => sub {
+            ok($timed_out, "update from second schema times out");
+            ok($artist2->is_column_changed('name'), "'name' column is still dirty from second schema");
+          },
         },
-      },
-      {
-        # Make sure that an error was NOT raised, and that the update succeeded
-        update_lock => 0,
-        test_sub => sub {
-          ok(! $timed_out, "update from second schema DOES NOT timeout");
-          ok(! $artist2->is_column_changed('name'), "'name' column is NOT dirty from second schema");
+        {
+          # Make sure that an error was NOT raised, and that the update succeeded
+          update_lock => 0,
+          test_sub => sub {
+            ok(! $timed_out, "update from second schema DOES NOT timeout");
+            ok(! $artist2->is_column_changed('name'), "'name' column is NOT dirty from second schema");
+          },
         },
-      },
-    ) {
-      # create a new schema
-      my $schema2 = DBICTest::Schema->connect($dsn, $user, $pass);
-      $schema2->source("Artist")->name("dbic_t_schema.artist");
+      ) {
+        # create a new schema
+        my $schema2 = DBICTest::Schema->connect($dsn, $user, $pass);
+        $schema2->source("Artist")->name("dbic_t_schema.artist");
 
-      $schema->txn_do( sub {
-        my $artist = $schema->resultset('Artist')->search(
-            {
-                artistid => 1
-            },
-            $t->{update_lock} ? { for => 'update' } : {}
-        )->first;
-        is($artist->artistid, 1, "select returns artistid = 1");
+        $schema->txn_do( sub {
+          my $rs = $schema->resultset('Artist')->search(
+              {
+                  artistid => 1
+              },
+              $t->{update_lock} ? { for => 'update' } : {}
+          );
+          ok ($rs->count, 'Count works');
 
-        $timed_out = 0;
-        eval {
-            my $h = set_sig_handler( 'ALRM', sub { die "DBICTestTimeout" } );
-            alarm(2);
-            $artist2 = $schema2->resultset('Artist')->find(1);
-            $artist2->name('fooey');
-            $artist2->update;
-            alarm(0);
-        };
-        $timed_out = $@ =~ /DBICTestTimeout/;
-      });
+          my $artist = $rs->next;
+          is($artist->artistid, 1, "select returns artistid = 1");
 
-      $t->{test_sub}->();
-    }
-}
+          $timed_out = 0;
+          eval {
+              my $h = set_sig_handler( 'ALRM', sub { die "DBICTestTimeout" } );
+              alarm(2);
+              $artist2 = $schema2->resultset('Artist')->find(1);
+              $artist2->name('fooey');
+              $artist2->update;
+              alarm(0);
+          };
+          $timed_out = $@ =~ /DBICTestTimeout/;
+        });
 
+        $t->{test_sub}->();
+      }
+  }
 
+
 ######## other older Auto-pk tests
 
-$schema->source("SequenceTest")->name("dbic_t_schema.sequence_test");
-for (1..5) {
-    my $st = $schema->resultset('SequenceTest')->create({ name => 'foo' });
-    is($st->pkid1, $_, "Oracle Auto-PK without trigger: First primary key");
-    is($st->pkid2, $_ + 9, "Oracle Auto-PK without trigger: Second primary key");
-    is($st->nonpkid, $_ + 19, "Oracle Auto-PK without trigger: Non-primary key");
+  $schema->source("SequenceTest")->name("dbic_t_schema.sequence_test");
+  for (1..5) {
+      my $st = $schema->resultset('SequenceTest')->create({ name => 'foo' });
+      is($st->pkid1, $_, "Auto-PK for sequence without default: First primary key");
+      is($st->pkid2, $_ + 9, "Auto-PK for sequence without default: Second primary key");
+      is($st->nonpkid, $_ + 19, "Auto-PK for sequence without default: Non-primary key");
+  }
+  my $st = $schema->resultset('SequenceTest')->create({ name => 'foo', pkid1 => 55 });
+  is($st->pkid1, 55, "Auto-PK for sequence without default: First primary key set manually");
+
+
+######## test non-serial auto-pk
+
+  if ($schema->storage->_supports_insert_returning) {
+    $schema->source('TimestampPrimaryKey')->name('dbic_t_schema.timestamp_primary_key_test');
+    my $row = $schema->resultset('TimestampPrimaryKey')->create({});
+    ok $row->id;
+  }
+
+######## test with_deferred_fk_checks
+
+  $schema->source('CD')->name('dbic_t_schema.cd');
+  $schema->source('Track')->name('dbic_t_schema.track');
+  lives_ok {
+    $schema->storage->with_deferred_fk_checks(sub {
+      $schema->resultset('Track')->create({
+        trackid => 999, cd => 999, position => 1, title => 'deferred FK track'
+      });
+      $schema->resultset('CD')->create({
+        artist => 1, cdid => 999, year => '2003', title => 'deferred FK cd'
+      });
+    });
+  } 'with_deferred_fk_checks code survived';
+
+  is eval { $schema->resultset('Track')->find(999)->title }, 'deferred FK track',
+     'code in with_deferred_fk_checks worked'; 
+
+  throws_ok {
+    $schema->resultset('Track')->create({
+      trackid => 1, cd => 9999, position => 1, title => 'Track1'
+    });
+  } qr/constraint/i, 'with_deferred_fk_checks is off';
 }
-my $st = $schema->resultset('SequenceTest')->create({ name => 'foo', pkid1 => 55 });
-is($st->pkid1, 55, "Oracle Auto-PK without trigger: First primary key set manually");
 
 done_testing;
 
-exit;
-
 END {
     return unless $schema;
     drop_test_schema($schema);
@@ -296,7 +342,35 @@
 
       $dbh->do("CREATE SCHEMA dbic_t_schema");
       $dbh->do("CREATE TABLE dbic_t_schema.artist $std_artist_table");
+
       $dbh->do(<<EOS);
+CREATE TABLE dbic_t_schema.timestamp_primary_key_test (
+  id timestamp default current_timestamp
+)
+EOS
+      $dbh->do(<<EOS);
+CREATE TABLE dbic_t_schema.cd (
+  cdid int PRIMARY KEY,
+  artist int,
+  title varchar(255),
+  year varchar(4),
+  genreid int,
+  single_track int
+)
+EOS
+      $dbh->do(<<EOS);
+CREATE TABLE dbic_t_schema.track (
+  trackid int,
+  cd int REFERENCES dbic_t_schema.cd(cdid) DEFERRABLE,
+  position int,
+  title varchar(255),
+  last_updated_on date,
+  last_updated_at date,
+  small_dt date
+)
+EOS
+
+      $dbh->do(<<EOS);
 CREATE TABLE dbic_t_schema.sequence_test (
     pkid1 integer
     , pkid2 integer
@@ -478,6 +552,7 @@
   my $search_path_save = eapk_get_search_path($schema);
 
   eapk_drop_all($schema);
+  %seqs = ();
 
   # make the test schemas and sequences
   $schema->storage->dbh_do(sub {

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/73oracle.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/73oracle.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/73oracle.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -53,22 +53,26 @@
   $dbh->do("DROP SEQUENCE nonpkid_seq");
   $dbh->do("DROP TABLE artist");
   $dbh->do("DROP TABLE sequence_test");
+  $dbh->do("DROP TABLE track");
   $dbh->do("DROP TABLE cd");
-  $dbh->do("DROP TABLE track");
 };
 $dbh->do("CREATE SEQUENCE artist_seq START WITH 1 MAXVALUE 999999 MINVALUE 0");
 $dbh->do("CREATE SEQUENCE cd_seq START WITH 1 MAXVALUE 999999 MINVALUE 0");
 $dbh->do("CREATE SEQUENCE pkid1_seq START WITH 1 MAXVALUE 999999 MINVALUE 0");
 $dbh->do("CREATE SEQUENCE pkid2_seq START WITH 10 MAXVALUE 999999 MINVALUE 0");
 $dbh->do("CREATE SEQUENCE nonpkid_seq START WITH 20 MAXVALUE 999999 MINVALUE 0");
+
 $dbh->do("CREATE TABLE artist (artistid NUMBER(12), name VARCHAR(255), rank NUMBER(38), charfield VARCHAR2(10))");
+$dbh->do("ALTER TABLE artist ADD (CONSTRAINT artist_pk PRIMARY KEY (artistid))");
+
 $dbh->do("CREATE TABLE sequence_test (pkid1 NUMBER(12), pkid2 NUMBER(12), nonpkid NUMBER(12), name VARCHAR(255))");
+$dbh->do("ALTER TABLE sequence_test ADD (CONSTRAINT sequence_test_constraint PRIMARY KEY (pkid1, pkid2))");
+
 $dbh->do("CREATE TABLE cd (cdid NUMBER(12), artist NUMBER(12), title VARCHAR(255), year VARCHAR(4), genreid NUMBER(12), single_track NUMBER(12))");
-$dbh->do("CREATE TABLE track (trackid NUMBER(12), cd NUMBER(12), position NUMBER(12), title VARCHAR(255), last_updated_on DATE, last_updated_at DATE, small_dt DATE)");
+$dbh->do("ALTER TABLE cd ADD (CONSTRAINT cd_pk PRIMARY KEY (cdid))");
 
-$dbh->do("ALTER TABLE artist ADD (CONSTRAINT artist_pk PRIMARY KEY (artistid))");
-$dbh->do("ALTER TABLE cd ADD (CONSTRAINT cd_pk PRIMARY KEY (cdid))");
-$dbh->do("ALTER TABLE sequence_test ADD (CONSTRAINT sequence_test_constraint PRIMARY KEY (pkid1, pkid2))");
+$dbh->do("CREATE TABLE track (trackid NUMBER(12), cd NUMBER(12) REFERENCES cd(cdid) DEFERRABLE, position NUMBER(12), title VARCHAR(255), last_updated_on DATE, last_updated_at DATE, small_dt DATE)");
+
 $dbh->do(qq{
   CREATE OR REPLACE TRIGGER artist_insert_trg
   BEFORE INSERT ON artist
@@ -218,6 +222,27 @@
   is( scalar @results, 1, "Group by with limit OK" );
 }
 
+# test with_deferred_fk_checks
+lives_ok {
+  $schema->storage->with_deferred_fk_checks(sub {
+    $schema->resultset('Track')->create({
+      trackid => 999, cd => 999, position => 1, title => 'deferred FK track'
+    });
+    $schema->resultset('CD')->create({
+      artist => 1, cdid => 999, year => '2003', title => 'deferred FK cd'
+    });
+  });
+} 'with_deferred_fk_checks code survived';
+
+is eval { $schema->resultset('Track')->find(999)->title }, 'deferred FK track',
+   'code in with_deferred_fk_checks worked'; 
+
+throws_ok {
+  $schema->resultset('Track')->create({
+    trackid => 1, cd => 9999, position => 1, title => 'Track1'
+  });
+} qr/constraint/i, 'with_deferred_fk_checks is off';
+
 # test auto increment using sequences WITHOUT triggers
 for (1..5) {
     my $st = $schema->resultset('SequenceTest')->create({ name => 'foo' });
@@ -271,8 +296,8 @@
         $dbh->do("DROP SEQUENCE nonpkid_seq");
         $dbh->do("DROP TABLE artist");
         $dbh->do("DROP TABLE sequence_test");
+        $dbh->do("DROP TABLE track");
         $dbh->do("DROP TABLE cd");
-        $dbh->do("DROP TABLE track");
         $dbh->do("DROP TABLE bindtype_test");
     }
 }

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/746mssql.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/746mssql.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/746mssql.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -33,6 +33,12 @@
   ok (! $schema2->storage->connected, 'a re-connected cloned schema starts unconnected');
 }
 
+$schema->storage->_dbh->disconnect;
+
+lives_ok {
+  $schema->storage->dbh_do(sub { $_[1]->do('select 1') })
+} '_ping works';
+
 $schema->storage->dbh_do (sub {
     my ($storage, $dbh) = @_;
     eval { $dbh->do("DROP TABLE artist") };
@@ -53,8 +59,6 @@
   { on_connect_call => 'use_dynamic_cursors' },
   {},
 );
-my $new;
-
 # test Auto-PK with different options
 for my $opts (@opts) {
   SKIP: {
@@ -71,384 +75,408 @@
 
     $schema->resultset('Artist')->search({ name => 'foo' })->delete;
 
-    $new = $schema->resultset('Artist')->create({ name => 'foo' });
+    my $new = $schema->resultset('Artist')->create({ name => 'foo' });
 
     ok($new->artistid > 0, "Auto-PK worked");
   }
 }
 
-$seen_id{$new->artistid}++;
 
-# test LIMIT support
-for (1..6) {
-    $new = $schema->resultset('Artist')->create({ name => 'Artist ' . $_ });
-    is ( $seen_id{$new->artistid}, undef, "id for Artist $_ is unique" );
-    $seen_id{$new->artistid}++;
-}
 
-my $it = $schema->resultset('Artist')->search( {}, {
-    rows => 3,
-    order_by => 'artistid',
-});
+# Test populate
 
-is( $it->count, 3, "LIMIT count ok" );
-is( $it->next->name, "foo", "iterator->next ok" );
-$it->next;
-is( $it->next->name, "Artist 2", "iterator->next ok" );
-is( $it->next, undef, "next past end of resultset ok" );
-
-# test GUID columns
-
-$schema->storage->dbh_do (sub {
+{
+  $schema->storage->dbh_do (sub {
     my ($storage, $dbh) = @_;
-    eval { $dbh->do("DROP TABLE artist") };
+    eval { $dbh->do("DROP TABLE owners") };
+    eval { $dbh->do("DROP TABLE books") };
     $dbh->do(<<'SQL');
-CREATE TABLE artist (
-   artistid UNIQUEIDENTIFIER NOT NULL,
+CREATE TABLE books (
+   id INT IDENTITY (1, 1) NOT NULL,
+   source VARCHAR(100),
+   owner INT,
+   title VARCHAR(10),
+   price INT NULL
+)
+
+CREATE TABLE owners (
+   id INT IDENTITY (1, 1) NOT NULL,
    name VARCHAR(100),
-   rank INT NOT NULL DEFAULT '13',
-   charfield CHAR(10) NULL,
-   a_guid UNIQUEIDENTIFIER,
-   primary key(artistid)
 )
 SQL
-});
 
-# start disconnected to make sure insert works on an un-reblessed storage
-$schema = DBICTest::Schema->connect($dsn, $user, $pass);
+  });
 
-my $row;
-lives_ok {
-  $row = $schema->resultset('ArtistGUID')->create({ name => 'mtfnpy' })
-} 'created a row with a GUID';
+  lives_ok ( sub {
+    # start a new connection, make sure rebless works
+    my $schema = DBICTest::Schema->connect($dsn, $user, $pass);
+    $schema->populate ('Owners', [
+      [qw/id  name  /],
+      [qw/1   wiggle/],
+      [qw/2   woggle/],
+      [qw/3   boggle/],
+      [qw/4   fRIOUX/],
+      [qw/5   fRUE/],
+      [qw/6   fREW/],
+      [qw/7   fROOH/],
+      [qw/8   fISMBoC/],
+      [qw/9   station/],
+      [qw/10   mirror/],
+      [qw/11   dimly/],
+      [qw/12   face_to_face/],
+      [qw/13   icarus/],
+      [qw/14   dream/],
+      [qw/15   dyrstyggyr/],
+    ]);
+  }, 'populate with PKs supplied ok' );
 
-ok(
-  eval { $row->artistid },
-  'row has GUID PK col populated',
-);
-diag $@ if $@;
 
-ok(
-  eval { $row->a_guid },
-  'row has a GUID col with auto_nextval populated',
-);
-diag $@ if $@;
+  lives_ok (sub {
+    # start a new connection, make sure rebless works
+    # test an insert with a supplied identity, followed by one without
+    my $schema = DBICTest::Schema->connect($dsn, $user, $pass);
+    for (2, 1) {
+      my $id = $_ * 20 ;
+      $schema->resultset ('Owners')->create ({ id => $id, name => "troglodoogle $id" });
+      $schema->resultset ('Owners')->create ({ name => "troglodoogle " . ($id + 1) });
+    }
+  }, 'create with/without PKs ok' );
 
-my $row_from_db = $schema->resultset('ArtistGUID')
-  ->search({ name => 'mtfnpy' })->first;
+  is ($schema->resultset ('Owners')->count, 19, 'owner rows really in db' );
 
-is $row_from_db->artistid, $row->artistid,
-  'PK GUID round trip';
+  lives_ok ( sub {
+    # start a new connection, make sure rebless works
+    my $schema = DBICTest::Schema->connect($dsn, $user, $pass);
+    $schema->populate ('BooksInLibrary', [
+      [qw/source  owner title   /],
+      [qw/Library 1     secrets0/],
+      [qw/Library 1     secrets1/],
+      [qw/Eatery  1     secrets2/],
+      [qw/Library 2     secrets3/],
+      [qw/Library 3     secrets4/],
+      [qw/Eatery  3     secrets5/],
+      [qw/Library 4     secrets6/],
+      [qw/Library 5     secrets7/],
+      [qw/Eatery  5     secrets8/],
+      [qw/Library 6     secrets9/],
+      [qw/Library 7     secrets10/],
+      [qw/Eatery  7     secrets11/],
+      [qw/Library 8     secrets12/],
+    ]);
+  }, 'populate without PKs supplied ok' );
+}
 
-is $row_from_db->a_guid, $row->a_guid,
-  'NON-PK GUID round trip';
+# test simple, complex LIMIT and limited prefetch support, with both dialects and quote combinations (if possible)
+for my $dialect (
+  'Top',
+  ($schema->storage->_server_info->{normalized_dbms_version} || 0 ) >= 9
+    ? ('RowNumberOver')
+    : ()
+  ,
+) {
+  for my $quoted (0, 1) {
 
-# test MONEY type
-$schema->storage->dbh_do (sub {
-    my ($storage, $dbh) = @_;
-    eval { $dbh->do("DROP TABLE money_test") };
-    $dbh->do(<<'SQL');
-CREATE TABLE money_test (
-   id INT IDENTITY PRIMARY KEY,
-   amount MONEY NULL
-)
-SQL
-});
+    $schema = DBICTest::Schema->connect($dsn, $user, $pass, {
+        limit_dialect => $dialect,
+        $quoted
+          ? ( quote_char => [ qw/ [ ] / ], name_sep => '.' )
+          : ()
+        ,
+      });
 
-my $rs = $schema->resultset('Money');
+    my $test_type = "Dialect:$dialect Quoted:$quoted";
 
-lives_ok {
-  $row = $rs->create({ amount => 100 });
-} 'inserted a money value';
+    # basic limit support
+    TODO: {
+      my $art_rs = $schema->resultset ('Artist');
+      $art_rs->delete;
+      $art_rs->create({ name => 'Artist ' . $_ }) for (1..6);
 
-cmp_ok $rs->find($row->id)->amount, '==', 100, 'money value round-trip';
+      my $it = $schema->resultset('Artist')->search( {}, {
+        rows => 4,
+        offset => 3,
+        order_by => 'artistid',
+      });
 
-lives_ok {
-  $row->update({ amount => 200 });
-} 'updated a money value';
+      is( $it->count, 3, "$test_type: LIMIT count ok" );
 
-cmp_ok $rs->find($row->id)->amount, '==', 200,
-  'updated money value round-trip';
+      local $TODO = "Top-limit does not work when your limit ends up past the resultset"
+        if $dialect eq 'Top';
 
-lives_ok {
-  $row->update({ amount => undef });
-} 'updated a money value to NULL';
+      is( $it->next->name, 'Artist 4', "$test_type: iterator->next ok" );
+      $it->next;
+      is( $it->next->name, 'Artist 6', "$test_type: iterator->next ok" );
+      is( $it->next, undef, "$test_type: next past end of resultset ok" );
+    }
 
-is $rs->find($row->id)->amount, undef,'updated money value to NULL round-trip';
+    # plain ordered subqueries throw
+    throws_ok (sub {
+      $schema->resultset('Owners')->search ({}, { order_by => 'name' })->as_query
+    }, qr/ordered subselect encountered/, "$test_type: Ordered Subselect detection throws ok");
 
-$schema->storage->dbh_do (sub {
-    my ($storage, $dbh) = @_;
-    eval { $dbh->do("DROP TABLE owners") };
-    eval { $dbh->do("DROP TABLE books") };
-    $dbh->do(<<'SQL');
-CREATE TABLE books (
-   id INT IDENTITY (1, 1) NOT NULL,
-   source VARCHAR(100),
-   owner INT,
-   title VARCHAR(10),
-   price INT NULL
-)
+    # make sure ordered subselects *somewhat* work
+    {
+      my $owners = $schema->resultset ('Owners')->search ({}, { order_by => 'name', offset => 2, rows => 3, unsafe_subselect_ok => 1 });
+      my $sealed_owners = $owners->as_subselect_rs;
 
-CREATE TABLE owners (
-   id INT IDENTITY (1, 1) NOT NULL,
-   name VARCHAR(100),
-)
-SQL
+      is_deeply (
+        [ map { $_->name } ($sealed_owners->all) ],
+        [ map { $_->name } ($owners->all) ],
+        "$test_type: Sort preserved from within a subquery",
+      );
+    }
 
-});
+    {
+      my $book_owner_ids = $schema->resultset ('BooksInLibrary')->search ({}, {
+        rows => 6,
+        offset => 2,
+        join => 'owner',
+        distinct => 1,
+        order_by => 'owner.name',
+        unsafe_subselect_ok => 1
+      })->get_column ('owner');
 
-lives_ok ( sub {
-  # start a new connection, make sure rebless works
-  my $schema = DBICTest::Schema->connect($dsn, $user, $pass);
-  $schema->populate ('Owners', [
-    [qw/id  name  /],
-    [qw/1   wiggle/],
-    [qw/2   woggle/],
-    [qw/3   boggle/],
-    [qw/4   fRIOUX/],
-    [qw/5   fRUE/],
-    [qw/6   fREW/],
-    [qw/7   fROOH/],
-    [qw/8   fISMBoC/],
-    [qw/9   station/],
-    [qw/10   mirror/],
-    [qw/11   dimly/],
-    [qw/12   face_to_face/],
-    [qw/13   icarus/],
-    [qw/14   dream/],
-    [qw/15   dyrstyggyr/],
-  ]);
-}, 'populate with PKs supplied ok' );
+      my @ids = $book_owner_ids->all;
 
+      is (@ids, 6, 'Limit works');
 
-lives_ok (sub {
-  # start a new connection, make sure rebless works
-  # test an insert with a supplied identity, followed by one without
-  my $schema = DBICTest::Schema->connect($dsn, $user, $pass);
-  for (2, 1) {
-    my $id = $_ * 20 ;
-    $schema->resultset ('Owners')->create ({ id => $id, name => "troglodoogle $id" });
-    $schema->resultset ('Owners')->create ({ name => "troglodoogle " . ($id + 1) });
-  }
-}, 'create with/without PKs ok' );
+      my $book_owners = $schema->resultset ('Owners')->search ({
+        id => { -in => $book_owner_ids->as_query }
+      });
 
-is ($schema->resultset ('Owners')->count, 19, 'owner rows really in db' );
+      TODO: {
+        local $TODO = "Correlated limited IN subqueries will probably never preserve order";
 
-lives_ok ( sub {
-  # start a new connection, make sure rebless works
-  my $schema = DBICTest::Schema->connect($dsn, $user, $pass);
-  $schema->populate ('BooksInLibrary', [
-    [qw/source  owner title   /],
-    [qw/Library 1     secrets0/],
-    [qw/Library 1     secrets1/],
-    [qw/Eatery  1     secrets2/],
-    [qw/Library 2     secrets3/],
-    [qw/Library 3     secrets4/],
-    [qw/Eatery  3     secrets5/],
-    [qw/Library 4     secrets6/],
-    [qw/Library 5     secrets7/],
-    [qw/Eatery  5     secrets8/],
-    [qw/Library 6     secrets9/],
-    [qw/Library 7     secrets10/],
-    [qw/Eatery  7     secrets11/],
-    [qw/Library 8     secrets12/],
-  ]);
-}, 'populate without PKs supplied ok' );
+        is_deeply (
+          [ map { $_->id } ($book_owners->all) ],
+          [ $book_owner_ids->all ],
+          "$test_type: Sort is preserved across IN subqueries",
+        );
+      }
+    }
 
-# plain ordered subqueries throw
-throws_ok (sub {
-  $schema->resultset('Owners')->search ({}, { order_by => 'name' })->as_query
-}, qr/ordered subselect encountered/, 'Ordered Subselect detection throws ok');
+    # still even with lost order of IN, we should be getting correct
+    # sets
+    {
+      my $owners = $schema->resultset ('Owners')->search ({}, { order_by => 'name', offset => 2, rows => 3, unsafe_subselect_ok => 1 });
+      my $corelated_owners = $owners->result_source->resultset->search (
+        {
+          id => { -in => $owners->get_column('id')->as_query },
+        },
+        {
+          order_by => 'name' #reorder because of what is shown above
+        },
+      );
 
-# make sure ordered subselects *somewhat* work
-{
-  my $owners = $schema->resultset ('Owners')->search ({}, { order_by => 'name', offset => 2, rows => 3, unsafe_subselect_ok => 1 });
+      is (
+        join ("\x00", map { $_->name } ($corelated_owners->all) ),
+        join ("\x00", map { $_->name } ($owners->all) ),
+        "$test_type: With an outer order_by, everything still matches",
+      );
+    }
 
-  my $al = $owners->current_source_alias;
-  my $sealed_owners = $owners->result_source->resultset->search (
-    {},
+    # make sure right-join-side single-prefetch ordering limit works
     {
-      alias => $al,
-      from => [{
-        -alias => $al,
-        -source_handle => $owners->result_source->handle,
-        $al => $owners->as_query,
-      }],
-    },
-  );
+      my $rs = $schema->resultset ('BooksInLibrary')->search (
+        {
+          'owner.name' => { '!=', 'woggle' },
+        },
+        {
+          prefetch => 'owner',
+          order_by => 'owner.name',
+        }
+      );
+      # this is the order in which they should come from the above query
+      my @owner_names = qw/boggle fISMBoC fREW fRIOUX fROOH fRUE wiggle wiggle/;
 
-  is_deeply (
-    [ map { $_->name } ($sealed_owners->all) ],
-    [ map { $_->name } ($owners->all) ],
-    'Sort preserved from within a subquery',
-  );
-}
+      is ($rs->all, 8, "$test_type: Correct amount of objects from right-sorted joined resultset");
+      is_deeply (
+        [map { $_->owner->name } ($rs->all) ],
+        \@owner_names,
+        "$test_type: Prefetched rows were properly ordered"
+      );
 
-TODO: {
-  local $TODO = "This porbably will never work, but it isn't critical either afaik";
+      my $limited_rs = $rs->search ({}, {rows => 6, offset => 2, unsafe_subselect_ok => 1});
+      is ($limited_rs->count, 6, "$test_type: Correct count of limited right-sorted joined resultset");
+      is ($limited_rs->count_rs->next, 6, "$test_type: Correct count_rs of limited right-sorted joined resultset");
 
-  my $book_owner_ids = $schema->resultset ('BooksInLibrary')
-                               ->search ({}, { join => 'owner', distinct => 1, order_by => 'owner.name', unsafe_subselect_ok => 1 })
-                                ->get_column ('owner');
+      my $queries;
+      $schema->storage->debugcb(sub { $queries++; });
+      $schema->storage->debug(1);
 
-  my $book_owners = $schema->resultset ('Owners')->search ({
-    id => { -in => $book_owner_ids->as_query }
-  });
+      is_deeply (
+        [map { $_->owner->name } ($limited_rs->all) ],
+        [@owner_names[2 .. 7]],
+        "$test_type: Prefetch-limited rows were properly ordered"
+      );
+      is ($queries, 1, "$test_type: Only one query with prefetch");
 
-  is_deeply (
-    [ map { $_->id } ($book_owners->all) ],
-    [ $book_owner_ids->all ],
-    'Sort is preserved across IN subqueries',
-  );
-}
+      $schema->storage->debugcb(undef);
+      $schema->storage->debug(0);
 
-# This is known not to work - thus the negative test
-{
-  my $owners = $schema->resultset ('Owners')->search ({}, { order_by => 'name', offset => 2, rows => 3, unsafe_subselect_ok => 1 });
-  my $corelated_owners = $owners->result_source->resultset->search (
-    {
-      id => { -in => $owners->get_column('id')->as_query },
-    },
-    {
-      order_by => 'name' #reorder because of what is shown above
-    },
-  );
+      is_deeply (
+        [map { $_->name } ($limited_rs->search_related ('owner')->all) ],
+        [@owner_names[2 .. 7]],
+        "$test_type: Rows are still properly ordered after search_related",
+      );
+    }
 
-  cmp_ok (
-    join ("\x00", map { $_->name } ($corelated_owners->all) ),
-      'ne',
-    join ("\x00", map { $_->name } ($owners->all) ),
-    'Sadly sort not preserved from within a corelated subquery',
-  );
+    # try a ->has_many direction with duplicates
+    my $owners = $schema->resultset ('Owners')->search (
+      {
+        'books.id' => { '!=', undef },
+        'me.name' => { '!=', 'somebogusstring' },
+      },
+      {
+        prefetch => 'books',
+        order_by => { -asc => \['name + ?', [ test => 'xxx' ]] }, # test bindvar propagation
+        rows     => 3,  # 8 results total
+        unsafe_subselect_ok => 1,
+      },
+    );
 
-  cmp_ok (
-    join ("\x00", sort map { $_->name } ($corelated_owners->all) ),
-      'ne',
-    join ("\x00", sort map { $_->name } ($owners->all) ),
-    'Which in fact gives a completely wrong dataset',
-  );
-}
+    my ($sql, @bind) = @${$owners->page(3)->as_query};
+    is_deeply (
+      \@bind,
+      [ ([ 'me.name' => 'somebogusstring' ], [ test => 'xxx' ]) x 2 ],  # double because of the prefetch subq
+    );
 
+    is ($owners->page(1)->all, 3, "$test_type: has_many prefetch returns correct number of rows");
+    is ($owners->page(1)->count, 3, "$test_type: has-many prefetch returns correct count");
 
-# make sure right-join-side single-prefetch ordering limit works
-{
-  my $rs = $schema->resultset ('BooksInLibrary')->search (
-    {
-      'owner.name' => { '!=', 'woggle' },
-    },
-    {
-      prefetch => 'owner',
-      order_by => 'owner.name',
+    is ($owners->page(3)->count, 2, "$test_type: has-many prefetch returns correct count");
+    TODO: {
+      local $TODO = "Top-limit does not work when your limit ends up past the resultset"
+        if $dialect eq 'Top';
+      is ($owners->page(3)->all, 2, "$test_type: has_many prefetch returns correct number of rows");
+      is ($owners->page(3)->count_rs->next, 2, "$test_type: has-many prefetch returns correct count_rs");
     }
-  );
-  # this is the order in which they should come from the above query
-  my @owner_names = qw/boggle fISMBoC fREW fRIOUX fROOH fRUE wiggle wiggle/;
 
-  is ($rs->all, 8, 'Correct amount of objects from right-sorted joined resultset');
-  is_deeply (
-    [map { $_->owner->name } ($rs->all) ],
-    \@owner_names,
-    'Rows were properly ordered'
-  );
 
-  my $limited_rs = $rs->search ({}, {rows => 7, offset => 2, unsafe_subselect_ok => 1});
-  is ($limited_rs->count, 6, 'Correct count of limited right-sorted joined resultset');
-  is ($limited_rs->count_rs->next, 6, 'Correct count_rs of limited right-sorted joined resultset');
+    # try a ->belongs_to direction (no select collapse, group_by should work)
+    my $books = $schema->resultset ('BooksInLibrary')->search (
+      {
+        'owner.name' => [qw/wiggle woggle/],
+      },
+      {
+        distinct => 1,
+        having => \['1 = ?', [ test => 1 ] ], #test having propagation
+        prefetch => 'owner',
+        rows     => 2,  # 3 results total
+        order_by => { -desc => 'me.owner' },
+        unsafe_subselect_ok => 1,
+      },
+    );
 
-  my $queries;
-  $schema->storage->debugcb(sub { $queries++; });
-  $schema->storage->debug(1);
+    ($sql, @bind) = @${$books->page(3)->as_query};
+    is_deeply (
+      \@bind,
+      [
+        # inner
+        [ 'owner.name' => 'wiggle' ], [ 'owner.name' => 'woggle' ], [ source => 'Library' ], [ test => '1' ],
+        # outer
+        [ 'owner.name' => 'wiggle' ], [ 'owner.name' => 'woggle' ], [ source => 'Library' ],
+      ],
+    );
 
-  is_deeply (
-    [map { $_->owner->name } ($limited_rs->all) ],
-    [@owner_names[2 .. 7]],
-    'Limited rows were properly ordered'
-  );
-  is ($queries, 1, 'Only one query with prefetch');
+    is ($books->page(1)->all, 2, "$test_type: Prefetched grouped search returns correct number of rows");
+    is ($books->page(1)->count, 2, "$test_type: Prefetched grouped search returns correct count");
 
-  $schema->storage->debugcb(undef);
-  $schema->storage->debug(0);
+    is ($books->page(2)->count, 1, "$test_type: Prefetched grouped search returns correct count");
+    TODO: {
+      local $TODO = "Top-limit does not work when your limit ends up past the resultset"
+        if $dialect eq 'Top';
+      is ($books->page(2)->all, 1, "$test_type: Prefetched grouped search returns correct number of rows");
+      is ($books->page(2)->count_rs->next, 1, "$test_type: Prefetched grouped search returns correct count_rs");
+    }
+  }
+}
 
 
-  is_deeply (
-    [map { $_->name } ($limited_rs->search_related ('owner')->all) ],
-    [@owner_names[2 .. 7]],
-    'Rows are still properly ordered after search_related'
+# test GUID columns
+{
+  $schema->storage->dbh_do (sub {
+    my ($storage, $dbh) = @_;
+    eval { $dbh->do("DROP TABLE artist") };
+    $dbh->do(<<'SQL');
+CREATE TABLE artist (
+   artistid UNIQUEIDENTIFIER NOT NULL,
+   name VARCHAR(100),
+   rank INT NOT NULL DEFAULT '13',
+   charfield CHAR(10) NULL,
+   a_guid UNIQUEIDENTIFIER,
+   primary key(artistid)
+)
+SQL
+  });
+
+  # start disconnected to make sure insert works on an un-reblessed storage
+  $schema = DBICTest::Schema->connect($dsn, $user, $pass);
+
+  my $row;
+  lives_ok {
+    $row = $schema->resultset('ArtistGUID')->create({ name => 'mtfnpy' })
+  } 'created a row with a GUID';
+
+  ok(
+    eval { $row->artistid },
+    'row has GUID PK col populated',
   );
-}
+  diag $@ if $@;
 
+  ok(
+    eval { $row->a_guid },
+    'row has a GUID col with auto_nextval populated',
+  );
+  diag $@ if $@;
 
-#
-# try a prefetch on tables with identically named columns
-#
+  my $row_from_db = $schema->resultset('ArtistGUID')
+    ->search({ name => 'mtfnpy' })->first;
 
-# set quote char - make sure things work while quoted
-$schema->storage->_sql_maker->{quote_char} = [qw/[ ]/];
-$schema->storage->_sql_maker->{name_sep} = '.';
+  is $row_from_db->artistid, $row->artistid,
+    'PK GUID round trip';
 
+  is $row_from_db->a_guid, $row->a_guid,
+    'NON-PK GUID round trip';
+}
+
+# test MONEY type
 {
-  # try a ->has_many direction
-  my $owners = $schema->resultset ('Owners')->search (
-    {
-      'books.id' => { '!=', undef },
-      'me.name' => { '!=', 'somebogusstring' },
-    },
-    {
-      prefetch => 'books',
-      order_by => { -asc => \['name + ?', [ test => 'xxx' ]] }, # test bindvar propagation
-      rows     => 3,  # 8 results total
-      unsafe_subselect_ok => 1,
-    },
-  );
+  $schema->storage->dbh_do (sub {
+    my ($storage, $dbh) = @_;
+    eval { $dbh->do("DROP TABLE money_test") };
+    $dbh->do(<<'SQL');
+CREATE TABLE money_test (
+   id INT IDENTITY PRIMARY KEY,
+   amount MONEY NULL
+)
+SQL
+  });
 
-  my ($sql, @bind) = @${$owners->page(3)->as_query};
-  is_deeply (
-    \@bind,
-    [ ([ 'me.name' => 'somebogusstring' ], [ test => 'xxx' ]) x 2 ],  # double because of the prefetch subq
-  );
+  my $rs = $schema->resultset('Money');
+  my $row;
 
-  is ($owners->page(1)->all, 3, 'has_many prefetch returns correct number of rows');
-  is ($owners->page(1)->count, 3, 'has-many prefetch returns correct count');
+  lives_ok {
+    $row = $rs->create({ amount => 100 });
+  } 'inserted a money value';
 
-  is ($owners->page(3)->all, 2, 'has_many prefetch returns correct number of rows');
-  is ($owners->page(3)->count, 2, 'has-many prefetch returns correct count');
-  is ($owners->page(3)->count_rs->next, 2, 'has-many prefetch returns correct count_rs');
+  cmp_ok $rs->find($row->id)->amount, '==', 100, 'money value round-trip';
 
+  lives_ok {
+    $row->update({ amount => 200 });
+  } 'updated a money value';
 
-  # try a ->belongs_to direction (no select collapse, group_by should work)
-  my $books = $schema->resultset ('BooksInLibrary')->search (
-    {
-      'owner.name' => [qw/wiggle woggle/],
-    },
-    {
-      distinct => 1,
-      having => \['1 = ?', [ test => 1 ] ], #test having propagation
-      prefetch => 'owner',
-      rows     => 2,  # 3 results total
-      order_by => { -desc => 'me.owner' },
-      unsafe_subselect_ok => 1,
-    },
-  );
+  cmp_ok $rs->find($row->id)->amount, '==', 200,
+    'updated money value round-trip';
 
-  ($sql, @bind) = @${$books->page(3)->as_query};
-  is_deeply (
-    \@bind,
-    [
-      # inner
-      [ 'owner.name' => 'wiggle' ], [ 'owner.name' => 'woggle' ], [ source => 'Library' ], [ test => '1' ],
-      # outer
-      [ 'owner.name' => 'wiggle' ], [ 'owner.name' => 'woggle' ], [ source => 'Library' ],
-    ],
-  );
+  lives_ok {
+    $row->update({ amount => undef });
+  } 'updated a money value to NULL';
 
-  is ($books->page(1)->all, 2, 'Prefetched grouped search returns correct number of rows');
-  is ($books->page(1)->count, 2, 'Prefetched grouped search returns correct count');
-
-  is ($books->page(2)->all, 1, 'Prefetched grouped search returns correct number of rows');
-  is ($books->page(2)->count, 1, 'Prefetched grouped search returns correct count');
-  is ($books->page(2)->count_rs->next, 1, 'Prefetched grouped search returns correct count_rs');
+  is $rs->find($row->id)->amount, undef,'updated money value to NULL round-trip';
 }
 
+
 done_testing;
 
 # clean up our mess

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/746sybase.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/746sybase.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/746sybase.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -569,12 +569,10 @@
     $row->update({ amount => undef });
   } 'updated a money value to NULL';
 
-  my $null_amount = eval { $rs->find($row->id)->amount };
-  ok(
-    (($null_amount == undef) && (not $@)),
-    'updated money value to NULL round-trip'
-  );
-  diag $@ if $@;
+  lives_and {
+    my $null_amount = $rs->find($row->id)->amount;
+    is $null_amount, undef;
+  } 'updated money value to NULL round-trip';
 
 # Test computed columns and timestamps
   $schema->storage->dbh_do (sub {

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/748informix.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/748informix.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/748informix.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -11,15 +11,39 @@
 #warn "$dsn $user $pass";
 
 plan skip_all => 'Set $ENV{DBICTEST_INFORMIX_DSN}, _USER and _PASS to run this test'
-  unless ($dsn && $user);
+  unless $dsn;
 
-my $schema = DBICTest::Schema->connect($dsn, $user, $pass);
+my $schema = DBICTest::Schema->connect($dsn, $user, $pass, {
+  auto_savepoint => 1
+});
 
 my $dbh = $schema->storage->dbh;
 
 eval { $dbh->do("DROP TABLE artist") };
-
 $dbh->do("CREATE TABLE artist (artistid SERIAL, name VARCHAR(255), charfield CHAR(10), rank INTEGER DEFAULT 13);");
+eval { $dbh->do("DROP TABLE cd") };
+$dbh->do(<<EOS);
+CREATE TABLE cd (
+  cdid int PRIMARY KEY,
+  artist int,
+  title varchar(255),
+  year varchar(4),
+  genreid int,
+  single_track int
+)
+EOS
+eval { $dbh->do("DROP TABLE track") };
+$dbh->do(<<EOS);
+CREATE TABLE track (
+  trackid int,
+  cd int REFERENCES cd(cdid),
+  position int,
+  title varchar(255),
+  last_updated_on date,
+  last_updated_at date,
+  small_dt date
+)
+EOS
 
 my $ars = $schema->resultset('Artist');
 is ( $ars->count, 0, 'No rows at first' );
@@ -72,7 +96,47 @@
 is( $lim->next->artistid, 102, "iterator->next ok" );
 is( $lim->next, undef, "next past end of resultset ok" );
 
+# test savepoints
+throws_ok {
+  $schema->txn_do(sub {
+    eval {
+      $schema->txn_do(sub {
+        $ars->create({ name => 'in_savepoint' });
+        die "rolling back savepoint";
+      });
+    };
+    ok ((not $ars->search({ name => 'in_savepoint' })->first),
+      'savepoint rolled back');
+    $ars->create({ name => 'in_outer_txn' });
+    die "rolling back outer txn";
+  });
+} qr/rolling back outer txn/,
+  'correct exception for rollback';
 
+ok ((not $ars->search({ name => 'in_outer_txn' })->first),
+  'outer txn rolled back');
+
+######## test with_deferred_fk_checks
+lives_ok {
+  $schema->storage->with_deferred_fk_checks(sub {
+    $schema->resultset('Track')->create({
+      trackid => 999, cd => 999, position => 1, title => 'deferred FK track'
+    });
+    $schema->resultset('CD')->create({
+      artist => 1, cdid => 999, year => '2003', title => 'deferred FK cd'
+    });
+  });
+} 'with_deferred_fk_checks code survived';
+
+is eval { $schema->resultset('Track')->find(999)->title }, 'deferred FK track',
+ 'code in with_deferred_fk_checks worked'; 
+
+throws_ok {
+  $schema->resultset('Track')->create({
+    trackid => 1, cd => 9999, position => 1, title => 'Track1'
+  });
+} qr/constraint/i, 'with_deferred_fk_checks is off';
+
 done_testing;
 
 # clean up our mess

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/749sybase_asa.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/749sybase_asa.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/749sybase_asa.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -3,9 +3,12 @@
 
 use Test::More;
 use Test::Exception;
+use Scope::Guard ();
 use lib qw(t/lib);
 use DBICTest;
 
+DBICTest::Schema->load_classes('ArtistGUID');
+
 # tests stolen from 748informix.t
 
 my ($dsn, $user, $pass)    = @ENV{map { "DBICTEST_SYBASE_ASA_${_}" }      qw/DSN USER PASS/};
@@ -21,19 +24,21 @@
   [ $dsn2, $user2, $pass2 ],
 );
 
-my @handles_to_clean;
+my $schema;
 
 foreach my $info (@info) {
   my ($dsn, $user, $pass) = @$info;
 
   next unless $dsn;
 
-  my $schema = DBICTest::Schema->connect($dsn, $user, $pass);
+  $schema = DBICTest::Schema->connect($dsn, $user, $pass, {
+    auto_savepoint => 1
+  });
 
+  my $guard = Scope::Guard->new(\&cleanup);
+
   my $dbh = $schema->storage->dbh;
 
-  push @handles_to_clean, $dbh;
-
   eval { $dbh->do("DROP TABLE artist") };
 
   $dbh->do(<<EOF);
@@ -58,6 +63,26 @@
   $new->discard_changes;
   is($new->artistid, 66, 'Explicit PK assigned');
 
+# test savepoints
+  throws_ok {
+    $schema->txn_do(sub {
+      eval {
+        $schema->txn_do(sub {
+          $ars->create({ name => 'in_savepoint' });
+          die "rolling back savepoint";
+        });
+      };
+      ok ((not $ars->search({ name => 'in_savepoint' })->first),
+        'savepoint rolled back');
+      $ars->create({ name => 'in_outer_txn' });
+      die "rolling back outer txn";
+    });
+  } qr/rolling back outer txn/,
+    'correct exception for rollback';
+
+  ok ((not $ars->search({ name => 'in_outer_txn' })->first),
+    'outer txn rolled back');
+
 # test populate
   lives_ok (sub {
     my @pop;
@@ -138,13 +163,62 @@
       ok($rs->find($id)->$type eq $binstr{$size}, "verified inserted $size $type" );
     }
   }
+ 
+  my @uuid_types = qw/uniqueidentifier uniqueidentifierstr/;
+
+# test uniqueidentifiers
+  for my $uuid_type (@uuid_types) {
+    local $schema->source('ArtistGUID')->column_info('artistid')->{data_type}
+      = $uuid_type;
+
+    local $schema->source('ArtistGUID')->column_info('a_guid')->{data_type}
+      = $uuid_type;
+
+    $schema->storage->dbh_do (sub {
+      my ($storage, $dbh) = @_;
+      eval { $dbh->do("DROP TABLE artist") };
+      $dbh->do(<<"SQL");
+CREATE TABLE artist (
+   artistid $uuid_type NOT NULL,
+   name VARCHAR(100),
+   rank INT NOT NULL DEFAULT '13',
+   charfield CHAR(10) NULL,
+   a_guid $uuid_type,
+   primary key(artistid)
+)
+SQL
+    });
+
+    my $row;
+    lives_ok {
+      $row = $schema->resultset('ArtistGUID')->create({ name => 'mtfnpy' })
+    } 'created a row with a GUID';
+
+    ok(
+      eval { $row->artistid },
+      'row has GUID PK col populated',
+    );
+    diag $@ if $@;
+
+    ok(
+      eval { $row->a_guid },
+      'row has a GUID col with auto_nextval populated',
+    );
+    diag $@ if $@;
+
+    my $row_from_db = $schema->resultset('ArtistGUID')
+      ->search({ name => 'mtfnpy' })->first;
+
+    is $row_from_db->artistid, $row->artistid,
+      'PK GUID round trip';
+
+    is $row_from_db->a_guid, $row->a_guid,
+      'NON-PK GUID round trip';
+  }
 }
 
 done_testing;
 
-# clean up our mess
-END {
-  foreach my $dbh (@handles_to_clean) {
-    eval { $dbh->do("DROP TABLE $_") } for qw/artist bindtype_test/;
-  }
+sub cleanup {
+  eval { $schema->storage->dbh->do("DROP TABLE $_") } for qw/artist bindtype_test/;
 }

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/74mssql.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/74mssql.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/74mssql.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -52,14 +52,15 @@
 
   isa_ok($schema->storage, "DBIx::Class::Storage::$storage_type");
 
-# start disconnected to test reconnection
+# start disconnected to test _ping
   $schema->storage->_dbh->disconnect;
 
-  my $dbh;
-  lives_ok (sub {
-    $dbh = $schema->storage->dbh;
-  }, 'reconnect works');
+  lives_ok {
+    $schema->storage->dbh_do(sub { $_[1]->do('select 1') })
+  } '_ping works';
 
+  my $dbh = $schema->storage->dbh;
+
   $dbh->do("IF OBJECT_ID('artist', 'U') IS NOT NULL
       DROP TABLE artist");
   $dbh->do("IF OBJECT_ID('cd', 'U') IS NOT NULL

Added: DBIx-Class/0.08/branches/group_by_consistency/t/750firebird.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/750firebird.t	                        (rev 0)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/750firebird.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -0,0 +1,274 @@
+use strict;
+use warnings;
+
+use Test::More;
+use Test::Exception;
+use lib qw(t/lib);
+use DBICTest;
+use Scope::Guard ();
+
+# tests stolen from 749sybase_asa.t
+
+my ($dsn, $user, $pass)    = @ENV{map { "DBICTEST_FIREBIRD_${_}" }      qw/DSN USER PASS/};
+my ($dsn2, $user2, $pass2) = @ENV{map { "DBICTEST_FIREBIRD_ODBC_${_}" } qw/DSN USER PASS/};
+
+plan skip_all => <<'EOF' unless $dsn || $dsn2;
+Set $ENV{DBICTEST_FIREBIRD_DSN} and/or $ENV{DBICTEST_FIREBIRD_ODBC_DSN},
+_USER and _PASS to run these tests.
+
+WARNING: this test creates and drops the tables "artist", "bindtype_test" and
+"sequence_test"; the generators "gen_artist_artistid", "pkid1_seq", "pkid2_seq"
+and "nonpkid_seq" and the trigger "artist_bi".
+EOF
+
+my @info = (
+  [ $dsn,  $user,  $pass  ],
+  [ $dsn2, $user2, $pass2 ],
+);
+
+my $schema;
+
+foreach my $conn_idx (0..$#info) {
+  my ($dsn, $user, $pass) = @{ $info[$conn_idx] || [] };
+
+  next unless $dsn;
+
+  $schema = DBICTest::Schema->connect($dsn, $user, $pass, {
+    auto_savepoint  => 1,
+    quote_char      => q["],
+    name_sep        => q[.],
+    on_connect_call => 'use_softcommit',
+  });
+  my $dbh = $schema->storage->dbh;
+
+  my $sg = Scope::Guard->new(\&cleanup);
+
+  eval { $dbh->do(q[DROP TABLE "artist"]) };
+  $dbh->do(<<EOF);
+  CREATE TABLE "artist" (
+    "artistid" INT PRIMARY KEY,
+    "name" VARCHAR(255),
+    "charfield" CHAR(10),
+    "rank" INT DEFAULT 13
+  )
+EOF
+  eval { $dbh->do(q[DROP GENERATOR "gen_artist_artistid"]) };
+  $dbh->do('CREATE GENERATOR "gen_artist_artistid"');
+  eval { $dbh->do('DROP TRIGGER "artist_bi"') };
+  $dbh->do(<<EOF);
+  CREATE TRIGGER "artist_bi" FOR "artist"
+  ACTIVE BEFORE INSERT POSITION 0
+  AS
+  BEGIN
+   IF (NEW."artistid" IS NULL) THEN
+    NEW."artistid" = GEN_ID("gen_artist_artistid",1);
+  END
+EOF
+  eval { $dbh->do('DROP TABLE "sequence_test"') };
+  $dbh->do(<<EOF);
+  CREATE TABLE "sequence_test" (
+    "pkid1" INT NOT NULL,
+    "pkid2" INT NOT NULL,
+    "nonpkid" INT,
+    "name" VARCHAR(255)
+  )
+EOF
+  $dbh->do('ALTER TABLE "sequence_test" ADD CONSTRAINT "sequence_test_constraint" PRIMARY KEY ("pkid1", "pkid2")');
+  eval { $dbh->do('DROP GENERATOR "pkid1_seq"') };
+  eval { $dbh->do('DROP GENERATOR "pkid2_seq"') };
+  eval { $dbh->do('DROP GENERATOR "nonpkid_seq"') };
+  $dbh->do('CREATE GENERATOR "pkid1_seq"');
+  $dbh->do('CREATE GENERATOR "pkid2_seq"');
+  $dbh->do('SET GENERATOR "pkid2_seq" TO 9');
+  $dbh->do('CREATE GENERATOR "nonpkid_seq"');
+  $dbh->do('SET GENERATOR "nonpkid_seq" TO 19');
+
+  my $ars = $schema->resultset('Artist');
+  is ( $ars->count, 0, 'No rows at first' );
+
+# test primary key handling
+  my $new = $ars->create({ name => 'foo' });
+  ok($new->artistid, "Auto-PK worked");
+
+# test auto increment using generators WITHOUT triggers
+  for (1..5) {
+      my $st = $schema->resultset('SequenceTest')->create({ name => 'foo' });
+      is($st->pkid1, $_, "Firebird Auto-PK without trigger: First primary key");
+      is($st->pkid2, $_ + 9, "Firebird Auto-PK without trigger: Second primary key");
+      is($st->nonpkid, $_ + 19, "Firebird Auto-PK without trigger: Non-primary key");
+  }
+  my $st = $schema->resultset('SequenceTest')->create({ name => 'foo', pkid1 => 55 });
+  is($st->pkid1, 55, "Firebird Auto-PK without trigger: First primary key set manually");
+
+# test savepoints
+  throws_ok {
+    $schema->txn_do(sub {
+      eval {
+        $schema->txn_do(sub {
+          $ars->create({ name => 'in_savepoint' });
+          die "rolling back savepoint";
+        });
+      };
+      ok ((not $ars->search({ name => 'in_savepoint' })->first),
+        'savepoint rolled back');
+      $ars->create({ name => 'in_outer_txn' });
+      die "rolling back outer txn";
+    });
+  } qr/rolling back outer txn/,
+    'correct exception for rollback';
+
+  ok ((not $ars->search({ name => 'in_outer_txn' })->first),
+    'outer txn rolled back');
+
+# test explicit key spec
+  $new = $ars->create ({ name => 'bar', artistid => 66 });
+  is($new->artistid, 66, 'Explicit PK worked');
+  $new->discard_changes;
+  is($new->artistid, 66, 'Explicit PK assigned');
+
+# row update
+  lives_ok {
+    $new->update({ name => 'baz' })
+  } 'update survived';
+  $new->discard_changes;
+  is $new->name, 'baz', 'row updated';
+
+# test populate
+  lives_ok (sub {
+    my @pop;
+    for (1..2) {
+      push @pop, { name => "Artist_$_" };
+    }
+    $ars->populate (\@pop);
+  });
+
+# test populate with explicit key
+  lives_ok (sub {
+    my @pop;
+    for (1..2) {
+      push @pop, { name => "Artist_expkey_$_", artistid => 100 + $_ };
+    }
+    $ars->populate (\@pop);
+  });
+
+# count what we did so far
+  is ($ars->count, 6, 'Simple count works');
+
+# test ResultSet UPDATE
+  lives_and {
+    $ars->search({ name => 'foo' })->update({ rank => 4 });
+
+    is eval { $ars->search({ name => 'foo' })->first->rank }, 4;
+  } 'Can update a column';
+
+  my ($updated) = $schema->resultset('Artist')->search({name => 'foo'});
+  is eval { $updated->rank }, 4, 'and the update made it to the database';
+
+
+# test LIMIT support
+  my $lim = $ars->search( {},
+    {
+      rows => 3,
+      offset => 4,
+      order_by => 'artistid'
+    }
+  );
+  is( $lim->count, 2, 'ROWS+OFFSET count ok' );
+  is( $lim->all, 2, 'Number of ->all objects matches count' );
+
+# test iterator
+  $lim->reset;
+  is( eval { $lim->next->artistid }, 101, "iterator->next ok" );
+  is( eval { $lim->next->artistid }, 102, "iterator->next ok" );
+  is( $lim->next, undef, "next past end of resultset ok" );
+
+# test nested cursors
+  {
+    my $rs1 = $ars->search({}, { order_by => { -asc  => 'artistid' }});
+
+    my $rs2 = $ars->search({ artistid => $rs1->next->artistid }, {
+      order_by => { -desc => 'artistid' }
+    });
+
+    is $rs2->next->artistid, 1, 'nested cursors';
+  }
+
+# test empty insert
+  lives_and {
+    my $row = $ars->create({});
+    ok $row->artistid;
+  } 'empty insert works';
+
+# test inferring the generator from the trigger source and using it with
+# auto_nextval
+  {
+    local $ars->result_source->column_info('artistid')->{auto_nextval} = 1;
+
+    lives_and {
+      my $row = $ars->create({ name => 'introspecting generator' });
+      ok $row->artistid;
+    } 'inferring generator from trigger source works';
+  }
+
+# test blobs (stolen from 73oracle.t)
+  eval { $dbh->do('DROP TABLE "bindtype_test"') };
+  $dbh->do(q[
+  CREATE TABLE "bindtype_test"
+  (
+    "id"     INT PRIMARY KEY,
+    "bytea"  INT,
+    "blob"   BLOB,
+    "clob"   BLOB SUB_TYPE TEXT
+  )
+  ]);
+
+  my %binstr = ( 'small' => join('', map { chr($_) } ( 1 .. 127 )) );
+  $binstr{'large'} = $binstr{'small'} x 1024;
+
+  my $maxloblen = length $binstr{'large'};
+  local $dbh->{'LongReadLen'} = $maxloblen;
+
+  my $rs = $schema->resultset('BindType');
+  my $id = 0;
+
+  foreach my $type (qw( blob clob )) {
+    foreach my $size (qw( small large )) {
+      $id++;
+
+# turn off horrendous binary DBIC_TRACE output
+      local $schema->storage->{debug} = 0;
+
+      lives_ok { $rs->create( { 'id' => $id, $type => $binstr{$size} } ) }
+      "inserted $size $type without dying";
+
+      ok($rs->find($id)->$type eq $binstr{$size}, "verified inserted $size $type" );
+    }
+  }
+}
+
+done_testing;
+
+# clean up our mess
+
+sub cleanup {
+  my $dbh;
+  eval {
+    $schema->storage->disconnect; # to avoid object FOO is in use errors
+    $dbh = $schema->storage->dbh;
+  };
+  return unless $dbh;
+
+  eval { $dbh->do('DROP TRIGGER "artist_bi"') };
+  diag $@ if $@;
+
+  foreach my $generator (qw/gen_artist_artistid pkid1_seq pkid2_seq
+                            nonpkid_seq/) {
+    eval { $dbh->do(qq{DROP GENERATOR "$generator"}) };
+    diag $@ if $@;
+  }
+
+  foreach my $table (qw/artist bindtype_test sequence_test/) {
+    eval { $dbh->do(qq[DROP TABLE "$table"]) };
+    diag $@ if $@;
+  }
+}

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/75limit.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/75limit.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/75limit.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -7,11 +7,6 @@
 
 my $schema = DBICTest->init_schema();
 
-BEGIN {
-    eval "use DBD::SQLite";
-    plan $@ ? (skip_all => 'needs DBD::SQLite for testing') : (tests => 10);
-}
-
 # test LIMIT
 my $it = $schema->resultset("CD")->search( {},
     { rows => 3,
@@ -77,3 +72,4 @@
 );
 is( $it->count, 1, "complex abstract count ok" );
 
+done_testing;

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/76joins.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/76joins.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/76joins.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -10,13 +10,6 @@
 
 my $orig_debug = $schema->storage->debug;
 
-BEGIN {
-    eval "use DBD::SQLite";
-    plan $@
-        ? ( skip_all => 'needs DBD::SQLite for testing' )
-        : ( tests => 33 );
-}
-
 # test the abstract join => SQL generator
 my $sa = new DBIx::Class::SQLAHacks;
 
@@ -240,3 +233,5 @@
     is(cd_count(), 5, '5 rows in table cd');
     is(tk_count(), 3, '3 rows in table twokeys');
 }
+
+done_testing;

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/76select.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/76select.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/76select.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -157,10 +157,9 @@
   $sub_rs->single,
   {
     artist         => 1,
-    track_position => 2,
-    tracks         => {
+    tracks => {
+      title => 'Apiary',
       trackid => 17,
-      title   => 'Apiary',
     },
   },
   'columns/select/as fold properly on sub-searches',

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/81transactions.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/81transactions.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/81transactions.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -150,10 +150,9 @@
   no warnings 'redefine';
   no strict 'refs';
 
-  # die in rollback, but maintain sanity for further tests ...
+  # die in rollback
   local *{"DBIx::Class::Storage::DBI::SQLite::txn_rollback"} = sub{
     my $storage = shift;
-    $storage->{transaction_depth}--;
     die 'FAILED';
   };
 
@@ -180,6 +179,9 @@
   $schema->storage->_dbh->rollback;
 }
 
+# reset schema object (the txn_rollback meddling screws it up)
+$schema = DBICTest->init_schema();
+
 # Test nested failed txn_do()
 {
   is( $schema->storage->{transaction_depth}, 0, 'txn depth starts at 0');

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/85utf8.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/85utf8.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/85utf8.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -5,54 +5,167 @@
 use Test::Warn;
 use lib qw(t/lib);
 use DBICTest;
-use utf8;
 
-warning_like (
+{
+  package A::Comp;
+  use base 'DBIx::Class';
+  sub store_column { shift->next::method (@_) };
+  1;
+}
+
+{
+  package A::SubComp;
+  use base 'A::Comp';
+
+  1;
+}
+
+warnings_are (
   sub {
-    package A::Comp;
-    use base 'DBIx::Class';
+    local $ENV{DBIC_UTF8COLUMNS_OK} = 1;
+    package A::Test1;
+    use base 'DBIx::Class::Core';
+    __PACKAGE__->load_components(qw(Core +A::Comp Ordered UTF8Columns));
+    __PACKAGE__->load_components(qw(Ordered +A::SubComp Row UTF8Columns Core));
     sub store_column { shift->next::method (@_) };
     1;
+  },
+  [],
+  'no spurious warnings issued',
+);
 
-    package A::Test;
+my $test1_mro;
+my $idx = 0;
+for (@{mro::get_linear_isa ('A::Test1')} ) {
+  $test1_mro->{$_} = $idx++;
+}
+
+cmp_ok ($test1_mro->{'A::SubComp'}, '<', $test1_mro->{'A::Comp'}, 'mro of Test1 correct (A::SubComp before A::Comp)' );
+cmp_ok ($test1_mro->{'A::Comp'}, '<', $test1_mro->{'DBIx::Class::UTF8Columns'}, 'mro of Test1 correct (A::Comp before UTF8Col)' );
+cmp_ok ($test1_mro->{'DBIx::Class::UTF8Columns'}, '<', $test1_mro->{'DBIx::Class::Core'}, 'mro of Test1 correct (UTF8Col before Core)' );
+cmp_ok ($test1_mro->{'DBIx::Class::Core'}, '<', $test1_mro->{'DBIx::Class::Row'}, 'mro of Test1 correct (Core before Row)' );
+
+warnings_like (
+  sub {
+    package A::Test2;
     use base 'DBIx::Class::Core';
     __PACKAGE__->load_components(qw(UTF8Columns +A::Comp));
+    sub store_column { shift->next::method (@_) };
     1;
   },
-  qr/Incorrect loading order of DBIx::Class::UTF8Columns.+affect other components overriding store_column \(A::Comp\)/,
-  'incorrect order warning issued',
+  [qr/Incorrect loading order of DBIx::Class::UTF8Columns.+affect other components overriding 'store_column' \(A::Comp\)/],
+  'incorrect order warning issued (violator defines)',
 );
 
+warnings_like (
+  sub {
+    package A::Test3;
+    use base 'DBIx::Class::Core';
+    __PACKAGE__->load_components(qw(UTF8Columns +A::SubComp));
+    sub store_column { shift->next::method (@_) };
+    1;
+  },
+  [qr/Incorrect loading order of DBIx::Class::UTF8Columns.+affect other components overriding 'store_column' \(A::SubComp \(via A::Comp\)\)/],
+  'incorrect order warning issued (violator inherits)',
+);
+
 my $schema = DBICTest->init_schema();
 DBICTest::Schema::CD->load_components('UTF8Columns');
 DBICTest::Schema::CD->utf8_columns('title');
 Class::C3->reinitialize();
 
-my $cd = $schema->resultset('CD')->create( { artist => 1, title => 'øni', year => '2048' } );
-my $utf8_char = 'uniuni';
+{
+  package DBICTest::UTF8::Debugger;
 
+  use base 'DBIx::Class::Storage::Statistics';
 
-ok( utf8::is_utf8( $cd->title ), 'got title with utf8 flag' );
-ok(! utf8::is_utf8( $cd->year ), 'got year without utf8 flag' );
+  __PACKAGE__->mk_group_accessors(simple => 'call_stack');
 
-utf8::decode($utf8_char);
-$cd->title($utf8_char);
-ok(! utf8::is_utf8( $cd->{_column_data}{title} ), 'store utf8-less chars' );
+  sub query_start {
+    my $self = shift;
+    my $sql = shift;
 
+    my @bind = map { substr $_, 1, -1 } (@_); # undo the effect of _fix_bind_params
 
-my $v_utf8 = "\x{219}";
+    $self->call_stack ( [ @{$self->call_stack || [] }, [$sql, @bind] ] );
+    $self->next::method ($sql, @_);
+  }
+}
 
-$cd->update ({ title => $v_utf8 });
-$cd->title($v_utf8);
+# as per http://search.cpan.org/dist/Test-Simple/lib/Test/More.pm#utf8
+binmode (Test::More->builder->$_, ':utf8') for qw/output failure_output todo_output/;
+
+my $bytestream_title = my $utf8_title = "weird \x{466} stuff";
+utf8::encode($bytestream_title);
+cmp_ok ($bytestream_title, 'ne', $utf8_title, 'unicode/raw differ (sanity check)');
+
+my $storage = $schema->storage;
+$storage->debugobj (DBICTest::UTF8::Debugger->new);
+$storage->debugobj->silence (1);
+$storage->debug (1);
+
+my $cd = $schema->resultset('CD')->create( { artist => 1, title => $utf8_title, year => '2048' } );
+
+# bind values are always alphabetically ordered by column, thus [2]
+TODO: {
+  local $TODO = "This has been broken since rev 1191, Mar 2006";
+  is ($storage->debugobj->call_stack->[-1][2], $bytestream_title, 'INSERT: raw bytes sent to the database');
+}
+
+# this should be using the cursor directly, no inflation/processing of any sort
+my ($raw_db_title) = $schema->resultset('CD')
+                             ->search ($cd->ident_condition)
+                               ->get_column('title')
+                                ->_resultset
+                                 ->cursor
+                                  ->next;
+
+is ($raw_db_title, $bytestream_title, 'INSERT: raw bytes retrieved from database');
+
+for my $reloaded (0, 1) {
+  my $test = $reloaded ? 'reloaded' : 'stored';
+  $cd->discard_changes if $reloaded;
+
+  ok( utf8::is_utf8( $cd->title ), "got $test title with utf8 flag" );
+  ok(! utf8::is_utf8( $cd->{_column_data}{title} ), "in-object $test title without utf8" );
+
+  ok(! utf8::is_utf8( $cd->year ), "got $test year without utf8 flag" );
+  ok(! utf8::is_utf8( $cd->{_column_data}{year} ), "in-object $test year without utf8" );
+}
+
+$cd->title('nonunicode');
+ok(! utf8::is_utf8( $cd->title ), 'update title without utf8 flag' );
+ok(! utf8::is_utf8( $cd->{_column_data}{title} ), 'store utf8-less title' );
+
+$cd->update;
+$cd->discard_changes;
+ok(! utf8::is_utf8( $cd->title ), 'reloaded title without utf8 flag' );
+ok(! utf8::is_utf8( $cd->{_column_data}{title} ), 'reloaded utf8-less title' );
+
+$bytestream_title = $utf8_title = "something \x{219} else";
+utf8::encode($bytestream_title);
+
+$cd->update ({ title => $utf8_title });
+is ($storage->debugobj->call_stack->[-1][1], $bytestream_title, 'UPDATE: raw bytes sent to the database');
+($raw_db_title) = $schema->resultset('CD')
+                             ->search ($cd->ident_condition)
+                               ->get_column('title')
+                                ->_resultset
+                                 ->cursor
+                                  ->next;
+is ($raw_db_title, $bytestream_title, 'UPDATE: raw bytes retrieved from database');
+
+$cd->discard_changes;
+$cd->title($utf8_title);
 ok( !$cd->is_column_changed('title'), 'column is not dirty after setting the same unicode value' );
 
-$cd->update ({ title => $v_utf8 });
+$cd->update ({ title => $utf8_title });
 $cd->title('something_else');
 ok( $cd->is_column_changed('title'), 'column is dirty after setting to something completely different');
 
 TODO: {
   local $TODO = 'There is currently no way to propagate aliases to inflate_result()';
-  $cd = $schema->resultset('CD')->find ({ title => $v_utf8 }, { select => 'title', as => 'name' });
+  $cd = $schema->resultset('CD')->find ({ title => $utf8_title }, { select => 'title', as => 'name' });
   ok (utf8::is_utf8( $cd->get_column ('name') ), 'utf8 flag propagates via as');
 }
 

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/86sqlt.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/86sqlt.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/86sqlt.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -6,12 +6,20 @@
 use DBICTest;
 
 BEGIN {
-  require DBIx::Class::Storage::DBI;
+  require DBIx::Class;
   plan skip_all =>
-      'Test needs SQL::Translator ' . DBIx::Class::Storage::DBI->_sqlt_minimum_version
-    if not DBIx::Class::Storage::DBI->_sqlt_version_ok;
+      'Test needs ' . DBIx::Class::Optional::Dependencies->req_missing_for ('deploy')
+    unless DBIx::Class::Optional::Dependencies->req_ok_for ('deploy')
 }
 
+my $custom_deployment_statements_called = 0;
+
+sub DBICTest::Schema::deployment_statements {
+  $custom_deployment_statements_called = 1;
+  my $self = shift;
+  return $self->next::method(@_);
+}
+
 my $schema = DBICTest->init_schema (no_deploy => 1);
 
 
@@ -44,28 +52,35 @@
 
 
 
-# replace the sqlt calback with a custom version ading an index
-$schema->source('Track')->sqlt_deploy_callback(sub {
-  my ($self, $sqlt_table) = @_;
+{
+  my $deploy_hook_called = 0;
 
-  is (
-    $sqlt_table->schema->translator->producer_type,
-    join ('::', 'SQL::Translator::Producer', $schema->storage->sqlt_type),
-    'Production type passed to translator object',
-  );
+  # replace the sqlt calback with a custom version ading an index
+  $schema->source('Track')->sqlt_deploy_callback(sub {
+    my ($self, $sqlt_table) = @_;
 
-  if ($schema->storage->sqlt_type eq 'SQLite' ) {
-    $sqlt_table->add_index( name => 'track_title', fields => ['title'] )
-      or die $sqlt_table->error;
-  }
+    $deploy_hook_called = 1;
 
-  $self->default_sqlt_deploy_hook($sqlt_table);
-});
+    is (
+      $sqlt_table->schema->translator->producer_type,
+      join ('::', 'SQL::Translator::Producer', $schema->storage->sqlt_type),
+      'Production type passed to translator object',
+    );
 
-$schema->deploy; # do not remove, this fires the is() test in the callback above
+    if ($schema->storage->sqlt_type eq 'SQLite' ) {
+      $sqlt_table->add_index( name => 'track_title', fields => ['title'] )
+        or die $sqlt_table->error;
+    }
 
+    $self->default_sqlt_deploy_hook($sqlt_table);
+  });
 
+  $schema->deploy; # do not remove, this fires the is() test in the callback above
+  ok($deploy_hook_called, 'deploy hook got called');
+  ok($custom_deployment_statements_called, '->deploy used the schemas deploy_statements method');
+}
 
+
 my $translator = SQL::Translator->new( 
   parser_args => {
     'DBIx::Schema' => $schema,

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/87ordered.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/87ordered.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/87ordered.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -64,36 +64,36 @@
 $employee->group_id(1);
 $employee->update;
 ok(
-	check_rs($employees->search_rs({group_id=>1})) && check_rs($employees->search_rs({group_id=>4})),
-	"overloaded update 3"
+  check_rs($employees->search_rs({group_id=>1})) && check_rs($employees->search_rs({group_id=>4})),
+  "overloaded update 3"
 );
 $employee = $employees->search({group_id=>4})->first;
 $employee->update({group_id=>2});
 ok(
-	check_rs($employees->search_rs({group_id=>2})) && check_rs($employees->search_rs({group_id=>4})),
-	"overloaded update 4"
+  check_rs($employees->search_rs({group_id=>2})) && check_rs($employees->search_rs({group_id=>4})),
+  "overloaded update 4"
 );
 $employee = $employees->search({group_id=>4})->first;
 $employee->group_id(1);
 $employee->position(3);
 $employee->update;
 ok(
-	check_rs($employees->search_rs({group_id=>1})) && check_rs($employees->search_rs({group_id=>4})),
-	"overloaded update 5"
+  check_rs($employees->search_rs({group_id=>1})) && check_rs($employees->search_rs({group_id=>4})),
+  "overloaded update 5"
 );
 $employee = $employees->search({group_id=>4})->first;
 $employee->group_id(2);
 $employee->position(undef);
 $employee->update;
 ok(
-	check_rs($employees->search_rs({group_id=>2})) && check_rs($employees->search_rs({group_id=>4})),
-	"overloaded update 6"
+  check_rs($employees->search_rs({group_id=>2})) && check_rs($employees->search_rs({group_id=>4})),
+  "overloaded update 6"
 );
 $employee = $employees->search({group_id=>4})->first;
 $employee->update({group_id=>1,position=>undef});
 ok(
-	check_rs($employees->search_rs({group_id=>1})) && check_rs($employees->search_rs({group_id=>4})),
-	"overloaded update 7"
+  check_rs($employees->search_rs({group_id=>1})) && check_rs($employees->search_rs({group_id=>4})),
+  "overloaded update 7"
 );
 
 # multicol tests begin here
@@ -154,7 +154,7 @@
 $employee = $employees->search({group_id_2=>4, group_id_3=>1})->first;
 $employee->group_id_2(1);
 $employee->update;
-ok( 
+ok(
     check_rs($employees->search_rs({group_id_2=>4, group_id_3=>1}))
     && check_rs($employees->search_rs({group_id_2=>1, group_id_3=>1})), 
     "overloaded multicol update 1" 

Deleted: DBIx-Class/0.08/branches/group_by_consistency/t/89dbicadmin.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/89dbicadmin.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/89dbicadmin.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -1,89 +0,0 @@
-# vim: filetype=perl
-use strict;
-use warnings;  
-
-use Test::More;
-use lib qw(t/lib);
-use DBICTest;
-
-
-eval 'require JSON::Any';
-plan skip_all => 'Install JSON::Any to run this test' if ($@);
-
-eval 'require Text::CSV_XS';
-if ($@) {
-    eval 'require Text::CSV_PP';
-    plan skip_all => 'Install Text::CSV_XS or Text::CSV_PP to run this test' if ($@);
-}
-
-my @json_backends = qw/XS JSON DWIW/;
-my $tests_per_run = 5;
-
-plan tests => $tests_per_run * @json_backends;
-
-for my $js (@json_backends) {
-
-    eval {JSON::Any->import ($js) };
-    SKIP: {
-        skip ("Json backend $js is not available, skip testing", $tests_per_run) if $@;
-
-        $ENV{JSON_ANY_ORDER} = $js;
-        eval { test_dbicadmin () };
-        diag $@ if $@;
-    }
-}
-
-sub test_dbicadmin {
-    my $schema = DBICTest->init_schema( sqlite_use_file => 1 );  # reinit a fresh db for every run
-
-    my $employees = $schema->resultset('Employee');
-
-    system( _prepare_system_args( qw|--op=insert --set={"name":"Matt"}| ) );
-    ok( ($employees->count()==1), "$ENV{JSON_ANY_ORDER}: insert count" );
-
-    my $employee = $employees->find(1);
-    ok( ($employee->name() eq 'Matt'), "$ENV{JSON_ANY_ORDER}: insert valid" );
-
-    system( _prepare_system_args( qw|--op=update --set={"name":"Trout"}| ) );
-    $employee = $employees->find(1);
-    ok( ($employee->name() eq 'Trout'), "$ENV{JSON_ANY_ORDER}: update" );
-
-    system( _prepare_system_args( qw|--op=insert --set={"name":"Aran"}| ) );
-
-    SKIP: {
-        skip ("MSWin32 doesn't support -| either", 1) if $^O eq 'MSWin32';
-
-        open(my $fh, "-|",  _prepare_system_args( qw|--op=select --attrs={"order_by":"name"}| ) ) or die $!;
-        my $data = do { local $/; <$fh> };
-        close($fh);
-        ok( ($data=~/Aran.*Trout/s), "$ENV{JSON_ANY_ORDER}: select with attrs" );
-    }
-
-    system( _prepare_system_args( qw|--op=delete --where={"name":"Trout"}| ) );
-    ok( ($employees->count()==1), "$ENV{JSON_ANY_ORDER}: delete" );
-}
-
-# Why do we need this crap? Apparently MSWin32 can not pass through quotes properly
-# (sometimes it will and sometimes not, depending on what compiler was used to build
-# perl). So we go the extra mile to escape all the quotes. We can't also use ' instead
-# of ", because JSON::XS (proudly) does not support "malformed JSON" as the author
-# calls it. Bleh.
-#
-sub _prepare_system_args {
-    my $perl = $^X;
-    my @args = (
-        qw|script/dbicadmin --quiet --schema=DBICTest::Schema --class=Employee --tlibs|,
-        q|--connect=["dbi:SQLite:dbname=t/var/DBIxClass.db","","",{"AutoCommit":1}]|,
-        qw|--force --tlibs|,
-        @_,
-    );
-
-    if ( $^O eq 'MSWin32' ) {
-        $perl = qq|"$perl"|;    # execution will fail if $^X contains paths
-        for (@args) {
-            $_ =~ s/"/\\"/g;
-        }
-    }
-
-    return ($perl, @args);
-}

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/90join_torture.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/90join_torture.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/90join_torture.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -1,13 +1,13 @@
 use strict;
-use warnings;  
+use warnings;
 
 use Test::More;
+use Test::Exception;
 use lib qw(t/lib);
 use DBICTest;
+use DBIC::SqlMakerTest;
 my $schema = DBICTest->init_schema();
 
-plan tests => 22;
-
  {
    my $rs = $schema->resultset( 'CD' )->search(
      {
@@ -25,11 +25,10 @@
        ],
      }
    );
-  
-   eval {
+
+   lives_ok {
      my @rows = $rs->all();
    };
-   is( $@, '' );
  }
 
 
@@ -106,7 +105,7 @@
 is(scalar(@{$merge_rs_2->{attrs}->{join}}), 1, 'only one join kept when inherited');
 my $merge_rs_2_cd = $merge_rs_2->next;
 
-eval {
+lives_ok (sub {
 
   my @rs_with_prefetch = $schema->resultset('TreeLike')
                                 ->search(
@@ -115,14 +114,44 @@
     prefetch => [ 'parent', { 'children' => 'parent' } ],
     });
 
-};
+}, 'pathological prefetch ok');
 
-ok(!$@, "pathological prefetch ok");
-
 my $rs = $schema->resultset("Artist")->search({}, { join => 'twokeys' });
 my $second_search_rs = $rs->search({ 'cds_2.cdid' => '2' }, { join =>
 ['cds', 'cds'] });
 is(scalar(@{$second_search_rs->{attrs}->{join}}), 3, 'both joins kept');
 ok($second_search_rs->next, 'query on double joined rel runs okay');
 
-1;
+# test joinmap pruner
+lives_ok ( sub {
+  my $rs = $schema->resultset('Artwork')->search (
+    {
+    },
+    {
+      distinct => 1,
+      join => [
+        { artwork_to_artist => 'artist' },
+        { cd => 'artist' },
+      ],
+    },
+  );
+
+  is_same_sql_bind (
+    $rs->count_rs->as_query,
+    '(
+      SELECT COUNT( * )
+        FROM (
+          SELECT me.cd_id
+            FROM cd_artwork me
+            JOIN cd cd ON cd.cdid = me.cd_id
+            JOIN artist artist_2 ON artist_2.artistid = cd.artist
+          GROUP BY me.cd_id
+        ) me
+    )',
+    [],
+  );
+
+  ok (defined $rs->count);
+});
+
+done_testing;

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/93single_accessor_object.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/93single_accessor_object.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/93single_accessor_object.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -45,20 +45,20 @@
 $schema = DBICTest->init_schema();
 
 {
-	my $artist = $schema->resultset('Artist')->create({ artistid => 666, name => 'bad religion' });
-	my $cd = $schema->resultset('CD')->create({ cdid => 187, artist => 1, title => 'how could hell be any worse?', year => 1982, genreid => undef });
+  my $artist = $schema->resultset('Artist')->create({ artistid => 666, name => 'bad religion' });
+  my $cd = $schema->resultset('CD')->create({ cdid => 187, artist => 1, title => 'how could hell be any worse?', year => 1982, genreid => undef });
 
-	ok(!defined($cd->get_column('genreid')), 'genreid is NULL');  #no accessor was defined for this column
-	ok(!defined($cd->genre), 'genre accessor returns undef');
+  ok(!defined($cd->get_column('genreid')), 'genreid is NULL');  #no accessor was defined for this column
+  ok(!defined($cd->genre), 'genre accessor returns undef');
 }
 
 $schema = DBICTest->init_schema();
 
 {
-	my $artist = $schema->resultset('Artist')->create({ artistid => 666, name => 'bad religion' });
-	my $genre = $schema->resultset('Genre')->create({ genreid => 88, name => 'disco' });
-	my $cd = $schema->resultset('CD')->create({ cdid => 187, artist => 1, title => 'how could hell be any worse?', year => 1982 });
+  my $artist = $schema->resultset('Artist')->create({ artistid => 666, name => 'bad religion' });
+  my $genre = $schema->resultset('Genre')->create({ genreid => 88, name => 'disco' });
+  my $cd = $schema->resultset('CD')->create({ cdid => 187, artist => 1, title => 'how could hell be any worse?', year => 1982 });
 
-	dies_ok { $cd->genre } 'genre accessor throws without column';
+  dies_ok { $cd->genre } 'genre accessor throws without column';
 }
 

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/94versioning.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/94versioning.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/94versioning.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -22,10 +22,10 @@
     || plan skip_all => 'Test needs Time::HiRes';
   Time::HiRes->import(qw/time sleep/);
 
-  require DBIx::Class::Storage::DBI;
+  require DBIx::Class;
   plan skip_all =>
-      'Test needs SQL::Translator ' . DBIx::Class::Storage::DBI->_sqlt_minimum_version
-    if not DBIx::Class::Storage::DBI->_sqlt_version_ok;
+      'Test needs ' . DBIx::Class::Optional::Dependencies->req_missing_for ('deploy')
+    unless DBIx::Class::Optional::Dependencies->req_ok_for ('deploy')
 }
 
 use lib qw(t/lib);
@@ -165,6 +165,37 @@
   is($schema_v3->get_db_version(), '3.0', 'db version number upgraded');
 }
 
+# Now, try a v1 -> v3 upgrade with a file that has comments strategically placed in it.
+# First put the v1 schema back again...
+{
+  # drop all the tables...
+  eval { $schema_v1->storage->dbh->do('drop table ' . $version_table_name) };
+  eval { $schema_v1->storage->dbh->do('drop table ' . $old_table_name) };
+  eval { $schema_v1->storage->dbh->do('drop table TestVersion') };
+
+  {
+    local $DBICVersion::Schema::VERSION = '1.0';
+    $schema_v1->deploy;
+  }
+  is($schema_v1->get_db_version(), '1.0', 'get_db_version 1.0 ok');
+}
+
+# add a "harmless" comment before one of the statements.
+system( qq($^X -pi -e "s/ALTER/-- this is a comment\nALTER/" $fn->{trans_v23};) );
+
+# Then attempt v1 -> v3 upgrade
+{
+  local $SIG{__WARN__} = sub { warn if $_[0] !~ /Attempting upgrade\.$/ };
+  $schema_v3->upgrade();
+  is($schema_v3->get_db_version(), '3.0', 'db version number upgraded to 3.0');
+
+  # make sure that the column added after the comment is actually added.
+  lives_ok ( sub {
+    $schema_v3->storage->dbh->do('select ExtraColumn from TestVersion');
+  }, 'new column created');
+}
+
+
 # check behaviour of DBIC_NO_VERSION_CHECK env var and ignore_version connect attr
 {
   my $schema_version = DBICVersion::Schema->connect($dsn, $user, $pass);

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/99dbic_sqlt_parser.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/99dbic_sqlt_parser.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/99dbic_sqlt_parser.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -9,22 +9,27 @@
 use Scalar::Util ();
 
 BEGIN {
-  require DBIx::Class::Storage::DBI;
+  require DBIx::Class;
   plan skip_all =>
-      'Test needs SQL::Translator ' . DBIx::Class::Storage::DBI->_sqlt_minimum_version
-    if not DBIx::Class::Storage::DBI->_sqlt_version_ok;
+      'Test needs ' . DBIx::Class::Optional::Dependencies->req_missing_for ('deploy')
+    unless DBIx::Class::Optional::Dependencies->req_ok_for ('deploy')
 }
 
 # Test for SQLT-related leaks
 {
   my $s = DBICTest::Schema->clone;
-  create_schema ({ schema => $s });
+  my $sqlt_schema = create_schema ({ schema => $s });
   Scalar::Util::weaken ($s);
 
   ok (!$s, 'Schema not leaked');
+
+  isa_ok ($sqlt_schema, 'SQL::Translator::Schema', 'SQLT schema object produced');
 }
 
+# make sure classname-style works
+lives_ok { isa_ok (create_schema ({ schema => 'DBICTest::Schema' }), 'SQL::Translator::Schema', 'SQLT schema object produced') };
 
+
 my $schema = DBICTest->init_schema();
 # Dummy was yanked out by the sqlt hook test
 # CustomSql tests the horrific/deprecated ->name(\$sql) hack

Added: DBIx-Class/0.08/branches/group_by_consistency/t/admin/01load.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/admin/01load.t	                        (rev 0)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/admin/01load.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -0,0 +1,15 @@
+use strict;
+use warnings;
+
+use Test::More;
+
+BEGIN {
+    require DBIx::Class;
+    plan skip_all => 'Test needs ' . DBIx::Class::Optional::Dependencies->req_missing_for('admin')
+      unless DBIx::Class::Optional::Dependencies->req_ok_for('admin');
+}
+
+use_ok 'DBIx::Class::Admin';
+
+
+done_testing;

Added: DBIx-Class/0.08/branches/group_by_consistency/t/admin/02ddl.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/admin/02ddl.t	                        (rev 0)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/admin/02ddl.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -0,0 +1,130 @@
+use strict;
+use warnings;
+
+use Test::More;
+use Test::Exception;
+use Test::Warn;
+
+BEGIN {
+    require DBIx::Class;
+    plan skip_all => 'Test needs ' . DBIx::Class::Optional::Dependencies->req_missing_for('admin')
+      unless DBIx::Class::Optional::Dependencies->req_ok_for('admin');
+
+    plan skip_all => 'Test needs ' . DBIx::Class::Optional::Dependencies->req_missing_for('deploy')
+      unless DBIx::Class::Optional::Dependencies->req_ok_for('deploy');
+}
+
+use lib qw(t/lib);
+use DBICTest;
+
+use Path::Class;
+
+use_ok 'DBIx::Class::Admin';
+
+
+my $sql_dir = dir(qw/t var/);
+my @connect_info = DBICTest->_database(
+  no_deploy=>1,
+  no_populate=>1,
+  sqlite_use_file  => 1,
+);
+{ # create the schema
+
+#  make sure we are  clean
+clean_dir($sql_dir);
+
+
+my $admin = DBIx::Class::Admin->new(
+  schema_class=> "DBICTest::Schema",
+  sql_dir=> $sql_dir,
+  connect_info => \@connect_info, 
+);
+isa_ok ($admin, 'DBIx::Class::Admin', 'create the admin object');
+lives_ok { $admin->create('MySQL'); } 'Can create MySQL sql';
+lives_ok { $admin->create('SQLite'); } 'Can Create SQLite sql';
+}
+
+{ # upgrade schema
+
+#my $schema = DBICTest->init_schema(
+#  no_deploy    => 1,
+#  no_populat    => 1,
+#  sqlite_use_file  => 1,
+#);
+
+clean_dir($sql_dir);
+require DBICVersion_v1;
+
+my $admin = DBIx::Class::Admin->new(
+  schema_class => 'DBICVersion::Schema', 
+  sql_dir =>  $sql_dir,
+  connect_info => \@connect_info,
+);
+
+my $schema = $admin->schema();
+
+lives_ok { $admin->create($schema->storage->sqlt_type(), {add_drop_table=>0}); } 'Can create DBICVersionOrig sql in ' . $schema->storage->sqlt_type;
+lives_ok { $admin->deploy(  ) } 'Can Deploy schema';
+
+# connect to now deployed schema
+lives_ok { $schema = DBICVersion::Schema->connect(@{$schema->storage->connect_info()}); } 'Connect to deployed Database';
+
+is($schema->get_db_version, $DBICVersion::Schema::VERSION, 'Schema deployed and versions match');
+
+
+require DBICVersion_v2;
+
+$admin = DBIx::Class::Admin->new(
+  schema_class => 'DBICVersion::Schema', 
+  sql_dir =>  $sql_dir,
+  connect_info => \@connect_info
+);
+
+lives_ok { $admin->create($schema->storage->sqlt_type(), {}, "1.0" ); } 'Can create diff for ' . $schema->storage->sqlt_type;
+{
+  local $SIG{__WARN__} = sub { warn $_[0] unless $_[0] =~ /DB version .+? is lower than the schema version/ };
+  lives_ok {$admin->upgrade();} 'upgrade the schema';
+}
+
+is($schema->get_db_version, $DBICVersion::Schema::VERSION, 'Schema and db versions match');
+
+}
+
+{ # install
+
+clean_dir($sql_dir);
+
+my $admin = DBIx::Class::Admin->new(
+  schema_class  => 'DBICVersion::Schema', 
+  sql_dir      => $sql_dir,
+  _confirm    => 1,
+  connect_info  => \@connect_info,
+);
+
+$admin->version("3.0");
+lives_ok { $admin->install(); } 'install schema version 3.0';
+is($admin->schema->get_db_version, "3.0", 'db thinks its version 3.0');
+dies_ok { $admin->install("4.0"); } 'cannot install to allready existing version';
+
+$admin->force(1);
+warnings_exist ( sub {
+  lives_ok { $admin->install("4.0") } 'can force install to allready existing version'
+}, qr/Forcing install may not be a good idea/, 'Force warning emitted' );
+is($admin->schema->get_db_version, "4.0", 'db thinks its version 4.0');
+#clean_dir($sql_dir);
+}
+
+sub clean_dir {
+  my ($dir) = @_;
+  $dir = $dir->resolve;
+  if ( ! -d $dir ) {
+    $dir->mkpath();
+  }
+  foreach my $file ($dir->children) {
+    # skip any hidden files
+    next if ($file =~ /^\./); 
+    unlink $file;
+  }
+}
+
+done_testing;

Added: DBIx-Class/0.08/branches/group_by_consistency/t/admin/03data.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/admin/03data.t	                        (rev 0)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/admin/03data.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -0,0 +1,64 @@
+use strict;
+use warnings;
+
+use Test::More;
+
+use Test::Exception;
+
+BEGIN {
+    require DBIx::Class;
+    plan skip_all => 'Test needs ' . DBIx::Class::Optional::Dependencies->req_missing_for('admin')
+      unless DBIx::Class::Optional::Dependencies->req_ok_for('admin');
+}
+
+use lib 't/lib';
+use DBICTest;
+
+use_ok 'DBIx::Class::Admin';
+
+
+{ # test data maniplulation functions
+
+  # create a DBICTest so we can steal its connect info
+  my $schema = DBICTest->init_schema(
+    sqlite_use_file => 1,
+  );
+
+  my $admin = DBIx::Class::Admin->new(
+    schema_class=> "DBICTest::Schema",
+    connect_info => $schema->storage->connect_info(),
+    quiet  => 1,
+    _confirm=>1,
+  );
+  isa_ok ($admin, 'DBIx::Class::Admin', 'create the admin object');
+
+  $admin->insert('Employee', { name => 'Matt' });
+  my $employees = $schema->resultset('Employee');
+  is ($employees->count(), 1, "insert okay" );
+
+  my $employee = $employees->find(1);
+  is($employee->name(),  'Matt', "insert valid" );
+
+  $admin->update('Employee', {name => 'Trout'}, {name => 'Matt'});
+
+  $employee = $employees->find(1);
+  is($employee->name(),  'Trout', "update Matt to Trout" );
+
+  $admin->insert('Employee', {name =>'Aran'});
+
+  my $expected_data = [ 
+    [$employee->result_source->columns() ],
+    [1,1,undef,undef,undef,'Trout',undef],
+    [2,2,undef,undef,undef,'Aran',undef]
+  ];
+  my $data;
+  lives_ok { $data = $admin->select('Employee')} 'can retrive data from database';
+  is_deeply($data, $expected_data, 'DB matches whats expected');
+
+  $admin->delete('Employee', {name=>'Trout'});
+  my $del_rs  = $employees->search({name => 'Trout'});
+  is($del_rs->count(), 0, "delete Trout" );
+  is ($employees->count(), 1, "left Aran" );
+}
+
+done_testing;

Copied: DBIx-Class/0.08/branches/group_by_consistency/t/admin/10script.t (from rev 8546, DBIx-Class/0.08/branches/group_by_consistency/t/89dbicadmin.t)
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/admin/10script.t	                        (rev 0)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/admin/10script.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -0,0 +1,91 @@
+# vim: filetype=perl
+use strict;
+use warnings;
+
+use Test::More;
+use Config;
+use lib qw(t/lib);
+$ENV{PERL5LIB} = join ($Config{path_sep}, @INC);
+use DBICTest;
+
+
+BEGIN {
+    require DBIx::Class;
+    plan skip_all => 'Test needs ' . DBIx::Class::Optional::Dependencies->req_missing_for('admin_script')
+      unless DBIx::Class::Optional::Dependencies->req_ok_for('admin_script');
+}
+
+my @json_backends = qw/XS JSON DWIW/;
+my $tests_per_run = 5;
+
+plan tests => $tests_per_run * @json_backends;
+
+for my $js (@json_backends) {
+
+    eval {JSON::Any->import ($js) };
+    SKIP: {
+        skip ("Json backend $js is not available, skip testing", $tests_per_run) if $@;
+
+        $ENV{JSON_ANY_ORDER} = $js;
+        eval { test_dbicadmin () };
+        diag $@ if $@;
+    }
+}
+
+sub test_dbicadmin {
+    my $schema = DBICTest->init_schema( sqlite_use_file => 1 );  # reinit a fresh db for every run
+
+    my $employees = $schema->resultset('Employee');
+
+    system( _prepare_system_args( qw|--op=insert --set={"name":"Matt"}| ) );
+    ok( ($employees->count()==1), "$ENV{JSON_ANY_ORDER}: insert count" );
+
+    my $employee = $employees->find(1);
+    ok( ($employee->name() eq 'Matt'), "$ENV{JSON_ANY_ORDER}: insert valid" );
+
+    system( _prepare_system_args( qw|--op=update --set={"name":"Trout"}| ) );
+    $employee = $employees->find(1);
+    ok( ($employee->name() eq 'Trout'), "$ENV{JSON_ANY_ORDER}: update" );
+
+    system( _prepare_system_args( qw|--op=insert --set={"name":"Aran"}| ) );
+
+    SKIP: {
+        skip ("MSWin32 doesn't support -| either", 1) if $^O eq 'MSWin32';
+
+        open(my $fh, "-|",  _prepare_system_args( qw|--op=select --attrs={"order_by":"name"}| ) ) or die $!;
+        my $data = do { local $/; <$fh> };
+        close($fh);
+        if (!ok( ($data=~/Aran.*Trout/s), "$ENV{JSON_ANY_ORDER}: select with attrs" )) {
+          diag ("data from select is $data")
+        };
+    }
+
+    system( _prepare_system_args( qw|--op=delete --where={"name":"Trout"}| ) );
+    ok( ($employees->count()==1), "$ENV{JSON_ANY_ORDER}: delete" );
+}
+
+# Why do we need this crap? Apparently MSWin32 can not pass through quotes properly
+# (sometimes it will and sometimes not, depending on what compiler was used to build
+# perl). So we go the extra mile to escape all the quotes. We can't also use ' instead
+# of ", because JSON::XS (proudly) does not support "malformed JSON" as the author
+# calls it. Bleh.
+#
+sub _prepare_system_args {
+    my $perl = $^X;
+
+    my @args = (
+        qw|script/dbicadmin --quiet --schema=DBICTest::Schema --class=Employee|,
+        q|--connect=["dbi:SQLite:dbname=t/var/DBIxClass.db","","",{"AutoCommit":1}]|,
+        qw|--force|,
+        @_,
+    );
+
+    if ( $^O eq 'MSWin32' ) {
+        $perl = qq|"$perl"|;    # execution will fail if $^X contains paths
+        for (@args) {
+            $_ =~ s/"/\\"/g;
+        }
+    }
+
+    return ($perl, @args);
+}

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/bind/attribute.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/bind/attribute.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/bind/attribute.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -9,13 +9,6 @@
 
 my $schema = DBICTest->init_schema;
 
-BEGIN {
-    eval "use DBD::SQLite";
-    plan $@
-        ? ( skip_all => 'needs DBD::SQLite for testing' )
-        : ( tests => 13 );
-}
-
 my $where_bind = {
     where => \'name like ?',
     bind  => [ 'Cat%' ],
@@ -122,3 +115,5 @@
             bind => [ 'Spoon%' ] });
     is ( $rs->count, 1, '...cookbook + chained search with extra bind' );
 }
+
+done_testing;

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/cdbi/columns_as_hashes.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/cdbi/columns_as_hashes.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/cdbi/columns_as_hashes.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -26,7 +26,7 @@
         my $rating = $waves->{rating};
         $waves->Rating("PG");
         is $rating, "R", 'evaluation of column value is not deferred';
-    } qr{^Column 'rating' of 'Film/$waves' was fetched as a hash at \Q$0};
+    } qr{^Column 'rating' of 'Film/$waves' was fetched as a hash at\b};
 
     warnings_like {
         is $waves->{title}, $waves->Title, "columns can be accessed as hashes";

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/count/count_rs.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/count/count_rs.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/count/count_rs.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -54,7 +54,7 @@
           JOIN cd disc ON disc.cdid = tracks.cd
         WHERE ( ( position = ? OR position = ? ) )
         LIMIT 3 OFFSET 8
-       ) count_subq
+       ) tracks
     )',
     [ [ position => 1 ], [ position => 2 ] ],
     'count_rs db-side limit applied',
@@ -88,7 +88,7 @@
           JOIN artist artist ON artist.artistid = cds.artist
         WHERE tracks.position = ? OR tracks.position = ?
         GROUP BY cds.cdid
-      ) count_subq
+      ) cds
     ',
     [ qw/'1' '2'/ ],
     'count softlimit applied',
@@ -109,7 +109,7 @@
         WHERE tracks.position = ? OR tracks.position = ?
         GROUP BY cds.cdid
         LIMIT 3 OFFSET 4
-      ) count_subq
+      ) cds
     )',
     [ [ 'tracks.position' => 1 ], [ 'tracks.position' => 2 ] ],
     'count_rs db-side limit applied',

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/count/distinct.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/count/distinct.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/count/distinct.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -74,7 +74,7 @@
   $rs = $schema->resultset('Tag')->search({ tag => 'Blue' }, { '+select' => { max => 'tagid' }, distinct => 1 });
   is($get_count->($rs), 4, 'Count with +select aggreggate');
 
-  $rs = $schema->resultset('Tag')->search({}, { select => 'length(me.tag)', distinct => 1 });
+  $rs = $schema->resultset('Tag')->search({}, { select => [\'length(me.tag)'], distinct => 1 });
   is($get_count->($rs), 3, 'Count by distinct function result as select literal');
 }
 

Added: DBIx-Class/0.08/branches/group_by_consistency/t/count/group_by_func.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/count/group_by_func.t	                        (rev 0)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/count/group_by_func.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -0,0 +1,36 @@
+use strict;
+use warnings;
+
+use Test::More;
+
+use lib qw(t/lib);
+
+use DBICTest;
+
+my $schema = DBICTest->init_schema();
+
+my $rs = $schema->resultset ('CD')->search ({}, {
+  select => [
+    { substr => [ 'title', 1, 1 ], -as => 'initial' },
+    { count => '*' },
+  ],
+  as => [qw/title_initial cnt/],
+  group_by => ['initial'],
+  order_by => { -desc => 'initial' },
+  result_class => 'DBIx::Class::ResultClass::HashRefInflator',
+});
+
+is_deeply (
+  [$rs->all],
+  [
+    { title_initial => 'S', cnt => '1' },
+    { title_initial => 'G', cnt => '1' },
+    { title_initial => 'F', cnt => '1' },
+    { title_initial => 'C', cnt => '2' },
+  ],
+  'Correct result',
+);
+
+is ($rs->count, 4, 'Correct count');
+
+done_testing;

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/count/prefetch.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/count/prefetch.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/count/prefetch.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -31,7 +31,7 @@
             JOIN artist artist ON artist.artistid = cds.artist
           WHERE tracks.position = ? OR tracks.position = ?
           GROUP BY cds.cdid
-        ) count_subq
+        ) cds
     )',
     [ map { [ 'tracks.position' => $_ ] } (1, 2) ],
   );
@@ -63,7 +63,7 @@
           WHERE ( genre.name = ? )
           GROUP BY genre.genreid
         )
-      count_subq
+      genre
     )',
     [ [ 'genre.name' => 'emo' ] ],
   );

Added: DBIx-Class/0.08/branches/group_by_consistency/t/inflate/datetime_firebird.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/inflate/datetime_firebird.t	                        (rev 0)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/inflate/datetime_firebird.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -0,0 +1,92 @@
+use strict;
+use warnings;  
+
+use Test::More;
+use Test::Exception;
+use lib qw(t/lib);
+use DBICTest;
+use Scope::Guard ();
+
+my ($dsn, $user, $pass)    = @ENV{map { "DBICTEST_FIREBIRD_${_}" }      qw/DSN USER PASS/};
+my ($dsn2, $user2, $pass2) = @ENV{map { "DBICTEST_FIREBIRD_ODBC_${_}" } qw/DSN USER PASS/};
+
+if (not ($dsn || $dsn2)) {
+  plan skip_all => <<'EOF';
+Set $ENV{DBICTEST_FIREBIRD_DSN} and/or $ENV{DBICTEST_FIREBIRD_ODBC_DSN}
+_USER and _PASS to run this test'.
+Warning: This test drops and creates a table called 'event'";
+EOF
+} else {
+  eval "use DateTime; use DateTime::Format::Strptime;";
+  if ($@) {
+    plan skip_all => 'needs DateTime and DateTime::Format::Strptime for testing';
+  }
+}
+
+my @info = (
+  [ $dsn,  $user,  $pass  ],
+  [ $dsn2, $user2, $pass2 ],
+);
+
+my $schema;
+
+foreach my $conn_idx (0..$#info) {
+  my ($dsn, $user, $pass) = @{ $info[$conn_idx] || [] };
+
+  next unless $dsn;
+
+  $schema = DBICTest::Schema->connect($dsn, $user, $pass, {
+    quote_char => '"',
+    name_sep   => '.', 
+    on_connect_call => [ 'datetime_setup' ],
+  });
+
+  my $sg = Scope::Guard->new(\&cleanup);
+
+  eval { $schema->storage->dbh->do('DROP TABLE "event"') };
+  $schema->storage->dbh->do(<<'SQL');
+  CREATE TABLE "event" (
+    "id" INT PRIMARY KEY,
+    "starts_at" DATE,
+    "created_on" TIMESTAMP
+  )
+SQL
+  my $rs   = $schema->resultset('Event');
+
+  my $dt = DateTime->now;
+  $dt->set_nanosecond($dsn =~ /odbc/i ? 0 : 555600000);
+
+  my $date_only = DateTime->new(
+    year => $dt->year, month => $dt->month, day => $dt->day
+  );
+
+  my $row;
+  ok( $row = $rs->create({
+    id => 1,
+    starts_at => $date_only, 
+    created_on => $dt,
+  }));
+  ok( $row = $rs->search({ id => 1 }, { select => [qw/starts_at created_on/] })
+    ->first
+  );
+  is $row->created_on, $dt, 'TIMESTAMP as DateTime roundtrip';
+
+  cmp_ok $row->created_on->nanosecond, '==', $dt->nanosecond,
+    'fractional part of a second survived' if 0+$dt->nanosecond;
+
+  is $row->starts_at, $date_only, 'DATE as DateTime roundtrip';
+}
+
+done_testing;
+
+# clean up our mess
+sub cleanup {
+  my $dbh; 
+  eval {
+    $schema->storage->disconnect; # to avoid object FOO is in use errors
+    $dbh = $schema->storage->dbh;
+  };
+  return unless $dbh;
+
+  eval { $dbh->do(qq{DROP TABLE "$_"}) } for qw/event/;
+}

Added: DBIx-Class/0.08/branches/group_by_consistency/t/inflate/datetime_informix.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/inflate/datetime_informix.t	                        (rev 0)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/inflate/datetime_informix.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -0,0 +1,78 @@
+use strict;
+use warnings;  
+
+use Test::More;
+use Test::Exception;
+use lib qw(t/lib);
+use DBICTest;
+use Scope::Guard ();
+
+my ($dsn, $user, $pass) = @ENV{map { "DBICTEST_INFORMIX_${_}" } qw/DSN USER PASS/};
+
+if (not $dsn) {
+  plan skip_all => <<'EOF';
+Set $ENV{DBICTEST_INFORMIX_DSN} _USER and _PASS to run this test'.
+Warning: This test drops and creates a table called 'event'";
+EOF
+} else {
+  eval "use DateTime; use DateTime::Format::Strptime;";
+  if ($@) {
+    plan skip_all => 'needs DateTime and DateTime::Format::Strptime for testing';
+  }
+}
+
+my $schema;
+
+{
+  $schema = DBICTest::Schema->connect($dsn, $user, $pass, {
+    on_connect_call => [ 'datetime_setup' ],
+  });
+
+  my $sg = Scope::Guard->new(\&cleanup);
+
+  eval { $schema->storage->dbh->do('DROP TABLE event') };
+  $schema->storage->dbh->do(<<'SQL');
+  CREATE TABLE event (
+    id INT PRIMARY KEY,
+    starts_at DATE,
+    created_on DATETIME YEAR TO FRACTION(5)
+  );
+SQL
+  my $rs = $schema->resultset('Event');
+
+  my $dt = DateTime->now;
+  $dt->set_nanosecond(555640000);
+
+  my $date_only = DateTime->new(
+    year => $dt->year, month => $dt->month, day => $dt->day
+  );
+
+  my $row;
+  ok( $row = $rs->create({
+    id => 1,
+    starts_at => $date_only, 
+    created_on => $dt,
+  }));
+  ok( $row = $rs->search({ id => 1 }, { select => [qw/starts_at created_on/] })
+    ->first
+  );
+  is $row->created_on, $dt, 'TIMESTAMP as DateTime roundtrip';
+
+  cmp_ok $row->created_on->nanosecond, '==', $dt->nanosecond,
+    'fractional part of a second survived';
+
+  is $row->starts_at, $date_only, 'DATE as DateTime roundtrip';
+}
+
+done_testing;
+
+# clean up our mess
+sub cleanup {
+  my $dbh; 
+  eval {
+    $dbh = $schema->storage->dbh;
+  };
+  return unless $dbh;
+
+  eval { $dbh->do(qq{DROP TABLE $_}) } for qw/event/;
+}

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/inflate/datetime_mssql.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/inflate/datetime_mssql.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/inflate/datetime_mssql.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -3,59 +3,79 @@
 
 use Test::More;
 use Test::Exception;
+use Scope::Guard ();
 use lib qw(t/lib);
 use DBICTest;
 
-my ($dsn, $user, $pass) = @ENV{map { "DBICTEST_MSSQL_ODBC_${_}" } qw/DSN USER PASS/};
+# use this if you keep a copy of DBD::Sybase linked to FreeTDS somewhere else
+BEGIN {
+  if (my $lib_dirs = $ENV{DBICTEST_MSSQL_PERL5LIB}) {
+    unshift @INC, $_ for split /:/, $lib_dirs;
+  }
+}
 
-if (not ($dsn && $user)) {
+my ($dsn, $user, $pass)    = @ENV{map { "DBICTEST_MSSQL_ODBC_${_}" } qw/DSN USER PASS/};
+my ($dsn2, $user2, $pass2) = @ENV{map { "DBICTEST_MSSQL_${_}" }      qw/DSN USER PASS/};
+
+if (not ($dsn || $dsn2)) {
   plan skip_all =>
-    'Set $ENV{DBICTEST_MSSQL_ODBC_DSN}, _USER and _PASS to run this test' .
+    'Set $ENV{DBICTEST_MSSQL_ODBC_DSN} and/or $ENV{DBICTEST_MSSQL_DSN} _USER '
+    .'and _PASS to run this test' .
     "\nWarning: This test drops and creates a table called 'track'";
 } else {
   eval "use DateTime; use DateTime::Format::Strptime;";
   if ($@) {
     plan skip_all => 'needs DateTime and DateTime::Format::Strptime for testing';
   }
-  else {
-    plan tests => 4 * 2; # (tests * dt_types)
-  }
 }
 
-my $schema = DBICTest::Schema->clone;
+my @connect_info = (
+  [ $dsn,  $user,  $pass ],
+  [ $dsn2, $user2, $pass2 ],
+);
 
-$schema->connection($dsn, $user, $pass);
-$schema->storage->ensure_connected;
+my $schema;
 
+for my $connect_info (@connect_info) {
+  my ($dsn, $user, $pass) = @$connect_info;
+
+  next unless $dsn;
+
+  $schema = DBICTest::Schema->connect($dsn, $user, $pass, {
+    on_connect_call => 'datetime_setup'
+  });
+
+  my $guard = Scope::Guard->new(\&cleanup);
+
 # coltype, column, datehash
-my @dt_types = (
-  ['DATETIME',
-   'last_updated_at',
-   {
-    year => 2004,
-    month => 8,
-    day => 21,
-    hour => 14,
-    minute => 36,
-    second => 48,
-    nanosecond => 500000000,
-  }],
-  ['SMALLDATETIME', # minute precision
-   'small_dt',
-   {
-    year => 2004,
-    month => 8,
-    day => 21,
-    hour => 14,
-    minute => 36,
-  }],
-);
+  my @dt_types = (
+    ['DATETIME',
+     'last_updated_at',
+     {
+      year => 2004,
+      month => 8,
+      day => 21,
+      hour => 14,
+      minute => 36,
+      second => 48,
+      nanosecond => 500000000,
+    }],
+    ['SMALLDATETIME', # minute precision
+     'small_dt',
+     {
+      year => 2004,
+      month => 8,
+      day => 21,
+      hour => 14,
+      minute => 36,
+    }],
+  );
 
-for my $dt_type (@dt_types) {
-  my ($type, $col, $sample_dt) = @$dt_type;
+  for my $dt_type (@dt_types) {
+    my ($type, $col, $sample_dt) = @$dt_type;
 
-  eval { $schema->storage->dbh->do("DROP TABLE track") };
-  $schema->storage->dbh->do(<<"SQL");
+    eval { $schema->storage->dbh->do("DROP TABLE track") };
+    $schema->storage->dbh->do(<<"SQL");
 CREATE TABLE track (
  trackid INT IDENTITY PRIMARY KEY,
  cd INT,
@@ -63,23 +83,30 @@
  $col $type,
 )
 SQL
-  ok(my $dt = DateTime->new($sample_dt));
+    ok(my $dt = DateTime->new($sample_dt));
 
-  my $row;
-  ok( $row = $schema->resultset('Track')->create({
-        $col => $dt,
-        cd => 1,
-      }));
-  ok( $row = $schema->resultset('Track')
-    ->search({ trackid => $row->trackid }, { select => [$col] })
-    ->first
-  );
-  is( $row->$col, $dt, 'DateTime roundtrip' );
+    my $row;
+    ok( $row = $schema->resultset('Track')->create({
+          $col => $dt,
+          cd => 1,
+        }));
+    ok( $row = $schema->resultset('Track')
+      ->search({ trackid => $row->trackid }, { select => [$col] })
+      ->first
+    );
+    is( $row->$col, $dt, "$type roundtrip" );
+
+    cmp_ok( $row->$col->nanosecond, '==', $sample_dt->{nanosecond},
+      'DateTime fractional portion roundtrip' )
+      if exists $sample_dt->{nanosecond};
+  }
 }
 
+done_testing;
+
 # clean up our mess
-END {
-  if (my $dbh = eval { $schema->storage->_dbh }) {
+sub cleanup {
+  if (my $dbh = eval { $schema->storage->dbh }) {
     $dbh->do('DROP TABLE track');
   }
 }

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/inflate/datetime_sybase.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/inflate/datetime_sybase.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/inflate/datetime_sybase.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -70,7 +70,11 @@
       ->search({ trackid => $row->trackid }, { select => [$col] })
       ->first
     );
-    is( $row->$col, $dt, 'DateTime roundtrip' );
+    is( $row->$col, $dt, "$type roundtrip" );
+
+    is( $row->$col->nanosecond, $dt->nanosecond,
+      'fractional DateTime portion roundtrip' )
+      if $dt->nanosecond > 0;
   }
 
   # test a computed datetime column

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/inflate/datetime_sybase_asa.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/inflate/datetime_sybase_asa.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/inflate/datetime_sybase_asa.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -44,7 +44,7 @@
 
 # coltype, col, date
   my @dt_types = (
-    ['TIMESTAMP', 'last_updated_at', '2004-08-21 14:36:48.080444'],
+    ['TIMESTAMP', 'last_updated_at', '2004-08-21 14:36:48.080445'],
 # date only (but minute precision according to ASA docs)
     ['DATE', 'small_dt', '2004-08-21 00:00:00.000000'],
   );
@@ -73,6 +73,9 @@
       ->first
     );
     is( $row->$col, $dt, 'DateTime roundtrip' );
+
+    is $row->$col->nanosecond, $dt->nanosecond,
+        'nanoseconds survived' if 0+$dt->nanosecond;
   }
 }
 

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/inflate/file_column.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/inflate/file_column.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/inflate/file_column.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -1,13 +1,22 @@
 use strict;
-use warnings;  
+use warnings;
 
 use Test::More;
 use lib qw(t/lib);
+
+# inject IC::File into the result baseclass for testing
+BEGIN {
+  $ENV{DBIC_IC_FILE_NOWARN} = 1;
+  require DBICTest::BaseResult;
+  DBICTest::BaseResult->load_components (qw/InflateColumn::File/);
+}
+
+
 use DBICTest;
 use File::Compare;
 use Path::Class qw/file/;
 
-my $schema = DBICTest->init_schema();
+my $schema = DBICTest->init_schema;
 
 plan tests => 10;
 

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/inflate/hri.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/inflate/hri.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/inflate/hri.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -26,6 +26,9 @@
 
     my $cd1 = $rs->find ({cdid => 1});
     is_deeply ( $cd1, $datahashref1, 'first/find return the same thing');
+
+    my $cd2 = $rs->search({ cdid => 1 })->single;
+    is_deeply ( $cd2, $datahashref1, 'first/search+single return the same thing');
 }
 
 sub check_cols_of {

Added: DBIx-Class/0.08/branches/group_by_consistency/t/lib/DBICNSTest/Result/D.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/lib/DBICNSTest/Result/D.pm	                        (rev 0)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/lib/DBICNSTest/Result/D.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -0,0 +1,5 @@
+package DBICNSTest::Result::D;
+use base qw/DBIx::Class::Core/;
+__PACKAGE__->table('d');
+__PACKAGE__->add_columns('d');
+1;

Added: DBIx-Class/0.08/branches/group_by_consistency/t/lib/DBICNSTest/ResultSet/D.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/lib/DBICNSTest/ResultSet/D.pm	                        (rev 0)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/lib/DBICNSTest/ResultSet/D.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -0,0 +1,2 @@
+package DBICNSTest::ResultSet::D;
+1;

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/lib/DBICTest/AuthorCheck.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/lib/DBICTest/AuthorCheck.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/lib/DBICTest/AuthorCheck.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -27,26 +27,37 @@
   my $root = _find_co_root()
     or return;
 
+  my $optdeps = file('lib/DBIx/Class/Optional/Dependencies.pm');
+
   # not using file->stat as it invokes File::stat which in turn breaks stat(_)
-  my ($mf_pl_mtime, $mf_mtime) = ( map
+  my ($mf_pl_mtime, $mf_mtime, $optdeps_mtime) = ( map
     { (stat ($root->file ($_)) )[9] }
-    qw/Makefile.PL Makefile/
+    (qw|Makefile.PL  Makefile|, $optdeps)
   );
 
   return unless $mf_pl_mtime;   # something went wrong during co_root detection ?
 
-  if (
-    not -d $root->subdir ('inc') 
-      or
-    not $mf_mtime
-      or
-    $mf_mtime < $mf_pl_mtime
-  ) {
-    print STDERR <<'EOE';
+  my @fail_reasons;
 
+  if(not -d $root->subdir ('inc')) {
+    push @fail_reasons, "Missing ./inc directory";
+  }
 
+  if (not $mf_mtime) {
+    push @fail_reasons, "Missing ./Makefile";
+  }
+  elsif($mf_mtime < $mf_pl_mtime) {
+    push @fail_reasons, "./Makefile.PL is newer than ./Makefile";
+  }
 
+  if ($mf_mtime < $optdeps_mtime) {
+    push @fail_reasons, "./$optdeps is newer than ./Makefile";
+  }
 
+  if (@fail_reasons) {
+    print STDERR <<'EOE';
+
+
 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 ======================== FATAL ERROR ===========================
 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
@@ -68,9 +79,15 @@
 The DBIC team
 
 
+Reasons you received this message:
 
 EOE
 
+    foreach my $r (@fail_reasons) {
+      print STDERR "  * $r\n";
+    }
+    print STDERR "\n\n\n";
+
     exit 1;
   }
 }

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/lib/DBICTest/Schema/Employee.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/lib/DBICTest/Schema/Employee.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/lib/DBICTest/Schema/Employee.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -32,18 +32,20 @@
         size      => 100,
         is_nullable => 1,
     },
+    encoded => {
+        data_type => 'integer',
+        is_nullable => 1,
+    },
 );
 
 __PACKAGE__->set_primary_key('employee_id');
 __PACKAGE__->position_column('position');
 
-#__PACKAGE__->add_unique_constraint(position_group => [ qw/position group_id/ ]);
+# Do not add unique constraints here - different groups are used throughout
+# the ordered tests
 
-__PACKAGE__->mk_classdata('field_name_for', {
-    employee_id => 'primary key',
-    position    => 'list position',
-    group_id    => 'collection column',
-    name        => 'employee name',
+__PACKAGE__->belongs_to (secretkey => 'DBICTest::Schema::Encoded', 'encoded', {
+  join_type => 'left'
 });
 
 1;

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/lib/DBICTest/Schema/Encoded.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/lib/DBICTest/Schema/Encoded.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/lib/DBICTest/Schema/Encoded.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -21,6 +21,8 @@
 
 __PACKAGE__->set_primary_key('id');
 
+__PACKAGE__->has_many (keyholders => 'DBICTest::Schema::Employee', 'encoded');
+
 sub set_column {
   my ($self, $col, $value) = @_;
   if( $col eq 'encoded' ){

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/lib/DBICTest/Schema/Event.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/lib/DBICTest/Schema/Event.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/lib/DBICTest/Schema/Event.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -10,14 +10,27 @@
 
 __PACKAGE__->add_columns(
   id => { data_type => 'integer', is_auto_increment => 1 },
-  starts_at => { data_type => 'datetime' },
+
+# this MUST be 'date' for the Firebird tests
+  starts_at => { data_type => 'date' },
+
   created_on => { data_type => 'timestamp' },
-  varchar_date => { data_type => 'varchar', inflate_date => 1, size => 20, is_nullable => 1 },
-  varchar_datetime => { data_type => 'varchar', inflate_datetime => 1, size => 20, is_nullable => 1 },
+  varchar_date => { data_type => 'varchar', size => 20, is_nullable => 1 },
+  varchar_datetime => { data_type => 'varchar', size => 20, is_nullable => 1 },
   skip_inflation => { data_type => 'datetime', inflate_datetime => 0, is_nullable => 1 },
   ts_without_tz => { data_type => 'datetime', is_nullable => 1 }, # used in EventTZPg
 );
 
 __PACKAGE__->set_primary_key('id');
 
+# Test add_columns '+colname' to augment a column definition.
+__PACKAGE__->add_columns(
+  '+varchar_date' => {
+    inflate_date => 1,
+  },
+  '+varchar_datetime' => {
+    inflate_datetime => 1,
+  },
+);
+
 1;


Property changes on: DBIx-Class/0.08/branches/group_by_consistency/t/lib/DBICTest/Schema/EventTZPg.pm
___________________________________________________________________
Deleted: svn:mergeinfo
   - 

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/lib/DBICTest/Schema/FileColumn.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/lib/DBICTest/Schema/FileColumn.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/lib/DBICTest/Schema/FileColumn.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -6,8 +6,6 @@
 use base qw/DBICTest::BaseResult/;
 use File::Temp qw/tempdir/;
 
-__PACKAGE__->load_components(qw/InflateColumn::File/);
-
 __PACKAGE__->table('file_columns');
 
 __PACKAGE__->add_columns(

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/lib/DBICTest/Schema/ForceForeign.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/lib/DBICTest/Schema/ForceForeign.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/lib/DBICTest/Schema/ForceForeign.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -12,30 +12,21 @@
 
 # Normally this would not appear as a FK constraint
 # since it uses the PK
-__PACKAGE__->might_have(
-			'artist_1', 'DBICTest::Schema::Artist', {
-			    'foreign.artistid' => 'self.artist',
-			}, {
-			    is_foreign_key_constraint => 1,
-			},
+__PACKAGE__->might_have('artist_1', 'DBICTest::Schema::Artist',
+  { 'foreign.artistid' => 'self.artist' },
+  { is_foreign_key_constraint => 1 },
 );
 
 # Normally this would appear as a FK constraint
-__PACKAGE__->might_have(
-			'cd_1', 'DBICTest::Schema::CD', {
-			    'foreign.cdid' => 'self.cd',
-			}, {
-			    is_foreign_key_constraint => 0,
-			},
+__PACKAGE__->might_have('cd_1', 'DBICTest::Schema::CD',
+  { 'foreign.cdid' => 'self.cd' },
+  { is_foreign_key_constraint => 0 },
 );
 
 # Normally this would appear as a FK constraint
-__PACKAGE__->belongs_to(
-			'cd_3', 'DBICTest::Schema::CD', {
-			    'foreign.cdid' => 'self.cd',
-			}, {
-			    is_foreign_key_constraint => 0,
-			},
+__PACKAGE__->belongs_to('cd_3', 'DBICTest::Schema::CD',
+  { 'foreign.cdid' => 'self.cd' },
+  { is_foreign_key_constraint => 0 },
 );
 
 1;

Added: DBIx-Class/0.08/branches/group_by_consistency/t/lib/DBICTest/Schema/TimestampPrimaryKey.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/lib/DBICTest/Schema/TimestampPrimaryKey.pm	                        (rev 0)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/lib/DBICTest/Schema/TimestampPrimaryKey.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -0,0 +1,17 @@
+package # hide from PAUSE 
+    DBICTest::Schema::TimestampPrimaryKey;
+
+use base qw/DBICTest::BaseResult/;
+
+__PACKAGE__->table('timestamp_primary_key_test');
+
+__PACKAGE__->add_columns(
+  'id' => {
+    data_type => 'timestamp',
+    default_value => \'current_timestamp',
+  },
+);
+
+__PACKAGE__->set_primary_key('id');
+
+1;

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/lib/DBICTest/Schema.pm
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/lib/DBICTest/Schema.pm	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/lib/DBICTest/Schema.pm	2010-05-06 09:42:51 UTC (rev 9313)
@@ -22,6 +22,7 @@
   Year1999CDs
   CustomSql
   Money
+  TimestampPrimaryKey
   /,
   { 'DBICTest::Schema' => [qw/
     LinerNotes

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/lib/sqlite.sql
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/lib/sqlite.sql	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/lib/sqlite.sql	2010-05-06 09:42:51 UTC (rev 9313)
@@ -1,6 +1,6 @@
 -- 
 -- Created by SQL::Translator::Producer::SQLite
--- Created on Sat Jan 30 19:18:55 2010
+-- Created on Mon Mar 22 11:08:33 2010
 -- 
 ;
 
@@ -35,18 +35,6 @@
 );
 
 --
--- Table: employee
---
-CREATE TABLE employee (
-  employee_id INTEGER PRIMARY KEY NOT NULL,
-  position integer NOT NULL,
-  group_id integer,
-  group_id_2 integer,
-  group_id_3 integer,
-  name varchar(100)
-);
-
---
 -- Table: encoded
 --
 CREATE TABLE encoded (
@@ -59,7 +47,7 @@
 --
 CREATE TABLE event (
   id INTEGER PRIMARY KEY NOT NULL,
-  starts_at datetime NOT NULL,
+  starts_at date NOT NULL,
   created_on timestamp NOT NULL,
   varchar_date varchar(20),
   varchar_datetime varchar(20),
@@ -181,6 +169,14 @@
 );
 
 --
+-- Table: timestamp_primary_key_test
+--
+CREATE TABLE timestamp_primary_key_test (
+  id timestamp NOT NULL DEFAULT current_timestamp,
+  PRIMARY KEY (id)
+);
+
+--
 -- Table: treelike
 --
 CREATE TABLE treelike (
@@ -253,6 +249,21 @@
 CREATE INDEX books_idx_owner ON books (owner);
 
 --
+-- Table: employee
+--
+CREATE TABLE employee (
+  employee_id INTEGER PRIMARY KEY NOT NULL,
+  position integer NOT NULL,
+  group_id integer,
+  group_id_2 integer,
+  group_id_3 integer,
+  name varchar(100),
+  encoded integer
+);
+
+CREATE INDEX employee_idx_encoded ON employee (encoded);
+
+--
 -- Table: forceforeign
 --
 CREATE TABLE forceforeign (

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/multi_create/in_memory.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/multi_create/in_memory.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/multi_create/in_memory.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -6,8 +6,6 @@
 use lib qw(t/lib);
 use DBICTest;
 
-plan tests => 12;
-
 my $schema = DBICTest->init_schema();
 
 # Test various new() invocations - this is all about backcompat, making 
@@ -46,17 +44,99 @@
 }
 
 {
-    my $new_artist = $schema->resultset("Artist")->new_result({ 'name' => 'Depeche Mode 2: Insertion Boogaloo' });
-    my $new_related_cd = $new_artist->new_related('cds', { 'title' => 'Leave Loudly While Singing Off Key', 'year' => 1982});
+    my $new_cd = $schema->resultset('CD')->new ({ 'title' => 'Leave Loudly While Singing Off Key', 'year' => 1982});
+    my $new_artist = $schema->resultset("Artist")->new ({ 'name' => 'Depeche Mode 2: Insertion Boogaloo' });
+    $new_cd->artist ($new_artist);
+
     eval {
-        $new_related_cd->insert;
+        $new_cd->insert;
     };
     is ($@, '', 'CD insertion survives by inserting artist');
+    ok($new_cd->in_storage, 'new_related_cd inserted');
     ok($new_artist->in_storage, 'artist inserted');
-    ok($new_related_cd->in_storage, 'new_related_cd inserted');
+
+    my $retrieved_cd = $schema->resultset('CD')->find ({ 'title' => 'Leave Loudly While Singing Off Key'});
+    ok ($retrieved_cd, 'CD found in db');
+    is ($retrieved_cd->artist->name, 'Depeche Mode 2: Insertion Boogaloo', 'Correct artist attached to cd');
 }
 
+# test both sides of a 1:(1|0)
 {
+  for my $reldir ('might_have', 'belongs_to') {
+    my $artist = $schema->resultset('Artist')->next;
+
+    my $new_track = $schema->resultset('Track')->new ({
+      title => "$reldir: First track of latest cd",
+      cd => {
+        title => "$reldir: Latest cd",
+        year => 2666,
+        artist => $artist,
+      },
+    });
+
+    my $new_single = $schema->resultset('CD')->new ({
+      artist => $artist,
+      title => "$reldir: Awesome first single",
+      year => 2666,
+    });
+
+    if ($reldir eq 'might_have') {
+      $new_track->cd_single ($new_single);
+      $new_track->insert;
+    }
+    else {
+      $new_single->single_track ($new_track);
+      $new_single->insert;
+    }
+
+    ok ($new_single->in_storage, "$reldir single inserted");
+    ok ($new_track->in_storage, "$reldir track inserted");
+
+    my $new_cds = $artist->search_related ('cds',
+      { year => '2666' },
+      { prefetch => 'tracks', order_by => 'cdid' }
+    );
+
+    is_deeply (
+      [$new_cds->search ({}, { result_class => 'DBIx::Class::ResultClass::HashRefInflator'})->all ],
+      [
+        {
+          artist => 1,
+          cdid => 9,
+          genreid => undef,
+          single_track => undef,
+          title => "$reldir: Latest cd",
+          tracks => [
+            {
+              cd => 9,
+              last_updated_at => undef,
+              last_updated_on => undef,
+              position => 1,
+              small_dt => undef,
+              title => "$reldir: First track of latest cd",
+              trackid => 19
+            }
+          ],
+          year => 2666
+        },
+        {
+          artist => 1,
+          cdid => 10,
+          genreid => undef,
+          single_track => 19,
+          title => "$reldir: Awesome first single",
+          tracks => [],
+          year => 2666
+        },
+      ],
+      'Expected rows created in database',
+    );
+
+    $new_cds->delete_all;
+  }
+}
+
+{
     my $new_cd = $schema->resultset("CD")->new_result({});
     my $new_related_artist = $new_cd->new_related('artist', { 'name' => 'Marillion',});
     lives_ok (
@@ -72,3 +152,5 @@
     ok($new_related_artist->in_storage, 'related artist inserted');
     ok($new_cd->in_storage, 'cd inserted');
 }
+
+done_testing;

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/multi_create/standard.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/multi_create/standard.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/multi_create/standard.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -72,7 +72,7 @@
       ],
     });
   },
-  qr/Recursive update is not supported over relationships of type multi/,
+  qr/Recursive update is not supported over relationships of type 'multi'/,
   'create via update of multi relationships throws an exception'
 );
 


Property changes on: DBIx-Class/0.08/branches/group_by_consistency/t/ordered/cascade_delete.t
___________________________________________________________________
Deleted: svn:mergeinfo
   - 

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/prefetch/grouped.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/prefetch/grouped.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/prefetch/grouped.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -76,7 +76,7 @@
           WHERE ( me.cd IN ( ?, ?, ?, ?, ? ) )
           GROUP BY me.cd
         )
-      count_subq
+      me
     )',
     [ map { [ 'me.cd' => $_] } ($cd_rs->get_column ('cdid')->all) ],
     'count() query generated expected SQL',
@@ -151,7 +151,7 @@
           WHERE ( me.cdid IS NOT NULL )
           GROUP BY me.cdid
           LIMIT 2
-        ) count_subq
+        ) me
     )',
     [],
     'count() query generated expected SQL',
@@ -262,7 +262,7 @@
           WHERE ( me.cd IN ( ?, ?, ?, ?, ? ) )
           GROUP BY SUBSTR(me.cd, 1, 1)
         )
-      count_subq
+      me
     )',
     [ map { [ 'me.cd' => $_] } ($cd_rs->get_column ('cdid')->all) ],
     'count() query generated expected SQL',

Added: DBIx-Class/0.08/branches/group_by_consistency/t/prefetch/one_to_many_to_one.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/prefetch/one_to_many_to_one.t	                        (rev 0)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/prefetch/one_to_many_to_one.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -0,0 +1,35 @@
+use strict;
+use warnings;
+
+use Test::More;
+use Test::Exception;
+
+use lib qw(t/lib);
+use DBICTest;
+
+my $schema = DBICTest->init_schema();
+
+my $artist = $schema->resultset ('Artist')->find ({artistid => 1});
+is ($artist->cds->count, 3, 'Correct number of CDs');
+is ($artist->cds->search_related ('genre')->count, 1, 'Only one of the cds has a genre');
+
+my $queries = 0;
+my $orig_cb = $schema->storage->debugcb;
+$schema->storage->debugcb(sub { $queries++ });
+$schema->storage->debug(1);
+
+
+my $pref = $schema->resultset ('Artist')
+                     ->search ({ 'me.artistid' => $artist->id }, { prefetch => { cds => 'genre' } })
+                      ->next;
+
+is ($pref->cds->count, 3, 'Correct number of CDs prefetched');
+is ($pref->cds->search_related ('genre')->count, 1, 'Only one of the prefetched cds has a prefetched genre');
+
+
+is ($queries, 1, 'All happened within one query only');
+$schema->storage->debugcb($orig_cb);
+$schema->storage->debug(0);
+
+
+done_testing;

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/prefetch/via_search_related.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/prefetch/via_search_related.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/prefetch/via_search_related.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -37,7 +37,6 @@
 
 }, 'search_related prefetch with order_by works');
 
-TODO: { local $TODO = 'Unqualified columns in where clauses can not be fixed without an SQLA rewrite' if SQL::Abstract->VERSION < 2;
 lives_ok ( sub {
   my $no_prefetch = $schema->resultset('Track')->search_related(cd =>
     {
@@ -65,9 +64,7 @@
   is($use_prefetch->count, $no_prefetch->count, 'counts with and without prefetch match');
 
 }, 'search_related prefetch with condition referencing unqualified column of a joined table works');
-}
 
-
 lives_ok (sub {
     my $rs = $schema->resultset("Artwork")->search(undef, {distinct => 1})
               ->search_related('artwork_to_artist')->search_related('artist',

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/relationship/core.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/relationship/core.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/relationship/core.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -79,6 +79,10 @@
 } );
 $track->set_from_related( cd => $cd );
 
+# has_relationship
+ok(! $track->has_relationship( 'foo' ), 'Track has no relationship "foo"');
+ok($track->has_relationship( 'disc' ), 'Track has relationship "disk"' );
+
 is($track->disc->cdid, 4, 'set_from_related ok, including alternative accessor' );
 
 $track->set_from_related( cd => undef );

Added: DBIx-Class/0.08/branches/group_by_consistency/t/relationship/unresolvable.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/relationship/unresolvable.t	                        (rev 0)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/relationship/unresolvable.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -0,0 +1,21 @@
+use strict;
+use warnings;
+
+use Test::More;
+use Test::Exception;
+
+use lib qw(t/lib);
+use DBICTest;
+
+my $schema = DBICTest->init_schema();
+
+my $cd = $schema->resultset('CD')->search ({}, { columns => ['year'], rows => 1 })->single;
+
+
+throws_ok (
+  sub { $cd->tracks },
+  qr/Unable to resolve relationship .+ column .+ not loaded from storage/,
+  'Correct exception on nonresolvable object-based condition'
+);
+
+done_testing;

Added: DBIx-Class/0.08/branches/group_by_consistency/t/resultset/as_subselect_rs.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/resultset/as_subselect_rs.t	                        (rev 0)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/resultset/as_subselect_rs.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -0,0 +1,42 @@
+use strict;
+use warnings;
+
+use Test::More;
+use Test::Exception;
+
+use lib qw(t/lib);
+use DBICTest;
+use DBIC::SqlMakerTest;
+
+my $schema = DBICTest->init_schema();
+
+my $new_rs = $schema->resultset('Artist')->search({
+   'artwork_to_artist.artist_id' => 1
+}, {
+   join => 'artwork_to_artist'
+});
+lives_ok { $new_rs->count } 'regular search works';
+lives_ok { $new_rs->search({ 'artwork_to_artist.artwork_cd_id' => 1})->count }
+   '... and chaining off that using join works';
+lives_ok { $new_rs->search({ 'artwork_to_artist.artwork_cd_id' => 1})->as_subselect_rs->count }
+   '... and chaining off the virtual view works';
+dies_ok  { $new_rs->as_subselect_rs->search({'artwork_to_artist.artwork_cd_id'=> 1})->count }
+   q{... but chaining off of a virtual view using join doesn't work};
+
+my $book_rs = $schema->resultset ('BooksInLibrary')->search ({}, { join => 'owner' });
+
+is_same_sql_bind (
+  $book_rs->as_subselect_rs->as_query,
+  '(SELECT me.id, me.source, me.owner, me.title, me.price 
+      FROM (
+        SELECT me.id, me.source, me.owner, me.title, me.price
+          FROM books me
+          JOIN owners owner ON owner.id = me.owner
+        WHERE ( source = ? )
+      ) me
+  )',
+  [ [ source => 'Library' ] ],
+  'Resultset-class attributes do not seep outside of the subselect',
+);
+
+done_testing;

Added: DBIx-Class/0.08/branches/group_by_consistency/t/resultset/is_ordered.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/resultset/is_ordered.t	                        (rev 0)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/resultset/is_ordered.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -0,0 +1,90 @@
+use strict;
+use warnings;
+
+use lib qw(t/lib);
+use Test::More;
+use Test::Exception;
+use DBICTest;
+
+my $schema = DBICTest->init_schema();
+my $rs = $schema->resultset('Artist');
+
+ok !$rs->is_ordered, 'vanilla resultset is not ordered';
+
+# Simple ordering with a single column
+{
+  my $ordered = $rs->search(undef, { order_by => 'artistid' });
+  ok $ordered->is_ordered, 'Simple column ordering detected by is_ordered';
+}
+
+# Hashref order direction
+{
+  my $ordered = $rs->search(undef, { order_by => { -desc => 'artistid' } });
+  ok $ordered->is_ordered, 'resultset with order direction is_ordered';
+}
+
+# Column ordering with literal SQL
+{
+  my $ordered = $rs->search(undef, { order_by => \'artistid DESC' });
+  ok $ordered->is_ordered, 'resultset with literal SQL is_ordered';
+}
+
+# Multiple column ordering
+{
+  my $ordered = $rs->search(undef, { order_by => ['artistid', 'name'] });
+  ok $ordered->is_ordered, 'ordering with multiple columns as arrayref is ordered';
+}
+
+# More complicated ordering
+{
+  my $ordered = $rs->search(undef, { 
+    order_by => [
+      { -asc => 'artistid' }, 
+      { -desc => 'name' },
+    ] 
+  });
+  ok $ordered->is_ordered, 'more complicated resultset ordering is_ordered';
+}
+
+# Empty multi-column ordering arrayref
+{
+  my $ordered = $rs->search(undef, { order_by => [] });
+  ok !$ordered->is_ordered, 'ordering with empty arrayref is not ordered';
+}
+
+# Multi-column ordering syntax with empty hashref
+{
+  my $ordered = $rs->search(undef, { order_by => [{}] });
+  ok !$ordered->is_ordered, 'ordering with [{}] is not ordered';
+}
+
+# Remove ordering after being set
+{
+  my $ordered = $rs->search(undef, { order_by => 'artistid' });
+  ok $ordered->is_ordered, 'resultset with ordering applied works..';
+  my $unordered = $ordered->search(undef, { order_by => undef });
+  ok !$unordered->is_ordered, '..and is not ordered with ordering removed';
+}
+
+# Search without ordering
+{
+  my $ordered = $rs->search({ name => 'We Are Goth' }, { join => 'cds' });
+  ok !$ordered->is_ordered, 'WHERE clause but no order_by is not ordered';
+}
+
+# Other functions without ordering
+{
+  # Join
+  my $joined = $rs->search(undef, { join => 'cds' });
+  ok !$joined->is_ordered, 'join but no order_by is not ordered';
+
+  # Group By
+  my $grouped = $rs->search(undef, { group_by => 'rank' });
+  ok !$grouped->is_ordered, 'group_by but no order_by is not ordered';
+
+  # Paging
+  my $paged = $rs->search(undef, { page=> 5 });
+  ok !$paged->is_ordered, 'paging but no order_by is not ordered';
+}
+
+done_testing;

Added: DBIx-Class/0.08/branches/group_by_consistency/t/row/inflate_result.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/row/inflate_result.t	                        (rev 0)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/row/inflate_result.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -0,0 +1,111 @@
+package My::Schema::Result::User;
+
+use strict;
+use warnings;
+use base qw/DBIx::Class::Core/;
+
+### Define what our admin class is, for ensure_class_loaded()
+my $admin_class = __PACKAGE__ . '::Admin';
+
+__PACKAGE__->table('users');
+
+__PACKAGE__->add_columns(
+    qw/user_id   email    password
+      firstname lastname active
+      admin/
+);
+
+__PACKAGE__->set_primary_key('user_id');
+
+sub inflate_result {
+    my $self = shift;
+    my $ret  = $self->next::method(@_);
+    if ( $ret->admin ) {    ### If this is an admin, rebless for extra functions
+        $self->ensure_class_loaded($admin_class);
+        bless $ret, $admin_class;
+    }
+    return $ret;
+}
+
+sub hello {
+    return "I am a regular user.";
+}
+
+package My::Schema::Result::User::Admin;
+
+use strict;
+use warnings;
+use base qw/My::Schema::Result::User/;
+
+# This line is important
+__PACKAGE__->table('users');
+
+sub hello {
+    return "I am an admin.";
+}
+
+sub do_admin_stuff {
+    return "I am doing admin stuff";
+}
+
+package My::Schema;
+
+use base qw/DBIx::Class::Schema/;
+
+My::Schema->register_class( Admin => 'My::Schema::Result::User::Admin' );
+My::Schema->register_class( User  => 'My::Schema::Result::User' );
+
+1;
+
+package main;
+
+use lib qw(t/lib);
+use DBICTest;
+
+use Test::More;
+
+my $user_data = {
+    email    => 'someguy at place.com',
+    password => 'pass1',
+    admin    => 0
+};
+
+my $admin_data = {
+    email    => 'someadmin at adminplace.com',
+    password => 'pass2',
+    admin    => 1
+};
+
+ok( my $schema = My::Schema->connection('dbi:SQLite:dbname=:memory:') );
+
+ok(
+    $schema->storage->dbh->do(
+"create table users (user_id, email, password, firstname, lastname, active,  admin)"
+    )
+);
+
+TODO: {
+    local $TODO = 'New objects should also be inflated';
+    my $user  = $schema->resultset('User')->create($user_data);
+    my $admin = $schema->resultset('User')->create($admin_data);
+
+    is( ref $user,  'My::Schema::Result::User' );
+    is( ref $admin, 'My::Schema::Result::User::Admin' );
+
+}
+
+my $user  = $schema->resultset('User')->single($user_data);
+my $admin = $schema->resultset('User')->single($admin_data);
+
+is( ref $user,  'My::Schema::Result::User' );
+is( ref $admin, 'My::Schema::Result::User::Admin' );
+
+is( $user->password,  'pass1' );
+is( $admin->password, 'pass2' );
+is( $user->hello,     'I am a regular user.' );
+is( $admin->hello,    'I am an admin.' );
+
+ok( !$user->can('do_admin_stuff') );
+ok( $admin->can('do_admin_stuff') );
+
+done_testing;

Added: DBIx-Class/0.08/branches/group_by_consistency/t/row/pkless.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/row/pkless.t	                        (rev 0)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/row/pkless.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -0,0 +1,32 @@
+use strict;
+use warnings;
+
+use Test::More;
+use Test::Exception;
+
+use lib qw(t/lib);
+use DBICTest;
+
+my $schema = DBICTest->init_schema();
+
+my $rs = $schema->resultset('NoPrimaryKey');
+
+my $row = $rs->create ({ foo => 1, bar => 1, baz => 1 });
+
+lives_ok (sub {
+  $row->foo (2);
+}, 'Set on pkless object works');
+
+is ($row->foo, 2, 'Column updated in-object');
+
+dies_ok (sub {
+  $row->update ({baz => 3});
+}, 'update() fails on pk-less object');
+
+is ($row->foo, 2, 'Column not updated by failed update()');
+
+dies_ok (sub {
+  $row->delete;
+}, 'delete() fails on pk-less object');
+
+done_testing;

Added: DBIx-Class/0.08/branches/group_by_consistency/t/search/select_chains.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/search/select_chains.t	                        (rev 0)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/search/select_chains.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -0,0 +1,61 @@
+use strict;
+use warnings;
+
+use Test::More;
+use Test::Exception;
+
+use lib qw(t/lib);
+use DBIC::SqlMakerTest;
+use DBICTest;
+
+
+my $schema = DBICTest->init_schema();
+
+my @chain = (
+  {
+    columns     => [ 'cdid' ],
+    '+columns'  => [ { title_lc => { lower => 'title' } } ],
+    '+select'   => [ 'genreid' ],
+    '+as'       => [ 'genreid' ],
+  } => 'SELECT me.cdid, LOWER( title ), me.genreid FROM cd me',
+
+  {
+    '+columns'  => [ { max_year => { max => 'me.year' }}, ],
+    '+select'   => [ { count => 'me.cdid' }, ],
+    '+as'       => [ 'cnt' ],
+  } => 'SELECT me.cdid, LOWER( title ), MAX( me.year ), me.genreid, COUNT( me.cdid ) FROM cd me',
+
+  {
+    select      => [ { min => 'me.cdid' }, ],
+    as          => [ 'min_id' ],
+  } => 'SELECT MIN( me.cdid ) FROM cd me',
+
+  {
+    '+columns' => [ { cnt => { count => 'cdid' } } ],
+  } => 'SELECT MIN( me.cdid ), COUNT ( cdid ) FROM cd me',
+
+  {
+    columns => [ 'year' ],
+  } => 'SELECT me.year FROM cd me',
+);
+
+my $rs = $schema->resultset('CD');
+
+my $testno = 1;
+while (@chain) {
+  my $attrs = shift @chain;
+  my $sql = shift @chain;
+
+  $rs = $rs->search ({}, $attrs);
+
+  is_same_sql_bind (
+    $rs->as_query,
+    "($sql)",
+    [],
+    "Test $testno of SELECT assembly ok",
+  );
+
+  $testno++;
+}
+
+done_testing;

Added: DBIx-Class/0.08/branches/group_by_consistency/t/sqlahacks/limit_dialects/rno.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/sqlahacks/limit_dialects/rno.t	                        (rev 0)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/sqlahacks/limit_dialects/rno.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -0,0 +1,74 @@
+use strict;
+use warnings;
+
+use Test::More;
+use lib qw(t/lib);
+use DBICTest;
+use DBIC::SqlMakerTest;
+
+my $schema = DBICTest->init_schema;
+
+$schema->storage->_sql_maker->limit_dialect ('RowNumberOver');
+
+my $rs_selectas_col = $schema->resultset ('BooksInLibrary')->search ({}, {
+  '+select' => ['owner.name'],
+  '+as' => ['owner.name'],
+  join => 'owner',
+  rows => 1,
+});
+
+is_same_sql_bind(
+  $rs_selectas_col->as_query,
+  '(
+    SELECT  id, source, owner, title, price,
+            owner__name
+      FROM (
+        SELECT  id, source, owner, title, price,
+                owner__name,
+                ROW_NUMBER() OVER( ) AS rno__row__index
+          FROM (
+            SELECT  me.id, me.source, me.owner, me.title, me.price,
+                    owner.name AS owner__name
+              FROM books me
+              JOIN owners owner ON owner.id = me.owner
+            WHERE ( source = ? )
+          ) me
+      ) me
+    WHERE rno__row__index BETWEEN 1 AND 1
+  )',
+  [  [ 'source', 'Library' ] ],
+);
+
+$schema->storage->_sql_maker->quote_char ([qw/ [ ] /]);
+$schema->storage->_sql_maker->name_sep ('.');
+
+my $rs_selectas_rel = $schema->resultset ('BooksInLibrary')->search ({}, {
+  '+select' => ['owner.name'],
+  '+as' => ['owner_name'],
+  join => 'owner',
+  rows => 1,
+});
+
+is_same_sql_bind(
+  $rs_selectas_rel->as_query,
+  '(
+    SELECT  [id], [source], [owner], [title], [price],
+            [owner_name]
+      FROM (
+        SELECT  [id], [source], [owner], [title], [price],
+                [owner_name],
+                ROW_NUMBER() OVER( ) AS [rno__row__index]
+          FROM (
+            SELECT  [me].[id], [me].[source], [me].[owner], [me].[title], [me].[price],
+                    [owner].[name] AS [owner_name]
+              FROM [books] [me]
+              JOIN [owners] [owner] ON [owner].[id] = [me].[owner]
+            WHERE ( [source] = ? )
+          ) [me]
+      ) [me]
+    WHERE [rno__row__index] BETWEEN 1 AND 1
+  )',
+  [ [ 'source', 'Library' ] ],
+);
+
+done_testing;

Copied: DBIx-Class/0.08/branches/group_by_consistency/t/sqlahacks/limit_dialects/rownum.t (from rev 8546, DBIx-Class/0.08/branches/group_by_consistency/t/41orrible.t)
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/sqlahacks/limit_dialects/rownum.t	                        (rev 0)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/sqlahacks/limit_dialects/rownum.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -0,0 +1,35 @@
+use strict;
+use warnings;
+
+use Test::More;
+
+use lib qw(t/lib);
+use DBICTest;
+use DBIC::SqlMakerTest;
+
+my $s = DBICTest->init_schema (no_deploy => 1, );
+$s->storage->sql_maker->limit_dialect ('RowNum');
+
+my $rs = $s->resultset ('CD');
+
+is_same_sql_bind (
+  $rs->search ({}, { rows => 1, offset => 3,columns => [
+      { id => 'foo.id' },
+      { 'bar.id' => 'bar.id' },
+      { bleh => \ 'TO_CHAR (foo.womble, "blah")' },
+    ]})->as_query,
+  '(SELECT id, bar__id, bleh
+      FROM (
+        SELECT id, bar__id, bleh, ROWNUM rownum__index
+          FROM (
+            SELECT foo.id AS id, bar.id AS bar__id, TO_CHAR(foo.womble, "blah") AS bleh
+              FROM cd me
+          ) me
+      ) me
+    WHERE rownum__index BETWEEN 4 AND 4
+  )',
+  [],
+  'Rownum subsel aliasing works correctly'
+);
+
+done_testing;

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/sqlahacks/limit_dialects/toplimit.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/sqlahacks/limit_dialects/toplimit.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/sqlahacks/limit_dialects/toplimit.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -14,139 +14,184 @@
 delete $schema->storage->_sql_maker->{_cached_syntax};
 $schema->storage->_sql_maker->limit_dialect ('Top');
 
-my $rs = $schema->resultset ('BooksInLibrary')->search ({}, { prefetch => 'owner', rows => 1, offset => 3 });
+my $books_45_and_owners = $schema->resultset ('BooksInLibrary')->search ({}, { prefetch => 'owner', rows => 2, offset => 3 });
 
-sub default_test_order {
-   my $order_by = shift;
-   is_same_sql_bind(
-      $rs->search ({}, {order_by => $order_by})->as_query,
-      "(SELECT
-        TOP 1 me__id, source, owner, title, price, owner__id, name FROM
-         (SELECT
-           TOP 4 me.id AS me__id, me.source, me.owner, me.title, me.price, owner.id AS owner__id, owner.name
-           FROM books me
-           JOIN owners owner ON
-           owner.id = me.owner
-           WHERE ( source = ? )
-           ORDER BY me__id ASC
-         ) me ORDER BY me__id DESC
-       )",
+for my $null_order (
+  undef,
+  '',
+  {},
+  [],
+  [{}],
+) {
+  my $rs = $books_45_and_owners->search ({}, {order_by => $null_order });
+  is_same_sql_bind(
+      $rs->as_query,
+      '(SELECT TOP 2
+            id, source, owner, title, price, owner__id, owner__name
+          FROM (
+            SELECT TOP 5
+                me.id, me.source, me.owner, me.title, me.price, owner.id AS owner__id, owner.name AS owner__name
+              FROM books me
+              JOIN owners owner ON owner.id = me.owner
+            WHERE ( source = ? )
+            ORDER BY me.id
+          ) me
+        ORDER BY me.id DESC
+       )',
     [ [ source => 'Library' ] ],
   );
 }
 
-sub test_order {
-  my $args = shift;
 
-  my $req_order = $args->{order_req}
-    ? "ORDER BY $args->{order_req}"
-    : ''
-  ;
-
-  is_same_sql_bind(
-    $rs->search ({}, {order_by => $args->{order_by}})->as_query,
-    "(SELECT
-      me__id, source, owner, title, price, owner__id, name FROM
-      (SELECT
-        TOP 1 me__id, source, owner, title, price, owner__id, name FROM
-         (SELECT
-           TOP 4 me.id AS me__id, me.source, me.owner, me.title, me.price, owner.id AS owner__id, owner.name FROM
-           books me
-           JOIN owners owner ON owner.id = me.owner
-           WHERE ( source = ? )
-           ORDER BY $args->{order_inner}
-         ) me ORDER BY $args->{order_outer}
-      ) me $req_order
-    )",
-    [ [ source => 'Library' ] ],
-  );
-}
-
-my @tests = (
+for my $ord_set (
   {
     order_by => \'foo DESC',
-    order_req => 'foo DESC',
     order_inner => 'foo DESC',
-    order_outer => 'foo ASC'
+    order_outer => 'ORDER__BY__1 ASC',
+    order_req => 'ORDER__BY__1 DESC',
+    exselect_outer => 'ORDER__BY__1',
+    exselect_inner => 'foo AS ORDER__BY__1',
   },
   {
     order_by => { -asc => 'foo'  },
-    order_req => 'foo ASC',
     order_inner => 'foo ASC',
-    order_outer => 'foo DESC',
+    order_outer => 'ORDER__BY__1 DESC',
+    order_req => 'ORDER__BY__1 ASC',
+    exselect_outer => 'ORDER__BY__1',
+    exselect_inner => 'foo AS ORDER__BY__1',
   },
   {
-    order_by => 'foo',
-    order_req => 'foo',
-    order_inner => 'foo ASC',
-    order_outer => 'foo DESC',
+    order_by => { -desc => 'foo' },
+    order_inner => 'foo DESC',
+    order_outer => 'ORDER__BY__1 ASC',
+    order_req => 'ORDER__BY__1 DESC',
+    exselect_outer => 'ORDER__BY__1',
+    exselect_inner => 'foo AS ORDER__BY__1',
   },
   {
-    order_by => [ qw{ foo bar}   ],
-    order_req => 'foo, bar',
-    order_inner => 'foo ASC, bar ASC',
-    order_outer => 'foo DESC, bar DESC',
+    order_by => 'foo',
+    order_inner => 'foo',
+    order_outer => 'ORDER__BY__1 DESC',
+    order_req => 'ORDER__BY__1',
+    exselect_outer => 'ORDER__BY__1',
+    exselect_inner => 'foo AS ORDER__BY__1',
   },
   {
-    order_by => { -desc => 'foo' },
-    order_req => 'foo DESC',
-    order_inner => 'foo DESC',
-    order_outer => 'foo ASC',
+    order_by => [ qw{ foo me.owner}   ],
+    order_inner => 'foo, me.owner',
+    order_outer => 'ORDER__BY__1 DESC, me.owner DESC',
+    order_req => 'ORDER__BY__1, me.owner',
+    exselect_outer => 'ORDER__BY__1',
+    exselect_inner => 'foo AS ORDER__BY__1',
   },
   {
     order_by => ['foo', { -desc => 'bar' } ],
-    order_req => 'foo, bar DESC',
-    order_inner => 'foo ASC, bar DESC',
-    order_outer => 'foo DESC, bar ASC',
+    order_inner => 'foo, bar DESC',
+    order_outer => 'ORDER__BY__1 DESC, ORDER__BY__2 ASC',
+    order_req => 'ORDER__BY__1, ORDER__BY__2 DESC',
+    exselect_outer => 'ORDER__BY__1, ORDER__BY__2',
+    exselect_inner => 'foo AS ORDER__BY__1, bar AS ORDER__BY__2',
   },
   {
     order_by => { -asc => [qw{ foo bar }] },
-    order_req => 'foo ASC, bar ASC',
     order_inner => 'foo ASC, bar ASC',
-    order_outer => 'foo DESC, bar DESC',
+    order_outer => 'ORDER__BY__1 DESC, ORDER__BY__2 DESC',
+    order_req => 'ORDER__BY__1 ASC, ORDER__BY__2 ASC',
+    exselect_outer => 'ORDER__BY__1, ORDER__BY__2',
+    exselect_inner => 'foo AS ORDER__BY__1, bar AS ORDER__BY__2',
   },
   {
     order_by => [
-      { -asc => 'foo' },
+      'foo',
       { -desc => [qw{bar}] },
-      { -asc  => [qw{hello sensors}]},
+      { -asc  => [qw{me.owner sensors}]},
     ],
-    order_req => 'foo ASC, bar DESC, hello ASC, sensors ASC',
-    order_inner => 'foo ASC, bar DESC, hello ASC, sensors ASC',
-    order_outer => 'foo DESC, bar ASC, hello DESC, sensors DESC',
+    order_inner => 'foo, bar DESC, me.owner ASC, sensors ASC',
+    order_outer => 'ORDER__BY__1 DESC, ORDER__BY__2 ASC, me.owner DESC, ORDER__BY__3 DESC',
+    order_req => 'ORDER__BY__1, ORDER__BY__2 DESC, me.owner ASC, ORDER__BY__3 ASC',
+    exselect_outer => 'ORDER__BY__1, ORDER__BY__2, ORDER__BY__3',
+    exselect_inner => 'foo AS ORDER__BY__1, bar AS ORDER__BY__2, sensors AS ORDER__BY__3',
   },
-);
+) {
+  my $o_sel = $ord_set->{exselect_outer}
+    ? ', ' . $ord_set->{exselect_outer}
+    : ''
+  ;
+  my $i_sel = $ord_set->{exselect_inner}
+    ? ', ' . $ord_set->{exselect_inner}
+    : ''
+  ;
 
-my @default_tests = ( undef, '', {}, [] );
+  is_same_sql_bind(
+    $books_45_and_owners->search ({}, {order_by => $ord_set->{order_by}})->as_query,
+    "(SELECT TOP 2
+          id, source, owner, title, price, owner__id, owner__name
+        FROM (
+          SELECT TOP 2
+              id, source, owner, title, price, owner__id, owner__name$o_sel
+            FROM (
+              SELECT TOP 5
+                  me.id, me.source, me.owner, me.title, me.price, owner.id AS owner__id, owner.name AS owner__name$i_sel
+                FROM books me
+                JOIN owners owner ON owner.id = me.owner
+              WHERE ( source = ? )
+              ORDER BY $ord_set->{order_inner}
+            ) me
+          ORDER BY $ord_set->{order_outer}
+        ) me
+      ORDER BY $ord_set->{order_req}
+    )",
+    [ [ source => 'Library' ] ],
+  );
+}
 
-plan (tests => scalar @tests + scalar @default_tests + 1);
-
-test_order ($_) for @tests;
-default_test_order ($_) for @default_tests;
-
-
+# with groupby
 is_same_sql_bind (
-  $rs->search ({}, { group_by => 'title', order_by => 'title' })->as_query,
-'(SELECT
-me.id, me.source, me.owner, me.title, me.price, owner.id, owner.name FROM
-   ( SELECT
-      id, source, owner, title, price FROM
-      ( SELECT
-         TOP 1 id, source, owner, title, price FROM
-         ( SELECT
-            TOP 4 me.id, me.source, me.owner, me.title, me.price FROM
-            books me  JOIN
-            owners owner ON owner.id = me.owner
-            WHERE ( source = ? )
-            GROUP BY title
-            ORDER BY title ASC
-         ) me
-         ORDER BY title DESC
+  $books_45_and_owners->search ({}, { group_by => 'title', order_by => 'title' })->as_query,
+  '(SELECT me.id, me.source, me.owner, me.title, me.price, owner.id, owner.name
+      FROM (
+        SELECT TOP 2 id, source, owner, title, price
+          FROM (
+            SELECT TOP 2
+                id, source, owner, title, price, ORDER__BY__1
+              FROM (
+                SELECT TOP 5
+                    me.id, me.source, me.owner, me.title, me.price, title AS ORDER__BY__1
+                  FROM books me
+                  JOIN owners owner ON owner.id = me.owner
+                WHERE ( source = ? )
+                GROUP BY title
+                ORDER BY title
+              ) me
+            ORDER BY ORDER__BY__1 DESC
+          ) me
+        ORDER BY ORDER__BY__1
       ) me
-      ORDER BY title
-   ) me  JOIN
-   owners owner ON owner.id = me.owner WHERE
-   ( source = ? )
-   ORDER BY title)' ,
+      JOIN owners owner ON owner.id = me.owner
+    WHERE ( source = ? )
+    ORDER BY title
+  )',
   [ [ source => 'Library' ], [ source => 'Library' ] ],
 );
+
+# test deprecated column mixing over join boundaries
+my $rs_selectas_top = $schema->resultset ('BooksInLibrary')->search ({}, {
+  '+select' => ['owner.name'],
+  '+as' => ['owner_name'],
+  join => 'owner',
+  rows => 1 
+});
+
+is_same_sql_bind( $rs_selectas_top->search({})->as_query,
+                  '(SELECT
+                      TOP 1 me.id, me.source, me.owner, me.title, me.price,
+                      owner.name AS owner_name
+                    FROM books me
+                    JOIN owners owner ON owner.id = me.owner
+                    WHERE ( source = ? )
+                    ORDER BY me.id
+                   )',
+                   [ [ 'source', 'Library' ] ],
+                );
+
+done_testing;

Copied: DBIx-Class/0.08/branches/group_by_consistency/t/sqlahacks/oraclejoin.t (from rev 8546, DBIx-Class/0.08/branches/group_by_consistency/t/41orrible.t)
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/sqlahacks/oraclejoin.t	                        (rev 0)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/sqlahacks/oraclejoin.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -0,0 +1,71 @@
+use strict;
+use warnings;
+
+use Test::More;
+
+use lib qw(t/lib);
+use DBIx::Class::SQLAHacks::OracleJoins;
+use DBICTest;
+use DBIC::SqlMakerTest;
+
+my $sa = new DBIx::Class::SQLAHacks::OracleJoins;
+
+# search with undefined or empty $cond
+
+#  my ($self, $table, $fields, $where, $order, @rest) = @_;
+my ($sql, @bind) = $sa->select(
+    [
+        { me => "cd" },
+        [
+            { "-join_type" => "LEFT", artist => "artist" },
+            { "artist.artistid" => "me.artist" },
+        ],
+    ],
+    [ 'cd.cdid', 'cd.artist', 'cd.title', 'cd.year', 'artist.artistid', 'artist.name' ],
+    undef,
+    undef
+);
+is_same_sql_bind(
+  $sql, \@bind,
+  'SELECT cd.cdid, cd.artist, cd.title, cd.year, artist.artistid, artist.name FROM cd me, artist artist WHERE ( artist.artistid(+) = me.artist )', [],
+  'WhereJoins search with empty where clause'
+);
+
+($sql, @bind) = $sa->select(
+    [
+        { me => "cd" },
+        [
+            { "-join_type" => "", artist => "artist" },
+            { "artist.artistid" => "me.artist" },
+        ],
+    ],
+    [ 'cd.cdid', 'cd.artist', 'cd.title', 'cd.year', 'artist.artistid', 'artist.name' ],
+    { 'artist.artistid' => 3 },
+    undef
+);
+is_same_sql_bind(
+  $sql, \@bind,
+  'SELECT cd.cdid, cd.artist, cd.title, cd.year, artist.artistid, artist.name FROM cd me, artist artist WHERE ( ( ( artist.artistid = me.artist ) AND ( artist.artistid = ? ) ) )', [3],
+  'WhereJoins search with where clause'
+);
+
+($sql, @bind) = $sa->select(
+    [
+        { me => "cd" },
+        [
+            { "-join_type" => "LEFT", artist => "artist" },
+            { "artist.artistid" => "me.artist" },
+        ],
+    ],
+    [ 'cd.cdid', 'cd.artist', 'cd.title', 'cd.year', 'artist.artistid', 'artist.name' ],
+    [{ 'artist.artistid' => 3 }, { 'me.cdid' => 5 }],
+    undef
+);
+is_same_sql_bind(
+  $sql, \@bind,
+  'SELECT cd.cdid, cd.artist, cd.title, cd.year, artist.artistid, artist.name FROM cd me, artist artist WHERE ( ( ( artist.artistid(+) = me.artist ) AND ( ( ( artist.artistid = ? ) OR ( me.cdid = ? ) ) ) ) )', [3, 5],
+  'WhereJoins search with or in where clause'
+);
+
+done_testing;
+

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/sqlahacks/quotes/quotes.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/sqlahacks/quotes/quotes.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/sqlahacks/quotes/quotes.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -6,14 +6,7 @@
 use lib qw(t/lib);
 use DBIC::SqlMakerTest;
 
-BEGIN {
-    eval "use DBD::SQLite";
-    plan $@
-        ? ( skip_all => 'needs DBD::SQLite for testing' )
-        : ( tests => 7 );
-}
 
-
 use_ok('DBICTest');
 use_ok('DBIC::DebugObj');
 my $schema = DBICTest->init_schema();
@@ -72,3 +65,5 @@
 $schema->storage->sql_maker->name_sep('.');
 
 is($schema->storage->sql_maker->update('group', \%data), 'UPDATE `group` SET `name` = ?, `order` = ?', 'quoted table names for UPDATE');
+
+done_testing;

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/sqlahacks/quotes/quotes_newstyle.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/sqlahacks/quotes/quotes_newstyle.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/sqlahacks/quotes/quotes_newstyle.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -6,13 +6,6 @@
 use lib qw(t/lib);
 use DBIC::SqlMakerTest;
 
-BEGIN {
-    eval "use DBD::SQLite";
-    plan $@
-        ? ( skip_all => 'needs DBD::SQLite for testing' )
-        : ( tests => 7 );
-}
-
 use_ok('DBICTest');
 use_ok('DBIC::DebugObj');
 
@@ -89,3 +82,5 @@
 );
 
 is($schema->storage->sql_maker->update('group', \%data), 'UPDATE `group` SET `name` = ?, `order` = ?', 'quoted table names for UPDATE');
+
+done_testing;

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/sqlahacks/sql_maker/sql_maker_quote.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/sqlahacks/sql_maker/sql_maker_quote.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/sqlahacks/sql_maker/sql_maker_quote.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -48,7 +48,7 @@
             'artist.name' => 'Caterwauler McCrae',
             'me.year' => 2001
           },
-          [],
+          {},
           undef,
           undef
 );
@@ -80,7 +80,7 @@
             'me.year'
           ],
           undef,
-          'year DESC',
+          { order_by => 'year DESC' },
           undef,
           undef
 );
@@ -105,10 +105,10 @@
             'me.year'
           ],
           undef,
-          [
+          { order_by => [
             'year DESC',
             'title ASC'
-          ],
+          ]},
           undef,
           undef
 );
@@ -133,7 +133,7 @@
               'me.year'
             ],
             undef,
-            { -desc => 'year' },
+            { order_by => { -desc => 'year' } },
             undef,
             undef
   );
@@ -158,10 +158,10 @@
               'me.year'
             ],
             undef,
-            [
+            { order_by => [
               { -desc => 'year' },
-              { -asc => 'title' }
-            ],
+              { -asc => 'title' },
+            ]},
             undef,
             undef
   );
@@ -188,7 +188,7 @@
             'me.year'
           ],
           undef,
-          \'year DESC',
+          { order_by => \'year DESC' },
           undef,
           undef
 );
@@ -213,10 +213,10 @@
             'me.year'
           ],
           undef,
-          [
+          { order_by => [
             \'year DESC',
             \'title ASC'
-          ],
+          ]},
           undef,
           undef
 );
@@ -283,9 +283,9 @@
           'me.*'
         ],
         undef,
-        [],
         undef,
-        undef    
+        undef,
+        undef,
   );
 
   is_same_sql_bind(
@@ -328,9 +328,9 @@
             'artist.name' => 'Caterwauler McCrae',
             'me.year' => 2001
           },
-          [],
           undef,
-          undef
+          undef,
+          undef,
 );
 
 is_same_sql_bind(

Added: DBIx-Class/0.08/branches/group_by_consistency/t/sqlahacks/sqlite.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/sqlahacks/sqlite.t	                        (rev 0)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/sqlahacks/sqlite.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -0,0 +1,16 @@
+use strict;
+use warnings;
+
+use Test::More;
+use lib qw(t/lib);
+use DBICTest;
+use DBIC::SqlMakerTest;
+
+my $schema = DBICTest->init_schema;
+
+is_same_sql_bind(
+  $schema->resultset('Artist')->search ({}, {for => 'update'})->as_query,
+  '(SELECT me.artistid, me.name, me.rank, me.charfield FROM artist me)', [],
+);
+
+done_testing;

Added: DBIx-Class/0.08/branches/group_by_consistency/t/storage/dbi_env.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/storage/dbi_env.t	                        (rev 0)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/storage/dbi_env.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -0,0 +1,90 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+use lib qw(t/lib);
+use DBICTest;
+use Test::More;
+use Test::Exception;
+
+BEGIN { delete @ENV{qw(DBI_DSN DBI_DRIVER)} }
+
+my $schema;
+
+DBICTest->init_schema(sqlite_use_file => 1);
+
+my $dbname = DBICTest->_sqlite_dbname(sqlite_use_file => 1);
+
+sub count_sheep {
+    my $schema = shift;
+    scalar $schema->resultset('Artist')->search( { name => "Exploding Sheep" } )
+        ->all;
+}
+
+$schema = DBICTest::Schema->connect("dbi::$dbname");
+throws_ok { count_sheep($schema) } qr{I can't work out what driver to use},
+    'Driver in DSN empty';
+isa_ok $schema->storage, 'DBIx::Class::Storage::DBI';
+
+$schema = DBICTest::Schema->connect("dbi:Test_NonExistant_DBD:$dbname");
+throws_ok { count_sheep($schema) }
+    qr{Can't locate DBD/Test_NonExistant_DBD\.pm in \@INC},
+    "Driver class doesn't exist";
+isa_ok $schema->storage, 'DBIx::Class::Storage::DBI';
+
+$ENV{DBI_DSN} = "dbi::$dbname";
+$schema = DBICTest::Schema->connect;
+throws_ok { count_sheep($schema) } qr{I can't work out what driver to use},
+    "Driver class not defined in DBI_DSN either.";
+isa_ok $schema->storage, 'DBIx::Class::Storage::DBI';
+
+$ENV{DBI_DSN} = "dbi:Test_NonExistant_DBD2:$dbname";
+$schema = DBICTest::Schema->connect;
+throws_ok { count_sheep($schema) }
+    qr{Can't locate DBD/Test_NonExistant_DBD2\.pm in \@INC},
+    "Driver class defined in DBI_DSN doesn't exist";
+isa_ok $schema->storage, 'DBIx::Class::Storage::DBI';
+
+$ENV{DBI_DSN} = "dbi::$dbname";
+$ENV{DBI_DRIVER} = 'Test_NonExistant_DBD3';
+$schema = DBICTest::Schema->connect;
+throws_ok { count_sheep($schema) }
+    qr{Can't locate DBD/Test_NonExistant_DBD3\.pm in \@INC},
+    "Driver class defined in DBI_DRIVER doesn't exist";
+isa_ok $schema->storage, 'DBIx::Class::Storage::DBI';
+
+$ENV{DBI_DSN} = "dbi:Test_NonExistant_DBD4:$dbname";
+$schema = DBICTest::Schema->connect;
+throws_ok { count_sheep($schema) }
+qr{Can't locate DBD/Test_NonExistant_DBD4\.pm in \@INC},
+    "Driver class defined in DBI_DSN doesn't exist";
+isa_ok $schema->storage, 'DBIx::Class::Storage::DBI';
+
+delete @ENV{qw(DBI_DSN DBI_DRIVER)};
+
+$schema = DBICTest::Schema->connect("dbi:SQLite:$dbname");
+lives_ok { count_sheep($schema) } 'SQLite passed to connect_info';
+isa_ok $schema->storage, 'DBIx::Class::Storage::DBI::SQLite';
+
+$ENV{DBI_DRIVER} = 'SQLite';
+$schema = DBICTest::Schema->connect("dbi::$dbname");
+lives_ok { count_sheep($schema) } 'SQLite in DBI_DRIVER';
+isa_ok $schema->storage, 'DBIx::Class::Storage::DBI::SQLite';
+
+delete $ENV{DBI_DRIVER};
+$ENV{DBI_DSN} = "dbi:SQLite:$dbname";
+$schema = DBICTest::Schema->connect;
+lives_ok { count_sheep($schema) } 'SQLite in DBI_DSN';
+isa_ok $schema->storage, 'DBIx::Class::Storage::DBI::SQLite';
+
+$ENV{DBI_DRIVER} = 'SQLite';
+$schema = DBICTest::Schema->connect;
+lives_ok { count_sheep($schema) } 'SQLite in DBI_DSN (and DBI_DRIVER)';
+isa_ok $schema->storage, 'DBIx::Class::Storage::DBI::SQLite';
+
+$ENV{DBI_DSN} = "dbi::$dbname";
+$ENV{DBI_DRIVER} = 'SQLite';
+$schema = DBICTest::Schema->connect;
+lives_ok { count_sheep($schema) } 'SQLite in DBI_DRIVER (not DBI_DSN)';
+isa_ok $schema->storage, 'DBIx::Class::Storage::DBI::SQLite';
+
+done_testing;

Added: DBIx-Class/0.08/branches/group_by_consistency/t/storage/deploy.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/storage/deploy.t	                        (rev 0)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/storage/deploy.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -0,0 +1,32 @@
+use strict;
+use warnings;
+
+use Test::More;
+
+use lib qw(t/lib);
+use DBICTest;
+
+use File::Spec;
+use File::Path qw/ mkpath rmtree /;
+
+
+my $schema = DBICTest->init_schema();
+
+my $var = File::Spec->catfile(qw| t var create_ddl_dir |);
+-d $var
+    or mkpath($var)
+    or die "can't create $var";
+
+my $test_dir_1 =  File::Spec->catdir( $var, 'test1', 'foo', 'bar' );
+rmtree( $test_dir_1 ) if -d $test_dir_1;
+$schema->create_ddl_dir( undef, undef, $test_dir_1 );
+
+ok( -d $test_dir_1, 'create_ddl_dir did a mkpath on its target dir' );
+ok( scalar( glob $test_dir_1.'/*.sql' ), 'there are sql files in there' );
+
+TODO: {
+    local $TODO = 'we should probably add some tests here for actual deployability of the DDL?';
+    ok( 0 );
+}
+
+done_testing;

Modified: DBIx-Class/0.08/branches/group_by_consistency/t/storage/error.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/storage/error.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/storage/error.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -1,29 +1,20 @@
-use Class::C3;
 use strict;
-use Test::More;
 use warnings;
 
-BEGIN {
-    eval "use DBD::SQLite";
-    plan $@
-        ? ( skip_all => 'needs DBD::SQLite for testing' )
-        : ( tests => 4 );
-}
+use Test::More;
+use Test::Warn;
+use Test::Exception;
 
 use lib qw(t/lib);
-
 use_ok( 'DBICTest' );
 use_ok( 'DBICTest::Schema' );
+
 my $schema = DBICTest->init_schema;
 
-{
-       my $warnings;
-       local $SIG{__WARN__} = sub { $warnings .= $_[0] };
-       eval {
-         $schema->resultset('CD')
-                ->create({ title => 'vacation in antarctica' })
-       };
-       like $@, qr/NULL/;  # as opposed to some other error
-       unlike( $warnings, qr/uninitialized value/, "No warning from Storage" );
-}
+warnings_are ( sub {
+  throws_ok (sub {
+    $schema->resultset('CD')->create({ title => 'vacation in antarctica' });
+  }, qr/NULL/);  # as opposed to some other error
+}, [], 'No warnings besides exception' );
 
+done_testing;

Added: DBIx-Class/0.08/branches/group_by_consistency/t/storage/global_destruction.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/storage/global_destruction.t	                        (rev 0)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/storage/global_destruction.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -0,0 +1,57 @@
+use strict;
+use warnings;
+
+use Test::More;
+use Test::Exception;
+
+use lib qw(t/lib);
+use DBICTest;
+
+for my $type (qw/PG MYSQL/) {
+
+  SKIP: {
+    skip "Skipping $type tests without DBICTEST_${type}_DSN", 1
+      unless $ENV{"DBICTEST_${type}_DSN"};
+
+    my $schema = DBICTest::Schema->connect (@ENV{map { "DBICTEST_${type}_${_}" } qw/DSN USER PASS/});
+
+    # emulate a singleton-factory, just cache the object *somewhere in a different package*
+    # to induce out-of-order destruction
+    $DBICTest::FakeSchemaFactory::schema = $schema;
+
+    # so we can see the retry exceptions (if any)
+    $ENV{DBIC_DBIRETRY_DEBUG} = 1;
+
+    ok (!$schema->storage->connected, "$type: start disconnected");
+
+    lives_ok (sub {
+      $schema->txn_do (sub {
+
+        ok ($schema->storage->connected, "$type: transaction starts connected");
+
+        my $pid = fork();
+        SKIP: {
+          skip "Fork failed: $!", 1 if (! defined $pid);
+
+          if ($pid) {
+            note "Parent $$ sleeping...";
+            wait();
+            note "Parent $$ woken up after child $pid exit";
+          }
+          else {
+            note "Child $$ terminating";
+            exit 0;
+          }
+
+          ok ($schema->storage->connected, "$type: parent still connected (in txn_do)");
+        }
+      });
+    });
+
+    ok ($schema->storage->connected, "$type: parent still connected (outside of txn_do)");
+
+    undef $DBICTest::FakeSchemaFactory::schema;
+  }
+}
+
+done_testing;

Copied: DBIx-Class/0.08/branches/group_by_consistency/t/storage/replicated.t (from rev 8546, DBIx-Class/0.08/branches/group_by_consistency/t/storage/replication.t)
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/storage/replicated.t	                        (rev 0)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/storage/replicated.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -0,0 +1,907 @@
+use strict;
+use warnings;
+use lib qw(t/lib);
+use Test::More;
+use Test::Exception;
+use DBICTest;
+use List::Util 'first';
+use Scalar::Util 'reftype';
+use File::Spec;
+use IO::Handle;
+
+BEGIN {
+    eval { require Test::Moose; Test::Moose->import() };
+    plan skip_all => "Need Test::Moose to run this test" if $@;
+      require DBIx::Class;
+
+    plan skip_all => 'Test needs ' . DBIx::Class::Optional::Dependencies->req_missing_for ('replicated')
+      unless DBIx::Class::Optional::Dependencies->req_ok_for ('replicated');
+}
+
+use_ok 'DBIx::Class::Storage::DBI::Replicated::Pool';
+use_ok 'DBIx::Class::Storage::DBI::Replicated::Balancer';
+use_ok 'DBIx::Class::Storage::DBI::Replicated::Replicant';
+use_ok 'DBIx::Class::Storage::DBI::Replicated';
+
+use Moose();
+use MooseX::Types();
+diag "Using Moose version $Moose::VERSION and MooseX::Types version $MooseX::Types::VERSION";
+
+=head1 HOW TO USE
+
+    This is a test of the replicated storage system.  This will work in one of
+    two ways, either it was try to fake replication with a couple of SQLite DBs
+    and creative use of copy, or if you define a couple of %ENV vars correctly
+    will try to test those.  If you do that, it will assume the setup is properly
+    replicating.  Your results may vary, but I have demonstrated this to work with
+    mysql native replication.
+
+=cut
+
+
+## ----------------------------------------------------------------------------
+## Build a class to hold all our required testing data and methods.
+## ----------------------------------------------------------------------------
+
+TESTSCHEMACLASSES: {
+
+    ## --------------------------------------------------------------------- ##
+    ## Create an object to contain your replicated stuff.
+    ## --------------------------------------------------------------------- ##
+
+    package DBIx::Class::DBI::Replicated::TestReplication;
+
+    use DBICTest;
+    use base qw/Class::Accessor::Fast/;
+
+    __PACKAGE__->mk_accessors( qw/schema/ );
+
+    ## Initialize the object
+
+    sub new {
+        my ($class, $schema_method) = (shift, shift);
+        my $self = $class->SUPER::new(@_);
+
+        $self->schema( $self->init_schema($schema_method) );
+        return $self;
+    }
+
+    ## Get the Schema and set the replication storage type
+
+    sub init_schema {
+        # current SQLT SQLite producer does not handle DROP TABLE IF EXISTS, trap warnings here
+        local $SIG{__WARN__} = sub { warn @_ unless $_[0] =~ /no such table.+DROP TABLE/s };
+
+        my ($class, $schema_method) = @_;
+
+        my $method = "get_schema_$schema_method";
+        my $schema = $class->$method;
+
+        return $schema;
+    }
+
+    sub get_schema_by_storage_type {
+      DBICTest->init_schema(
+        sqlite_use_file => 1,
+        storage_type=>{
+          '::DBI::Replicated' => {
+            balancer_type=>'::Random',
+            balancer_args=>{
+              auto_validate_every=>100,
+          master_read_weight => 1
+            },
+          }
+        },
+        deploy_args=>{
+          add_drop_table => 1,
+        },
+      );
+    }
+
+    sub get_schema_by_connect_info {
+      DBICTest->init_schema(
+        sqlite_use_file => 1,
+        storage_type=> '::DBI::Replicated',
+        balancer_type=>'::Random',
+        balancer_args=> {
+          auto_validate_every=>100,
+      master_read_weight => 1
+        },
+        deploy_args=>{
+          add_drop_table => 1,
+        },
+      );
+    }
+
+    sub generate_replicant_connect_info {}
+    sub replicate {}
+    sub cleanup {}
+
+    ## --------------------------------------------------------------------- ##
+    ## Add a connect_info option to test option merging.
+    ## --------------------------------------------------------------------- ##
+    {
+    package DBIx::Class::Storage::DBI::Replicated;
+
+    use Moose;
+
+    __PACKAGE__->meta->make_mutable;
+
+    around connect_info => sub {
+      my ($next, $self, $info) = @_;
+      $info->[3]{master_option} = 1;
+      $self->$next($info);
+    };
+
+    __PACKAGE__->meta->make_immutable;
+
+    no Moose;
+    }
+
+    ## --------------------------------------------------------------------- ##
+    ## Subclass for when you are using SQLite for testing, this provides a fake
+    ## replication support.
+    ## --------------------------------------------------------------------- ##
+
+    package DBIx::Class::DBI::Replicated::TestReplication::SQLite;
+
+    use DBICTest;
+    use File::Copy;
+    use base 'DBIx::Class::DBI::Replicated::TestReplication';
+
+    __PACKAGE__->mk_accessors(qw/master_path slave_paths/);
+
+    ## Set the master path from DBICTest
+
+    sub new {
+        my $class = shift @_;
+        my $self = $class->SUPER::new(@_);
+
+        $self->master_path( DBICTest->_sqlite_dbfilename );
+        $self->slave_paths([
+            File::Spec->catfile(qw/t var DBIxClass_slave1.db/),
+            File::Spec->catfile(qw/t var DBIxClass_slave2.db/),
+        ]);
+
+        return $self;
+    }
+
+    ## Return an Array of ArrayRefs where each ArrayRef is suitable to use for
+    ## $storage->connect_info to be used for connecting replicants.
+
+    sub generate_replicant_connect_info {
+        my $self = shift @_;
+        my @dsn = map {
+            "dbi:SQLite:${_}";
+        } @{$self->slave_paths};
+
+        my @connect_infos = map { [$_,'','',{AutoCommit=>1}] } @dsn;
+
+        ## Make sure nothing is left over from a failed test
+        $self->cleanup;
+
+        ## try a hashref too
+        my $c = $connect_infos[0];
+        $connect_infos[0] = {
+          dsn => $c->[0],
+          user => $c->[1],
+          password => $c->[2],
+          %{ $c->[3] }
+        };
+
+        @connect_infos
+    }
+
+    ## Do a 'good enough' replication by copying the master dbfile over each of
+    ## the slave dbfiles.  If the master is SQLite we do this, otherwise we
+    ## just do a one second pause to let the slaves catch up.
+
+    sub replicate {
+        my $self = shift @_;
+        foreach my $slave (@{$self->slave_paths}) {
+            copy($self->master_path, $slave);
+        }
+    }
+
+    ## Cleanup after ourselves.  Unlink all gthe slave paths.
+
+    sub cleanup {
+        my $self = shift @_;
+        foreach my $slave (@{$self->slave_paths}) {
+            if(-e $slave) {
+                unlink $slave;
+            }
+        }
+    }
+
+    ## --------------------------------------------------------------------- ##
+    ## Subclass for when you are setting the databases via custom export vars
+    ## This is for when you have a replicating database setup that you are
+    ## going to test against.  You'll need to define the correct $ENV and have
+    ## two slave databases to test against, as well as a replication system
+    ## that will replicate in less than 1 second.
+    ## --------------------------------------------------------------------- ##
+
+    package DBIx::Class::DBI::Replicated::TestReplication::Custom;
+    use base 'DBIx::Class::DBI::Replicated::TestReplication';
+
+    ## Return an Array of ArrayRefs where each ArrayRef is suitable to use for
+    ## $storage->connect_info to be used for connecting replicants.
+
+    sub generate_replicant_connect_info {
+        return (
+            [$ENV{"DBICTEST_SLAVE0_DSN"}, $ENV{"DBICTEST_SLAVE0_DBUSER"}, $ENV{"DBICTEST_SLAVE0_DBPASS"}, {AutoCommit => 1}],
+            [$ENV{"DBICTEST_SLAVE1_DSN"}, $ENV{"DBICTEST_SLAVE1_DBUSER"}, $ENV{"DBICTEST_SLAVE1_DBPASS"}, {AutoCommit => 1}],
+        );
+    }
+
+    ## pause a bit to let the replication catch up
+
+    sub replicate {
+        sleep 1;
+    }
+}
+
+## ----------------------------------------------------------------------------
+## Create an object and run some tests
+## ----------------------------------------------------------------------------
+
+## Thi first bunch of tests are basic, just make sure all the bits are behaving
+
+my $replicated_class = DBICTest->has_custom_dsn ?
+    'DBIx::Class::DBI::Replicated::TestReplication::Custom' :
+    'DBIx::Class::DBI::Replicated::TestReplication::SQLite';
+
+my $replicated;
+
+for my $method (qw/by_connect_info by_storage_type/) {
+  undef $replicated;
+  ok $replicated = $replicated_class->new($method)
+      => "Created a replication object $method";
+
+  isa_ok $replicated->schema
+      => 'DBIx::Class::Schema';
+
+  isa_ok $replicated->schema->storage
+      => 'DBIx::Class::Storage::DBI::Replicated';
+
+  isa_ok $replicated->schema->storage->balancer
+      => 'DBIx::Class::Storage::DBI::Replicated::Balancer::Random'
+      => 'configured balancer_type';
+}
+
+### check that all Storage::DBI methods are handled by ::Replicated
+{
+  my @storage_dbi_methods = Class::MOP::Class
+    ->initialize('DBIx::Class::Storage::DBI')->get_all_method_names;
+
+  my @replicated_methods  = DBIx::Class::Storage::DBI::Replicated->meta
+    ->get_all_method_names;
+
+# remove constants and OTHER_CRAP
+  @storage_dbi_methods = grep !/^[A-Z_]+\z/, @storage_dbi_methods;
+
+# remove CAG accessors
+  @storage_dbi_methods = grep !/_accessor\z/, @storage_dbi_methods;
+
+# remove DBIx::Class (the root parent, with CAG and stuff) methods
+  my @root_methods = Class::MOP::Class->initialize('DBIx::Class')
+    ->get_all_method_names;
+  my %count;
+  $count{$_}++ for (@storage_dbi_methods, @root_methods);
+
+  @storage_dbi_methods = grep $count{$_} != 2, @storage_dbi_methods;
+
+# make hashes
+  my %storage_dbi_methods;
+  @storage_dbi_methods{@storage_dbi_methods} = ();
+  my %replicated_methods;
+  @replicated_methods{@replicated_methods} = ();
+
+# remove ::Replicated-specific methods
+  for my $method (@replicated_methods) {
+    delete $replicated_methods{$method}
+      unless exists $storage_dbi_methods{$method};
+  }
+  @replicated_methods = keys %replicated_methods;
+
+# check that what's left is implemented
+  %count = ();
+  $count{$_}++ for (@storage_dbi_methods, @replicated_methods);
+
+  if ((grep $count{$_} == 2, @storage_dbi_methods) == @storage_dbi_methods) {
+    pass 'all DBIx::Class::Storage::DBI methods implemented';
+  }
+  else {
+    my @unimplemented = grep $count{$_} == 1, @storage_dbi_methods;
+
+    fail 'the following DBIx::Class::Storage::DBI methods are unimplemented: '
+      . "@unimplemented";
+  }
+}
+
+ok $replicated->schema->storage->meta
+    => 'has a meta object';
+
+isa_ok $replicated->schema->storage->master
+    => 'DBIx::Class::Storage::DBI';
+
+isa_ok $replicated->schema->storage->pool
+    => 'DBIx::Class::Storage::DBI::Replicated::Pool';
+
+does_ok $replicated->schema->storage->balancer
+    => 'DBIx::Class::Storage::DBI::Replicated::Balancer';
+
+ok my @replicant_connects = $replicated->generate_replicant_connect_info
+    => 'got replication connect information';
+
+ok my @replicated_storages = $replicated->schema->storage->connect_replicants(@replicant_connects)
+    => 'Created some storages suitable for replicants';
+
+our %debug;
+$replicated->schema->storage->debug(1);
+$replicated->schema->storage->debugcb(sub {
+    my ($op, $info) = @_;
+    ##warn "\n$op, $info\n";
+    %debug = (
+        op => $op,
+        info => $info,
+        dsn => ($info=~m/\[(.+)\]/)[0],
+        storage_type => $info=~m/REPLICANT/ ? 'REPLICANT' : 'MASTER',
+    );
+});
+
+ok my @all_storages = $replicated->schema->storage->all_storages
+    => '->all_storages';
+
+is scalar @all_storages,
+    3
+    => 'correct number of ->all_storages';
+
+is ((grep $_->isa('DBIx::Class::Storage::DBI'), @all_storages),
+    3
+    => '->all_storages are correct type');
+
+my @all_storage_opts =
+  grep { (reftype($_)||'') eq 'HASH' }
+    map @{ $_->_connect_info }, @all_storages;
+
+is ((grep $_->{master_option}, @all_storage_opts),
+    3
+    => 'connect_info was merged from master to replicants');
+
+my @replicant_names = keys %{ $replicated->schema->storage->replicants };
+
+ok @replicant_names, "found replicant names @replicant_names";
+
+## Silence warning about not supporting the is_replicating method if using the
+## sqlite dbs.
+$replicated->schema->storage->debugobj->silence(1)
+  if first { m{^t/} } @replicant_names;
+
+isa_ok $replicated->schema->storage->balancer->current_replicant
+    => 'DBIx::Class::Storage::DBI';
+
+$replicated->schema->storage->debugobj->silence(0);
+
+ok $replicated->schema->storage->pool->has_replicants
+    => 'does have replicants';
+
+is $replicated->schema->storage->pool->num_replicants => 2
+    => 'has two replicants';
+
+does_ok $replicated_storages[0]
+    => 'DBIx::Class::Storage::DBI::Replicated::Replicant';
+
+does_ok $replicated_storages[1]
+    => 'DBIx::Class::Storage::DBI::Replicated::Replicant';
+
+does_ok $replicated->schema->storage->replicants->{$replicant_names[0]}
+    => 'DBIx::Class::Storage::DBI::Replicated::Replicant';
+
+does_ok $replicated->schema->storage->replicants->{$replicant_names[1]}
+    => 'DBIx::Class::Storage::DBI::Replicated::Replicant';
+
+## Add some info to the database
+
+$replicated
+    ->schema
+    ->populate('Artist', [
+        [ qw/artistid name/ ],
+        [ 4, "Ozric Tentacles"],
+    ]);
+
+    is $debug{storage_type}, 'MASTER',
+        "got last query from a master: $debug{dsn}";
+
+    like $debug{info}, qr/INSERT/, 'Last was an insert';
+
+## Make sure all the slaves have the table definitions
+
+$replicated->replicate;
+$replicated->schema->storage->replicants->{$replicant_names[0]}->active(1);
+$replicated->schema->storage->replicants->{$replicant_names[1]}->active(1);
+
+## Silence warning about not supporting the is_replicating method if using the
+## sqlite dbs.
+$replicated->schema->storage->debugobj->silence(1)
+  if first { m{^t/} } @replicant_names;
+
+$replicated->schema->storage->pool->validate_replicants;
+
+$replicated->schema->storage->debugobj->silence(0);
+
+## Make sure we can read the data.
+
+ok my $artist1 = $replicated->schema->resultset('Artist')->find(4)
+    => 'Created Result';
+
+## We removed testing here since master read weight is on, so we can't tell in
+## advance what storage to expect.  We turn master read weight off a bit lower
+## is $debug{storage_type}, 'REPLICANT'
+##     => "got last query from a replicant: $debug{dsn}, $debug{info}";
+
+isa_ok $artist1
+    => 'DBICTest::Artist';
+
+is $artist1->name, 'Ozric Tentacles'
+    => 'Found expected name for first result';
+
+## Check that master_read_weight is honored
+{
+    no warnings qw/once redefine/;
+
+    local
+    *DBIx::Class::Storage::DBI::Replicated::Balancer::Random::_random_number =
+    sub { 999 };
+
+    $replicated->schema->storage->balancer->increment_storage;
+
+    is $replicated->schema->storage->balancer->current_replicant,
+       $replicated->schema->storage->master
+       => 'master_read_weight is honored';
+
+    ## turn it off for the duration of the test
+    $replicated->schema->storage->balancer->master_read_weight(0);
+    $replicated->schema->storage->balancer->increment_storage;
+}
+
+## Add some new rows that only the master will have  This is because
+## we overload any type of write operation so that is must hit the master
+## database.
+
+$replicated
+    ->schema
+    ->populate('Artist', [
+        [ qw/artistid name/ ],
+        [ 5, "Doom's Children"],
+        [ 6, "Dead On Arrival"],
+        [ 7, "Watergate"],
+    ]);
+
+    is $debug{storage_type}, 'MASTER',
+        "got last query from a master: $debug{dsn}";
+
+    like $debug{info}, qr/INSERT/, 'Last was an insert';
+
+## Make sure all the slaves have the table definitions
+$replicated->replicate;
+
+## Should find some data now
+
+ok my $artist2 = $replicated->schema->resultset('Artist')->find(5)
+    => 'Sync succeed';
+
+is $debug{storage_type}, 'REPLICANT'
+    => "got last query from a replicant: $debug{dsn}";
+
+isa_ok $artist2
+    => 'DBICTest::Artist';
+
+is $artist2->name, "Doom's Children"
+    => 'Found expected name for first result';
+
+## What happens when we disconnect all the replicants?
+
+is $replicated->schema->storage->pool->connected_replicants => 2
+    => "both replicants are connected";
+
+$replicated->schema->storage->replicants->{$replicant_names[0]}->disconnect;
+$replicated->schema->storage->replicants->{$replicant_names[1]}->disconnect;
+
+is $replicated->schema->storage->pool->connected_replicants => 0
+    => "both replicants are now disconnected";
+
+## All these should pass, since the database should automatically reconnect
+
+ok my $artist3 = $replicated->schema->resultset('Artist')->find(6)
+    => 'Still finding stuff.';
+
+is $debug{storage_type}, 'REPLICANT'
+    => "got last query from a replicant: $debug{dsn}";
+
+isa_ok $artist3
+    => 'DBICTest::Artist';
+
+is $artist3->name, "Dead On Arrival"
+    => 'Found expected name for first result';
+
+is $replicated->schema->storage->pool->connected_replicants => 1
+    => "At Least One replicant reconnected to handle the job";
+
+## What happens when we try to select something that doesn't exist?
+
+ok ! $replicated->schema->resultset('Artist')->find(666)
+    => 'Correctly failed to find something.';
+
+is $debug{storage_type}, 'REPLICANT'
+    => "got last query from a replicant: $debug{dsn}";
+
+## test the reliable option
+
+TESTRELIABLE: {
+
+    $replicated->schema->storage->set_reliable_storage;
+
+    ok $replicated->schema->resultset('Artist')->find(2)
+        => 'Read from master 1';
+
+    is $debug{storage_type}, 'MASTER',
+        "got last query from a master: $debug{dsn}";
+
+    ok $replicated->schema->resultset('Artist')->find(5)
+        => 'Read from master 2';
+
+    is $debug{storage_type}, 'MASTER',
+        "got last query from a master: $debug{dsn}";
+
+    $replicated->schema->storage->set_balanced_storage;
+
+    ok $replicated->schema->resultset('Artist')->find(3)
+        => 'Read from replicant';
+
+    is $debug{storage_type}, 'REPLICANT',
+        "got last query from a replicant: $debug{dsn}";
+}
+
+## Make sure when reliable goes out of scope, we are using replicants again
+
+ok $replicated->schema->resultset('Artist')->find(1)
+    => 'back to replicant 1.';
+
+    is $debug{storage_type}, 'REPLICANT',
+        "got last query from a replicant: $debug{dsn}";
+
+ok $replicated->schema->resultset('Artist')->find(2)
+    => 'back to replicant 2.';
+
+    is $debug{storage_type}, 'REPLICANT',
+        "got last query from a replicant: $debug{dsn}";
+
+## set all the replicants to inactive, and make sure the balancer falls back to
+## the master.
+
+$replicated->schema->storage->replicants->{$replicant_names[0]}->active(0);
+$replicated->schema->storage->replicants->{$replicant_names[1]}->active(0);
+
+{
+    ## catch the fallback to master warning
+    open my $debugfh, '>', \my $fallback_warning;
+    my $oldfh = $replicated->schema->storage->debugfh;
+    $replicated->schema->storage->debugfh($debugfh);
+
+    ok $replicated->schema->resultset('Artist')->find(2)
+        => 'Fallback to master';
+
+    is $debug{storage_type}, 'MASTER',
+        "got last query from a master: $debug{dsn}";
+
+    like $fallback_warning, qr/falling back to master/
+        => 'emits falling back to master warning';
+
+    $replicated->schema->storage->debugfh($oldfh);
+}
+
+$replicated->schema->storage->replicants->{$replicant_names[0]}->active(1);
+$replicated->schema->storage->replicants->{$replicant_names[1]}->active(1);
+
+## Silence warning about not supporting the is_replicating method if using the
+## sqlite dbs.
+$replicated->schema->storage->debugobj->silence(1)
+  if first { m{^t/} } @replicant_names;
+
+$replicated->schema->storage->pool->validate_replicants;
+
+$replicated->schema->storage->debugobj->silence(0);
+
+ok $replicated->schema->resultset('Artist')->find(2)
+    => 'Returned to replicates';
+
+is $debug{storage_type}, 'REPLICANT',
+    "got last query from a replicant: $debug{dsn}";
+
+## Getting slave status tests
+
+SKIP: {
+    ## We skip this tests unless you have a custom replicants, since the default
+    ## sqlite based replication tests don't support these functions.
+
+    skip 'Cannot Test Replicant Status on Non Replicating Database', 10
+     unless DBICTest->has_custom_dsn && $ENV{"DBICTEST_SLAVE0_DSN"};
+
+    $replicated->replicate; ## Give the slaves a chance to catchup.
+
+    ok $replicated->schema->storage->replicants->{$replicant_names[0]}->is_replicating
+        => 'Replicants are replicating';
+
+    is $replicated->schema->storage->replicants->{$replicant_names[0]}->lag_behind_master, 0
+        => 'Replicant is zero seconds behind master';
+
+    ## Test the validate replicants
+
+    $replicated->schema->storage->pool->validate_replicants;
+
+    is $replicated->schema->storage->pool->active_replicants, 2
+        => 'Still have 2 replicants after validation';
+
+    ## Force the replicants to fail the validate test by required their lag to
+    ## be negative (ie ahead of the master!)
+
+    $replicated->schema->storage->pool->maximum_lag(-10);
+    $replicated->schema->storage->pool->validate_replicants;
+
+    is $replicated->schema->storage->pool->active_replicants, 0
+        => 'No way a replicant be be ahead of the master';
+
+    ## Let's be fair to the replicants again.  Let them lag up to 5
+
+    $replicated->schema->storage->pool->maximum_lag(5);
+    $replicated->schema->storage->pool->validate_replicants;
+
+    is $replicated->schema->storage->pool->active_replicants, 2
+        => 'Both replicants in good standing again';
+
+    ## Check auto validate
+
+    is $replicated->schema->storage->balancer->auto_validate_every, 100
+        => "Got the expected value for auto validate";
+
+        ## This will make sure we auto validatge everytime
+        $replicated->schema->storage->balancer->auto_validate_every(0);
+
+        ## set all the replicants to inactive, and make sure the balancer falls back to
+        ## the master.
+
+        $replicated->schema->storage->replicants->{$replicant_names[0]}->active(0);
+        $replicated->schema->storage->replicants->{$replicant_names[1]}->active(0);
+
+        ## Ok, now when we go to run a query, autovalidate SHOULD reconnect
+
+    is $replicated->schema->storage->pool->active_replicants => 0
+        => "both replicants turned off";
+
+    ok $replicated->schema->resultset('Artist')->find(5)
+        => 'replicant reactivated';
+
+    is $debug{storage_type}, 'REPLICANT',
+        "got last query from a replicant: $debug{dsn}";
+
+    is $replicated->schema->storage->pool->active_replicants => 2
+        => "both replicants reactivated";
+}
+
+## Test the reliably callback
+
+ok my $reliably = sub {
+
+    ok $replicated->schema->resultset('Artist')->find(5)
+        => 'replicant reactivated';
+
+    is $debug{storage_type}, 'MASTER',
+        "got last query from a master: $debug{dsn}";
+
+} => 'created coderef properly';
+
+$replicated->schema->storage->execute_reliably($reliably);
+
+## Try something with an error
+
+ok my $unreliably = sub {
+
+    ok $replicated->schema->resultset('ArtistXX')->find(5)
+        => 'replicant reactivated';
+
+} => 'created coderef properly';
+
+throws_ok {$replicated->schema->storage->execute_reliably($unreliably)}
+    qr/Can't find source for ArtistXX/
+    => 'Bad coderef throws proper error';
+
+## Make sure replication came back
+
+ok $replicated->schema->resultset('Artist')->find(3)
+    => 'replicant reactivated';
+
+is $debug{storage_type}, 'REPLICANT', "got last query from a replicant: $debug{dsn}";
+
+## make sure transactions are set to execute_reliably
+
+ok my $transaction = sub {
+
+    my $id = shift @_;
+
+    $replicated
+        ->schema
+        ->populate('Artist', [
+            [ qw/artistid name/ ],
+            [ $id, "Children of the Grave"],
+        ]);
+
+    ok my $result = $replicated->schema->resultset('Artist')->find($id)
+        => "Found expected artist for $id";
+
+    is $debug{storage_type}, 'MASTER',
+        "got last query from a master: $debug{dsn}";
+
+    ok my $more = $replicated->schema->resultset('Artist')->find(1)
+        => 'Found expected artist again for 1';
+
+    is $debug{storage_type}, 'MASTER',
+        "got last query from a master: $debug{dsn}";
+
+   return ($result, $more);
+
+} => 'Created a coderef properly';
+
+## Test the transaction with multi return
+{
+    ok my @return = $replicated->schema->txn_do($transaction, 666)
+        => 'did transaction';
+
+        is $return[0]->id, 666
+            => 'first returned value is correct';
+
+        is $debug{storage_type}, 'MASTER',
+            "got last query from a master: $debug{dsn}";
+
+        is $return[1]->id, 1
+            => 'second returned value is correct';
+
+        is $debug{storage_type}, 'MASTER',
+             "got last query from a master: $debug{dsn}";
+
+}
+
+## Test that asking for single return works
+{
+    ok my @return = $replicated->schema->txn_do($transaction, 777)
+        => 'did transaction';
+
+        is $return[0]->id, 777
+            => 'first returned value is correct';
+
+        is $return[1]->id, 1
+            => 'second returned value is correct';
+}
+
+## Test transaction returning a single value
+
+{
+    ok my $result = $replicated->schema->txn_do(sub {
+        ok my $more = $replicated->schema->resultset('Artist')->find(1)
+        => 'found inside a transaction';
+        is $debug{storage_type}, 'MASTER', "got last query from a master: $debug{dsn}";
+        return $more;
+    }) => 'successfully processed transaction';
+
+    is $result->id, 1
+       => 'Got expected single result from transaction';
+}
+
+## Make sure replication came back
+
+ok $replicated->schema->resultset('Artist')->find(1)
+    => 'replicant reactivated';
+
+is $debug{storage_type}, 'REPLICANT', "got last query from a replicant: $debug{dsn}";
+
+## Test Discard changes
+
+{
+    ok my $artist = $replicated->schema->resultset('Artist')->find(2)
+        => 'got an artist to test discard changes';
+
+    is $debug{storage_type}, 'REPLICANT', "got last query from a replicant: $debug{dsn}";
+
+    ok $artist->get_from_storage({force_pool=>'master'})
+       => 'properly discard changes';
+
+    is $debug{storage_type}, 'MASTER', "got last query from a master: $debug{dsn}";
+
+    ok $artist->discard_changes({force_pool=>'master'})
+       => 'properly called discard_changes against master (manual attrs)';
+
+    is $debug{storage_type}, 'MASTER', "got last query from a master: $debug{dsn}";
+
+    ok $artist->discard_changes()
+       => 'properly called discard_changes against master (default attrs)';
+
+    is $debug{storage_type}, 'MASTER', "got last query from a master: $debug{dsn}";
+
+    ok $artist->discard_changes({force_pool=>$replicant_names[0]})
+       => 'properly able to override the default attributes';
+
+    is $debug{storage_type}, 'REPLICANT', "got last query from a replicant: $debug{dsn}"
+}
+
+## Test some edge cases, like trying to do a transaction inside a transaction, etc
+
+{
+    ok my $result = $replicated->schema->txn_do(sub {
+        return $replicated->schema->txn_do(sub {
+            ok my $more = $replicated->schema->resultset('Artist')->find(1)
+            => 'found inside a transaction inside a transaction';
+            is $debug{storage_type}, 'MASTER', "got last query from a master: $debug{dsn}";
+            return $more;
+        });
+    }) => 'successfully processed transaction';
+
+    is $result->id, 1
+       => 'Got expected single result from transaction';
+}
+
+{
+    ok my $result = $replicated->schema->txn_do(sub {
+        return $replicated->schema->storage->execute_reliably(sub {
+            return $replicated->schema->txn_do(sub {
+                return $replicated->schema->storage->execute_reliably(sub {
+                    ok my $more = $replicated->schema->resultset('Artist')->find(1)
+                      => 'found inside crazy deep transactions and execute_reliably';
+                    is $debug{storage_type}, 'MASTER', "got last query from a master: $debug{dsn}";
+                    return $more;
+                });
+            });
+        });
+    }) => 'successfully processed transaction';
+
+    is $result->id, 1
+       => 'Got expected single result from transaction';
+}
+
+## Test the force_pool resultset attribute.
+
+{
+    ok my $artist_rs = $replicated->schema->resultset('Artist')
+        => 'got artist resultset';
+
+    ## Turn on Forced Pool Storage
+    ok my $reliable_artist_rs = $artist_rs->search(undef, {force_pool=>'master'})
+        => 'Created a resultset using force_pool storage';
+
+    ok my $artist = $reliable_artist_rs->find(2)
+        => 'got an artist result via force_pool storage';
+
+    is $debug{storage_type}, 'MASTER', "got last query from a master: $debug{dsn}";
+}
+
+## Test the force_pool resultset attribute part two.
+
+{
+    ok my $artist_rs = $replicated->schema->resultset('Artist')
+        => 'got artist resultset';
+
+    ## Turn on Forced Pool Storage
+    ok my $reliable_artist_rs = $artist_rs->search(undef, {force_pool=>$replicant_names[0]})
+        => 'Created a resultset using force_pool storage';
+
+    ok my $artist = $reliable_artist_rs->find(2)
+        => 'got an artist result via force_pool storage';
+
+    is $debug{storage_type}, 'REPLICANT', "got last query from a replicant: $debug{dsn}";
+}
+## Delete the old database files
+$replicated->cleanup;
+
+done_testing;
+
+# vim: sw=4 sts=4 :

Deleted: DBIx-Class/0.08/branches/group_by_consistency/t/storage/replication.t
===================================================================
--- DBIx-Class/0.08/branches/group_by_consistency/t/storage/replication.t	2010-05-06 09:39:59 UTC (rev 9312)
+++ DBIx-Class/0.08/branches/group_by_consistency/t/storage/replication.t	2010-05-06 09:42:51 UTC (rev 9313)
@@ -1,853 +0,0 @@
-use strict;
-use warnings;
-use lib qw(t/lib);
-use Test::More;
-use Test::Exception;
-use DBICTest;
-use List::Util 'first';
-use Scalar::Util 'reftype';
-use File::Spec;
-use IO::Handle;
-
-BEGIN {
-    eval "use DBIx::Class::Storage::DBI::Replicated; use Test::Moose";
-    plan skip_all => "Deps not installed: $@" if $@;
-}
-
-use_ok 'DBIx::Class::Storage::DBI::Replicated::Pool';
-use_ok 'DBIx::Class::Storage::DBI::Replicated::Balancer';
-use_ok 'DBIx::Class::Storage::DBI::Replicated::Replicant';
-use_ok 'DBIx::Class::Storage::DBI::Replicated';
-
-use Moose();
-use MooseX::Types();
-diag "Using Moose version $Moose::VERSION and MooseX::Types version $MooseX::Types::VERSION";
-
-=head1 HOW TO USE
-
-    This is a test of the replicated storage system.  This will work in one of
-    two ways, either it was try to fake replication with a couple of SQLite DBs
-    and creative use of copy, or if you define a couple of %ENV vars correctly
-    will try to test those.  If you do that, it will assume the setup is properly
-    replicating.  Your results may vary, but I have demonstrated this to work with
-    mysql native replication.
-
-=cut
-
-
-## ----------------------------------------------------------------------------
-## Build a class to hold all our required testing data and methods.
-## ----------------------------------------------------------------------------
-
-TESTSCHEMACLASSES: {
-
-    ## --------------------------------------------------------------------- ##
-    ## Create an object to contain your replicated stuff.
-    ## --------------------------------------------------------------------- ##
-
-    package DBIx::Class::DBI::Replicated::TestReplication;
-
-    use DBICTest;
-    use base qw/Class::Accessor::Fast/;
-
-    __PACKAGE__->mk_accessors( qw/schema/ );
-
-    ## Initialize the object
-
-    sub new {
-        my ($class, $schema_method) = (shift, shift);
-        my $self = $class->SUPER::new(@_);
-
-        $self->schema( $self->init_schema($schema_method) );
-        return $self;
-    }
-
-    ## Get the Schema and set the replication storage type
-
-    sub init_schema {
-        # current SQLT SQLite producer does not handle DROP TABLE IF EXISTS, trap warnings here
-        local $SIG{__WARN__} = sub { warn @_ unless $_[0] =~ /no such table.+DROP TABLE/s };
-
-        my ($class, $schema_method) = @_;
-
-        my $method = "get_schema_$schema_method";
-        my $schema = $class->$method;
-
-        return $schema;
-    }
-
-    sub get_schema_by_storage_type {
-      DBICTest->init_schema(
-        sqlite_use_file => 1,
-        storage_type=>{
-          '::DBI::Replicated' => {
-            balancer_type=>'::Random',
-            balancer_args=>{
-              auto_validate_every=>100,
-          master_read_weight => 1
-            },
-          }
-        },
-        deploy_args=>{
-          add_drop_table => 1,
-        },
-      );
-    }
-
-    sub get_schema_by_connect_info {
-      DBICTest->init_schema(
-        sqlite_use_file => 1,
-        storage_type=> '::DBI::Replicated',
-        balancer_type=>'::Random',
-        balancer_args=> {
-          auto_validate_every=>100,
-      master_read_weight => 1
-        },
-        deploy_args=>{
-          add_drop_table => 1,
-        },
-      );
-    }
-
-    sub generate_replicant_connect_info {}
-    sub replicate {}
-    sub cleanup {}
-
-    ## --------------------------------------------------------------------- ##
-    ## Add a connect_info option to test option merging.
-    ## --------------------------------------------------------------------- ##
-    {
-    package DBIx::Class::Storage::DBI::Replicated;
-
-    use Moose;
-
-    __PACKAGE__->meta->make_mutable;
-
-    around connect_info => sub {
-      my ($next, $self, $info) = @_;
-      $info->[3]{master_option} = 1;
-      $self->$next($info);
-    };
-
-    __PACKAGE__->meta->make_immutable;
-
-    no Moose;
-    }
-
-    ## --------------------------------------------------------------------- ##
-    ## Subclass for when you are using SQLite for testing, this provides a fake
-    ## replication support.
-    ## --------------------------------------------------------------------- ##
-
-    package DBIx::Class::DBI::Replicated::TestReplication::SQLite;
-
-    use DBICTest;
-    use File::Copy;
-    use base 'DBIx::Class::DBI::Replicated::TestReplication';
-
-    __PACKAGE__->mk_accessors(qw/master_path slave_paths/);
-
-    ## Set the master path from DBICTest
-
-    sub new {
-        my $class = shift @_;
-        my $self = $class->SUPER::new(@_);
-
-        $self->master_path( DBICTest->_sqlite_dbfilename );
-        $self->slave_paths([
-            File::Spec->catfile(qw/t var DBIxClass_slave1.db/),
-            File::Spec->catfile(qw/t var DBIxClass_slave2.db/),
-        ]);
-
-        return $self;
-    }
-
-    ## Return an Array of ArrayRefs where each ArrayRef is suitable to use for
-    ## $storage->connect_info to be used for connecting replicants.
-
-    sub generate_replicant_connect_info {
-        my $self = shift @_;
-        my @dsn = map {
-            "dbi:SQLite:${_}";
-        } @{$self->slave_paths};
-
-        my @connect_infos = map { [$_,'','',{AutoCommit=>1}] } @dsn;
-
-        ## Make sure nothing is left over from a failed test
-        $self->cleanup;
-
-        ## try a hashref too
-        my $c = $connect_infos[0];
-        $connect_infos[0] = {
-          dsn => $c->[0],
-          user => $c->[1],
-          password => $c->[2],
-          %{ $c->[3] }
-        };
-
-        @connect_infos
-    }
-
-    ## Do a 'good enough' replication by copying the master dbfile over each of
-    ## the slave dbfiles.  If the master is SQLite we do this, otherwise we
-    ## just do a one second pause to let the slaves catch up.
-
-    sub replicate {
-        my $self = shift @_;
-        foreach my $slave (@{$self->slave_paths}) {
-            copy($self->master_path, $slave);
-        }
-    }
-
-    ## Cleanup after ourselves.  Unlink all gthe slave paths.
-
-    sub cleanup {
-        my $self = shift @_;
-        foreach my $slave (@{$self->slave_paths}) {
-            if(-e $slave) {
-                unlink $slave;
-            }
-        }
-    }
-
-    ## --------------------------------------------------------------------- ##
-    ## Subclass for when you are setting the databases via custom export vars
-    ## This is for when you have a replicating database setup that you are
-    ## going to test against.  You'll need to define the correct $ENV and have
-    ## two slave databases to test against, as well as a replication system
-    ## that will replicate in less than 1 second.
-    ## --------------------------------------------------------------------- ##
-
-    package DBIx::Class::DBI::Replicated::TestReplication::Custom;
-    use base 'DBIx::Class::DBI::Replicated::TestReplication';
-
-    ## Return an Array of ArrayRefs where each ArrayRef is suitable to use for
-    ## $storage->connect_info to be used for connecting replicants.
-
-    sub generate_replicant_connect_info {
-        return (
-            [$ENV{"DBICTEST_SLAVE0_DSN"}, $ENV{"DBICTEST_SLAVE0_DBUSER"}, $ENV{"DBICTEST_SLAVE0_DBPASS"}, {AutoCommit => 1}],
-            [$ENV{"DBICTEST_SLAVE1_DSN"}, $ENV{"DBICTEST_SLAVE1_DBUSER"}, $ENV{"DBICTEST_SLAVE1_DBPASS"}, {AutoCommit => 1}],
-        );
-    }
-
-    ## pause a bit to let the replication catch up
-
-    sub replicate {
-        sleep 1;
-    }
-}
-
-## ----------------------------------------------------------------------------
-## Create an object and run some tests
-## ----------------------------------------------------------------------------
-
-## Thi first bunch of tests are basic, just make sure all the bits are behaving
-
-my $replicated_class = DBICTest->has_custom_dsn ?
-    'DBIx::Class::DBI::Replicated::TestReplication::Custom' :
-    'DBIx::Class::DBI::Replicated::TestReplication::SQLite';
-
-my $replicated;
-
-for my $method (qw/by_connect_info by_storage_type/) {
-  undef $replicated;
-  ok $replicated = $replicated_class->new($method)
-      => "Created a replication object $method";
-
-  isa_ok $replicated->schema
-      => 'DBIx::Class::Schema';
-
-  isa_ok $replicated->schema->storage
-      => 'DBIx::Class::Storage::DBI::Replicated';
-
-  isa_ok $replicated->schema->storage->balancer
-      => 'DBIx::Class::Storage::DBI::Replicated::Balancer::Random'
-      => 'configured balancer_type';
-}
-
-ok $replicated->schema->storage->meta
-    => 'has a meta object';
-
-isa_ok $replicated->schema->storage->master
-    => 'DBIx::Class::Storage::DBI';
-
-isa_ok $replicated->schema->storage->pool
-    => 'DBIx::Class::Storage::DBI::Replicated::Pool';
-
-does_ok $replicated->schema->storage->balancer
-    => 'DBIx::Class::Storage::DBI::Replicated::Balancer';
-
-ok my @replicant_connects = $replicated->generate_replicant_connect_info
-    => 'got replication connect information';
-
-ok my @replicated_storages = $replicated->schema->storage->connect_replicants(@replicant_connects)
-    => 'Created some storages suitable for replicants';
-
-our %debug;
-$replicated->schema->storage->debug(1);
-$replicated->schema->storage->debugcb(sub {
-    my ($op, $info) = @_;
-    ##warn "\n$op, $info\n";
-    %debug = (
-        op => $op,
-        info => $info,
-        dsn => ($info=~m/\[(.+)\]/)[0],
-        storage_type => $info=~m/REPLICANT/ ? 'REPLICANT' : 'MASTER',
-    );
-});
-
-ok my @all_storages = $replicated->schema->storage->all_storages
-    => '->all_storages';
-
-is scalar @all_storages,
-    3
-    => 'correct number of ->all_storages';
-
-is ((grep $_->isa('DBIx::Class::Storage::DBI'), @all_storages),
-    3
-    => '->all_storages are correct type');
-
-my @all_storage_opts =
-  grep { (reftype($_)||'') eq 'HASH' }
-    map @{ $_->_connect_info }, @all_storages;
-
-is ((grep $_->{master_option}, @all_storage_opts),
-    3
-    => 'connect_info was merged from master to replicants');
-
-my @replicant_names = keys %{ $replicated->schema->storage->replicants };
-
-ok @replicant_names, "found replicant names @replicant_names";
-
-## Silence warning about not supporting the is_replicating method if using the
-## sqlite dbs.
-$replicated->schema->storage->debugobj->silence(1)
-  if first { m{^t/} } @replicant_names;
-
-isa_ok $replicated->schema->storage->balancer->current_replicant
-    => 'DBIx::Class::Storage::DBI';
-
-$replicated->schema->storage->debugobj->silence(0);
-
-ok $replicated->schema->storage->pool->has_replicants
-    => 'does have replicants';
-
-is $replicated->schema->storage->pool->num_replicants => 2
-    => 'has two replicants';
-
-does_ok $replicated_storages[0]
-    => 'DBIx::Class::Storage::DBI::Replicated::Replicant';
-
-does_ok $replicated_storages[1]
-    => 'DBIx::Class::Storage::DBI::Replicated::Replicant';
-
-does_ok $replicated->schema->storage->replicants->{$replicant_names[0]}
-    => 'DBIx::Class::Storage::DBI::Replicated::Replicant';
-
-does_ok $replicated->schema->storage->replicants->{$replicant_names[1]}
-    => 'DBIx::Class::Storage::DBI::Replicated::Replicant';
-
-## Add some info to the database
-
-$replicated
-    ->schema
-    ->populate('Artist', [
-        [ qw/artistid name/ ],
-        [ 4, "Ozric Tentacles"],
-    ]);
-
-    is $debug{storage_type}, 'MASTER',
-        "got last query from a master: $debug{dsn}";
-
-    like $debug{info}, qr/INSERT/, 'Last was an insert';
-
-## Make sure all the slaves have the table definitions
-
-$replicated->replicate;
-$replicated->schema->storage->replicants->{$replicant_names[0]}->active(1);
-$replicated->schema->storage->replicants->{$replicant_names[1]}->active(1);
-
-## Silence warning about not supporting the is_replicating method if using the
-## sqlite dbs.
-$replicated->schema->storage->debugobj->silence(1)
-  if first { m{^t/} } @replicant_names;
-
-$replicated->schema->storage->pool->validate_replicants;
-
-$replicated->schema->storage->debugobj->silence(0);
-
-## Make sure we can read the data.
-
-ok my $artist1 = $replicated->schema->resultset('Artist')->find(4)
-    => 'Created Result';
-
-## We removed testing here since master read weight is on, so we can't tell in
-## advance what storage to expect.  We turn master read weight off a bit lower
-## is $debug{storage_type}, 'REPLICANT'
-##     => "got last query from a replicant: $debug{dsn}, $debug{info}";
-
-isa_ok $artist1
-    => 'DBICTest::Artist';
-
-is $artist1->name, 'Ozric Tentacles'
-    => 'Found expected name for first result';
-
-## Check that master_read_weight is honored
-{
-    no warnings qw/once redefine/;
-
-    local
-    *DBIx::Class::Storage::DBI::Replicated::Balancer::Random::_random_number =
-    sub { 999 };
-
-    $replicated->schema->storage->balancer->increment_storage;
-
-    is $replicated->schema->storage->balancer->current_replicant,
-       $replicated->schema->storage->master
-       => 'master_read_weight is honored';
-
-    ## turn it off for the duration of the test
-    $replicated->schema->storage->balancer->master_read_weight(0);
-    $replicated->schema->storage->balancer->increment_storage;
-}
-
-## Add some new rows that only the master will have  This is because
-## we overload any type of write operation so that is must hit the master
-## database.
-
-$replicated
-    ->schema
-    ->populate('Artist', [
-        [ qw/artistid name/ ],
-        [ 5, "Doom's Children"],
-        [ 6, "Dead On Arrival"],
-        [ 7, "Watergate"],
-    ]);
-
-    is $debug{storage_type}, 'MASTER',
-        "got last query from a master: $debug{dsn}";
-
-    like $debug{info}, qr/INSERT/, 'Last was an insert';
-
-## Make sure all the slaves have the table definitions
-$replicated->replicate;
-
-## Should find some data now
-
-ok my $artist2 = $replicated->schema->resultset('Artist')->find(5)
-    => 'Sync succeed';
-
-is $debug{storage_type}, 'REPLICANT'
-    => "got last query from a replicant: $debug{dsn}";
-
-isa_ok $artist2
-    => 'DBICTest::Artist';
-
-is $artist2->name, "Doom's Children"
-    => 'Found expected name for first result';
-
-## What happens when we disconnect all the replicants?
-
-is $replicated->schema->storage->pool->connected_replicants => 2
-    => "both replicants are connected";
-
-$replicated->schema->storage->replicants->{$replicant_names[0]}->disconnect;
-$replicated->schema->storage->replicants->{$replicant_names[1]}->disconnect;
-
-is $replicated->schema->storage->pool->connected_replicants => 0
-    => "both replicants are now disconnected";
-
-## All these should pass, since the database should automatically reconnect
-
-ok my $artist3 = $replicated->schema->resultset('Artist')->find(6)
-    => 'Still finding stuff.';
-
-is $debug{storage_type}, 'REPLICANT'
-    => "got last query from a replicant: $debug{dsn}";
-
-isa_ok $artist3
-    => 'DBICTest::Artist';
-
-is $artist3->name, "Dead On Arrival"
-    => 'Found expected name for first result';
-
-is $replicated->schema->storage->pool->connected_replicants => 1
-    => "At Least One replicant reconnected to handle the job";
-
-## What happens when we try to select something that doesn't exist?
-
-ok ! $replicated->schema->resultset('Artist')->find(666)
-    => 'Correctly failed to find something.';
-
-is $debug{storage_type}, 'REPLICANT'
-    => "got last query from a replicant: $debug{dsn}";
-
-## test the reliable option
-
-TESTRELIABLE: {
-
-    $replicated->schema->storage->set_reliable_storage;
-
-    ok $replicated->schema->resultset('Artist')->find(2)
-        => 'Read from master 1';
-
-    is $debug{storage_type}, 'MASTER',
-        "got last query from a master: $debug{dsn}";
-
-    ok $replicated->schema->resultset('Artist')->find(5)
-        => 'Read from master 2';
-
-    is $debug{storage_type}, 'MASTER',
-        "got last query from a master: $debug{dsn}";
-
-    $replicated->schema->storage->set_balanced_storage;
-
-    ok $replicated->schema->resultset('Artist')->find(3)
-        => 'Read from replicant';
-
-    is $debug{storage_type}, 'REPLICANT',
-        "got last query from a replicant: $debug{dsn}";
-}
-
-## Make sure when reliable goes out of scope, we are using replicants again
-
-ok $replicated->schema->resultset('Artist')->find(1)
-    => 'back to replicant 1.';
-
-    is $debug{storage_type}, 'REPLICANT',
-        "got last query from a replicant: $debug{dsn}";
-
-ok $replicated->schema->resultset('Artist')->find(2)
-    => 'back to replicant 2.';
-
-    is $debug{storage_type}, 'REPLICANT',
-        "got last query from a replicant: $debug{dsn}";
-
-## set all the replicants to inactive, and make sure the balancer falls back to
-## the master.
-
-$replicated->schema->storage->replicants->{$replicant_names[0]}->active(0);
-$replicated->schema->storage->replicants->{$replicant_names[1]}->active(0);
-
-{
-    ## catch the fallback to master warning
-    open my $debugfh, '>', \my $fallback_warning;
-    my $oldfh = $replicated->schema->storage->debugfh;
-    $replicated->schema->storage->debugfh($debugfh);
-
-    ok $replicated->schema->resultset('Artist')->find(2)
-        => 'Fallback to master';
-
-    is $debug{storage_type}, 'MASTER',
-        "got last query from a master: $debug{dsn}";
-
-    like $fallback_warning, qr/falling back to master/
-        => 'emits falling back to master warning';
-
-    $replicated->schema->storage->debugfh($oldfh);
-}
-
-$replicated->schema->storage->replicants->{$replicant_names[0]}->active(1);
-$replicated->schema->storage->replicants->{$replicant_names[1]}->active(1);
-
-## Silence warning about not supporting the is_replicating method if using the
-## sqlite dbs.
-$replicated->schema->storage->debugobj->silence(1)
-  if first { m{^t/} } @replicant_names;
-
-$replicated->schema->storage->pool->validate_replicants;
-
-$replicated->schema->storage->debugobj->silence(0);
-
-ok $replicated->schema->resultset('Artist')->find(2)
-    => 'Returned to replicates';
-
-is $debug{storage_type}, 'REPLICANT',
-    "got last query from a replicant: $debug{dsn}";
-
-## Getting slave status tests
-
-SKIP: {
-    ## We skip this tests unless you have a custom replicants, since the default
-    ## sqlite based replication tests don't support these functions.
-
-    skip 'Cannot Test Replicant Status on Non Replicating Database', 10
-     unless DBICTest->has_custom_dsn && $ENV{"DBICTEST_SLAVE0_DSN"};
-
-    $replicated->replicate; ## Give the slaves a chance to catchup.
-
-    ok $replicated->schema->storage->replicants->{$replicant_names[0]}->is_replicating
-        => 'Replicants are replicating';
-
-    is $replicated->schema->storage->replicants->{$replicant_names[0]}->lag_behind_master, 0
-        => 'Replicant is zero seconds behind master';
-
-    ## Test the validate replicants
-
-    $replicated->schema->storage->pool->validate_replicants;
-
-    is $replicated->schema->storage->pool->active_replicants, 2
-        => 'Still have 2 replicants after validation';
-
-    ## Force the replicants to fail the validate test by required their lag to
-    ## be negative (ie ahead of the master!)
-
-    $replicated->schema->storage->pool->maximum_lag(-10);
-    $replicated->schema->storage->pool->validate_replicants;
-
-    is $replicated->schema->storage->pool->active_replicants, 0
-        => 'No way a replicant be be ahead of the master';
-
-    ## Let's be fair to the replicants again.  Let them lag up to 5
-
-    $replicated->schema->storage->pool->maximum_lag(5);
-    $replicated->schema->storage->pool->validate_replicants;
-
-    is $replicated->schema->storage->pool->active_replicants, 2
-        => 'Both replicants in good standing again';
-
-    ## Check auto validate
-
-    is $replicated->schema->storage->balancer->auto_validate_every, 100
-        => "Got the expected value for auto validate";
-
-        ## This will make sure we auto validatge everytime
-        $replicated->schema->storage->balancer->auto_validate_every(0);
-
-        ## set all the replicants to inactive, and make sure the balancer falls back to
-        ## the master.
-
-        $replicated->schema->storage->replicants->{$replicant_names[0]}->active(0);
-        $replicated->schema->storage->replicants->{$replicant_names[1]}->active(0);
-
-        ## Ok, now when we go to run a query, autovalidate SHOULD reconnect
-
-    is $replicated->schema->storage->pool->active_replicants => 0
-        => "both replicants turned off";
-
-    ok $replicated->schema->resultset('Artist')->find(5)
-        => 'replicant reactivated';
-
-    is $debug{storage_type}, 'REPLICANT',
-        "got last query from a replicant: $debug{dsn}";
-
-    is $replicated->schema->storage->pool->active_replicants => 2
-        => "both replicants reactivated";
-}
-
-## Test the reliably callback
-
-ok my $reliably = sub {
-
-    ok $replicated->schema->resultset('Artist')->find(5)
-        => 'replicant reactivated';
-
-    is $debug{storage_type}, 'MASTER',
-        "got last query from a master: $debug{dsn}";
-
-} => 'created coderef properly';
-
-$replicated->schema->storage->execute_reliably($reliably);
-
-## Try something with an error
-
-ok my $unreliably = sub {
-
-    ok $replicated->schema->resultset('ArtistXX')->find(5)
-        => 'replicant reactivated';
-
-} => 'created coderef properly';
-
-throws_ok {$replicated->schema->storage->execute_reliably($unreliably)}
-    qr/Can't find source for ArtistXX/
-    => 'Bad coderef throws proper error';
-
-## Make sure replication came back
-
-ok $replicated->schema->resultset('Artist')->find(3)
-    => 'replicant reactivated';
-
-is $debug{storage_type}, 'REPLICANT', "got last query from a replicant: $debug{dsn}";
-
-## make sure transactions are set to execute_reliably
-
-ok my $transaction = sub {
-
-    my $id = shift @_;
-
-    $replicated
-        ->schema
-        ->populate('Artist', [
-            [ qw/artistid name/ ],
-            [ $id, "Children of the Grave"],
-        ]);
-
-    ok my $result = $replicated->schema->resultset('Artist')->find($id)
-        => "Found expected artist for $id";
-
-    is $debug{storage_type}, 'MASTER',
-        "got last query from a master: $debug{dsn}";
-
-    ok my $more = $replicated->schema->resultset('Artist')->find(1)
-        => 'Found expected artist again for 1';
-
-    is $debug{storage_type}, 'MASTER',
-        "got last query from a master: $debug{dsn}";
-
-   return ($result, $more);
-
-} => 'Created a coderef properly';
-
-## Test the transaction with multi return
-{
-    ok my @return = $replicated->schema->txn_do($transaction, 666)
-        => 'did transaction';
-
-        is $return[0]->id, 666
-            => 'first returned value is correct';
-
-        is $debug{storage_type}, 'MASTER',
-            "got last query from a master: $debug{dsn}";
-
-        is $return[1]->id, 1
-            => 'second returned value is correct';
-
-        is $debug{storage_type}, 'MASTER',
-             "got last query from a master: $debug{dsn}";
-
-}
-
-## Test that asking for single return works
-{
-    ok my @return = $replicated->schema->txn_do($transaction, 777)
-        => 'did transaction';
-
-        is $return[0]->id, 777
-            => 'first returned value is correct';
-
-        is $return[1]->id, 1
-            => 'second returned value is correct';
-}
-
-## Test transaction returning a single value
-
-{
-    ok my $result = $replicated->schema->txn_do(sub {
-        ok my $more = $replicated->schema->resultset('Artist')->find(1)
-        => 'found inside a transaction';
-        is $debug{storage_type}, 'MASTER', "got last query from a master: $debug{dsn}";
-        return $more;
-    }) => 'successfully processed transaction';
-
-    is $result->id, 1
-       => 'Got expected single result from transaction';
-}
-
-## Make sure replication came back
-
-ok $replicated->schema->resultset('Artist')->find(1)
-    => 'replicant reactivated';
-
-is $debug{storage_type}, 'REPLICANT', "got last query from a replicant: $debug{dsn}";
-
-## Test Discard changes
-
-{
-    ok my $artist = $replicated->schema->resultset('Artist')->find(2)
-        => 'got an artist to test discard changes';
-
-    is $debug{storage_type}, 'REPLICANT', "got last query from a replicant: $debug{dsn}";
-
-    ok $artist->get_from_storage({force_pool=>'master'})
-       => 'properly discard changes';
-
-    is $debug{storage_type}, 'MASTER', "got last query from a master: $debug{dsn}";
-
-    ok $artist->discard_changes({force_pool=>'master'})
-       => 'properly called discard_changes against master (manual attrs)';
-
-    is $debug{storage_type}, 'MASTER', "got last query from a master: $debug{dsn}";
-
-    ok $artist->discard_changes()
-       => 'properly called discard_changes against master (default attrs)';
-
-    is $debug{storage_type}, 'MASTER', "got last query from a master: $debug{dsn}";
-
-    ok $artist->discard_changes({force_pool=>$replicant_names[0]})
-       => 'properly able to override the default attributes';
-
-    is $debug{storage_type}, 'REPLICANT', "got last query from a replicant: $debug{dsn}"
-}
-
-## Test some edge cases, like trying to do a transaction inside a transaction, etc
-
-{
-    ok my $result = $replicated->schema->txn_do(sub {
-        return $replicated->schema->txn_do(sub {
-            ok my $more = $replicated->schema->resultset('Artist')->find(1)
-            => 'found inside a transaction inside a transaction';
-            is $debug{storage_type}, 'MASTER', "got last query from a master: $debug{dsn}";
-            return $more;
-        });
-    }) => 'successfully processed transaction';
-
-    is $result->id, 1
-       => 'Got expected single result from transaction';
-}
-
-{
-    ok my $result = $replicated->schema->txn_do(sub {
-        return $replicated->schema->storage->execute_reliably(sub {
-            return $replicated->schema->txn_do(sub {
-                return $replicated->schema->storage->execute_reliably(sub {
-                    ok my $more = $replicated->schema->resultset('Artist')->find(1)
-                      => 'found inside crazy deep transactions and execute_reliably';
-                    is $debug{storage_type}, 'MASTER', "got last query from a master: $debug{dsn}";
-                    return $more;
-                });
-            });
-        });
-    }) => 'successfully processed transaction';
-
-    is $result->id, 1
-       => 'Got expected single result from transaction';
-}
-
-## Test the force_pool resultset attribute.
-
-{
-    ok my $artist_rs = $replicated->schema->resultset('Artist')
-        => 'got artist resultset';
-
-    ## Turn on Forced Pool Storage
-    ok my $reliable_artist_rs = $artist_rs->search(undef, {force_pool=>'master'})
-        => 'Created a resultset using force_pool storage';
-
-    ok my $artist = $reliable_artist_rs->find(2)
-        => 'got an artist result via force_pool storage';
-
-    is $debug{storage_type}, 'MASTER', "got last query from a master: $debug{dsn}";
-}
-
-## Test the force_pool resultset attribute part two.
-
-{
-    ok my $artist_rs = $replicated->schema->resultset('Artist')
-        => 'got artist resultset';
-
-    ## Turn on Forced Pool Storage
-    ok my $reliable_artist_rs = $artist_rs->search(undef, {force_pool=>$replicant_names[0]})
-        => 'Created a resultset using force_pool storage';
-
-    ok my $artist = $reliable_artist_rs->find(2)
-        => 'got an artist result via force_pool storage';
-
-    is $debug{storage_type}, 'REPLICANT', "got last query from a replicant: $debug{dsn}";
-}
-## Delete the old database files
-$replicated->cleanup;
-
-done_testing;
-
-# vim: sw=4 sts=4 :




More information about the Bast-commits mailing list