?? fastdb.htm
字號:
The method should be a parameterless instance member function
returning a
boolean, numeric, reference or string type. Methods should be specified after
all other attributes of the class.
</DL><P>
Although only atomic fields can be indexed, an index type can be specified
for structures. The index will be created for components of the structure
only if such type of index is specified in the index type mask of the
structure. This allows the programmers to enable or disable indices for
structure fields depending on the role of the structure in the record.<P>
The following example illustrates the creation of a type descriptor
in the header file:<P>
<PRE>
class dbDateTime {
int4 stamp;
public:
int year() {
return localtime((time_t*)&stamp)->tm_year + 1900;
}
...
CLASS_DESCRIPTOR(dbDateTime,
(KEY(stamp,INDEXED|HASHED),
METHOD(year), METHOD(month), METHOD(day),
METHOD(dayOfYear), METHOD(dayOfWeek),
METHOD(hour), METHOD(minute), METHOD(second)));
};
class Detail {
public:
char const* name;
char const* material;
char const* color;
real4 weight;
dbArray< dbReference<Contract> > contracts;
TYPE_DESCRIPTOR((KEY(name, INDEXED|HASHED),
KEY(material, HASHED),
KEY(color, HASHED),
KEY(weight, INDEXED),
RELATION(contracts, detail)));
};
class Contract {
public:
dbDateTime delivery;
int4 quantity;
int8 price;
dbReference<Detail> detail;
dbReference<Supplier> supplier;
TYPE_DESCRIPTOR((KEY(delivery, HASHED|INDEXED),
KEY(quantity, INDEXED),
KEY(price, INDEXED),
RELATION(detail, contracts),
RELATION(supplier, contracts)));
};
</PRE>
Type descriptors should be defined for all classes used in the database.
In addition to defining type descriptors, it is necessary to establish
a mapping between C++ classes and database tables. The macro
<code>REGISTER(</code>name<code>)</code> will do it. Unlike the
<code>TYPE_DESCRIPTOR</code> macro, the <code>REGISTER</code> macro should
be used in the implementation file and not in the header file. It constructs
a descriptor of the table associated with the class. If you are going to work
with multiple databases from one application, it is possible to register
a table in a concrete database by means of the
<code>REGISTER_IN(</code>name,database</code<code>)</code> macro.
The parameter <code>database</code> of this macro should be a pointer to the
<code>dbDatabase</code> object. You can register tables
in the database as follows:<P>
<PRE>
REGISTER(Detail);
REGISTER(Supplier);
REGISTER(Contract);
</PRE>
The table (and correspondent class) can be used only with one database
at each moment of time. When you open a database, FastDB imports into
the database all classes defined in the application.
If a class with the same name already exists
in the database, its descriptor stored in the database is compared with the
descriptor of this class in the application. If the class definitions
differ, FastDB tries to convert records from the table to the new
format. Any kind of conversion between numeric types (integer to
real, real to integer, with extension or truncation) is allowed. Also,
addition of new fields can be easily handled. But removal of fields
is only possible for empty tables (to avoid accidental data destruction).<P>
After loading all class descriptors, FastDB checks if all indices specified
in the application class descriptor are already present in the database,
constructs new indices and
removes indices, which are no more used. Reformatting the table and
adding/removing indices is only possible when no more than one
application accesses the database. So when the first application is attached
to the database, it can perform table conversion. All other applications
can only add new classes to the database.<P>
There is one special internal database <code>Metatable</code>, which
contains information about other tables in the database. C++ programmers
need not access this table, because the format of database tables is specified
by C++ classes. But in an interactive SQL program, it may be necessary to
examine this table to get information about record fields.<P>
Starting from version 2.30 FastDB supports autoincrement fields
(fields unique value to which are assigned automaticaly by database).
To be able to use them you should:<P>
<OL>
<LI>Recompile FastDB and your application with <code>-DAUTOINCREMENT_SUPPROT</code> flags
(add this flag to <code>DEFS</code> variables in FastDB makefile).<BR>
<B>Attention</B>: database files created by FastDB compiled without this option will be incompatible
with FastDB compiled with <code>DAUTOINCREMENT_SUPPORT</code>.
<LI>If you want to use other than 0 initial counter value, you should
asssign value to <code>dbTableDescriptor::initialAutoincrementCount</code>.
It will be shared between all tables, so all table will have the same initial value of
autoincrement counter.
<LI>Autoincrement fields should be of int4 type and should be declared
with <code>AUTOINCREMENT</code> flag:
<PRE>
class Record {
int4 rid;
char const* name;
...
TYPE_DESCRIPTOR((KEY(rid, AUTOINCREMENT|INDEXED), FIELD(name), ...));
}
</PRE>
<LI>When record with autoincrement field is inserted in the database
there is no need to specify value of autoincremented field (it will be
ignored). After successful insertion of record this field will be
assigned unique value (which is guaranteed to be not used before this
table):
<PRE>
Record rec;
// no rec.rid should be specified
rec.name = "John Smith";
insert(rec);
// rec.rid now assigned unique value
int newRecordId = rec.rid; // and can be used to reference this record
</PRE>
<LI>When record is removed the value will not be reused.
When transaction is aborted, table autoincrement counter is also rolled back.
</OL><P>
<H3><A NAME = "query">Query</A></H3>
The class query is used to serve two purposes:
<OL>
<LI>to construct a query and bind query parameters
<LI>to cache compiled queries
</OL>
FastDB provides overloaded '<code>=</code>' and '<code>,</code>' C++ operators
to construct query statements with parameters. Parameters can be specified
directly in places where they are used, eliminating any mapping between
parameter placeholders and C variables. In the following sample query,
pointers to the parameters <code>price</code> and <code>quantity</code>
are stored in the query, so that the query can be executed several times
with different parameter values. C++ overloaded functions make it possible
to automatically determine the type of the parameter,
requiring no extra information
to be supplied by the programmer (such reducing the possibility of a bug).
<PRE>
dbQuery q;
int price, quantity;
q = "price >=",price,"or quantity >=",quantity;
</PRE>
Since the <code>char*</code> type can be used both for specifying a fraction
of a query (such as "price >=") and for a parameter of string type,
FastDB uses a special rule to resolve this ambiguity. This rule is based on the
assumption that there is no reason for splitting a query text into two strings
like ("price ",">=") or specifying more than one parameter sequentially
("color=",color,color). So FastDB assumes the first string to be a fraction
of the query text and switches to <I>operand mode</I>
after it. In <I>operand mode</I>, FastDB treats the <code>char*</code> argument
as a query parameter and switches back to query <I>text mode</I>, and so on...
It is also possible not to use this "syntax sugar" and construct
query elements explicitly by the
<code>dbQuery::append(dbQueryElement::ElementType type, void const* ptr)</code>
method. Before appending elements to the query,
it is necessary to reset the query by the <code>dbQuery::reset()</code> method
('<code>operator=</code>' does it automatically).<P>
It is not possible to use C++ numeric constants as query parameters, because
parameters are accessed by reference. But it is possible to use string
constants, because strings are passed by value. There two possible ways of
specifying string parameters in a query: using a string buffer or a
pointer to pointer to string:<P>
<PRE>
dbQuery q;
char* type;
char name[256];
q = "name=",name,"and type=",&type;
scanf("%s", name);
type = "A";
cursor.select(q);
...
scanf("%s", name);
type = "B";
cursor.select(q);
...
</PRE><P>
Query variables can neither be passed to a function as a parameter
nor be assigned to another variable.
When FastDB compiles the query, it saves the compiled tree in this object.
The next time the query will be used,
no compilation is needed and the already compiled
tree can be used. It saves some time needed for query compilation.<P>
FastDB provides two approaches to integrate user-defined types in databases.
The first - the definition of class methods - was already mentioned.
The other approach deals only with query construction. Programmers should
define methods, which will not do actual calculations, but instead
return an expression (in terms of predefined database types), which
performs the necessary calculation. It is better to describe it by example.
FastDB has no builtin datetime type. Instead of this, a normal C++
class <code>dbDateTime</code> can be used by the programmer. This class defines
methods allowing to specify datetime fields in ordered lists and
to compare two dates using normal relational operators:<P>
<PRE>
class dbDateTime {
int4 stamp;
public:
...
dbQueryExpression operator == (char const* field) {
dbQueryExpression expr;
expr = dbComponent(field,"stamp"),"=",stamp;
return expr;
}
dbQueryExpression operator != (char const* field) {
dbQueryExpression expr;
expr = dbComponent(field,"stamp"),"<>",stamp;
return expr;
}
dbQueryExpression operator < (char const* field) {
dbQueryExpression expr;
expr = dbComponent(field,"stamp"),">",stamp;
return expr;
}
dbQueryExpression operator <= (char const* field) {
dbQueryExpression expr;
expr = dbComponent(field,"stamp"),">=",stamp;
return expr;
}
dbQueryExpression operator > (char const* field) {
dbQueryExpression expr;
expr = dbComponent(field,"stamp"),"<",stamp;
return expr;
}
dbQueryExpression operator >= (char const* field) {
dbQueryExpression expr;
expr = dbComponent(field,"stamp"),"<=",stamp;
return expr;
}
friend dbQueryExpression between(char const* field, dbDateTime& from,
dbDateTime& till)
{
dbQueryExpression expr;
expr=dbComponent(field,"stamp"),"between",from.stamp,"and",till.stamp;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -