?? fastdb.htm
字號:
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;
return expr;
}
friend dbQueryExpression ascent(char const* field) {
dbQueryExpression expr;
expr=dbComponent(field,"stamp");
return expr;
}
friend dbQueryExpression descent(char const* field) {
dbQueryExpression expr;
expr=dbComponent(field,"stamp"),"desc";
return expr;
}
};
</PRE>
All these methods receive as their parameter a name of a field in the record.
This name is used to contract the full name of the record's component.
This can be done by class <code>dbComponent</code>, which constructor takes
the name of the structure field and the name of the component of the structure
and returns a compound name separated by a '.' symbol.
The class <code>dbQueryExpression</code> is used to collect expression items.
The expression is automatically enclosed in parentheses, eliminating conflicts
with operator precedence.<P>
So, assuming a record containing a field <code>delivery</code>
of dbDateTime type, it is possible
to construct queries like these:
<PRE>
dbDateTime from, till;
q1 = between("delivery", from, till),"order by",ascent("delivery");
q2 = till >= "delivery";
</PRE>
In addition to these methods, some class specific method can be defined
in such way, for example the method <code>overlaps</code> for a region type.
The benefit of this approach is that a database engine will work
with predefined types and is able to apply indices and other optimizations
to proceed such query. And from the other side, the encapsulation of the class
implementation is preserved, so programmers should not rewrite all queries
when a class representation is changed.<P>
Variables of the following C++ types can be used as query parameters:<P>
<TABLE BORDER ALIGN="center">
<TR><TD WIDTH=50%>int1</TD><TD WIDTH=50%>bool</TD></TR>
<TR><TD>int2</TD><TD>char const*</TD></TR>
<TR><TD>int4</TD><TD>char **</TD></TR>
<TR><TD>int8</TD><TD>char const**</TD></TR>
<TR><TD>real4</TD><TD>dbReference<T></TD></TR>
<TR><TD>real8</TD><TD>dbArray< dbReference<T> ></TD></TR>
</TABLE><P>
<H3><A NAME = "cursor">Cursor</A></H3>
Cursors are used to access records returned by a select statement.
FastDB provides typed cursors, i.e. cursors associated with concrete tables.
There are two kinds of cursors in FastDB: readonly cursors and cursors for
update. Cursors in FastDB are represented by the C++ template class
<code>dbCursor<T></code>,
where <code>T</code> is the name of a C++ class associated with
the database table. The cursor type should be specified in the constructor
of the cursor. By default, a read-only cursor is created.
To create a cursor for update, you should pass a parameter
<code>dbCursorForUpdate</code> to the constructor.<P>
A query is executed either by the cursor
<code>select(dbQuery& q)</code> method.
Or by the <code>select()</code> method,
which can be used to iterate through
all records in the table. Both methods return the number of selected records
and set the current position to the first record (if available).
A cursor can be scrolled in forward or backward direction.
The methods <code>next(), prev(), first(), last()</code> can be used to
change the current position of the cursor.
If no operation can be performed as there are no (more) records
available, these methods return <code>NULL</code>
and the cursor position is not changed.<P>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -