?? fastdb.htm
字號:
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 andremoves indices, which are no more used. Reformatting the table and adding/removing indices is only possible when no more than oneapplication accesses the database. So when the first application is attachedto the database, it can perform table conversion. All other applicationscan only add new classes to the database.<P>There is one special internal database <code>Metatable</code>, whichcontains information about other tables in the database. C++ programmersneed not access this table, because the format of database tables is specifiedby C++ classes. But in an interactive SQL program, it may be necessary toexamine 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 shouldasssign 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 declaredwith <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 databasethere is no need to specify value of autoincremented field (it will beignored). After successful insertion of record this field will beassigned unique value (which is guaranteed to be not used before thistable):<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++ operatorsto construct query statements with parameters. Parameters can be specified directly in places where they are used, eliminating any mapping betweenparameter 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 timeswith different parameter values. C++ overloaded functions make it possibleto automatically determine the type of the parameter, requiring no extra informationto 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 fractionof 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 theassumption that there is no reason for splitting a query text into two stringslike ("price ",">=") or specifying more than one parameter sequentially("color=",color,color). So FastDB assumes the first string to be a fractionof the query text and switches to <I>operand mode</I>after it. In <I>operand mode</I>, FastDB treats the <code>char*</code> argumentas 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 constructquery 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, becauseparameters are accessed by reference. But it is possible to use stringconstants, because strings are passed by value. There two possible ways of specifying string parameters in a query: using a string buffer or apointer 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 parameternor 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 compiledtree 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 shoulddefine methods, which will not do actual calculations, but insteadreturn an expression (in terms of predefined database types), whichperforms 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 definesmethods allowing to specify datetime fields in ordered lists andto 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 takesthe name of the structure field and the name of the component of the structureand 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 conflictswith operator precedence.<P>So, assuming a record containing a field <code>delivery</code>of dbDateTime type, it is possibleto 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 definedin such way, for example the method <code>overlaps</code> for a region type.The benefit of this approach is that a database engine will workwith predefined types and is able to apply indices and other optimizationsto proceed such query. And from the other side, the encapsulation of the classimplementation is preserved, so programmers should not rewrite all querieswhen 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 withthe database table. The cursor type should be specified in the constructorof 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 throughall records in the table. Both methods return the number of selected recordsand 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) recordsavailable, these methods return <code>NULL</code>and the cursor position is not changed.<P>A cursor for class T contains an instance of class T, used for fetching thecurrent record. That is why table classes should have a default constructor(constructor without parameters), which has no side effects. FastDB optimizes fetching records from the database, copying only data fromfixed parts of the object. String bodies are not copied, insteadof this the correspondent field points directly into the database. The same istrue for arrays: their components have the same representation in thedatabase as in the application (arrays of scalar types or arrays of nested structures of scalar components).<P>An application should not changeelements of strings and arrays in a database directly.When an array method needs to update an array body,it creates an in-memory copy of the array and updates this copy. If the programmer wants to update a string field, she/he should assignto the pointer a new value, but don't change the string directly in the database.It is recommended to use the <code>char const*</code> type instead of the<code>char*</code> type for string components,
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -