/* $Revision: 34 $ $Date: 16/06/06 22:22 $ Copyright © 2002-2006, FSL Technologies Limited. Contact "http://fost3.fsltech.com". */ #include "stdafx.h" #include using namespace std; using namespace FSLib; using namespace FSLib::Definition; using namespace FSLib::Attribute; namespace { const Revision c_revision( L"$Archive: /FOST.3/F3Util/table.cpp $", __DATE__, L"$Revision: 34 $", L"$Date: 16/06/06 22:22 $" ); inline FSLib::wstring columns( const Compound::t_columns &coll ) { Nullable< FSLib::wstring > cols; {for ( Compound::t_columns::const_iterator col( coll.begin() ); col != coll.end(); ++col ) { int columns( (*col)->columns() ); for ( int ncol( 0 ); ncol != columns; ++ncol ) { cols = concat( cols, L", ", L"[" + concat( (*col)->definition().name(), L"_", (*col)->suffix( ncol ) ).value() + L"]" ); } }} return cols.value(); } inline FSLib::wstring values( const Compound::t_columns &coll ) { Nullable< FSLib::wstring > cols; {for ( Compound::t_columns::const_iterator col( coll.begin() ); col != coll.end(); ++col ) { int columns( (*col)->columns() ); for ( int ncol( 0 ); ncol != columns; ++ncol ) { try { cols = concat( cols, L", ", (*col)->toSQL( ncol ) ); } catch ( FSLib::Exceptions::Exception &e ) { e.info() << L"Attempt to generate SQL column value for [" << concat( (*col)->definition().name(), L"_", (*col)->suffix( ncol ) ).value() << L"] within " << (*col)->definition().partOf().implName() << endl << L"F3Util.DLL:table.cpp FSLib::wstring values( const Compound::t_columns &coll )" << endl; throw; } } }} return cols.value(); } inline Nullable< FSLib::wstring > name_val( const Compound::t_columns &coll, const FSLib::wstring &sep, bool includeReadOnly = true ) { Nullable< FSLib::wstring > cols; {for ( Compound::t_columns::const_iterator col( coll.begin() ); col != coll.end(); ++col ) { int columns( (*col)->columns() ); for ( int ncol( 0 ); ncol != columns; ++ncol ) { if ( includeReadOnly || !(*col)->definition().readOnly ) { try { cols = concat( cols, sep, L"[" + concat( (*col)->definition().name(), L"_", (*col)->suffix( ncol ) ).value() + L"]=" + (*col)->toSQL( ncol ) ); } catch ( FSLib::Exceptions::Exception &e ) { e.info() << L"Attempt to generate SQL column value for [" << concat( (*col)->definition().name(), L"_", (*col)->suffix( ncol ) ).value() << L"] within " << (*col)->definition().partOf().implName() << endl << L"F3Util.DLL:table.cpp FSLib::wstring name_val( const Compound::t_columns &coll, const FSLib::wstring &sep )" << endl; throw; } } } }} return cols; } } /* FSLib::Definition::Table */ inline Table::Table( const FSLib::wstring &name, const Nullable< FSLib::wstring > &table ) : m_superTable( NULL ), m_className( name ), m_table( table ) { //Log::log() << L"Table," << this << L"," << name << ( table.isnull() ? L",NULL" : L"," + table.value() ) << endl; } inline Table::Table( const Table &super, const FSLib::wstring &name, const Nullable< FSLib::wstring > &table ) : m_superTable( &super ), m_className( name ), m_table( table ) { //Log::log() << L"Table," << name << ( table.isnull() ? L",NULL" : L"," + table.value() ) << L"," << this << endl; } inline void Table::column( Column *column ) const { //Log::log() << L"Table,Column," << this << L"," << m_className << L"," << column->name() << endl; ExclusiveWrite::WriteLock lock( m_columns_synch ); m_columns.push_back( column ); } inline const Table::t_columns Table::columns() const { ExclusiveWrite::ReadLock lock( m_columns_synch ); FSLib::wstring cols; for ( t_columns::const_iterator it( m_columns.begin() ); it != m_columns.end(); ++it ) { cols += L"," + (*it)->name(); } //Log::log() << L"Table,Columns," << this << L"," << m_className << cols << endl; return m_columns; } inline bool Table::operator ==( const Table &rhs ) const { return m_superTable == rhs.m_superTable && m_className == rhs.m_className; } inline const Table *Table::superTable() const { return m_superTable; } inline const Nullable< FSLib::wstring > &Table::table() const { return m_table; } inline const FSLib::wstring &Table::implName() const { return m_className; } inline long Table::depth() const { if ( m_superTable == NULL ) { return 0; } else { return 1 + m_superTable->depth(); } } /* FSLib::Definition::Facet */ inline Definition::Facet::Facet( const Definition::Table &owner, const FSLib::wstring &name, const FSLib::Nullable< FSLib::wstring > &table ) : Table( name, table ), m_owner( &owner ) { //Log::log() << L"Table,Facet," << name << endl; } /* FSLib::Definition::Column */ inline Column::Column( const Table &cls, const wchar_t *col, bool primary, bool readOnly ) : m_class( cls ), m_column( col ), m_ownes( NULL ), m_owningColumn( NULL ), primary( primary ), readOnly( readOnly ), owner( false ), aggregates( false ), collection( false ) { cls.column( this ); } inline Column::Column( const Table &cls, const FSLib::wstring &col, bool primary, bool readOnly ) : m_class( cls ), m_column( col ), m_ownes( NULL ), m_owningColumn( NULL ), primary( primary ), readOnly( readOnly ), owner( false ), aggregates( false ), collection( false ) { cls.column( this ); } inline Column::Column( const Table &cls, const Table &agg, const wchar_t *col, bool primary, bool readOnly ) : m_class( cls ), m_column( col ), m_ownes( &agg ), m_owningColumn( NULL ), primary( primary ), readOnly( readOnly ), owner( false ), aggregates( true ), collection( false ) { cls.column( this ); } inline Column::Column( const Table &cls, const Table &agg, const FSLib::wstring &col, bool primary, bool readOnly ) : m_class( cls ), m_column( col ), m_ownes( &agg ), m_owningColumn( NULL ), primary( primary ), readOnly( readOnly ), owner( false ), aggregates( true ), collection( false ) { cls.column( this ); } inline // Owning column Column::Column( const Table &cls, const Definition::Facet &facet, const wchar_t *col ) : m_class( cls ), m_column( col ), m_ownes( &facet ), m_owningColumn( NULL ), primary( false ), readOnly( false ), owner( false ), aggregates( true ), collection( true ) { cls.column( this ); } inline // Facet PK <> column Column::Column( const Definition::Facet &cls, const Column &owner, const wchar_t *col ) : m_class( cls ), m_column( col ), m_ownes( NULL ), m_owningColumn( &owner ), primary( true ), readOnly( false ), owner( true ), aggregates( false ), collection( false ) { cls.column( this ); } inline bool Column::operator ==( const Column &rhs ) const { return m_class == rhs.m_class && m_column == rhs.m_column; } inline bool Column::operator !=( const Column &rhs ) const { return !operator ==( rhs ); } inline const Column &Column::owningColumn() const { if ( m_owningColumn == NULL ) { throw Exceptions::Null( L"The column \"" + partOf().implName() + L"::" + name() + L"\" does not have an owner counterpart" ); } return *m_owningColumn; } inline const Table &Column::ownes() const { if ( m_ownes == NULL ) { throw Exceptions::Null( L"The column \"" + partOf().implName() + L"::" + name() + L"\" does not own any tables" ); } return *m_ownes; } inline const FSLib::wstring &Column::name() const { return m_column; } inline const Table &Column::partOf() const { return m_class; } /* FSLib::Compound */ inline Compound::Compound() : persistent( NULL ) { } inline Compound::Compound( Persistent &pers ) : persistent( &pers ) { } inline void Compound::value( FSLib::Attribute::Value *attrib ) { if ( attrib->definition().primary ) { m_key.push_back( attrib ); } else { m_attributes[ &attrib->definition().partOf() ].push_back( attrib ); if ( attrib->definition().aggregates ) { m_ownedPointers.push_back( attrib ); } } } inline void Compound::facet( FSLib::Attribute::Facet *attrib ) { m_facets.push_back( attrib ); } inline const FSLib::Attribute::Value * const Compound::value( const FSLib::Definition::Column *col ) const { {for ( t_columns::const_iterator val( m_key.begin() ); val != m_key.end(); ++val ) { //Log::log() << L"Comparing " << (*val)->definition().partOf().implName() + L"::" + (*val)->definition().name() << L" with " << col->partOf().implName() + L"::" + col->name() << endl; if ( &(*val)->definition() == col ) return *val; }} t_collection::const_iterator pos( m_attributes.find( &col->partOf() ) ); if ( pos != m_attributes.end() ) { //Log::log() << L"Looking for " << col->partOf().implName() + L"::" + col->name() << L" in " << (*pos).second.size() << L" columns within " << &col->partOf() << endl; {for ( t_columns::const_iterator val( (*pos).second.begin() ); val != (*pos).second.end(); ++val ) { //Log::log() << L"Comparing " << (*val)->definition().partOf().implName() + L"::" + (*val)->definition().name() << L" with " << col->partOf().implName() + L"::" + col->name() << endl; if ( &(*val)->definition() == col ) return *val; }} throw Exceptions::UnexpectedEOF( L"Could not find column value (\"" + col->partOf().implName() + L"::" + col->name() + L"\") for owner's key in table \"" + (*pos).first->implName() + L"\"" ); } else { throw Exceptions::UnexpectedEOF( L"Could not find table (\"" + col->partOf().implName() + L"\") for owner's key" ); } } inline FSLib::Attribute::Attribute * Compound::operator [] ( const FSLib::wstring &name ) const { for ( t_columns::const_iterator val( m_key.begin() ); val != m_key.end(); ++val ) if ( (*val)->definition().name() == name ) return *val; for ( t_collection::const_iterator level( m_attributes.begin() ); level != m_attributes.end(); ++level ) for ( t_columns::const_iterator val( (*level).second.begin() ); val != (*level).second.end(); ++val ) if ( (*val)->definition().name() == name ) return *val; for ( t_facets::const_iterator fac( m_facets.begin() ); fac != m_facets.end(); ++fac ) if ( (*fac)->definition().name() == name ) return *fac; return NULL; } inline FSLib::Attribute::Attribute *Compound::operator[]( const FSLib::Definition::Column &col ) const { for ( t_columns::const_iterator val( m_key.begin() ); val != m_key.end(); ++val ) if ( (*val)->definition() == col ) return *val; for ( t_collection::const_iterator level( m_attributes.begin() ); level != m_attributes.end(); ++level ) for ( t_columns::const_iterator val( (*level).second.begin() ); val != (*level).second.end(); ++val ) if ( (*val)->definition() == col ) return *val; for ( t_facets::const_iterator fac( m_facets.begin() ); fac != m_facets.end(); ++fac ) if ( (*fac)->definition() == col ) return *fac; return NULL; } inline const Compound::t_columns &Compound::keys() const { return m_key; } inline void Compound::keys( const Compound::t_columns &from ) { m_key.insert( m_key.end(), from.begin(), from.end() ); } inline const Compound::t_collection &Compound::attributes() const { return m_attributes; } inline const Compound::t_columns &Compound::aggregates() const { return m_ownedPointers; } inline const Compound::t_facets &Compound::facets() const { return m_facets; } inline void Compound::subscriber( Notification *sub ) { subscriber( boost::shared_ptr< Notification >( sub ) ); } inline void Compound::subscriber( const boost::shared_ptr< Notification > &sub ) { m_subscribers.push_back( sub ); } inline const Compound::t_subscribers &Compound::subscribers() const { return m_subscribers; } inline FSLib::wstring Compound::newSQL( const FSLib::wstring &tName ) const { FSLib::wstring sql; sql += L"INSERT INTO " + tName; sql += L" ( " + columns( m_key ) + L" )"; sql += L" SELECT " + values( m_key ); return sql; } inline FSLib::wstring Compound::newSQL( const Definition::Table *table, const FSLib::wstring &tName ) const { t_columns blank; const t_columns &attribs = ( m_attributes.find( table ) == m_attributes.end() ? blank : (*m_attributes.find( table )).second ); FSLib::wstring sql; sql += L"INSERT INTO " + tName; sql += L" ( " + concat( columns( m_key ), L", ", columns( attribs ) ).value() + L" )"; sql += L" SELECT " + concat( values( m_key ), L", ", values( attribs ) ).value(); return sql; } inline Nullable< FSLib::wstring > Compound::initSQL( const Definition::Table *table, const FSLib::wstring &tName ) const { t_columns blank; const t_columns &attribs = ( m_attributes.find( table ) == m_attributes.end() ? blank : (*m_attributes.find( table )).second ); if ( attribs.size() ) { FSLib::wstring sql; sql += L"SELECT " + columns( attribs ); sql += L" FROM " + tName; sql += L" WHERE " + name_val( m_key, L" AND " ).value(); return sql; } return Null; } inline Nullable< FSLib::wstring > Compound::changeSQL( const Definition::Table *table, const FSLib::wstring &tName ) const { t_columns blank; const t_columns &attribs = ( m_attributes.find( table ) == m_attributes.end() ? blank : (*m_attributes.find( table )).second ); Nullable< FSLib::wstring > cols( name_val( attribs, L", ", false ) ); if ( !cols.isnull() ) return L"UPDATE " + tName+ L" SET " + cols.value() + L" WHERE " + name_val( m_key, L" AND " ).value(); else return Null; } inline FSLib::wstring Compound::deleteSQL( const FSLib::wstring &tName ) const { FSLib::wstring sql; sql += L"DELETE FROM " + tName; sql += L" WHERE " + name_val( m_key, L" AND " ).value(); return sql; } inline FSLib::wstring Compound::deleteSQL( const Definition::Table *, const FSLib::wstring &tName ) const { return deleteSQL( tName ); } inline FSLib::wstring Compound::facetSQLWhere( const Definition::Table *facet ) const { t_columns ownerColumns; Nullable< FSLib::wstring > cols; Table::t_columns columns( facet->columns() ); for ( Table::t_columns::const_iterator it( columns.begin() ); it != columns.end(); ++it ) { if ( (*it)->owner ) { for ( t_columns::const_iterator kit( keys().begin() ); kit != keys().end(); ++kit ) { const Attribute::Value * const val = *kit; // This should be stripped out along with all other _id etc. special cases FSLib::wstring name( val->definition().name() ), prefix( (*it)->name() ); if ( name != prefix && prefix.size() <= name.size() || prefix.substr( prefix.size() - name.size() ) != name ) { name = prefix + L"_" + name; } else { name = prefix; } int columns( val->columns() ); for ( int ncol( 0 ); ncol != columns; ++ncol ) { cols = concat( cols, L" AND ", concat( name, L"_", val->suffix( ncol ) ).value() + L"=" + val->toSQL( ncol ) ); } } } } if ( cols.isnull() ) { throw Exceptions::Null( L"Could not find any owner column values for " + facet->implName() ); } else { return cols.value(); } } /* FSLib::Compound::Notification */ inline Compound::Notification::~Notification() { } inline Compound::Notification::t_action Compound::Notification::aboutToRead( const Value * ) { return e_keep; } inline Compound::Notification::t_action Compound::Notification::loaded( const Value * ) { return e_keep; } inline Compound::Notification::t_action Compound::Notification::aboutToWrite( Value * ) { return e_keep; } inline Compound::Notification::t_action Compound::Notification::changed( Value * ) { return e_keep; } /* FSLib::Attribute::Pointer */ inline FSLib::Attribute::Pointer::~Pointer() { } /* FSLib::Attribute::Attribute */ inline FSLib::Attribute::Attribute::Attribute( const Column &def, Compound &holder ) : m_definition( def ), m_holder( holder ) { } inline FSLib::Attribute::Attribute::~Attribute() { } inline const Column &FSLib::Attribute::Attribute::definition() const { return m_definition; } inline Compound &FSLib::Attribute::Attribute::holder() const { return m_holder; } /* FSLib::Attribute::Facet */ inline FSLib::Attribute::Facet::Facet( const Definition::Column &def, Compound &holder ) : FSLib::Attribute::Attribute( def, holder ) { holder.facet( this ); } bool FSLib::Attribute::Facet::nullable() const { return false; } bool FSLib::Attribute::Facet::isnull() const { return false; } bool FSLib::Attribute::Facet::loaded() const { return true; } inline Persistent &FSLib::Attribute::Facet::referenced() const { return const_cast< FSLib::Attribute::Facet & >( *this ); } boost::shared_ptr< Persistent > FSLib::Attribute::Facet::candidate() { return boost::shared_ptr< Persistent >(); } /* FSLib::Attribute::Value */ inline FSLib::Attribute::Value::Value( const Column &def, Compound &holder ) : Attribute( def, holder ) { holder.value( this ); } inline int FSLib::Attribute::Value::columns() const { return 1; } inline Nullable< FSLib::wstring > FSLib::Attribute::Value::suffix( int ) const { return Null; } inline void FSLib::Attribute::Value::aboutToRead() const { Compound::t_subscribers toRetire; for ( Compound::t_subscribers::const_iterator iter( holder().subscribers().begin() ); iter != holder().subscribers().end(); ++iter ) { if ( (*iter)->aboutToRead( this ) == Compound::Notification::e_retire ) { toRetire.push_back( *iter ); } } /*while ( toRetire.begin() != toRetire.end() ) { holder().retire( *toRetire.begin() ); toRetire.erase( toRetire.begin() ); }*/ } inline void FSLib::Attribute::Value::loaded() const { Compound::t_subscribers toRetire; for ( Compound::t_subscribers::const_iterator iter( holder().subscribers().begin() ); iter != holder().subscribers().end(); ++iter ) { if ( (*iter)->loaded( this ) == Compound::Notification::e_retire ) { toRetire.push_back( *iter ); } } /*while ( toRetire.begin() != toRetire.end() ) { holder().retire( *toRetire.begin() ); toRetire.erase( toRetire.begin() ); }*/ } inline void FSLib::Attribute::Value::aboutToWrite() { Compound::t_subscribers toRetire; for ( Compound::t_subscribers::const_iterator iter( holder().subscribers().begin() ); iter != holder().subscribers().end(); ++iter ) { if ( (*iter)->aboutToWrite( this ) == Compound::Notification::e_retire ) { toRetire.push_back( *iter ); } } /*while ( toRetire.begin() != toRetire.end() ) { holder().retire( *toRetire.begin() ); toRetire.erase( toRetire.begin() ); }*/ } inline void FSLib::Attribute::Value::changed() { Compound::t_subscribers toRetire; for ( Compound::t_subscribers::const_iterator iter( holder().subscribers().begin() ); iter != holder().subscribers().end(); ++iter ) { if ( (*iter)->changed( this ) == Compound::Notification::e_retire ) { toRetire.push_back( *iter ); } } /*while ( toRetire.begin() != toRetire.end() ) { holder().retire( *toRetire.begin() ); toRetire.erase( toRetire.begin() ); }*/ } /* $History: table.cpp $ * * ***************** Version 34 ***************** * User: Kirit Date: 16/06/06 Time: 22:22 * Updated in $/FOST.3/F3Util * Added readOnly (from the database) attributes. * * ***************** Version 33 ***************** * User: Kirit Date: 29/10/05 Time: 16:47 * Updated in $/FOST.3/F3Util * Added attribute lookup by column definition. * * ***************** Version 32 ***************** * User: Kirit Date: 21/07/05 Time: 17:22 * Updated in $/FOST.3/F3Util * Removed class FSLib::Compound::Subscriber as it was not used. * * ***************** Version 31 ***************** * User: Kirit Date: 6/07/05 Time: 14:37 * Updated in $/FOST.3/F3Util * Compound now allows finding of persistent object it represents. * * ***************** Version 30 ***************** * User: Kirit Date: 5/07/05 Time: 17:02 * Updated in $/FOST.3/F3Util * Aggregated objects are now only commited when they are loaded into the * cache. Stops a cache miss fault when in a transaction. * * ***************** Version 29 ***************** * User: Kirit Date: 18/03/05 Time: 11:35 * Updated in $/FOST.3/F3Util * FSLib::Definition::Column now uses FOST.3 standard jargon. * * ***************** Version 28 ***************** * User: Kirit Date: 17/03/05 Time: 16:08 * Updated in $/FOST.3/F3Util * Facets can now be added, but they don't work 100% yet. * * ***************** Version 27 ***************** * User: Kirit Date: 16/03/05 Time: 17:25 * Updated in $/FOST.3/F3Util * Start of more complete form implementations especially where dealing * with facets. * * ***************** Version 26 ***************** * User: Kirit Date: 11/02/05 Time: 13:47 * Updated in $/FOST.3/F3Util * Improved error reporting where SQL generation failures occur. * * ***************** Version 25 ***************** * User: Kirit Date: 25/06/04 Time: 11:41 * Updated in $/FOST.3/F3Util * Basic new framework for writing HTML interfaces. * * ***************** Version 24 ***************** * User: Kirit Date: 9/02/04 Time: 12:41 * Updated in $/FOST.3/F3Util * Added optimisations for the case where all members of a facet attribute * are killed before being read from the database. No database reads are * now triggered and more efficient SQL is generated for handling the in * database elements. * * ***************** Version 23 ***************** * User: Kirit Date: 10/11/03 Time: 12:45 * Updated in $/FOST.3/F3Util * Added nullable and isnull to all attribute types. * * ***************** Version 22 ***************** * User: Kirit Date: 3/11/03 Time: 12:07 * Updated in $/FOST.3/F3Util * Added extra run-time type identification. * * ***************** Version 21 ***************** * User: Kirit Date: 27/10/03 Time: 13:16 * Updated in $/FOST.3/F3Util * New property output method works with ability to override default * behaviour on several basis. * * ***************** Version 20 ***************** * User: Kirit Date: 9/10/03 Time: 15:44 * Updated in $/FOST.3/F3Util * Headers re-arranged to give a proper SDK feel and to make determination * of required headers simpler. * * ***************** Version 18 ***************** * User: Kirit Date: 4/10/03 Time: 0:47 * Updated in $/FOST.3/F3Util * FSDB files incorporated into F3Util.DLL. * * ***************** Version 17 ***************** * User: Kirit Date: 3/10/03 Time: 16:09 * Updated in $/FOST/Cpp/FSDB * Added stdafx.h and stdafx.cpp pre-compiled header support. * * ***************** Version 16 ***************** * User: Kirit Date: 2/10/03 Time: 12:22 * Updated in $/FOST/Cpp/FSDB * Added != operator to Columns. * * ***************** Version 15 ***************** * User: Kirit Date: 1/10/03 Time: 17:54 * Updated in $/FOST/Cpp/FSDB * Changed subscription interface for less syntax (typing). * * ***************** Version 14 ***************** * User: Kirit Date: 20/07/03 Time: 22:25 * Updated in $/FOST/Cpp/FSDB * * Better reporting of exceptions in some circumstances. * * Addition of Fraction attribute handler. * * ***************** Version 13 ***************** * User: Kirit Date: 10/05/03 Time: 13:58 * Updated in $/FOST/Cpp/FSDB * Sorted out an issue with facets of facets. * * ***************** Version 12 ***************** * User: Kirit Date: 28/04/03 Time: 14:46 * Updated in $/FOST/Cpp/FSDB * Changed Facet handling to support renaming of owner columns. * * ***************** Version 11 ***************** * User: Kirit Date: 8/03/03 Time: 19:34 * Updated in $/FOST/Cpp/FSDB * Implementation now allows multiple SQL columns to be handled by a * single virtual column. * * ***************** Version 10 ***************** * User: Kirit Date: 7/01/03 Time: 14:46 * Updated in $/FOST/Cpp/FSDB * Changes to Nullable<> to make use comparisons less error prone. * * ***************** Version 9 ***************** * User: Kirit Date: 15/07/02 Time: 19:24 * Updated in $/FOST/Cpp/FSDB * Minor tidying of interface definitions. * * ***************** Version 8 ***************** * User: Kirit Date: 14/07/02 Time: 13:53 * Updated in $/FOST/Cpp/FSDB * * Demo::ABNAmro::Counterparty now uses notifications to synchronise its * display name. * * Notifcations restructured so that they can be retired (more) * correctlly. * * FSLib::Class::dBCommitNew & FSLib::Class::dBCommitDelete now deal * (more) correctly with types where there are tables that only have key * values. * * Facets now include an internal factory (in the Attribute) for better * delegation of load/delete handling. * * All FSLib::Object attributes now use new style attribute handling. * * ***************** Version 7 ***************** * User: Kirit Date: 5/07/02 Time: 10:52 * Updated in $/FOST/Cpp/FSDB * * FSLib::Content::PageContent is now an auto-loaded facet using the new * attribute machanism. * * Various debugs and improvements of facet and attribute handling. * * ***************** Version 6 ***************** * User: Kirit Date: 4/07/02 Time: 13:32 * Updated in $/FOST/Cpp/FSDB * * Removed FSLib::Key class (now handled internally by * Definition::Compound). * * Refactored Facet::Attribute so that there are now seperate AutoLoad * and ManualLoad implementations depending on the required behaviour for * initialisation. * * ***************** Version 5 ***************** * User: Kirit Date: 2/07/02 Time: 12:32 * Updated in $/FOST/Cpp/FSDB * Integrated new attribute and table handling into full source code. * There are still many performance optimisations that should be done, but * the basic mechanism works. * * ***************** Version 4 ***************** * User: Kirit Date: 24/06/02 Time: 21:26 * Updated in $/FOST/Cpp/FSDB * Addition of aggregation support for columns. * * ***************** Version 3 ***************** * User: Kirit Date: 20/06/02 Time: 15:15 * Updated in $/FOST/Cpp/FSDB * Renamed classes and re-arranged slightly. * * ***************** Version 2 ***************** * User: Kirit Date: 17/06/02 Time: 14:43 * Updated in $/FOST/Cpp/FSDB * Moved attribute handling to new header file and implemented the final * SQL operations. * * ***************** Version 1 ***************** * User: Kirit Date: 17/06/02 Time: 12:47 * Created in $/FOST/Cpp/FSDB */