Sets are generally used to implement one-to-many relationships among objects or to hold the results of queries. They are implemented as a container class, and may contain objects of any persistent class. PtObjectSet is the base class for all sets of persistent objects.
This chapter documents the functions for PtObjectSet, and also serves as the main description for PtOnDemandSet, which is derived from PtObjectSet. When PTXX finds a set declaration which includes one of your persistent classes, it creates a new class to manage sets for that persistent class. The new class which PTXX generates is derived from PtObjectSet. Most of the functions you will use are directly inherited from PtObjectSet, but a type-safe Get() function is created in the generated class. For instance, JetSet is derived from PtObjectSet, but it's Get() function uses only Jet pointers and Jet ondemands, not PtObject pointers or PtOndemands. PtAllSets are also derived from PtObjectSet.
PTXX-generated ObjectSets are discussed in the chapter "PTXX-generated classes" in this Reference Guide.
You do not declare PtObjectSets directly. They are generated by the PTXX precompiler. See the chapter "Sets" in your Programmer's Guide for general information on declaring and using sets, including PtObjectSets.
Files to include | Class declaration | Base class |
poet.hxx | ptobjset.hxx | PtCallback |
constructor | PtObjectSet(PtAccessMethod AM, PtSetType settype,PtBase* Base = 0, int initnum = 0); |
destructor | virtual ~PtObjectSet(); |
Append | virtual int Append(PtObject* pObj, int do_remember = 1); |
Assign | virtual void Assign(PtBase* Base); |
BeginCriticalSection | virtual void BeginCriticalSection(); |
CheckIn | virtual int CheckIn( PtDepthMode ); |
CheckOut | virtual int CheckOut( PtWorkSpace *, PtDepthMode = PtNO_ONDEMAND, PtLockMode = PtLK_DELETEvWRITE ); |
Clear | virtual int Clear(); |
Delete | virtual int Delete(); |
EndCriticalSection | virtual void EndCriticalSection(); |
Find | int Find(PtObject* pObj); |
Get | int Get(PtObject*& pObj, long offset = 0,PtSeekMode mode = PtCURRENT,PtLockSpec* pLSpec = 0, PtWatchSpec* pWSpec = 0); |
GetAccMethod | PtAccessMethod GetAccMethod(); |
GetAddressPoint | virtual void* GetAddressPoint( const PtClassId &) const; |
GetBase | PtBase* GetBase(); |
GetClassId | virtual PtClassId& GetClassId() = 0; |
GetCurrentPos | virtual long GetCurrentPos(); |
GetDefaultLock | PtLockSpec* GetDefaultLock(); |
GetDefaultWatch | PtWatchSpec* GetDefaultWatch(); |
GetDescId | virtual PtClassId& GetDescId() = 0; |
GetExpectedNum | virtual PtDWord GetExpectedNum(); |
GetMetaType | virtual PtMetaSet* GetMetaType(); |
GetNum | virtual PtDWord GetNum(); |
GetSetType | PtSetType GetSetType(); |
Insert | virtual int Insert(PtObject* pObj, int do_remember=1); |
Lock | virtual int Lock( PtLockSpec* pSpec = 0); |
Make | static PtObjectSet* Make(PtBase* , const PtString& classname, PtSetType); |
Put | virtual int Put(PtOnDemand& Ond ); |
Query | virtual int Query(PtQuery* , PtObjectSet* Result = 0, PtLockSpec* plk = 0, PtWatchSpec* pwatch = 0); |
Seek | virtual int Seek(long offset, PtSeekMode mode); |
SetDefaultLock | void SetDefaultLock(PtLockSpec* = 0); |
SetExpectedNum | virtual void SetExpectedNum(PtDWord num); |
SetDefaultWatch | void SetDefaultWatch(PtWatchSpec* = 0); |
SetReadAhead | virtual int SetReadAhead(PtWord); |
Unget | virtual int Unget(PtOnDemand& Ond, PtLockSpec* pLSpec = 0,PtWatchSpec* pWSpec = 0); |
Unlock | virtual int Unlock(PtLockSpec* pSpec = 0); |
UnsetWatch | virtual int UnsetWatch(PtWatchSpec* pSpec = 0); |
UpdateSource | virtual int UpdateSource( PtDepthMode = PtNO_ONDEMAND, PtLockMode = PtLK_DELETEvWRITE ); |
Watch | virtual int Watch(PtWatchSpec* pSpec = 0); |
- PtObjectSet::PtObjectSet(); PtObjectSet::PtObjectSet(PtAccessMethod AM, PtSetType settype,PtBase* Base = 0, int initnum = 0);
These are the constructors for a set. Ignore the second, more complicated form - it is used internally by POET. If the set is part of a persistent object then PTXX automatically defines your set type and derives it from the proper base types so that the second form of the constructor will be called whenever it is needed. You don't have to do this explicitly:
If you need a result set for a query then you will declare the type of the set using a typedef in the .hcd file and use the first form of the constructor, without parameters:
- virtual PtObjectSet::~PtObjectSet()
Destructor. The destructor for a PtObjectSet does a Forget() on each member of the set if the set is a pointer set. If it is an AllSet, it does not. If it is a PtOnDemandSet, it will do the Forget() on those objects it has responsibility for; i.e., for those objects which have been added to the set since the constructor was called, except for those objects which were added using ondemands which did not have responsibility for the objects they reference. See the chapter on "Persistent Objects" in your Programmer's Guide for details on link counts.
- int PtObjectSet::Append(PtObject* pObj, int do_remember = 1) int PtObjectSet::Append(PtOnDemand& odObj)
Appends an element to the end of the set.
PtObject* pObj or PtOnDemand& odObj | Element to be appended. |
int do_remember | if 1, the set takes responsibility for the object (see discussion, below) |
The current internal position does not change.
When the first parameter is a pointer, link counts and responsibility are handled like this: If the set contains pointers to persistent objects then the object's link count is always incremented and the set always takes responsibility for the object. If the set is an ondemand set, then the object's link count is incremented unless do_remember is set to 0 - in this case, the set does not take responsibility for the object, and the object's link count is not incremented.
When the first parameter is an ondemand, link counts and responsibility are handled like this: the set takes responsibility for the object if and only if the ondemand had responsibility.
PtOnDemandSet is derived from PtObjectSet. If the set is an ondemand set, the object must be assigned to a database before it can be added to a set; if the object is not assigned, this function will fail. Type checking is done at run time if BeTypeSafe is set. See the chapter "Configuration files" for discussion of the BeTypeSafe keyword. You can also set type safety using the method PtBase:: SetBeTypeSafe(), which is discussed in the chapter "PtBase."
A non-zero return value indicates an error.
- void PtObjectSet::Assign(PtBase* pb)
Assigns the set to a database. In general, you will only do this for AllSets.
pb | Database identifier. |
A set must be assigned to a database if it is to be used for queries, sorts and finds.
Note: It is not usually necessary to use this method unless you are using sets that are not members of persistent objects. If a set is read from the database then it is automatically assigned. If a set is a member of a persistent object then it is assigned when that object is stored.
- virtual void PtObjectSet::BeginCriticalSection()
enters a critical section local to this object. If the critical section is already in use by a different thread, the function blocks until the other thread calls EndCriticalSection().
This function can be used to serialize access if you are using the same PtObjectSet object in different threads simultaneously and you need to call more than one function sequentially. You do not need to call this function if you are using different PtObjectSet objects in every thread.
- int PtObjectSet::CheckIn(PtDepthMode dmode = PtDEEP)
Partially check-in the objects contained within the set. See the chapter on check-out/check-in in the Programmer's Guide.
PtDepthMode dmode=PtDEEP | which subobjects belongs to this operation |
- int PtObjectSet::CheckOut(PtWorkspace *pws, PtDepthMode dmode = PtNO_ONDEMAND, PtLockMode lkmode = PtLK_DELETEvWRITE)
Check-out the objects contained within the set into the workspace 'pws'. See the chapter on check-out/check-in in the Programmer's Guide.
PtWorkspace *pws | the workspace into which the objects should be checked out |
PtDepthMode dmode=PtNO_ONDEMAND | which subobjects belong to this operation |
PtLockMode lkmode=PtLK_DELETEvWRITE | how the objects in the original base should be locked |
- int PtObjectSet::Clear()
Removes all elements from the set.
If the set contains pointers to persistent objects then the link count of each object in the set is decremented. If the set is a PtOnDemandSet, the link count of each object in the set is decremented if and only if the set has responsibility for that object. Please see the chapter "Persistent objects" in the Programmer's Guide for a discussion of responsibility. A non-zero return value indicates an error.
- int PtObjectSet::Delete()
Deletes the current element from the set.
An object set always has one internal position. The internal position is not changed by Delete(), but it now refers to the next element. If you delete the last element in the set then the internal position is undefined. If the set contains pointers to persistent objects then the link count of the object is decremented. The element is not deleted from the database. It is only deleted from RAM if the resulting link count is zero. To delete the object from the database use the object's Delete() member function. Note that both of these functions work very differently than the C++ delete operator, which removes an object from RAM regardless of the link count.
A non-zero return value indicates an error.
- virtual void PtObjectSet::EndCriticalSection()
leaves a critical section local to this object. After this call, other threads are able to enter a critical section for this object.
- int PtObjectSet::Find(PtObject* pObject) int PtObjectSet::Find(PtOnDemand& odObject) int PtObjectSet::Find(PtObjId& surr)
Performs a Seek() to the object's position in the set by searching for the object's object identity. If the set is an AllSet then any sort order specified by PtAllSet:: SortBy() is not changed. An error is returned if the object is not in the set or if the object has not been assigned to the database. The set has to be assigned.
PtObject* pObjector PtOnDemand& odObject | The object to be found |
0 | Success |
Non-zero | Could not position to the object (object not assigned or object not in set) |
- int PtObjectSet::Get(PtObject*& pObj, long offset = 0, PtSeekMode mode = PtCURRENT, PtLockSpec* pLSpec = 0, PtWatchSpec* pWSpec = 0) int PtObjectSet::Get(PtOnDemand& odObj, long offset = 0,
- PtSeekMode mode = PtCURRENT, PtLockSpec* pLSpec = 0,
- PtWatchSpec* pWSpec = 0)
Reads an element. Only the first parameter is required, so don't let all the default parameters scare you!
PtObject*& pObj or PtOnDemand& Ond | Object pointer or ondemand to hold the reference to the object which is read |
long offset=0 | Offset in the set - which object should be read? |
PtSeekMode mode=PtCURRENT | Seek mode |
PtLockSpec*, pLSpec=0 | Lock specification for the object to be read |
PtWatchSpec*, pWSpec=0 | Watch specification for the object to be read |
The simplest form of Get() simply reads the current object.
If the object is not in memory then Get() reads it from the database and sets the reference parameter to the new object. If the object is in memory then Get() simply sets the reference parameter to the appropriate address in RAM. To ensure that all methods are properly initialized Get() calls the object's factory constructor before reading it from the database. When you are done with the object, use Unget() to free up its resources; if there are no further references to the object, POET will then remove it from memory. If you need to keep the object in memory then call the object's Remember() method before calling Unget(); the object can then be removed from memory later using it's Forget() method. This is all described in the discussion on link counts in the chapter "Persistent objects" in your Programmer's Guide.
If your object contains transient members then you are responsible for initializing them after the Get(). The best way to do this is usually to override PtObject::Activate().
It is usually simpler to perform the seek in the Get() function. To do this you need to specify the next two parameters, which are the same as the parameters to the Seek() function:
You may want to set a lock on an object when you read it from a set. Locks are described in the chapter "Locking." If you specify a PtLockSpec as the fourth parameter to Get() then the object will be locked when it is read from the set. You can specify the PtLockSpec as a parameter:
If you call Remember() for the object to keep it from being deleted when Unget() is called then you probably want to keep the lock in place after the Unget(). However, Forget() will not remove the locks, so you have to remember to unlock the object before you Forget() it:
If you neglect to do this then the locks remain in place until your application terminates or disconnects from the POET server. You can also use SetDefaultLock(...) and leave out the lock specification on Get/Unget. Get() can also be used to set watches. You can set a watch on an object when you read it from a set by specifying a PtWatchSpec as the fifth parameter:
Obviously, you can set both a lock and a watch when you read the object:
Any non-zero return value indicates an error.
- PtAccessMethod PtObjectSet::GetAccMethod()
Returns the access method for the set. A PtAccessMethod is an enum which may take the following values:
PtDIRECT | The set contains non-persistent objects or C++ base types, or ondemands. |
PtINDIRECT | The set contains pointers to persistent objects. |
- virtual void * PtObjectSet::GetAddressPoint( const PtClassId & clid ) const
Returns the address point for the given class 'clid'. Could be used for instances of virtual or multiple derived classes to get the different entry points for specific classes.
const PtClassId & clid | The class whose entry point within this object should be returned. |
- PtBase* PtObjectSet::GetBase()
If the set is assigned, returns a pointer to the PtBase to which it is assigned. Returns zero otherwise.
- virtual PtClassId& PtObjectSet::GetClassId()
Returns the PtClassId for the set type itself. For instance, if this set was declared like this:
Then it would return the PtClassId for PersonIndirectLSet, which is the set type which PTXX generates for the above declaration.
- PtLockSpec* PtObjectSet::GetDefaultLock()
Gets the current default lock for the set. If there is no default lock then zero is returned.
- PtWatchSpec* PtObjectSet::GetDefaultWatch()
Gets the current default watch for the set. If there is no default watch then zero is returned.
- virtual PtClassId& PtObjectSet::GetDescId()
Returns the PtClassId for the class contained in the set. For instance, if this set was declared like this:
Then it would return the PtClassId for Person. Since sets are polymorphic, the set may contain any object which belongs to a class derived from Person, e.g. Firemen, Programmers, and Morticians.
- virtual PtDWord PtObjectSet::GetExpectedNum()
Returns the expected number of elements contained in the set.
- virtual PtMetaSet* PtObjectSet::GetMetaType()
Returns the PtMetaType pointer for the set, which is always a PtMetaSet.
- PtDWord PtObjectSet::GetNum()
Returns the number of elements contained in the set.
- PtSetType PtObjectSet::GetSetType()
Returns the set type for the set. A PtSetType may be:
PtCSET | The set is a cset. |
PtLSET | The set is an lset. |
PtHSET | The set is an hset. |
PtALLSET | The set is an AllSet |
- int PtObjectSet::Insert(PtObject* pObj, int do_remember = 1) int PtObjectSet::Insert(PtOnDemand& odObj)
Inserts the item at the current internal position.
PtObject* pObj or PtOnDemand& odObj | Element to be appended. |
int do_remember | if 1, the set takes responsibility for the object (see discussion, below) |
After completion the newly inserted item is at the current position, which is not changed. You can change the current position using Seek() if you want to insert items at the beginning of the set.
When the first parameter is a pointer, link counts and responsibility are handled like this: If the set contains pointers to persistent objects then the object's link count is always incremented and the set always takes responsibility for the object. If the set is an ondemand set, then the object's link count is incremented unless do_remember is set to 0 - in this case, the set does not take responsibility for the object, and the object's link count is not incremented.
When the first parameter is an ondemand, link counts and responsibility are handled like this: the set takes responsibility for the object if and only if the ondemand had responsibility.
If the set is an ondemand set, the object must be assigned to a database before it can be added to a set; if the object is not assigned, this function will fail.
Type checking is done at run time if BeTypeSafe is set. See the chapter "Configuration files" for discussion of the BeTypeSafe keyword. You can also set type safety using the method PtBase:: SetBeTypeSafe(), which is discussed in the chapter "PtBase."
Any non-zero return value indicates an error.
- virtual int PtObjectSet::Lock(PtLockSpec* pSpec = 0)
Sets a lock which will be used for all objects referenced by the set. Adding an object to the set means that the lock is applied to the object; removing an object from the set also removes the lock from the object. If no lock is specified then the default lock for the set is activated. Default locks are set using the SetDefaultLock() method.
Any non-zero result indicates an error.
- static PtObjectSet* PtObjectSet::Make(PtBase* pBase,
- const PtString& PtObjectSet, PtSetType type)
Creates an object set to contain objects of the given class, and assigns the set to the database. Since this is a static function, you do not need to create a PtObjectSet to call this function.
PtBase* pBase | The database to which the set should be assigned |
const PtString& PtObjectSet | The name of the class that the set should contain |
PtSetType type | PtCSET, PtLSET, PtHSET, or PtALLSET |
A pointer to the new set. If the set could not be created, returns 0.
- int PtObjectSet::Put(PtOnDemand& odObj) int PtObjectSet::Put(PtObject* pObj, int do_remember = 1)
Overwrites the current element.
PtObject* pObj or PtOnDemand& odObj | Element to be appended. |
int do_remember | if 1, the set takes responsibility for the object (see discussion, below) |
The object at the current internal position is overwritten by the new object. The current internal position remains unchanged. Use Seek() to position within the set.
When the first parameter is a pointer, link counts and responsibility are handled like this: If the set contains pointers to persistent objects then the new object's link count is always incremented, the old object's link count is decremented, and the set always takes responsibility for the new object. If the set is an ondemand set, then the new object's link count is incremented unless do_remember is set to 0 - in this case, the set does not take responsibility for the object, and the object's link count is not incremented. The set does a Forget() for the old object if it had responsibility for it.
When the first parameter is an ondemand, link counts and responsibility are handled like this: the set takes responsibility for the object if and only if the ondemand had responsibility. The set does a Forget() for the old object if it had responsibility for it.
If the set is an ondemand set, the object must be assigned to a database before it can be added to a set; if the object is not assigned, this function will fail.
The type of Elem must match the declaration in your .hcd file. Type checking is done at run time if BeTypeSafe is set. See the chapter "Configuration files" for discussion of the BeTypeSafe keyword. You can also set type safety using the method PtBase:: SetBeTypeSafe(), which is discussed in the chapter "PtBase."
Note: Put() is not a way to rewrite an object that you read using Get(). This would lead to inconsistent link counts. In fact, there is no need to rewrite such an object: the reference to the object is in the set and remains in the set after calling Get(). Simply change the object directly - POET makes sure that all references to the object are handled consistently. Any non-zero return value indicates an error.
- int PtObjectSet::Query(PtQuery* QueryArg, PtObjectSet* Result=0)
Performs a query on the set and appends the result in Result. If no result set is given the result set replaces the set which is queried.
QueryArg | Query specification - see PtQuery for details. |
Result | Result set. |
If a result set is specified and the set contains pointers to persistent objects then the link count of every object in the result set is incremented. If no result set is specified and the set contains pointers to persistent objects then the link count is decremented for every object that is removed from the set which is queried.
Please note that a query can only be performed on objects that have been inserted with Append(), Insert() or Put() and previously have been assigned. The query compares the objects in memory, except for with PtOnDemand referenced subobjects.. Any non-zero return value indicates an error.
- int PtObjectSet::Seek(long Offset, PtSeekMode RelativeTo)
Sets the internal position for the set.
Offset | Number of objects. If negative, will position backwards. |
RelativeTo | PtSTART, PtEND or PtCURRENT. |
This function is analogous to the standard lseek() function, but Offset is measured in elements instead of bytes. If Offset is 12 and RelativeTo is PtSTART then Seek() sets the internal position to the 12th object from the start of the set. Negative offsets are used when positioning backwards within the set. Any non-zero return value indicates an error. Note: Seek() is very useful for Insert() and Put(), but when you use Get() it is easier to specify the seek parameters directly in the Get() method. In fact, using Seek() explicitly seems to encourage people to ignore error codes.
Consider the following example:
Lazy human beings tend to leave out the error handing for Get() in the second example. The code which uses an explicit Seek() is also noticeably harder to read.
- void PtObjectSet::SetDefaultLock(PtLockSpec* = 0)
Sets the default lock for the set. This lock is used if no PtLockSpec is specified when the set is locked and also on Get / Unget calls. If no PtLockSpec is specified then SetDefaultLock sets the default lock to zero, which means that no locking is performed. Any non-zero result indicates an error.
- void PtObjectSet::SetDefaultWatch(PtWatchSpec* = 0)
Sets the default watch for the set. This watch is used if no PtWatchSpec is specified when the set is watched and also on Get / Unget calls. If no PtWatchSpec is specified then SetDefaultWatch sets the default watch to zero, which means that no watching is performed. Any non-zero result indicates an error.
- virtual void PtObjectSet::SetExpectedNum( PtDWord num )
Sets the expected number of elements contained in the set.
- virtual int PtObjectSet::SetReadAhead(PtWord n)
Specifies the size of a read-ahead cache which POET will use when reading items for a particular set. It is particularly useful for writing browsers. The cache takes responsibility for the objects it reads. If the object was not in memory previously, its link count is set to one. If it was in memory, its link count is incremented.
Setting read-ahead to zero flushes the cache and decrements the link count of any objects in the cache.
Note: locks and watches are applied when the object is read using Get(), not when it is read into the cache, so you should be very careful if you use this for applications where you need concurrency control or distributed objects. The cache is a "forward" cache, don't use it when stepping backwards.
- int PtObjectSet::Unget(PtOnDemand& odObj, PtLockSpec* pLSpec = 0, PtWatchSpec* pWSpec = 0) int PtObjectSet::Unget(PtObject* pObj, PtLockSpec* pLSpec = 0, PtWatchSpec* pWSpec = 0)
Frees up resources associated with an element.
pObj or odObj | Element to unget. |
PtLockSpec*, pLSpec=0 | Lock specification for the object to be unget |
PtWatchSpec*, pWSpec=0 | Watch specification for the object to be unget |
PtObjectSet:: Get() must allocate resources if it loads an object into memory. PtObjectSet:: Unget() deallocates these resources.
In the current implementation of POET this method simply decrements the link count if the object is persistent and removes it from RAM if there are no other references. Future versions of POET may do more. If you want to keep an object in memory you can call the object's Remember() method before calling Unget():
Returns the new link count for the object. If this is 0 then the object has been removed from memory.
- virtual int PtObjectSet::Unlock(PtLockSpec* pSpec = 0)
Removes a lock which was set using Lock(). If no PtLockSpec is specified then it inactivates the default lock for the set.
Any non-zero result indicates an error.
- virtual int PtObjectSet::UnsetWatch(PtWatchSpec* pSpec = 0)
Removes a watch which was set using Watch(). If no PtWatchSpec is specified then it inactivates the default watch for the set. Any non-zero result indicates an error.
- int PtObjectSet::UpdateSource(PtDepthMode dmode = PtDEEP, PtLockMode lkmode = PtLK_DELETEvWRITE)
Partially check-in the objects contained within the set. The checked out objects are left in the workspace. The objects in the original database will re-locked with 'lkmode'.
PtDepthMode dmode=PtDEEP | which subobjects belongs to this operation |
PtLockMode lkmode=PtLK_DELETEvWRITE | how the objects in the original base should be locked |
- virtual int PtObjectSet::Watch(PtWatchSpec* pSpec = 0)
Sets a Watch which will be used for all objects referenced by the set. Adding an object to the set means that the watch is applied to the object; removing an object from the set also removes the watch from the object. If no watch is specified then the default watch for the set is activated. Default watchs are set using the SetDefaultWatch() method. Any non-zero result indicates an error.
Copyright (c) 1996 POET Software, Inc. All rights reserved. Reproduction in whole or in part in any form or medium without the express permission of POET Software, Inc. is prohibited.