- Forget to include data browser files in MANIFEST.  Caused weirdness
if you said you wanted it when asked during install.


Bug fixes only

- Fix bugs in Alzabo::MethodMaker.  The insert, update, lookup_table,
and self_relation (parent portion only) were broken.

- A bug in the SQL making code was causing some queries to appear as
if they failed when they didn't.


- The convert.pl script in eg/ has been updated to handle the new
release.  IMPORTANT: I forgot to include a mention of this in the last
release but you need to run the script _before_ installing a new
version of Alzabo.

- Many improvements and updates to Alzabo::MethodMaker.  Highlights
include fixing a bug that prevented the insert and update methods from
being created, a new callback system that allows you to specify all
the method names to be generated, and a new 'self_relations' option
for tables that have parent/child relationships with themself.

- Fix handling of NULL columns for inserts and updates.  Now, Alzabo
only throws an exception if the column is not nullable and has no
default.  If it has a default and is specified as NULL then it will
not be included in the INSERT clause (in which case the RDBMS should
insert the default value itself).

- Fix bugs in Postgres reverse engineering.  Defaults were not handled
properly, nor were numeric column type length and precision.

- The schema creator and data browser now allow you to enter the host
for database connections where needed.

- Foreign keys can now span multiple columns.  This means you can have
a relation from foo.foo_id and foo.index_id to bar.foo_id and
bar.index_id.  This required some changes to the interface for the
foreign key objects.  Notably, the Alzabo::ForeignKey->column_from and
Alzabo::ForeignKey->column_to methods are now
Alzabo::ForeignKey->columns_from and Alzabo::ForeignKey->columns_to.
In addition, the parameters given to the
Alazbo::Create::Schema->add_relation have changed.

- Major changes to caching architecture.  The caching code has been
split up.  There is now a 'storing' class, which holds onto the
objects (the cache).  Then there is a 'sync' class.  This class
handles expiration and deletion tracking.  These two classes can be
mixed and matched.  Right now there is only one storage class (which
stores the objects in memory).  There are 3 syncing classes.  One,
NullSync, doesn't actually sync objects.  It does track deletions, but
not expirations.  The others, IPCSync and DBMSync, use IPC or DBM
files to track expiration and deletion of objects.

- Doing this work highlighted some bugs in the caching/syncing code.
One oversight was that if you deleted an object and then inserted
another row with the exact same primary key, the cache continued to
think the object was deleted.  Other bugs also surfaced.  These have
been fixed and the test suite has been updated so caching should be
stable (if not, I'll have to cry).

- When viewing an existing column in the schema creator, defaults,
lengths, and precision of 0 were not being shown.

- Alzabo::Runtime::Table->row_count can now take a where clause.

- Fix bugs in Alzabo::Create::Table.  This was causing problems with
indexes when the table name was changed.

- Fixed a bug in Alzabo::Util that caused the test cases to fail if
Alzabo hadn't been previously installed.  Reported by Robert Goff.

- The SQLMaker class is now smarter about not letting you make bad
SQL.  For example, if you try to make a WHERE clause with tables not
mentioned in the FROM clause, it will throw an exception.  This will
hopefully help catch logic errors in your code a bit sooner.

- Removed use of prepare_cached in Alzabo::Driver.  This has the
potential to cause some strange errors under Alzabo.  Because of the
way Alzabo works, it is possible to have a Cursor object holding onto
a statement handle that needs to be used elsewhere (by a row object,
for example).  It is safer to let a new statement handle be created in
this case.


- See the note above about the changes required to support
multi-column foreign keys.

- Because of the aforementioned changes to the caching architecture,
caching just does not work the way it used.

1. By default, there is no caching at all.

2. To get the old behavior, which defaulted to an in-process memory
cache with no inter-process syncing (meaning deletes are tracked but
there is no such thing as expiration), you can do this in your code:

  use Alzabo::ObjectCache( store => 'Alzabo::ObjectCache::MemoryStore',
                           sync  => 'Alzabo::ObjectCache::NullSync' );

or just:

  use Alzabo::ObjectCache;  # the above modules are the defaults

3. To get the behavior of the old Alzabo::ObjectCacheIPC module, do:

  use Alzabo::ObjectCache( store => 'Alzabo::ObjectCache::MemoryStore',
                           sync  => 'Alzabo::ObjectCache::IPCSync' );

However, the new DBMSync module will probably scale better, and
performance should be about the same for smaller applications.  To use
it, do:

  use Alzabo::ObjectCache( store => 'Alzabo::ObjectCache::MemoryStore',
                           sync  => 'Alzabo::ObjectCache::DBMSync' );

4. If you run without any caching at all then the Alzabo::Runtime::Row
class's behavior has changed somewhat.  In particular, selects or
updates against a deleted object will always throw an
Alzabo::Exception::NoSuchRow exception.  Before, the behavior wasn't
very well defined.

Please read the section on clearing the cache in the
Alzabo::ObjectCache module, as this is an important concept.  By
default, the caching and syncing modules will just grow unchecked.
You need to clear at the appropriate points (usually your
application's entry points) in order to keep them under control.


- Preliminary Postgres support.  There is no support yet for
constraints or foreign keys when reverse engineering or making SQL.
There is also no support for large objects (I'm hoping that 7.1 will
be released soon so I won't have to think about this).  Otherwise, the
support is about at the same level as MySQL support, though less

- Added Alzabo::MethodMaker module.  This can be used to auto-generate
useful methods for your schema/table/row objects based on the
properties of your objects themselves.

- Reworking/expanding/clarifying/editing of the docs.

- Add order_by and limit options whenever creating a cursor.

- Method documentation POD from the Alzabo::* modules is merged into
the relevant Alzabo::Create::* and Alzabo::Runtime::* modules during
install.  This should make it easier to find what you need since the
average user will only need to look at a few modules in

- Reworked exceptions so they are all now Alzabo::Exception::Something.

- Added default as a column attribute (thus there are now
Alzabo::Column->default and Alzabo::Create::Column->set_default

- Added length & precision attributes for columns.  Both are set
through the Alzabo::Create::Column->set_length method.

- This release includes a script in eg/ called convert.pl to convert
older schemas.

- Alzabo::Schema->tables & Alzabo::Table->columns now take an optional
list of tables/columns as an argument and return a list of matching

- Added Alzabo::Column->has_attribute method.

- The data browser has actually lost some functionality (the
filtering).  Making this more powerful is a fairly low priority at the

- Fix bugs where extra params passed to Alzabo::Runtime::Table->insert
were not making it to the Alzabo::Runtime::Row->new method.

- Fix for Alzabo::Runtime::Table->set_prefetch method.

- Fixed bug in handling of deleted object in Alzabo::ObjectCacheIPC
(they were never reported as deleted).

- Fix bug that caused schema to get bigger every time it was saved.

- Finally switched to regular hashes for objects.

- Added Alzabo::SQLMaker classes to handle generating SQL
in a cross-platform compatible way.


- Parameters for Alzabo::Create::Column->new: 'null' parameter is now
'nullable'.  The use of the parameter 'null' is deprecated.

- Alzabo::Column->null & Alzabo::Column->set_null methods are now
Alzabo::Column->nullable & Alzabo::Column->set_nullable.  The old
methods are deprecated.

- Alzabo::Create::ForeignKey->new no longer requires table_from &
table_to params (it took me this long to realize I can get that from
the column passed in.  doh!)


- Alzabo::Runtime::Table->rows_where parameters have changed.  The
from parameter has been removed (use the Alzabo::Runtime::Schema->join
method instead).  The where parameter expects something different now.

- Alzabo::Runtime::Table->rows_by_where_clause method has been

- Alzabo::Runtime::Schema->join method's where parameter expects
something different.


- You can now specify a database name to be used for testing.  The
default is 'test_alzabo'.  This a good default for MySQL, at least.
Thanks to Randal Schwartz for the help.

- Make sure test file cleanup is done _before_ attempting tests so
that files from a test previously aborted are cleaned up (and no
errors are generated.  Thanks to Randal Schwartz for the bug report.

- Doesn't fail on install for Mason components if no Mason component
extension was given.  Thanks _again_ to Randal for working with me on
this in IRC late at night.


- Fix Makefile.PL bug

- Auto select a column when adding a relation (if there is a logical
one to select).


- Fix bug with deleting foreign key objects from tables.



- Doc bug fixes in Alzabo::Runtime::Schema.

- Fix fact that Alzabo::Runtime::Row rows_by_foreign_key method could
return either a Row _or_ RowCursor object.  Now it always returns a
cursor object.

- Fix fact that no_cache parameter was not propagated through the
RowCursor object to the rows it created.

- Add all all_rows method to Alzabo::Runtime::RowCursor.

- Add ability to reset instantiation flag in schema creation

- Updated INSTALL to mention how to get the schema creator and data
browser working.

- Finally make creating relations between tables _without_ specifying
the columns work.  This does some, IMHO, pretty cool DWIMmery.

- Added primary_key param to Alzabo::Runtime::Table make_column

- Added set_host and host methods to Alzabo::Runtime::Schema.

- Added drop method to Alzabo::Create::Schema and necessary support in
driver modules.

- Changed 'id' param to 'pk' for Alzabo::Runtime::Table row_by_pk
method.  'id' still works, for now, but is deprecated.

- Fix problem where an insert could generate a referential integrity
exception but still end up in the database.  Note, without
transactions (in MySQL, for example), there's no way to make the all
of the referential integrity code work correctly 100% of the time.

- Added new class Alzabo::ObjectCache to make sure that objects stay
in sync after referential integrity operations happen.  This is now
the default caching class.  Please make sure to read the docs for this
new module, particularly if you're running Alzabo under a persistent
environment where this module can be quite the memory hog if not used
properly (clear the cache!).

- Fixed breakage in maintenance of referential integrity caused by
switch to cursors (and me not fixing all the code that expected row

- Added Alzabo::Runtime::Cursor base class.

- Added join method to Alzabo::Runtime::Schema.  *EXPERIMENTAL*

- Added Alzabo::Runtime::JoinCursor class.  *EXPERIMENTAL*

- Began conversion of all classes from pseudohash to hash.

- Both schema creator and data browser now respect user choice of
component extension.


- MAJOR CHANGE: All the Alzabo::Runtime::Row methods that used to
return lists of rows now return the new Alzabo::Runtime::RowCursor
object.  This change is a major speed and memory optimization.  It
does, however, break the old interface.  But its worth it.

- Set autohandlers for schema maker and data browser so that they
won't inherit from other autohandlers higher up the directory tree.

- Fix bug in Alzabo::Driver which made it so that the one_row_hash
method always returned a hash with keys.  This caused spurious row
object to be created in the Alzabo::Runtime::Row class.

- Fix bug in Alzabo::Table::rows_where method where it wasn't handling
the construct $table->rows_where( where => { foo => undef } )


- Lazy column evaluation had made it possible to create an
Alzabo::Runtime::Row object that did not correspond to any data in the
database if its table object did specify any rows to prefetch.  This
would have only been discovered later by calling the select method on
a non-primary key column.  This hole was plugged.

- As a corollary to the above change methods in Alzabo::Runtime::Table
that produce rows now always return an empty list or undef when the
rows cannot be made because the specified primary key doesn't exist.
Previously, the rows_by_where_clause method did this while others
would cause an exception either during the object creation or later,
depending upon the situation described above.

- GENERAL NOTE: I probably used exceptions too much, as in the above
case.  I will probably be making a few more changes like this in the

- Bug fix in Alzabo::RDBMSRules when making SQL diffs.  Forgot to
account for new foreign key method names.

- Bug fix related to MySQL auto_increment column and
Alzabo::Runtime::Table insert method.  Basically, you couldn't insert
an to a table and use its auto_increment feature.

- Alzabo::Table::set_prefetch now makes sure that primary key columns
are not included.  It simply ignores them but they will not be
returned by the prefetch method.

- fix bug where some row retrieval methods would fail if not given a
'bind' parameter.

- Doc bug fix.  Docs for Alzabo::Runtime::Table listed group_by_column
as simply group.  Of course, this probably only needs to be used by
Alzabo::Runtime::Row anyway.

- Added Alzabo::Runtime::Table rows_where method.

- Added Alzabo::Runtime::Table all_rows method.

- Documented 'bind' parameter for Alzabo::Runtime::Table
rows_by_where_clause method.


- Fixed major bugs in Alzabo::Runtime::Table::insert method.

- Fixed bug in Alzabo::Runtime::Row::delete method related to API
change in 0.06

- Reduce amount of work done in Alzabo::Runtime::Row when referential
integrity maintenance is set to false.

- Added new method to Alzabo::Runtime::Row: rows_by_foreign_key.  A
row can now fetch the rows that are related to it automatically.

- Made all Alzabo::Table foreign key object returning methods
list/scalar context sensitive.  This is useful when you know that
there is only one foreign key that matches what you are looking for.


- change return value from Alzabo::Index id method to be something
that can be an actual index name.  This is a bug fix as previously
index SQL was not valid (at least not for MySQL).

- cosmetic fixes in schema creator

- moved exception component to common mason files so its shared by
schema creator and data browser.

- added Index attribute of unique (so we can make unique indexes).

- made SQL making code for MySQL aware of this.

- added ability to set this to schema creator.

- added ability to specify column order in an index in schema creator.

- made it possible for a table to have more than one foreign from a
given column.  documented how this changes API in Alzbo::Table.

- API: The Alzabo::Table foreign_keys() method name has been changed
to all_foreign_keys().  The foreign_key method (which returns keys by
table to and column from) is now the foreign_keys() method because it
can return more than one object.

- change schema creator, Alzabo::Create::Schema module, and
03/create.t test to handle this properly.

- added ability to move columns and tables to arbitrary new locations
after they've been created (without the arrows).


- bug fix for Alzabo::Runtime::Row calling wrong method from schema

- got rid of the locking stuff in the MySQL driver.  Since its not
possible to have more than 1 lock at a time with the GET_LOCK function
there's no way to have the right kinds of locks for cascading deletes.
It might be possible to do this kind of locking via some other
mechanism (semaphores, DBM files, whatever, but that's a hack for
another day.


- Switched to use Tie::IxHash object interface

- fixed stupid bug in Alzabo::RDBMSRules::MySQL

- changed the way Alzabo::ChangeTracker works.  it requires fewer
method calls to do its job now.

- added set_referential_integrity/referential_integrity methods to
Alzabo::Runtime::Schema.  The default is to not attempt to maintain

- It should no longer be possible for Alzabo::Runtime::ForeignKey
objects to create loops when maintaining referential integrity.  It
also should be a bit more efficient in the register_delete method.  If
no action needs to be taken, it won't loop through all the rows in the
related table before finding this out.

- fixed data browser bug when putting in a filter on any page that was
not the first page of results for a table.

- fixed data browser bug in paging with filters.


- Fixed bugs in Alzabo::ObjectCacheIPC so it now works.

- Added lazy column evaluation (see Alzabo::Runtime::Table) docs

- Added Alzabo::DriverStatement and Alzabo::Driver::Exception to Alzabo::Driver

- improved data browser memory efficiency

- minor bug fixes (bad links) in data browser and schema maker

- minor buglet fix in Alzabo::Driver::MySQL

- big fix to how Alzabo::Runtime::Schema is saved from
Alzabo::Create::Schema.  Previous implementation was accidentally
saving both the runtime and create versions at once.  The new version
fixes this.