home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 14 Text
/
14-Text.zip
/
techov.zip
/
TECHOVER.TXT
Wrap
Text File
|
1993-12-26
|
35KB
|
822 lines
Hello,
Thank you for your interest in POET. For more information on POET please contact:
POET Software Corporation
4633 Old Ironsides Drive, Suite #110
Santa Clara CA 95054
Sales (408) 970-4640
Fax (408) 970-4630
Best Regards,
Brad Sturtevant
POET Software Technical Support
Compuserve: 70402.74
Internet: 70402.74@compuserve.com
POET TECHNICAL OVERVIEW April 20, 1993
POET (Persistent Objects and Extended database Technology) is an
innovative object-oriented database development system for C++
applications. POET has received a variety of awards, including Computer
Language's Jolt award for product excellence, Computer Language's
productivity award, and BYTE Magazine's award of distinction.
POET is truly object oriented. It supports fully all aspects of C++ objects,
including encapsulation, inheritance, polymorphism, object identity, and
references among objects. POET also gives you full database functionality,
including queries, device independent formats, and sharing of objects
among programs in a multi-user environment. Database operations
manage your C++ objects directly without programmer intervention.
Instead of making you understand our database formats, we have taught
our database to understand your objects.
POET is available on MS-DOS, MS-Windows, MS-NT, Macintosh, OS/2,
NeXT, SCO, Interactive, Sun, and various other flavors of UNIX. Both
single-user and client/server versions are available. Heterogeneous
networks are also supported--no matter what computer your application
runs on, it can use any server on the network. Because POET uses the
same database format for all systems, objects stored by one computer can
be used on any other computer.
OBJECTS NEED POET...
Applications continue to become more complex, and often require
immense effort to develop and maintain. Object oriented techniques let
the structure of your program closely reflect the structure of the problem
to be solved. Related code and data are combined into objects, and C++
has rich features for expressing the structural and semantic relationships
among objects. Object oriented programs are modular, easy to understand,
easy to maintain, and easy to extend. This significantly reduces both
development and maintenance costs, which explains the rapid growth in
object-oriented programming.
Conventional database systems (relational database, ISAM, b-tree, etc.)
manage their data in two dimensional tables. Complex structures must be
broken up and distributed among these tables, which offer no real support
for the object oriented programming model. As a result, many programs
stop being object oriented whenever they use the database. The program
and the database have two different designs, and the program must
constantly convert back and forth. This significantly increases both
program complexity and run time overhead.
A conventional database is like a garage which forces you to take your car
apart and store the pieces in little drawers. You can do it, but you
probably don't want to. POET lets you store even complex C++ objects
directly, without modification. Only object oriented databases can store
complex objects 1:1.
POET's database operations preserve all aspects of your C++ objects.
References among objects are preserved, as is the full polymorphic
structure of each object. Only one command is needed to store, read, or
delete an object, now matter how complex the object is. For instance, you
could use one command to store a CAD drawing with many shapes, a document
with many paragraphs and images, or an invoice with many items. The
individual shapes, paragraphs, images, or items are objects in their own
right, and can be processed independently in other parts of your program.
Database management with POET requires a fraction of the effort and a
fraction of the code. Less code means less work--your programs are easier
to develop and maintain.
POET -- A THUMBNAIL SUMMARY
POET Keywords. POET extends C++ syntax to allow you to specify
database attributes directly in your class declarations.
POET Precompiler. The precompiler translates POET's extended C++
declaration syntax into ANSI C++ header files which you include in your
program. It also adds your class declarations to the class dictionary of
the database
POET Tool Classes. POET's tool classes provide the C++ interface to the
database. In addition, they allow management of sets and query
specification.
POET Run Time System. The run time system manages the database and
processes queries. In multi-user systems it is part of the server; in
single-user systems it is linked to the application.
PROGRAMMING WITH POET
In the next section we would like to illustrate POET programming with an
example. We will design an inventory management system for a computer
supply store and show how it would be implemented with POET.
Scenario : Inventory Management
An inventory system must manage a wide variety of data. Our store sells
hardware, software, literature, services, and accessories. We need to
generate packing lists and invoices which list the items we sell. Our
database must keep track of manufacturers, distributors, customers, and
employees. The first step in object oriented design is often to list the
objects in the system and to group related objects. Delivery notices and
invoices are both documents. We will call anything that can be listed on
an invoice an item. Manufacturers, customers, and employees all have
names and addresses. For our purposes we can call them all persons.
Our database will have to manage objects of the following types:
Item Hardware, Software, Literature, Service, Accessory
Document Delivery Notice, Invoice
Person Manufacturer, Distributor, Customer, Employee
Representing the individual objects is not enough; we must also represent
the relationships among objects, and doing this naturally is central to the
design of the program. Consider an invoice: An invoice contains the
address of the customer and a list of items. Each item refers to its
manufacturer. We want to represent these relationships directly in our
database design. Direct Integration in C++
Direct Integration in C++
Because C++ is tightly integrated into the C++ programming language you
do not need to convert C++ objects for the database. POET manages your
C++ objects, and it carefully follows the semantics of C++. Database
classes are defined using C++ class declarations with a few simple
extensions. POET does not need a separate class definition; your class
declarations are the only database schema you need. Your database objects
are your program objects. This dramatically simplifies database design.
Let's start with the base classes "Person" and "Item". These classes
represent the Person and Item sets in the previous diagram. They will need
data and functions for input and output. The declarations below are
normal C++ class declarations except for one keyword: persistent. Any
class declared with the persistent keyword can be stored in the database.
persistent class Person
{
private:
PtString Name;
PtString Firstname;
PtString Street;
...
public:
virtual int Input (..);
virtual int Print (..);
};
persistent class Item
{
private:
int ItemNumber;
PtString Description;
...
public:
virtual int Input (..);
virtual int Print (..);
};
Now POET has declarations for the set of all Items or the set of all Persons.
As shown in the diagram, each of these sets has subsets. A Software is an
Item, but not all Items are Software. All items have the data and the
methods needed to list them on an invoice. A Manufacturer is a Person,
but not all Persons are Manufacturers. All persons have addresses. How
do we represent these subsets?
C++ represents subsets by using inheritance. POET ensures that this
inheritance always works properly for objects stored in the database. In
the following declaration, persistent class Software: public Item means that
a Software is an Item and has all functions and data that any other Item has.
persistent class Software : public Item
{
private:
PtString Release;
public:
...
virtual int Input ();
virtual int Print();
};
persistent class Hardware : public Item
{
private:
...
public:
virtual int Input();
virtual int Print();
};
persistent class Manufacturer : public Person
{
...
cset<Item*> Products;
virtual int Input();
virtual int Print();
};
The "Manufacturer" class contains the statement cset<Item*> Products;.
This is a container which can hold a set of references to Items. These
Items can be "Hardware", "Software", or any other kind of item -- even if
it is a new kind of Item developed after this declaration was written!
The above example shows how POET derives the structure of your objects
and the relationships among them by reading your C++ class declarations.
You simply add POET's keywords. Now let's see how the resulting
database definition is integrated into your program.
The POET Precompiler
Unfortunately, no C++ compiler in the world understands our language
extensions. Therefore, we have written a precompiler which produces code
that can be compiled with any ANSI 2.0 C++ compiler.
Persistent class declarations are usually placed in files with the .hcd
extension. Our precompiler produces a header file with the .hxx extension.
You include this file in your source files.
Of course, the POET precompiler does a lot more than this behind the
curtains. It manages the class dictionary of the database to ensure that
all of your class declarations are registered an up to date. It also
produces code to tell the POET run time system how to manage your objects.
Less Code, Less Work
Since POET can manage both your objects and their relationships without
programmer intervention, your programs are smaller and simpler. POET
applications are easy to write. A single line in a POET program is often
equivalent to many lines of code in traditional database systems.
Suppose our program has just changed the name and business form of a
manufacturer and added a few items to their product line. Now we need to
save these changes. In conventional systems
these objects are stored in a series of two-dimensional tables (Persons,
Manufacturers, Item, Software) and your program must know how to
change your objects into the rows of these tables. In POET you need only
one line: pManufacturer->Store(); POET's precompiler always generates a
Store() member function for any persistent class, so you don't have to
bother with the details. The object is completely stored, and the
references to the items in the product line are automatically updated.
Your application code is much shorter and easier to understand. Less code
also means fewer programming bugs. Moreover, since the class dictionary
resides in the server, you simply send exchange complete objects with the
server instead of all the rows of individual tables needed for a
conventional system. This reduces the communications overhead for
client/server applications.
Of course, you need an open database before you can store an object. The
following code is all you need to connect to a server, open the database,
and store an object:
main()
{
// A PtBase manages the connection to the database.
PtBase base;
base.Connect ("Local");
base.Open ("test");
// Create a manufacturer and read its data
Manufacturer * pManufacturer = new Manufacturer (base);
pManufacturer->Input();
pManufacturer->Store();
base.Close();
base.DisConnect();
}
That's all the code you need!
pManufacturer->Store() is the member function that the POET precompiler
automatically creates to store a persistent object. You need some way to
input the data; in this example we assume you have written a member
function to do this, and pManufacturer->Input() calls this function.
PtBase is a POET class that manages the connection to the database.
base.Connect() and base.DisConnect() are used to establish and break the
connection to the server. In the single- user version you use the server
name "Local". base.Open() and base.Close() open and close the database.
POET's Object Management Model
You have already seen that any C++ class declaration can be made
persistent simply by adding one keyword to its class declaration. The
precompiler translates your persistent class declarations into ANSI 2.0
C++ code. Once the database is open, storing a persistent object requires
one line of code. However, database programming is not a matter of
storing individual objects.
A database system must provide a clear and consistent programming model
for expressing and managing the relationships among objects. This is
where POET really shines. When you program in POET you program in
C++. POET carefully follows the semantics of C++ to provide powerful
database functionality using the programming model that every C++
programmer already knows. C++ inheritance, polymorphism, and pointer
references provide POET with an elegant model for database
programming. All the classes you need to manage the database are
provided, and are used like any other C++ class library.
AllSets: Every Object for a Given Class
Whenever the POET precompiler encounters a persistent class declaration
it creates a set to hold all objects of this type. This set is called an
AllSet, and the name of the AllSet depends on the name of the class. In
our example we have defined the classes "Person", "Manufacturer", "Item",
"Hardware", and "Software". The POET precompiler would generate the
AllSets "PersonAllSet", "ManufacturerAllSet",
'ItemAllSet", "HardwareAllSet", and "SoftwareAllSet" to hold objects for
these classes. When you store the object it is added to the appropriate
classes. Since C++ objects can belong to several classes, a POET object
may belong to several AllSets.
Of course, an object can belong to more than one set. In our design every
"Manufacturer" is also a "Person". Whenever a Manufacturer is stored it
will be added to both the ManufacturerAllSet and the PersonAllSet.
POET's AllSets, like all other sets, use the same inheritance as the objects
they contain. since a "Manufacturer" is a "Person", a ManufacturerAllSet
is a PersonAllSet. If you have a function that browses a PersonAllSet then
you can also use this function with a ManufacturerAllSet.
Reading Objects
When POET creates an AllSet it automatically derives it from PtAllSet,
giving it a variety of methods for managing objects of a given class.
Suppose you want to read the first Person from the database. You simply
call the Get() method of the PersonAllSet, telling it you want the first
person: POET reads the first Person object from the database and builds
this object in your program's memory. In the code below pPerson points to
this first object:
PersonAllSet * AllPersons = new PersonAllSet( base );
Person * pPerson = 0;
...
AllPersons->Get( pPerson ); // read object from database
...
pPerson->Print();
When you read an object from the database it behaves just like the object
that was stored. Its member functions, data, and references are identical
to the original object.
Objects and Polymorphism
If you ask two musicians to play a song, one may start squeezing an
accordion while the other strums a guitar. They are both musicians, but
they are different kinds of musicians and they respond to the same request
in different ways. If they did not know how to play a song, though, they
would not be musicians at all.
Similarly, in C++ objects derived from the same base class may call
completely different functions in response to the same member function
call. This is known as polymorphism, and any C++ function can be used
polymorphically if it is declared virtual and occurs in both a base class
and derived classes.
In practice, polymorphism can often simplify code. For instance, in our
example we need to be able to compute tax for each item on an invoice.
However, taxes are computed differently for different kinds of items. In
the States there is no sales tax for services, but sales tax is charged for
hardware or software. The easiest way to deal with this is to ask each kind
of item to compute its own tax. If we want to compute the total tax for an
invoice we could do it like this:
double TotalTax = 0.0;
Item * pItem;
long i;
for (i=0; Items.Get(pItem, i, PtSTART) == 0; i++)
{
TotalTax += pItem->ComputeTax();
Items->Unget(pItem); // removes the item from memory
}
Because C++ supports polymorphism, each kind of Item can have its own
virtual ComputeTax() function, and we do not need to know the derived
type to call this function. If the object is of type Hardware then
hardware::ComputeTax() will be called, if it is of type Service then
Service::ComputeTax() will be called. In fact, if a new tax category is
introduced in the future then we can create a new kind of Item with a new
ComputeTax() function--the above code will call it correctly without
change and without recompiling!
Note that you can write your C++ objects to the database and retrieve them
without affecting polymorphism. When you read an object it has precisely
the same member functions that it had when it was stored.
Navigation
The objects in your program can refer to each other, and so can the objects
in your database. For instance, an invoice has a list of Items, and each
item has a Manufacturer. Following the references among objects is called
navigation.
Suppose we want to print a description of the Customer for the second
Invoice in the database or print a description for the manufacturer of the
third item on this invoice. In a normal C++ program you would do this by
following pointers in memory. You may be surprised to know that you can
also do this with
objects that you read from the database!
When POET stores an object which has pointers it automatically converts
these into database references. If you read this object from the database
then POET loads the referenced objects and sets your pointers
appropriately. Sets of references are also resolved automatically. To
follow the relationships in your database, you simply follow the pointers
in your C++ programs. This makes it quite easy to make hypertext-style
programs which follow the references in a database.
For our example, let's assume that an invoice has a pointer to the customer
and a set of pointers to Items. An Item has a pointer to its manufacturer:
persistent class Invoice
{
...
Customer *pCustomer;
cset <Item*> Items;
...
};
persistent class Item
{
...
Manufacturer *pManufacturer;
};
The pointers and sets of pointers in the above declarations will be resolved
automatically by POET whenever objects of these classes are read from the
database. This makes navigation quite simple:
...
InvoicesAllSet *Invoices = new InvoicesAllSet(base);
Invoice *pInvoice;
if (Invoices.Get(pInvoice, 1, PtSTART) == 0) // get the second invoice
{
pInvoice->pCustomer->Print(); // print the customer
Item *pItem;
if (Items.Get(pItem, 2, PtSTART) == 0) // get the third item
pItem->pManufacturer->Print(); // print the manufacturer
}
What if the referenced object is deleted? POET has referential integrity:
it knows that the referenced object is gone, so it initializes the pointer
to zero and returns a warning. What if you have large objects or large
sets of references that you do not want loaded into memory? POET also
supports other kinds of references that do not load the object until the
programmer asks for it.
Queries
Queries allow you to find all objects that contain specific values. Suppose
you want to list all customers whose names start with "A*". Query objects
are used to specify queries. The POET precompiler generates a query
specification class for every persistent class it encounters. The query
specification class generated for Customer is called CustomerQuery. If you
want to state that the Name field should start with A, you can do this using
the SetName function. You can also tell the query how to sort the result
set; for instance, we can also sort by Name. CustomerAllSet has a member
function called Query which takes your query specification and builds a set
of matching objects. The code might look like the following:
CustomerAllSet * AllCustomers = new CustomerAllSet (base);
CustomerSubSet * Result = new CustomerResultSet;
CustomerQuery Query;
Customer * pCustomer = 0;
// Specify Query: All customers beginning with "A*" in ascending order.
Query.SetName("A*", PtMATCHES);
Query.SortByName(PtACSENDING);
AllCustomers-> Query(Query, Result);
Result->Get(pCustomer);
The results of the query are placed in a set. You can read this set using
Get(), just as you would with an AllSet. In fact, all sets are derived from
the same base class, PtObjectSet, so you can write one browser that can be
used for result sets, AllSets, or any other sets in your program.
Intelligent Client / Server Architecture
POET is available in both single-user and multi-user versions. The multi-
user version of POET uses a client/server architecture. Application
programs can run on any computer on the network. Access to the database
is done by making requests to one central process, the database server. The
server manages multi-user access and ensures that the database is kept
consistent. Because the server runs on the computer where the database is
stored it can access objects quickly, without network overhead. This
computer is typically much more powerful than the computers that the
client applications run on, which also improves system performance.
Furthermore, since only the results of queries are sent to the clients
network overhead is reduced significantly.
Multi-user databases need to provide features to ensure that updates made
by different processes do not make the database inconsistent. POET
provides traditional features like locking and transactions. It also it
offers more innovative features--a program can ask the server to notify it
when one of its objects is modified by another process, or to notify it
when certain events occur during processing.
Locking
A program can lock an object to ensure that no other process performs
certain actions on that object. Different kinds of locks prohibit different
kinds of actions, such as reading, writing, deleting, or setting locks on
the object. A program can also lock a set, which means that a lock is set
on all objects in the set. A lock can also be set implicitly when an object
is read from a set.
Transactions
Transactions are used to ensure that a series of operations either succeed
completely or fail completely without making any changes to the database.
Every PtBase has a transaction manager which is accessed using the
member function Transaction(). When you start a series of logically
related operations you call the Begin() function of the transaction manager.
Now you can perform any series of database operations. As far as your
program is concerned the database acts as though all of these changes have
actually been made, but in reality nothing has been written to the database.
If operations succeed you can call the Commit() function to write all
changes to the database. If not, you simply call the Abort() function; the
database now looks just like it did when
you called Begin().
PtBase base;
Manufacturer * pMan = new Manufacturer (base);
Customer * pCust = new Customer (base)
pMan->Input();
pCust->Input();
// We want to store both objects. If one of the objects is locked then
// store might fail. If it fails for one object, should fail for both.
base->Transact()->Begin();
if ((pMan->Store() != 0) || (pCust->Store() != 0))
base->Transact()->Abort();
else
base->Transact()->Commit();
Does your program have many levels of nested logic? No problem.
Transactions can also be nested. Each Abort() or Commit() applies to the
current transaction level.
Incidentally, POET also has a second kind of transaction that is invisible
to the user. Any operation which changes a database is performed using our
file-level transaction manager. This ensures that changes either succeed
completely or fail completely, and protects the integrity of your database.
Watch & Notify
Sometimes it is perfectly acceptable for other processes to modify the
objects you are using, but you want to ensure that your process always has
the most recent version. POET allows you to set a watch on object or set
of objects; this means that the database will inform you whenever they are
accessed or modified by another process. You can also ask POET to
update the object in your memory if it is modified by another program.
POET does this automatically without further program intervention.
Suppose our inventory program is running on many different computers,
and changes are being made to the database. If an item is discontinued
then we may no longer sell it. We want to ensure that all programs using
the database are informed instantly. The traditional approach is to force
all applications to reread items from the database if they may have changed.
This increases the number of database accesses that are needed, slowing
down the programs and increasing the network traffic. Worse, the
programmer has to ensure that the item is reread at many different points
in the program. Any part of the code that uses an object in memory can
cause errors if it is critical to use the most recent version of the object
and the programmer forgets to reread it.
In POET you can use the Watch() method to set a watch on an object or set
of objects. UnsetWatch() removes the watch. The PtWatchSpec class is
used to specify the operations that you want to know about, and the
PtMethodRef class is used to specify the action that POET should take if
this operation is performed by another program. The server can notify
clients when an object is modified in the database. You can tell POET to
update the object in your memory or to call a function in your program
when this occurs.
....
pDistributor->Display();
// Define the watch specification: if anybody updates the
// distributor in the database, the POET server should call
// our application's target function
PtMethodRef Target ( pDistributor, (PtFunc) &Distributor::Display()):
PtWatchSpec WatchSpec(PtWATCH_UPDATE, PtDEEP, Target);
// Install the watch for the object.
pDistributor->Watch (&WatchSpec);
Let's assume we have two clients using the same database on a network.
Client 1 executes the code in the previous example. Client 2 modifies the
distributor and stores it. This is what happens:
Time Client 1 Client 2
1 Installs watch using code
from above example
2 modifies and stores
the product line for a
distributor
3 The POET server notices that
the watched object has been
modified, updates the distributor
in this client's RAM, and calls
the target function.
Event Handling
An application is usually blocked while a database operation is performed.
If the operation takes a long time then the application may need to gain
control from time to update the screen, process user input, or allow the
user to cancel the operation.
Event handling allows you to gain control when a database operation
begins, ends, or when a certain number of objects have been processed.
You simply give POET the address of a function which it calls when these
events occur. POET examines the return value of your function to see if
it should continue.
In our example the application opens a window when the operation begins
and periodically checks to see if the Cancel button has been pressed. If
so, it aborts the database operation. When the operation is completed the
window is closed.
The event handler can only call functions that are member functions of
classes derived from PtCallback. In our example we declare a class called
ActionWindow. It has three member functions to handle the window when
processing begins, during processing, and when the operation is finished.
class ActionWindow : public PtCallback
{
public:
int OpenWindow()
{
WindowSystem->OpenWindow(&MessageWindow);
...
return PtEXCCONTINUE; // continue database operation
}
int CancelButton(int percent)
{
WindowSystem->Message(&MessageWindow, "%d percent finished",
percent);
...
if ( ! CANCELBUTTON )
return PtEXCCONTINUE; // continue database operation
else
return PtEXCABORT; // abort database operation
}
int CloseWindow()
{
WindowSystem->CloseWindow(&MessageWindow);
...
return PtEXCCONTINUE;
}
} myActionWindow;
Every PtBase has an exception manager which lets you install callback
functions. We will use three exception manager functions:
SetActionStarting()--Installs the callback function that will be called
when a database operation begins.
SetActionPending()--Installs the callback function that will be called
periodically during database processing.
SetActionTerminated()--Installs the callback function that will be called
when a database operation is terminated.
Because C++ member functions need to know the address of their objects
when they are called, you must specify both the object and the member
function when installing a callback function:
ActionWindow myActionWindow;
base->GetExcMgr()->SetActionStarting (&myActionWindow, (PtFunc)
&ActionWindow::OpenWindow);
base->GetExcMgr()->SetActionPending(&myActionWindow, (PtFuncInt)
&ActionWindow::CancelButton);
base->GetExcMgr()->SetActionTerminated(&myActionWindow, (PtFunc)
&ActionWindow::CloseWindow);
That's all there is to it. Your functions will be called automatically
when a database operation starts, during processing, and when the
operation completes.
POET: An Overview
C++ Language Support
o Tight semantic integration with C++.
o Any C++ object or structure can be made persistent by adding the
persistent keyword.
o Storing and reading a C++ object does not change its state or behavior.
o Full support for C++ encapsulation, object identity, inheritance, and
polymorphism.
o C++ pointers and references are automatically converted to database
references when storing objects.
o Database references are automatically converted to C++ pointers and
references when reading objects.
o All database definition is done through a small extension to C++
declaration syntax.
Database Functionality
o Navigation
o Queries
o Sorting
o Indexes
o Single-user operation
o Multi-user operation using client/server architecture
o Flexible locking for objects and sets
o Nested transactions
o Watch & notify for objects and sets
o Event handling
o Database size limited only by hard disk size
C++ Language Extensions
o Persistence
o Indexes
o Transient data elements in persistent classes
o Sets
o Dependent objects
PTXX-Precompiler
o Automatically converts extended C++ class declarations into
ANSI 2.0 code
o Registers classes in the class dictionary
o Automatically generates POET Tool Classes
o Provides class versioning
Predefined C++ Classes
o Predefined classes for date, time, strings, and BLOBS
(binary large objects) can save you development time
Portability
o All platforms are source-code compatible
o Any POET database may be read by any computer
o Full support for heterogeneous networks
Platforms
o Available for MS-DOS / MS-Windows (Borland C++, Microsoft C++,
Zortech C++), OS/2 (Borland C++), Novell, Macintosh (MPW), and
various Unix systems, including NeXT (NeXTStep), SCO (Liant C++),
and Sun OS (Sun C++).
POET Keywords
o persistent--Defines database classes. Instances of a persistent
class can be stored in the POET database.
o transient--Defines non-persistent members of a persistent class.
Transient members are not stored in the database.
o depend--Defines dependent sub-objects.
o indexdef, useindex--Defines indices. If available, indices are
automatically used for query optimization.
o ondemand<type>--Defines special references among objects. Ondemand
references are explicitly loaded after object is read.
o cset<type>, lset<type>, hset<type>--Define object containers that
may or may not swap objects to disk
POET Tool Classes
o PtBase--Used for database management.
o PtObject--Management of persistence and database characteristics.
o PtAllSet<type>--Provides access to all objects of a given class.
o PtSet<type>--Sets which can be used for one to many relationships
among objects or to hold the results of a query.
o PtOndemand<type>--An optimization class for references to objects
which are to be explicitly loaded.
o PtQuery<type>--A class to define and hold query specifications.
POET Data Types
o int, long, char, float, double--All of the standard C++ data types
are supported.
o class[n]--Arrays are fully supported.
o PtString--A variable length string is provided.
o PtDate--Date type.
o PtTime--Time type.
o PtBlob--BLOBs--Binary Large OBjects